  /* ══════════════════════════════════════════════════════════════════════════
     FRAME.IO / TIMELINER SHAPE (Chaz, 2026-10-05: "i feel like the studio
     hasnt been updated? its meant to be like frame.io/timeliner.io" and "it
     should also have the library with SOP's etc in the sidebar")
     ══════════════════════════════════════════════════════════════════════════
     What the next section describes (a kanban of thumbnail cards, then a
     project page) is still the shape; this is what was changed on top of it:

       THE SIDEBAR  a permanent left rail (#side): Your work, What you're
                    owed, Start here, and the Library's docs listed in place.
                    A doc opens in the main area (#library=<id>, SCREEN 3).
                    Under 900px it slides in behind the Menu button.
       THE TILES    a card is a media tile — a 16:10 poster at the column's
                    full width, an intentional placeholder when there is no
                    cut, a version pill, a status pill, "N new notes". All
                    six columns stay on screen at 1440 and 1920 (the board
                    screen lifts the page's width cap; posters scale with the
                    column); only under ~1360px does the board scroll.
       THE GRID     the same cards as Frame.io's asset grid; Board/Grid is
                    remembered per viewer (localStorage, try/catch).
       THE PLAYER   the project screen is the review player, in the Studio:
                    video centre, comments right, a marker per comment on the
                    timeline, v1/v2 switcher, compare, draw, upload next
                    version. It is public/review-player.js — the SAME module
                    review-studio.html and cut.html mount — so this file holds
                    no second copy of any comment/drawing/timecode logic;
                    the markup and CSS below are that module's mount surface
                    in this page's tokens.

     Access is untouched: owner + assigned editors only (studioRole below),
     no migration, no new route. Graded by scripts/verify-studio-frameio.js. */
  /* ══════════════════════════════════════════════════════════════════════════
     STUDIO = KANBAN OF PROJECTS (goal 2026-09-25-after-rehearsal.md §3 Unit C)
     ══════════════════════════════════════════════════════════════════════════

     Chaz, verbatim, 2026-09-25 (the live rehearsal): "the editor portal is
     clunky too and doesnt match the UI from the warroom... it should
     basically be a projects view with proper thumbnails and thats it, then
     when you click into the project thumbnail it opens another project view
     of the specific project and you can see the brief panel and other client
     specific information" — then "inside the one project there is the
     moodboard also. but all of the studio should be kanban focused". Measured
     at that rehearsal: the card sat in BRIEFED while the Board said EDIT;
     nothing on the card flagged a new client note; "What you are owed", the
     brand-kit grid and the media form filled one long scrolling page.

     THIS FILE REPLACES THAT LONG PAGE WITH TWO SCREENS, hash-routed so either
     is a real, linkable URL under /studio (server.js already serves this
     file at that address — no route was added for the routing itself):

       /studio             — SCREEN 1, the board: a kanban of THIS editor's
                              own assigned pieces as thumbnail cards, nothing
                              else on the page (earnings moved to a small
                              header link).
       /studio#piece=<id>  — SCREEN 2, the project page for one piece: brief,
                              the client's brand-kit facts, the cut player +
                              versions + upload, "Open review", the mood
                              board, the piece's own notes thread.

     EVERY DOOR THIS SCREEN CALLS ALREADY EXISTED BUT ONE. GET
     /api/calendar/plan/:id (routes/calendar.js, added THIS unit, beside its
     PATCH/DELETE siblings) is the one new route — a single piece read for a
     scoped editor login, gated by the SAME access.mayOpenReviewDoor every
     other piece door on this page already uses. Nothing else was added:
     the kanban board, brand kit, media versions/upload, notes and mood board
     all read through doors E1/B1/B2/S1/N-notes/M-moodboard already built.

     ── THE THREE RULES THIS PAGE IS STILL NOT ALLOWED TO BREAK (E1's own) ──
     1. A STAGE IS DERIVED, NEVER STORED (KANBAN-PLAN.md §3). This file holds
        no list of stage names as the SOURCE of which column a card sits in —
        every card's column is exactly the server's own stages[].key from GET
        /api/kanban/board, read fresh every load. STAGE_META below is a
        PRESENTATION table only (a label + a colour per key, matching
        public/index.html's own STAGE_META almost verbatim, on purpose — "the
        same look as the WarRoom") — it never decides a card's column, and an
        unknown key still renders (with a neutral pill), it is never dropped.
     2. AN EDITOR SEES THEIR WORK, NOT THEIR CLIENT'S. Every board fetch still
        carries `assigned_to=me`. Unchanged from E1 — see flattenAssignedPieces
        below, kept byte-identical, including its own comment, because it is a
        named anchor scripts/verify-editor-hub.js's mutation proof depends on.
     3. MEDIA GOES THROUGH S1'S DOOR AND NO OTHER — the upload legs
        (sendFile, capturePosterBlob) are carried over unedited in spirit:
        mint a grant, PUT to the URL the grant gave, settle, attach.

     ── WHAT MOVED, AND WHY ──────────────────────────────────────────────────
     "What you are owed" -> a small header link that opens a modal (same
     GET /api/editor-pay/me, same total_cents rendered verbatim, never
     re-summed here — E1c's own rule). The full brand-kit field dump -> a
     compact facts card (colours/fonts/logo-presence only) on the project
     page, because "the client's details the editor needs" is what Chaz asked
     for, not every stored field. The always-visible Media form -> the
     project page, keyed to the ONE open piece — no picker at all now (fix
     round 1): the piece is already known the moment this screen is open, so
     a control re-naming it would be a control with one option nobody needs
     to choose.

     BOTH NOTES THREADS ARE ON THE PROJECT PAGE (fix round 1, restoring
     Chaz's own 2026-09-23 decision: "THERE SHOULD BE CLIENT NOTES AND ALSO
     SEPERATE PIECE (PROJECT) NOTES"). The first cut of this rewrite dropped
     the client-wide thread, reasoning it had "no piece to hang off" — that
     was wrong: the project page already has a client (the piece's own
     client_id), so the client thread hangs off THAT, next to the brand-kit
     facts card it is about, labelled "Client notes" apart from "This
     piece's notes" lower down. See mountEditorClientNotes/
     mountEditorPieceNotes below.

     ── STILL OWNER + EDITOR ONLY (Unit H1) ──────────────────────────────────
     studioRole/showRefused/the whole gate are carried over unedited — access
     rules are explicitly unchanged by this unit's own brief (constraint 5).

     ── THE LOOK — THE WARROOM'S OWN TOKENS, NOT A SECOND PALETTE ───────────
     The neutral ladder, ink and jewel-accent values below are copied
     VERBATIM from public/index.html's own `:root` (the WarRoom shell,
     PR #89's card/pill patterns) — read from that file, not re-invented —
     so a colour changed there and copied here is the ONLY drift risk, never
     two independently-chosen palettes rendering two different "dark blues".
     index.html cannot itself be edited by this unit (PR #89 just merged, a
     different unit owns it), so this is a presentation copy of its tokens,
     the same shape STAGE_META above already is for stage colours — not a
     shared stylesheet file, because creating one that only THIS page linked
     to would not be "one set of tokens" either; copying the values verbatim
     is the smallest true thing available without editing index.html. */
  /* The colour ladder, Syne and the body gradient come from /brand-theme.css (ONE
     spelling, linked in <head>) — this page used to carry a verbatim copy. */
  :root { --gut:16px; }
  * { box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
  html,body { margin:0; padding:0; }
    body { line-height:1.5; color-scheme:dark; }
  h1,h2,h3,h4 { margin:0; }
  a { color:var(--fg2); }
  .wrap { max-width:1280px; margin:0 auto; padding:0 var(--gut) 56px; }
  [hidden] { display:none !important; }

  /* ══════════════════════════════════════════════════════════════════════
     THE SHELL — A PERMANENT LEFT SIDEBAR (Chaz, 2026-10-05: "its meant to be
     like frame.io/timeliner.io" and "it should also have the library with
     SOP's etc in the sidebar"). The glass recipe below is index.html's own
     #war-rail rule, copied (not re-invented) for the same reason this
     file's :root is: one look. At 900px and under there is no room for a
     208px rail, so it slides in behind a Menu button instead. */
  #side { position:fixed; left:0; top:0; bottom:0; width:232px; z-index:60; display:flex; flex-direction:column;
          gap:2px; padding:16px 8px; overflow-y:auto; overscroll-behavior:contain;
          background-color:var(--l0);
          background-image:radial-gradient(240px 220px at 18% 8%,rgba(255,255,255,.10) 0%,rgba(255,255,255,0) 70%),
            radial-gradient(320px 320px at 85% 92%,rgba(255,255,255,.06) 0%,rgba(255,255,255,0) 70%),
            linear-gradient(180deg,rgba(255,255,255,.08) 0%,rgba(255,255,255,.04) 50%,rgba(0,0,0,.08) 100%);
          -webkit-backdrop-filter:var(--glass-blur-lg); backdrop-filter:var(--glass-blur-lg);
          border-right:1px solid var(--line-soft); }
  #side .side-brand { padding:2px 10px 14px; }
  #side .side-title { font-family:var(--serif); font-size:var(--t-lg); font-weight:600; letter-spacing:-.01em; }
  #side .navbtn { width:100%; display:flex; align-items:center; gap:10px; text-align:left; border-radius:var(--r1);
                  border:1px solid rgba(255,255,255,.09); background:rgba(255,255,255,.06); color:var(--fg2);
                  padding:8px 10px; font-size:var(--t-sm); box-shadow:inset 0 1px 0 rgba(255,255,255,.10); }
  #side .navbtn:hover { background:rgba(255,255,255,.11); border-color:rgba(255,255,255,.16); color:var(--fg); }
  #side .navbtn[hidden] { display:none; }
  #side .navbtn.active { color:var(--fg); font-weight:500; background:rgba(255,255,255,.17); border-color:var(--jw-line);
                         box-shadow:inset 0 1px 0 rgba(255,255,255,.24),inset 2px 0 0 var(--jade); }
  #side .navbtn svg { width:16px; height:16px; stroke:currentColor; fill:none; stroke-width:1.8; stroke-linecap:round;
                      stroke-linejoin:round; flex-shrink:0; }
  #side .navlabel { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  #side .navsep { font-size:var(--t-mi); font-weight:500; letter-spacing:.16em; text-transform:uppercase; color:var(--fg4);
                  padding:16px 10px 6px; }
  #side .libgroup-title { font-size:var(--t-mi); letter-spacing:.12em; text-transform:uppercase; color:var(--fg4);
                          font-weight:700; padding:8px 10px 3px; }
  #side .libdoc { width:100%; text-align:left; background:transparent; border:1px solid transparent; border-radius:var(--r1);
                  color:var(--fg2); padding:6px 10px; font-size:var(--t-sm); display:block; overflow:hidden;
                  text-overflow:ellipsis; white-space:nowrap; }
  #side .libdoc:hover { background:rgba(255,255,255,.08); color:var(--fg); }
  #side .libdoc.active { background:rgba(255,255,255,.14); color:var(--fg); border-color:var(--jw-line); }
  #side .libempty { color:var(--fg4); font-size:var(--t-xs); padding:4px 10px; }
  #side-scrim { display:none; }
  #menu-btn { display:none; }
  .main { margin-left:232px; min-width:0; }
  @media (max-width:900px) {
    .main { margin-left:0; }
    #side { transform:translateX(-102%); visibility:hidden; transition:transform .18s ease, visibility 0s linear .18s; width:min(280px,84vw); z-index:70; }
    #side.open { transform:none; visibility:visible; transition:transform .18s ease; }
    #side-scrim { position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:65; }
    #side.open ~ #side-scrim { display:block; }
    #menu-btn { display:inline-flex; align-items:center; gap:7px; }
  }

  header.top { padding:18px var(--gut) 14px; border-bottom:1px solid var(--line-soft); }
  header.top .inner { max-width:1280px; margin:0 auto; display:flex; align-items:flex-end;
                      justify-content:space-between; gap:14px; flex-wrap:wrap; }
  .eyebrow { font-size:var(--t-xs); letter-spacing:.22em; text-transform:uppercase;
             color:var(--fg4); font-weight:600; }
  h1.pagetitle { font-weight:500; font-size:24px; line-height:1.1; margin:4px 0 0; }
  .who { text-align:right; font-size:var(--t-sm); color:var(--fg4); display:flex; align-items:center; gap:10px; flex-wrap:wrap; justify-content:flex-end; }
  .who b { color:var(--fg2); font-weight:600; }
  .headerlink { background:none; border:1px solid var(--line); color:var(--fg2); font:inherit;
                font-size:var(--t-sm); cursor:pointer; border-radius:20px; padding:5px 12px; }
  .headerlink:hover { border-color:var(--line-strong); color:var(--fg); }

  button { font:inherit; font-size:var(--t-xs); font-weight:600; letter-spacing:var(--btn-tracking); text-transform:uppercase; cursor:pointer;
           border-radius:var(--btn-radius); border:1px solid var(--bt-cream);
           background:rgba(36,36,36,.27); color:var(--fg); padding:7px 16px; }
  button:hover { background:var(--l4); color:var(--fg); }
  /* Cards and library entries are CONTENT, not actions: normal case, normal tracking (the website's small-caps pill is for buttons that DO something). */
  button.card, #side .libdoc { text-transform:none; letter-spacing:normal; font-weight:400; font-size:var(--t-bd); }
  #side .libdoc { font-size:var(--t-sm); }
  button.primary { background:var(--jw); border-color:var(--jw-edge); color:var(--jw-ink); font-weight:600; }
  button.primary:hover { background:var(--jw-hi); }
  button:disabled { opacity:.45; cursor:not-allowed; }
  input, select { font:inherit; background:var(--l1); color:var(--fg); border:1px solid var(--line);
                  border-radius:var(--r1); padding:8px 10px; width:100%; }
  label { display:block; font-size:var(--t-xs); text-transform:uppercase; letter-spacing:.12em;
          color:var(--fg4); font-weight:600; margin:0 0 5px; }

  section.panel { margin-top:24px; }
  .panel-head { display:flex; align-items:baseline; justify-content:space-between; gap:12px;
                margin-bottom:10px; flex-wrap:wrap; }
  .panel-note { font-size:var(--t-sm); color:var(--fg4); max-width:72ch; }
  .empty { color:var(--fg4); font-size:var(--t-sm); padding:6px 2px; }

  .tag { font-size:var(--t-mi); letter-spacing:.04em; color:var(--fg3); background:var(--l3);
         border:1px solid var(--line-soft); border-radius:4px; padding:1px 5px; white-space:nowrap; }
  .tag.stagepill { font-weight:700; background:transparent; }
  .tag.vbadge { color:var(--fg2); font-weight:700; }
  /* IN-HOUSE (2026-10-06) — Combe's own content, labelled wherever a brand name shows. */
  .tag.inhouse { color:var(--fg2); border-color:var(--line-strong); font-weight:500; text-transform:uppercase; letter-spacing:.08em; }
  /* The owner's own stage move ("Move it on") on a piece he took. */
  #proj-owner-move { display:flex; align-items:center; gap:8px; margin-top:8px; }
  #proj-owner-move[hidden] { display:none; }
  #proj-owner-move select { min-height:34px; }

  /* ── SCREEN 1 — THE BOARD, THUMBNAIL CARDS, NOTHING ELSE ─────────────── */
  /* fix round 1 — the EDIT column (and anything past it) was cut off at the
     right edge at 1440px with no VISIBLE cue that there was more to scroll
     to. `.board` already scrolled (overflow-x:auto), but an OS/browser's own
     scrollbar can render thin or overlay-hidden until hovered — real, but
     not a "clear cue" a screenshot or a glance actually shows. `.board-wrap`
     is the scroll container's own parent, `position:relative` so the fade
     can sit over its right edge; the fade+label are shown/hidden by
     updateBoardScrollCue() (below), driven by the board's real scrollWidth/
     scrollLeft/clientWidth — never a fixed guess at how many columns fit. */
  .board-wrap { position:relative; }
  .board { display:flex; gap:12px; overflow-x:auto; padding-bottom:20px; align-items:flex-start; }
  .board-fade { position:absolute; top:0; right:0; bottom:0; width:88px; pointer-events:none;
                background:linear-gradient(to right, transparent, var(--l0) 70%);
                display:flex; align-items:flex-start; justify-content:center; padding-top:56px; }
  .board-fade span { font-size:var(--t-xs); letter-spacing:.03em; color:var(--fg3); white-space:nowrap; }
  /* ALL SIX COLUMNS VISIBLE, POSTERS THAT SCALE WITH THEM (Chaz, via QC, 2026-10-05).
     "Changes asked" is the column an editor acts on; it must never sit off-screen.
     So on the board screen the page's 1280px cap is lifted (the :has() rule just
     below), the six columns share the whole width (flex:1 1 0) and each card's
     poster is the column's width — ~170px at 1440, ~250px at 1920. The 180px floor
     is what keeps a poster legible: under ~1360px of window there is no room for
     six columns at 180px, and only then does the board scroll sideways, with the
     existing fade + "Scroll for more" cue (updateBoardScrollCue, below). The Grid
     view is the big-tile view. Below 760px the columns stack vertically. */
  .wrap:has(#screen-board:not([hidden])) { max-width:none; padding-left:12px; padding-right:12px; }
  .board { gap:8px; }
  /* YOUR JOBS (editors plan, phase 3): the same cards read by JOB - one tile per listing or shoot, every video of it listed, a tap opens it.
     Drawn by public/studio-jobs.js from the board's own cards (job_id / job_label). Every video row is a real tap target (>= 44px). */
  .jobs { margin:0 0 14px; }
  .jobs-h { font-size:var(--t-sm); font-weight:600; color:var(--fg2); letter-spacing:.06em; text-transform:uppercase; margin:0 0 8px; }
  .jobs-list { display:grid; grid-template-columns:repeat(auto-fill, minmax(min(100%, 300px), 1fr)); gap:10px; }
  .job { background:var(--l2); border:1px solid var(--line); border-radius:var(--r1); padding:12px; min-width:0; }
  .job-t { font-size:var(--t-md); font-weight:600; color:var(--fg); overflow-wrap:anywhere; }
  .job-m { font-size:var(--t-sm); color:var(--fg3); margin:2px 0 8px; }
  .job-videos { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px; }
  .job-video { width:100%; min-height:44px; display:flex; align-items:center; justify-content:space-between; gap:10px; text-align:left; background:var(--l3); color:var(--fg);
               border:1px solid var(--line-soft); border-radius:var(--r1); padding:8px 12px; font:inherit; font-size:14px; cursor:pointer; }
  .job-video:hover { border-color:var(--line-strong); }
  .job-video .jv-t { min-width:0; overflow-wrap:anywhere; }
  .job-video .jv-s { flex:0 0 auto; }
  .col { flex:1 1 0; min-width:180px; background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r2);
         padding:6px; box-shadow:var(--edge),var(--e1); }
  .col-head { display:flex; align-items:center; justify-content:space-between; gap:8px;
              font-size:var(--t-xs); letter-spacing:.16em; text-transform:uppercase;
              color:var(--fg4); font-weight:700; margin-bottom:9px; }
  .col-n { background:var(--l3); color:var(--fg2); border-radius:20px; padding:1px 8px;
           font-size:11px; letter-spacing:0; }
  .card { background:var(--l2); border:1px solid var(--line); border-radius:var(--r1);
          padding:0; margin-bottom:8px; box-shadow:var(--edge),var(--e1); cursor:pointer;
          text-align:left; width:100%; color:var(--fg); overflow:hidden; }
  .card:last-child { margin-bottom:0; }
  .card:hover { border-color:var(--line-strong); box-shadow:var(--edge),var(--e-hover); }
  .card:focus-visible { outline:2px solid var(--jw); outline-offset:1px; }
  /* THE MEDIA TILE (Frame.io). The poster is the card: a 16:10 frame that is
     always at least the column's width, never a 118px strip. A portrait poster
     (a 9:16 reel) is shown whole on the dark frame rather than cropped to a
     landscape slice, so the editor sees the real composition; fillPosters sets
     data-orient on the tile once the image knows its own shape. */
  .card-thumb { position:relative; width:100%; aspect-ratio:16/10; background:var(--l0); overflow:hidden; }
  .card-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
  .card-thumb[data-orient="portrait"] img { object-fit:contain; }
  .card-thumb .placeholder { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:8px;
                             width:100%; height:100%; color:var(--fg4); font-size:var(--t-xs); letter-spacing:.1em;
                             text-transform:uppercase;
                             background:linear-gradient(135deg,var(--l3),var(--l1)); }
  .card-thumb .ph-mark { display:flex; align-items:center; justify-content:center; width:54px; height:54px; border-radius:50%;
                         background:var(--l4); border:1px solid var(--line); color:var(--fg); font-family:var(--serif);
                         font-size:var(--t-lg); font-weight:600; letter-spacing:.02em; }
  .card-thumb .ph-type { display:flex; align-items:center; gap:6px; }
  .card-thumb .ph-type svg { width:15px; height:15px; stroke:currentColor; fill:none; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
  .card-thumb .typechip { position:absolute; left:8px; bottom:8px; background:rgba(0,0,0,.62); color:var(--fg);
                          border-radius:20px; padding:2px 8px; font-size:10px; font-weight:700; letter-spacing:.08em;
                          text-transform:uppercase; }
  .card-badge { position:absolute; top:8px; right:8px; min-width:18px; height:20px; padding:0 8px;
                border-radius:20px; background:var(--bad); color:#3A0A10; font-size:11px; font-weight:800;
                display:flex; align-items:center; justify-content:center; line-height:1; white-space:nowrap;
                box-shadow:0 1px 3px rgba(0,0,0,.5); }
  .card-body { padding:9px 10px 10px; }
  .card .t { font-size:var(--t-bd); line-height:1.32; font-weight:500; }
  .card .pillrow { display:flex; align-items:center; gap:6px; margin-top:6px; flex-wrap:wrap; }
  .card .meta { font-size:var(--t-xs); color:var(--fg4); margin-top:6px; display:flex; gap:7px; flex-wrap:wrap; }
  /* the one-line "what do I do now" — every card carries it (S2c) */
  .card .nextstep { font-size:var(--t-xs); color:var(--fg3); margin-top:6px; font-weight:600; }
  @media (max-width:760px) {
    .board { flex-direction:column; }
    .col { flex:1 1 auto; width:100%; }
    .board-fade { display:none; } /* the board stacks vertically here — nothing to scroll horizontally to */
  }

  /* ── BOARD / GRID TOGGLE (Frame.io's asset grid) ─────────────────────────
     Same pieces, same renderCard(), a different arrangement: the grid drops
     the six columns and lays every card out as a responsive thumbnail grid,
     the stage showing on each card's own status pill. The choice is kept per
     viewer in localStorage (studio_view), wrapped in try/catch — a private
     window just always opens on the board. */
  .viewtoggle { display:inline-flex; border:1px solid var(--line); border-radius:20px; overflow:hidden; }
  .viewtoggle button { border:0; border-radius:0; background:transparent; padding:5px 14px; font-size:var(--t-sm); color:var(--fg3); }
  .viewtoggle button[aria-pressed="true"] { background:var(--l4); color:var(--fg); font-weight:600; }
  .board.is-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(250px,1fr)); gap:14px; overflow-x:visible; align-items:start; }
  .board.is-grid .card { margin-bottom:0; }
  .board.is-grid .card-thumb { aspect-ratio:16/10; }

  /* ── SCREEN 2 — THE PROJECT PAGE ──────────────────────────────────────── */
  /* THE NEXT STEP BAR (S2c) — one line, top of the page, "what do I do now".
     Same fact the card's own .nextstep line carries, never a second answer
     (kanban.nextStepFor is the one spelling; both read the server's text). */
  .nextbar { display:flex; align-items:center; gap:8px; background:var(--l2); border:1px solid var(--line-soft);
             border-radius:var(--r2); padding:10px 14px; margin-top:12px; font-size:var(--t-sm); font-weight:600; }
  .nextbar .k { text-transform:uppercase; letter-spacing:.1em; font-size:10px; color:var(--fg4); font-weight:700; }
  .projhead { display:flex; align-items:flex-start; justify-content:space-between; gap:14px; flex-wrap:wrap; margin-top:6px; }
  .projhead .titles { display:flex; flex-direction:column; gap:6px; }
  .projhead h2 { font-size:20px; }
  .backlink { background:none; border:none; color:var(--fg4); font:inherit; font-size:var(--t-sm);
              cursor:pointer; padding:0; margin-bottom:8px; display:inline-flex; align-items:center; gap:5px; }
  .backlink:hover { color:var(--fg); }
  /* THE JOB PAGE (editors plan, phase 4): ONE column of sections in a fixed order, each thing once. Every section is a .jsec; there is no jump bar and no
     two-column grid, so the page reads the same on a phone and a desktop. */
  .jsec { margin-top:14px; }
  .jsec > h3 { font-size:var(--t-md); margin-bottom:8px; }
  .jh4 { font-size:var(--t-xs); text-transform:uppercase; letter-spacing:.1em; color:var(--fg4); margin:14px 0 6px; }
  .jh4:first-of-type { margin-top:4px; }
  #job-due { margin-top:6px; }
  .dueline { display:flex; align-items:baseline; gap:8px 14px; flex-wrap:wrap; margin-top:12px; font-size:var(--t-sm); }
  .dueline .k { text-transform:uppercase; letter-spacing:.1em; font-size:10px; color:var(--fg4); font-weight:700; }
  .dueline #proj-due { font-weight:600; color:var(--fg); }
  #job-videos { margin-top:12px; }
  #job-videos .k { text-transform:uppercase; letter-spacing:.1em; font-size:10px; color:var(--fg4); font-weight:700; margin-bottom:6px; }
  .jobvideos { display:flex; flex-wrap:wrap; gap:8px; }
  .jobvideo { display:flex; flex-direction:column; align-items:flex-start; gap:2px; text-align:left; min-height:44px; padding:6px 14px; border-radius:var(--r2);
              background:var(--l3); border:1px solid var(--line); color:var(--fg2); max-width:100%; }
  .jobvideo .jv-t { font-weight:600; overflow-wrap:anywhere; }
  .jobvideo .jv-d { font-size:var(--t-xs); color:var(--fg4); }
  .jobvideo.current { border-color:var(--line-strong); background:var(--l4); color:var(--fg); cursor:default; }
  /* the brief section carries no card of its own: the editor brief draws its own cards, and the written brief is plain text */
  #job-brief.jsec { background:none; border:0; box-shadow:none; padding:0; }
  #job-brief.jsec > h3 { margin-bottom:6px; }
  #job-music .eb-block { background:none; border:0; padding:0; margin:0; }
  a.btnlink { display:inline-flex; align-items:center; justify-content:center; min-height:44px; padding:0 20px; border-radius:var(--r2); border:1px solid var(--line-strong);
              background:var(--l3); color:var(--fg); text-decoration:none; font-weight:600; font-size:var(--t-sm); }
  a.btnlink:hover { background:var(--l4); }
  /* the cut section draws no card of its own: the player and the thread are cards already, and a padded frame would squeeze the video on a phone */
  #job-cut.jsec { background:none; border:0; box-shadow:none; padding:0; }
  #job-cut.jsec > h3 { margin-bottom:6px; }
  /* COMBE'S REVIEW CARD (phase 5): the same card as the upload card, with a note box and two buttons that stack on a phone */
  /* THE OWNER IS REVIEWING (editor-review-panel.js sets .reviewing while his Approve & send / Send back card is up): the cut and his two buttons come FIRST, straight under the
     title, not after the brief, the footage folder and the checklists (loop-rest, 10 Nov 2026). Every other section keeps its fixed order, after them. */
  #screen-project.reviewing:not([hidden]) { display:flex; flex-direction:column; }
  #screen-project.reviewing > * { order:5; }
  #screen-project.reviewing > #proj-back { order:0; align-self:flex-start; }
  #screen-project.reviewing > #job-due { order:1; }
  #screen-project.reviewing > #job-cut { order:2; }
  .upcard .sendrow { margin-top:12px; }
  .upcard .sendrow button { min-height:44px; padding:0 20px; }
  .reviewcard { margin-top:14px; background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r2); padding:14px; box-shadow:var(--edge),var(--e1); }
  .reviewcard textarea { width:100%; min-height:72px; padding:8px; background:var(--l1); color:var(--fg); border:1px solid var(--line); border-radius:var(--r1); font:inherit; resize:vertical; }
  .reviewcard .revtell { display:flex; align-items:center; gap:12px; min-height:44px; margin-top:10px; cursor:pointer; color:var(--fg); font-weight:600; }
  .reviewcard .revtell[hidden] { display:none; }
  .reviewcard .revtell input { width:22px; height:22px; flex:none; margin:0; cursor:pointer; accent-color:var(--accent, #3d7bf7); }
  .reviewcard .revtell small { display:block; font-weight:400; font-size:var(--t-sm); color:var(--fg2); }
  .reviewcard .revbtns { display:flex; gap:10px; flex-wrap:wrap; margin-top:12px; }
  .reviewcard .revbtns button { min-height:44px; padding:0 20px; }
  /* on a phone the two buttons sit SIDE BY SIDE and the note box is short, so both are on screen under the title without scrolling (loop-rest, 10 Nov 2026) */
  @media (max-width:600px) { .reviewcard .revbtns button { flex:1 1 140px; padding:0 10px; } .reviewcard textarea { min-height:52px; } }
  #rev-say { margin-top:8px; font-size:var(--t-sm); min-height:19px; }
  #rev-say.err { color:var(--bad-fg); }
  .upcard { margin-top:14px; background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r2); padding:14px; box-shadow:var(--edge),var(--e1); }
  /* THE VIEWER — Frame.io / Timeliner layout (2026-10-05): the cut in the
     middle, the comments on the right, the timeline under the video. Every id
     inside it (#stagewrap, #player, #draw, #seek, #thread, #body, ...) is the
     review player's own mount surface (public/review-player.js, the ONE
     player — review-studio.html and cut.html mount the same module); the CSS
     below is its stylesheet in this page's dark tokens. */
  .viewer { display:grid; grid-template-columns:minmax(0,1fr) 380px; gap:14px; margin-top:14px; align-items:start; }
  @media (max-width:1100px) { .viewer { grid-template-columns:1fr; } }
  .vpanel { background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r2); overflow:hidden;
            box-shadow:var(--edge),var(--e1); }
  .vhead { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;
           padding:10px 14px; border-bottom:1px solid var(--line-soft); }
  .vhead h3 { font-size:var(--t-sm); letter-spacing:.1em; text-transform:uppercase; color:var(--fg4); font-weight:700; }
  .vbody { padding:12px 14px; }
  .versionbar { display:flex; gap:6px; flex-wrap:wrap; align-items:center; }
  .vchip { border-radius:20px; padding:4px 13px; font-size:var(--t-sm); font-weight:600; }
  .vchip[aria-pressed="true"] { background:var(--jw); color:var(--jw-ink); border-color:var(--jw-edge); }
  .vchip .cur { font-size:9px; letter-spacing:.08em; text-transform:uppercase; margin-left:6px; opacity:.75; }
  #stagewrap { position:relative; background:#000; border-radius:var(--r2); overflow:hidden; display:flex;
               align-items:center; justify-content:center; min-height:240px; }
  #player { display:block; max-width:100%; max-height:62vh; background:#000; }
  #draw { position:absolute; inset:0; width:100%; height:100%; touch-action:none; }
  #draw.armed { cursor:crosshair; }
  #nomedia { color:var(--fg4); padding:40px 20px; text-align:center; font-size:var(--t-sm); }
  .transport { display:flex; gap:8px; align-items:center; margin-top:10px; flex-wrap:wrap; }
  .transport button { padding:5px 12px; }
  .transport button.on, .composer .tools button.on { background:var(--jw); color:var(--jw-ink); border-color:var(--jw-edge); }
  #seek { flex:1; min-width:120px; accent-color:var(--jade-fg); }
  .tc { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:var(--t-sm); color:var(--fg2); min-width:104px; }
  /* the review player's own injected buttons are light-on-white (it is also
     mounted on a light page) — restated here in this page's tokens */
  .vpanel #rp-cmpbar button, .vpanel #rp-filterbar button { background:var(--l3); color:var(--fg2); border:1px solid var(--line); }
  .vpanel #rp-cmpbar button.on, .vpanel #rp-filterbar button.on { background:var(--jw); color:var(--jw-ink); border-color:var(--jw-edge); }
  .vpanel #rp-cmpsel { background:var(--l1); color:var(--fg); border:1px solid var(--line); }
  .vpanel #rp-filterbar { border-bottom:1px solid var(--line-soft) !important; }
  .rp-marker i { flex:none !important; width:8px !important; height:8px !important; background:var(--jade-fg) !important; box-shadow:0 0 0 1px #000 !important; }
  .cmt.rp-hi { background:var(--jw-tint) !important; box-shadow:inset 3px 0 0 var(--jade-fg) !important; }
  .commentpane { display:flex; flex-direction:column; }
  #thread { max-height:46vh; overflow:auto; }
  .cmt { border-bottom:1px solid var(--line-soft); padding:9px 14px; }
  .cmt.res { opacity:.55; }
  .cmt .hd { display:flex; gap:7px; align-items:center; flex-wrap:wrap; margin-bottom:3px; }
  .cmt .who { font-weight:600; font-size:var(--t-sm); }
  .cmt .bd { white-space:pre-wrap; word-break:break-word; color:var(--fg2); }
  .cmt .ac { margin-top:5px; display:flex; gap:10px; flex-wrap:wrap; }
  .cmt .ac button { background:none; border:0; padding:0; color:var(--fg3); font-size:var(--t-xs); text-decoration:underline; }
  .cmt audio { width:100%; margin-top:6px; height:32px; }
  .cmt .pill, .cmt .pill.good { background:var(--l3); color:var(--fg3); border:1px solid var(--line-soft); font-weight:500; padding:0 8px; }
  .tcchip { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:11px; background:var(--l3); color:var(--fg);
            border:1px solid var(--line); border-radius:5px; padding:1px 7px; }
  .composer { border-top:1px solid var(--line-soft); padding:10px 14px; }
  .composer textarea { width:100%; min-height:62px; padding:8px; background:var(--l1); color:var(--fg); border:1px solid var(--line);
                       border-radius:var(--r1); resize:vertical; font:inherit; }
  .composer .tools { display:flex; gap:7px; align-items:center; flex-wrap:wrap; margin-top:8px; }
  .composer .tools button { padding:5px 10px; }
  .composer .tools button.rec { background:var(--bad); color:#3A0A10; border-color:var(--bad); }
  #post { background:var(--jw); color:var(--jw-ink); border-color:var(--jw-edge); font-weight:700; }
  #note { font-size:var(--t-sm); color:var(--fg4); margin-top:6px; min-height:16px; }
  #note.err { color:var(--bad-fg); }
  .swatches { display:flex; gap:5px; }
  .sw { width:20px; height:20px; border-radius:50%; border:2px solid var(--l1); box-shadow:0 0 0 1px var(--line); padding:0; }
  .sw.on { box-shadow:0 0 0 2px var(--fg); }
  .uprow { display:flex; align-items:flex-end; gap:10px; flex-wrap:wrap; }
  .uprow > div:first-child { flex:1 1 240px; }

  .pcard { background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r2); padding:14px;
           box-shadow:var(--edge),var(--e1); }
  .pcard + .pcard { margin-top:14px; }
  .pcard .pcard { box-shadow:none; }
  .pcard h3 { font-size:var(--t-md); margin-bottom:8px; }
  .briefbody { font-size:var(--t-sm); color:var(--fg2); white-space:pre-wrap; word-break:break-word;
               max-height:340px; overflow-y:auto; line-height:1.5; }
  .kitrow { display:flex; align-items:center; gap:8px; margin-top:8px; flex-wrap:wrap; }
  .swatch { display:inline-block; width:22px; height:22px; border-radius:5px; border:1px solid var(--line); }
  .kswatch { display:inline-flex; align-items:center; gap:6px; background:var(--l3); border:1px solid var(--line-soft);
             border-radius:20px; padding:3px 10px 3px 4px; font-size:var(--t-xs); }
  .kswatch .v { color:var(--fg2); font-variant-numeric:tabular-nums; }
  .kswatch .s { color:var(--fg4); }
  .kfont { background:var(--l3); border:1px solid var(--line-soft); border-radius:20px; padding:3px 10px; font-size:var(--t-xs); }
  .klogo { font-size:var(--t-xs); color:var(--fg4); }

  .player { width:100%; background:var(--l0); border-radius:var(--r2); overflow:hidden; }
  .player video { width:100%; max-height:460px; display:block; background:#000; }
  .versrow { display:flex; align-items:center; gap:8px; padding:7px 0; border-top:1px solid var(--line-soft);
             font-size:var(--t-sm); flex-wrap:wrap; }
  .versrow:first-of-type { border-top:none; }
  .versrow .poster { display:inline-block; width:34px; height:34px; border-radius:4px; object-fit:cover; background:var(--l3); flex-shrink:0; }
  .versrow button.small, .versrow a.small { font-size:var(--t-xs); padding:3px 9px; }
  .pill { display:inline-block; border-radius:20px; padding:1px 9px; font-size:11px; font-weight:700; letter-spacing:.04em; }
  .pill.ok { background:var(--ok-t); color:var(--ok-fg); border:1px solid var(--ok-l); }
  .pill.bad { background:var(--bad-t); color:var(--bad-fg); border:1px solid var(--bad-l); }
  .pill.wait { background:var(--att-t); color:var(--att-fg); border:1px solid var(--att-l); }
  .row3 { display:grid; grid-template-columns:1fr auto; gap:8px; align-items:end; margin-top:10px; }
  @media (max-width:600px) { .row3 { grid-template-columns:1fr; } }
  .mbframe { width:100%; height:340px; border:1px solid var(--line-soft); border-radius:var(--r2); background:var(--l1); }

  /* ── the pay modal (was a full page panel; now a small header link) ──── */
  .modal-scrim { position:fixed; inset:0; background:rgba(0,0,0,.6); display:flex; align-items:center;
                 justify-content:center; z-index:75; padding:20px; }
  .modal { background:var(--l2); border:1px solid var(--line); border-radius:var(--r3); padding:18px;
           box-shadow:var(--e2); max-width:460px; width:100%; max-height:80vh; overflow-y:auto; }
  /* The pay modal sits over the board, and --l2 is frosted glass: the board's text showed through the money. Opaque base for this one modal. */
  #pay-scrim .modal { background:var(--l1); }
  .modal-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; margin-bottom:12px; }
  .pay-top { display:flex; align-items:baseline; gap:18px; flex-wrap:wrap; }
  .pay-total { font-size:28px; font-weight:600; letter-spacing:-.01em; }
  .pay-sub { font-size:var(--t-sm); color:var(--fg4); }
  .pay-warn { color:var(--att-fg); }
  .pay-rates { display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
  .rate { background:var(--l3); border:1px solid var(--line-soft); border-radius:20px; padding:4px 11px; font-size:var(--t-sm); }
  .rate .k { color:var(--fg4); text-transform:uppercase; letter-spacing:.1em; font-size:10px; font-weight:700; margin-right:6px; }
  .earn { display:grid; grid-template-columns:1fr auto; gap:8px; align-items:baseline;
          border-top:1px solid var(--line-soft); padding:7px 0; font-size:var(--t-sm); }
  .earn .w { color:var(--fg4); font-size:11px; margin-top:2px; }
  .earn .amt { font-variant-numeric:tabular-nums; font-weight:600; }
  .earn .amt.none { color:var(--att-fg); font-weight:400; font-style:italic; }
  .paystate { display:inline-block; margin-left:4px; padding:1px 8px; border-radius:20px; font-size:10px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; border:1px solid var(--line-soft); }
  .paystate.is-paid { color:var(--ok-fg, #1e7a4f); border-color:currentColor; }
  .paystate.is-owed { color:var(--att-fg); border-color:currentColor; }

  /* ── the Library modal + the Reference panel's "Checklists for this job" (E4) ── */
  .libmodal-detail { font-size:var(--t-sm); color:var(--fg2); line-height:1.6; max-height:50vh; overflow-y:auto; }
  .libmodal-detail h2, .libmodal-detail h3, .libmodal-detail h4 { color:var(--fg); margin:10px 0 5px; }
  .libmodal-detail ul.md-tasklist { list-style:none; padding-left:0; }
  .libmodal-detail li.md-task { display:flex; align-items:flex-start; gap:6px; padding:2px 0; }
  #ref-job-checklists { margin-top:10px; }
  .refchecklist { border-top:1px solid var(--line-soft); padding-top:8px; margin-top:8px; }
  /* A checklist line is content a person reads and ticks, not a form-field caption: the global label rule's uppercase/tracking must not reach it. */
  .refchecklist .rc-item label { text-transform:none; letter-spacing:normal; font-size:var(--t-sm); font-weight:400; color:inherit; margin:0; }
  .libdoc .libdraft { margin-left:6px; font-size:9px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; padding:1px 6px; border-radius:999px; border:1px solid var(--line); color:var(--fg3); }
  .refchecklist h5 { font-size:var(--t-sm); font-weight:600; color:var(--fg); margin:0 0 5px; }
  .refchecklist .rc-item { display:flex; align-items:flex-start; gap:6px; font-size:var(--t-sm); color:var(--fg2); padding:2px 0; }
  .refchecklist .rc-item.is-ticked { color:var(--fg4); text-decoration:line-through; }
  /* The global input/select rule above styles every input like a text box,
     which flattens a native checkbox — the same fix index.html's own
     .libdoc-body override applies for the identical reason. */
  .refchecklist .rc-item input,.libmodal-detail input[type=checkbox] { margin-top:3px; flex:none; width:15px; height:15px; background:none; border:none; accent-color:var(--jw); }
  .refchecklist .rc-progress { font-size:11px; color:var(--fg4); margin-top:3px; }
  @media (max-width:600px) { .modal { max-width:none; } }

  .up { background:var(--l3); border:1px solid var(--line-soft); border-radius:var(--r1);
        padding:8px 10px; margin-top:8px; font-size:var(--t-sm); }

  /* "What the client asked for" (B3) — one row per unresolved comment */
  .changecomment { display:flex; gap:8px; align-items:baseline; padding:6px 0;
                    border-top:1px solid var(--line-soft); font-size:var(--t-sm); }
  .changecomment:first-child { border-top:none; }
  .changecomment .who { color:var(--fg4); font-size:var(--t-xs); white-space:nowrap; }
  .changecomment .tc { color:var(--fg4); font-size:var(--t-xs); font-variant-numeric:tabular-nums; white-space:nowrap; }

  /* ── SCREEN 0 — START HERE (E2, 2026-10-04) ───────────────────────────── */
  .startstrip { display:flex; gap:8px; flex-wrap:wrap; margin:16px 0 22px; }
  .startpill { display:flex; align-items:center; gap:8px; background:var(--l2); border:1px solid var(--line-soft);
               border-radius:20px; padding:6px 13px 6px 8px; font-size:var(--t-xs); color:var(--fg3); flex:1 1 170px; }
  .startpill .n { display:inline-flex; align-items:center; justify-content:center; width:20px; height:20px;
                  border-radius:50%; background:var(--l3); border:1px solid var(--line); font-size:11px; font-weight:700;
                  color:var(--fg3); flex-shrink:0; }
  .startpill.done { border-color:var(--ok-l); color:var(--fg2); }
  .startpill.done .n { background:var(--ok-t); border-color:var(--ok-l); color:var(--ok-fg); }
  .startstep { margin-top:16px; }
  .startstep h3 { display:flex; align-items:center; gap:9px; }
  .startstep h3 .donepill { font-size:10px; font-weight:800; letter-spacing:.06em; text-transform:uppercase;
                              background:var(--ok-t); color:var(--ok-fg); border:1px solid var(--ok-l);
                              border-radius:20px; padding:2px 9px; }
  .startstep h3 .pendingpill { font-size:10px; font-weight:800; letter-spacing:.06em; text-transform:uppercase;
                                 background:var(--att-t); color:var(--att-fg); border:1px solid var(--att-l);
                                 border-radius:20px; padding:2px 9px; }
  .startform { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:12px; }
  .startform .full { grid-column:1 / -1; }
  @media (max-width:600px) { .startform { grid-template-columns:1fr; } }
  .startform .f label { margin-bottom:4px; }
  .maskedpay { display:flex; align-items:center; gap:10px; background:var(--l3); border:1px solid var(--line-soft);
               border-radius:var(--r1); padding:9px 12px; font-size:var(--t-sm); margin-top:10px; }
  .contracttext { background:var(--l1); border:1px solid var(--line-soft); border-radius:var(--r2); padding:16px 18px;
                  max-height:360px; overflow-y:auto; font-size:var(--t-sm); line-height:1.6; white-space:pre-wrap;
                  word-break:break-word; margin-top:10px; }
  .signrow { display:flex; gap:10px; align-items:flex-end; margin-top:12px; flex-wrap:wrap; }
  .signrow .f { flex:1 1 220px; }
  .agreerow { display:flex; align-items:center; gap:8px; margin-top:10px; font-size:var(--t-sm); color:var(--fg2); }
  .agreerow input { width:auto; }
  .startfirstjob { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-top:10px;
                   background:var(--l3); border:1px solid var(--line-soft); border-radius:var(--r2); padding:12px 14px; }

  /* ── THE RATES PANEL (step 2) and the HOW WE WORK page (step 3), editors phase 2, 2026-10-28 ── */
  .ratepanel { background:var(--l3); border:1px solid var(--line-soft); border-radius:var(--r2); padding:12px 14px; margin-top:10px; }
  .ratepanel .ratehead { font-size:var(--t-sm); font-weight:700; color:var(--fg1); margin-bottom:6px; }
  .ratepanel .rategroup { margin-top:8px; }
  .ratepanel .rategroup .gl { font-size:var(--t-xs); color:var(--fg4); letter-spacing:.06em; text-transform:uppercase; }
  .ratepanel .rategroup.now .gl { color:var(--ok-fg); }
  .ratepanel .raterow { display:flex; justify-content:space-between; gap:12px; padding:5px 0; border-top:1px solid var(--line-soft);
                        font-size:var(--t-sm); }
  .ratepanel .raterow:first-of-type { border-top:none; }
  .ratepanel .raterow .amt { font-weight:700; white-space:nowrap; font-variant-numeric:tabular-nums; }
  .hww h4 { font-size:var(--t-sm); margin:14px 0 6px; color:var(--fg1); }
  .hww h4:first-child { margin-top:10px; }
  .hww ol, .hww ul { margin:0; padding:0 0 0 20px; font-size:13.5px; line-height:1.55; color:var(--fg2); }
  /* EVERY control on the start screen is at least 44px tall (a thumb, not a mouse): fields, the country/payout selects, Save, Change, Sign, "I've read this",
     the links, and the "I agree" row. The checkbox itself stays small inside a 44px row. */
  #screen-start input[type=text], #screen-start input[type=email], #screen-start select, #screen-start button { min-height:44px; }
  #screen-start a { display:inline-flex; align-items:center; min-height:44px; }
  #screen-start .agreerow { min-height:44px; }
  #screen-start .agreerow input { width:22px; height:22px; min-height:0; }
  #screen-start summary { min-height:44px; }
  .hww li { margin:0 0 6px; }
  .hww details { margin-top:14px; }
  .hww summary { cursor:pointer; font-size:var(--t-sm); color:var(--fg2); display:flex; align-items:center; }

  /* ── EDITOR BRIEF (2026-10-18) - drawn by editor-brief.js ──────────────────── */
  .eb-block { background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r2); padding:14px; margin-top:12px; }
  .eb-block:first-child { margin-top:0; }
  .eb-head { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:wrap; border-color:var(--line-strong); }
  .eb-title { font-size:var(--t-xl); margin:2px 0 0; }
  .eb-tag { font-size:var(--t-mi); font-weight:600; letter-spacing:.14em; text-transform:uppercase; color:var(--fg4); margin:0 0 6px; }
  .eb-pills { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
  .eb-pill { font-size:var(--t-xs); background:var(--l3); border:1px solid var(--line-soft); border-radius:20px; padding:4px 10px; color:var(--fg2); }
  .eb-lead { font-size:var(--t-md); color:var(--fg); margin:4px 0 8px; }
  .eb-p { margin:6px 0; color:var(--fg2); }
  .eb-p b, .eb-beat-h b { color:var(--fg); }
  .eb-beat { margin:8px 0; color:var(--fg2); }
  .eb-beat-t { color:var(--fg2); }
  .eb-sub { margin-top:3px; color:var(--fg3); }
  .eb-list { margin:6px 0 4px 18px; padding:0; }
  .eb-muted { color:var(--fg4); }
  .eb-keepout { margin-top:10px; }
  .eb-swatch { width:26px; height:26px; border-radius:6px; border:1px solid var(--line); display:inline-block; background:var(--l3); }
  .eb-hex { font-size:var(--t-xs); color:var(--fg3); margin-right:8px; }
  .eb-link { color:var(--fg); text-decoration:underline; }
  .eb-btn { font:inherit; font-size:var(--t-sm); color:var(--fg); background:transparent; border:1px solid var(--line-strong); border-radius:20px; padding:6px 14px; cursor:pointer; margin-top:6px; }
  .eb-btn:hover { background:var(--l3); }
  .eb-note { color:var(--fg3); }
  /* several videos (brand / campaign briefs, 2026-10-27): each video is a card of three parts, Intro, Body, Outro */
  .eb-reel-title { font-size:var(--t-lg, var(--t-md)); margin:2px 0 4px; overflow-wrap:anywhere; }
  .eb-part { border-left:3px solid var(--line-strong); padding:2px 0 2px 12px; margin:12px 0; }
  .eb-beats { margin:10px 0 6px; padding-left:22px; display:grid; gap:8px; }
  .eb-beat { color:var(--fg2); }
  .eb-beat b { color:var(--fg); }
  .eb-part-h { font-size:var(--t-mi); font-weight:600; letter-spacing:.14em; text-transform:uppercase; color:var(--fg3); margin-bottom:2px; }
  .eb-reels .eb-block { overflow-wrap:anywhere; }
  .eb-inner { background:var(--l3); }
  #eb-print-sheet { display:none; }
  /* PRINT / SAVE AS PDF: the page prints a plain clone of the brief (public/editor-brief.js printBrief), black on white, nothing else */
  @media print {
    body.eb-printing > *:not(#eb-print-sheet) { display:none !important; }
    body.eb-printing #eb-print-sheet { display:block !important; }
    body.eb-printing, html:has(body.eb-printing) { background:#fff !important; color:#111 !important; }
    #eb-print-sheet { padding:0; font-size:11pt; line-height:1.4; }
    #eb-print-sheet *:not(.eb-swatch) { background:transparent !important; color:#111 !important; box-shadow:none !important; border-color:#bbb !important; }
    #eb-print-sheet .eb-block { break-inside:avoid; border:1px solid #bbb; margin-top:8pt; padding:8pt; }
    #eb-print-sheet .eb-part { break-inside:avoid; }
    #eb-print-sheet .eb-reel { break-inside:auto; }
    #eb-print-sheet .eb-noprint { display:none !important; }
    #eb-print-sheet .eb-link { text-decoration:underline; }
  }

  /* ── REFERENCE PANEL (E4 — Studio half, 2026-10-04) ───────────────────── */
  .refpanel { margin-top:14px; background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r3);
              box-shadow:var(--edge),var(--e1); }
  .refpanel-head { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:12px 16px;
                   cursor:pointer; user-select:none; }
  .refpanel-head h3 { font-size:var(--t-md); }
  .refpanel-head .chev { color:var(--fg4); font-size:var(--t-sm); transition:transform .15s ease; }
  .refpanel.collapsed .refpanel-head .chev { transform:rotate(-90deg); }
  .refpanel-body { padding:0 16px 16px; display:grid; grid-template-columns:1fr 1fr; gap:16px; }
  @media (max-width:860px) { .refpanel-body { grid-template-columns:1fr; } }
  .refpanel.collapsed .refpanel-body { display:none; }
  .refsec { font-size:var(--t-sm); }
  .refsec h4 { font-size:var(--t-xs); text-transform:uppercase; letter-spacing:.1em; color:var(--fg4); margin-bottom:8px; }
  .hexrow { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
  .hexrow .hexsrc { color:var(--fg4); font-size:var(--t-xs); flex:1 1 0; min-width:0; overflow-wrap:anywhere; }
  .hexrow .swatch { width:20px; height:20px; border-radius:4px; border:1px solid var(--line); flex-shrink:0; }
  .hexrow .hexval { font-variant-numeric:tabular-nums; color:var(--fg2); }
  .hexrow .hexname { color:var(--fg4); font-size:var(--t-xs); min-width:0; width:64px; flex:0 0 auto; }
  .hexrow button.copyhex { font-size:var(--t-xs); padding:2px 10px; border-radius:4px; min-height:32px; }
  /* A TAP TARGET IS AT LEAST 44px HIGH on a phone: every control of the job page (the player's own colour dots are drawn dots, not buttons to hit) */
  @media (max-width:760px) {
    #screen-project button:not(.sw), #screen-project select, #screen-project a.btnlink, #screen-project a.tag, #screen-project input[type=file],
    #screen-project .refpanel-head, #screen-project #ref-job-checklists label { min-height:44px; }
    #screen-project .refhowto a, #screen-project .reflogo a, #screen-project #job-music a[href] { display:inline-flex; align-items:center; min-height:44px; }
  }
  .reflogo { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
  .reflogo img { width:30px; height:30px; object-fit:contain; background:var(--l3); border-radius:4px; border:1px solid var(--line-soft); }
  .reffonts { display:flex; gap:6px; flex-wrap:wrap; margin-bottom:6px; }
  .reftone { font-style:italic; color:var(--fg3); white-space:pre-wrap; }
  .refbrief { white-space:pre-wrap; max-height:160px; overflow-y:auto; color:var(--fg2); }
  /* a job with two or more videos: the editor brief is ONE reel, so only this video's own written brief stays beside it (editor-job-sections.js applyBriefMode) */
  #job-brief-written.only-own-video #ref-month-brief-wrap, #job-brief-written.only-own-video .refhowto { display:none; }
  .refhowto { font-size:var(--t-xs); }

  /* ── gate / refusal ── */
  #gate { max-width:380px; margin:12vh auto; padding:0 var(--gut); }
  #gate .box { background:var(--l2); border:1px solid var(--line-soft); border-radius:var(--r3);
               padding:20px; box-shadow:var(--edge),var(--e1); }
  #gate .f { margin-bottom:12px; }
  #notice { margin-top:20px; border:1px solid var(--line-soft); background:var(--l2); border-radius:var(--r2);
            padding:12px 14px; font-size:var(--t-sm); color:var(--fg2); }
  #err { color:var(--bad-fg); font-size:var(--t-sm); min-height:19px; margin-top:8px; }

  /* the brand kit stays closed on every job once an editor closes it (remembered in this browser), so the closed header says so: the section is never just missing its body */
  .refpanel .refhint { display:none; margin-left:auto; margin-right:8px; font-size:12px; color:var(--fg2); }
  .refpanel.collapsed .refhint { display:inline; }
