:root{
  --ground:#F5F7F8; --surface:#fff; --sunk:#EDF0F2;
  --ink:#14181C; --muted:#5C6773; --hair:#DBE1E6;
  --accent:#A8681A; --danger:#A63A2B; --film:#fff;
  --target:#FF1A1A;             /* highlight around the line being transcribed */
  --pm-track:#31363F;           /* dark gray track behind the progress bar */
  --pm-w:500px;                 /* progress bar width */
  --radius:2px;
  --drawer-w:465px;
  /* Wide enough that a line image never needs to scroll sideways. Surveyed
     over 3,469 sliced lines at ZOOM=2: p50 802px, p90 816px, p99.5 1022px,
     widest 1250px -- so 1280 clears every crop in the corpus. The form shares
     the width, so the typed line sits under the printed one at the same
     scale. */
  --content-w:1280px;
  --header-h:64px;
  --footer-h:38px;              /* no footer element any more; kept as the
                                  bottom-gutter constant for main + the meter */
}
@media (prefers-color-scheme: dark){
  :root{
    --ground:#0F1216; --surface:#161B21; --sunk:#1C222A;
    --ink:#E7EBEF; --muted:#8E99A6; --hair:#262D35;
    --accent:#DFA355; --danger:#DE7B66; --film:#fff;
    --target:#FF3B3B;
    --pm-track:#2A2F37;
  }
}
*{box-sizing:border-box}
body{
  margin:0; background:var(--ground); color:var(--ink);
  font:16px/1.6 ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
}
/* Sticky, with an explicit height, so "the bottom of the header" is a fixed
   boundary the drawer can anchor to (below) even once the page has scrolled
   -- an in-flow header would scroll out from under that boundary. */
header{
  position:sticky; top:0; z-index:6; height:var(--header-h);
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:0 24px; border-bottom:1px solid var(--hair); background:var(--surface);
}
h1{margin:0; font-size:17px; letter-spacing:-.01em}
h1 span{color:var(--muted); font-weight:400; margin-left:6px}
.head-right{display:flex; align-items:center; gap:14px}
/* Round help-icon button in the header corner. Mirrors the Submit button --
   same gold, same hover brightening; the icon is white-on-gold while the
   drawer is closed and flips to dark-on-gold while it's open. */
.icon-btn{
  display:inline-flex; align-items:center; justify-content:center;
  width:36px; height:36px; padding:0; border-radius:999px;
  background:var(--accent); border-color:var(--accent); color:#fff;
  box-shadow:0 1px 5px rgba(0,0,0,.2);
}
.icon-btn svg{display:block}
.icon-btn[aria-expanded="true"]{color:#1b1206}
.icon-btn:hover{filter:brightness(1.08)}

main{max-width:var(--content-w); margin:0 auto; padding:24px 24px calc(64px + var(--footer-h))}

/* The viewport never changes height, so expanding the viewer cannot push the
   form around. The neighbouring lines are simply hidden padding until asked
   for. Extra bottom margin keeps the expanded box clear of the input. */
.viewport{position:relative; margin-bottom:40px}
/* overflow-x:auto rather than hidden: when the window is too narrow for a
   line's full width, the line scrolls sideways instead of losing text off
   the edge -- a crop is never trustworthy to transcribe with part of it
   clipped away. Vertical stays hidden; that axis is the deliberate
   collapse/expand mechanism, not a size accident. */
.viewer{
  position:absolute; left:0; right:0; overflow-x:auto; overflow-y:hidden;
  background:var(--film); border:1px solid var(--hair); border-radius:var(--radius);
  transition:height .18s ease, top .18s ease;
}
.viewer:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.film{position:absolute; left:0; top:0; transition:transform .18s ease}
.film img{position:absolute; display:block}

/* Drawn as an overlay rather than an outline on the image: neighbouring
   crops are absolutely positioned and would paint over an outline's bottom
   and left edges. Only meaningful with context showing, so it fades in. */
.highlight{
  position:absolute; border:4px solid var(--target); border-radius:1px;
  opacity:0; transition:opacity .18s ease; pointer-events:none; z-index:2;
}
.viewer.open .highlight{opacity:1}

form{display:flex; flex-direction:column; gap:10px}
/* The quick-insert buttons sit left, the dateline note sits right, on one
   line above the input. */
.char-row{display:flex; align-items:flex-end; gap:16px}
.chars{display:flex; gap:6px; flex-wrap:wrap; flex:0 0 auto}
/* A dim aside telling the volunteer roughly when the paper they're reading
   was printed. Takes the rest of the row and right-aligns its text; renders
   nothing (but holds the row's height via the buttons) when it's empty -- no
   task yet, or a reel whose filename carried no readable date span. */
.reading-date{
  flex:1 1 auto; margin:0; text-align:right;
  font-size:12px; line-height:1.35; color:var(--muted); opacity:.75;
}
.chars button{
  font:15px/1 ui-monospace,monospace; padding:7px 11px; cursor:pointer;
  background:var(--sunk); color:var(--ink);
  border:1px solid var(--hair); border-radius:var(--radius);
}
.chars button:hover{border-color:var(--accent)}
textarea{
  width:100%; padding:12px 14px; resize:vertical;
  font:17px/1.5 ui-monospace,"SF Mono",Menlo,monospace;
  background:var(--surface); color:var(--ink);
  border:1px solid var(--hair); border-radius:var(--radius);
}
textarea:focus{outline:2px solid var(--accent); outline-offset:-1px; border-color:transparent}
/* Two items only: space-between puts Skip at the left edge and Submit at
   the right, matching the convention of a secondary action on one side and
   the primary action on the other. */
.actions{display:flex; gap:10px; align-items:center; justify-content:space-between; flex-wrap:wrap}
button{
  font:14px/1 inherit; padding:11px 16px; cursor:pointer;
  background:var(--surface); color:var(--ink);
  border:1px solid var(--hair); border-radius:var(--radius);
}
button:hover{border-color:var(--muted)}
button.primary{background:var(--accent); border-color:var(--accent); color:#fff; font-weight:600}
button.primary:hover{filter:brightness(1.08)}

/* Progress meter: one wide bar pinned to the bottom of the viewport and centred
   on the page, with a dim one-line summary above it. Fixed rather than in-flow
   so it holds its place no matter how little the page holds (it also stands in
   for the old footer). The overlay is click-through (pointer-events:none) so it
   can't intercept a click meant for the form below it; the caption and track
   switch them back on for their hover titles. */
.pmeter{
  position:fixed; left:0; right:0; bottom:calc(var(--footer-h));
  z-index:9; pointer-events:none;
  display:flex; flex-direction:column; align-items:center; gap:7px;
  transition:transform .18s ease;
}
.pm-caption{
  margin:0; pointer-events:auto; max-width:90vw; text-align:center;
  font-size:12px; line-height:1.3; color:var(--muted); opacity:.7;
  font-variant-numeric:tabular-nums;
}
.pm-track{
  position:relative; pointer-events:auto;
  width:var(--pm-w); max-width:90vw; height:10px;
  background:var(--pm-track); border-radius:999px;
  box-shadow:inset 0 1px 2px rgba(0,0,0,.35), inset 0 0 0 1px rgba(255,255,255,.04);
}
/* Three fills stacked from the left edge, each zero-to-its-own-count. Colours
   are fixed per category; JS sets z-index (smallest count on top) so every
   band stays visible unless two counts are exactly equal. Each has a soft halo
   plus a tight bright core so the bar reads as lit rather than just painted. */
.pm-fill{
  position:absolute; left:0; top:0; bottom:0; width:0;
  border-radius:999px;
  transition:width .45s cubic-bezier(.4,0,.2,1);
}
.pm-fill.f-verified{                         /* verified / matched -- gold */
  background:linear-gradient(90deg,#E8A31A,#F7CE2B);
  box-shadow:0 0 2px 1px rgba(247,206,43,.45), 0 0 1px rgba(247,206,43,.85);
}
.pm-fill.f-community{                         /* community reviewed -- teal */
  background:linear-gradient(90deg,#159BD0,#2FD6C6);
  box-shadow:0 0 2px 1px rgba(47,214,198,.45), 0 0 1px rgba(47,214,198,.85);
}
.pm-fill.f-you{                              /* your own count -- blue */
  background:linear-gradient(90deg,#2563EB,#4C93FF);
  box-shadow:0 0 2px 1px rgba(76,147,255,.5), 0 0 1px rgba(76,147,255,.9);
}
@media (prefers-reduced-motion:reduce){
  .pmeter, .pm-fill{transition:none}
}
/* Mirror main's shift so the centred bar rides left with the page when the
   instructions drawer opens on a wide screen. */
@media (min-width:900px){
  body.guide-open .pmeter{transform:translateX(calc(-1 * var(--shift)))}
}
/* Mirrors .actions directly below it: the left hint sits under Skip, the
   right hint under Submit. */
.keys{display:flex; justify-content:space-between; margin:0; font-size:12px; color:var(--muted)}

dialog{
  border:1px solid var(--hair); border-radius:var(--radius); padding:22px;
  background:var(--surface); color:var(--ink); max-width:380px;
}
dialog::backdrop{background:rgba(0,0,0,.45)}
dialog h2{margin:0 0 14px; font-size:15px}
dialog form{gap:8px}
dialog button{width:100%; text-align:left}
dialog button.cancel{color:var(--muted)}
dialog hr.divider{border:none; border-top:1px solid var(--hair); margin:20px 0; width:100%}
.done{padding:40px 0; text-align:center; color:var(--muted)}

/* Instructions drawer: overlays rather than reflows, so it can stay open
   while working. On a wide screen the page shifts over to sit beside it.
   Starts below the sticky header and runs to the bottom of the page, so it
   never covers the header controls above it. */
.drawer{
  position:fixed; top:var(--header-h); right:0; bottom:0;
  width:var(--drawer-w); max-width:100%;
  overflow-y:auto; padding:20px 22px 40px; z-index:10;
  background:var(--surface); border-left:1px solid var(--hair);
  box-shadow:-8px 0 24px rgba(0,0,0,.10);
}
.drawer[hidden]{display:none}
/* Themed scrollbar so the drawer's overflow track picks up the palette rather
   than the browser default. Firefox uses the two-value scrollbar-color (thumb,
   track); WebKit/Blink use the pseudo-elements. */
.drawer{scrollbar-width:auto; scrollbar-color:var(--hair) var(--surface)}
.drawer::-webkit-scrollbar{width:16px}
.drawer::-webkit-scrollbar-track{background:var(--surface)}
.drawer::-webkit-scrollbar-thumb{
  background:var(--hair); border-radius:999px;
  border:4px solid var(--surface);
}
.drawer::-webkit-scrollbar-thumb:hover{background:var(--muted)}
.drawer-head{display:flex; align-items:center; justify-content:space-between; gap:10px}
.drawer h2{margin:0; font-size:15px}
.drawer h3{margin:22px 0 8px; font-size:13px; text-transform:uppercase; letter-spacing:.09em; color:var(--muted)}
.drawer h3.warn{color:var(--danger)}
.drawer p{margin:0 0 10px; font-size:14px}
.drawer .lede{margin-top:14px; color:var(--muted)}
.drawer #guideClose{border:none; background:none; font-size:22px; line-height:1; padding:2px 6px; color:var(--muted)}
/* Each rule is shown as a specimen cut from the scans, with the rule beneath
   it. A rule about what the ink looks like is far easier to follow from the
   ink than from a sentence describing it. The specimens are fixed files in
   web/examples/ rather than live crops -- see pipeline/extract_examples.py. */
.rules{margin:0; display:flex; flex-direction:column; gap:20px; font-size:14px}
.rule{display:flex; flex-direction:column; gap:8px; padding-bottom:20px}
.rule img{
  display:block; max-width:100%; align-self:flex-start;
  background:#fff; padding:6px 8px;
  border:1px solid var(--hair); border-radius:var(--radius);
}
.rule p{margin:0}
/* What a volunteer should actually type for the specimen above it. */
.answer{
  font:13px/1.5 ui-monospace,"SF Mono",Menlo,monospace;
  background:var(--sunk); padding:7px 10px;
  border-left:2px solid var(--accent);
  border-radius:0 var(--radius) var(--radius) 0;
  overflow-wrap:anywhere;
}
.answer.skip{color:var(--danger); border-left-color:var(--danger)}
.drawer code{font:13px ui-monospace,monospace; background:var(--sunk); padding:1px 5px}

/* Re-centering the column in the space left of the drawer, rather than
   narrowing it, keeps the image viewer at its full natural width for as long
   as that's geometrically possible -- so its own horizontal scrollbar stays
   a rare fallback (a genuinely wide line) instead of the common case (any
   time the drawer happens to be open).

   Centering a fixed-width box within [0, viewport-drawer] instead of
   [0, viewport] is algebraically just the normal centered position shifted
   left by half the drawer's width -- true regardless of the box's own
   width, which is why --shift below doesn't depend on it. That shift alone
   is enough once the column already had at least that much side margin to
   give up (viewport >= content-width + drawer-width, i.e. >= 1720px here).
   Below that, shifting as far as the left edge allows isn't quite enough to
   clear the drawer on the right, and the residual -- never more than it
   would have been without shifting at all -- is taken up by narrowing, the
   same safe padding-based mechanism as before (never a margin or transform
   on width, so it still can't clip anything off the left edge).

   This applies to `main` only. `header` is full-bleed with no centering
   margin of its own to shift into -- translating it just slides the whole
   bar away from the right edge, opening a gap of bare background there
   (which, sitting right above the drawer's top-left corner, is exactly the
   "gap above the panel" this once caused). It also isn't needed: the drawer
   is anchored below the header's bottom edge (see .drawer, --header-h), so
   the two can never overlap regardless of viewport width. */
body{
  --half-drawer: calc(var(--drawer-w) / 2);
  --shift: min(var(--half-drawer), max(0px, (100vw - var(--content-w)) / 2));
  --narrow: max(0px, var(--drawer-w) - (2 * var(--shift)));
}

/* Below the width where the centered column has no side gap at all, the
   drawer covers the full screen instead -- the standard small-screen
   pattern -- so there is nothing to protect underneath and no shift or
   narrowing is applied. */
@media (max-width:899px){
  .drawer{width:100%}
}
@media (min-width:900px){
  body.guide-open main{
    transform:translateX(calc(-1 * var(--shift)));
    padding-right:calc(24px + var(--narrow));
  }
}
main{transition:padding-right .18s ease, transform .18s ease}

:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
@media (prefers-reduced-motion:reduce){*{transition:none!important}}
