/* ============================================================================
   room-intake-manifest.css — the interior of the Import Media Room.

   recomposing-room-pilots S2, Pilot 1. Presentation only.

   ── WHY THIS FILE EXISTS RATHER THAN A BLOCK IN room-windows.css ────────────
   room-windows.css is the CHASSIS engine: the shell, the well, the silhouette
   linework and the per-room palette tokens, shared by every vessel in the fleet
   and asserted byte-wise by room-windows.smoke.cjs + themed-vessels.smoke.cjs.
   What follows is one Room's INTERIOR — a different concern with a different
   lifetime and, decisively, a different rollback: reverting this pilot is
   `git checkout` on this one file plus its one <link>, with no chassis diff to
   read. A second pilot (Portraits) gets its own file for the same reason.

   ── THE SEAM ───────────────────────────────────────────────────────────────
   buildWindow() stamps `.ffrw-shell.ffrw-vessel.ffrw-import-media`, and the
   view-room factory REPARENTS the live App-Panel view element into `.ffrw-body`
   with `.ffrw-hosted`. So

       .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted <anything>

   reaches every node of the hosted workflow with zero JavaScript, is scoped to
   this Room by construction, and leaves the flat App-Panel view untouched when
   the Room closes and the element goes home.

   ── WHAT THIS FILE MAY NOT DO ──────────────────────────────────────────────
   No handler, no onclick, no label, no workflow state, no authorization, no
   truthful string. No `!important`. No second scroll owner — `#view-sandbox`
   is the one, and it stays the one. Two nodes carry `display:` from JS as
   BEHAVIOUR (`.sandbox-tab-content` visibility, `.sandbox-tab-btn.admin-only`
   authorization) and nothing here touches either.

   Two sections, and the split is load-bearing:

     § 1  BASE — verbatim replacements for the inline styles excised from
          sandbox.js and index.html. Not room-scoped. These exist so the flat
          App-Panel view and the mobile bundle render EXACTLY as they did
          before the excision. Read them as a transcript, not as design.
     § 2  ROOM — the Intake Manifest recomposition, room-scoped, layered on
          top. Delete § 2 and the Room reverts to today's presentation with
          every control still in place.
   ============================================================================ */


/* ══════════════════════════════════════════════════════════════════════════
   § 1  BASE — the excision transcript (flat-view parity, NOT room-scoped)

   Each rule below carries the exact declarations that used to sit in a
   `style="…"` attribute, with the source line they came from. An inline style
   outranks any room-scoped rule at any specificity, which is the whole reason
   § 2 could not be written until these moved. Enumerated node-by-node in
   docs/rooms-blueprint/pilots/PILOT_IMPORT_MEDIA.md.
   ══════════════════════════════════════════════════════════════════════════ */

/* index.html — #view-sandbox .view-header <p> */
#view-sandbox .view-header p {
  margin: 8px 0 0 0;
  font-size: 0.95rem;
  opacity: 0.9;
}

/* sandbox.js renderBatchesList() — the docket header row */
.sandbox-batches-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding: 0 4px;
}

.sandbox-batches-count {
  font-size: 0.9rem;
  color: var(--color-text-light);
}

.sandbox-create-new-btn {
  padding: 8px 16px;
  font-size: 0.9rem;
}

/* sandbox.js — the per-profile action chip, six branches that carried six
   hardcoded gradients inline. Shared shape first, then the branch palettes. */
.batch-review-btn {
  border: none;
  color: white;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
}

.batch-review-btn--resume     { background: linear-gradient(135deg, #3b82f6, #2563eb); }
.batch-review-btn--dedup      { background: linear-gradient(135deg, #f59e0b, #d97706); }
.batch-review-btn--curate     { background: linear-gradient(135deg, #667eea, #764ba2); }

.batch-review-btn--incomplete {
  background: linear-gradient(135deg, #ef4444, #dc2626);
  cursor: not-allowed;
  opacity: 0.9;
}

/* The three inert chips. `--processing` and `--pending` reproduce the grey
   gradient they carried inline; `--awaiting` and `--closed` are the two chips
   S2 ADDED (S1 findings F2 and F1) and take the same inert treatment so the
   flat view reads them as the same kind of thing. */
.batch-review-btn--processing,
.batch-review-btn--pending,
.batch-review-btn--awaiting,
.batch-review-btn--closed {
  background: linear-gradient(135deg, #9ca3af, #6b7280);
  cursor: not-allowed;
  opacity: 0.7;
}

.batch-add-items-btn {
  background: linear-gradient(135deg, #6366f1, #4f46e5);
  border: none;
  cursor: pointer;
  color: white;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 0.875rem;
  font-weight: 500;
}

.batch-publish-btn {
  background: linear-gradient(135deg, #10b981, #059669);
  border: none;
  cursor: pointer;
  color: white;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 0.875rem;
  font-weight: 500;
}

/* The card's two clickable regions. The card itself carries the onclick; these
   only ever advertised that fact with a cursor. */
.batch-card-header,
.batch-card-stats {
  cursor: pointer;
}

.batch-footer-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.batch-delete-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: #ef4444;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 0.875rem;
}

.stat--failed { color: #ef4444; }

/* Lane 1 F26/F27 — a published batch's out-of-band enrichment. Colour carries the
   state: amber = owed/working, green = done, red = failed (re-runnable). */
.stat--enrichment { cursor: pointer; text-decoration: underline dotted; }
.stat--enrichment-queued,
.stat--enrichment-running { color: #f59e0b; }
.stat--enrichment-done    { color: #10b981; }
.stat--enrichment-failed  { color: #ef4444; }

.enrichment-stage { margin: 0 0 var(--space-lg, 16px); padding: 12px 14px; border-radius: 10px;
  border: 1px solid rgba(245, 158, 11, 0.45); background: rgba(245, 158, 11, 0.08); }
.enrichment-stage[data-state="done"]   { border-color: rgba(16, 185, 129, 0.5); background: rgba(16, 185, 129, 0.08); }
.enrichment-stage[data-state="failed"] { border-color: rgba(239, 68, 68, 0.5);  background: rgba(239, 68, 68, 0.08); }
.enrichment-stage-header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  font-size: 0.85rem; margin-bottom: 8px; }
.enrichment-stage-label { font-weight: 700; letter-spacing: 0.06em; }
.enrichment-stage-bar { height: 6px; border-radius: 3px; background: rgba(255, 255, 255, 0.12); overflow: hidden; }
.enrichment-stage-fill { height: 100%; width: 0; background: #f59e0b; transition: width 0.6s ease; }
.enrichment-stage[data-state="done"] .enrichment-stage-fill { background: #10b981; }
.enrichment-stage-items { list-style: none; margin: 10px 0 0; padding: 0; max-height: 180px; overflow-y: auto;
  font-size: 0.8rem; }
.enrichment-stage-items li { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
.enrichment-item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.enrichment-item-count { flex-shrink: 0; opacity: 0.8; }

.upload-subtitle--large-video { color: #60a5fa; }
.upload-subtitle--deduped     { color: #10b981; font-size: 0.85em; }

/* The card's left tally edge for the two states that used to borrow 'ready'
   and paint themselves GREEN — a rejected profile and one waiting on a person
   both wore the go-ahead colour of a profile genuinely ready to curate. The
   other four values are in styles.css and are unchanged. */
.sandbox-batch-card.widget-style.rejected { border-left-color: #b45454; }
.sandbox-batch-card.widget-style.awaiting { border-left-color: #d99a2b; }
.sandbox-batch-card.widget-style.failed   { border-left-color: #b45454; }


/* ══════════════════════════════════════════════════════════════════════════
   § 2  ROOM — Import Media as one receiving docket

   Palette is the manifest entry `import-media`, verbatim and unextended:
     surface #121A2A · raised #25324D · accent #55B8FF · accentAlt #F2B84B
     text #F2F7FF · muted #AAB5C8 · border #286891
   Semantics are the manifest's shared.semanticColors:
     success #4FD1A1 · attention #F2B84B · destructive #F06A67 · info #55B8FF

   Nothing below invents a metric. Every colour, shape and word on screen is
   chosen from state renderBatchesList() already computes — the nine status
   badges and the (now) eight action branches enumerated in
   DOM_OWNERSHIP_IMPORT_MEDIA.md § 3.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── The well: the docket sits on the plate, and owns its own gutters ──────
   #view-sandbox is the scroll owner and had padding 0 on all four sides, which
   is why the header subtitle's right edge WAS the vessel wall at all eight
   measured geometries (GEOMETRY_CONTRACT C1). The gutters below are the fix;
   S4 owns the contract that makes them checkable. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted {
  --im-gutter: 20px;
  --im-ink: #F2F7FF;
  --im-ink-muted: #AAB5C8;
  --im-rule: rgba(40, 104, 145, 0.42);
  --im-accent: #55B8FF;
  --im-stamp: #F2B84B;

  /* ── S4 · GEOMETRY CONTRACT §2.5 — the exclusion zones, named and derived ──
     TWO numbers, because the zone has two jobs and one number would be wrong
     for both. Each is derived from something measured, not picked to look
     right.

     `--im-reserve-end` is the CONTENT reservation: how far the last painted
     row must stay off the floor of the well. Two things want that clearance —
     the well's own `border-radius: 10px`, which eats a full-width row at both
     ends when it sits flush, and §2.3's 16px content-to-shell-edge separation.
     max(10, 16) = 16. It is applied on the scroll owner and the docket list's
     own 22px bottom padding is dropped, so the reservation has exactly ONE
     source rather than two that drift apart.

     `--im-float-reserve` is the FLOATING-CONTROL exclusion zone: the create
     tab's terminal action is sticky (§ C2 below), so it overlays the foot of
     the scrollport. Measured band 44px + its 1px top rule, rounded to 48.
     This one is reflected in `scroll-padding` only — it must not become blank
     content padding in the docket tab, where nothing floats.

     ⚠️ One value for the whole scroll owner rather than per-tab, because the
     visible tab is set by an inline `display:` that JS owns and no selector can
     read. Over-reserving SCROLL padding in the docket tab costs nothing: a
     keyboard-focused last row simply lands 48px rather than 16px off the floor.

     `--im-reserve-start` is the top zone. Nothing floats at the top of this
     scroll owner — the masthead and tab strip scroll away with the content —
     so it is §2.3's separation alone, enough that a keyboard-scrolled item does
     not land flush in the well's top radius. */
  --im-reserve-start: 16px;
  --im-reserve-end: 16px;
  --im-float-reserve: 48px;

  /* §2.5 requires the zone be reflected in BOTH content and scroll padding.
     `scroll-padding` is the half keyboard focus uses — it is what makes the
     last item REACHABLE clear of the ornament rather than merely painted
     beneath it. */
  padding-block-end: var(--im-reserve-end);
  scroll-padding-block-start: var(--im-reserve-start);
  scroll-padding-block-end: var(--im-float-reserve);
  color: var(--im-ink);
}

/* ── Room identity: one visible title, and it is the chassis's ─────────────
   The chassis header already says `Import Media / INTAKE MANIFEST` in the
   vessel's own type. The hosted view repeats it in a second typeface eight
   pixels below, which is the duplicate the commission names.

   VISUALLY RETIRED, NOT REMOVED. `display: none` would take the H2 out of the
   accessibility tree, and it is the root of this view's heading outline
   (H2 -> H4 per profile). The clip technique keeps it named, focusable-by-AT
   and in document order; only the pixels go. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .view-header h2 {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── The masthead: what the docket is, in the docket's own register ────────
   The band itself is painted by the launcher-visual chrome layer
   (.ffvl-chromed-header sets background + bottom rule + text colour, and only
   those). Nothing here touches those three properties — this is spacing and
   type, so removing the chrome class still leaves a coherent masthead. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .view-header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
  padding: 11px var(--im-gutter) 10px;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .view-header p {
  margin: 0;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.62;
  /* C1: the subtitle stops short of the wall instead of running into it. */
  padding-inline-end: 4px;
  min-width: 0;
}

/* ── The manifest tabs ────────────────────────────────────────────────────
   These were raw browser-default buttons — white-on-black system chrome inside
   a sculpted vessel, and the single most visible discontinuity in the Room
   (S1 F7). They become ruled manifest tabs. Handlers, labels, data-tab values
   and the .active class that showSandboxTab() toggles are all untouched. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-view-toggle {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0;
  padding: 0 var(--im-gutter);
  border-bottom: 1px solid var(--im-rule);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  margin: 0 0 -1px;
  padding: 9px 13px;
  min-height: 36px;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(242, 247, 255, 0.58);
  cursor: pointer;
  transition: color 160ms cubic-bezier(.2,.8,.2,1),
              background 160ms cubic-bezier(.2,.8,.2,1),
              border-color 160ms cubic-bezier(.2,.8,.2,1);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn:hover {
  color: var(--im-ink);
  background: rgba(85, 184, 255, 0.08);
}

/* Selected carries TWO signals, not one: the ruled underline (shape) and the
   ink stepping to full strength (weight). Colour alone never decides. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn.active {
  color: var(--im-ink);
  border-bottom-color: var(--im-accent);
  background: rgba(85, 184, 255, 0.10);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: -2px;
}

/* THE ONE CREATE ACTION. `+ New Profile` (tab) and `+ Create New` (docket
   header button) call the SAME handler with the SAME argument —
   showSandboxTab('create') — verified live at S1 (F5). They are duplicate
   affordances, not distinct canonical actions, so the commission's "one
   unambiguous visible create action" is reachable by presentation alone.

   The TAB is the one kept, because it is the affordance that carries the
   create tab's SELECTED state: retire it instead and opening the create form
   would leave `My Media Profiles` reading as the active tab over a form. It is
   given a stamped-pill treatment in the docket's saffron so it cannot be
   misread as a third navigational tab. The duplicate button is retired below. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn[data-tab="create"] {
  border: 1px solid rgba(242, 184, 75, 0.55);
  border-radius: 7px;
  margin: 0 4px 5px;
  padding: 7px 13px;
  min-height: 30px;
  background: rgba(242, 184, 75, 0.10);
  color: var(--im-stamp);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn[data-tab="create"]:hover {
  background: rgba(242, 184, 75, 0.20);
  color: #FFF3DC;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn[data-tab="create"].active {
  background: rgba(242, 184, 75, 0.28);
  border-color: var(--im-stamp);
  color: #FFFFFF;
}

/* ── The docket head: the count line ──────────────────────────────────────
   The duplicate create button is retired HERE, in the Room only. `display:none`
   is correct for this one node and not for the H2 above: this is a CONTROL, and
   a hidden-but-focusable control is a phantom tab stop that announces an action
   the reader cannot see. The action itself is not lost — it is one row up, in
   the tab strip, on the same handler. The flat App-Panel view keeps both. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batches-header {
  margin: 0;
  padding: 13px var(--im-gutter) 7px;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-create-new-btn {
  display: none;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batches-count {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--im-ink-muted);
}

/* ── The docket itself ────────────────────────────────────────────────────
   Rows are manifest lines, not cards: square, ruled, sharing one hairline, so
   the eye reads a single continuous document instead of a stack of widgets. */
/* The list's own bottom padding is GONE: the scroll owner's
   `--im-reserve-end` is now the single source of the floor reservation
   (§2.5). Two sources of the same clearance is how they drift apart. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batches-list {
  padding: 0 var(--im-gutter);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card {
  /* STABLE DOCKET COLUMNS. The card was a three-child flexbox with
     `justify-content: space-between`, so the middle cell ("0 files") landed at
     a different x on every row — the count was legible but the COLUMN was not.
     A grid makes identity, count, date and action line up down the docket,
     which is what turns thirty rows into one document. */
  display: grid;
  /* The identity column takes the slack so the count/date/action cluster stays
     a CLUSTER: at the canvas rect the well is ~1500px, and an evenly-shared
     remainder stranded "0 files · Jul 9, 2026" alone in the middle of the row
     with the action another 400px away. 0.34fr keeps the four columns reading
     as one right-hand block at every width the Room can be dragged to.

     ⚠️ THE COLUMN FLOORS ARE SIZED FOR THE BUSIEST ROW, NOT THE LIVE ONE. Every
     live profile today is `rejected` with 0 files, which renders ONE stat and
     ONE chip — and the first cut of this grid (74px / 232px) looked correct
     against all twenty-nine of them. Rendering the synthetic all-branches
     fixture showed what the live docket was hiding: a curatable profile emits
     up to four stats and four controls, the action group overflowed its cell
     leftward, and `Review Similar Photos` printed straight over the date. The
     floors below hold the worst case the renderer can actually produce. */
  grid-template-columns: minmax(14em, 1fr) minmax(118px, 30%) minmax(380px, 0.34fr);
  /* ⛔ closing-rehearsal-defects S3, P6-F6 (the CSS half) — MEASURED: the line above used to read
     `minmax(118px, fit-content(30%))`. `fit-content()` is not a legal `minmax()` argument, so
     Chromium AND WebKit rejected the WHOLE declaration (CSS.supports → false) and every card fell
     back to ONE column: name, stats and actions stacked full-width, each right-aligned to its own
     content ("counts and buttons at different right edges"). A track sized by the row alone
     (30%, the ceiling fit-content meant) is legal and identical on every card, so the columns
     line up down the docket (s3_f6_measure.cjs: 1 distinct stats edge at 1250/1600/2000 px). */
  /* ⛔ THE NAME COLUMN HAS A FLOOR, AND THE STATS COLUMN HAS A CEILING
     (reforging-biography-folio S6 = slim-down S2 — Joe 2026-09-26: "each
     profile's title column has collapsed to one character wide"). This line
     used to read `minmax(0, 1fr) minmax(118px, max-content) …`. A flexible
     track with a ZERO floor beside a track that grows to its content's
     max-content is a trade the name always loses: the stats cell now carries
     a whole SENTENCE — "✨ Enrichment: done — Learned: 15 people in 89 items ·
     3 events · …" (contextualizing-import-harvest S6's learned_card) — whose
     max-content is ~1200 px, so the stats track took the row and the name was
     laid out in the remainder: 0 px on the real P5 profiles, one glyph per
     line, 78 lines tall (measured on the served page at 1250×608 and
     2000×1200, in every dress). fit-content(30%) lets a short stat stay
     short and wraps the sentence inside a third of the row; 14em keeps the
     name a name. */
  align-items: center;
  gap: 0 16px;
  margin: 0;
  padding: 9px 14px;
  border: 1px solid var(--im-rule);
  border-left-width: 3px;
  border-radius: 0;
  background: rgba(37, 50, 77, 0.30);
  box-shadow: none;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card + .sandbox-batch-card {
  border-top: 0;
}

/* ⚠️ NOT `:first-child`. S2 wrote it that way and the rule was dead: the
   renderer builds the list as `headerHtml + batchCardsHtml`
   (sandbox.js:775), so the FIRST child of `#sandboxBatchesList` is
   `.sandbox-batches-header` and no card is ever its parent's first child.
   The docket's top corner never rounded. `:last-child` was fine and stayed
   fine, which is why looking at the foot of the docket never showed it.

   The first card is the one not preceded by another card — which CSS can say,
   even without a previous-sibling combinator. Found by verify-rooms.cjs. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted
  .sandbox-batch-card:not(.sandbox-batch-card + .sandbox-batch-card) {
  border-radius: 4px 4px 0 0;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card:last-child {
  border-radius: 0 0 4px 4px;
}

/* A docket line does not levitate. The base widget hover lifts the card 2px
   and drops a shadow; here the row lights instead, which reads as "this line"
   without breaking the ruled column. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card:hover,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style:hover {
  transform: none;
  background: rgba(85, 184, 255, 0.10);
  border-color: rgba(85, 184, 255, 0.42);
  box-shadow: none;
}

/* Column 1 — identity and disposition, stacked. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-card-header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
}

/* The profile name is a manifest LINE ENTRY, not a chip. styles.css:31964 gives
   .batch-name a translucent 20px-radius pill — a widget affordance that reads as
   "tag" and, at the Room's declared minimum, wraps into a two-line lozenge. The
   docket wants a name. The pill is unset here and nowhere else. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-name {
  margin: 0;
  max-width: 100%;
  padding: 0;
  border-radius: 0;
  background: none;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--im-ink);
  overflow-wrap: anywhere;
}

/* Column 2 — the file count, right-aligned so the numerals stack. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-card-stats {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  font-size: 11.5px;
  color: var(--im-ink-muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* P6-F6: the enrichment summary is a SENTENCE in a right-aligned column. Right-aligned, its wrapped
   lines started at a different x each ("wrap ragged"); it reads as a paragraph, flush-left in the
   column's full width, with its line breaks balanced. The short stats above it stay right-aligned. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-card-stats .stat--enrichment {
  align-self: stretch;
  text-align: left;
  text-wrap: pretty;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-card-stats .stat strong {
  color: var(--im-ink);
  font-weight: 600;
}

/* Columns 3 and 4 — date, then the available action. */
/* `minmax(0, 1fr)` on the action cell is what stops the collision: without an
   explicit zero minimum a grid cell floors at its content's min-content width,
   so a wide chip group pushed the cell open and overflowed leftward across the
   date. The date column is content-sized so it never steals room it cannot use. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-card-footer {
  display: grid;
  grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-date {
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--im-ink-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-footer-actions {
  justify-content: flex-end;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  min-width: 0;
}

/* ── Disposition badges ───────────────────────────────────────────────────
   All nine of them, re-derived into the vessel's palette from the semantic
   colours the manifest already declares. The badge TEXT is the primary signal
   and is unchanged in every branch; colour is the second signal, never the
   only one. No branch is added, removed or merged. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status {
  padding: 2px 7px;
  border: 1px solid;
  border-radius: 3px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: transparent;
  white-space: nowrap;
}

/* success — the two settled, good outcomes */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-ready,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-approved {
  color: #4FD1A1;
  border-color: rgba(79, 209, 161, 0.50);
  background: rgba(79, 209, 161, 0.11);
}

/* promoted — in the Vault, a state of its own */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-promoted {
  color: #B79BFF;
  border-color: rgba(183, 155, 255, 0.50);
  background: rgba(183, 155, 255, 0.12);
}

/* destructive — refused, or failed */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-rejected,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-failed {
  color: #F06A67;
  border-color: rgba(240, 106, 103, 0.48);
  background: rgba(240, 106, 103, 0.11);
}

/* attention — a person has to do something */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-approval_requested,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-dedup-review,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-interrupted {
  color: var(--im-stamp);
  border-color: rgba(242, 184, 75, 0.50);
  background: rgba(242, 184, 75, 0.12);
}

/* information — the machine is working */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status.status-processing {
  color: var(--im-accent);
  border-color: rgba(85, 184, 255, 0.48);
  background: rgba(85, 184, 255, 0.12);
}

/* ── Action chips ─────────────────────────────────────────────────────────
   Seven competing hardcoded gradients (blue, amber, red, grey, purple, indigo,
   emerald), none of them the vessel's, collapse into ONE chip family with four
   intents. Handlers and labels unchanged; only the paint. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-add-items-btn,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-publish-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 28px;
  padding: 5px 11px;
  border: 1px solid;
  border-radius: 5px;
  background: transparent;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  opacity: 1;
  transition: background 160ms cubic-bezier(.2,.8,.2,1),
              border-color 160ms cubic-bezier(.2,.8,.2,1);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn:focus-visible,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-add-items-btn:focus-visible,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-publish-btn:focus-visible,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-delete-btn:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 2px;
}

/* the actionable ones — azure, the Room's own go */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--curate,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--resume {
  color: #06121F;
  background: var(--im-accent);
  border-color: var(--im-accent);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--curate:hover,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--resume:hover {
  background: #7ECAFF;
  border-color: #7ECAFF;
}

/* the secondary action — same family, quieter register */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-add-items-btn {
  color: var(--im-accent);
  border-color: rgba(85, 184, 255, 0.50);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-add-items-btn:hover {
  background: rgba(85, 184, 255, 0.14);
  border-color: var(--im-accent);
}

/* wants a person — the docket's saffron */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--dedup {
  color: var(--im-stamp);
  border-color: rgba(242, 184, 75, 0.55);
  background: rgba(242, 184, 75, 0.12);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--dedup:hover {
  background: rgba(242, 184, 75, 0.24);
}

/* commits to the Vault */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-publish-btn {
  color: #4FD1A1;
  border-color: rgba(79, 209, 161, 0.55);
  background: rgba(79, 209, 161, 0.12);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-publish-btn:hover {
  background: rgba(79, 209, 161, 0.24);
}

/* went wrong */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--incomplete {
  color: #F06A67;
  border-color: rgba(240, 106, 103, 0.48);
  background: rgba(240, 106, 103, 0.10);
  cursor: not-allowed;
}

/* NOTHING TO DO, AND IT SHOULD LOOK LIKE NOTHING TO DO.
   `--processing` is the one honest machine-progress chip and keeps the
   information hue; `--awaiting`, `--closed` and `--pending` are inert and take
   steel, so an idle, refused or human-blocked line reads as a line at rest
   rather than as work in flight. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--processing {
  color: rgba(85, 184, 255, 0.78);
  border-color: rgba(85, 184, 255, 0.34);
  background: rgba(85, 184, 255, 0.07);
  cursor: not-allowed;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--awaiting,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--closed,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn--pending {
  color: rgba(170, 181, 200, 0.72);
  border-color: rgba(170, 181, 200, 0.26);
  background: transparent;
  cursor: not-allowed;
  font-weight: 500;
}

/* The destructive control. The chip is Room-owned; the CONFIRMATION behind it
   is native window.confirm(), which is not a DOM node and cannot be styled —
   declared as a structural limit at S1 and carried to SR rather than replaced,
   because replacing it changes focus model and dismissal semantics. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-delete-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  min-height: 28px;
  padding: 4px 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: transparent;
  color: rgba(240, 106, 103, 0.82);
  font-size: 12px;
  transition: background 160ms cubic-bezier(.2,.8,.2,1),
              border-color 160ms cubic-bezier(.2,.8,.2,1),
              color 160ms cubic-bezier(.2,.8,.2,1);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-delete-btn:hover {
  color: #F06A67;
  border-color: rgba(240, 106, 103, 0.45);
  background: rgba(240, 106, 103, 0.14);
}

/* ── The left tally edge, in the Room's register ──────────────────────────
   Four values were already in styles.css and two were added by this pilot; all
   six are restated here in the vessel's palette so no row wears a colour from
   outside the docket. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.ready      { border-left-color: #4FD1A1; }
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.approved   { border-left-color: #4FD1A1; }
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.promoted   { border-left-color: #B79BFF; }
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.processing { border-left-color: var(--im-accent); }
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.awaiting   { border-left-color: var(--im-stamp); }
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.rejected,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card.widget-style.failed     { border-left-color: rgba(240, 106, 103, 0.62); }

/* ── The other surfaces of the same Room ──────────────────────────────────
   The resting-empty state, the loader and the error branch are preserved
   exactly as behaviours; they are given the docket's gutters so they do not
   sit against the vessel wall. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-content {
  padding: 0;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .empty-state,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .loading-indicator {
  padding: 34px var(--im-gutter);
  color: var(--im-ink-muted);
  text-align: center;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .empty-state h3 {
  color: var(--im-ink);
}

/* ⚠️ THE CLASS IS `sandbox-create-form`, AND S2 WROTE `create-batch-form`.
   S4 found the rule dead: `.create-batch-form` is a styles.css block for a form
   this app no longer renders anywhere (app/index.html:1850 emits
   `<div class="sandbox-create-form">`), so this gutter never applied and the
   create tab kept its browser-default gutters — which is a large part of why it
   still read as a raw administrative form inside the vessel. The selector was
   written from the stylesheet's block name instead of from the live markup.
   Guarded at root by verify-rooms.cjs, which now fails any room-scoped selector
   in either pilot stylesheet that matches no node in the rendered Room. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-create-form {
  padding: 16px var(--im-gutter) 24px;
}

/* ══════════════════════════════════════════════════════════════════════════
   § 3  S4 — the create tab: the entry form, and C2

   S2 recomposed the DOCKET tab and believed it had given this one the docket's
   gutters too; the rule was dead (see `.sandbox-create-form` above), so the
   create tab shipped at v1.0.181–.185 as a browser-default administrative form
   inside a sculpted vessel — white input boxes, system checkboxes, a terminal
   action below the fold. Everything below is presentation on the SAME nodes:
   no field added or removed, no handler, no `onclick`, no label, no name, no
   placeholder, no `required`, no validation. `#sandboxFileInput` and
   `.recording-indicator` carry `display:` from JS as BEHAVIOUR and are not
   touched here or anywhere in this file.
   ══════════════════════════════════════════════════════════════════════════ */

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-group {
  margin: 0 0 16px;
}

/* Field labels take the same operational register as the masthead and the
   docket count, so the form reads as part of the same document. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-group > label {
  display: block;
  margin: 0 0 6px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--im-ink-muted);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .label-hint {
  margin-inline-start: 6px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: none;
  opacity: 0.72;
}

/* The fields themselves. A white box is the single loudest thing in this Room;
   these become wells cut into the plate, in the vessel's own ink and rule. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-control {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--im-rule);
  border-radius: 4px;
  background: rgba(9, 15, 26, 0.55);
  color: var(--im-ink);
  font: inherit;
  font-size: 13px;
  line-height: 1.45;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-control::placeholder {
  color: rgba(170, 181, 200, 0.62);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-control:focus,
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-control:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 1px;
  border-color: var(--im-accent);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-textarea {
  min-height: 84px;
  resize: vertical;
}

/* The dictation control — a chip in the family the docket already uses. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-input-wrapper {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-mic-btn {
  flex: 0 0 auto;
  min-width: 34px;
  min-height: 34px;
  padding: 5px 8px;
  border: 1px solid var(--im-rule);
  border-radius: 5px;
  background: rgba(37, 50, 77, 0.42);
  color: var(--im-ink);
  cursor: pointer;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-mic-btn:hover {
  background: rgba(85, 184, 255, 0.16);
  border-color: var(--im-accent);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-mic-btn:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 2px;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-options {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin: 0 0 16px;
}

/* §2.3: two adjacent interactive controls keep 8px, and a checkbox keeps 8px
   from its own label — the `gap` below is that separation, declared. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--im-ink-muted);
  cursor: pointer;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-checkbox input:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 2px;
}

/* The intake mouth. Ruled rather than dashed-blue, and quiet enough that the
   terminal action below it stays the loudest thing on the surface. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-zone {
  margin: 0 0 16px;
  padding: 24px 16px;
  border: 1px dashed rgba(85, 184, 255, 0.42);
  border-radius: 5px;
  background: rgba(37, 50, 77, 0.22);
  cursor: pointer;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-zone:hover {
  border-color: var(--im-accent);
  background: rgba(85, 184, 255, 0.09);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .upload-title {
  margin: 8px 0 3px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--im-ink);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .upload-subtitle {
  margin: 0;
  font-size: 11.5px;
  color: var(--im-ink-muted);
}

/* ── C2: THE TERMINAL ACTION IS VISIBLE THE MOMENT THE TAB OPENS ───────────
   GEOMETRY_CONTRACT C2, the last of the three live violations S1 measured:
   `Create Media Profile & Upload` sat 74px below the visible well at v1.0.176
   and 58px below it at v1.0.185. The workflow's terminal action was not on
   screen when its own tab opened, at BOTH viewports, at default geometry.

   ⛔ COMPRESSING THE FORM WOULD NOT HAVE CLOSED IT. That was the first
   instinct and the arithmetic refuses it: at the Room's declared minimum the
   well is 350px tall, and a name field, a four-row textarea, two checkboxes and
   a drop zone do not fit in 350px at any type size a family member can read.
   A fix that works only at 1160x780 is a fix that fails exactly where the
   contract is tightest.

   So the action becomes STICKY at the foot of the scroll owner — which is the
   case §2.5 names in its own words, "fixed/floating-control exclusion zones
   reflected in content and scroll padding". Three things make that safe:

     · it is the LAST element in the form, so nothing can ever be trapped
       underneath it — the only thing that passes beneath is content the reader
       has already scrolled past;
     · the band is OPAQUE, so nothing shows through it and no text under it can
       lose contrast (§2.4);
     · the scroll owner reserves `--im-float-reserve` in `scroll-padding-block-
       end`, so a keyboard-focused field near the foot of the form scrolls clear
       of the band instead of under it.

   Handler, label, id and native <button> semantics are untouched. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #createBatchBtn {
  position: sticky;
  bottom: 0;
  z-index: 3;
  display: block;
  width: 100%;
  /* Full-bleed to the form's gutters so the band reads as the foot of the
     document rather than as a button floating over it. */
  margin: 4px calc(-1 * var(--im-gutter)) calc(-1 * var(--im-gutter));
  padding: 12px var(--im-gutter);
  border: 0;
  border-top: 1px solid rgba(85, 184, 255, 0.55);
  border-radius: 0;
  /* OPAQUE, deliberately — see above. */
  background: #123249;
  color: #EAF6FF;
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  cursor: pointer;
  box-shadow: 0 -12px 16px -12px rgba(4, 10, 18, 0.95);
  transition: background 160ms cubic-bezier(.2,.8,.2,1);
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #createBatchBtn:hover {
  background: #17456A;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #createBatchBtn:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: -4px;
}

/* The preview grid appears above the band once files are chosen. It keeps its
   own behaviour entirely; it is given the docket's rule so it does not arrive
   as a third visual language. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .preview-grid-container {
  margin: 0 0 12px;
  border-top: 1px solid var(--im-rule);
  padding-top: 12px;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .preview-grid-header h4 {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--im-ink-muted);
}

/* ── The create form retires height before the band has much to cover ──────
   ⚠️ WHAT THE PICTURE SAID, AND THE MEASUREMENT DID NOT. With C2 measuring
   `insideBody: true, offscreenByPx: 0` at both viewports, the minimum-geometry
   capture showed the pinned band resting across BOTH upload checkboxes. A
   sticky footer overlays whatever is at the foot of the scrollport — that is
   the pattern, and at full scroll every control clears it (verified, and
   asserted by verify-rooms.cjs) — but the well at the declared minimum is only
   350px tall, so at rest a great deal is under the band.

   This retires form HEIGHT at exactly that geometry, so less is under the band
   and the reader scrolls less far to clear it. It is keyed to the container's
   inline size rather than the viewport for the reason S2 established (a Room is
   dragged to size), and to `#sandboxCreateTab` rather than the form because an
   element is never matched by its own container.

   ⛔ Nothing is hidden, clamped or removed — the textarea's floor and three
   paddings shrink, and the textarea stays user-resizable. `rows="4"` is the
   markup's own attribute and is untouched. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #sandboxCreateTab {
  container-type: inline-size;
  container-name: im-create;
}

@container im-create (max-width: 720px) {
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-group {
    margin-bottom: 11px;
  }

  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-textarea {
    min-height: 58px;
  }

  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-options {
    margin-bottom: 11px;
  }

  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-zone {
    margin-bottom: 11px;
    padding: 13px 12px;
  }
}


/* ── Responsive retirement, before anything collides ──────────────────────
   A CONTAINER query, not a viewport query, and the distinction is the whole
   point: a Room is a window the family DRAGS TO SIZE. Its declared minimum is
   700x500 on a screen that may be 1920 wide, so `@media (max-width: …)` asks
   the wrong question — it would never fire for a small Room on a big monitor,
   which is exactly the case that needs it. (Written as a media query first;
   the 700x500 capture showed the columns holding and the query never firing,
   which is how the mistake was caught rather than reasoned about.)

   The containment goes on the LIST, not on `#view-sandbox`: the view is the
   Room's one scroll owner and already carries `contain: layout paint` from
   room-windows.css, and adding inline-size containment to a scroll container
   is not a change this pilot needs to make. Where @container is unsupported
   the docket simply stays three-column, which the minimum-geometry capture
   shows fitting — so the degradation is safe rather than merely unlikely. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batches-list {
  container-type: inline-size;
  container-name: im-docket;
}

@container im-docket (max-width: 860px) {
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card {
    /* Same floor/ceiling rule at the narrow docket: the old fixed 74px stats
       cell squeezed the Enrichment sentence to a few characters per line. */
    grid-template-columns: minmax(10em, 1fr) minmax(74px, fit-content(45%));
    gap: 8px 14px;
  }

  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-card-footer {
    grid-column: 1 / -1;
    grid-template-columns: 92px minmax(0, 1fr);
    padding-top: 6px;
    border-top: 1px solid rgba(40, 104, 145, 0.28);
  }
}

/* ── The chevrons stay decoration ─────────────────────────────────────────
   The chassis engraves five stage chevrons along the clip and burns a saffron
   CHECKSUM LIGHT at the end of the run. The chevrons were already faint; the
   checksum was not — a lit tick closing a five-stage run reads as "verified,
   complete", which is activity the docket beneath it is not doing. Above a
   list of thirty refused profiles it is simply false, and the commission's
   own words are that the chevrons "must not imply activity for an empty,
   rejected, or idle profile."

   So the checksum is brought down into the same ENGRAVED register as the rule
   line and the chevrons it terminates. It is still there — it is part of the
   vessel's authored identity and this pilot does not redraw the silhouette —
   it is no longer lit.

   ⛔ This does NOT answer the question S1 carried to Joe: whether the five
   chevrons may ever carry meaning (the workflow exposes nine per-profile
   statuses over four widget classes, and no global stage sequence at all).
   That stays open, with its picture, for SR. Reverting is these six lines. */
.ffrw-import-media .ffvc-checksum-ring {
  stroke: rgba(170, 181, 200, 0.34);
}

.ffrw-import-media .ffvc-checksum-tick {
  stroke: rgba(170, 181, 200, 0.40);
}

/* ── Reduced motion ──────────────────────────────────────────────────────
   Every transition above is a colour transition on a control, which
   prefers-reduced-motion does not require removing — but the vault's practice
   is to still them anyway, and a docket has no reason to animate. */
/* ⚠️ A LIST, NOT A CLASS — WHICH IS WHY IT KEPT BEING WRONG. S2 enumerated the
   six nodes it had styled. S4 added five more when the create tab became Room
   surface, then a re-run found a sixth (`.upload-protection-banner`) the first
   extension had missed, and the run after THAT found three more
   (`.overall-progress-fill`, `.pipeline-node`, `.entertainment-text`) that only
   render while an upload is in flight. Three rounds of whack-a-mole against a
   renderer whose node inventory depends on state.

   The honest scope of "reduced motion" in this Room is: everything in this
   Room's well. `*` inside one audited, room-scoped well is not the blanket skin
   the commission forbids — that prohibition is about STYLING unaudited markup,
   and this styles nothing. It withdraws motion, which is exactly and only what
   the reader asked for, and it cannot go stale when the renderer grows a node.

   ⛔ `animation` is deliberately NOT killed. A loading spinner that stops
   spinning reads as a hung Room; the preference asks for less motion, not for
   the loss of the one signal that says work is happening. */
@media (prefers-reduced-motion: reduce) {
  /* THE FLOOR — catches any node no rule below names. `*` contributes nothing
     to specificity, so this is (0,3,1) and loses to every single-class rule in
     this file, which is exactly why it cannot stand alone: replacing the list
     with it made things WORSE, waking transitions on nodes S2 and S3 had
     already stilled. Kept as the floor for markup nobody has enumerated yet. */
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted * {
    transition: none;
  }

  /* THE LIST — one entry per node whose own rule outranks the floor. */
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-add-items-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-publish-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-delete-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #createBatchBtn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-control,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-mic-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-zone,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .filter-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .upload-protection-banner,
  /* these three render only while an upload is in flight */
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .overall-progress-fill,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .pipeline-node,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .entertainment-text {
    transition: none;
  }
}

/* ⚠️ THE LIST ABOVE IS FRAGILE BY CONSTRUCTION, AND KNOWING WHY IS THE POINT.
   It went wrong three times: S2 enumerated the six nodes it had styled; S4 added
   five when the create tab became Room surface; a re-run found a sixth the first
   extension missed; the run after that found three more that exist only while an
   upload is running. Each round was correct and each was incomplete, because the
   set of nodes in this well depends on renderer STATE.

   The floor cannot fix it: `*` is (0,3,1) and every rule it needs to beat is
   (0,4,1) or higher. The only CSS answers are `!important` — which the
   commission forbids as a sweep, and forbids for good reason — or raising this
   file's specificity, which is an arms race with `styles.css`.

   ⭐ THE ACTUAL ROOT FIX IS NOT IN THIS FILE. The base transitions should be
   authored inside `@media (prefers-reduced-motion: no-preference)` in
   `styles.css`, so motion is never declared for a reader who asked for none and
   nothing has to be un-declared afterwards. That is an app-wide change to a
   shared stylesheet, well outside a two-Room presentation pilot — carried to SR
   as a finding, with this list as the interim. */

/* ── Forced colours ──────────────────────────────────────────────────────
   Under a forced-colours palette every background and border above is
   discarded by the UA, which would leave the tabs, chips and badges as
   undifferentiated text. Restoring a system border on each one keeps the
   shapes — and therefore the state distinctions — legible. */
@media (forced-colors: active) {
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-status,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-review-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-add-items-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-publish-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .batch-delete-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-batch-card {
    /* Shape only. The UA owns the palette in this mode and is left to own it;
       all that is restored is the border that tells one region from the next. */
    border: 1px solid ButtonBorder;
  }

  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-tab-btn.active {
    border-bottom: 3px solid Highlight;
  }

  /* S4. The create tab's fields and its sticky terminal action. The band's
     opacity is what keeps scrolled content from showing through it, and under
     a forced palette `background: #123249` is discarded — so the system's own
     Canvas is restored explicitly. Without it the band would go transparent
     and the form would scroll visibly through the terminal action. */
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .form-control,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .context-mic-btn,
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-upload-zone {
    border: 1px solid ButtonBorder;
  }

  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #createBatchBtn {
    background: Canvas;
    border-top: 2px solid Highlight;
  }

  /* ⚠️ OPACITY IS THE ONE THING A FORCED PALETTE CANNOT REPAIR. The UA
     substitutes its own colours for ours and thereby guarantees the contrast
     of the PAIR — but `opacity: 0.62` is applied afterwards, to the composited
     result, so the masthead came out washed to near-invisibility while every
     colour in it was technically the system's own. Found by looking at the
     forced-colors capture, not by any contrast number. The subtitle is
     essential text (§2.9); it is returned to full strength here and keeps its
     quieter weight everywhere else. */
  .ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .view-header p {
    opacity: 1;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   IMPORT MEDIA v14 — the ported Intake Manifest.  (porting-perimeter-souls S3)

   Everything below this line is reached ONLY through `html.ffv-modal-fleet-v14`,
   the reflection FFAFlags writes for `ffa_modal_fleet_v14`. With the flag off
   not one selector here matches, and the room renders exactly as the lines
   above render it.

   WHY THE REFLECTION AND NOT A JS BRANCH. The LINEWORK half gates itself inside
   layers(): flag-off never emits a `.ffvc-v14-*` element, so those rules could
   not match anyway and are belt-and-braces. The SHELL half cannot work that
   way — this room's v14 chassis needs its own weights on `.ffvc-rim-glow`,
   `.ffvc-body` and `.ffvc-lip`, three classes room-windows.css draws in BOTH
   flag states. An unconditioned override would reach the flag-off room and
   break the byte-identity that makes this flag a rollback path.

   ── THE APERTURE IS UNCHANGED HORIZONTALLY, AND THAT IS THE POINT ─────────
   Nothing here touches `.ffrw-header`'s or `.ffrw-body`'s insets. The port's
   only geometry is vertical and it moves through the theme's own DERIVED
   keep-outs (129 / 89, from 74 / 38), and `#view-sandbox` remains the one
   scroll owner — the drop target, the stage list, the job identifiers and the
   recovery language are untouched by a chassis port. FIVE units of that raise
   is the decoration: the manifest lines are the only furniture that drives
   either band, and the steel lip asks 124 / 89 on its own. The old 74 (10.6%)
   was far shallower than the accepted standard; 129/700 is 18.4% against the
   Family Navigator's praised 20.4%.

   ── STROKE WIDTHS ARE THE ONE JUDGEMENT ──────────────────────────────────
   Colours and opacities carry over from the lab unchanged — they are unitless
   and a coordinate change cannot touch them. Widths cannot: the lab draws in
   1600x1000 and this fleet in 1000x700, both stretched to their container, so
   a horizontal stroke wants 0.625 and a vertical one 0.7, and one number
   cannot be both. Every width below is the lab's times the GEOMETRIC MEAN,
   sqrt(0.625 * 0.7) = 0.6614, which preserves stroke area and splits the
   residual evenly. Each is written as `lab N x 0.6614` so the arithmetic is
   checkable rather than trusted.
   ═══════════════════════════════════════════════════════════════════════════ */

html.ffv-modal-fleet-v14 .ffrw-import-media {
  --v14-amber: #f2b84b;   /* the lab's --room-a     */
  --v14-azure: #50d8ff;   /* the lab's --room-b     */
  --v14-rose:  #ef3fa5;   /* the lab's --room-c     */
  --v14-metal: #7fd3b2;   /* the lab's --room-metal */
}

/* The shell: the lab's heavy aura, its solid rim and its pale inner lip. These
   three override the fleet-wide widths in room-windows.css, which is why they
   carry the room class as well as the flag class. */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-rim-glow { stroke-width: 6.61; opacity: .24; }   /* lab 10  x 0.6614 */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-body     { stroke-width: 2.65; }                 /* lab 4   x 0.6614 */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-lip      { stroke: rgba(220, 246, 255, .45); stroke-width: .99; opacity: 1; }  /* lab 1.5 x 0.6614 */

/* the room's furniture, all of it in the margins the working panel leaves */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock path,
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-guiderail path,
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dockfoot path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* the head: the ruled manifest lines either side of the clip */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-manifest-lines {
  stroke: var(--v14-metal);
  stroke-width: 1.32;                                                                             /* lab 2   x 0.6614 */
}

/* the intake tray crest, seated on the clip plateau (sunk 10.7 — see the theme) */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-hero-ring { fill: rgba(4, 15, 26, .96); stroke-width: 1.46; }  /* lab 2.2 x 0.6614 */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-hero-line {
  stroke: color-mix(in srgb, var(--v14-amber) 78%, #ffffff 8%);
  stroke-width: 1.32;                                                                             /* lab 2   x 0.6614 */
}

/* the flanks: the guide-rail uprights and their rivets, flanked out into the
   x 33..47 reveal the solver measured against the vessel wall */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock-post {
  stroke: var(--v14-azure);
  stroke-width: 3.97;                                                                             /* lab 6   x 0.6614 */
}
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock-rivet {
  fill: #10181c;
  stroke: var(--v14-metal);
  stroke-width: 1.98;                                                                             /* lab 3   x 0.6614 */
}

/* the foot: the dock's two rails, the conveyor, and the blank manifest stamp */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock-rail {
  stroke: color-mix(in srgb, var(--v14-azure) 60%, #40484a);
  stroke-width: 3.31;                                                                             /* lab 5   x 0.6614 */
}
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-conveyor {
  stroke: var(--v14-metal);
  stroke-width: 1.32;                                                                             /* lab 2   x 0.6614 */
}
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-manifest-stamp {
  fill: rgba(24, 29, 28, .9);
  stroke: var(--v14-amber);
  stroke-width: 1.32;                                                                             /* lab 2   x 0.6614 */
  stroke-dasharray: 4.63 2.65;                                                                    /* lab 7 4 x 0.6614 */
}

/* ── motion ────────────────────────────────────────────────────────────────
   The lab gives this room exactly ONE moving part — the conveyor, a dashed
   stroke running along the dock rail — and nothing else in `manifest` breathes,
   turns or chases. That restraint is the room's register (working steel, not
   atmosphere) and it is carried rather than embellished: no travelling signal
   on the posts, no pulse on the checksum, no breath on the crest.

   The dash lengths are lengths ALONG A PATH and take the same geometric mean
   as a stroke width; so does the offset the keyframe animates to. Under
   `prefers-reduced-motion: reduce` this block simply does not apply, which
   leaves the conveyor a plain solid chevron rather than a frozen dashed one —
   the lab's own parity, and the reason the dasharray lives in here with the
   animation rather than outside it. */
@media (prefers-reduced-motion: no-preference) {
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-conveyor {
    stroke-dasharray: 10.58 6.61;                                                                 /* lab 16 10 x 0.6614 */
    animation: ffvc-v14-conveyor-run 5s linear infinite;
  }
}
@keyframes ffvc-v14-conveyor-run { to { stroke-dashoffset: -68.79px; } }                          /* lab -104 x 0.6614 */

/* ── forced colours ────────────────────────────────────────────────────────
   The UA discards the fills and strokes above. The chassis is decoration and
   is allowed to disappear — what may NOT happen is the posts, the rails and
   the manifest stamp surviving as unstyled black-on-black shapes across the
   room's head, flanks and foot. Hand them the system's own pairing so they
   either read or vanish cleanly. */
@media (forced-colors: active) {
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-manifest-stamp,
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock-rivet {
    fill: Canvas;
    stroke: CanvasText;
  }
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-manifest-lines,
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock-post,
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-dock-rail,
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-conveyor,
  html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-hero-line {
    stroke: CanvasText;
  }
}


/* ══════════════════════════════════════════════════════════════════════════
   § F14 · F15 — DEFINING A BATCH GETS THE WHOLE STAGE (Lane 1, 2026-09-24)
   Joe: "When I am defining a new batch it should get the whole modal stage, as
   it did at one time in the past." Measured: the Ambient Fergi rail (the
   search-shaped first row), the "Upload and curate…" masthead and the tab strip
   all survived above the form, the chassis repeated its own title as a footer
   pill, and the Create action rendered below the frame.
   ══════════════════════════════════════════════════════════════════════════ */

/* F14 — the defining state (sandbox.js showSandboxTab toggles the class). Every
   direct child of the view except the form stands down: the rail, the masthead,
   the tab strip, the other tabs' panels. Not room-scoped: on a phone the form
   deserves the whole screen for the same reason. The Control Center is exempt
   (it is re-mounted to <body> when shown, but never hide it if it is not). */
#view-sandbox.is-defining-batch > :not(#sandboxCreateTab):not(#sandboxUploadProgress) {
  display: none !important;
}

.sandbox-create-back {
  display: none;
}
#view-sandbox.is-defining-batch .sandbox-create-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 14px;
  padding: 6px 12px;
  border: 1px solid rgba(40, 104, 145, 0.6);
  border-radius: 6px;
  background: transparent;
  color: #AAB5C8;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
}
#view-sandbox.is-defining-batch .sandbox-create-back:hover { color: #F2F7FF; border-color: #55B8FF; }
#view-sandbox.is-defining-batch .sandbox-create-back:focus-visible { outline: 2px solid #FFFFFF; outline-offset: 2px; }

/* The stage the rows gave back goes to the form's own top gutter. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted.is-defining-batch #sandboxCreateTab {
  padding-top: var(--im-gutter);
}

/* F15 — the form must not overflow the chassis. The sticky Create band carried
   `margin-bottom: calc(-1 * gutter)` to bleed over the form's foot padding; a
   sticky box is held to the scrollport by its MARGIN box, so a negative bottom
   margin parks the border box one gutter BELOW the visible well — the Create
   button Joe saw rendered under the frame. Zero it; the band still bleeds side
   to side. */
.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted #createBatchBtn {
  margin-bottom: 0;
}

/* F15 — one room title, and it is the chassis header's. The skirt nameplate
   ("INTAKE MANIFEST") is the same duplicate the § Room identity rule already
   retired for the in-view H2 — it goes too. VISIBILITY, not display: the plate
   carries the theme's foot keep-out as its margin, and removing its box would
   let the well slide down over the dock's foot furniture. */
.ffrw-import-media .ffrw-nameplate {
  visibility: hidden;
}

/* F15 — the empty bottom slot. The v14 foot's "blank manifest stamp" is a
   dashed saffron frame that names nothing and holds nothing (nothing is ever
   docked into it); drawn under the pill it read as an empty drop target. The
   rails and the conveyor — the room's one moving part — stay. */
html.ffv-modal-fleet-v14 .ffrw-import-media .ffvc-v14-manifest-stamp {
  display: none;
}

/* sandbox.js interruptedUploadNoticeHtml() — the quiet cancel-or-resume line.
   restoring-takeout-substitutes S2, Joe's ruling (h), 2026-09-28: a backend restart no
   longer waits for an interrupted upload, and the uploader sees this on their next visit.
   Quiet by the ruling: body-weight text in the muted ink, no icon, no alarm colour, no
   border. The two actions read as inline links, not buttons. */
.sandbox-interrupted-notice {
  margin: 0 4px 14px;
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--color-text-light);
}

.sandbox-interrupted-notice__action {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.ffrw-import-media .ffrw-body > #view-sandbox.ffrw-hosted .sandbox-interrupted-notice {
  margin: 0;
  padding: 0 var(--im-gutter) 10px;
}
