/* Earth Music Theater — flight test stylesheet.
   Design direction: docs/EMT/02.
   Near-black rather than pure black (pure black crushes the footage's
   shadows at the frame edge). One serif with presence, one grotesque for
   utility. No cards. No shadows. Nothing bounces. */

:root {
  /* ONE home for the menu bar's height. The bar is PINNED to this value,
     and everything that must clear it derives from it: the hero's height,
     every section's jump offset, the edit page's sticky bar. Restyle the
     bar freely — alignment cannot drift again. (Structural cleanup,
     Jul 30, after jump offsets went stale three restyles in a row.) */
  --headh:    64px;

  --ink:      #0A0B0D;          /* field  */
  --paper:    #F2EFE9;          /* type   */
  --dim:      #8B8880;
  --dimmer:   #55534E;
  --rule:     #23252A;
  --accent:   #E8A33D;          /* sodium-orange of city lights at night */
  --aurora:   #63DF7C;          /* the bright green of the aurora itself */
  --tile:     #16181C;          /* empty artwork cell */
  --tile-ink: #2C2F35;
  --scrim:    rgba(10,11,13,.72);
  --prose:    #DBD8D1;
  --ghost:    #3A3D43;          /* input placeholders */
  --heroveil: .58;              /* hero image opacity */
  --veil-1:   rgba(10,11,13,.75);
  --veil-2:   rgba(10,11,13,.55);
  --veil-3:   rgba(10,11,13,.12);
  --slow:     900ms cubic-bezier(.22,.61,.36,1);
  --slower:   1400ms cubic-bezier(.22,.61,.36,1);
}

/* Light mode — an experiment, toggled in the masthead.
   Not a simple inversion: the accent has to darken sharply to hold against
   white, and the hero image needs less veil because there is no darkness
   for it to emerge from. */
body.light {
  --ink:      #FAF8F4;
  --paper:    #14161A;
  --dim:      #6E6B65;
  --dimmer:   #9A968E;
  --rule:     #E0DCD4;
  --accent:   #A8620C;
  --tile:     #EDE9E2;
  --tile-ink: #CFCAC1;
  --scrim:    rgba(250,248,244,.82);
  --prose:    #2A2D33;
  --ghost:    #BBB6AD;
  --heroveil: .92;
  --veil-1:   rgba(250,248,244,.82);
  --veil-2:   rgba(250,248,244,.62);
  --veil-3:   rgba(250,248,244,.14);
}
/* The player keeps its dark surround in both modes — a film should not sit
   on white. */
body.light .player-wrap, body.light .player { background: #0A0B0D; }

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }


body {
  background: var(--ink);
  color: var(--paper);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }

.serif {
  font-family: "Instrument Serif", "Iowan Old Style", Georgia, serif;
  font-weight: 400;
  letter-spacing: -0.01em;
}

/* ---- the kicker: small letterspaced caps. The repeating unit. --------- */
.kicker {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 500;
}
.kicker .num { color: var(--accent); }

/* ---- masthead --------------------------------------------------------- */
/* A defined bar above the content, not a veil over it (Dan, Jul 30).
   Sticky so it stays while scrolling; solid in both modes — EVERY
   page including the watch page (Dan, Aug 6: a reliable anchor). */
header.top {
  position: sticky; top: 0; left: 0; right: 0; z-index: 60;
  height: var(--headh); box-sizing: border-box;
  /* Brand leads (Aug 6): brand · menu, search pushed right by its
     own margin inside the nav (which now flexes to fill). */
  display: flex; gap: 30px; align-items: center;
  padding: 0 40px;
  background: var(--ink);
  border-bottom: 1px solid var(--rule);
}
header.top .wordmark { font-size: 19px; letter-spacing: .005em; }
/* The beta flag (Aug 7, go-live): centered in the sticky header,
   above the flex flow. Remove at cutover. */
.betaflag {
  position: absolute; left: 50%; transform: translateX(-50%);
  color: var(--accent); border: 1px solid var(--accent);
  border-radius: 999px; padding: 4px 14px;
  font-size: 12px; letter-spacing: .14em; white-space: nowrap;
}
.topbrand { display: flex; align-items: center; gap: 12px; }
.toplogo { height: 40px; width: auto; }
header.top .season a { transition: color var(--slow); }
header.top .season a:hover { color: var(--paper); }
/* The marquee light (D30): the active program's button. */
header.top .season a.marq.on { color: var(--accent); }
.mode {
  background: transparent; border: 1px solid var(--rule); color: var(--dim);
  border-radius: 999px; font: inherit; font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; padding: 5px 12px; margin-left: 18px;
  cursor: pointer;
  transition: color var(--slow), border-color var(--slow);
}
.mode:hover { color: var(--paper); border-color: var(--dimmer); }
header.top .season   { font-size: 13px; letter-spacing: .18em;
                       text-transform: uppercase; color: var(--dim);
                       display: flex; align-items: center;
                       flex: 1 1 auto; }
/* Separators live in CSS so the same markup can stack on phones. */
.season a + a::before { content: "\00B7"; margin: 0 12px;
                        color: var(--dimmer); }
/* Dan's desks, far right (Aug 6): a shade quieter than the visitor
   menu — present, not advertised. Gone from the nav at cutover. */
.season a.desk { color: var(--dimmer); }
/* The desks-and-Light cluster takes the far right; everything before
   it (brand · menu · search) holds the left. */
.season .topsearch + a.desk { margin-left: auto; }
.navburger {
  display: none; background: none; border: 0; color: var(--paper);
  font-size: 22px; cursor: pointer; padding: 0 4px; line-height: 1;
}


/* .ncard: the medium card (ui.medium, _parts.html) — the film page's
   recommendation rails wear it. (.nhead/.nbar died with triage, Aug 3.) */
.ncard { display: block; }
.ncard-art {
  /* 4K aspect, like every format (Dan, Jul 30). */
  display: block; position: relative; aspect-ratio: 16/9;
  background: var(--tile); background-size: cover; background-position: center;
  border: 1px solid var(--dim);
  transition: opacity var(--slow);
}
.ncard:hover .ncard-art { opacity: .85; }
.ncard-art .dur {
  position: absolute; right: 10px; bottom: 10px;
  background: rgba(10,11,13,.72); color: #F2EFE9;
  font-size: 11px; padding: 3px 8px; border-radius: 2px;
  font-variant-numeric: tabular-nums;
}
/* Copy below the art — the large feature's voice at card scale
   (the NatGeo white panel is retired; Dan, Jul 30). */
.ncard-copy { display: block; padding: 14px 0 0; }
.ncard-copy .kicker { font-size: 10.5px; }
.ncard-title { display: block; font-size: 24px; line-height: 1.15;
  margin-top: 6px; }
.ncard-desc {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 13.5px; line-height: 1.55; color: var(--dim);
  margin-top: 8px;
}


/* ==== Responsive system (Jul 30) — breakpoints used SITE-WIDE:
   1024px  grid collapses to one column (tablets portrait and down)
    900px  nav collapses to the burger panel
    640px  phone scale: type, ring, lockup, paddings
   The bar height (--headh) is the one shared constant; media queries
   cannot read CSS vars, so these three numbers are the convention —
   change them here and nowhere else. ==== */

@media (max-width: 900px) {
  .navburger { display: block; }
  /* Phone header is burger + brand; the centered beta flag would sit
     on the wordmark, so it docks right instead. */
  .betaflag { left: auto; right: 16px; transform: none;
              font-size: 10px; padding: 3px 10px; }
  .season { display: none; }
  .season.open {
    display: flex; flex-direction: column; align-items: flex-start;
    gap: 16px; position: absolute; top: var(--headh); left: 0; right: 0;
    padding: 18px 24px 22px; background: var(--ink);
    border-bottom: 1px solid var(--rule);
  }
  .season.open a + a::before { content: none; margin: 0; }
}

@media (max-width: 640px) {
  header.top { padding: 0 20px; }
  footer.foot { padding: 40px 20px; }
}

/* ---- film page -------------------------------------------------------- */
/* The whole 16:9 frame must fit on screen without scrolling. Sizing the
   width from the viewport HEIGHT is what guarantees that: at most 100svh
   tall, at most 100vw wide, whichever binds first. */
.player-wrap {
  padding: 0; background: #000;
  height: 100svh; display: flex;
  align-items: center; justify-content: center;
}
.player {
  position: relative;
  width: min(100vw, calc(100svh * 16 / 9));
  aspect-ratio: 16 / 9;
  background: #000;
}

/* Watching (Dan, Aug 6): the menu STAYS — a reliable anchor above
   the movie, just like on every page. The old dissolve-on-watch
   (doc 02 principle 1) is retired for the HEADER; the film itself
   still owns the space below it. Its mousemove script left
   film.html the same day. */
.player iframe { position: absolute; inset: 0; width: 100%; height: 100%;
                 border: 0; }

/* the sound-on moment: explicit, once, unmissable */
.sound {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10,11,13,.55);
  background-size: cover; background-position: center;
  cursor: pointer; transition: opacity var(--slow);
}
.sound.gone { opacity: 0; pointer-events: none; }
.sound span {
  border: 1px solid rgba(242,239,233,.5); border-radius: 2px;
  padding: 16px 34px; font-size: 12px;
  letter-spacing: .2em; text-transform: uppercase;
  background: rgba(10,11,13,.35); backdrop-filter: blur(3px);
  transition: border-color var(--slow), letter-spacing var(--slow);
}
.sound:hover span { border-color: var(--paper); letter-spacing: .28em; }

article.film { padding: 74px 40px 120px; max-width: 1180px; }
article.film h1 { font-size: clamp(38px, 5.4vw, 76px); line-height: 1;
                  margin: 16px 0 26px; max-width: 18ch; }

/* The VIEW (D6) — what the film shows, right under the title. */
.viewline { font-size: clamp(17px, 2vw, 22px); color: var(--dim);
            margin: -14px 0 26px; max-width: 60ch; }

/* Two rows: the short scannable facts on top, the music underneath with the
   whole width to itself — a full work title with catalogue number will not
   sit politely in a column (Dan, Jul 28). */
.credits {
  padding: 26px 0 34px; border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule); margin-bottom: 56px;
}
/* The globe sits left, credits shift right to make room (Dan, Jul 28).
   Transparent PNG-derived WebP — no plate, no border, it just sits on the
   page like an object rather than an image in a box. */
.credits.has-globe { display: flex; gap: 46px; align-items: flex-start; }
.credits .globe {
  width: clamp(112px, 11vw, 168px); height: auto; flex-shrink: 0;
  margin-top: -4px;
}
.cstack { flex: 1 1 auto; min-width: 0; }
.crow { display: flex; flex-wrap: wrap; gap: 44px; }
.crow + .crow { margin-top: 30px; }
.credit .kicker { display: block; margin-bottom: 6px; }
.credit .v { font-size: 17px; }
.credit.wide { flex: 1 1 100%; }
.credit.grow { flex: 1 1 auto; }
.credit.mid { margin-left: auto; }

/* On desktop the credit rows share ONE grid, so the Movie ID cell in
   row two sits in the SAME column as Movie maker in row one — real
   alignment, not a right-edge push (Dan, Aug 4). The .crow wrappers
   dissolve (display: contents); their credits place in order. */
@media (min-width: 901px) {
  .cstack { display: grid;
    grid-template-columns: repeat(5, max-content);
    column-gap: 44px; row-gap: 30px; align-items: start; }
  .crow { display: contents; }
  .credit.grow { grid-column: 1 / 5; }
  .credit.mid { grid-column: 5; margin-left: 0; }
  .credit.wide { grid-column: 1 / -1; }
}

/* The cover takes the column the prose was leaving empty (Dan, Jul 28), and
   stays with you while you read. */
.bodywrap { display: flex; gap: 60px; align-items: flex-start;
            margin-bottom: 56px; }
.coverfig {
  flex: 0 0 clamp(220px, 26vw, 380px);
  position: sticky; top: calc(var(--headh) + 40px);
}
.coverfig img { width: 100%; height: auto; border-radius: 3px;
  display: block; box-sizing: border-box;
  border: 1px solid rgba(242, 239, 233, .16); }
.coverfig figcaption {
  margin-top: 12px; font-size: 13px; color: var(--dim); line-height: 1.5;
}
/* The musician under the cover (Dan, Aug 6): name · instrument ·
   square portrait, unmasked — the film-page cousin of the Musicians
   shelf portrait. Every piece optional (D12). */
/* Fonts match the prose across the aisle (Dan, Aug 6): name = the
   lead sentence's voice (21px paper), instrument = body voice. */
.mcard { margin-top: 34px; }
.mname { display: block; font-size: 21px; color: var(--paper); }
.minstr { display: block; margin: 4px 0 12px; font-size: 17.5px;
  color: var(--prose); line-height: 1.5; }
.mport { width: 100%; max-width: 300px; aspect-ratio: 1;
  object-fit: cover; border-radius: 3px; display: block;
  border: 1px solid rgba(242, 239, 233, .16); }

.prose { max-width: 63ch; flex: 1 1 auto; min-width: 0; }
.prose p { margin-bottom: 1.5em; font-size: 17.5px; color: var(--prose); }
.prose p:first-child { font-size: 21px; color: var(--paper); }
.prose .prule { border: 0; border-top: 1px solid var(--rule);
                margin: 0 0 1.5em; }

@media (max-width: 900px) {
  .bodywrap { flex-direction: column; gap: 34px; }
  .coverfig { position: static; flex: 1 1 auto; max-width: 460px; }
}

.more-head {
  font-family: "Instrument Serif", "Iowan Old Style", Georgia, serif;
  font-weight: 400; letter-spacing: -0.01em;
  font-size: clamp(30px, 4vw, 44px); line-height: 1.1;
  padding: 0 40px 34px; max-width: 1180px;
  color: var(--accent);
}
.more { padding: 0 40px 120px; max-width: 1180px; }
.more .kicker { display: block; margin-bottom: 22px; }
/* The musician's other films, medium format, in a left-right grid. */
.more-grid {
  display: grid; gap: 36px 28px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

/* ---- browse: Apple Music logic, our palette --------------------------- */
/* Header is in-flow now, so the page no longer clears a fixed bar. */
.browse { padding: 48px 40px 120px; }

.browse-head {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 30px; flex-wrap: wrap; margin-bottom: 30px;
}
.browse-head h2 { font-size: clamp(32px, 4vw, 52px); line-height: 1; }

.search input {
  background: transparent; border: 0; border-bottom: 1px solid var(--rule);
  color: var(--paper); font: inherit; font-size: 14px;
  padding: 9px 2px; width: min(360px, 68vw);
  transition: border-color var(--slow);
}
.search input::placeholder { color: var(--dimmer); }
.search input:focus { outline: none; border-color: var(--paper); }

.bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px 0; border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.bar .kicker { margin-right: 4px; }
.bar .count { margin-left: auto; color: var(--dimmer); font-size: 12px;
              font-variant-numeric: tabular-nums; }

.chip {
  font-size: 12.5px; padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--rule); color: var(--dim);
  transition: color var(--slow), border-color var(--slow),
              background var(--slow);
  white-space: nowrap;
}
.chip:hover { color: var(--paper); border-color: var(--dimmer); }
.chip.on { color: var(--ink); background: var(--paper);
           border-color: var(--paper); }

/* (The old flat-grid card system — .grid/.cell/.art/.ct/.cs/.prov —
   and the facet-filter styles died in the Aug 2 nail-down: D29's ONE
   card and D31's no-filters ruling made them unreachable. The 452px
   "Large is best" cell was superseded by the home card. Git holds
   everything.) */

/* ---- the editor's desk ------------------------------------------------ */
.edit .hint { color: var(--dim); font-size: 13px; line-height: 1.7; }
.edit .hint em { color: var(--dimmer); }
.saved { color: var(--accent); font-size: 13px; padding: 12px 0; }

.bar.sticky { position: sticky; top: var(--headh); z-index: 40;
              background: var(--ink); }
.save {
  background: var(--paper); color: var(--ink); border: 0; border-radius: 2px;
  font: inherit; font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  padding: 11px 24px; cursor: pointer;
  transition: opacity var(--slow);
}
.save:hover { opacity: .84; }

.erow {
  display: grid; grid-template-columns: 172px 1fr; gap: 22px;
  padding: 16px 0; border-bottom: 1px solid var(--rule);
}
.ethumb {
  position: relative; aspect-ratio: 16/9; border-radius: 3px;
  background: var(--tile); background-size: cover; background-position: center;
}
.ethumb.empty::after { content: "\266A"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--tile-ink); font-size: 26px; }
.enum {
  position: absolute; left: 7px; top: 6px; font-size: 11px;
  letter-spacing: .1em; color: var(--accent);
  background: var(--scrim); padding: 2px 6px; border-radius: 2px;
}

/* BLOCK layout (Dan, Aug 4): the data model's five groups laid across
   the full width — MOVIE · MUSIC · EARTH · ASTRONAUTS · DELIVERY.
   Columns are sized to what each holds, not split evenly: the old
   1fr 1fr gave an 1100px box to a field containing "40". Optimized
   for Dan's Studio Display (2560 CSS px) — he is the only user.
   Supersedes the Aug 3 campaign/settled two-stack (D33). */
.efields {
  display: grid; gap: 12px 34px; align-items: start;
  /* MOVIE, then everything else — the four short blocks live in
     .eright so the credits card can sit under THEM (Dan, Aug 4). */
  grid-template-columns: 2.2fr 4.6fr;
}
.eright {
  display: grid; gap: 12px 34px; align-items: start;
  grid-template-columns: 1.6fr .8fr 1.2fr 1fr;
}
.egroup { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.eghead {
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--accent); padding-bottom: 7px; margin-bottom: 1px;
  border-bottom: 1px solid var(--rule);
}
.ecol { display: flex; flex-direction: column; gap: 12px; }
/* .pair / .narrow were referenced by edit.html but never defined — the
   Work and BWV boxes stacked. Now they sit side by side, as the class
   name always claimed. */
.efields .pair { display: flex; gap: 14px; align-items: flex-end; }
.efields .pair input.narrow { flex: 0 0 108px; }
.efields label { display: block; }
.efields .kicker { display: block; margin-bottom: 5px; }
.efields .kicker .ok { color: var(--accent); font-weight: 400;
                       letter-spacing: .12em; }
.efields input, .efields textarea {
  width: 100%; background: transparent; color: var(--paper);
  border: 0; border-bottom: 1px solid var(--rule);
  font: inherit; font-size: 15px; padding: 7px 2px;
  transition: border-color var(--slow), color var(--slow);
}
.efields textarea { resize: vertical; line-height: 1.5; }
/* Read-only DERIVED value, dressed like an input without the invite.
   Full brightness (Dan, Aug 4): grey is reserved for machine PROPOSALS
   awaiting a human (D34). These are confirmed facts the system worked
   out — the dotted underline is what says "not yours to type". */
.efields .ro { display: block; font-size: 15px; padding: 7px 2px;
  color: var(--paper); border-bottom: 1px dotted var(--rule); }
.efields .ro.done { color: var(--accent); }

/* Published: the checkbox and its sentence on ONE row, no kicker —
   the sentence is the label (Dan, Aug 4). */
/* The three flags read as one cluster, not three fields (Dan, Aug 4).
   Negative margin pulls them inside the .egroup's 12px gap so they sit
   tighter to each other than to the boxes above and below. */
.efields label.pubbox {
  display: flex; align-items: center; gap: 10px;
  padding: 2px 2px; border-bottom: 1px dotted var(--rule);
}
.efields label.pubbox + label.pubbox { margin-top: -11px; }
.efields label.pubbox input { width: auto; flex: 0 0 auto; }
/* Grey until checked (Dan, Aug 4) — the state is readable from across
   the room, without reading a word. */
.efields label.pubbox em { font-size: 14px; color: var(--dim); }
.efields label.pubbox:has(input:checked) em { color: var(--paper); }

/* D39 — the third state: in development, not released */
.draftbadge { color: var(--accent); font-weight: 400;
  letter-spacing: .1em; text-transform: uppercase; }

/* D37 — "Multiple Paths": site chrome laid over the globe crop for
   films drawing on several Earth passes. Never baked into the WebP. */
.globewrap { display: inline-block; }
.globeimg { position: relative; display: inline-block; }
.globewrap .globelabel {
  position: absolute; left: 50%; top: 12%;
  transform: translateX(-50%);
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  white-space: nowrap; color: var(--paper);
  background: rgba(0, 0, 0, .55); padding: 3px 10px;
  border-radius: 999px; backdrop-filter: blur(2px);
}
.efields input:focus, .efields textarea:focus {
  outline: none; border-color: var(--paper); }
.efields input::placeholder, .efields textarea::placeholder {
  color: var(--ghost); }
/* proposed, not yet confirmed */
.efields input.prop { color: var(--dim); font-style: italic; }
.vname { display: block; margin-top: 5px; font-size: 11.5px;
         color: var(--dimmer); }

/* Five blocks want room. Step down rather than crush them. */
@media (max-width: 1700px) {
  .efields { grid-template-columns: 1.8fr 1.4fr 1fr; }
}
@media (max-width: 1200px) {
  .efields { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 900px) {
  .erow { grid-template-columns: 1fr; }
  .efields { grid-template-columns: 1fr; }
}

/* ---- musicians roster -------------------------------------------------- */
.murow { grid-template-columns: 90px 1fr; }
.mucount { text-align: center; padding-top: 8px; }
.nfilm { display: block; font-size: 26px; font-weight: 700;
         font-variant-numeric: tabular-nums; }
.nfilm.zero { color: var(--dimmer); }
.mudel .dec { margin-top: 8px; }

/* ---- tags & collections ------------------------------------------------ */
.collection-grid { padding-top: 28px; }

/* ---- shared row controls (.dec lives on in roster + sections) --------- */
.dec { display: flex; gap: 16px; margin-top: 10px; font-size: 12.5px;
       color: var(--dim); }
.dec label { display: flex; gap: 6px; align-items: center; cursor: pointer; }
.dec input { accent-color: var(--accent); }

.nothing { padding: 60px 0; color: var(--dim); }
.nothing a { border-bottom: 1px solid var(--dimmer); }

footer.foot {
  padding: 60px 40px; border-top: 1px solid var(--rule);
  color: var(--dimmer); font-size: 12px;
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
}

@media (max-width: 760px) {
  article.film, .more, .more-head { padding-left: 20px; padding-right: 20px; }
  .prose { margin-left: 0; }
}

/* ==========================================================================
   THE THEATER (graduated from stage.html's playground block, Aug 2 —
   the day the stage grammar became every listing page's grammar).
   Home / All Films / Season One / Bach / any collection: one stage,
   one card, one rail, one grid. Dan: "so we're not building one-offs."
   ========================================================================== */

/* ---- the stage ---- */
/* No margin-top: header.top is STICKY, so it already occupies its
   64px in flow — adding margin doubled the offset (the black band
   Dan caught, Aug 1). */
.stage { position: relative; overflow: hidden; background: var(--ink);
         height: min(56.25vw, 84vh);
         /* Teaser zoom (Dan, Jul 31): finished films carry a lower-left
            overlay that collides with the stage's own label. Scaling
            from the TOP-RIGHT crops out left and bottom. */
         --tz: 1.35;
         transition: height var(--slower); }
.stage-vid { position: absolute; inset: 0; }
.stage-vid iframe { position: absolute; top: 0; right: 0;
  width: 100vw; height: 56.25vw; border: 0;
  transform: scale(var(--tz)); transform-origin: top right;
  opacity: 0; transition: opacity var(--slower); }
.stage-vid iframe.live { opacity: 1; }
.stage-vid video { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity var(--slower); }
.stage-vid video.live { opacity: 1; }
.stage-poster { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0; transition: opacity var(--slower); }
.stage-poster.show { opacity: .55; }
/* The stage keeps its DARK veil in BOTH modes (Dan, Aug 2): a film
   should not sit on white. */
.stage-veil { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, rgba(10,11,13,.75), transparent 45%),
              linear-gradient(to right, rgba(10,11,13,.55), transparent 55%); }
/* Stage chrome pinned to the dark palette in light mode too. */
body.light #stageTop {
  --paper: #F2EFE9; --ink: #0A0B0D; --dim: #8B8880;
  --dimmer: #55534E; --accent: #E8A33D; }
.stage-lower { position: absolute; left: 5vw; bottom: 8vh;
  display: flex; align-items: center; gap: clamp(24px, 4vw, 64px); }
.stage-info { max-width: 44ch;
  display: flex; flex-direction: column; gap: 10px; }
.stage-port { width: clamp(120px, 16vw, 260px);
  height: clamp(120px, 16vw, 260px); flex: 0 0 auto;
  border-radius: 50%; object-fit: cover;
  border: 1px solid rgba(242, 239, 233, .45);
  opacity: 0; visibility: hidden;
  transition: opacity var(--slower), visibility var(--slower); }
.stage-port.show { opacity: 1; visibility: visible; }
.stage-info .kicker { color: var(--accent); }
.stage-title { font-size: clamp(30px, 4.4vw, 62px); line-height: 1.04;
  color: var(--paper); font-weight: 400; }
/* The view on the stage (Dan, Aug 6): the authored line under the
   title, serif like the room's voice, quiet against the footage. */
.stage-view { color: var(--paper); opacity: .92; font-size: 18px;
  letter-spacing: .01em; max-width: 44ch; }
.stage-meta { color: var(--dim); font-size: 14px; letter-spacing: .02em; }
/* The music line (Dan, Aug 2): the work's authored short form, serif
   like a concert program; bright after Dan's legibility call. */
.stage-music { color: var(--paper); font-size: 16px;
  font-style: italic; letter-spacing: .01em; }
/* The blurb below Watch (Dan, Aug 6): brief, quiet, readable over
   footage; vanishes cleanly when unwritten (D12). */
.stage-blurb { color: var(--prose); opacity: .88; font-size: 14.5px;
  line-height: 1.55; max-width: 46ch; margin-top: 16px; }
.stage-blurb:empty { display: none; }
.stage-watch .wt { color: var(--accent); margin-left: 4px; }
.stage-watch { align-self: flex-start; margin-top: 8px;
  padding: 10px 26px; border: 1px solid var(--paper); border-radius: 999px;
  color: var(--paper); text-decoration: none; font-size: 14px;
  letter-spacing: .14em; text-transform: uppercase;
  transition: background var(--slow), color var(--slow); }
.stage-watch:hover { background: var(--paper); color: var(--ink); }
.stage-dots { position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 22px; display: flex; gap: 12px; }
.stage-dots button { width: 8px; height: 8px; border-radius: 50%;
  border: 0; padding: 0; cursor: pointer; background: var(--dimmer);
  transition: background var(--slow), transform var(--slow); }
.stage-dots button.on { background: var(--paper); transform: scale(1.3); }

/* ---- the welcome: same room, lights up (home only) ---- */
.stage.welcome { height: calc(100vh - var(--headh)); }
.stage-wel { position: absolute; inset: 0; opacity: 0;
  visibility: hidden; pointer-events: none;
  transition: opacity var(--slower), visibility var(--slower); }
/* While welcoming, the whole room accepts the entering click (Dan,
   Aug 2); pointer-events retire with the welcome. */
.stage.welcome .stage-wel { opacity: 1; visibility: visible;
  pointer-events: auto; cursor: pointer; }
.stage.welcome .stage-lower, .stage.welcome .stage-dots {
  opacity: 0; visibility: hidden; }
.stage-lower, .stage-dots {
  transition: opacity var(--slower), visibility var(--slower); }
@keyframes welrise { from { opacity: 0; } to { opacity: 1; } }
.stage.welcome .wel-title {
  opacity: 0; animation: welrise 1400ms cubic-bezier(.22,.61,.36,1)
  900ms forwards; }
.stage.welcome .wel-brand {
  opacity: 0; animation: welrise 1400ms cubic-bezier(.22,.61,.36,1)
  1500ms forwards; }
.stage.welcome .wel-enter {
  opacity: 0; animation: welrise 1400ms cubic-bezier(.22,.61,.36,1)
  2100ms forwards; }
.wel-title { position: absolute; left: 7vw; top: 10vh;
  font-size: clamp(40px, 5.5vw, 84px); color: var(--paper);
  font-weight: 400; }
.wel-brand { position: absolute; left: 3vw; bottom: 6vh;
  display: flex; align-items: center; gap: 14px;
  color: var(--prose); font-size: 15px; line-height: 1.35; }
.wel-brand img { width: 74px; height: 74px; border-radius: 50%; }
/* Center stage (Dan, Aug 2): the ring waits where the eye rests. */
.wel-enter { position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%); text-align: center;
  pointer-events: auto; cursor: pointer; background: none;
  border: 0; color: var(--paper); }
.wel-enter .lbl { display: block; font-size: 12px;
  letter-spacing: .3em; margin-bottom: 12px; }
.wel-enter .ring { display: flex; align-items: center;
  justify-content: center; width: 64px; height: 64px; margin: 0 auto;
  border: 1px solid var(--aurora); border-radius: 50%;
  font-size: 18px; transition: box-shadow var(--slow),
  transform var(--slow); box-shadow: 0 0 18px rgba(99,223,124,.25); }
.wel-enter:hover .ring { transform: scale(1.08);
  box-shadow: 0 0 30px rgba(99,223,124,.45); }
/* With the body and footer hidden the welcome is EXACTLY one viewport
   — scroll restoration has nowhere to jump (the "black band", Aug 1).
   The body lives in #tbody since D30 (the marquee's swap target). */
.stage.welcome ~ #tbody { display: none; }
.stage.welcome ~ footer.foot { display: none; }
/* The curtain line: spoken once as the first film takes the stage. */
.stage-tag { position: absolute; left: 7vw; top: 8vh;
  font-size: clamp(30px, 3.3vw, 54px); color: var(--paper);
  font-weight: 400; opacity: 0; visibility: hidden;
  line-height: 1.22;
  transition: opacity var(--slower), visibility var(--slower); }
.stage-tag.show { opacity: .92; visibility: visible; }

/* ---- shelves and rails ---- */
.shelves { padding: 44px 5vw 80px; display: flex;
  flex-direction: column; gap: 52px; }
.shelf-head { display: flex; align-items: baseline; gap: 14px;
  margin-bottom: 16px; }
.shelf-label { font-size: 24px; color: var(--paper); }
/* Gold kicker before a home person-shelf's name (Dan, Aug 6):
   "Featured Musician: Brian Hoffman". */
.shelf-kick { color: var(--accent); margin-right: 2px; }
.shelf-note { color: var(--dim); font-size: 13px;
  letter-spacing: .04em; }
.rail { display: flex; gap: 18px; overflow-x: auto;
  scroll-snap-type: x proximity; padding-bottom: 8px;
  scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
/* The Featured shelf closes with a gold hairline (Dan, Aug 6) —
   curtain-edge between the staged picks and the taste shelves. The
   accent touches almost nothing (doc 02 §1), which is why one thin
   line is enough to mark the boundary. */
.shelf-featured { padding-bottom: 44px;
  border-bottom: 1px solid var(--accent); }
.shelf-featured .shelf-label { color: var(--accent); }
/* Person shelves wear their portrait (Dan, Aug 6): the '{Name} -
   Square' photo, square and unmasked — the circle is the stage's
   voice; the shelf hangs the photo like the covers, same frame
   language. Height matches the card thumb at its floor (300px
   card ≈ 169px thumb) so portrait and covers read as one row. */
.shelf-body { display: flex; gap: 18px; align-items: flex-start; }
.shelf-portrait { flex: 0 0 auto; aspect-ratio: 1;
  height: calc(var(--card-w) * 9 / 16);   /* = the thumb's height */
  width: auto; object-fit: cover; border-radius: 4px;
  border: 1px solid rgba(242, 239, 233, .16); }
.shelf-body .rail { flex: 1 1 auto; min-width: 0; }

/* ---- THE CARD (one size everywhere — Dan, Aug 2: the home card,
        "big and compelling"). --card-w is THE width; anything that
        must align with the cards (shelf portraits) derives from it. */
:root { --card-w: clamp(300px, 30vw, 440px); }
.ritem { flex: 0 0 auto; width: var(--card-w);
  scroll-snap-align: start; text-decoration: none; display: block; }
/* The frame (Dan, Aug 1): a quiet frame restores each cover as a
   hung work on the dark wall. */
.rthumb { display: block; aspect-ratio: 16 / 9; border-radius: 4px;
  background: var(--tile); position: relative; overflow: hidden;
  border: 1px solid rgba(242, 239, 233, .16);
  transition: transform var(--slow), opacity var(--slow),
              border-color var(--slow); }
.ritem:hover .rthumb { border-color: rgba(242, 239, 233, .34); }
.rthumb img { position: absolute; inset: 0; width: 100%;
  height: 100%; object-fit: cover; }
.ritem:hover .rthumb, .ritem.on .rthumb { transform: scale(1.03); }
.ritem.on .rthumb { outline: 1px solid var(--paper); outline-offset: 3px; }
.rthumb .dur { position: absolute; right: 8px; bottom: 8px;
  font-size: 11px; padding: 3px 8px; border-radius: 3px;
  background: var(--scrim); color: var(--paper); }
/* Position chip — ordered collections only (the ONE home of episode
   numbers, D27 complete): top-left, quiet. */
.rthumb .rpos { position: absolute; left: 8px; top: 8px;
  font-size: 11px; padding: 3px 8px; border-radius: 3px;
  background: var(--scrim); color: var(--paper); }
/* Label plate: the museum label under the artwork. Title left,
   m-number right (Dan, Aug 6) — the address on the label. */
.rt { display: flex; align-items: baseline; gap: 10px;
  margin-top: 12px; color: var(--prose);
  font-size: 14px; transition: color var(--slow); }
.rt-t { flex: 1 1 auto; min-width: 0; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.rid { flex: 0 0 auto; color: var(--dimmer); font-size: 11.5px; }
.ritem:hover .rt { color: var(--paper); }
/* The authored pair closing the plate (Dan, Aug 6): view — "what
   the film shows", italic, one line — then the brief blurb, two
   lines at most. Both optional (D12). */
.rv { display: block; margin-top: 4px; color: var(--dim);
  font-size: 13px; font-style: italic; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.rb { display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
  margin-top: 2px; color: var(--dimmer); font-size: 12px;
  line-height: 1.45; }
.rs { display: block; margin-top: 3px; color: var(--dim);
  font-size: 12.5px; }
.rx { display: block; margin-top: 2px; color: var(--dimmer);
  font-size: 12px; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
/* End-cap: the quiet door into the deep page. */
.rcap .rthumb { display: flex; align-items: center;
  justify-content: center; border: 1px solid var(--rule);
  background: transparent; }
.rcap-in { color: var(--dim); font-size: 17px;
  letter-spacing: .04em; transition: color var(--slow); }
.rcap:hover .rcap-in { color: var(--paper); }

/* ---- the theater grid: same card, wrapping (All Films, collections).
        minmax floor matches the card's clamp floor; cells breathe to
        the same max. ---- */
.tbody { padding: 44px 5vw 80px; }
.tgrid { display: grid; gap: 26px 18px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.tgrid .ritem { width: auto; }
/* Collection/section heading above a grid — same voice as shelf-head. */
.thead { display: flex; align-items: baseline; gap: 14px;
  margin-bottom: 22px; }
/* Collection tiles (D30 v5): the card frame wearing a collection's
   name — the veil keeps the serif legible over any cover. */
.ctile .ctile-name { position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center; text-align: center;
  padding: 12px; font-size: clamp(22px, 2.4vw, 34px);
  color: var(--paper);
  background: linear-gradient(to top, rgba(10,11,13,.66),
              rgba(10,11,13,.25)); }
/* Masthead search (D30 v5 — industry chrome convention): quiet until
   focused. Hidden on phones; the Arrange row's search serves there. */
.topsearch { margin-left: 18px; position: relative; }
/* The x inside the box — visible only when a term is in play. */
.qclear { position: absolute; right: 10px; top: 50%;
  transform: translateY(-50%); background: none; border: 0;
  color: var(--dim); font-size: 15px; cursor: pointer;
  padding: 0 2px; line-height: 1; }
.qclear:hover { color: var(--paper); }
.topsearch input { background: transparent;
  border: 1px solid var(--rule); border-radius: 999px;
  color: var(--prose); padding: 6px 26px 6px 14px; width: 150px;
  font-size: 12.5px; transition: width var(--slow),
  border-color var(--slow); }
.topsearch input:focus { width: 240px; outline: none;
  border-color: var(--dim); }
/* D31: the chrome search is THE search (the Arrange row died) — it
   stays on phones too, sized down. */
@media (max-width: 900px) { .topsearch input { width: 110px; } }


/* ---- EDIT FEATURED (D53, Aug 6 2026) — the stage-five desk --------
   All rules scoped under .fdesk (the D44 collision lesson). Source
   rail wears the cockpit's contact-sheet size; panel slots are
   larger, numbered, with quiet controls. */
.fdesk { padding: 0 40px 120px; }
.fdesk .frail {
  display: flex; gap: 8px; overflow-x: auto; overflow-y: hidden;
  padding: 12px 0 10px; margin-bottom: 30px;
  position: sticky; top: 0; z-index: 30;
  background: var(--ink); border-bottom: 1px solid var(--rule);
  scrollbar-width: thin;
}
.fdesk .fthumb {
  position: relative; flex: 0 0 118px; height: 66px; border-radius: 3px;
  background: var(--tile); overflow: hidden; display: block;
  cursor: pointer; transition: transform var(--slow);
}
.fdesk .fthumb:hover { transform: translateY(-2px); }
.fdesk .fthumb.picked {
  outline: 3px solid var(--accent); outline-offset: -3px;
  box-shadow: 0 0 0 2px var(--ink), 0 0 14px 2px rgba(232,163,61,.55);
  z-index: 1;
}
.fdesk .fthumb img { width: 100%; height: 100%; object-fit: cover;
  display: block; }
.fdesk .fgroup { margin: 34px 0; }
.fdesk .fghead { display: flex; align-items: baseline; gap: 14px;
  margin-bottom: 12px; }
.fdesk .fitems { display: flex; flex-wrap: wrap; gap: 16px; }
.fdesk .fitem { width: 200px; }
.fdesk .fslotthumb { position: relative; display: block;
  aspect-ratio: 16 / 9; border-radius: 3px; background: var(--tile);
  overflow: hidden; cursor: pointer;
  border: 1px solid rgba(242, 239, 233, .16); }
.fdesk .fslotthumb img { position: absolute; inset: 0; width: 100%;
  height: 100%; object-fit: cover; }
.fdesk .fitem:hover .fslotthumb { border-color: var(--accent); }
.fdesk .fpos { position: absolute; left: 6px; top: 5px;
  font-size: 12px; padding: 2px 7px; border-radius: 3px;
  background: var(--scrim); color: var(--accent); }
.fdesk .fitem .rbadge { left: auto; right: 6px; top: 5px; }
.fdesk .ftitle { display: block; margin-top: 6px; font-size: 12.5px;
  color: var(--prose); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }
.fdesk .fctl { display: flex; gap: 6px; margin-top: 4px; }
.fdesk .fctl button { background: transparent; color: var(--dim);
  border: 1px solid var(--rule); border-radius: 3px; cursor: pointer;
  font-size: 12px; padding: 1px 8px; }
.fdesk .fctl button:hover { color: var(--paper);
  border-color: var(--dim); }
.fdesk .fadd .fslotthumb { display: flex; align-items: center;
  justify-content: center; background: transparent;
  border: 1px dashed var(--rule); }
.fdesk .faddin { color: var(--dim); font-size: 30px; }
.fdesk .fadd:hover .faddin { color: var(--accent); }

/* ---- THE COCKPIT (Dan, Aug 4 2026 — D44) -----------------------------
   One film per page. The rail is the index and never re-renders on a
   field save; the visuals column is 3x the old thumbnail strip so the
   teaser and the film itself can actually be watched while editing.
   ALL rules here are scoped under .cockpit (Aug 6): the desk reuses
   the public .rail/.rthumb class names, and the un-scoped originals
   overrode THE CARD site-wide — every public thumbnail collapsed to
   117x66 (height 66 + the card's aspect-ratio). Scoping is the fence;
   never add un-scoped .rail/.rthumb rules below the card spec. */
.cockpit { padding: 0 40px 120px; }

.cockpit .rail {
  display: flex; gap: 8px; overflow-x: auto; overflow-y: hidden;
  padding: 12px 0 10px; margin-bottom: 22px;
  position: sticky; top: 0; z-index: 30;
  background: var(--ink); border-bottom: 1px solid var(--rule);
  scrollbar-width: thin;
}
.cockpit .rthumb {
  position: relative; flex: 0 0 118px; height: 66px; border-radius: 3px;
  background: var(--tile); overflow: hidden; display: block;
  /* Full brightness for every film (Dan, Aug 4) — the rail is a
     contact sheet, not a dimmed backdrop. The current film is marked
     by the gold frame alone, so that frame has to carry it. */
  transition: transform var(--slow), box-shadow var(--slow);
}
.cockpit .rthumb:hover { transform: translateY(-2px); }
.cockpit .rthumb.here {
  outline: 3px solid var(--accent); outline-offset: -3px;
  box-shadow: 0 0 0 2px var(--ink), 0 0 14px 2px rgba(232,163,61,.55);
  z-index: 1;
}
.cockpit .rthumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rnone { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; color: var(--tile-ink); font-size: 20px; }
.rbadge { position: absolute; left: 4px; top: 3px; font-size: 9.5px;
  letter-spacing: .06em; color: var(--accent); background: var(--scrim);
  padding: 1px 4px; border-radius: 2px; }
.rpips { position: absolute; right: 4px; bottom: 4px; display: flex; gap: 2px; }
.rpips i { width: 4px; height: 4px; border-radius: 50%;
  background: rgba(255,255,255,.28); }
.rpips i.on { background: var(--accent); }

.ckhead {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 30px; flex-wrap: wrap; margin: 0 0 22px;
}
.ckhead h2 { font-size: clamp(26px, 2.6vw, 40px); line-height: 1.05; }
.cknav { display: flex; gap: 10px; align-items: center; }
.ckbtn {
  font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
  padding: 8px 16px; border: 1px solid var(--rule); border-radius: 2px;
  color: var(--paper); transition: border-color var(--slow);
}
.ckbtn:hover { border-color: var(--paper); }
.ckbtn.off { opacity: .3; }
#savenote.good { color: var(--accent); }
#savenote.bad  { color: #ff6b6b; }

.ckbody { display: grid; grid-template-columns: 516px 1fr; gap: 34px;
  align-items: start; }

.visuals { display: flex; flex-direction: column; gap: 18px;
  position: sticky; top: 100px; }
/* Vimeo's own title, above the thumbnail — the identity check, not a
   field (Dan, Aug 4). The gold rule below it separates it from the
   three visuals, matching the rules between them. */
.vtitle { padding-bottom: 16px; border-bottom: 1px solid var(--accent); }
.vtitletext { font-size: 14px; line-height: 1.45; color: var(--paper); }
/* The m-number rides with the film's name — one address, D27. */
.ckhead h2 .ckid { color: var(--accent); }

.vthumb { position: relative; aspect-ratio: 16/9; border-radius: 3px;
  background: var(--tile); background-size: cover;
  background-position: center; }
.vthumb.empty::after { content: "\266A"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--tile-ink); font-size: 30px; }
.vdraft { position: absolute; right: 8px; top: 7px; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent);
  background: var(--scrim); padding: 2px 7px; border-radius: 2px; }
.vplayer video, .vplayer iframe {
  width: 100%; aspect-ratio: 16/9; border: 0; border-radius: 3px;
  background: #000; display: block;
}
.vlabel { font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--dim); margin-bottom: 6px; }
.vnone { aspect-ratio: 16/9; border: 1px dashed var(--rule);
  border-radius: 3px; display: flex; align-items: center;
  justify-content: center; color: var(--dimmer); font-size: 13px; }
/* Gold hairline between the three visuals (Dan, Aug 4) — thumbnail,
   teaser, film are three different KINDS of thing, not one stack. */
.visuals > .vplayer + .vplayer,
.visuals > .vtitle + .vplayer { border-top: 1px solid var(--accent);
  padding-top: 18px; }
/* ...but .vtitle already draws the rule beneath itself, so the first
   player must not double it. */
.visuals > .vtitle + .vplayer { border-top: 0; padding-top: 18px; }

/* The globe moved into the EARTH block, under the fields it stands on
   (Dan, Aug 4). Site chrome for the D37 label, never baked in. */
.eglobe { position: relative; margin-top: 6px; width: 168px; }
.eglobe img { width: 100%; display: block; }
.egmulti {
  position: absolute; left: 50%; top: 10%; transform: translateX(-50%);
  font-size: 9px; letter-spacing: .14em; text-transform: uppercase;
  white-space: nowrap; color: var(--paper);
  background: rgba(0,0,0,.55); padding: 2px 8px; border-radius: 999px;
}

/* A failed autosave stays visible until a later write succeeds. */
.efields input.failed, .efields textarea.failed {
  border-bottom-color: #ff6b6b; color: #ff6b6b;
}

@media (max-width: 1500px) {
  .ckbody { grid-template-columns: 420px 1fr; }
  .efields { grid-template-columns: 1fr; }
  .eright { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 1100px) {
  .ckbody { grid-template-columns: 1fr; }
  .visuals { position: static; }
}

/* The film's own end-credits card (F26) — a source to type from, laid
   under the short blocks where the space already was. Full width of
   columns 2..5; the MOVIE column stays tall with its caption box. */
.ecredits { grid-column: 1 / -1; margin-top: 22px; }
.ecredits img {
  width: 100%; max-width: 733px; display: block; margin-top: 10px;
  border: 1px solid var(--rule); border-radius: 3px;
}
.ecalts { margin-top: 8px; font-size: 11.5px; color: var(--dimmer); }
.ecalts a { color: var(--accent); margin-left: 8px; }
@media (max-width: 1200px) { .eright { grid-template-columns: 1fr; } }

/* The cover picker (F27) — candidate thumbnails under the card. Click
   is the save. The matcher gets the easy films; this gets the rest. */
.ecnone { padding: 26px; border: 1px dashed var(--rule); border-radius: 3px;
  color: var(--dimmer); font-size: 13px; text-align: center; }
.ecpick { margin-top: 16px; }
.ecrow { display: flex; gap: 10px; overflow-x: auto; padding: 10px 0 4px; }
.eccand {
  flex: 0 0 132px; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--dim); font: inherit; text-align: left;
  transition: color var(--slow);
}
.eccand img {
  width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block;
  border: 1px solid var(--rule); border-radius: 2px; opacity: .72;
  transition: opacity var(--slow), border-color var(--slow);
}
.eccand:hover img { opacity: 1; border-color: var(--dimmer); }
.eccand.on img { opacity: 1; border-color: var(--accent); border-width: 2px; }
.eccand.on { color: var(--accent); }
.eccand span {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 10.5px; line-height: 1.35; margin-top: 5px;
}

/* Teaser prep (D28 std op, in the cockpit Aug 4) — the facts Dan's
   Resolve Teaser Maker timeline needs, under the teaser player.
   Compact and mono: it is an instrument readout, not prose. */
.tpload { margin-top: 8px; font-size: 11.5px; color: var(--dimmer); }
.tprep { margin-top: 8px; font-size: 11.5px; line-height: 1.55;
  font-family: ui-monospace, "SF Mono", Menlo, monospace; }
.tprep .tpnone { color: var(--dimmer); }
.tppass { margin-bottom: 8px; }
.tphead { color: var(--paper); font-weight: 600; text-transform: uppercase;
  font-size: 10px; letter-spacing: .08em; }
.tphead span { text-transform: none; letter-spacing: 0;
  color: var(--paper); font-weight: 600; margin-left: 6px; }
.tprow { color: var(--dim); overflow-wrap: anywhere; }
.tprow b { color: var(--paper); font-weight: 600; }
.tpk { display: inline-block; min-width: 62px; color: var(--dimmer); }
.tpwarn { color: var(--accent); margin-left: 6px; }
.tpdim { color: var(--dimmer); margin-left: 6px; font-size: 12px; }
.tpsum { margin-top: 0; }
.tpsum code { color: var(--paper); background: none; font-size: 11px; }
.tpub { font: inherit; font-size: 11px; color: var(--accent);
  background: none; border: 1px solid var(--accent); border-radius: 3px;
  padding: 3px 10px; cursor: pointer; transition: opacity var(--slow); }
.tpub:hover { opacity: .8; }
.tpub:disabled { color: var(--dimmer); border-color: var(--dimmer);
  cursor: default; }
