/* The web fonts are served from this repo - /fonts/fonts.css, linked from index.html
   BEFORE this file. Until 2026-09-20 line 1 here imported them from Google (items 0HW, 0JC). */

:root {
  --ink: #1a202c;
  --ink-soft: #4a5568;
  /* The grey of every label and hint (style guide D1, decided 2026-10-01): was #94a3b8, 2.6:1 on white - now 4.8:1,
     still quieter than body text (--ink-soft, 7.5:1). */
  --ink-faint: #64748b;
  --paper: #ffffff;
  --wash: #f6f7fb;
  --line: #e2e8f0;
  --accent: #2b6cb0;
  --accent-dark: #1a365d;
  --accent-wash: #ebf8ff;
  --danger: #e53e3e;
  /* Red as LETTERING (F1, the reviewer 2026-10-08), as --pending-ink is amber's: --danger is 4.1:1 on white. */
  --danger-ink: #c53030;
  /* The three pane headers. LIGHTENED 2026-09-01 (reviewer: "try lighter color
     since text pane has no matching header" - the middle pane has one now, so
     the dark bar that read as an accent on two panes became a heavy band across
     the whole window). Tokens rather than literals: one value changes all three
     bars, which is the point of them being one bar. */
  --header-bg: #e4ecf6;
  --header-fg: #1a365d;
  /* The lettering on the bars (style guide D4, 2026-10-01): was #5a7ba6, 3.7:1 on --header-bg - now 5.0:1. */
  --header-muted: #46658f;
  --header-line: #c2d4e8;
  --header-hover: rgba(26, 54, 93, 0.10);
  /* The pane headers' height, as a token since 2026-09-02: the scan pane's
     overlay controls now anchor to the PANE (they used to anchor to the
     scrolling viewer and slid away with the page), so they have to subtract the
     bar to stay centred on the scan rather than on the pane. */
  --pane-header-h: 46px;
  --pending: #d69e2e;
  /* Amber as a MARK or as TEXT (style guide D2, decided 2026-10-01): --pending as a word's underline or a fill reads,
     as lettering it is 2.4:1 on white. This is 5.5:1; the underlines and fills keep --pending. */
  --pending-ink: #975a16;
  /* A decided word's green as TEXT - a pending replacement's new word (E2, the reviewer 2026-10-01): the green of the
     underlines and fills is 2.9:1 on the selected entry's yellow; this is 6.0:1. */
  --decided-ink: #276749;
  /* THE FOUR WORD STATES (style guide B1, 2026-10-01): one colour each wherever a state is drawn - the text's
     underlines, the scan's boxes and rings, the legend's swatches, the index's counts, a panel's state mark. The
     script names these tokens (STATE_META in app.js) and writes no colour of its own. */
  --state-open: var(--danger);      /* needs a ruling */
  --state-machine: var(--pending);  /* resolved by the machine */
  --state-human: #38a169;           /* decided by a person */
  --state-ai: #805ad5;              /* flagged by a detector */
  /* The ring the scan draws round a word reached by a link that has no state of its own (and the ring's colour when a
     box names none). */
  --ring-linked: #3182ce;
  /* THE TWO KINDS OF NOTICE (style guide D7, decided 2026-10-01): "for your information" - one yellow - and "needs
     you" - one red. There were three yellows, a brown bar and a red box. */
  --notice-bg: #fffbeb;
  --notice-line: #ecc94b;
  --alert-bg: #fff5f5;
  /* A DEMO COPY's line across the window (Board #38, 2026-10-14): neither kind above - it says which copy this is, and
     must be told from the real one at a glance. Slate, the page's own ink family, so no new colour is added. */
  --demo-bg: #334155;
  --demo-ink: #f1f5f9;
  --demo-h: 22px;
  /* The nav pane's width, shared so the side panels can dock BESIDE it rather
     than on top of it. Two hardcoded 380s (nav pane, legend) drifting apart is
     how the panel came to cover the klal list completely. */
  /* CONTINUOUS, not stepped. Reviewer, 2026-09-04: "still jittery as it
     shrinks." It was stepped (380 -> 300 at a breakpoint), and because the scan
     pane takes THE REMAINDER, every step in this variable became a jump in the
     scan: measured sweeping 1406 -> 1400px, the scan went 435 -> 512, so
     dragging the window smaller made the ink pane suddenly bigger, then smaller
     again, then bigger at the next breakpoint. A sawtooth.
     clamp() gives the same narrowing without a single discontinuity, so the
     scan changes smoothly all the way down to the one intended step - the point
     where the index leaves entirely. */
  --nav-w: clamp(240px, 24vw, 380px);
  /* The list pane's width (W1 (a), 2026-10-04), and the width of the ruling panels that open over it. */
  --list-w: clamp(300px, 23vw, 420px);  /* 420 at 1864 wide; 300 at 1229, where the index, list, text and scan still fit */
  /* ---- Structural typography, 2026-08-31 (reviewer) --------------------------
     These name the ROLE a piece of text plays in a sefer's structure, not this
     book's particular layout, so another work with a different shape restyles
     itself by re-pointing these four values and touches no rules:
       --font-title   the running head / klal title, wherever it is shown.
                      Deliberately NOT the body face: the body is set in Frank
                      Ruhl Libre, so a title in the same face reads as more body
                      text. David Libre is a different Hebrew serif - same
                      period feel, visibly distinct letterforms.
       --font-marker  the section number, in either script
     The point of the variables is that the SAME role gets the SAME treatment in
     every pane - the reviewer asked for the title to look identical in the index
     and in the text, and before this each pane styled its own text ad hoc. Any
     new surface that shows a title should use `.klal-title`, never a font stack.
     A work whose headings are set in Rashi script, say, changes --font-title
     here and both panes follow. */
  --font-title: 'David Libre', 'David', 'Times New Roman', serif;
  /* FIXED 2026-09-01 (reviewer: "is the heb num in the index pane the same font
     as the text nums? it should be" - it was not). Inter carries no Hebrew, so
     this token silently resolved every Hebrew marker to whatever the system
     picked, while the index pane's `.nheb` had no font-family at all and
     inherited the body's Frank Ruhl Libre. The same `יב` was a system sans in
     the text pane and a serif in the index. Naming a Hebrew face makes the
     fallback a CHOICE: font matching is per-glyph, so Latin digits still take
     Inter and Hebrew letters take David Libre - the same face --font-title
     already uses, which is the book's own type. */
  --font-marker: 'Inter', 'David Libre', 'David', sans-serif;
  --title-size: 15px;      /* the heading in the index row */
  --marker-size: 20px;     /* the section number in the text-pane head */
  --nav-marker-size: 18px; /* the HEBREW marker in the index row */
  --nav-id-drop: 0.115em;  /* the index row's number down to its Hebrew numeral's baseline (1.5px at 13px) */
  /* The Latin klal id in the index row, its own token since 2026-09-01
     (reviewer: "english numbers are too large wasting space"). It was sharing
     --nav-marker-size at 18px with a 34px min-width, in a 380px column of 222
     rows - the widest fixed thing in the row after the badges, for the half of
     the reference the BOOK does not print. The Hebrew marker keeps the larger
     size: that is the one a reviewer matches against the scan. */
  --nav-id-size: 13px;
  --title-inline-size: 18px;  /* the heading where it sits IN the running text */
  /* The marker INSIDE the running text is its own token, larger than the heading
     beside it: it is the reader's place-keeper down a long scrolling column and
     is what the eye looks for when matching against the scan. Raised twice at the
     reviewer's request (2026-08-31). */
  --marker-inline-size: 24px;
  /* ONE TYPE SCALE for the panels, lists, notices and buttons (style guide D5, decided 2026-10-01; there were 24
     sizes). The text pane, the index and the header bars keep the sizes the reviewer set (the role tokens above).
     Filter chips take the note size, not the button size: at 13px the chip rows wrapped. */
  --fs-label: 11px;   /* a small-capitals label, a mark */
  --fs-note: 12px;    /* a hint, a note, a notice, a chip */
  --fs-ui: 13px;      /* panel text, list rows, buttons, fields */
  --fs-title: 15px;   /* a panel's title, a group's heading word */
  --fs-word: 17px;    /* a Hebrew word or line shown in a panel */
  --fs-close: 22px;   /* the close mark */
  /* THE ROLE SIZES, NAMED (the font-size pass, 2026-10-08; no visible change). Sizes the reviewer set, or that belong to
     the text itself, kept at the value each had (D5: the text, the index and the header bars keep their sizes); a size
     already on the scale above takes the scale's token instead. A `font-size: 0` hides a node's own text and is no size. */
  --fs-base: 15px;            /* the page's own size, inherited by anything given none */
  --text-size: 17px;          /* the running text */
  --entry-head-size: 13.5px;  /* an entry's heading row in the text */
  --superscript-em: .62em;    /* a note's number, raised in the text or a citation */
  --mark-em: .65em;           /* a mark set beside a word, relative to it */
  --punct-size: 18px;         /* a proposed stop mark */
  --header-size: 12.5px;      /* the three header bars */
  --header-he-size: 16px;     /* a Hebrew slot in a header bar (2026-09-15) */
  --header-en-size: 13.5px;   /* an English slot in a header bar (2026-09-15) */
  --brand-he-size: 13px;      /* the wordmark's Hebrew, on the index bar's second line (Board #23, 2026-10-12) */
  --brand-en-size: 10px;      /* the wordmark's Latin capitals beside it */
  --brand-line-1: 19px;       /* the index bar's two lines: the section's name... */
  --brand-line-2: 15px;       /* ...and the wordmark under it - 35px of the bar's 46 */
  --nav-size: 13px;           /* an index row */
  --count-size: 10px;         /* the numbers in the index's count pills */
  --control-small: 12px;      /* the index's part selector and name filter, the text bar's which-text box */
  --note-size: 16px;          /* a note's text in the note card */
  --list-copy-size: 18px;     /* a list row's copy icon, in the number's place ("bigger", the reviewer 2026-10-10) */
  --ring-size: 34px;          /* the progress ring in the list bar (Board #8, 2026-10-11), inside the bar's 46px */
  --ring-count-size: 10px;    /* the number left, in the ring's centre: four digits fit inside it */
  --gear-size: 22px;          /* the index bar's Settings gear; the bar keeps its room beside the name (Board #24) */
  /* Shadows (style guide B3): one token per kind as each is reached. */
  --shadow-card: 0 4px 12px rgba(0,0,0,0.08);
  /* Lettering on the dark tooltip and the translucent hover card (2026-10-01): the card stays translucent as ruled
     (2026-08-26); its lighter lines were 2.7:1 on it and are made lighter instead - 5.4:1 and 5.0:1. */
  --on-dark-soft: #e2e8f0;
  --on-dark-link: #bee3f8;
  /* the hairline between the hover card's strip and its detail */
  --on-dark-rule: rgba(255, 255, 255, 0.16);
  /* LAYERS (style guide B3; one pass 2026-10-06 - there were twelve numbers from 1 to 1000, none named). Two scales.
     THE PAGE'S LAYERS, bottom to top - everything that floats over the four panes; the numbers are the ones each had: */
  --z-backdrop: 900;    /* the click-catcher behind an open panel */
  --z-pane: 910;        /* the four panes, above the backdrop so a click on another word reaches it (2026-08-21) */
  --z-panel: 950;       /* the ruling panels */
  --z-tooltip: 998;     /* the tooltip */
  --z-hover-card: 999;  /* the hover card on a word */
  --z-note-card: 1000;  /* a note's card */
  /* INSIDE ONE PANE OR PANEL: each is a stack of its own, so these order only what shares it. */
  --z-lift: 1;          /* above its neighbours: a list's sticky heading, a panel's pinned Save row, the focused box on the scan */
  --z-control: 2;       /* a pane's floating controls: the scan's zoom and page buttons, above a focused box */
  --z-popover: 3;       /* above those: a popover (the settings tray, Apply's panel) and the toast */
  /* CORNERS (style guide B3; one pass 2026-10-06 - there were ten values, 2 to 20px and 999): four steps, by what the
     thing is. A mark on a word, a box on the scan and the scan page itself keep a hairline's rounding, so a word's
     highlight hugs its letters; a box, a field, a button or a row is --radius-sm; a card or anything floating is
     --radius; a pill or a chip is round at its ends whatever its height. */
  --radius-mark: 2px;
  --radius-sm: 5px;
  --radius: 8px;
  --radius-pill: 999px;
  --sp-hair: 1px;   /* a word's own padding and a mark's offset in the running text - the text's typesetting */
  --sp-half: 2px;   /* inside a control: the top and bottom of a pill, chip, button or field */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  /* THE REST OF THE PAGE'S COLOURS (the colour pass, style guide B1, 2026-10-08): every colour the stylesheet still wrote
     as a literal, named by what it does and kept at the value it had - no visible change. */
  --ink-text: #2d3748;              /* the running text's ink */
  --on-fill: #ffffff;               /* lettering on a filled colour: a pill, a primary button, a panel's title bar */
  --on-dark: #f7fafc;               /* lettering on the dark tooltip and toast */
  --scan-wash: #eef1f6;             /* behind the scan page */
  --control-glass: rgba(255,255,255,0.92);  /* the scan's floating zoom and page buttons */
  --selected-row: #bee3f8;          /* the index's chosen row */
  --word-hover: rgba(43,108,176,0.08);      /* a word under the pointer */
  --word-mark-wash: #fff3cd;        /* the word marked in a panel's context */
  --info-wash: rgba(49, 130, 206, 0.12);    /* the editor's "info" formatting */
  --marked-applied: var(--accent);  /* an applied correction in the marked view */
  /* a place, not a state (B1): the entry being read, a word reached by a link */
  --place: #d69e2e;
  --place-wash: rgba(214, 158, 46, 0.14);
  --routed-wash: rgba(214, 158, 46, 0.18);
  --routed-pulse: rgba(214, 158, 46, 0.25);
  --pending-wash: #fffaf0;          /* a flagged entry's button, a heading change waiting */
  /* the stop marks: proposed and decided */
  --punct-pending: #3182ce;
  --punct-pending-wash: rgba(49,130,206,0.14);
  --punct-decided: #718096;
  /* success - the "Saved" mark and a copied reference; not a word's state (B1) */
  --success: #38a169;
  /* the lists: chips, rows and group rules */
  --chip-line: rgba(45,55,72,0.22);
  --row-hover: rgba(45,55,72,0.07);
  --row-hover-line: rgba(45,55,72,0.12);
  --group-line: rgba(45,55,72,0.15);
  --group-line-strong: rgba(45,55,72,0.35);
  --applied-ink: #2f855a;           /* a recorded ruling's "applied" */
  --confirmed-ink: #4a7fb5;         /* "confirmed" and "unreadable" */
  --alert-row-wash: rgba(229,62,62,0.05);   /* a recorded ruling that needs a person */
  --danger-wash: rgba(229,62,62,0.08);      /* an armed Delete */
  --warn-ink: #9c4221;              /* a warning line in the export and Apply panels */
  --notice-ink: #744210;            /* the test-mode line in Apply's panel */
  --toast-bg: rgba(26,32,44,0.95);
  --toast-fail-bg: rgba(155,44,44,0.96);
  --backdrop: rgba(15,23,42,0.35);  /* behind an open panel */
  /* the hover card, translucent as ruled (2026-08-26) */
  --card-glass: rgba(26, 32, 44, 0.72);
  --on-glass: rgba(247, 250, 252, 0.82);
  --on-dark-line: rgba(255,255,255,0.22);
  --on-dark-hover: rgba(255,255,255,0.10);
  --on-dark-hover-strong: rgba(255,255,255,0.16);
  /* shadows, one per kind (B3) */
  --shadow-control: 0 2px 8px rgba(0,0,0,0.14);
  --shadow-page: 0 6px 24px rgba(15,23,42,0.15);
  --shadow-float: 0 4px 14px rgba(0,0,0,0.18);   /* the note card, the hover card */
  --shadow-tooltip: 0 8px 24px rgba(0,0,0,0.35);
  --shadow-toast: 0 4px 14px rgba(0,0,0,0.28);
  --shadow-panel: -8px 0 32px rgba(0,0,0,0.25);
}

* { box-sizing: border-box; }
/* HIDDEN MEANS HIDDEN, everywhere (audit B2, 2026-09-30). Any rule that gives an element a `display` outranks the
   browser's own rule for the `hidden` attribute, so the element stays on screen while the page says it is hidden.
   It happened three times, each patched for its one element (#export-pending-row, #server-notice - "an empty yellow
   bar across the top of the text pane" - and #test-mode-notice), and a fourth time unpatched: "Show the editor's
   formatting" (`#settings-popover label { display: flex }`) showed on every book, where it does nothing. One rule for
   the page instead of one per element; measured before it, that switch was the only element it changes. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0;
  height: 100%;
}

body {
  font-family: 'Frank Ruhl Libre', serif;
  background: var(--wash);
  color: var(--ink);
  display: flex;
  height: 100vh;
  overflow: hidden;
  font-size: var(--fs-base);
}

button, input, textarea { font-family: 'Inter', sans-serif; }

/* ---------- LEFT: scan ---------- */
#scan-pane {
  /* THE SCAN TAKES WHAT IS LEFT. Reviewer, 2026-09-04: "i don't see the scan
     winning... the middle pane doesn't shrink after that. the scan does."
     Exactly right, and it was backwards: this pane had `width: 34%`, a
     PERCENTAGE OF THE WINDOW, so it shrank on every pixel the window lost -
     while #text-pane was `flex: 1`, which takes the remainder and therefore
     ABSORBED what the scan gave up. The narrower the window, the more the text
     won. Inverted here: the text now carries the percentage basis and this pane
     grows into everything else, so tightening the window takes width from the
     text and the ink keeps its size. That also settles the popup case - "when I
     have a popup disputed word, the only import parts are the scan and the
     popup" - because .side-panel overlays the TEXT pane, so a panel now opens
     over the pane that shrank rather than beside a scan that did. */
  flex: 1 1 0;
  /* A FORWARD GUARD, and INERT TODAY - said plainly because the obvious reading
     of this line is that it fixed something. Measured 2026-09-04 across 1600 →
     800px with and without it: identical geometry at every width. #text-pane is
     `flex: 1; min-width: 0`, so it absorbs the entire remainder and no deficit
     ever reaches this pane to shrink it. What actually holds the scan's floor
     is `min-width` below, and what enforces the reviewer's collapse order is
     the breakpoints at the end of this file.
     Kept anyway, at one line: it becomes load-bearing the moment anyone gives
     #text-pane a min-width of its own, and that is precisely the change that
     would start squeezing the ink without anyone noticing. */
  /* The scan's floor - it never goes below this and never disappears. */
  min-width: 400px;
  background: var(--scan-wash);
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--line);
  position: relative;
  z-index: var(--z-pane);
}
/* ONE header bar, worn by both the scan pane and the index pane. EXTRACTED
   2026-09-01 (reviewer: the index pane's header "should be very similar look to
   scan pane"). Two panes styling their own bar to look alike is the shape that
   drifts; this is the same rule twice. */
.pane-header {
  padding: 0 var(--sp-4);
  background: var(--header-bg);
  color: var(--header-fg);
  border-bottom: 1px solid var(--header-line);
  font-family: 'Inter', sans-serif;
  font-size: var(--header-size);
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: center;      /* the reference sits in the MIDDLE of its pane */
  gap: var(--sp-3);
  direction: ltr;
  position: relative;           /* so the settings gear can pin to the edge */
  /* A FIXED height, not a min-height. All three bars sit on one line across the
     top of the window, and whichever one happened to hold the tallest control
     was setting its own height - the index pane stood 2px proud of the scan pane
     because of a 26px gear button. Nothing inside may exceed this. */
  height: var(--pane-header-h);
  flex-shrink: 0;
  overflow: hidden;
}
/* THE FOUR SLOTS, in the order the reviewer specified for the scan pane and
   which all three panes now follow:
       [Hebrew title]  [Hebrew reference]  [English reference]  [English title]
   The titles bookend; the two references sit together in the middle, which is
   what puts real whitespace between the title and the reference (reviewer: "need
   whitespace btw title and klal") without any pane needing its own rule. */
.ph-mid {
  display: flex; align-items: baseline; min-width: 0;
  /* A thin rule between slots instead of raw whitespace - it reads as one line
     with parts, rather than four things that happen to be near each other.
     Widened 12 -> 16px 2026-09-15 (reviewer: "more white space between words -
     there is space to grow a bit"). */
  gap: var(--sp-4);
}
/* PHYSICAL border-left, not an ::before with a logical margin. The Hebrew slots
   are `direction: rtl`, so a pseudo-element inside one renders at ITS start edge
   - the right - which put the rule on the wrong side of the Hebrew items and
   stacked two of them together next to the Latin ones. The flex ROW is laid out
   ltr regardless of what each item's own text direction is, so the left edge is
   unambiguous here and a physical property is the correct tool. */
.ph-mid > * + * {
  border-left: 1px solid var(--header-line);
  padding-left: var(--sp-4);
}
/* word-spacing: the reviewer asked for more air between the words INSIDE a
   slot as well as between slots (2026-09-15). */
.ph-title, .ph-ref { white-space: nowrap; word-spacing: 0.2em; }
.ph-he {
  direction: rtl; unicode-bidi: isolate;
  font-family: 'Frank Ruhl Libre', 'David', serif;
}
/* The title is a PEER of the reference beside it, not a heading over it
   (reviewer 2026-09-02: "make them the same size and boldness - the hebrew is
   darker and bigger than the other hebrew in the header"). It was 16px/700 in
   full-strength ink against 13.5px/500 muted, so it read as a title with
   metadata trailing it rather than as one line. One size per SCRIPT, because
   Hebrew and Latin do not have the same optical size at the same px. */
.ph-title.ph-he, .ph-ref.ph-he {
  /* 13.5 -> 16px 2026-09-15 (reviewer: "font can be a bit bigger"). Still the
     same size for every Hebrew slot, which is the rule that matters. */
  font-size: var(--header-he-size);
  font-weight: 500;
  color: var(--header-muted);
  flex-shrink: 0;
  line-height: 1.2;
}
/* The English reference yields FIRST when a pane is too narrow: it is the slot
   whose Hebrew twin sits immediately to its left, so an ellipsis here costs the
   least. The index pane clears its content by only ~5px at 380px, and a work
   with a longer section name than "Klalei HaGemara" would otherwise break the
   bar rather than shorten a word. */
.ph-ref.ph-en, .ph-title.ph-en {
  font-size: var(--header-en-size);            /* 11.5 -> 13.5px with the Hebrew, 2026-09-15 */
  font-weight: 500;
  color: var(--header-muted);
  font-variant-numeric: tabular-nums;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Peer of the English reference, for the same reason as the Hebrew pair above.
   The uppercase + letter-spacing treatment went with it: small caps read as a
   LABEL, which is the opposite of the "one line of peers" this bar is now.

   AND IT GIVES WAY BEFORE THE REFERENCE (reviewer 2026-09-15: "yes eng title
   give way"). Where the title shares a bar with the reference - the text pane's
   - the reference yielding first meant `Shoresh #1` shrank to NOTHING at a
   1280px window on HaShorashim, an empty slot between two rules, while the
   static book name beside it stayed whole. The title is the slot a reviewer
   needs least: the Hebrew title already names the book.

   BY TURN, NOT BY WEIGHT. The first cut gave the title `flex-shrink: 1000`
   against the reference's 1, so the title would take all but a thousandth of
   the squeeze. It did, and a thousandth was enough: at 1280px the reference
   lost about 0.08px, `text-overflow: ellipsis` fires on ANY overflow, and the
   screen read `Shoresh #...` while clientWidth and scrollWidth both rounded
   to 102. So the reference does not shrink at all while a title shares its
   bar, and the title alone gives way. Once the title has nothing left, the
   reference overflows instead, into the bar's 16px padding first and then
   clipped at its edge, without an ellipsis. The index and scan bars have no
   title, and their reference still yields as it did. */
/* SUPERSEDED THE SAME DAY (reviewer 2026-09-15: "remove the shoresh from the
   middle pane header - just the book title"). The text bar no longer carries a
   reference, so nothing is left for the title to give way to, and the rule
   that held the reference at full width is gone with it. The title still
   yields, with an ellipsis, if its bar is short. The paragraphs above are the
   history of why it yields at all. */
.ph-title.ph-en { flex-shrink: 1; }
/* An empty slot must take no room, or the gaps double up before /api/corpus
   lands and on the panes whose reference is not set yet. */
.ph-title:empty, .ph-ref:empty { display: none; }
/* The Hebrew half of the scan reference (reviewer, 2026-08-31: "white space
   followed by the same info in Hebrew"). `direction: rtl` with `unicode-bidi:
   isolate` so the Hebrew orders itself correctly without reordering the
   surrounding LTR header, and a real gap rather than a padding space, which the
   flex row would otherwise collapse. */
#klal-indicator {
  /* margin-LEFT, explicitly. This was `margin-inline-start`, which resolves
     against the ELEMENT's own direction - and this span is `direction: rtl`, so
     it became margin-right: 28px and put the gap on the far side, outside the
     row. The visible separation was then just the single literal space in
     index.html, which is exactly what the reviewer saw. Measured after the fix:
     28px between the two halves. */
  margin-left: 1.75rem;
  direction: rtl;
  unicode-bidi: isolate;
  /* NO font-size here. This id rule carried its own 13.5px, a second copy of
     `.ph-ref.ph-he`'s size that outranks it, so raising the shared size on
     2026-09-15 left the scan pane's Hebrew behind. The slot rule is the one
     place the size lives. */
  /* F5 (2026-10-08): no longer faded to .92 - the bar's decided lettering, 5.0:1 (it was 4.3:1) */
}
/* MOVED OUT OF THE HEADER 2026-09-01. The scan bar could not fit its four text
   slots and a control cluster - it overflowed by 58px at a 1280px window, hidden
   by `overflow:hidden` - and the reviewer's ask was a uniform bar across three
   panes, which a bar with widgets in one of them is not. These now float over
   the scan itself, beside the page arrows that were already there. */
#zoom-controls {
  position: absolute;
  bottom: 12px; left: 12px;
  z-index: var(--z-control);
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-1);
  border-radius: var(--radius-pill);
  background: var(--control-glass);
  border: 1px solid var(--header-line);
  box-shadow: var(--shadow-control);
  direction: ltr;
}
#zoom-controls button {
  width: 22px; height: 22px;
  border: 1px solid var(--header-line); border-radius: var(--radius-sm);
  background: transparent;
  color: var(--header-fg);
  font-size: var(--fs-ui);
  line-height: 1;
  cursor: pointer;
  transition: background .12s ease;
}
#zoom-controls button:hover { background: var(--header-hover); }
#zoom-level { font-size: var(--fs-label); min-width: 34px; text-align: center; color: var(--header-muted); }
/* THE SCROLLBAR'S WIDTH IS ALWAYS RESERVED (item 0LL, reviewer 2026-09-24: "the scan page
   got stuck in a flashing loop"). The page is fitted to this pane's width (refitScanToPane).
   Where a scrollbar TAKES width - 17px on Windows, or a Mac set to always show them - a page
   that just overflowed got a scrollbar, the pane narrowed, the page was refitted shorter, the
   scrollbar went, and round again, every frame, in a band of window heights ~20px wide.
   Reserving the gutter keeps clientWidth the same whether the scrollbar shows or not, so the
   fit width cannot move under its own feet. No effect with overlay scrollbars. */
#scan-viewer {
  flex: 1;
  position: relative;
  overflow: auto;
  scrollbar-gutter: stable;
  padding: var(--sp-4) 0;
  cursor: grab;
}
#scan-viewer.panning { cursor: grabbing; }
#page-container {
  position: relative;
  display: table;
  margin: 0 auto;
  box-shadow: var(--shadow-page);
  background: var(--paper);
  border-radius: var(--radius-mark);
  overflow: hidden;
}
#page-img { display: block; width: 480px; height: auto; -webkit-user-drag: none; user-select: none; }
#hl-container { position: absolute; inset: 0; overflow: hidden; }
.hl-box {
  position: absolute;
  border-radius: var(--radius-mark);
  /* box-shadow instead of border: a border sits ON the box's own edge
     (exactly the token's bbox, per Lesson from 2026-08-07 review-dashboard
     feedback) and covers a couple pixels of the actual letter strokes
     right at that boundary on tight-fitting boxes. A non-inset box-shadow
     draws OUTSIDE the box entirely, so it outlines the region without
     ever overlapping the scan image underneath it. */
  box-shadow: 0 0 0 2px var(--hl-color, currentColor);
  /* the box's tint, 20% of its state colour (until 2026-10-01 the script wrote it, the colour's hex with "33" added) */
  background: color-mix(in srgb, var(--hl-color, transparent) 20%, transparent);
  cursor: pointer;
  transition: opacity .15s ease;
}
/* --hl-color is set per-box in app.js from the same tri-state (open/
   machine/human) as the text pane's underlines and the nav legend - color
   alone carries the state here. No dotted variant for the machine-resolved
   state: a dotted *border* would sit back on the box's own edge, exactly
   the letter-stroke-covering problem box-shadow was introduced to avoid
   (see comment above), so the scan pane deliberately doesn't reproduce the
   text pane's solid/dotted distinction. */
.hl-box.dim { opacity: 0.35; }
/* When a specific word is focused (reviewer clicked it in the text pane),
   fade everything else to near-invisible so the highlighted box reads alone
   against the scan image. Only the .focused box keeps full opacity. */
#hl-container.has-focus .hl-box:not(.focused) { opacity: 0.06 !important; }
/* The specific word clicked in the text pane: thick ring in the box's
   own state color so the boundary is unmistakable without obscuring the
   underlying scan text. Entirely transparent inside for human eyeball review.
   z-index so the ring renders above adjacent boxes. */
.hl-box.focused {
  box-shadow: 0 0 0 5px var(--hl-color, currentColor) !important;
  background: transparent !important;
  z-index: var(--z-lift);
  opacity: 1 !important;
}
/* A BOX THE PAGE PLACED, NOT ONE THE OCR READ (girsa-operator's fd59b49; the reviewer 2026-10-05: a "dashed" box
   "just after the word before it", then "build the same line"): for a word with no box of its own, the space between
   its boxed neighbours on one line. It must never pass for a box the OCR read: DASHED, in the accent blue that no word
   state uses, with a faint wash of it inside. An outline, drawn outside the box with a gap (as the rings' box-shadow
   is), so it never covers the letters; it carries no state colour, since nothing here was read. */
.hl-box.hl-placed, .hl-box.hl-placed.focused {
  box-shadow: none !important;
  outline: 3px dashed var(--accent);
  outline-offset: 2px;
  background: color-mix(in srgb, var(--accent) 10%, transparent) !important;
  cursor: default;
}
/* THE KINDS (girsa-operator's e5b609a: hl-placed-line, -break, -entry). An 'entry' box is the entry's whole region on
   the page, so it keeps only a thinner dashed outline - a wash over a whole entry would tint a large part of the scan,
   and the place is only "somewhere in this entry". A 'break' draws two boxes, both dashed; the second is not .focused. */
.hl-box.hl-placed.hl-placed-entry, .hl-box.hl-placed.hl-placed-entry.focused { outline-width: 2px; background: transparent !important; }
/* WHILE A PLACED BOX STANDS FOR THE WORD, THE REST FADE as they do for a word with a box of its own (the rule above,
   #hl-container.has-focus): the page decides has-focus before it places a box, so without this the red and amber boxes
   around a placed one stayed at full strength and competed with it (measured on the second book's entry 203 w260). */
#hl-container:has(.hl-placed.focused) .hl-box:not(.hl-placed) { opacity: 0.06 !important; }
/* THE ENTRY BEING READ, one look on both panes: its region on the scan and its
   block in the text (reviewer 2026-09-15: "add light yellow box around selected
   shoresh in text pane - same as scan pane"). One rule for both, so the two
   boxes cannot drift apart. */
.hl-current-klal, .klal-block.current-entry {
  border-radius: var(--radius-sm);
  box-shadow: 0 0 0 3px var(--pending);
  background: var(--place-wash);
}
.hl-current-klal {
  position: absolute;
  pointer-events: none;
  transition: top .15s ease, left .15s ease, width .15s ease, height .15s ease, opacity .15s ease;
}
/* THE PAGE ARROWS ARE ZOOM-CLUSTER BUTTONS (the reviewer 2026-10-04, W4): they take the cluster's button rule above.
   Previous sits left and next right in the cluster, each glyph pointing inward (swapped 2026-09-01 at the reviewer's
   request: "arrow behavior is correct but swap two icons"), so the sides and the handlers are as they were. */
.page-nav-btn { font-size: var(--fs-title); }
.page-nav-btn:disabled { opacity: 0.35; cursor: default; }
.page-nav-btn:disabled:hover { background: transparent; }

/* ---------- MIDDLE: running text ---------- */
#text-pane {
  /* THE PANE THAT YIELDS. Basis is a share of the window, shrink is on, so this
     is what a narrowing window takes width from - see #scan-pane above for why
     the two were swapped. 42% keeps the wide-window proportions the reviewer
     already had (at 1600px: text 672, scan 548, against 676/544 before). */
  /* 30% since the list pane became the fourth column (W1 (a), 2026-10-04): at 1864 wide the text 559px and the scan
     505, where 42% left the scan 400. */
  flex: 0 1 30%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  min-width: 220px;
  /* FIXED 2026-08-21 (user bug report: switching directly from one
     highlighted word to another took two clicks, not one). #overlay-
     backdrop is `position:fixed; inset:0; z-index:900` and opens the
     instant any candidate/witness/manual panel is open - since #text-pane
     had no z-index of its own (defaulted to the static stacking level,
     below the backdrop), a click on a word while a DIFFERENT word's panel
     was still open hit the backdrop first (dismissing it) instead of the
     word underneath - only the SECOND click, now that the backdrop was
     gone, actually reached the word and opened/highlighted it. #scan-pane
     already carries this exact fix (`z-index: 910`, just below); text-pane
     never got the same treatment when panels were added. */
  position: relative;
  z-index: var(--z-pane);
}
#text-scroll {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-6) var(--sp-6);
  line-height: 2;
  font-size: var(--text-size);
}
/* Room for the current-entry box on EVERY block, not only the boxed one:
   padding on the current block alone would re-flow its text each time the
   reading line crossed into the next entry. The negative inline margin gives
   the width back, so the text sits exactly where it always did. */
.klal-block {
  margin-bottom: var(--sp-6); scroll-margin-top: 12px; min-height: 40px;
  padding: var(--sp-2) var(--sp-3);
  margin-inline: calc(-1 * var(--sp-3));
}
/* A RULE ABOVE EACH ENTRY (girsa-operator's REQUEST, 2026-10-13): under a three-line entry the next entry's head, its
   "3 flagged words" button with it, read as the short entry's own - the reviewer clicked it there as 188's
   (http://127.0.0.1:8420/entry/188/word/11). The hairline in the gap says where an entry starts, so its head reads with
   the text under it. An inset shadow, not a border: no block grows by a pixel, so no scroll position moves. The entry
   being read has its box instead, and the first entry nothing above it. */
.klal-block + .klal-block:not(.current-entry) { box-shadow: inset 0 1px 0 var(--line); }
.klal-block .klal-head {
  font-weight: 700;
  color: var(--accent);
  font-size: var(--entry-head-size);
  font-family: 'Inter', sans-serif;
  margin-bottom: var(--sp-2);
  display: flex;
  gap: var(--sp-3);
  align-items: center;
  /* Packed against the heading (reviewer 2026-09-02: put the flag pill with its
     heading). The row is as wide as the pane, so without this the controls
     drifted to the far edge and read as belonging to nothing. `start` in an RTL
     column is the right-hand side, where the heading is. */
  justify-content: flex-start;
  /* THE ROW WRAPS (2026-10-06): in the text pane the reviewer chose to squeeze (234px at 1229x673, 2026-10-05) the
     number and the three buttons need about 420px, and a row that could not wrap pushed them out past the pane's
     start edge - the "flagged word" pill out of sight, "Heading" cut in half, "Flag klal" squeezed onto three lines.
     Now what does not fit starts a line of its own, still packed against the start. */
  flex-wrap: wrap;
  row-gap: var(--sp-1);
}
/* .sec (the section name) was dropped from the heading 2026-09-02 - it never
   changed down the whole pane and the header bar already names the work. The
   rule goes with it rather than lingering as a selector for nothing. */
/* Both numerals at ONE size: the same fact in two scripts, so sizing one above
   the other implied a hierarchy that is not there. */
.klal-block .klal-head .kid-n { font-size: var(--marker-size); }
.klal-wordflags {
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  font-weight: 600;
  color: var(--pending-ink);
  border: 1px solid var(--pending);
  border-radius: var(--radius-pill);
  padding: var(--sp-half) var(--sp-2);   /* the flag button's, so the heading row's three buttons are one height */
  background: transparent;
  cursor: pointer;
  white-space: nowrap;
}
/* The section marker, larger and bold in the text pane (reviewer 2026-08-31) -
   it is the reader's place-keeper down a long scrolling column. Uses the shared
   role tokens so the index pane's marker can never drift away from it. */
.klal-block .klal-head .kid {
  color: var(--accent-dark);
  font-family: var(--font-marker);
  font-size: var(--marker-size);
  font-weight: 800;
  letter-spacing: .01em;
  white-space: nowrap;
}

/* ---- .klal-title: ONE rule, both panes ------------------------------------
   The index row and the text-pane head render the same string and must look the
   same doing it. Set in --font-title so a title reads as a HEADING rather than
   as more UI chrome, which is what distinguishes it from the surrounding
   interface text in either pane. */
.klal-title {
  font-family: var(--font-title);
  font-size: var(--title-size);
  font-weight: 600;
  color: var(--ink);
  direction: rtl;
  unicode-bidi: isolate;
}
/* ---- the heading and marker WHERE THEY ACTUALLY SIT, inside the text --------
   The book does not print a title above a klal; the klal OPENS with its heading,
   set in larger type, and the marker before it. So these style words in the
   running text rather than a separate line (reviewer 2026-08-31). Both are
   layered ON TOP of whatever state class the word already carries - a heading
   word can also be disputed or flagged - so neither sets `color`, which would
   overwrite the state colour the reviewer navigates by. */
.klal-body .klal-marker-word {
  font-weight: 800;
  font-size: var(--marker-inline-size);
  font-family: var(--font-marker);
  letter-spacing: .01em;
}
.klal-body .klal-title-word {
  font-family: var(--font-title);
  font-size: var(--title-inline-size);
  font-weight: 700;
}
/* Breathing room around the heading in the running text (reviewer 2026-08-31:
   "one more space between count title and text in reading pane"). Logical
   properties, so this stays correct in an RTL column: `end` is the side the text
   continues toward. A margin rather than a wider word-space, so it applies once
   at each boundary instead of between every heading word. */
.klal-body .klal-marker-word { margin-inline-end: .5em; }
.klal-body .klal-title-end   { margin-inline-end: .6em; }
.klal-flag-btn {
  border: 1px solid var(--line);
  background: var(--wash);
  color: var(--ink-faint);
  border-radius: var(--radius-pill);
  font-size: var(--fs-note);
  font-family: 'Inter', sans-serif;
  padding: var(--sp-half) var(--sp-2);
  cursor: pointer;
  /* `margin-inline-start: auto` used to push this to the far end of a
     pane-wide row, ~490px from the heading it belongs to - a control floating
     against nothing. Reviewer 2026-09-02: put the pill with its heading. */
  transition: all .12s ease;
}
.klal-flag-btn:hover { border-color: var(--pending); color: var(--pending-ink); }
.klal-flag-btn.active {
  background: var(--pending-wash);
  border-color: var(--pending);
  color: var(--pending-ink);
  font-weight: 600;
}
.klal-body { color: var(--ink-text); }
.klal-body.loading { color: var(--ink-faint); font-family: 'Inter', sans-serif; font-size: var(--fs-ui); }

.flag-word {
  cursor: pointer;
  border-radius: var(--radius-mark);
  padding: 0 var(--sp-hair);
  position: relative;
}
/* Tri-state review coloring, shared with the scan pane and nav legend
   (see wordState() in app.js): red = nobody has resolved this dispute
   yet, yellow dotted = the vision pass confirmed the current text without
   a human, green = a human recorded a decision (always wins, even over a
   machine "confirmed" verdict). */
/* A ruling the text pane cannot place. Deliberately the DANGER colour and not
   the witness banner's amber: an unmapped scan reading is informational, this is
   work a human recorded that nothing is doing anything about.
   An entry whose text could not be loaded (c619e1f) is the same kind of notice - "needs you" (D7): its text is missing
   and only its "Try again" brings it; it was a bare paragraph in the text's face, laid out right to left.
   So is a ruling whose writing was interrupted (#ledger-notice, E M4): a ruling may be missing, and only its reviewer
   saving it again brings it back; it stands where #server-notice does, over the text. */
.stranded-banner, .entry-load-failed, #ledger-notice {
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  color: var(--ink);
  background: var(--alert-bg);
  border: 1px solid var(--danger);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-2);
  margin: 0 0 var(--sp-2);
  line-height: 1.5;
}
.stranded-banner ul { margin: var(--sp-1) 0 0; padding-inline-start: var(--sp-4); }
.stranded-banner li { margin: var(--sp-half) 0; color: var(--ink-soft); }
/* ENGLISH IN THE RIGHT-TO-LEFT TEXT COLUMN (audit B4, 2026-09-30). An element holding English that takes the column's
   direction puts a leading number or a trailing stop at the wrong end: the notice below read "... reviewable in the
   1 .scan pane only", the heading's pill "flagged word 1". The two notices are left to right, as .stale-banner and
   .alt-banner already were. The heading's three buttons take their direction from their own text instead
   (`plaintext`), so their boxes keep the column's direction. */
.stranded-banner, .witness-banner, .entry-load-failed, #ledger-notice { direction: ltr; text-align: left; }
#ledger-notice { margin: var(--sp-2) var(--sp-3) 0; }
.entry-load-failed .entry-load-retry { margin-inline-start: var(--sp-2); padding: var(--sp-half) var(--sp-2); }
.klal-wordflags, .klal-flag-btn, .klal-title-btn { unicode-bidi: plaintext; }
/* One line height for the three (2026-10-06): with `normal`, a symbol drawn from a fallback font (the concern's warning
   sign) made its button 3px taller than the others. .klal-title-btn repeats it after its `font: inherit`. */
.klal-wordflags, .klal-flag-btn { line-height: 1.25; }

.witness-banner {
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  color: var(--ink-soft);
  background: var(--notice-bg);
  border: 1px solid var(--notice-line);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-2);
  margin-bottom: var(--sp-2);
  line-height: 1.5;
}
/* Another printing's reading, in a ruling panel: a notice for your information (D7), where it was a brown bar written
   inline in the template with a token that was never defined (`--warn`). */
.cross-edition-warning {
  font-size: var(--fs-note); color: var(--ink-soft); line-height: 1.5; margin-top: var(--sp-1);
  background: var(--notice-bg); border: 1px solid var(--notice-line); border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-2);
}
/* Each rule below draws a state's underline in the text AND its swatch in the legend (#legend i.swatch-*, style guide
   B1, 2026-10-01): the key is the same rule as the thing it is a key for. Until then the swatches were inline styles
   in app.js (LEGEND_SWATCH), kept in step by a browser test. */
#legend i.swatch-open, .flag-word.state-open { border-bottom: 3px solid var(--state-open); }
/* ADDED 2026-08-17: a klal_flag naming a specific word_index (an AI pass
   like detect_real_word_substitution.py, not the vision-adjudication
   pipeline behind state-open/state-machine) - visually distinct (dashed,
   not solid/dotted) since it carries no vision confirmation, only the
   pass's own textual/frequency reasoning (shown in .title on hover). */
#legend i.swatch-ai, .flag-word.state-ai-flag { border-bottom: 3px dashed var(--state-ai); }
#legend i.swatch-machine, .flag-word.state-machine { border-bottom: 2px dotted var(--state-machine); }
.flag-word.state-machine { opacity: 0.92; }
#legend i.swatch-human, .flag-word.state-human { border-bottom: 3px solid var(--state-human); }
/* A WORD WHOSE RULINGS ARE ALL APPLIED, while Settings' switch is on (the reviewer, 2026-10-06: "default behav
   [behaviour] - keep them plain. option under settings - double-green"; the server names the words, step 5's C6c3, and
   the switch sets the body's class): two thin green lines in the same 3px band as a ruled word's one solid line, so
   nothing in the line moves and the two read apart. Not a word state - no swatch, no row in the modes. Over a word an
   answered flag draws, the double line wins while the switch is on: the word is finished either way. */
body.show-ruled-applied .ruled-applied { border-bottom: 3px double var(--state-human); }
.flag-word.pending-delete { text-decoration: line-through; text-decoration-color: var(--danger); opacity: 0.7; }
/* ADDED 2026-08-17 (user bug report: "I manually corrected it, and the
   word is now marked in green, but it has the wrong text" - a recorded-
   but-not-yet-applied manual correction showed the OLD disputed word,
   styled as if resolved, with no indication of what it would actually
   become - see .pending-replace-text below for the paired fix). */
.flag-word.pending-replace { text-decoration: line-through; text-decoration-color: var(--state-human); opacity: 0.75; }
.pending-replace-text { color: var(--decided-ink); font-weight: 600; margin: 0 var(--sp-half); }
/* between a struck word and its pending replacement: no symbol (item 0MI - an arrow in right-to-left text points
   back at the old word); the English panels say "to" */
.pending-replace-gap { font-size: var(--fs-label); }
.pending-replace-to { color: var(--ink-faint); font-size: var(--fs-label); }
/* THE EDITOR'S OWN FORMATTING (item 0LZ): each kind its own style, none an underline or a colour
   the review states use. Hidden with Settings > "Show the editor's formatting" off.
   ITS KEY, under that switch in Settings (the reviewer, 2026-10-09: "(a) In Settings (Recommended)", from mock-ups of
   today, a key in Settings and a key under the legend - the kinds were named only in each piece's hover): a sample of
   each kind drawn by the same rule as the text, and drawn whether the switch is on or off - it is a key. */
.klal-body .fmt-bold, .formatting-key .fmt-bold { font-weight: 700; }
.klal-body .fmt-info-text, .formatting-key .fmt-info-text { background: var(--info-wash); border-radius: var(--radius-mark); }
.klal-body .fmt-mediumGrey, .formatting-key .fmt-mediumGrey { color: var(--ink-faint); } /* E1, the reviewer 2026-10-01: was #8a94a6, 2.7:1 on the selected entry - now 4.2:1, still grey */
/* the samples in the text's ink, not the hint's grey, which is mediumGrey's own: there the grey sample read as the line
   around it (caught by its test) */
.formatting-key span { color: var(--ink); }
.formatting-key bdi { font-family: 'Frank Ruhl Libre', serif; font-size: var(--fs-ui); padding: 0 var(--sp-hair); }
body.hide-formatting .klal-body .fmt-bold { font-weight: inherit; }
body.hide-formatting .klal-body .fmt-info-text { background: none; }
body.hide-formatting .klal-body .fmt-mediumGrey { color: inherit; }
/* The marked text's APPLIED corrections (item 0M1) - blue, apart from the pending ones' green. */
.marked-view .marked-applied-old { text-decoration: line-through; text-decoration-color: var(--marked-applied); color: var(--ink-faint); }
.marked-view .marked-applied-new { color: var(--marked-applied); font-weight: 600; }
/* The marked text (item 0LZ) is read-only: its struck words are not buttons. */
.marked-view .flag-word { cursor: default; }
.marked-view .flag-word:hover { background: none; }
.flag-word:hover { background: var(--word-hover); }
/* Cross-edition marker (2026-09-04). The Dicta witness reads the Jerusalem
   1975/6 printing rather than the Berlin scan this corpus transcribes, so a
   dispute it takes part in is a different KIND of claim - see
   pipeline/synthesize_multi_witness.py's SAME_EDITION_ENGINES. Marked with a
   superscript rather than a colour because the underline already carries
   decision state and the two facts are unrelated. */
.cross-edition-mark {
  font-size: var(--mark-em);
  font-weight: 700;
  color: var(--pending-ink);
  margin-inline-start: var(--sp-hair);
  cursor: help;
  vertical-align: super;
}
/* Every word is clickable now (2026-08-13, "flag any word and replace
   it"), not just machine-flagged ones - but a permanent visual mark on
   every single word in the corpus would bury the tri-state coloring above
   in noise, so this is deliberately hover-only: no border, no color,
   until the reviewer's cursor is actually on it. */
.plain-word { cursor: pointer; border-radius: var(--radius-mark); padding: 0 var(--sp-hair); }
.plain-word:hover { background: var(--word-hover); }
.flag-gap {
  display: inline-block;
  width: 9px;
  height: 15px;
  margin: 0 var(--sp-half);
  border-radius: var(--radius-mark);
  cursor: pointer;
  vertical-align: middle;
  opacity: 0.85;
}
.flag-gap:hover { opacity: 1; transform: scaleY(1.15); }
.punct-marker {
  display: inline-block;
  cursor: pointer;
  font-weight: 900;
  font-size: var(--punct-size);
  line-height: 1;
  margin: 0 var(--sp-half);
  padding: 0 var(--sp-half);
  border-radius: var(--radius-mark);
  vertical-align: middle;
}
.punct-marker.punct-pending { color: var(--punct-pending); }
.punct-marker.punct-pending:hover { background: var(--punct-pending-wash); }
.punct-marker.punct-accepted { color: var(--state-human); }
.punct-marker.punct-rejected { color: var(--ink-faint); opacity: 0.5; }
.punct-marker.punct-rejected:hover { opacity: 0.85; }
.editorial-mark {
  color: var(--accent);
  font-weight: bold;
  cursor: help;
  opacity: 0.8;
}
/* Invisible scroll-position anchor - see continuationBoundaries() in app.js.
   display:inline-block so it gets its own line-position rect even with no
   content, without affecting text flow/spacing (width:0). */
.continuation-marker { display: inline-block; width: 0; pointer-events: none; }

/* ---------- RIGHT: abridged nav ---------- */
#nav-pane {
  width: var(--nav-w);
  flex-shrink: 0;
  background: var(--paper);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  /* Same treatment #scan-pane and #text-pane already carry, and for the same
     reason: without a z-index of its own this pane sits below
     #overlay-backdrop (z 900) and every click on it while a panel is open hits
     the backdrop instead. It was the only one of the three left out. */
  position: relative;
  z-index: var(--z-pane);
}
/* Two toggles on ONE line (reviewer: "put two flags above index pane on same
   line to max real estate for the index"). Every row this block costs is a klal
   the index cannot show. */
#part-select {
  /* Content-width, on the filter row - see index.html for why it stopped being a
     full-width band. */
  padding: var(--sp-half) var(--sp-1);
  border-radius: var(--radius-sm);
  font-family: 'Inter', sans-serif;
  font-size: var(--control-small);
  font-weight: 600;
  background: var(--header-bg);
  color: var(--header-fg);
  border: 1px solid var(--header-line);
  cursor: pointer;
}
#nav-toggles label { white-space: nowrap; }
#nav-filter {
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--line);
  font-family: 'Inter', sans-serif;
  font-size: var(--control-small);
  color: var(--ink-soft);
}
#nav-filter label { display: flex; align-items: center; gap: var(--sp-1); cursor: pointer; }
/* TWO LINES (the reviewer, 2026-10-06, shown today and two lines at both window sizes: "2B"): the part selector at
   the start and the reviewer's name at the end, then the two filters together on a line of their own. Item 0HZ had
   one row, the name yielding first by shrinking; once the part selector joined the row, Yad Malachi's toggles took
   290px of a 347px row - the name showed one letter at full screen and none at 1229x673, where the row also ran 12px
   out of the pane. Kept from the rulings that meet here: the name always in view (2026-09-17), the two filters on one
   line ("put two flags above index pane on same line"), the part selector its content's width, never a band. The name
   still yields first - it ends in an ellipsis when its line is short. A book of one part hides the selector; its name
   takes the line. */
#nav-filter {
  display: grid; grid-template-columns: max-content minmax(0, 1fr);
  align-items: center; column-gap: var(--sp-3); row-gap: var(--sp-1);
}
#nav-filter #nav-toggles { display: contents; }
#part-select { grid-row: 1; grid-column: 1; justify-self: start; }
.nav-flags { grid-row: 2; grid-column: 1 / -1; justify-self: start; display: flex; align-items: center; gap: var(--sp-3); }
#reviewer-pill {
  grid-row: 1; grid-column: 2; justify-self: end;
  min-width: 0;
  max-width: 100%;
  display: inline-flex; align-items: baseline;
  overflow: hidden; white-space: nowrap;
  direction: ltr; unicode-bidi: isolate;
  font: inherit; font-size: var(--fs-label);
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: var(--sp-half) var(--sp-2);
  cursor: pointer;
}
#reviewer-pill:hover { background: var(--accent-wash); }
#reviewer-pill b { font-weight: 600; color: var(--ink); unicode-bidi: isolate; }
#reviewer-pill { align-items: center; gap: var(--sp-1); }
#reviewer-pill .rp-icon { flex: 0 0 auto; width: 11px; height: 11px; fill: currentColor; opacity: 0.7; }
/* signed in through a proxy (item 0JC): the name is not a choice, so it does not look like one */
#reviewer-pill.verified { cursor: default; }
#reviewer-pill.verified .rp-icon { opacity: 1; fill: var(--accent); }
#reviewer-pill .rp-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* A name this tab CHOSE, as against the server's default, is worth noticing: it
   is the one that will not be there in a new tab. */
#reviewer-pill.chosen { border-color: var(--accent); color: var(--accent-dark); }
#nav-list { flex: 1; overflow-y: auto; padding: var(--sp-1); container-type: inline-size; }   /* the legend left the foot 2026-10-04 (W1 a): no room to reserve */
.nav-item {
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--nav-size);
  display: flex;
  justify-content: space-between;
  gap: var(--sp-1);
  align-items: center;
  transition: background .1s ease;
}
.nav-item:hover { background: var(--accent-wash); }
.nav-item.active { background: var(--selected-row); }
/* tabular-nums: Inter's default digit widths aren't equal (e.g. "1" is
   narrower than "0"/"2"-"9"), so right-aligned numbers like 11/21/31/41
   sat visibly closer to the right edge than neighbors like 10/12/20/22 -
   confirmed by measuring rendered text width (11px for "11" vs 14px for
   "10"/"12"). Forcing fixed-width digits makes every klal number occupy
   the same width regardless of which digits it contains. */
/* Same face as the marker in the text-pane head (--font-marker), larger and
   bolder than the row around it (reviewer 2026-08-31): the number is what the
   reviewer scans this column for, and it should read as the same object in both
   places. */
.nav-item .nid {
  color: var(--accent); font-weight: 700;
  min-width: var(--nid-w, 24px);   /* the widest number, see sizeMarkerColumn() */
  font-family: var(--font-marker); font-size: var(--nav-id-size);
  font-variant-numeric: tabular-nums;
}
/* The number columns and the badges are the fixed furniture of the row; the
   TITLE is the only thing that may give way. All of them are flex-shrink: 0 so
   a long title can never squeeze the dispute counts or the flag out of view
   (reviewer, 2026-08-31) - `.nid` was shrinkable before, which is what let a
   long title push the row's right-hand end off. `.ntitle` keeps flex: 1 with
   min-width: 0, which is what makes text-overflow: ellipsis actually fire
   inside a flex child. */
.nav-item .nid { flex-shrink: 0; }
/* THE TWO NUMBERS ON ONE LINE (the reviewer, 2026-10-12: "the arabic numerals a bit higher than the corresponding
   gematria entries"): the row centres each piece's box, and the number (Inter, 13px) and its Hebrew numeral (the
   Hebrew face, 18px) have different boxes - the number's baseline sat 1.5px above the numeral's in every row, both
   books, both sizes. The number is moved down by that much, measured to 0.02px. Not `align-self: baseline`: that
   puts the pair at the row's top, beside the first line of a two-line title, where the row today centres it. */
.nav-item .nid { position: relative; top: var(--nav-id-drop); }
.nav-item .nheb {
  flex-shrink: 0;
  /* The widest marker in the list, so every title starts in the same place
     (item 0GO); see sizeMarkerColumn() in app.js. */
  min-width: var(--nheb-w, 30px);
  /* The one line this element was missing. Without it the Hebrew marker
     inherited the body serif while its twin in the text pane took
     --font-marker - the same numeral in two faces, one pane apart. */
  font-family: var(--font-marker);
  color: var(--accent);
  opacity: .8;
  font-weight: 700;
  font-size: var(--nav-marker-size);
  direction: rtl;
  unicode-bidi: isolate;   /* keep the Hebrew from reordering the LTR row */
}
/* On the chosen row the softening goes (E3, the reviewer 2026-10-01): at .8 on the row's blue it is 2.9:1, at full
   strength 4.0:1, as the row's number beside it already is. */
.nav-item.active .nheb { opacity: 1; }
/* colour stays softer than the text pane's (this is a list, not a heading in
   its own right) but the FONT is the shared one - see .klal-title. */
/* TWO LINES BEFORE THE ELLIPSIS (item 0LR finding a; reviewer 2026-09-26: "#7"). One line cut
   302 of the second book's 317 titles at a 1920x1080 laptop at 150% - the index is ~306px
   there, and nearly every title opens `האל'ף ו…`, so only the root told rows apart. A title
   that fits one line keeps a one-line row. In a NARROW index (below) the title also takes a
   line of its own: beside the number, the root and the three badge slots it had one word. */
.nav-item .ntitle { flex: 1; min-width: 3.5em; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; white-space: normal;
  line-height: 1.3; }
/* AFTER the rule above, which it overrides at equal specificity (`flex: 1` resets the basis). */
@container (max-width: 340px) {
  .nav-item { flex-wrap: wrap; row-gap: var(--sp-half); }
  .nav-item .ntitle { order: 10; flex-basis: 100%; }
}/* REFERENCE NUMERALS (item 0GO): drawn small and raised, as the page prints
   them. They stay words in the text; see markFootnoteRefs() in app.js. */
.klal-body .fn-ref { vertical-align: super; font-size: var(--superscript-em); line-height: 0; color: var(--ink-soft); }
/* A footnote ANCHOR (item 0KF): the note is known, drawn as a numbered mark before its word. */
.klal-body .fn-anchor { font-size: var(--superscript-em); line-height: 0; color: var(--accent); margin: 0 .1em; padding: 0 .15em; cursor: pointer; }
.klal-body .fn-anchor:hover, .klal-body .fn-anchor:focus { text-decoration: underline; outline: none; }
/* A note number COUNTED on its page, not read from it (item 0M1): may be off - drawn apart. */
.klal-body .fn-anchor.fn-counted { color: var(--ink-faint); font-style: italic; }
/* The note card (showNoteCard): the note, and the cited verse on Sefaria. */
#note-card {
  position: fixed; z-index: var(--z-note-card); max-width: 360px; padding: var(--sp-2) var(--sp-2); border-radius: var(--radius);
  background: var(--paper); color: var(--ink); border: 1px solid var(--line);
  box-shadow: var(--shadow-float); font-family: 'Inter', sans-serif; font-size: var(--fs-ui);
}
#note-card .nc-head { font-size: var(--fs-label); color: var(--ink-faint); text-transform: uppercase; letter-spacing: .03em; }
/* the qualifier of a number the page did not give, under the label in ordinary case (2026-10-09): a sentence in small
   capitals read as one shouted line */
#note-card .nc-why { display: block; font-size: var(--fs-note); text-transform: none; letter-spacing: normal; margin-top: var(--sp-half); }
/* ENGLISH IN A RIGHT-TO-LEFT CARD (style guide B5): the card takes the page's right-to-left, so the head's "?" fell to its
   left ("? NOTE"), the qualifier's brackets swapped ends, and the link's closing mark stood before its words. Laid out
   left to right, still at the card's right edge, where the Hebrew note above aligns. */
#note-card .nc-head, #note-card .nc-link { direction: ltr; text-align: right; }
#note-card .nc-link { display: block; }
#note-card .nc-note { font-family: 'Frank Ruhl Libre', serif; font-size: var(--note-size); margin: var(--sp-1) 0; }
#note-card .nc-link { color: var(--accent); }
/* A stray OCR mark identified as a footnote numeral (item 0GO): the stored word
   is still the mark, so the number is drawn in its place, dotted to show it was
   inferred rather than read. */
.klal-body .fn-mark { font-size: 0; }
/* The other half of a split numeral (item 0GO): the mark beside it already
   shows the whole number. */
.klal-body .fn-absorbed { font-size: 0; }
.klal-body .fn-mark::after {
  content: attr(data-fn); font-size: var(--fs-label); vertical-align: super;
  color: var(--ink-soft); text-decoration: underline dotted;
}
.nav-item .nflag { color: var(--pending-ink); font-size: var(--fs-note); flex-shrink: 0; }
.nav-item .nflag.nflag-empty { visibility: hidden; }
/* The badge group is `direction: ltr` inside an RTL row, so DOM order is
   left-to-right here: red is written first and therefore sits leftmost, on every
   row (reviewer 2026-09-02: "red pill first on the left so they all line up").
   Every slot is always present and every slot is the same width, so the column
   can be read straight down - a badge omitted at zero used to move the red one
   sideways on every row. */
.nav-item .ncounts { display: flex; direction: ltr; gap: var(--sp-1); flex-shrink: 0; }
.nav-item .ncount {
  color: var(--on-fill); border-radius: var(--radius-pill);
  font-size: var(--count-size); font-family: 'Inter', sans-serif; padding: var(--sp-half) var(--sp-half); flex-shrink: 0;
  /* A FIXED width, not a minimum: a two-digit count used to widen its pill and push
     the pennant beside it off the column (reviewer 2026-09-23, klal 128). Three
     digits fit. */
  width: 26px; box-sizing: border-box; text-align: center;
  font-variant-numeric: tabular-nums;
}
/* An empty slot holds its width and draws nothing. More specific than the three
   colour rules below, so no !important is needed. */
.nav-item .ncount.ncount-empty { background: transparent; }
/* ONE badge at rest - the red one, which is the only count that is asking the
   reviewer for something. Reviewer 2026-09-02: "show the red open count and the
   rest on hover". Three coloured pills on every row made the column read as
   decoration, and the number that matters was the hardest to pick out of it.
   The others are still there, one hover away, and the row does not reflow when
   they appear because the space is reserved either way. */
.nav-item .ncount-machine,
.nav-item .ncount-decided { visibility: hidden; }
.nav-item:hover .ncount-machine,
.nav-item:hover .ncount-decided,
.nav-item.active .ncount-machine,
.nav-item.active .ncount-decided { visibility: visible; }
/* Two distinct badges, not one undifferentiated count: red = still open
   (needs a decision), green = already decided - so the queue length and
   the actual remaining work are visually different at a glance. */
.nav-item .ncount-open { background: var(--state-open); }
.nav-item .ncount-decided { background: var(--state-human); color: var(--ink); }
/* Machine-resolved: the same amber the word itself renders in, so the badge and
   the text agree at a glance. Added 2026-08-31 - see navItemInnerHtml. */
/* Dark numbers on the amber and green pills (style guide D3, 2026-10-01): white on them was 2.4:1 and 3.3:1; the
   fills still match their words' colours. The red pill keeps its white number (4.1:1). */
.nav-item .ncount-machine { background: var(--state-machine); color: var(--ink); }
/* Punctuation review queue badges - same open/decided shape as
   corrections above, but blue-toned so the two queues read as visually
   distinct at a glance. */
.nav-item .ncount-punct-open { background: var(--punct-pending); }
.nav-item .ncount-punct-decided { background: var(--punct-decided); }

/* ---------- tooltip (quick hover info) ---------- */
#tooltip {
  position: fixed;
  max-width: 340px;
  background: var(--ink);
  color: var(--on-dark);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius);
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  line-height: 1.5;
  box-shadow: var(--shadow-tooltip);
  z-index: var(--z-tooltip);
  /* starts hidden by its `hidden` attribute (index.html) - the script shows and hides it so (style guide B2) */
  pointer-events: none;
  direction: ltr;
  text-align: left;
  unicode-bidi: isolate;
}
#tooltip .t-flag { font-weight: 600; margin-bottom: var(--sp-half); display: block; }
#tooltip .t-docai { display: block; margin-bottom: var(--sp-1); opacity: 0.95; }
#tooltip .t-conf { color: var(--on-dark-soft); font-size: var(--fs-label); display: block; }
#tooltip .t-hint { color: var(--on-dark-link); font-size: var(--fs-label); display: block; margin-top: var(--sp-1); }

/* ---------- legend ----------
   Pinned to the viewport's bottom-right corner (the layout is RTL, so the
   right column is the nav pane - see #nav-pane above) where it overlays
   that pane's own bottom rather than the scan pane on the left. Doubles as
   the corpus-wide tri-state count readout (built in app.js buildLegend()),
   so the nav pane's per-klal badges and this box always use the same
   red/yellow/green vocabulary. dir:ltr because the legend text is English. */
/* THE MODES (D1, the reviewer 2026-10-04: "the counts on the bottom right are perhaps the best way to run through the
   disputes - lets make them more prominent on the top bar above the center panel. each number needs a label and to be
   a button"). The legend's five counts, once a one-line strip at the index's foot (its rulings of 2026-09-02/03 - a
   swatch, the label in the hover, one line - are superseded by this), are labelled buttons under the list pane's bar.
   Each keeps its swatch (the text's own underline rule, #legend i.swatch-*), shows its label, and carries its count;
   the mode the list shows is filled.
   COMPACT ROWS (the reviewer 2026-10-05, shown three ways - today's wrapping buttons, compact rows, two columns: "B"):
   one slim row per mode, the swatch and label at its start and the count at its end, so the counts form one column;
   the five took 174px of a 673px window as buttons on their own lines at 1229x673, and take 114px at every size. */
#legend {
  display: flex; flex-direction: column;
  padding: var(--sp-1) var(--sp-2);
  background: var(--wash); border-bottom: 1px solid var(--line);
  font-family: 'Inter', sans-serif; font-size: var(--fs-note);
  direction: ltr; text-align: left;
}
#legend .legend-row {
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-half) var(--sp-2); border-radius: var(--radius-sm);
  border: 0; background: transparent; color: var(--ink);
  cursor: pointer;
}
#legend .legend-row .legend-count { margin-inline-start: auto; }
#legend .legend-row:hover { background: var(--header-hover); }
#legend .legend-row.legend-on { background: var(--accent-dark); border-color: var(--accent-dark); color: var(--paper); }
#legend i { width: 12px; height: 8px; display: inline-block; flex-shrink: 0; background: transparent; }
#legend .legend-label { font-weight: 600; }
#legend .legend-count { font-weight: 700; font-variant-numeric: tabular-nums; }
/* THE READER'S OWN LISTS (the word list, STEP5-WORD-LIST-PLAN.md; defined ahead of its L2, 2026-10-13): a group of
   rows after the modes, under a heading in the panel labels' look (.panel-label); each list a sub row as "Every ruling
   recorded" is, with no swatch - a list is not a word's state. */
#legend .legend-group {
  margin-top: var(--sp-1); padding: var(--sp-half) var(--sp-2) 0;
  font-size: var(--fs-label); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-faint);
}
/* PAST THREE LISTS, THE REST FOLD (the reviewer's Board #35, "B - Three lists, the rest folded", 2026-10-13: each list
   took 19px from the list below - at 1229x673 the list had 523px with none and 351px with eight). The link after the
   three rows is the list filters' fold link (.filter-fold): a link button, no border, on its own line. */
#legend .legend-fold {
  align-self: flex-start; margin: var(--sp-half) var(--sp-2) 0; padding: 0; border: 0; background: none;
  font-family: inherit; font-size: var(--fs-note);
}
/* LOAD A LIST, IN THE HEADING (girsa-builder's L2, c5111ed1): the same link button after the heading's words - the
   button's own border and fill, left to it, made the heading 31px where it is 17 */
#legend .legend-group .history-toggle {
  margin: 0 0 0 var(--sp-2); padding: 0; border: 0; background: none;
  font-family: inherit; font-weight: 400; letter-spacing: normal; text-transform: none;
}

/* ---------- the progress ring ----------
   THE REVIEWER'S BOARD #8, "A - One ring" (2026-10-11, from the steward's mock-ups `scratch/shots/progress/A-*` in its
   worktree; the request of 2026-10-10: "green and red dials ... not in an obvious game-like way"). One ring at the end of
   the list pane's bar - no new line - drawn from the legend's own two counts by buildLegend (app.js), so it never
   disagrees with the legend under it: green what is recorded ("Every ruling recorded"), red what still needs a ruling,
   and that number - what is left - in its centre, in red lettering (F1's --danger-ink). No ring per entry (the
   recommendation the answer took: the index's red badge already says what each entry has left). "+N today" sits at the
   bar's other end, its count girsa-operator's; Settings' switch puts `progress-off` on the body. */
/* IN THE BAR'S ROW, NOT PINNED OVER IT (the reviewer, 2026-10-12, a screenshot at about 1613 wide: "heading text
   overlaps"): the ring and "+N today" sat absolutely at the bar's two ends and the list's name, centred under them, ran
   into both - every "... (the list as it is now)" name at 1229, 1613 and 1864, in both layouts. Now "+N today" is the
   row's first item, the ring its last, at the same 8px from each end, and the name takes the room between them,
   centred there and wrapping to a second whole line where one is too short. */
#list-header { padding-inline: var(--sp-2); }
#list-header .ph-mid { flex: 1 1 0; justify-content: center; }
#list-header #flag-list-panel-title { white-space: normal; text-wrap: balance; text-align: center; line-height: 1.2; text-overflow: clip; }
#list-header .progress-ring-box { flex: none; display: flex; cursor: help; }
.progress-ring { width: var(--ring-size); height: var(--ring-size); display: block; }
.progress-ring circle { fill: none; stroke-width: 4; }
.progress-ring .ring-track { stroke: var(--line); }
.progress-ring .ring-done { stroke: var(--state-human); }
.progress-ring .ring-left { stroke: var(--state-open); }
/* the arcs start at twelve o'clock and run clockwise */
.progress-ring .ring-arcs { transform: rotate(-90deg); transform-origin: 50% 50%; }
.progress-ring text {
  fill: var(--danger-ink); font-family: 'Inter', sans-serif; font-size: var(--ring-count-size); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
#list-header .progress-today {
  order: -1; flex: none;
  color: var(--decided-ink); font-size: var(--fs-label); font-weight: 600; white-space: nowrap;
}
body.progress-off #list-header .progress-ring-box, body.progress-off #list-header .progress-today { display: none; }

/* ---------- the recorded-rulings view (senior review) ---------- */
.rec-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: 0 0 var(--sp-2); }
.rec-chip, .order-chip, .scope-chip {
  font: inherit; font-size: var(--fs-note);
  padding: var(--sp-half) var(--sp-2); border-radius: var(--radius-pill); cursor: pointer;
  border: 1px solid var(--chip-line);
  background: transparent; color: inherit;
}
.rec-chip:hover, .order-chip:hover, .scope-chip:hover { background: var(--row-hover); }
.rec-chip-on, .rec-chip-on:hover, .order-chip-on, .order-chip-on:hover, .scope-chip-on, .scope-chip-on:hover { background: var(--accent); border-color: var(--accent); color: var(--on-fill); }
.rec-chip b, .scope-chip b { font-variant-numeric: tabular-nums; }
.rec-status {
  font-size: var(--fs-label); text-transform: uppercase; letter-spacing: 0.03em;
  padding: var(--sp-half) var(--sp-1); border-radius: var(--radius-pill); white-space: nowrap; flex-shrink: 0;
  border: 1px solid currentColor; opacity: 0.85;
}
/* Colour carries the same meaning as everywhere else in this dashboard: green
   is settled, red is something a human still has to look at, amber is waiting. */
.recorded-item.rec-applied   .rec-status,
/* "already written" (P2, STEP5-APPLY-PLACE-PLAN.md row 19): its words already stand at its place, so Apply writes
   nothing and nothing is owed - the green of a change that is in the text. The server's key is one word,
   `already_written`, as `not_in_text` is: the class is `rec-` + the key. */
.recorded-item.rec-already_written .rec-status { color: var(--applied-ink); }
/* "unreadable" (2026-10-05, the builder's C5e) kept the text as it stood, as "confirmed" did: the same blue */
.recorded-item.rec-confirmed .rec-status,
.recorded-item.rec-unreadable .rec-status,
/* "kept" (W2, the reviewer's D2-a of 2026-10-08): a ruling the book's policy settles keeps the text as it stood - the
   same blue, not the green of a change applied */
.recorded-item.rec-kept .rec-status { color: var(--confirmed-ink); }
.recorded-item.rec-pending  .rec-status { color: var(--pending-ink); }
.recorded-item.rec-drifted  .rec-status,
.recorded-item.rec-not_in_text .rec-status { color: var(--danger); }
.recorded-item.rec-unplaced .rec-status,
/* "held" (P2; the reviewer's decision 1 on Board #1, 2026-10-09, "A - at its place, marked held", from the steward's
   mock-ups `held-A-*`): pending, but Apply will not write it - something a person has to look at, so the needs-you red,
   as "unplaced"; Apply's sentence is the row's own why line (.rec-why). In the text its place takes the open state's
   mark (STATE_META's state-open) with the sentence on it, and its words are not drawn as pending. */
.recorded-item.rec-held .rec-status { color: var(--danger); }
.recorded-item.rec-unknown  .rec-status { color: var(--ink-faint); }
/* `retired` is grey, not red: the word this ruling names was deleted from the
   corpus by a later ruling, which is a settled answer and not a lost address.
   Colouring it as danger would put 0 actionable rows in a reviewer's red count. */
.recorded-item.rec-retired  .rec-status { color: var(--ink-faint); }
/* "cancelled" (2026-10-05, C5e): a withdrawn insertion leaves nothing to apply - settled, like "retired": the same grey */
.recorded-item.rec-cancelled .rec-status { color: var(--ink-faint); }
.recorded-item.rec-drifted, .recorded-item.rec-unplaced, .recorded-item.rec-not_in_text,
.recorded-item.rec-held { background: var(--alert-row-wash); }
/* The stale-address marker. Deliberately NOT a status colour: it is a second,
   independent fact about the row (see RECORDED_STALE_LABEL) and a ruling can be
   honoured and still carry one. */
.rec-stale-mark { color: var(--pending-ink); flex-shrink: 0; cursor: help; font-size: var(--fs-note); }
/* A ruling no person adjudicated. Deliberately a MARK, not a colour swap: it is
   orthogonal to the status - a script-written ruling can be applied, pending or
   drifted like any other. */
.rec-machine-mark { color: var(--ink-faint); flex-shrink: 0; cursor: help; font-size: var(--fs-label); }
.rec-chip.rec-machine.rec-chip-on { background: var(--ink-soft); border-color: var(--ink-soft); }
.rec-chip.rec-stale.rec-chip-on { background: var(--pending); border-color: var(--pending); color: var(--ink); }
.rec-to { opacity: 0.55; flex-shrink: 0; }
/* The old word, "to" and the chosen text as one unit: a row that wraps (below) moves the change whole to its next
   line rather than splitting it between two (2026-10-01). The same gap between its pieces as between the row's (--sp-2). */
.rec-change { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.rec-chosen {
  direction: rtl; unicode-bidi: isolate;
  font-family: 'Frank Ruhl Libre', 'David', serif;
  font-size: var(--fs-word); font-weight: 600;
  min-width: 0; overflow-wrap: anywhere;   /* as .flag-list-word: the last resort for a chosen text longer than the row */
}
.rec-deleted { font-size: var(--fs-label); font-style: italic; opacity: 0.6; }
/* In the recorded view the current word is one column among several, so it must
   not push everything else to the far edge the way it does in the plain list. */
.recorded-item .flag-list-word { margin-inline-start: 0; }

/* (The former #book-title / #scan-book-title rules lived here. REMOVED
   2026-09-01: each pane styled its own title, which is exactly how the two bars
   came to differ - reviewer: "text differs between two blue headers". The four
   `.ph-*` slot rules above are the one description now, and every pane wears
   them.) */

/* ---------- the settings tray ---------- */
/* Reviewer: "don't put click word on link up there on the index pane, hide it
   away somewhere - settings icon?" A preference set once does not belong beside
   the two filters that get toggled while reading. */
#settings-btn {
  position: absolute;
  right: var(--sp-4);
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: 1px solid var(--header-line);
  color: var(--header-fg);
  border-radius: var(--radius-sm);
  width: var(--gear-size); height: var(--gear-size);
  font-size: var(--fs-ui); line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  opacity: 0.85;
}
#settings-btn:hover, #settings-btn[aria-expanded="true"] { opacity: 1; background: var(--header-hover); }
#settings-popover {
  /* ITS OWN SCROLL, ABOVE THE LEGEND (Audit D, D8, 2026-09-27): the Apply panel grew the tray past
     the pane - its button lay under the legend (1600x1000, classic) and opening it scrolled the whole
     stacked layout 543px at 1280x650 */
  max-height: calc(100vh - 150px);
  overflow-y: auto;
  position: relative;
  z-index: var(--z-popover);
  direction: ltr;
  padding: var(--sp-3) var(--sp-4);
  background: var(--accent-wash);
  border-bottom: 1px solid var(--line);
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  color: var(--ink-soft);
}
#settings-popover label { display: flex; align-items: center; gap: var(--sp-1); cursor: pointer; }
#settings-popover .settings-hint { margin: var(--sp-1) 0 0 calc(var(--sp-4) + var(--sp-1)); font-size: var(--fs-note); color: var(--ink-faint); }
#reviewer-settings { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
#reviewer-settings .reviewer-label { cursor: default; font-weight: 600; color: var(--ink); }
#reviewer-settings .reviewer-row { display: flex; gap: var(--sp-1); margin-top: var(--sp-1); }
#reviewer-name {
  flex: 1; min-width: 0;
  font: inherit; font-size: var(--fs-ui);
  padding: var(--sp-half) var(--sp-1);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--paper); color: var(--ink);
}
#reviewer-name.invalid { border-color: var(--danger); }
#reviewer-reset {
  font: inherit; font-size: var(--fs-note); white-space: nowrap;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--paper); color: var(--ink-soft); cursor: pointer; padding: var(--sp-half) var(--sp-1);
}
#reviewer-reset:disabled { opacity: 0.5; cursor: default; }
#reviewer-settings .settings-hint { margin-left: 0; }
#export-settings { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
#export-settings .export-label { cursor: default; font-weight: 600; color: var(--ink); }
#export-settings .export-row { display: flex; gap: var(--sp-1); margin-top: var(--sp-1); }
#export-settings .settings-hint { margin-left: 0; }
/* THE RELEASE'S VERSION AT THE GEAR MENU'S FOOT (the reviewer, 2026-10-12: "on the gear menu"; girsa-builder's
   release-version piece fills it): its own section under a rule, as the two above, flush left, the hint's look */
#settings-popover #settings-version { margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--line); }
#export-format, #export-text { flex: 1; min-width: 0; font: inherit; font-size: var(--fs-ui); }
#export-btn {
  font: inherit; font-size: var(--fs-ui); white-space: nowrap; cursor: pointer; padding: var(--sp-half) var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--paper); color: var(--ink);
}
#export-btn:disabled { opacity: 0.5; cursor: default; }
#export-result { max-height: 260px; overflow-y: auto; }
#export-result p { margin: var(--sp-1) 0 var(--sp-half); }
#export-result ul { margin: var(--sp-half) 0 var(--sp-1); padding-left: var(--sp-4); }
#export-result .export-warn { color: var(--warn-ink); font-weight: 600; }
#export-pending-btn,
#apply-btn, #apply-panel button, #apply-top button {
  font: inherit; font-size: var(--fs-ui); white-space: nowrap; cursor: pointer; padding: var(--sp-half) var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--paper); color: var(--ink);
}
#export-pending-btn:disabled, #apply-btn:disabled, #apply-panel button:disabled, #apply-top button:disabled { opacity: 0.5; cursor: default; }
/* APPLY (item 0M3): the same tray section shape as the export */
#apply-settings { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
#apply-settings .export-label { cursor: default; font-weight: 600; color: var(--ink); }
/* THE PANEL'S BUTTONS STAY INSIDE IT (2026-10-08): in the squeezed text pane (1229x673, classic) the panel has about
   178px for a row, and "Cancel" and "Reload the page to see the text" ran past its edge, cut off. A row wraps; a
   label longer than the panel takes a second line. The bar's own Apply button keeps its one line. */
#apply-settings .export-row { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-1); }
#apply-panel button, #apply-top button { white-space: normal; max-width: 100%; text-align: start; }
#apply-settings .settings-hint { margin-left: 0; }
/* APPLY ON THE TEXT PANE'S BAR (the reviewer 2026-10-01: "apply is buried under settings, that is a regularly run
   step. export is rarer" - then "b"). The bar's third column holds the button, which never shrinks, so at a narrow
   window it is still there. The bar's one filled control: the step the reviewer runs most. (The wordmark shared
   this column until 2026-10-12 and gave way first; it is in the index bar now, see #brand.) */
#text-header-end {
  /* NO min-width: 0 here: the column must keep the button's width, so a narrow bar takes the room from the
     titles (they end in an ellipsis) - with it, the column went to nothing and the button lay over the
     English title (the second book at 1229x673, measured 2026-10-01). */
  grid-column: 3; grid-row: 1; justify-self: stretch;
  display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-3);
}
#text-header #apply-btn {
  flex-shrink: 0;
  font: inherit; font-size: var(--fs-note); font-weight: 600; white-space: nowrap; cursor: pointer;
  padding: var(--sp-half) var(--sp-2); border-radius: var(--radius-sm);
  border: 1px solid var(--accent); background: var(--accent); color: var(--paper);
}
#text-header #apply-btn:hover:not(:disabled),
#text-header #apply-btn[aria-expanded="true"] { background: var(--accent-dark); border-color: var(--accent-dark); }
/* While its panel is open the button is off (a second press would start over), but it reads as pressed, not faded. */
#text-header #apply-btn[aria-expanded="true"]:disabled { opacity: 1; cursor: default; }
/* THE COUNT ON IT (the reviewer 2026-10-01: "b with count", then "server call for count"): the rulings Apply would
   write, as a white pill in the blue button - shown only when there is something to apply. */
#apply-btn .apply-count {
  display: inline-block; min-width: 1.5em; margin-inline-start: var(--sp-1); padding: 0 var(--sp-1);
  border-radius: var(--radius-pill); background: var(--paper); color: var(--accent);
  font-size: var(--fs-label); font-weight: 700; line-height: 1.5; text-align: center;
}
#apply-btn .apply-count[hidden] { display: none; }
#text-header #apply-btn:hover:not(:disabled) .apply-count,
#text-header #apply-btn[aria-expanded="true"] .apply-count { color: var(--accent-dark); }
/* ITS PANEL drops from the button: a card under the bar's right end, over the text, scrolling inside itself so it
   fits the pane in both layouts (the stacked layout's text pane is under half the window). */
#apply-popover {
  position: absolute; z-index: var(--z-popover);
  top: calc(var(--pane-header-h) + var(--sp-1)); right: var(--sp-3);
  width: min(380px, calc(100% - 2 * var(--sp-3)));
  max-height: calc(100% - var(--pane-header-h) - var(--sp-4));
  overflow-y: auto;
  padding: var(--sp-3) var(--sp-4);
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-card);
  direction: ltr; font-family: 'Inter', sans-serif; font-size: var(--fs-note); color: var(--ink-soft);
}
#apply-popover #apply-settings { margin-top: 0; padding-top: 0; border-top: 0; }
#apply-popover .settings-hint { margin: var(--sp-1) 0 0; font-size: var(--fs-note); color: var(--ink-faint); }
#apply-panel p { margin: var(--sp-1) 0 var(--sp-half); }
#apply-panel ul { margin: var(--sp-half) 0 var(--sp-1); padding-left: var(--sp-4); max-height: 180px; overflow-y: auto; }
#apply-panel .apply-confirm-label { display: block; cursor: default; margin-top: var(--sp-1); }
#apply-panel .export-warn { color: var(--warn-ink); font-weight: 600; }
#apply-panel .apply-refusal { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--ink); }
/* LOAD A LIST (the word list's L2, defined ahead 2026-10-13): Apply's card, dropped from the list pane's bar over the
   list - the pane (.list-pane) is its positioned parent - and scrolling inside itself. Its field takes pasted lines left
   to right; a refusal is an .export-warn line, as Apply's warnings. */
#load-list-panel {
  position: absolute; z-index: var(--z-popover);
  top: calc(var(--pane-header-h) + var(--sp-1)); inset-inline: var(--sp-3);
  max-height: calc(100% - var(--pane-header-h) - var(--sp-4)); overflow-y: auto;
  padding: var(--sp-3) var(--sp-4);
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-card);
  direction: ltr; font-size: var(--fs-note); color: var(--ink-soft);
}
/* every field the card's full width, a drop-down too (L2's "which column" choice ran past the card at 1229x673); Add to a
   list's fields in a word panel the same */
#load-list-panel textarea, #load-list-panel input[type="text"], #load-list-panel select,
.add-to-list select, .add-to-list input[type="text"] {
  display: block; width: 100%; box-sizing: border-box; margin: var(--sp-1) 0 var(--sp-2);
  padding: var(--sp-1) var(--sp-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: inherit; font-size: var(--fs-ui); color: var(--ink); direction: ltr;
}
#load-list-panel textarea { min-height: 8em; resize: vertical; }
/* the file chooser keeps the browser's own button, at the card's width (its intrinsic width ran past the card at 1229) */
#load-list-panel input[type="file"] {
  display: block; width: 100%; box-sizing: border-box; margin: var(--sp-1) 0 var(--sp-2); font: inherit; font-size: var(--fs-note);
}
#load-list-panel .export-warn { color: var(--warn-ink); font-weight: 600; }
/* SHARING A LIST (the word list's L4, girsa-builder's 538a414b): Save list, Copy link and Make a list of these, one row
   of link buttons at the foot of a word list's controls; a page list's Make a list of these after its rows, where it
   costs the rows no room (at 1229x673 the rows' room is what the legend's lists already take from, Board #35). What
   they answer is a line at the top of the rows: the count line's look, or the warning's. */
#flag-list-panel .list-share { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin-bottom: var(--sp-2); }
#flag-list-panel .list-share .history-toggle, #flag-list-panel .flag-list-summary .history-toggle { margin-top: 0; }
#flag-list-panel .flag-list + .flag-list-summary { margin-top: var(--sp-2); }
#flag-list-panel .list-rows > .export-warn {
  margin: 0 0 var(--sp-2); font-size: var(--fs-note); line-height: 1.5; color: var(--warn-ink); font-weight: 600;
}
/* ADD TO A LIST, at a word panel's foot (L4): a strip under the Save row and the list's steps, as .work-steps is - its
   own padding and rule above, on the paper (it records nothing in the book). Closed, one link; opened, its labels in the
   hints' size above the Load card's fields, and Add as compact as the steps' buttons. */
.side-panel .add-to-list {
  padding: var(--sp-1) var(--sp-5) var(--sp-2); border-top: 1px solid var(--line); background: var(--paper);
  font-size: var(--fs-note); color: var(--ink-soft);
}
.side-panel .add-to-list .add-to-list-open { margin-top: 0; }
.side-panel .add-to-list label { display: block; }
.side-panel .add-to-list label[hidden] { display: none; }
.side-panel .add-to-list .panel-btn { padding: var(--sp-1) var(--sp-3); }
.side-panel .add-to-list-says p { margin: var(--sp-1) 0 0; line-height: 1.5; }
.side-panel .add-to-list-says .export-warn { color: var(--warn-ink); font-weight: 600; }
/* THE APPLY'S OWN NOTICES (polish 2-4: the reviewer's decisions 2-4 of 2026-10-08, taken from the steward's mock-ups 2b,
   3b and 4b; the behaviour girsa-builder's adabb9c, the words girsa-operator's). In #apply-top, under the panel's title,
   so they are in view without scrolling at 1229x673: the run as it goes, the guide's for-your-information notice (D7);
   a failed rebuild or check, the needs-you notice, with its rerun row straight under it and the raw output folded. */
#apply-top .apply-notice, #apply-top .apply-failed-after {
  margin: var(--sp-2) 0 0; padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-sm);
  font-size: var(--fs-note); line-height: 1.5; font-weight: 400; color: var(--ink);
}
#apply-top .apply-notice { background: var(--notice-bg); border: 1px solid var(--notice-line); }
#apply-top .apply-failed-after { background: var(--alert-bg); border: 1px solid var(--danger); }
#apply-top .export-row { margin-top: var(--sp-2); }
#apply-top .apply-output { margin-top: var(--sp-2); }
#apply-top .apply-output summary { font-size: var(--fs-note); color: var(--ink-faint); cursor: pointer; }
#apply-top .apply-output pre {
  margin: var(--sp-1) 0 0; padding: var(--sp-1) var(--sp-2); max-height: 240px; overflow: auto;
  font-size: var(--fs-note); white-space: pre-wrap; overflow-wrap: anywhere; color: var(--ink);
  background: var(--wash); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
/* A SAVE REFUSED, IN THE PANEL'S OWN SAVE ROW (decision 3, mock-up 3b): "Not saved yet: an Apply is running ..." or
   "Not saved: ..." - the needs-you line across the row, above its buttons, at the note size. */
.panel-save-bar .save-line {
  flex-basis: 100%; margin: 0; padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-sm);
  font-size: var(--fs-note); line-height: 1.5; color: var(--ink); background: var(--alert-bg); border: 1px solid var(--danger);
}
#apply-confirm {
  width: 6em; font: inherit; font-size: var(--fs-ui); padding: var(--sp-half) var(--sp-1);
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--paper); color: var(--ink);
}
#apply-settings .test-mode-line { color: var(--notice-ink); }

/* ---------- another session's work (item 0HZ) ---------- */
.stale-banner, #server-notice {
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  direction: ltr;
  color: var(--ink-soft);
  background: var(--notice-bg);
  border: 1px solid var(--notice-line);
  border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-2);
  line-height: 1.5;
  display: flex; align-items: center; gap: var(--sp-2);
}
.stale-banner { margin: var(--sp-1) 0 var(--sp-2); }
#server-notice { margin: var(--sp-2) var(--sp-3) 0; }
/* TEST MODE (item 0M3): the same notice above the text - since D7 (2026-10-01) the same size and colours exactly */
#test-mode-notice {
  font-family: 'Inter', sans-serif; font-size: var(--fs-note); direction: ltr;
  color: var(--ink-soft); background: var(--notice-bg); border: 1px solid var(--notice-line); border-radius: var(--radius-sm);
  padding: var(--sp-1) var(--sp-2); margin: var(--sp-2) var(--sp-3) 0; line-height: 1.5;
  display: flex; align-items: center; gap: var(--sp-2);
}
/* A DEMO COPY (review_server.py --demo; the reviewer's Board Q&A #18, its look Board #38): one line across the whole
   window above the four panes, on every view and in the stacked layout, never hidden. The panes and the side panels
   start under it; the backdrop of an open panel stays under it. */
#demo-notice {
  position: fixed; top: 0; left: 0; right: 0; height: var(--demo-h); z-index: var(--z-pane);
  display: flex; align-items: center; justify-content: center; direction: ltr; cursor: default;
  background: var(--demo-bg); color: var(--demo-ink);
  font-family: 'Inter', sans-serif; font-size: var(--fs-note); font-weight: 600; letter-spacing: .02em; line-height: 1;
}
#demo-notice .demo-text::before {
  content: ''; display: inline-block; width: 7px; height: 7px; vertical-align: middle; margin-right: var(--sp-2);
  border-radius: var(--radius-pill); background: currentColor; opacity: .7;
}
body:has(> #demo-notice:not([hidden])) { padding-top: var(--demo-h); box-sizing: border-box; }
body:has(> #demo-notice:not([hidden])) .side-panel { top: var(--demo-h); }
body:has(> #demo-notice:not([hidden])) #settings-popover { max-height: calc(100vh - 150px - var(--demo-h)); }
#test-mode-notice .stale-text { flex: 1; }
#test-mode-notice button {
  font: inherit; white-space: nowrap; cursor: pointer; padding: var(--sp-half) var(--sp-2); font-weight: 600;
  border: 1px solid var(--notice-line); border-radius: var(--radius-sm); background: var(--paper); color: var(--ink);
}
.stale-banner .stale-text, #server-notice .stale-text { flex: 1; }
.stale-banner button, #server-notice button {
  font: inherit; font-size: var(--fs-ui); font-weight: 600; white-space: nowrap;
  border: 1px solid var(--notice-line); border-radius: var(--radius-sm);
  background: var(--paper); color: var(--ink); cursor: pointer; padding: var(--sp-half) var(--sp-2);
}

/* ---------- the word list behind a legend count ---------- */
#flag-list-panel .flag-list-summary {
  margin: 0 0 var(--sp-2); font-size: var(--fs-note); color: var(--ink-faint); line-height: 1.5;
}
/* WHAT THE MODE MEANS, under the count (the reviewer, 2026-10-09: "(a) A line under the count (Recommended)", from
   mock-ups of today, this line and a link that opens it - the meaning was said only in the legend row's hover, which
   stays): the legend row's own sentence, quieter than the count line above it. */
#flag-list-panel .flag-list-why {
  margin: calc(-1 * var(--sp-1)) 0 var(--sp-2); font-size: var(--fs-note); color: var(--ink-faint); font-style: italic;
  line-height: 1.5;
}
#flag-list-panel .flag-list-empty { font-size: var(--fs-ui); color: var(--ink-faint); }
#flag-list-panel .flag-list { display: flex; flex-direction: column; gap: var(--sp-half); direction: ltr; }
/* A ROW THAT DOES NOT FIT WRAPS; NOTHING IS CUT (reviewer 2026-10-01, entry 41 w104 in the rulings list: "right side of
   ruling is truncated"). One line of pieces none of which could shrink - number, reference, status, marks, the word,
   "to", the chosen text, the copy button - ran past the panel: on 2026-10-01 142 of Yad Malachi's 1,003 recorded
   rulings at the reviewer's window (171 at a laptop at 150%), and 4 of the second book's open rows (11). The row now
   continues on a second line; a long chosen phrase wraps inside itself. */
.flag-list-item {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-half) var(--sp-2);
  padding: var(--sp-1) var(--sp-2);
  /* A hanging indent: a second line starts under the reference, not under the row's number (whose own negative
     margin, below, takes it back into this space). The indent is the number's slot, named so the copy button can
     fill it (registered below as a length, so its `ch` is the row's, whatever size the button's icon is). */
  --list-n-slot: calc(8px + 3.5ch + 10px);
  padding-inline-start: var(--list-n-slot);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
  font-size: var(--fs-ui);
  border: 1px solid transparent;
}
.flag-list-item:hover { background: var(--row-hover); border-color: var(--row-hover-line); }
/* The reference may break, between its words, only when it alone is wider than the row (a flex row moves an item to
   a new line before it squeezes one): in the 300px pane, "Klal 167 (...) · #1235, now #1234" in the panels' face ran
   15px past the row's box when it was kept on one line (2026-10-05). */
.flag-list-ref { font-variant-numeric: tabular-nums; opacity: 0.8; }
/* The row's number in the list as shown - the work-through bar's "N of M" (2026-09-30). */
/* F2 (the reviewer, 2026-10-08, from mock-ups at both sizes: "F1 ... F5" as recommended): the number in the decided label grey at full strength, 4.8:1 - faded to .55 it was 3.7:1. */
.flag-list-n { font-variant-numeric: tabular-nums; min-width: 3.5ch; text-align: end; color: var(--ink-faint); flex-shrink: 0;
               margin-inline-start: calc(-3.5ch - 10px); }
/* In the bar's own list: a row ruled on since the list was opened. It keeps its place and number. */
.flag-list-item.wb-done { opacity: 0.5; }
/* ONE HEADING STYLE, STICKY (W3 S2, decided 2026-10-04 - "w3 fine"): a group's heading is its name, its count at the
   heading's end and a rule under it, in every order. It sticks to the top of the rows while its own rows scroll past
   (each group is a section, so the next group's heading takes its place), and so the group being read is always
   named. A change inside a kind ("by change") is the second level: indented, a rule at its start, sticking under its
   kind's heading - which is one line high for that reason (a long kind's name ends in an ellipsis; its count never). */
#flag-list-panel { --kind-head-h: 30px; }
#flag-list-panel .flag-list-group {
  display: flex; align-items: baseline; gap: var(--sp-2);
  position: sticky; top: 0; z-index: var(--z-lift);
  margin: var(--sp-3) 0 var(--sp-half); padding: var(--sp-1) var(--sp-2); background: var(--paper);
  font-size: var(--fs-note); font-weight: 600;
  border-bottom: 1px solid var(--group-line);
}
#flag-list-panel .flag-list-section:first-child > .flag-list-group { margin-top: 0; }
#flag-list-panel .flag-list-group-name { min-width: 0; }
#flag-list-panel .flag-list-group b {
  /* F3 (2026-10-08): the decided label grey at full strength, 4.8:1 - faded to .6 it was 4.4:1 */
  margin-inline-start: auto; font-weight: 400; color: var(--ink-faint); font-variant-numeric: tabular-nums; flex-shrink: 0;
}
#flag-list-panel .flag-list-group bdi { font-size: var(--fs-title); }
/* "By change": the kind a run of change groups belongs to, with the filter's count (0MJ); its changes sit under it. */
#flag-list-panel .flag-list-group.flag-list-kind {
  box-sizing: border-box; height: var(--kind-head-h); align-items: center; margin-top: var(--sp-4);
  font-size: var(--fs-ui); font-weight: 700; border-bottom: 2px solid var(--group-line-strong);
  white-space: nowrap;
}
#flag-list-panel .flag-list-kind .flag-list-group-name { overflow: hidden; text-overflow: ellipsis; }
#flag-list-panel .flag-list-kind-section .flag-list-section > .flag-list-group {
  top: var(--kind-head-h); margin: var(--sp-1) 0 var(--sp-half) var(--sp-4);
  border-inline-start: 2px solid var(--line);
}
.flag-list-order-label { font-size: var(--fs-label); align-self: center; opacity: 0.7; }

/* THE LIST'S CONTROLS, FIXED ABOVE ITS ROWS (W3 S1, and D2 - the reviewer 2026-10-04: "let us have the order by line
   permanently under the top bar above the current list"): Scope, Order, Filter, one row each, in that order in every
   mode, their chips starting at one edge; a mode with nothing to filter says "none". Only the rows scroll - the
   body is a column of the two, and the rows are its scroller. */
#flag-list-panel-body { display: flex; flex-direction: column; overflow: hidden; padding: 0; }
#flag-list-panel-body > p { padding: var(--sp-5) var(--sp-4); margin: 0; }
#flag-list-panel .list-controls {
  flex: none; padding: var(--sp-3) var(--sp-4) var(--sp-1);
  border-bottom: 1px solid var(--line);
}
#flag-list-panel .list-controls .rec-chips { margin-bottom: var(--sp-2); }
#flag-list-panel .list-controls .flag-list-order-label { min-width: 3.6em; }
/* A CHIP THAT WRAPS HANGS UNDER THE FIRST CHIP, not under the row's label (2026-10-07): at 1229x673 the second book's
   "by change" (after the order chip became "by shoresh", 126b1e3) and its Scope row's entry chip went to a second line
   that began under "Order:" and "Scope:", so the label no longer stood beside its chips - as the Filter row's sets
   already hang (.flag-list-filter-sets). The row is indented by the label's column and its gap; the label is drawn
   back into it. The label is --fs-label, so its 3.6em is 3.6 of that token. */
#flag-list-panel .list-controls .rec-chips { --label-col: calc(3.6 * var(--fs-label) + var(--sp-1)); padding-inline-start: var(--label-col); }
#flag-list-panel .list-controls .rec-chips > .flag-list-order-label { margin-inline-start: calc(-1 * var(--label-col)); }
#flag-list-panel .flag-list-filter { display: flex; align-items: flex-start; gap: var(--sp-1); }
#flag-list-panel .flag-list-filter > .flag-list-order-label { align-self: auto; padding-top: var(--sp-1); }
#flag-list-panel .flag-list-filter-sets { flex: 1; min-width: 0; }
/* Folded (D3): only the chip in force shows, one line with the button that opens the rest; the "all" chip of the
   second set (the kinds, after the engines' agreement) is the same filter as the first's, so it shows once. */
#flag-list-panel .flag-list-filter.folded .flag-list-filter-sets {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); margin-bottom: var(--sp-2);
}
#flag-list-panel .flag-list-filter.folded .rec-chips { display: contents; }
#flag-list-panel .flag-list-filter.folded .rec-chip:not(.rec-chip-on),
#flag-list-panel .flag-list-filter.folded .rec-chips ~ .rec-chips .rec-chip[data-status="all"] { display: none; }
#flag-list-panel .filter-fold {
  margin: 0 0 var(--sp-2); padding: 0; border: 0; background: none; font-size: var(--fs-note);
}
#flag-list-panel .flag-list-filter.folded .filter-fold { margin-bottom: 0; }
#flag-list-panel .flag-list-none {
  display: inline-block; margin-bottom: var(--sp-2); padding-top: var(--sp-half);
  font-size: var(--fs-note); color: var(--ink-faint);
}
/* no padding above the rows: a heading stuck at the top would show the rows passing through the gap above it */
#flag-list-panel .list-rows { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 var(--sp-4) var(--sp-5); }
#flag-list-panel .list-rows > :first-child { margin-top: var(--sp-3); }
.flag-list-item.wb-done .flag-list-n::after { content: " \2713"; }
#flag-list-panel .wb-note { font-weight: 600; }
.flag-list-word {
  direction: rtl; unicode-bidi: isolate;
  font-family: 'Frank Ruhl Libre', 'David', serif;
  font-size: var(--fs-word);
  margin-inline-start: auto;
  /* a word longer than the row (the list pane is 300px at a laptop since W1 (a), 2026-10-04) breaks inside itself
     rather than run past the pane - the last resort, after the row's own wrapping (79ef17e) */
  min-width: 0; overflow-wrap: anywhere;
}
.flag-list-nul { margin-inline-start: auto; font-style: italic; opacity: 0.55; font-size: var(--fs-note); }
/* Hidden until the pointer has HELD the row (FLAG_LIST_DWELL_MS in app.js); revealing it must not reflow the row out
   from under the pointer that is about to click it.
   IN THE NUMBER'S PLACE (the reviewer, 2026-10-10, Board #5, from mock-ups at both sizes): the button kept a box of its
   own at the row's end, so a row whose reference and word fit took a second line for an invisible button - on the
   second book at 1229x673, 906 of 928 rows of "Needs a ruling". Drawn over the number's slot instead, out of the row's
   flow, it takes no room; the number hides while the row is held. With it (the same answer: "copy icon should be
   bigger and centered, if it is one line center on that line, if two place between the two"): the button fills the
   slot from the row's top to its foot and centres its icon in it, so on a one-line row the icon sits on the line and
   on a two-line row between the lines; the icon at --list-copy-size. */
@property --list-n-slot { syntax: '<length>'; inherits: true; initial-value: 0px; }
.flag-list-item { position: relative; }
.flag-list-item .flag-list-copy {
  visibility: hidden; position: absolute; inset-block: 0; inset-inline-start: 0; width: var(--list-n-slot);
  display: flex; align-items: center; justify-content: center; padding: 0;
  font-size: var(--list-copy-size);
}
.flag-list-item.dwell .flag-list-copy { visibility: visible; }
.flag-list-item.dwell .flag-list-n { visibility: hidden; }
/* A ROW NOT CARRIED (option C, 2026-10-07; the steward's mock-up): its words follow the entry's name - the word, and
   "kept as it stood", "a flag:", "heading:", not pushed to the row's end as a list row's word and note are - and the
   reason is a quiet line of its own under them. */
.not-carried-item .flag-list-word, .not-carried-item .flag-list-nul { margin-inline-start: 0; }
.not-carried-item .not-carried-why { flex-basis: 100%; font-size: var(--fs-note); font-style: italic; color: var(--ink-faint); }
/* A RECORDED ROW UNDER NO NUMBER (W2, the reviewer's D4-a of 2026-10-08: rulings the view cannot place, listed by their
   words after the entry's numbered rows): its number slot kept empty so the references line up, its words after the
   reference as a not-carried row's are, and - on this row or any recorded row that has one - its own why as a quiet
   line under it (D2-a's "kept" note too). A word list's row not found (the word list's L2) is such a row too. */
.unnumbered-item .flag-list-word, .unnumbered-item .flag-list-nul { margin-inline-start: 0; }
.recorded-item .rec-why, .unnumbered-item .rec-why {
  flex-basis: 100%; font-size: var(--fs-note); font-style: italic; color: var(--ink-faint);
}

/* ---------- transient status toast ---------- */
/* OVER THE SCAN'S FOOT, just above the zoom and page buttons (2026-10-05). It sat at the window's bottom centre,
   clear of the legend and the side panels of its day; since the list became the centre column (W1) and the steps
   moved to the open panel's foot (W5), that spot is the panel's Save row or its Previous (measured at 1229x673 and
   1864x1033, classic layout). The scan's foot holds nothing a click needs but the cluster it sits above, and a word
   clicked is centred on the scan, not at its foot. pointer-events:none - it must never swallow the next click, the
   same reason #tooltip does not. */
#toast {
  position: absolute;
  bottom: 56px;                         /* the cluster's 12px inset, its 32px height, and 12px between */
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-popover);            /* above the scan and its cluster (--z-control), inside the scan pane */
  width: max-content;
  max-width: min(560px, calc(100% - 2 * var(--sp-4)));
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--radius);
  background: var(--toast-bg);
  color: var(--on-dark);
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-ui);
  line-height: 1.4;
  direction: ltr;
  text-align: center;
  box-shadow: var(--shadow-toast);
  pointer-events: none;
}
#toast.toast-fail { background: var(--toast-fail-bg); }
/* A KEPT MESSAGE'S CLOSE BUTTON (the reviewer 2026-10-05: "how about a dismissal"; girsa-operator's e4199c0 keeps a
   long message until it is closed). In the toast's top end corner, in room the toast keeps for it, so it never wraps
   under the text; the toast lets clicks through everywhere else (pointer-events above), the button takes them. Light
   on the dark toast and on the failure's red alike. */
#toast:has(.toast-close) { padding-inline-end: calc(16px + 22px + var(--sp-1)); text-align: start; text-wrap: pretty; }
#toast .toast-close {
  position: absolute; top: 6px; inset-inline-end: 6px;
  width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: var(--radius-sm); background: transparent;
  color: var(--on-dark-soft); font-size: var(--fs-title); line-height: 1;
  cursor: pointer; pointer-events: auto;
}
#toast .toast-close:hover { background: var(--on-dark-rule); }
#toast .toast-close:focus-visible { outline: 2px solid var(--on-dark-soft); outline-offset: 1px; }

/* ---------- side panels (candidate override / klal flag) ---------- */
#overlay-backdrop {
  position: fixed; inset: 0;
  background: var(--backdrop);
  display: none;
  z-index: var(--z-backdrop);
}
#overlay-backdrop.open { display: block; }

.side-panel {
  position: fixed;
  /* DOCKED BESIDE THE NAV PANE, NOT OVER IT. At `right: 0` this 420px panel
     covered the 380px nav pane completely - measured, 380px of overlap, 100% of
     the pane - so while any decision panel was open the whole klal list was
     unclickable: the click landed on the panel. Reported 2026-08-31 as "clicking
     on klal 12 in the correction pane does not jump the text pane to that klal",
     and it was never about klal 12; it was every klal, whenever a panel was
     open. The panel now overlays the TEXT pane, which the reviewer is not
     navigating from. */
  top: 0; bottom: 0; right: var(--nav-w);
  width: var(--list-w);                 /* over the list pane, exactly (W1 (a)) */
  max-width: 92vw;
  background: var(--paper);
  box-shadow: var(--shadow-panel);
  z-index: var(--z-panel);
  display: flex;
  flex-direction: column;
  font-family: 'Inter', sans-serif;
  direction: ltr;
  transition: transform .18s ease;
}
/* Off-screen must clear the nav pane the panel now sits beside, or a closed
   panel parks on top of the list it was moved off. */
.side-panel { transform: translateX(calc(100% + var(--nav-w))); }
.side-panel.open { transform: translateX(0); }
/* NO SHADOW WHILE CLOSED (audit B1, 2026-09-30). A closed panel parks with its left edge on the window's right edge,
   and its shadow - thrown 8px left, 32px blur - fell back into the window: seven closed panels deep, the index's
   last 40px shaded to near black (the edge pixel measured (64,66,68) against #e2e8f0), on every page. */
.side-panel:not(.open) { box-shadow: none; }
.panel-head {
  padding: var(--sp-4) var(--sp-5);
  background: var(--accent-dark);
  color: var(--on-fill);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.panel-title { font-size: var(--fs-title); font-weight: 600; }
.panel-close {
  background: none; border: none; color: var(--on-fill);
  font-size: var(--fs-close); line-height: 1; cursor: pointer; opacity: 0.85;
  padding: 0 var(--sp-1);
}
.panel-close:hover { opacity: 1; }
.panel-body { flex: 1; overflow-y: auto; padding: var(--sp-5); }

.panel-section { margin-bottom: var(--sp-5); }
/* SMALL PIECES EVERY PANEL SHARES (style guide B4 and D5, 2026-10-01). A template writes these classes, never a style:
   .hint, a grey line saying what the control above or below it means (it was `font-size:12px;color:var(--ink-faint)`
   written into the templates some 25 times, with seven different margins); .note, the same size in ink; .faint, grey
   alone; and spacing on the scale - .gap-t 4px above, .gap-b 8px below, .tuck pulled up 4px under its label. */
.hint { font-size: var(--fs-note); color: var(--ink-faint); }
.note { font-size: var(--fs-note); }
.faint { color: var(--ink-faint); }
.gap-t { margin-top: var(--sp-1); }
.gap-b { margin-bottom: var(--sp-2); }
.tuck { margin-top: calc(-1 * var(--sp-1)); }
.aside { font-style: italic; }
.ai-flag-reason { white-space: pre-wrap; }
/* The scan pane's notice for an entry with no scan page (showPage), and the text pane's for an address naming an entry
   the book lacks (showNotInBook, girsa-builder's 550f24f6; bare until this rule): one card, so both read as the page
   speaking. Their words are English, so they run left to right: under `direction: rtl` a wrapped sentence put its full
   stop at the start of its last line (the steward, 2026-10-12). No `display` here - each keeps its `hidden`. */
#scan-notice, #entry-not-in-book {
  padding: var(--sp-6) var(--sp-5); text-align: center; color: var(--ink-faint); font-family: 'Inter', sans-serif;
  font-size: var(--fs-ui); line-height: 1.6; background: var(--paper); border-radius: var(--radius);
  margin: var(--sp-6) auto; max-width: min(320px, calc(100% - 2 * var(--sp-4))); box-shadow: var(--shadow-card);
  direction: ltr; text-wrap: balance;   /* inset in a narrow pane (the text pane is 234px at 1229x673); no lone "to 4." */
}
.scan-notice-title { color: var(--accent); font-size: var(--fs-title); display: block; margin-bottom: var(--sp-2); }
.scan-notice-body { color: var(--ink-soft); display: block; }
.panel-label {
  font-size: var(--fs-label); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-faint); margin-bottom: var(--sp-2);
}
.panel-word-context {
  font-family: 'Frank Ruhl Libre', serif;
  direction: rtl; text-align: right;
  font-size: var(--fs-word); color: var(--ink-soft);
  background: var(--wash); border-radius: var(--radius-sm);
  padding: var(--sp-3); margin-bottom: var(--sp-4);
  line-height: 1.9;
}
.panel-word-context b { color: var(--ink); background: var(--word-mark-wash); padding: 0 var(--sp-half); border-radius: var(--radius-mark); }
/* The box's English fallback ("The words around this place are not available.") reads as English: under the box's rtl
   serif it showed ".are not available" on its second line at 1229x673 (the steward, 2026-10-12, the second book's
   212 w479). */
.panel-word-context .faint {
  display: block; direction: ltr; text-align: left; font-family: 'Inter', sans-serif; font-size: var(--fs-ui); line-height: 1.6;
}

.disputed-option, .candidate-option {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  margin-bottom: var(--sp-2);
  cursor: pointer;
  transition: all .1s ease;
}
.disputed-option:hover, .candidate-option:hover { border-color: var(--accent); background: var(--accent-wash); }
.disputed-option.active, .candidate-option.active {
  border-color: var(--accent);
  background: var(--accent-wash);
  box-shadow: 0 0 0 1px var(--accent);
}
.disputed-option input[type=radio], .candidate-option input[type=radio] { margin-top: var(--sp-half); flex-shrink: 0; }
.disputed-option .co-body, .candidate-option .co-body { flex: 1; min-width: 0; }
.disputed-option .co-label, .candidate-option .co-label { font-size: var(--fs-label); font-weight: 600; color: var(--ink-faint); text-transform: uppercase; letter-spacing: 0.03em; }
.disputed-option .co-text, .candidate-option .co-text {
  font-family: 'Frank Ruhl Libre', serif; direction: rtl; text-align: right;
  font-size: var(--fs-word); color: var(--ink); margin-top: var(--sp-half);
}
.disputed-option .co-meta, .candidate-option .co-meta { font-size: var(--fs-note); color: var(--ink-faint); margin-top: var(--sp-half); }
/* WHAT A SAVE OF THE SCAN'S READING DOES TO THE EDITOR'S WORD (finding 1, option C, the reviewer 2026-10-05): one
   English sentence under the option. The note look (a hint's size and grey); where a Save would REMOVE his points or
   marks, the guide's amber as text (D2, --pending-ink, 5.5:1) - a caution, not a "needs you" red: the Save is still
   the reviewer's to make. Where only the letters change and his marks are kept, the plain note. */
.disputed-option .co-note, .candidate-option .co-note {
  font-size: var(--fs-note); line-height: 1.4; color: var(--ink-faint); margin-top: var(--sp-1);
}
.candidate-option .co-note.co-note-warn { color: var(--pending-ink); }
.disputed-option.active .co-label, .candidate-option.active .co-label { color: var(--accent); }

textarea, input[type=text] {
  width: 100%;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-ui);
  font-family: inherit;
  resize: vertical;
}
textarea:focus, input[type=text]:focus { outline: none; border-color: var(--accent); }
textarea.custom-text, input.custom-text {
  font-family: 'Frank Ruhl Libre', serif; direction: rtl; text-align: right; font-size: var(--fs-word);
}
/* ITS PLACEHOLDER IS ENGLISH (the steward, 2026-10-12): in the 17px serif "Type the correct reading…" ran 195px in the
   witness panel's 167px box at 1229x673, and under rtl its "…" stood at the left end - both ends cut. The interface's
   font and size, and its own direction. */
textarea.custom-text::placeholder, input.custom-text::placeholder {
  font-family: 'Inter', sans-serif; font-size: var(--fs-ui); unicode-bidi: plaintext;   /* `direction` is not applied here */
}

.panel-btn {
  background: var(--accent);
  color: var(--on-fill);
  border: none;
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-ui);
  font-weight: 600;
  cursor: pointer;
  transition: background .1s ease;
}
.panel-btn:hover { background: var(--accent-dark); }
.panel-btn:disabled { opacity: 0.5; cursor: default; }
.panel-btn.secondary { background: transparent; color: var(--accent); border: 1.5px solid var(--accent); }
.panel-btn.secondary:hover { background: var(--accent-wash); }
.panel-btn.secondary.armed { color: var(--danger); border-color: var(--danger); background: var(--danger-wash); }

/* THE SUGGESTION BOX in the word panel (openManualCorrectionPanel): "Suggested replacement" and "Suggested: keep the
   current text". FIXED 2026-09-30 (item 0MI; the reviewer handed it to the UI steward): both boxes were inline
   styles from a dark theme - the word WHITE on a 13% blue wash over the paper (about 1.2:1, nearly invisible) and
   the label light blue (#63b3ed, about 1.9:1) - first written 2026-08-20, the second box copied from it 2026-09-30.
   Since the correction box opens empty (0MJ) this box is the only place the suggested word shows. Now the page's
   tokens: the accent wash and border, the label in the panel head's dark blue, the word in the text's ink and face
   (as a dispute option's `.co-text`). Its button is a SECONDARY button: it only fills the correction box, and a
   second solid blue button beside Save, in another blue (#3182ce, not --accent), is what the reviewer took for
   the Save on 2026-09-30 ("the blue button ... didn't do anything"). */
.panel-section.suggestion-box {
  background: var(--accent-wash);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
}
.suggestion-head { font-size: var(--fs-ui); font-weight: 600; color: var(--accent-dark); }
.suggestion-word { font-family: 'Frank Ruhl Libre', serif; font-size: var(--fs-word); color: var(--ink); }
.suggestion-note { font-size: var(--fs-note); color: var(--ink-soft); margin-top: var(--sp-half); }
.suggestion-box .panel-btn { margin-top: var(--sp-2); }

/* THE LINK BUTTON (STYLE.md B4). On a <button> the browser's own border, fill and padding are taken off here, once: the
   word list's L4 wrote five such buttons and each drew as a grey box (2026-10-13), where the earlier three took them
   off one rule at a time (.filter-fold, .legend-fold, Load a list). A <span> has none of them to lose. */
.history-toggle {
  font-size: var(--fs-note); color: var(--accent); cursor: pointer; text-decoration: underline;
  margin-top: var(--sp-2); display: inline-block;
  padding: 0; border: 0; background: none; font-family: inherit;
}
.history-list { margin-top: var(--sp-3); border-top: 1px solid var(--line); padding-top: var(--sp-3); }
.history-item {
  font-size: var(--fs-note); padding: var(--sp-2) 0; border-bottom: 1px dashed var(--line);
}
.history-item:last-child { border-bottom: none; }
.history-item .h-ts { color: var(--ink-faint); font-size: var(--fs-label); }
.history-item .h-text { direction: rtl; text-align: right; font-family: 'Frank Ruhl Libre', serif; font-size: var(--fs-ui); margin: var(--sp-half) 0; }
.history-item .h-note { color: var(--ink-soft); font-style: italic; }
/* A MACHINE ACTOR'S TAG IN A HOVER on plain text (girsa-operator's rule for machine actors' names, girsa-builder's
   0a5c8fb3, 2026-10-11): the history row's "recorded by X (not a person)" line, the heading history's name and the
   unlinked row's "closed by X" carry "recorded as <tag>" in a title. Hover-only text shows the help cursor, as the
   machine mark, the stale mark and the cross-edition mark do - else nothing says a hover is there. */
.h-note[title], .history-item span[title], .work-row-unlinked span[title] { cursor: help; }

.checkbox-row { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-4); font-size: var(--fs-ui); }
.checkbox-row input { width: 16px; height: 16px; }

/* The bar the Save button lives in, pinned to the bottom of the scrolling
   panel body. `position: sticky` works here because .panel-body is the element
   with `overflow-y: auto`, so this sticks to the bottom of ITS scroll viewport
   rather than the window's. Opaque background and a rule above it because the
   option list scrolls UNDER this - a transparent bar would show text through
   the button. */
.panel-save-bar {
  position: sticky;
  /* STUCK, it sits on the true bottom edge too (audit, 2026-09-30). At `bottom: 0` a stuck row stopped where the body's
     own bottom padding begins - 24px above the edge - and the panel's content scrolled visibly through that strip
     under the Save button (measured at 1280x650: the row's bottom at 626 of 650); the work-through bar floated over
     the same strip. The offset is the body's padding, as the margin below is. */
  bottom: calc(-1 * var(--sp-5));
  margin-top: var(--sp-4);
  /* Cancels .panel-body's own bottom padding so the bar reaches the true
     bottom edge instead of floating above a strip of paper. */
  margin-bottom: calc(-1 * var(--sp-5));
  padding: var(--sp-3) var(--sp-5);
  margin-inline: calc(-1 * var(--sp-5));
  background: var(--paper);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;            /* every panel's actions live here since D6 (2026-10-01); the word panel has five */
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  z-index: var(--z-lift);
}
/* The heading panel's word-correction buttons, shown when a word is chosen: they join the row's own line. */
.panel-save-bar #title-buttons { display: contents; }

/* THE "SAVED" MARK. Two rulings meet here (STYLE.md B6: the later decides the shape, the earlier's purpose stays).
   2026-08-21 (the reviewer's request): the confirmation must be unmistakable - it was 12px inline text, easy to miss
   just before the panel closed - so it became a full-width green banner, held on screen for
   DECISION_SAVED_CLOSE_DELAY_MS (app.js) before the panel closes. 2026-09-04 (below) replaced the banner with this
   inline mark beside the Save button; it keeps the banner's purpose by its solid green, bold white lettering and the
   same hold. (This comment once sat above .panel-save-bar and still described the banner, until 2026-10-06.) */
.save-status {
  /* INLINE, not block. Reviewer, 2026-09-04: "too much whitespace below the
     save." This was `display: block` with `margin-top: 12px`, and it is hidden
     with `visibility`/`opacity` rather than `display: none` - which means it
     kept its box whether or not it was showing, reserving a permanent ~50px
     strip of nothing under every Save button in all five panels. Inline in the
     flex bar above, it costs no vertical space at all and still appears in
     place without shifting anything when a save lands. */
  display: inline-block;
  margin-top: 0;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  background: var(--success);
  color: var(--on-fill);
  font-size: var(--fs-ui);
  font-weight: 700;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .15s ease, transform .15s ease;
}
.save-status.show { opacity: 1; visibility: visible; transform: translateY(0); }

/* A word arrived at by deep link (#klal=N&word=M). Transient and additive: the
   word's own state class keeps owning its colour, this only says "here it is"
   for a few seconds. ADDED 2026-08-26 with the deep-link feature. */
/* THE CURSOR MARKER - "where you left off", not "here it is".
   ADDED 2026-09-08 (item 0DL). snapToLastVisitedWord() first reused
   .routed-word below, which is the DEEP-LINK ring: 3px solid gold plus a gold
   background wash and a pulse, designed to shout at someone who has just
   arrived from a pasted URL and does not know where to look. Left on the word
   after every dismissal it reads as a state - the reviewer reported "clicking
   on any word then clicking away leaves a gold box around the word" - and gold
   already means `--pending` everywhere else on this screen.
   A cursor should be findable and otherwise silent: one thin neutral outline,
   no fill, no animation, nothing that competes with a word's real state
   colour. */
.cursor-word {
  outline: 2px solid var(--ink-faint);
  outline-offset: 2px;
  border-radius: var(--radius-mark);
}
/* THE WORD ITS PANEL IS OPEN FOR - the text's partner to the scan's ring, only while the panel is open (the reviewer's
   point 6, 2026-10-09: "(b) Blue ring (Recommended)", from mock-ups of a ring in the word's state colour, one blue ring
   and a blue fill - scratch/shots/open-word/ in the steward's worktree). The accent blue, which no word state uses: a
   fill would read as the editor's "info" formatting, and a state-coloured ring on an amber word as the link's gold.
   The cursor's shape, so closing the panel only turns the ring grey. Before .routed-word, which wins on a word a link
   has just reached. */
.open-word {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-mark);
}

.routed-word {
  outline: 3px solid var(--place);
  outline-offset: 2px;
  border-radius: var(--radius-mark);
  background: var(--routed-wash);
  animation: routed-pulse 1s ease-in-out 2;
}
@keyframes routed-pulse {
  0%, 100% { outline-color: var(--pending); }
  50%      { outline-color: var(--routed-pulse); }
}

/* Copy-the-reference control in a correction panel's klal/word header.
   ADDED 2026-08-26: the header doubles as a handle, copying both the readable
   reference and the deep link so a finding can be pasted anywhere. */
/* The klal/word context header. Bigger than a plain .panel-label (2026-08-26,
   reviewer): it is the line a reviewer reads to know WHERE they are, and it now
   carries the copy control, so it is a heading rather than a caption. */
.panel-label-copy {
  display: flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-ui);
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}
.copy-ref {
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: var(--fs-note);
  line-height: 1;
  padding: var(--sp-half) var(--sp-1);
  border-radius: var(--radius-sm);
  opacity: 0.55;
  transition: opacity 0.12s, background 0.12s;
}
.copy-ref:hover { opacity: 1; background: var(--on-dark-hover); }
.copy-ref.copied { opacity: 1; color: var(--success); }
.copy-ref.copy-failed { opacity: 1; color: var(--danger); }

/* Hover card on every word in the text pane. Distinct from #tooltip, which sets
   pointer-events:none so it can never swallow a click - this one CONTAINS a
   button, so it must be hoverable and clickable. ADDED 2026-08-26. */
#word-card {
  position: fixed;
  z-index: var(--z-hover-card);
  /* Lighter and more transparent (2026-08-26, reviewer). This box follows the
     pointer across text the reviewer is reading, so it should sit over the page
     rather than block it. The backdrop blur is what keeps it legible at this
     alpha - without it, Hebrew text showing through the panel is unreadable. */
  background: var(--card-glass);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--on-glass);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius);
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-note);
  direction: ltr;
  box-shadow: var(--shadow-float);
  /* THE BODY LETS THE POINTER THROUGH. Reviewer, 2026-09-04: "when i move my
     cursor to click on a word behind a hover pane it should move out of the way
     so i dont have to click blindly."
     This card is placed over the running text by construction - it sits above
     the word it describes, which means it covers the LINE ABOVE, and those are
     words the reviewer clicks. While it swallowed pointer events the only way
     to reach a covered word was to move off the text entirely, wait 260ms for
     the card to time out, and come back to nothing.
     Pass-through instead: the mouse reaches the word underneath, that word's
     own mouseover fires, and the card re-anchors to it - so moving toward a
     covered word makes the card follow the cursor away from it. The head keeps
     `pointer-events: auto` below, because it carries the copy button and a
     button you cannot click is not a button. */
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  max-width: 380px;
}
/* One box, two shapes. A PLAIN word gets a single compact row (reference +
   copy). A flagged word gets the same row plus the full detail block that used
   to live in a SECOND floating box beside it - the reviewer's point that a
   disputed word does not need both. */
#word-card { flex-direction: column; align-items: stretch; gap: 0; }
/* Drawn above its word, the card puts its head strip - the one part that takes the
   pointer, with the copy button - at the BOTTOM, flush with the word (app.js
   showWordCard, 2026-09-24). IN EFFECT SINCE 2026-10-02: until then the script showed the
   card with an inline `display: block`, which overrode this flex column, so a flagged
   word's card kept its strip at the far edge; the card is shown by the `hidden` attribute
   now (style guide B2). The gap is 0 because the one above (--sp-1) is the one-row card's, and the
   detail's hairline moves to its side next to the strip. */
#word-card.wc-above { flex-direction: column-reverse; }
#word-card.wc-above .wc-detail {
  margin-top: 0; padding-top: 0; border-top: 0;
  margin-bottom: var(--sp-1); padding-bottom: var(--sp-1); border-bottom: 1px solid var(--on-dark-rule);
}
#word-card.wc-rich { max-width: 420px; }
#word-card .wc-head { display: flex; align-items: center; gap: var(--sp-1); }
/* THE COPY BUTTON IS THE ONLY LIVE TARGET IN THE CARD, and nothing larger.
   Making the whole head interactive was not enough: for a plain word the card
   IS its head - one line, no detail body - so the head covered the text and the
   pointer still could not get through. Only the button takes events now, which
   keeps it clickable while every other pixel of the card lets the reviewer
   reach the word underneath. */
#word-card .copy-ref { pointer-events: auto; }
#word-card .wc-ref { font-weight: 500; white-space: nowrap; }
#word-card .wc-status {
  font-size: var(--fs-label); color: var(--on-dark-soft); white-space: nowrap;
  padding-left: var(--sp-1); border-left: 1px solid var(--on-dark-line);
}
#word-card .wc-head .copy-ref { margin-inline-start: auto; }
#word-card .wc-detail {
  margin-top: var(--sp-1); padding-top: var(--sp-1);
  border-top: 1px solid var(--on-dark-rule);
  color: var(--on-dark-soft);
  font-size: var(--fs-note);
  max-height: 9em;
  overflow: hidden;
}
#word-card .wc-detail .t-docai { display: block; margin-bottom: var(--sp-1); }
#word-card .wc-detail .t-conf { display: block; color: var(--on-dark-soft); font-size: var(--fs-label); }
#word-card .wc-detail .t-hint { display: block; color: var(--on-dark-link); font-size: var(--fs-label); margin-top: var(--sp-1); }
#word-card .wc-detail bdi { direction: rtl; unicode-bidi: isolate; }
#word-card .copy-ref { color: var(--on-dark); opacity: 0.75; }
#word-card .copy-ref:hover { background: var(--on-dark-hover-strong); opacity: 1; }


/* ---- The heading panel (item 39 / 0BC, 2026-09-03) ----------------------
   A klal's `title` is corpus text stored separately from its body, and until
   0BC nothing on screen could correct one - the five repairs of 2026-08-31
   were hand-edits to part1.json.

   TWO BUGS LIVED IN THE FIRST VERSION OF THIS BLOCK, both from writing colours
   instead of using this file's tokens:

     1. It was appended to review_frontend/style.css, which index.html does not
        link and which did not exist until that commit created it (`>>` makes a
        file silently). Every rule was inert.
     2. Moved here, it rendered BLACK ON BLACK: the chips hardcoded a dark
        `background: #262b34` with `color: inherit`, and this app is LIGHT
        (--ink is #1a202c on --paper #ffffff). Dark text on a dark chip. The
        `var(--rule, ...)` fallbacks were the tell - `--rule` is not a token in
        this file, so every one of them fell through to a dark literal.

   So: no literal colours below. --paper/--wash/--line/--ink are the surface and
   --accent/--accent-wash mark the picked chip, exactly as .disputed-option
   already does. A panel that invents its own palette is a second copy of the
   theme, which is Lesson 13 in CSS.

   The chips carry their word's index deliberately - a heading index is NOT a
   body index (item 0BB) - so the number has to read as an annotation and not
   as part of the Hebrew. Hence the separator, which must be real spacing and
   not a flex `gap`: the row is RTL, the number sits at the word's left, and a
   gap alone left them touching at the sizes this actually renders at. */
.klal-title-btn {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--fs-note);
  /* ONE SIZE AND WEIGHT FOR THE HEADING ROW'S THREE BUTTONS (2026-10-06): `font: inherit` took the text pane's
     line-height of 2 and the row's bold, so this button stood 28px tall and bold beside the other two (21px and 19px,
     plain) - and bolder than its own `.pending` state below, which is how a recorded ruling is meant to stand out.
     Now the flag button's line and padding, plain until a state sets the weight; the row's gap spaces it, so the 6px
     margin that set it in from the start on a wrapped line is gone. */
  font-weight: 400;
  line-height: 1.25;
  padding: var(--sp-half) var(--sp-2);
  cursor: pointer;
}
.klal-title-btn:hover { color: var(--ink); border-color: var(--accent); }
/* A heading ruling is RECORDED, not applied - the same two-step boundary every
   other decision here has. Without this the button looked identical before and
   after saving, which is exactly what happened: the reviewer saved klal 89, saw
   nothing change, and saved the identical ruling again half an hour later. */
.klal-title-btn.pending {
  border-color: var(--pending);
  color: var(--pending-ink);
  font-weight: 600;
}
/* A HEADING CONCERN (item 0GJ): a heading word that is not the name of a letter.
   The danger colour, because it is a question about the entry's anchor, and
   the reasons are in the button's tooltip. */
/* F1 (the reviewer, 2026-10-08, from mock-ups at both sizes: "F1 ... F5" as recommended): the lettering a darker red, 4.9:1 on the selected entry's yellow and 5.5:1 on white - in
   --danger it was 3.7:1 and 4.1:1. The border keeps --danger, as D2 kept amber for underlines and fills. */
/* A HELD heading ruling's button (P3, 2026-10-11; defined ahead of its build, its words girsa-operator's) wears the same
   red in place of .pending's amber, this rule coming after it - a held ruling's words are not drawn as pending (P2,
   Board #1 "A"). One that would be overtaken stays .pending, as Board #2's mock-up drew it. */
.klal-title-btn.concern, .klal-title-btn.held {
  border-color: var(--danger);
  color: var(--danger-ink);
  font-weight: 600;
}
/* A HEADING CORRECTED IN THE EXPORT (girsa-builder's STEP5-LOCKED-HEADING-PLAN, 2026-10-13; defined ahead of its build,
   the words girsa-operator's): with applying off, a saved correction whose exported heading passes the heading check is
   settled - a person's decision, still not in the base text here. So the green of "decided by a person" (B1), as a
   saved word is drawn with applying off: the border --state-human, the lettering --decided-ink (6.0:1 on the selected
   entry's yellow, E2), bold as every other state of this button. Not amber (nothing waits on an Apply that this copy
   will never run) and not red (no concern is left). One whose exported heading still has a concern stays `.pending
   .concern`, today's red. Last, so it wins over `.pending` if both are ever set. */
.klal-title-btn.exported {
  border-color: var(--state-human);
  color: var(--decided-ink);
  font-weight: 600;
}

.title-word-row { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.title-word-chip {
  background: var(--wash);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-family: 'Frank Ruhl Libre', serif;
  font-size: var(--fs-word);
  padding: var(--sp-half) var(--sp-2);
  cursor: pointer;
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-1);
  line-height: 1.5;
}
.title-word-chip:hover { border-color: var(--accent); background: var(--accent-wash); }
.title-word-chip.picked {
  border-color: var(--accent);
  background: var(--accent-wash);
  box-shadow: 0 0 0 1px var(--accent);
}
.title-word-i {
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-label);
  color: var(--ink-faint);
  /* The separator proper. `gap` alone is not enough here - see the note above. */
  margin-inline-start: var(--sp-1);
  padding-inline-start: var(--sp-1);
  border-inline-start: 1px solid var(--line);
}
#title-panel textarea {
  font-family: 'Frank Ruhl Libre', serif;
  font-size: var(--fs-word);
  line-height: 1.6;
}
/* "Recorded, not yet applied" - said in the panel as well as on the button,
   because the panel is where a reviewer is looking when they wonder whether the
   last save landed. */
.title-pending-note {
  border: 1.5px solid var(--pending);
  background: var(--pending-wash);
  border-radius: var(--radius-sm);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-2);
  font-size: var(--fs-note);
  color: var(--ink-soft);
}
/* WHAT YOUR EXPORT WRITES (the locked-heading build, girsa-builder's look question of 2026-10-13): the line under the
   note says a result, at the note's size and grey, its heading in the word face as the note's own heading is - bare, it
   was a sentence at the page's 15px in the interface face, larger than the note above it. */
.title-export-line { font-size: var(--fs-note); color: var(--ink-soft); }
.title-pending-note bdi, .title-export-line bdi {
  font-family: 'Frank Ruhl Libre', serif;
  font-size: var(--fs-word);
  color: var(--ink);
}
/* An APPLIED ruling is not pending, so it must not wear the pending colour -
   the panel has to distinguish "recorded, waiting" from "this is what the
   heading now says", which is the whole question the reviewer asked. */
.title-pending-note.applied { border-color: var(--line); background: var(--wash); }
/* A heading ruling NOT CARRIED into this version (option C, the reviewer 2026-10-07: "C, go on the words") is work
   that needs the editor again, not a ruling waiting to be applied: the needs-you notice's colours (D7), as the
   entry's not-carried notice (.stranded-banner) wears them - not the pending amber. */
/* A heading ruling HELD (P3, girsa-builder's request of 2026-10-11): Apply will not write it, and says why - the
   needs-you notice, as a held word's line is (.status-line.held-says; the reviewer's Board #1, "A - at its place, marked
   held"). One that WOULD BE OVERTAKEN keeps the plain pending note above: the reviewer's "yes" on Board #2 was given on
   the mock-up drawing it so (`overtaken-decision-2/`), only its sentence changed. `held` is defined ahead of P3's build. */
.title-pending-note.not-carried, .title-pending-note.held { border-color: var(--danger); background: var(--alert-bg); }
#title-panel .history-item { display: flex; gap: var(--sp-2); align-items: baseline; flex-wrap: wrap; }


/* ---------- Horizontal collapse order ----------

   Reviewer, 2026-09-04: "shrinking the window horiz should always collapse the
   index then the text never the scan."

   The order is a claim about what the reviewer cannot work without. The scan is
   the ink, and every decision in this project is made against it - a ruling
   entered without seeing the page is the failure Lesson 14 names. The text pane
   is next: it is where the word is clicked. The index is the most replaceable of
   the three, because a klal can also be reached by URL, by the deep links in
   the worklists, and by the nav that returns the moment the window widens.

   STAGED, not continuous, and that is deliberate: #legend is `position: fixed`
   with `width: var(--nav-w)` so it can overlay the index pane's own bottom. If
   the index narrowed continuously the legend would keep its old width and hang
   over the text; stepping the variable instead means the legend tracks it for
   free, which is the whole reason the width was a variable to begin with.

   Reversible by widening the window - nothing here is a mode the reviewer can
   get stuck in. But note the consequence at the narrow end: with the index gone
   so is the settings gear and the part selector, so those are wide-window
   controls. */

/* 1. The index narrowing first is handled by --nav-w's clamp(), not by a
      breakpoint - see the variable's own note on why a step there sawtoothed
      the scan pane.

   2. The index goes entirely. `display: none` on the pane also removes
      #legend, which is its child in the markup even though it is positioned
      out of the flow - so the count readout leaves with the pane it belongs
      to rather than stranding itself over the text. */
@media (max-width: 1200px) {
  #nav-pane { display: none; }
  #flag-list-panel { display: none; }      /* the list pane leaves with the index (W1 a); its ruling panels still open */
  :root { --list-w: 0px; }
  #text-pane { flex-basis: 42%; }          /* two panes again: the share the text had before the list pane (W1 a) */
  /* AND THE VARIABLE GOES WITH IT. `.side-panel` docks at `right: var(--nav-w)`
     so it sits BESIDE the index rather than over it (that fix is documented on
     .side-panel itself). With the index hidden but the variable still 300px,
     every decision panel floated 300px short of the window edge with dead space
     behind it - introduced by this very media query on 2026-09-04 and caught by
     the reviewer the same afternoon. The gap is only correct while there is
     something in it. */
  :root { --nav-w: 0px; }
}

/* 3. Only then does the text go, and the scan takes the whole window. Its
      `width: 34%` has to be released here or the pane would hold a third of the
      viewport with nothing beside it. */
@media (max-width: 720px) {
  #text-pane { display: none; }
  #scan-pane {
    width: auto;
    flex: 1 1 auto;
    border-left: none;
  }
}

/* Per-word deletion inside a multi-word candidate span (2026-09-04). Laid out
   as a row of small buttons rather than another radio option, because it is not
   an answer to "which reading is right" - it is a different, narrower edit. */
.span-word-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.span-del-btn { font-size: var(--fs-ui); direction: rtl; }
.span-word-hint {
  font-size: var(--fs-note); color: var(--ink-faint); margin-top: var(--sp-2);
  font-family: 'Inter', sans-serif;
}

/* The history panel's provenance caption - see renderDecisionHistory in app.js. One look since 2026-10-06: its amber
   variant, `h-basis-weak`, marked rows served by bare position, and since step 5's C6c2 no row is (girsa-operator's
   4b6f19e removed the last use; the rule retired with it). */
.h-basis { font-size: var(--fs-note); color: var(--ink-faint); margin: 0 0 var(--sp-1); }

/* Text-view toggle and the read-only views (item 0GC). */
/* The which-text box shares the bar with the centred group, and it used to be
   pinned out of the flow at left: 8px. Nothing kept the group off it: measured
   2026-09-15 on HaShorashim, 14px clear at a 1700px window and OVERLAPPING the
   Hebrew title by 41px at 1440 and 75px at 1280 (reviewer: "master text
   selection box needs whitespace separation"). A three-column grid keeps the
   group centred on the pane while there is room, and pushes it right rather
   than under the box when there is not: the two 1fr columns share the free
   space equally until the box's column needs more than its share. The column
   gap is the guaranteed separation. When the box is hidden (a book with no
   comparison texts) the first column is empty and the group centres exactly as
   the other two bars do. */
#text-header {
  position: relative;
  display: grid;
  /* THE ENDS SHRINK, THE MIDDLE STAYS CENTRED (2026-10-05, 0MK). A bare `1fr` cannot go below its content's
     min-width, so once the bar is too narrow for both ends at full size - the text pane's share is 30% beside the
     list pane, 452px at 1600 - the two end columns come out unequal (80px against 99px on the fixture book with
     seven rulings on the Apply button) and the title drifts, 10px there, 3px in the suite's module run. With
     `minmax(0, 1fr)` the ends always get equal shares and the title stays in the middle; the wordmark yields first
     (it is `flex: 1 1 0`), and the which-text box and the Apply button keep their own width inside the bar. */
  grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(min-content, 1fr);
  column-gap: var(--sp-5);
}
/* THE SQUEEZED BAR (the reviewer, 2026-10-05: "squeezed" - the four columns at every width, so the text bar can be
   234px wide at the reviewer's 1229-wide window). What gives way, in order: the wordmark, then the which-text box
   (it takes the column left over and shows what fits of its text), then the title (the middle column can shrink to
   nothing, minmax(0, auto), and clips at its own edges), never the Apply button (its column keeps its content). The
   title is in the middle of the bar whenever both ends fit equal shares. Under a 460px bar (a container query on
   the text pane) the box keeps 84px - "Base text" whole, a longer choice in the box's own ellipsis - and the title
   yields first; under 320px the gaps narrow to 8px, or two controls with two 24px gaps and the padding overrun a
   234px bar. Measured on the way: with the ends at 0 the box ran 48px into the title at 234px; with min-content
   ends and no cap the second book's box (190px, its chosen text) ran 37px out of the bar. */
#text-header .ph-mid { grid-column: 2; grid-row: 1; overflow: hidden; }
/* A PART OF THE TITLE THAT CANNOT FIT LEAVES WHOLE, THE ENGLISH FIRST (the reviewer, 2026-10-08: "(b) Whole or nothing",
   from mock-ups at 1864, 1440 and 1229). The row clipped at its edge: "Y..." and "S." from 1440, the Hebrew cut to its
   last letters at 1229 - a broken word for a Hebrew reader. The wordmark's trick: the row is one line high (the Hebrew
   title's 16px x 1.2) and wraps, so a part that no longer fits drops to a second line the height hides - the English
   first, being last in the row. The empty first item is as tall as the row, so the Hebrew, alone and too wide, drops
   too; it stays out of the baseline alignment (as an item with no text its bottom edge became the row's baseline, and
   the title sat 5.6px low), and its negative margin takes back the row's gap. Where the title fits, nothing moves. The
   browser tab still names the book when the bar has no room for it. */
#text-header .ph-mid { flex-wrap: wrap; height: calc(16px * 1.2); align-content: flex-start; justify-content: center; }
#text-header .ph-mid::before {
  content: ''; width: 0; height: 100%; align-self: flex-start; margin-inline-end: calc(-1 * var(--sp-4));
}
#text-pane { container-type: inline-size; }
@container (max-width: 320px) { #text-header { column-gap: var(--sp-2); } }
#text-view { grid-column: 1; grid-row: 1; justify-self: start; font-size: var(--control-small); }
/* As wide as the text it shows, not as its longest choice (Apply's button, 2026-10-01): "Base text" in a box sized
   for "Their corrected, no vowel points" took 203px of a 516px bar. A browser without field-sizing keeps the old
   width; the column above still keeps the titles from under the button. */
#text-view { field-sizing: content; }
/* In a narrow bar the box is capped (the browser counts the LONGEST choice, 190px, as a select's minimum width,
   field-sizing or not - measured 2026-10-05 on the second book at 1229: the box ran 37px out of the bar's left
   edge). Capped at 84px, "Base text" (72px) still shows whole; a longer choice ends in the box's own ellipsis.
   The order of giving way in the bar: the wordmark, then the title (clipped), then this box; the Apply button
   never. */
#text-view { max-width: 100%; }
@container (max-width: 460px) {
  #text-header { grid-template-columns: minmax(min-content, 1fr) minmax(0, auto) minmax(min-content, 1fr); }
  #text-view { max-width: 84px; }
}
/* THE PROJECT'S WORDMARK, UNDER THE BOOK'S NAME IN THE INDEX BAR (the reviewer's Board #23, 2026-10-12: "B - Under
   the book's name, in the index bar", from mock-ups at both sizes; the rule: the name is never dropped). Until then it
   sat in the text bar's third column and gave way to the titles and Apply - 0px at 1229x673 on both books. Now the
   bar is two lines, centred: the section's name, then this smaller line, so the bar keeps its 46px and no pane
   loses height. Its own line, in the bar's quieter lettering: on 2026-09-21 the same name BESIDE the section's
   reference read as part of it. The gear stays pinned at the bar's right, out of the flow. */
/* CENTRED WHERE IT FITS, NEVER UNDER THE GEAR (the reviewer's Board #24, 2026-10-13: "A - Move left only as far as it
   must", from mock-ups at 1229x673). Centred on the bar as if the pinned gear were not there, the second book's
   "Aleph-Bet-Gimel" ran 4px under it at 1229x673 (at every width from 1210 to 1260), and Yad Malachi's name touched it
   at 1210-1220. Three columns: the two lines in the middle one, sized to them; the right column never narrower than
   the gear and a step of air. While the lines fit with that room on both sides, the outer columns are equal and the
   lines are centred on the bar; where they do not, the left column gives way first, so the lines move left only as
   far as they must (12px on the second book at 1229x673, 7px on Yad Malachi; nothing at 1864). Only a name too long
   for the whole bar shortens its English half with "...", as `.ph-ref.ph-en` always has. */
#nav-header {
  display: grid; align-content: center; justify-items: center; gap: 0;
  grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(calc(var(--gear-size) + var(--sp-2)), 1fr);
}
#nav-header .ph-mid, #nav-header #brand { grid-column: 2; }
#nav-header .ph-mid { line-height: var(--brand-line-1); max-width: 100%; }
#brand {
  display: flex; align-items: baseline; gap: var(--sp-2);
  line-height: var(--brand-line-2); margin-top: var(--sp-hair); white-space: nowrap;
  font-family: 'Inter', sans-serif;
  font-size: var(--brand-en-size); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  /* F4 (2026-10-08): the bar's decided lettering at full strength, 5.0:1 - --header-fg faded to .6 was 3.5:1 */
  color: var(--header-muted);
  cursor: default; user-select: none;
}
/* The pair is ONE flex item, so it never splits. The Aramaic is set in the page's Hebrew face, a little larger so the
   two read as one size (the bars' own title pair does the same), and without the tracking and capitals, which are
   Latin devices. */
#brand .brand-pair { display: inline-flex; align-items: baseline; gap: var(--sp-1); white-space: nowrap; }
#brand .brand-he {
  font-family: 'Frank Ruhl Libre', 'David', serif;   /* the bars' own Hebrew stack */
  font-size: var(--brand-he-size); font-weight: 500; letter-spacing: 0; text-transform: none;
}
/* The release's version beside the pair ("alpha-rc17"; in our own checkout "Girsa, development copy" - girsa-operator's
   words), written by the page once the server serves the release's tag (girsa-builder's, 2026-10-12): Board #23's
   mock-up, the note size in plain Latin, no capitals. Full strength, not faded (F4). */
#brand .brand-version { font-size: var(--fs-note); font-weight: 500; letter-spacing: 0; text-transform: none; }
.klal-body.alt-view .alt-banner { font-size: var(--fs-note); color: var(--ink-faint); margin: var(--sp-1) 0 var(--sp-2); direction: ltr; text-align: left; }
/* The other texts' words, with THE BASE TEXT'S word metrics (item 0GX): the same
   1px padding as .plain-word and .flag-word, the pane's own line height and
   whitespace, so toggling moves only what actually differs. Read-only - no
   pointer, no hover. */
.klal-body .alt-word { border-radius: var(--radius-mark); padding: 0 var(--sp-hair); }
/* Their citation, small and raised where the page prints its note's reference
   numeral - set like .fn-ref, in the accent colour that marks it as theirs. */
.alt-citation { vertical-align: super; font-size: var(--superscript-em); line-height: 0; color: var(--accent); }

/* The cited verse in the witness panel (item 0GE). */
.verse-text { font-size: var(--fs-word); line-height: 1.9; color: var(--ink); margin: var(--sp-half) 0 var(--sp-1); }

/* The klal flag panel's account of what the flag asked (klalFlagSummaryHtml). */
.flag-summary { font-size: var(--fs-ui); color: var(--ink-soft); }
.flag-summary .flag-words { margin: var(--sp-1) 0 0; padding-inline-start: var(--sp-4); }
.flag-summary .flag-word-item { margin: var(--sp-half) 0; }
.flag-summary .flag-full-note { margin-top: var(--sp-2); }
.flag-summary .flag-full-note summary { cursor: pointer; color: var(--ink-faint); }
.flag-summary .flag-full-note .h-note { white-space: pre-wrap; max-height: 240px; overflow: auto; }

/* THE LIST'S STEPS AT THE PANEL'S FOOT (W5, 2026-10-05; renderWorkSteps): the floating work-through bar is gone. A strip
   below the Save row, in the panel's own flow, so it covers nothing and Save keeps its place in every panel while a
   list is worked: Previous at the left, "3 of 17" in the middle, Next at the right. The wash sets it apart from the
   Save row above it - it moves through the list, it records nothing. */
.work-steps {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-1) var(--sp-5);
  border-top: 1px solid var(--line);
  background: var(--wash);
  font-size: var(--fs-ui);
  color: var(--ink-soft);
}
.work-steps .wb-pos b { color: var(--ink); }
/* What the row said, under the panel's title (part (3) of 2026-10-08): the row's status and its meaning, a hint band. */
.work-row-says {
  padding: var(--sp-1) var(--sp-5); border-bottom: 1px solid var(--line); background: var(--wash);
  font-size: var(--fs-note); line-height: 1.5; color: var(--ink-soft);
}
.work-row-says b { color: var(--ink); font-weight: 600; }
/* Compact: at 1229x673 stacked the panel body above the Save row is short, and every pixel here comes out of it. */
.work-steps .panel-btn { padding: var(--sp-1) var(--sp-3); }
.flag-list-item.wb-current { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ---------- the stacked layout (item 0LU) ----------
   The Sefaria editor's suggestion: the scan above the text, the ruling panel kept open
   beside them. The page is right to left, so the grid's first column is the RIGHT one:
   index | panel column | scan over text. The panel column is the panels' own 420px
   directly left of the index - exactly where .side-panel already docks (right:
   var(--nav-w)) - so an opening panel lands in it and covers nothing. */
/* The switch alone decides this (the reviewer, 2026-10-05: "squeezed" - the four columns stay at every width the
   index stays at; a band under 1500px that stacked the classic layout by the window's width was removed). */
body.layout-stacked {
  display: grid;
  grid-template-columns: var(--nav-w) var(--list-w) minmax(0, 1fr);
  grid-template-rows: minmax(0, 55fr) minmax(0, 45fr);
  grid-template-areas: "nav panel scan" "nav panel text";
}
body.layout-stacked #nav-pane { grid-area: nav; width: auto; }
body.layout-stacked #scan-pane { grid-area: scan; min-height: 0; border-bottom: 2px solid var(--line); }
body.layout-stacked #text-pane { grid-area: text; min-height: 0; min-width: 0; }
body.layout-stacked .side-panel { width: var(--list-w); box-shadow: none; border-left: 1px solid var(--line); }
body.layout-stacked #overlay-backdrop { display: none !important; }
/* THE LIST PANE (W1 (a), 2026-10-04): the centre column in both layouts - a flex item between the index and the
   text in the classic layout, the panel column's grid area in the stacked one (where #panel-placeholder stood). */
.list-pane {
  width: var(--list-w); flex-shrink: 0; min-width: 0;
  display: flex; flex-direction: column;
  background: var(--paper); border-right: 1px solid var(--line);
  position: relative; z-index: var(--z-pane);   /* above the backdrop, as the index is, so its buttons take clicks */
  direction: ltr;
  /* The panels' face, which the list had as a .side-panel until W1 moved it here: without it the list's English -
     scope, chips, order, every row's reference - fell to the body's Hebrew text face (found 2026-10-05). The rows'
     Hebrew word keeps the text face (.flag-list-word). */
  font-family: 'Inter', sans-serif;
}
.list-pane > .panel-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
body.layout-stacked #flag-list-panel { grid-area: panel; width: auto; }


/* AN OPEN REVISIT FLAG ON ITS WORD (2026-09-30, item 0MI): a small flag after the word, on top of whatever state
   colour the word carries - the flag is its own thing, not a kind of dispute. */
.klal-body .has-open-flag::after {
  content: "\2691";
  font-size: var(--superscript-em);
  vertical-align: super;
  margin-inline-start: var(--sp-hair);
  color: var(--danger);
}
/* The flag/correct panel's one line on where the word stands (2026-09-30, item 0MI). */
/* WHERE THE WORD STANDS, one line in ink under the context, in every ruling panel (style guide D6, 2026-10-01): the
   word panel's line since 0MI; the dispute and witness panels' since D6 - there the state was a larger line above
   the reference, or a green line under a "Current decision" label. */
.status-line { font-size: var(--fs-ui); margin-top: var(--sp-2); font-weight: 600; color: var(--ink); }
/* WHY NO RULING IS LINKED HERE (girsa-builder's line, 2026-10-09; Yad Malachi 75 w320): it explains the status line above
   it, so it is quieter than it - the note size, regular weight, the soft ink - and not a second bold statement; in bold
   at 1229x673 it was a five-line block pushing the correction box down. One status line per panel (STYLE.md D6). */
.status-line.work-row-unlinked { font-size: var(--fs-note); font-weight: 400; color: var(--ink-soft); margin-top: var(--sp-1); line-height: 1.5; }
/* A HELD RULING'S LINE in a panel with no row of its own (P2; the reviewer's decision 1 on Board #1, 2026-10-09, "A - at
   its place, marked held"): girsa-operator's rule gives Apply's reason once, as the panel's status line - and the chosen
   mock-up (held-A-panel) draws it as the needs-you notice, red as the list's tag and the text's mark are. So it takes
   the notice's look (D7, as .stranded-banner, which a panel on a held row opens with). */
.status-line.held-says {
  font-size: var(--fs-note); font-weight: 400;
  background: var(--alert-bg); border: 1px solid var(--danger); border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-2);
  direction: ltr; text-align: left;
}
/* A small square in the word's state colour before a panel's status line (until 2026-10-01 an inline style). */
.state-dot { display: inline-block; width: 9px; height: 9px; border-radius: var(--radius-mark); margin-inline-end: var(--sp-1); }
.state-dot-open { background: var(--state-open); }
.state-dot-machine { background: var(--state-machine); }
.state-dot-human { background: var(--state-human); }

/* Why the word is in the queue, first line of the dispute panel (2026-09-30, item 0MI). */
#disputed-panel .dispute-reason { font-size: var(--fs-ui); margin-top: var(--sp-1); }
