/* ---------- Novel Forge: the Audio desk ----------
   plans/VOICE-DIRECTION.md §3. One sheet, one room, the house tokens only —
   NOT A COLOUR IS TYPED IN THIS FILE, the theme law, same rule reader.css
   states for itself. The centre canvas (rooms/forge-novel.js) and the Tool
   Box (rooms/audiobook-panel.js) share this one sheet, the way the Reader's
   page and its panels share reader.css. */

/* ---------- empty states: the honest ones, before a work or a route ---------- */
.novel-empty { max-width: 56ch; margin: 15vh auto 0; padding: 0 20px; text-align: center; }
.novel-empty-h { font-size: var(--t-head); font-weight: var(--w-semi); color: var(--text); margin-bottom: 10px; }
.novel-empty-p { font-size: var(--t-sub); color: var(--muted); line-height: var(--lh-read); margin-bottom: 16px; }
.novel-empty-actions{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--s3)}
.novel-empty-import{position:relative;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}

/* ---------- the desk: one chapter's own text ---------- */
.novel-desk { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.novel-head {
  display: flex; align-items: baseline; gap: 10px; padding: 14px 24px;
  border-bottom: var(--bd) solid var(--edge);
}
.novel-ch { font-size: var(--t-tiny); color: var(--muted); }
/* THE CHAPTER LINE'S TRANSPORT (M-18, ruled by Mark 2026-08-24): the title
   keeps the left and the press takes the right, which is what the auto
   margin is for rather than a spacer element. It reads quiet until it is
   reached for, the same manners as .novel-edit and .novel-dl below, because
   the words are what the room is for and the control is not competing with
   them. Aligned to CENTER against a baseline row: a glyph and a word have no
   shared baseline worth honouring, and baseline alignment visibly drops the
   icon below the line. */
.novel-listen {
  margin-left: auto; align-self: center; display: inline-flex; align-items: center; gap: 6px;
  border: var(--bd) solid var(--edge); background: none; color: var(--muted);
  font-size: var(--t-tiny); cursor: pointer; padding: 3px 10px; border-radius: var(--r-sm);
}
.novel-listen:hover { color: var(--accent); border-color: var(--accent); }
.novel-listen svg { flex: none; }
.novel-listen-w { line-height: 1; }
.novel-page { flex: 1; min-height: 0; overflow: auto; padding: 24px; max-width: 74ch; margin: 0 auto; }
.novel-p { font-size: var(--t-body); line-height: var(--lh-read); color: var(--text); margin-bottom: 1em; }

/* THE UNDIRECTED NOTICE sits under the real text, not over it — the words
   are the proof the desk has the real book, and the notice is honest about
   what has not happened to them yet. */
.novel-undirected {
  border-top: var(--bd) solid var(--edge); padding: 16px 24px; text-align: center;
  background: var(--inset);
}
.novel-undirected-p { font-size: var(--t-tiny); color: var(--muted); max-width: 60ch; margin: 0 auto 10px; }

/* ---------- the Tool Box: the chapter rail and the render bar ---------- */
.novel-toolbox { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.novel-toolbox-empty { padding: 20px; font-size: var(--t-tiny); color: var(--muted); text-align: center; }
.novel-rail { flex: 1; min-height: 0; overflow: auto; }
.novel-rail-row {
  position: relative;
  display: flex; flex-direction: column; gap: 3px; width: 100%; text-align: left;
  background: none; border: 0; border-bottom: var(--bd) solid var(--edge);
  padding: 10px 40px 10px 14px; cursor: pointer; color: var(--text);
}
.novel-rail-row:hover { background: var(--inset); }
.novel-rail-row.on { background: var(--sel); }
/* The play on a rendered row: the list is where you see what is done and
   hear it. A nested action, so the press plays without turning the chapter. */
.novel-rail-play {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--r-sm); color: var(--accent);
}
.novel-rail-play:hover { background: var(--sel); }
.novel-rail-t { font-size: var(--t-sub); font-weight: var(--w-med); }
.novel-rail-s { font-size: var(--t-tiny); letter-spacing: var(--ls-label); }
.novel-state-undirected { color: var(--muted); }
.novel-state-drafted { color: var(--text); }
.novel-state-kept, .novel-state-rendered { color: var(--accent); }
/* THE FIFTH STATE HAD NO RULE UNTIL NOW, so "Words changed" printed in the
   row's own colour while the four states around it each had one, and the only
   WARNING among the five was the one that looked like every other report. It
   takes --danger, which is the colour the re-keep button beside it already
   wears (.novel-stale, below), so one fault reads as one colour. */
.novel-state-stale { color: var(--danger); }

/* Rendering IS wired up (src/routes/audiobook.mjs, the render pass, 2026-08-22).
   The off state is not a feature standing in for itself any more: it is one of
   two real conditions the desk can be in, no chapter kept yet, or a character
   in this chapter with no frontier voice cast, and rooms/audiobook-panel.js
   renderBar says which in words. It stays visible and disabled rather than
   hiding, because a gap where a control belongs reads as a bug, and there is
   no price to print until a chapter is kept (plans/VOICE-DIRECTION.md §3,
   "the price is printed before the press"). */
.novel-render {
  border-top: var(--bd) solid var(--edge); padding: 12px 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.novel-render-off { opacity: .75; }
.novel-render-line { font-size: var(--t-tiny); color: var(--muted); line-height: var(--lh-read); }
.novel-render-go[disabled] { opacity: .5; cursor: not-allowed; }

/* ---------- the directed chapter: passages, not paragraphs ----------
   Once a chapter is directed the page IS the performance, so a passage
   wears its cue above its words the way a script does. The prose keeps
   `.novel-p` in both states on purpose: the words do not change size or
   face when they gain a speaker, because they are the same words. */
.novel-passage { margin-bottom: 22px; }
.novel-cue { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }
.novel-speaker {
  font-size: var(--t-label); font-weight: var(--w-bold); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--muted);
}
/* A named character reads as the accent; the narrator stays quiet, because
   the narrator is the common case and a highlight on every passage is a
   highlight nobody sees. */
.novel-speaker-cast { color: var(--accent); }
.novel-delivery { font-size: var(--t-tiny); font-style: italic; color: var(--muted); }
.novel-pause {
  font-size: var(--t-label); letter-spacing: var(--ls-label); color: var(--muted);
  border: var(--bd) solid var(--edge); border-radius: var(--r-pill); padding: 1px 8px;
}

/* ---------- the two bars under the page ---------- */
.novel-cost { font-size: var(--t-label); color: var(--muted); max-width: 60ch; margin: 8px auto 0; }
/* A refusal speaks where the press was, and stays until the next one
   succeeds — fail soft, never fail silent. */
.novel-refused { font-size: var(--t-tiny); color: var(--danger); max-width: 60ch; margin: 0 auto 10px; }

.novel-keepbar {
  border-top: var(--bd) solid var(--edge); padding: 14px 24px; background: var(--inset);
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
}
.novel-draft-line, .novel-kept-line { font-size: var(--t-tiny); color: var(--muted); line-height: var(--lh-read); max-width: 64ch; }
.novel-kept-line { color: var(--accent); }

/* ---------- THE BAND, IN THE PANEL (M-19, ruled by Mark 2026-08-24) -------
   Both bars above were dressed as a FOOTER: a rule along the top, the page's
   own 24px side padding, and the inset fill that set them off from the words
   over them. None of that is true any more. In the Cast tab they are the
   FIRST thing in the panel, so the rule goes underneath instead of over,
   the page padding comes off because the panel supplies its own measure, and
   the inset fill goes because there is nothing above to be set off from.

   The row goes to a COLUMN. .novel-keepbar is a space-between row built for
   a page 74ch wide; in a panel of about 180px a note and a button side by
   side squeezes the note to one word a line, which is the exact fault the
   listening window's own keep row hit and had to be ruled out of. */
.novel-band { display: flex; flex-direction: column; gap: 10px; padding-bottom: 12px;
  border-bottom: var(--bd) solid var(--edge); }
.novel-band .novel-keepbar, .novel-band .novel-undirected {
  border-top: 0; padding: 0; background: none; text-align: left;
  display: flex; flex-direction: column; align-items: stretch; gap: 8px;
}
.novel-band .novel-undirected-p, .novel-band .novel-cost, .novel-band .novel-refused,
.novel-band .novel-draft-line, .novel-band .novel-kept-line { max-width: none; margin: 0; }

/* THE DESK WHILE A DOOR IS OPEN. One line, naming which pass of how many,
   and every press is gone while it runs: a chapter is directed window by
   window and a second press would spend twice and race the revision it is
   writing. Wait state dies with the tab (lib/audiobook-store.js). */
.novel-working {
  border-top: var(--bd) solid var(--edge); padding: 16px 24px; text-align: center; background: var(--inset);
}
.novel-working-line { font-size: var(--t-tiny); color: var(--accent); letter-spacing: var(--ls-label); }
.novel-toolbox-note {
  padding: 10px 14px; font-size: var(--t-label); color: var(--muted);
  letter-spacing: var(--ls-label); border-bottom: var(--bd) solid var(--edge);
}

/* ---------- the cue names the voice, and the voice is a press ----------
   Mark, 2026-08-22: "where it shows notes should also call out the model and
   voice". An uncast seat says so in the cue and IS the press that fixes it,
   which is the never-silently-cast law worn on the page. */
.novel-voice {
  border: 0; background: none; font: inherit; font-size: var(--t-tiny);
  color: var(--accent); cursor: pointer; padding: 0; letter-spacing: var(--ls-label);
}
.novel-voice:hover { color: var(--ink); text-decoration: underline; }
.novel-voice-none { color: var(--muted); font-style: italic; }
.novel-engine { color: var(--muted); font-style: normal; }
.novel-engine::before { content: " · "; }

/* ---------- the cast panel, behind the megaphone ---------- */
.novel-cast { flex: 1; min-height: 0; overflow: auto; }
.novel-cast-note {
  padding: 10px 14px; font-size: var(--t-label); color: var(--muted);
  line-height: var(--lh-read); border-bottom: var(--bd) solid var(--edge);
}
.novel-cast-row {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  padding: 10px 14px; border: 0; border-bottom: var(--bd) solid var(--edge);
  background: none; font: inherit; cursor: pointer;
}
.novel-cast-row:hover { background: var(--sel); }
.novel-cast-n { flex: 1; min-width: 0; font-size: var(--t-small); color: var(--ink); }
.novel-cast-v { font-size: var(--t-tiny); color: var(--accent); }
.novel-cast-v.none { color: var(--muted); font-style: italic; }
.novel-cast-e { font-size: var(--t-tiny); color: var(--muted); }

/* ---------- the bars' buttons wear the house's proportions ----------
   Mark, 2026-08-22: "the massive response button on the bottom look weird."
   .work-button is a CARD button and its `width:100%` is right inside a narrow
   card; these two bars are the width of the whole canvas, so the same class
   stretched a button clean across the room. Nothing else about it changes:
   same padding, same tokens, same colours, auto width like every other button
   standing in a bar. */
.novel-keepbar .work-button,
.novel-undirected .work-button { width: auto; min-width: 0; }
/* The direct bar centres its own column, so its button centres with it. */
.novel-undirected .work-button { display: inline-block; }

/* ---------- the writing room (plans/NOVEL-FORGE.md A21, slice one) ----------
   Same room, second face. THE WRITING SURFACE JOINED THE READING SURFACE'S
   LAW (Mark's ruling, 2026-08-23: "without a question the default writing
   needs to be this style", looking at the Reader's own manuscript mode) —
   it earned its own rack, and this is that. `.rd-m-sheet` (reader.css,
   unscoped) is the paper itself: background, border, font, size, leading,
   all read off `--rd-page-*`/`--rd-face`/`--rd-size`/`--rd-leading`. NOT A
   COLOUR IS TYPED BELOW — the theme law, same rule reader.css states for
   itself. This file only adds the flex geometry a gutter beside a live
   textarea needs. */
.fw-desk { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.fw-m-page { flex: 1; min-height: 0; display: flex; justify-content: center; padding-top: 12px; }
/* padding:0 cancels .rd-m-sheet's own 26px 0 — the gutter and the textarea
   each carry that inset themselves below, so it is not paid twice. */
.fw-m-sheet { display: flex; min-height: 0; overflow: hidden; padding: 0; }
.fw-m-gutter {
  flex: 0 0 6ch; position: relative; overflow: hidden;
  padding: 26px 0 26px 14px; user-select: none;
}
.fw-m-gutter-in { position: relative; }
/* One number per HARD line, positioned at its own measured offset
   (rooms/forge-write.js armManuscriptGutter — the inline `top` there is
   the documented data-driven exception, recorded in the census). */
.fw-m-gnum {
  position: absolute; left: 0; right: 2ch; text-align: right;
  opacity: .45; font-size: var(--t-tiny); line-height: var(--rd-leading, var(--lh-read));
}
.fw-m-text {
  flex: 1; min-width: 0; min-height: 0; resize: none; border: 0; background: none; color: inherit;
  padding: 26px 30px 26px 6px;
  font-family: var(--rd-face, var(--font-ui)); font-size: var(--rd-size, 17px);
  line-height: var(--rd-leading, var(--lh-read));
}
.fw-m-text:focus { outline: none; }
/* THE HIDDEN MIRROR — shares .fw-m-text's own font/padding/wrap so its
   lines' offsetHeight is the textarea's true wrapped-row count; never
   painted, never in the tab order. */
.fw-m-mirror {
  position: absolute; visibility: hidden; left: -9999px; top: 0;
  height: auto; pointer-events: none; white-space: pre-wrap; overflow-wrap: break-word;
}
.fw-m-mirror div { white-space: pre-wrap; overflow-wrap: break-word; }
.fw-status {
  max-width: 78ch; margin: 6px auto 0; width: 100%;
  font-size: var(--t-tiny); color: var(--muted); text-align: right;
}
.fw-status-live { color: var(--accent); }

/* the lobby */
.fw-project { display: flex; justify-content: space-between; gap: 10px; margin: 6px auto; }
.fw-project-n { color: var(--muted); font-size: var(--t-tiny); }
.fw-new { margin-top: 18px; display: flex; flex-direction: column; gap: 6px; align-items: center; }
.fw-hint { font-size: var(--t-tiny); color: var(--muted); }
.fw-name {
  width: 100%; max-width: 34ch;
  background: var(--inset); color: var(--text);
  border: var(--bd) solid var(--edge); border-radius: var(--r-sm);
  padding: 8px 10px; font-size: var(--t-sub);
}

/* The Set (the left panel's second tab) */
.fw-set { display: flex; flex-direction: column; height: 100%; min-height: 0; }
/* THE HAMBURGER, across from the title (Mark's design, 2026-08-23) — the
   title keeps its own type, the head carries the padding the title used to
   carry alone. */
.fw-set-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 10px 8px 14px; }
.fw-set-title { padding: 0; font-size: var(--t-sub); font-weight: var(--w-semi); }
/* TWO SEATS NOW, the audio door and the status toggle (Mark, 2026-08-24), in
   a row of their own so the head's own space-between keeps the title away
   from both rather than from whichever one happened to be last. The lit rule
   is the outline button's own, renamed with the seat that replaced it: only
   the toggle can be lit, because a door is never on. */
.fw-set-seats { display: inline-flex; align-items: center; gap: 2px; }
.fw-set-head-btn.on { color: var(--accent); background: var(--sel); }
/* The honest line under the head when the toggle is on and nothing has been
   read yet. Quiet, and shaped like .fw-set-total beneath it, because it is a
   note about the list and not a refusal. */
.fw-set-unread { padding: 0 14px 8px; font-size: var(--t-tiny); color: var(--muted); line-height: var(--lh-read); }
.fw-set-list { flex: 1; min-height: 0; overflow: auto; }
.fw-set-row {
  position: relative; display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  background: none; border: 0; border-bottom: var(--bd) solid var(--edge);
  padding: 9px 10px 9px 14px; cursor: pointer; color: var(--text);
}
.fw-set-row:hover { background: var(--inset); }
.fw-set-row.on { background: var(--sel); }
.fw-set-t { font-size: var(--t-sub); }
.fw-set-k { font-size: var(--t-tiny); color: var(--muted); }
.fw-set-dot {
  position: absolute; left: 4px; top: 50%; transform: translateY(-50%);
  width: 6px; height: 6px; border-radius: var(--r-round); background: var(--accent);
}
.fw-set-foot { padding: 10px 14px 14px; display: flex; flex-direction: column; gap: 10px; }

/* the import review */
.fw-import-file { position: absolute; width: 1px; height: 1px; opacity: 0; }
.fw-import-pick { position: relative; display: block; cursor: pointer; }
.fw-import-line { font-size: var(--t-tiny); color: var(--muted); line-height: var(--lh-read); }
.fw-import { display: flex; flex-direction: column; gap: 8px; }
.fw-import-row {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  background: var(--inset); border: var(--bd) solid var(--edge); border-radius: var(--r-sm);
  padding: 6px 10px; cursor: pointer; color: var(--muted);
}
.fw-import-row.on { color: var(--text); border-color: var(--accent-line, var(--accent)); }
.fw-import-mark { width: 14px; color: var(--accent); }
.fw-import-t { font-size: var(--t-tiny); }
.fw-import-n {
  margin-left: auto; font-size: var(--t-tiny); opacity: 0.7;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 12ch;
}
.fw-import-acts { display: flex; gap: 8px; align-items: center; }
.fw-import-no { opacity: 0.7; }

/* the Tool Box on the writing face: the desk's materials */
.fw-tools { flex: 1; min-height: 0; overflow: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.fw-tools-h { font-size: var(--t-label); letter-spacing: var(--ls-label); color: var(--muted); text-transform: uppercase; margin-top: 6px; }
/* MUTED, NOT ACCENT (the lane brief, 2026-08-23, the named tell): a plain
   count read as a link when it wore the accent colour. Used for both THIS
   CHAPTER's own count and THE BOOK's total — neither is a press. */
.fw-tools-count { font-size: var(--t-tiny); color: var(--muted); }
.fw-tools-quiet { font-size: var(--t-tiny); color: var(--muted); line-height: var(--lh-read); }

/* THE SYNOPSIS, under This chapter: quiet text and its pencil, the row
   ops' own .fw-op reused rather than a second icon style. */
.fw-syn { display: flex; align-items: baseline; gap: 8px; }
.fw-syn-t { flex: 1; min-width: 0; font-size: var(--t-tiny); color: var(--text); line-height: var(--lh-read); }
.fw-syn-empty { color: var(--muted); font-style: italic; }
.fw-syn-edit .fw-name { max-width: none; width: 100%; }

/* Bring in your draft, DEMOTED once the book has chapters (the lane brief,
   2026-08-23): one small quiet seat at the foot, never a work-button. */
.fw-tools-quiet-seat { margin-top: 6px; padding-top: 6px; border-top: var(--bd) solid var(--edge); }
.fw-import-pick-quiet { display: block; cursor: pointer; }
.fw-import-quiet { font-size: var(--t-tiny); color: var(--muted); }
.fw-import-pick-quiet:hover .fw-import-quiet { color: var(--accent); text-decoration: underline; }
.fw-cast-row {
  display: flex; align-items: baseline; gap: 8px;
  background: var(--inset); border: var(--bd) solid var(--edge); border-radius: var(--r-sm);
  padding: 7px 10px;
}
.fw-cast-n { font-size: var(--t-sub); font-weight: var(--w-med); color: var(--text); }
.fw-cast-note { font-size: var(--t-tiny); color: var(--muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fw-cast-x {
  margin-left: auto; background: none; border: 0; padding: 2px; cursor: pointer;
  color: var(--muted); display: inline-flex; border-radius: var(--r-sm);
}
.fw-cast-x:hover { color: var(--text); background: var(--sel); }

/* ---------- the per-passage edit (2026-08-22) ----------
   The quiet Edit press on a cue, the inline editor under it, and the stale
   chip a passage wears when its rendered audio was cleared by an edit. */
.novel-edit{border:none;background:none;color:var(--muted);font-size:var(--t-tiny);
  cursor:pointer;padding:2px 6px;border-radius:var(--r-sm);}
.novel-edit:hover{color:var(--accent);}
.novel-stale{border:var(--bd) solid var(--danger);background:none;color:var(--danger);
  font-size:var(--t-tiny);cursor:pointer;padding:2px 8px;border-radius:var(--r-round);}
.novel-stale:hover{background:var(--danger);color:var(--onAccent);}
.novel-editor{display:flex;flex-direction:column;gap:8px;margin:6px 0 10px;
  padding:10px;border:var(--bd) solid var(--edge);border-radius:var(--r-md);background:var(--panel);}
.novel-editor-f{display:flex;flex-direction:column;gap:4px;}
.novel-editor-l{color:var(--muted);font-size:var(--t-tiny);}
.novel-editor-num{max-width:120px;}
.novel-editor-row{display:flex;align-items:center;gap:10px;}
.novel-editor-hint{color:var(--muted);font-size:var(--t-tiny);}

/* The chapter's Download press (the single-file seal): quiet beside Play,
   the same dress as the cue's Edit press. */
.novel-dl{border:none;background:none;color:var(--muted);font-size:var(--t-tiny);
  cursor:pointer;padding:2px 6px;border-radius:var(--r-sm);}
.novel-dl:hover{color:var(--accent);}

/* the chapter operations: numbers, counts, the quiet op cluster, the archive foot */
.fw-set-no { font-size: var(--t-label); color: var(--muted); min-width: 1.4em; text-align: right; font-variant-numeric: tabular-nums; flex-shrink: 0; }
.fw-set-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.fw-set-w { font-size: var(--t-label); color: var(--muted); }
.fw-set-total { padding: 0 14px 8px; font-size: var(--t-tiny); color: var(--muted); }
/* THE AUDIO STATUS, ON THE LEFT NOW (Mark's ruling, 2026-08-23: "the data
   in the chapters on audio status on the right belongs on the left"). Same
   place the word count sits, same letter-spacing the rail's own pill wore
   (audiobook.css's .novel-rail-s, before this lane retired the rail) — the
   colour comes free from .novel-state-* below, unscoped on purpose so the
   rail and this row always agreed and still do without a second rule. */
.fw-set-s { font-size: var(--t-label); letter-spacing: var(--ls-label); white-space: nowrap; flex-shrink: 0; }
.fw-set-play {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: var(--r-sm); color: var(--accent); flex-shrink: 0;
}
.fw-set-play:hover { background: var(--sel); }
/* THE LISTEN FACE'S ROW WEARS THE RAIL'S OWN TWO-LINE SHAPE (Mark, caught
   on this lane's own first screenshot: a title racing the status word for
   one line loses at panel width — "The Reconciliators" or "Hadara Claims"
   truncate to nothing readable). Title stands alone on the first line,
   full width, still numbered; the count and the status word ride the
   second, small, with play pinned to the row's right edge exactly where
   the rail's own play sat (.novel-rail-play's own position, ported). The
   write face's rows never wear this — they have never carried anything to
   fight the title for room. */
.fw-set-row-2l { flex-direction: column; align-items: stretch; gap: 3px; padding: 9px 40px 9px 14px; }
.fw-set-line1, .fw-set-sub { display: flex; align-items: baseline; gap: 8px; }
.fw-set-row-2l .fw-set-play { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); }

/* THE OUTLINE'S FIVE RULES STOOD HERE and went with it, 2026-08-24: Mark
   called the outline "some halucinated crap" and its seat is the audio
   door's now. Style outlives markup more quietly than markup outlives style,
   so they leave in the same commit. */
/* THE EXPLICIT BADGE, beside the title of a chapter cut at four or five
   (Mark, 2026-08-24: "plainly, the way music does it"). Music's own mark
   is a small bordered square with one letter in it, quiet enough to sit
   beside a title without shouting over it, and this is that in this
   list's own muted colour rather than a red of its own.

   IT DOES NOT FADE ON THE ROW'S HOVER the way the word count and the
   audio status do, one rule below. Those are data the ops cluster is
   allowed to cover while a hand is reaching for a control; what a
   document contains is not, and a warning that disappears under the
   cursor is a warning that is not being made. It sits left of the count,
   so the ops overlay never lands on it either. */
.fw-set-e {
  flex-shrink: 0; font-size: var(--t-label); line-height: 1;
  padding: 2px 3px; border: 1px solid var(--muted); border-radius: 3px;
  color: var(--muted); font-weight: 600;
}
/* THE QUIET FACE: at rest a row is a title, its count and (on the Listen
   face) its audio status; the ops rise on the hover (or keyboard focus),
   overlaying all three on the row's own hover colour, so a narrow panel
   never starves the titles for controls nobody is reaching for. */
.fw-set-ops {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  display: inline-flex; gap: 2px; padding: 0 2px; border-radius: var(--r-sm);
  background: var(--inset); opacity: 0; pointer-events: none;
}
.fw-set-row:hover .fw-set-ops, .fw-set-row:focus-within .fw-set-ops { opacity: 1; pointer-events: auto; }
.fw-set-row:hover .fw-set-w, .fw-set-row:hover .fw-set-s, .fw-set-row:hover .fw-set-play { opacity: 0; pointer-events: none; }
.fw-op {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: var(--r-sm); color: var(--muted); cursor: pointer;
}
.fw-op:hover { color: var(--text); background: var(--sel); }
.fw-op-ghost { display: none; }
.fw-set-renaming { cursor: default; }
.fw-set-renaming .fw-name { max-width: none; width: 100%; }
/* + NEW CHAPTER, the foot of the list (the lane brief, 2026-08-23) — the
   Cellar's own "+ New character" dress (cellar.css .cast-row-new,
   .cast-face-plus), a dashed quiet seat rather than a bare input sitting
   open. STANDALONE classes, on purpose: this row is not a chapter, and
   .fw-set-row/.fw-set-t are what every count and every title-read in this
   list walks — sharing them would count the affordance as a document. Only
   the geometry is borrowed, not the class. */
.fw-set-new, .fw-set-new-open {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  background: none; border: 0; border-bottom: var(--bd) solid var(--edge);
  padding: 9px 10px 9px 14px; color: var(--muted);
}
.fw-set-new { border-style: dashed; cursor: pointer; }
.fw-set-new:hover { border-color: var(--accent-line, var(--accent)); color: var(--text); }
.fw-set-new-plus {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.4em; font-size: var(--t-sub); font-weight: var(--w-med);
}
.fw-set-new-label { font-size: var(--t-sub); }
.fw-set-new-open { cursor: default; }
.fw-set-new-open .fw-name { max-width: none; width: 100%; }

/* ADD A FILE, the Docs tab's own foot row (Mark, 2026-08-25: "i want an add
   file modal or button or whatever makes sense to me"). It borrows
   .fw-set-new's whole dress, because it IS the same affordance in the same
   seat doing the same job one tab over, and a second look for it would be a
   second decision to keep in step.

   THE ONE RULE IT ADDS is a positioning context. This row is a <label>
   rather than a <button> (only a real file input opens a picker), and the
   input it wraps is .fw-import-file, which hides by being absolutely
   positioned at one transparent pixel. Without a positioned ancestor that
   pixel escapes to the nearest one and the hit area stops matching the row.
   .fw-import-pick carries the identical line for the identical reason. */
.fw-set-new-file { position: relative; }

/* The landing sentence, in the row's own seat so the list does not jump as
   a file lands. .fw-import-line's type, .fw-set-new's padding: it stands
   exactly where the row it replaces stood. */
.fw-set-new-line {
  padding: 9px 10px 9px 14px; font-size: var(--t-tiny);
  color: var(--muted); line-height: var(--lh-read);
}

.fw-arch-h {
  padding: 14px 14px 6px; font-size: var(--t-label); letter-spacing: var(--ls-label);
  color: var(--muted); text-transform: uppercase;
}
.fw-arch-row { cursor: default; color: var(--muted); }

/* ---------- history on the bench (revision safety, plan 7.2) ----------
   One row per kept version, newest first; the restore press is quiet and
   the ask() behind it carries the real promise. */
.fw-hist-row {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  border-bottom: var(--bd) solid var(--edge); padding: 6px 0;
}
.fw-hist-n { font-size: var(--t-sub); color: var(--text); }
.fw-hist-auto {
  margin-left: 6px; font-size: var(--t-label); letter-spacing: var(--ls-label);
  color: var(--muted); border: var(--bd) solid var(--edge); border-radius: var(--r-pill); padding: 0 6px;
}
.fw-hist-m { font-size: var(--t-tiny); color: var(--muted); }
.fw-hist-go {
  margin-left: auto; background: none; border: 0; padding: 2px 0; cursor: pointer;
  font-size: var(--t-tiny); color: var(--accent);
}
.fw-hist-go:hover { text-decoration: underline; }

/* ---------- the Cast tab (rooms/forge-cast.js) ----------
   Every row in this panel is cellar.css's own .cast-* — unscoped there,
   reused verbatim here, which is the pixel-perfect port itself rather than
   a rule that approximates it. The one thing genuinely new is the
   narrator's pinned seat: a hairline under her row is all that marks her
   off from the toggle and the manifest's own people below, the Cellar's
   own restraint (a section is a label and a rule, never a box). */
.fc-narrator { padding-bottom: 9px; border-bottom: var(--bd) solid var(--edge); }

/* NOVEL'S HEADER HAS TWO CLEAR LINES. Three labelled destinations use the
   full segmented track; the two fixed face seats sit beneath it. Trying to
   put five controls across the 200px panel made the words read as
   "AssistantTool BoxCast" even when the boxes technically did not overflow.
   This wrapper belongs only to Novel Forge, so Reader and every other room's
   shared house tabs keep their established geometry. */
.fc-right-head{display:grid;gap:3px;margin:var(--s3) 6px 6px}
.fc-right-head .house-tabs{margin:0}
.fc-tabs-trio{gap:0}
.fc-tabs-trio .house-tab{min-width:0;white-space:nowrap;padding-left:0;padding-right:0;
  font-size:var(--t-label);flex:1 1 0}
.fc-face-seats{display:flex;justify-content:flex-end;gap:2px;padding-right:3px}

/* ---------- THE CHARACTER STUDY (rooms/forge-person.js, Lane S, 2026-08-23)
   ----------
   plans/NOVEL-FORGE-UX.md: "the modal needs to fill the center canvas...
   it's also a major feature." Portrait leading, the panes composed as one
   room — a study, not a form. Tokens only, the theme law this file states
   for itself at the top. Everything under .fp-body is modals/character.js's
   own .settings-* markup, unscoped and untouched: this file styles only the
   composition around it, never the pages themselves.

   NO FIXED HEIGHT ANYWHERE BELOW — that IS how "create opens minimal and
   grows in place" is kept: a one-field draft and a six-tab person are two
   different amounts of content in the same flowing block, never two sizes
   of the same box. */
.fp-study { display: flex; flex-direction: column; min-height: 0; height: 100%; overflow: auto; padding: 24px; gap: 18px; }
.fp-hero { display: flex; align-items: center; gap: 16px; }
.fp-portrait {
  width: 96px; height: 96px; flex: none; overflow: hidden;
  border-radius: var(--r-lg); background: var(--inset); border: var(--bd) solid var(--edge);
}
.fp-who { min-width: 0; flex: 1; }
.fp-kicker { font-size: var(--t-label); letter-spacing: var(--ls-label); color: var(--muted); text-transform: uppercase; }
.fp-name { font-size: var(--t-room); font-weight: var(--w-semi); margin-top: 2px; }
.fp-close { flex: none; width: 32px; height: 32px; border-radius: var(--r-sm); color: var(--muted); font-size: var(--t-sub); }
.fp-close:hover { color: var(--text); background: var(--sel); }
/* THE TIER, upper right (Mark, 2026-08-23: "MOVE MAJOR MINOR CHARACTER TO
   UPPER RIGHT"). Major/minor is a book concept and lives only in the study's
   own hero — .char-pill is the shared pill (council.css) and needs no wrapper
   of its own to size correctly, so this is only the row that holds it. */
.fp-tier { display: flex; flex: none; gap: 6px; }

/* the tab row — a quiet pill rack, the house's own toggle manner
   (novel-tier/fw-set-new share the same idiom: rest is quiet, chosen is
   accent-on-tint, never a border alone) */
.fp-tabs { display: flex; flex-wrap: wrap; gap: 6px; border-bottom: var(--bd) solid var(--edge); padding-bottom: 14px; }
.fp-tab { padding: 7px 13px; border-radius: var(--r-pill); color: var(--muted); font-size: var(--t-small); }
.fp-tab:hover { color: var(--text); background: var(--inset); }
.fp-tab.on { color: var(--accent); background: var(--sel); }

.fp-body { min-width: 0; }

/* ---------- IN THE BOOK ---------- */
.fp-inbook-list { display: flex; flex-direction: column; gap: 8px; }
.fp-inbook-row {
  display: flex; flex-direction: column; gap: 3px; width: 100%; text-align: left; padding: 10px 12px;
  border: var(--bd) solid var(--edge); border-radius: var(--r-md); background: var(--panel);
}
.fp-inbook-row:hover { border-color: var(--accent-line, var(--accent)); background: var(--inset); }
.fp-inbook-ch { font-size: var(--t-small); font-weight: var(--w-semi); }
.fp-inbook-said { font-size: var(--t-tiny); color: var(--muted); line-height: var(--lh-read); }
