/* global React */
const { useState } = React;

/* ── Media · Narration · Edit · Music · Publish ─────────────────────── */

function Media() {
  const [checked, setChecked] = useState(new Set([0, 1]));
  const items = [
    "Shoot b-roll in horizontal 1080p (or 4K) with locked exposure.",
    "Record 30 seconds of \"room tone\" at every location.",
    "Ask every interviewee to sign a release — even friends and family.",
    "Collect archival scans at 600 DPI minimum; capture the back of photos too.",
    "Name files on import: YYMMDD_location_shot_take.mp4",
    "Back up to two places before you leave the location.",
    "Log each clip in a spreadsheet: timecode, subject, usable (Y/N), notes.",
  ];
  const tog = (i) => setChecked((s) => { const n = new Set(s); n.has(i) ? n.delete(i) : n.add(i); return n; });

  return (
    <section className="sec" id="media">
      <div className="wrap">
        <window.SectionHead
          num="04"
          eyebrow="Gathering media"
          title="Collect more than you'll use. Log everything you collect."
          lede="The single biggest reason a digital story stalls in editing is messy source material. A 3-minute piece needs 30 minutes of usable footage, 2–3 interviews, 10 stills, and an inventoried folder structure. Teach the logistics before the aesthetics."
        />
        <div className="cols-2">
          <div className="card">
            <h4 className="card-title">Field checklist</h4>
            <div style={{marginTop: 8}}>
              {items.map((x, i) => (
                <div key={i} className={"checklist-item" + (checked.has(i) ? " done" : "")} onClick={() => tog(i)}>
                  <span className={"checkbox" + (checked.has(i) ? " checked" : "")}>
                    {checked.has(i) && <window.Ic.check />}
                  </span>
                  <span>{x}</span>
                </div>
              ))}
            </div>
          </div>
          <div className="card">
            <h4 className="card-title">The folder structure students should use</h4>
            <pre style={{fontFamily: "var(--mono)", fontSize: 12.5, lineHeight: 1.7, color: "var(--ink-dim)", margin: 0, whiteSpace: "pre-wrap"}}>
{`project-name/
├── 01-script/
│   ├── draft-01.md
│   └── storyboard.pdf
├── 02-source/
│   ├── video/
│   ├── audio/
│   ├── stills/
│   └── archive/
├── 03-edit/
│   └── project.wevideo
├── 04-export/
│   ├── rough-cut-v1.mp4
│   └── final.mp4
└── 05-releases/
    └── signed/`}
            </pre>
            <p style={{fontSize: 13, color: "var(--ink-mute)", marginTop: 12}}>
              Rigid structure isn't pedantry — it's the difference between a student finishing and a student losing a weekend to "which version was the good one."
            </p>
          </div>
        </div>
      </div>
    </section>
  );
}

function Narration() {
  return (
    <section className="sec" id="narration">
      <div className="wrap">
        <window.SectionHead
          num="06"
          eyebrow="Recording narration"
          title="A closet is a studio."
          lede="Narration is the single most important audio element in a digital story. Good narration in a bad edit still works. Bad narration in a great edit doesn't. Teach the microphone first, the performance second."
        />
        <div className="cols-3">
          <div className="card">
            <div style={{color: "var(--accent)", marginBottom: 10}}><window.Ic.mic /></div>
            <h4 className="card-title">The room</h4>
            <p className="card-body">Find soft surfaces — a coat closet, a car, a bedroom with curtains. Avoid kitchens, bathrooms, empty classrooms. If you can clap and hear the clap bounce, keep walking.</p>
          </div>
          <div className="card">
            <div style={{color: "var(--accent)", marginBottom: 10}}><window.Ic.mic /></div>
            <h4 className="card-title">The mic</h4>
            <p className="card-body">A phone's voice memo in a good room beats a $200 mic in a bad one. If you have a USB mic, keep it 4–6 inches from your mouth and slightly off-axis to dodge plosives.</p>
          </div>
          <div className="card">
            <div style={{color: "var(--accent)", marginBottom: 10}}><window.Ic.mic /></div>
            <h4 className="card-title">The performance</h4>
            <p className="card-body">Read the whole script through once without recording. Then record three takes of each paragraph — no more. Your third take is usually the one. Edit between takes, not within them.</p>
          </div>
        </div>
        <div className="pull">
          If students remember one thing from this section, let it be: <em>record room tone for 30 seconds at every session.</em> The edit needs it even when the story doesn't.
        </div>
      </div>
    </section>
  );
}

function Editing() {
  return (
    <section className="sec" id="edit">
      <div className="wrap">
        <window.SectionHead
          num="07"
          eyebrow="Editing &amp; assembly"
          title="Build the skeleton. Then the skin."
          lede="Every editor, regardless of tool, goes through the same four passes. Skipping one creates a muddy cut that students can't diagnose. Name the passes explicitly in your assignment deadlines."
        />
        <div className="cols-4">
          {[
            {n: "01", t: "Radio cut", b: "Narration + room tone only, on a single track. No visuals yet. The piece should work as audio alone. If it doesn't, the script is the problem."},
            {n: "02", t: "Rough cut", b: "Drop in the primary visual for each line of narration. Ugly title cards are fine. Watch end-to-end twice without pausing. Note, don't fix."},
            {n: "03", t: "Fine cut", b: "Tighten every cut by a few frames. Add b-roll, inserts, archival. Introduce music under one section. Color-balance if your tool allows."},
            {n: "04", t: "Picture lock", b: "Decide no more cuts. Then — and only then — do final titles, credits, captions, and the full music mix. Export at your target resolution."},
          ].map((x) => (
            <div className="card" key={x.n}>
              <div className="num-big" style={{fontSize: 40}}>{x.n}</div>
              <h4 className="card-title">{x.t}</h4>
              <p className="card-body">{x.b}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function Music() {
  return (
    <section className="sec" id="music">
      <div className="wrap">
        <window.SectionHead
          num="08"
          eyebrow="Music &amp; sound design"
          title="Score the silences, not the sentences."
          lede="Music in a digital story is a structural tool, not a decoration. It should tell the viewer when a chapter is ending or when the tone is about to shift — and go quiet when the narrator has something real to say."
        />
        <div className="cols-2">
          <div className="card">
            <h4 className="card-title">Where to source</h4>
            <ul style={{margin: 0, paddingLeft: 18, color: "var(--ink-dim)", fontSize: 14, lineHeight: 1.7}}>
              <li><b style={{color: "var(--ink)"}}>Free (with rights):</b> YouTube Audio Library, Free Music Archive, Pixabay Music, Uppbeat.</li>
              <li><b style={{color: "var(--ink)"}}>Cheap &amp; licensed:</b> Epidemic Sound, Artlist, Musicbed (education discounts exist).</li>
              <li><b style={{color: "var(--ink)"}}>Built-in:</b> GarageBand's loop library is genuinely good, and pre-cleared.</li>
              <li><b style={{color: "var(--ink)"}}>Original:</b> a student composer in the class can often score the whole cohort.</li>
            </ul>
          </div>
          <div className="card">
            <h4 className="card-title">The mixing rule students always skip</h4>
            <p className="card-body">
              Set your narration to peak at <b style={{color: "var(--ink)"}}>−6 dB</b>. Set music <b style={{color: "var(--ink)"}}>−18 to −24 dB under the voice</b>. When music plays without narration, bring it up 6–8 dB. When narration comes back in, duck it again. This "ducking" is the single most important edit move — and every editor has it.
            </p>
          </div>
        </div>
      </div>
    </section>
  );
}

function Publish() {
  return (
    <section className="sec" id="publish">
      <div className="wrap">
        <window.SectionHead
          num="09"
          eyebrow="Publishing &amp; sharing"
          title="Where it lives is part of the piece."
          lede="Don't let students' work die inside an LMS dropbox. Decide at the start of the assignment where the final cut will live, who can see it, and how it will be credited. The venue shapes the edit."
        />
        <div className="cols-3">
          <div className="card">
            <h4 className="card-title">Private / class-only</h4>
            <p className="card-body">Upload unlisted to YouTube or Vimeo. Share via LMS. Safest for FERPA, for personal stories, and for pieces with minors on camera.</p>
            <div className="gal-tags" style={{marginTop: 12}}>
              <span className="tag">Vimeo · unlisted</span>
              <span className="tag">YouTube · unlisted</span>
              <span className="tag">Panopto</span>
            </div>
          </div>
          <div className="card">
            <h4 className="card-title">Public · portfolio</h4>
            <p className="card-body">A dedicated student site (single page, clean type, a short written context) does more for their portfolio than a raw upload ever will. Build once, reuse every semester.</p>
            <div className="gal-tags" style={{marginTop: 12}}>
              <span className="tag">Custom site</span>
              <span className="tag">Vimeo Showcase</span>
              <span className="tag">Cargo</span>
            </div>
          </div>
          <div className="card">
            <h4 className="card-title">Public · festival</h4>
            <p className="card-body">Student-film and micro-doc festivals accept 3–5 minute digital stories. Submit 2–3 per year at the department level. External recognition changes how students take the assignment.</p>
            <div className="gal-tags" style={{marginTop: 12}}>
              <span className="tag">All American HS Film Fest</span>
              <span className="tag">Campus MovieFest</span>
              <span className="tag">Local film fests</span>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── Pitfalls · Templates · FAQ · Footer ──────────────────────────── */

const PITFALLS = [
  ["Narration that sounds like a paper.", "Students read their English-class voice. Assign a rewrite where every sentence must pass a dinner-table test: would you actually say this to a friend?"],
  ["Music as background wallpaper.", "One track under the entire piece, same volume the whole way. Require a minimum of three music moves: an entrance, a duck, and an exit."],
  ["No silence.", "Every second of a 3-minute piece is filled with voice or music. Assign a 6-second stretch of pure room tone somewhere. It will be the moment viewers remember."],
  ["Meaningful-looking b-roll.", "Slow-motion water, abstract window reflections. If the shot doesn't serve the specific sentence under it, cut it."],
  ["A summary ending.", "\"And that's why…\" Resolution belongs in the image and in the silence, not in a thesis statement. Ban the phrase \"in conclusion\" from the last 30 seconds."],
  ["Exporting at the wrong spec.", "Vertical, pillar-boxed, 480p, or 60fps. Require 1920×1080, 24 or 30fps, MP4 H.264 — and check every hand-in against it before critique."],
];

function Pitfalls() {
  return (
    <section className="sec" id="pitfalls">
      <div className="wrap">
        <window.SectionHead
          num="11"
          eyebrow="Common pitfalls"
          title="Six ways it goes wrong — and what to do instead."
          lede="Every instructor sees the same six failures, cohort after cohort. Name them on day one. Students can't avoid mistakes whose names they don't know."
        />
        <div>
          {PITFALLS.map(([bad, fix], i) => (
            <div className="pit-row" key={i}>
              <div className="pit-num">{String(i + 1).padStart(2, "0")}</div>
              <div className="pit-bad"><b>{bad}</b></div>
              <div className="pit-fix">{fix}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

const TEMPLATES = [
  { icon: <window.Ic.pen />, title: "Two-column script", desc: "The tested narration / visual layout. Prints to 8.5×11 or A4. Students draft both columns at the same time, line by line.", meta: "HTML · print to PDF", href: "templates/two-column-script.html", rid: "tpl_script" },
  { icon: <window.Ic.frame />, title: "Storyboard grid", desc: "A 12-cell printable storyboard with shot-type boxes and duration fields. Pair with the drag-and-drop builder above.", meta: "HTML · print to PDF", href: "templates/storyboard-grid.html", rid: "tpl_storyboard" },
  { icon: <window.Ic.mic />, title: "Release form", desc: "A plain-language release for on-camera subjects and archival use. Review with your institution's counsel before adoption.", meta: "HTML · print to PDF", href: "templates/release-form.html", rid: "tpl_release" },
  { icon: <window.Ic.clip />, title: "Rubric (faculty)", desc: "A 25-point rubric across script, structure, image, sound, and craft. Aligned with this guide's passes so feedback maps to edits.", meta: "HTML · print to PDF", href: "templates/rubric.html", rid: "tpl_rubric" },
  { icon: <window.Ic.book />, title: "Syllabus module", desc: "A three-week drop-in module: week 1 script/storyboard, week 2 shoot/record, week 3 edit/critique. Includes pacing notes.", meta: "HTML · print to PDF", href: "templates/syllabus-module.html", rid: "tpl_syllabus" },
  { icon: <window.Ic.share />, title: "Critique protocol", desc: "A 20-minute structured critique format — watch, silent notes, two rounds of spoken feedback. Keeps the room on the piece, not the person.", meta: "HTML · print to PDF", href: "templates/critique-protocol.html", rid: "tpl_critique" },
];

function tplHref(t) {
  if (window.__resources && window.__resources[t.rid]) return window.__resources[t.rid];
  return t.href;
}

function Templates() {
  return (
    <section className="sec" id="templates">
      <div className="wrap">
        <window.SectionHead
          num="12"
          eyebrow="Downloadable templates"
          title="Steal these. Remix them. Put your logo on them."
          lede="Six documents the department can adopt tomorrow. They're intentionally plain so they survive copy-paste into your existing syllabus. Everything here is CC-BY-NC."
        />
        <div className="cols-3">
          {TEMPLATES.map((t) => (
            <a className="tpl-card" key={t.title} href={tplHref(t)} target="_blank" rel="noopener" style={{textDecoration: "none", color: "inherit"}}>
              <div className="tpl-icon">{t.icon}</div>
              <div>
                <h4 className="tpl-title">{t.title}</h4>
                <p className="tpl-desc">{t.desc}</p>
              </div>
              <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: "auto"}}>
                <span className="tpl-meta">{t.meta}</span>
                <span className="tpl-dl"><window.Ic.download /> Open</span>
              </div>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
}

const FAQ = [
  ["How long should a digital story be?", "For undergraduate coursework, 2–4 minutes is the sweet spot. Shorter than 90 seconds rarely leaves room for a turn; longer than 5 minutes exceeds most students' craft ceiling and the audience's attention. When in doubt, cut."],
  ["What if a student has no usable footage?", "A digital story can be made entirely from stills, archival scans, screen-recorded documents, and narration. Some of the most effective student pieces use no video at all. Don't let \"I couldn't shoot it\" become an excuse — it's a constraint, and constraints are good."],
  ["How do we handle privacy when stories get personal?", "Decide the audience at assignment time — class-only, department showcase, or public — and let students calibrate accordingly. Never require public posting. Use a release for any identifiable person on camera, including the student themselves if the piece will be public."],
  ["Is AI-generated content allowed?", "This is a faculty policy decision. A reasonable default: AI-generated voice and AI-generated video are not allowed (they undermine the authorial voice the assignment is about); AI-assisted editing (auto-captions, noise reduction, transcription, script editing) is allowed and disclosed in the credits."],
  ["How do we grade this without being subjective?", "Grade the craft passes, not the taste. Did the student submit a radio cut before a rough cut? Does the script hit 150 words per minute? Are music levels ducked under narration? These are checkable. Critique, not grading, is where taste enters."],
  ["What's the minimum hardware a student needs?", "A smartphone from the last five years, a pair of wired earbuds with a mic, and access to a laptop or school computer for editing. That's it. Spend the money students would have spent on hardware on licensing music and printing storyboards."],
];

function Faq() {
  const [open, setOpen] = useState(0);
  return (
    <section className="sec" id="faq">
      <div className="wrap">
        <window.SectionHead
          num="13"
          eyebrow="FAQ"
          title="Questions every instructor asks."
          lede="Six questions we get from faculty adopting digital storytelling for the first time. If one of these is on your mind, you're not alone."
        />
        <div>
          {FAQ.map(([q, a], i) => (
            <div key={i} className={"faq-item" + (open === i ? " open" : "")}>
              <button className="faq-q" onClick={() => setOpen((o) => (o === i ? -1 : i))}>
                <span>{q}</span>
                <span className="faq-toggle"><window.Ic.plus /></span>
              </button>
              <div className="faq-a"><p>{a}</p></div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="foot">
      <div className="wrap">
        <div className="foot-grid">
          <div>
            <div className="brand" style={{marginBottom: 14}}>
              <div className="brand-mark">ds</div>
              <span>Digital Story Studio</span>
            </div>
            <p style={{maxWidth: "38ch", color: "var(--ink-dim)", fontSize: 13.5, lineHeight: 1.6}}>
              A faculty-led, student-tested guide for teaching digital storytelling in higher ed. Updated each semester by the teaching team.
            </p>
          </div>
          <div>
            <h6>Guide</h6>
            <ul>
              <li><a href="#what">What it is</a></li>
              <li><a href="#structure">Structure</a></li>
              <li><a href="#tools">Tools</a></li>
              <li><a href="#publish">Publish</a></li>
            </ul>
          </div>
          <div>
            <h6>Resources</h6>
            <ul>
              <li><a href="#templates">Templates</a></li>
              <li><a href="#gallery">Gallery</a></li>
              <li><a href="#pitfalls">Pitfalls</a></li>
              <li><a href="#faq">FAQ</a></li>
            </ul>
          </div>
          <div>
            <h6>For faculty</h6>
            <ul>
              <li><a href="#">Syllabus module</a></li>
              <li><a href="#">Critique protocol</a></li>
              <li><a href="#">Rubric</a></li>
              <li><a href="#">Workshop booking</a></li>
            </ul>
          </div>
        </div>
        <div className="foot-bottom">
          <span>© Teaching Team · CC-BY-NC 4.0</span>
          <span>v2.4 · Fall 2026</span>
        </div>
      </div>
    </footer>
  );
}

window.Media = Media;
window.Narration = Narration;
window.Editing = Editing;
window.Music = Music;
window.Publish = Publish;
window.Pitfalls = Pitfalls;
window.Templates = Templates;
window.Faq = Faq;
window.Footer = Footer;
