/* Storydrills — Hoodworks Media Group. Single stylesheet, no build step. */

/* ---------------------------------------------------------------------------
   BRAND — Hoodworks Media Group palette, applied verbatim.

     #E0392F  brand red     identity, primary actions, "chaos" half, Act Two
     #8B0000  deep red      negative-state fills ONLY (2.1:1 on black, never text)
     #FFEDDF  cream         primary ink, "order" half, Act One
     #747578  grey          muted accents, Act Three
     #000000  black         canvas

   Two deliberate departures, both forced:

   1. --ink-2 / --ink-3 are lifted greys, not #747578. Brand grey measures
      4.06:1 on the raised surface, which fails WCAG AA for body text. Brand
      grey is kept for non-text uses. (Asserted in the brand test suite.)
   2. --ok is a green. The palette has no green, and "correct" cannot be
      signalled in red without colliding with "wrong".

   Brand red is the identity colour; deep red carries every failure state, so
   a red accent is never mistaken for an error.
   --------------------------------------------------------------------------- */
:root{
  --brand-red:#E0392F;
  --brand-red-deep:#8B0000;
  --brand-cream:#FFEDDF;
  --brand-grey:#747578;
  --brand-black:#000000;
}

/* ---------------------------------------------------------------------------
   GEOMETRY AND MOTION — theme-independent.

   --pitch was the ruling pitch. Nothing is ruled any more, so it is now just
   the line-height the handwriting is set at — the rhythm of the hand rather
   than an alignment to anything drawn on the page. It no longer has to be
   defended to the pixel, and --rule-offset, which existed only to sit a
   baseline on a rule, is gone with the rules.
   --------------------------------------------------------------------------- */
:root{
  --radius:14px;
  --tabh:60px;
  --maxw:640px;
  --pitch:34px;             /* handwriting line-height */
  /* Pen settings, tuned on the motion bench. Fast and flat: at 900 px/s a
     full line lands in well under half a second, no gap means the next line
     starts the instant the last one finishes, and linear easing is a plotter
     rather than a hand settling at the end of a stroke. The high jitter is
     what puts the hand back in — and it is only safe because nothing is ruled
     any more. On ruled paper this much wobble lifts the text off the line. */
  --pen-speed:900;          /* px/s — duration derives from line width */
  --line-gap:0;             /* ms between lines */
  --jitter:2.5;
  --ease-write:linear;

  --sys-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,"Helvetica Neue",Arial,sans-serif;
  --sys-serif:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  --hand:"Kalam","Segoe Print",cursive;
  --label:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

}

/* ---------------------------------------------------------------------------
   THEME: STUDIO — the shipped Hoodworks look. Default, and what you get with
   no data-theme attribute at all, so a first paint before the theme script
   runs is never wrong.
   --------------------------------------------------------------------------- */
:root,
html[data-theme="studio"],
[data-theme="studio"]{
  /* paper metaphor — studio has no stock, so both textures are inert */
  --paper:var(--brand-black);
  --paper-edge:var(--brand-black);
  --paper-texture:none;
  --plate-texture:none;
  --pencil:var(--brand-cream);
  --plate:var(--brand-cream);
  --plate-deep:var(--brand-black);
  --plate-text:var(--brand-black);
  --plate-ink-2:#4a4a4a;      /* studio paints no cover; kept coherent anyway */
  --plate-line:var(--line);

  --bg:var(--brand-black);
  --bg-2:#121214;
  --bg-3:#1b1b1e;
  --line:#2c2c31;
  --line-soft:#1f1f23;
  --line-2:#4a4b4e;
  --ink:var(--brand-cream);
  --ink-2:#a6a7aa;          /* 7.8:1 on --bg-2 */
  --ink-3:#8c8d90;          /* 5.6:1 on --bg-2 */
  --order:var(--brand-cream);
  --chaos:var(--brand-red);
  --chaos-soft:var(--brand-red-deep);
  --ok:#5fa357;
  --warn:var(--brand-grey);
  --miss:var(--brand-red-deep);

  --accent:var(--brand-red);
  /* Third documented departure, and the same reason as --ink-2/--ink-3:
     brand red measures 4.27:1 on the raised surface, so as SMALL TEXT — links,
     the lit tab label, the 9.5px scope chips — it fails AA. --accent-ink and
     --link are a lifted tint used only where the colour has to be read as
     words. --accent itself stays pure brand red for borders and fills, where
     contrast rules do not apply. (Measured in themetest.mjs.) */
  --accent-ink:#F1554E;
  --accent-line:rgba(224,57,47,.45);
  --accent-wash:rgba(224,57,47,.13);
  --link:#F1554E;
  --btn-bg:var(--brand-red);
  --btn-ink:#000;
  --on-band:#000;

  --ok-bg:#16251a;   --ok-line:#2f5a2c;  --ok-ink:#8fc98a;
  --bad-bg:#2a0a0b;  --bad-bg-soft:#1c0708; --bad-line:#6e1116; --bad-ink:#f2a9a5;
  --neutral-bg:#212124; --neutral-ink:#c4c5c8;
  --miss-bg:var(--brand-red-deep); --miss-ink:var(--brand-cream); --miss-line:#b3161c;

  --band-order:#FFEDDF; --band-chaos:#E0392F;
  --band-act1:#FFEDDF;  --band-act2:#E0392F;  --band-act3:#747578;
  --band-sm1:#FFEDDF;   --band-sm2a:#E0392F;  --band-sm2b:#F0757A; --band-sm3:#747578;
  --band-tv0:#C9BFB4;   --band-tv1:#FFEDDF;   --band-tv2:#E0392F;  --band-tv3:#F0757A;
  --band-tv4:#B04A4E;   --band-tv5:#747578;
  --band-fallback:#a99e91;
  --axis:#3a3a40;
  --node-fill:#000000;

  --bar-bg:rgba(0,0,0,.92);
  --bar-bg-2:rgba(0,0,0,.95);
  --scrim:rgba(0,0,0,.72);
  --shadow:rgba(0,0,0,.45);

  --sans:var(--sys-sans);
  --serif:var(--sys-serif);
}

/* ---------------------------------------------------------------------------
   THEME: STUDIO LIGHT — the same look on paper-white rather than black.
   Derived from the dark block token for token rather than invented, so the
   two studios stay the same DESIGN and differ only in where the light is.
   Brand red drops to #B8121A here: pure #E0392F measures 4.38:1 on white and
   fails AA as small text, the mirror of the problem --accent-ink solves in the
   dark theme. Both are contrast-driven UI tokens, not second brand reds — the
   v7 package's "one red literal" rule governs the mark, the icons and the
   wordmark, all of which are #E0392F and nothing else.
   Not animated, for the same reason studio is not: the write-on belongs to
   the paper themes.
   --------------------------------------------------------------------------- */
html[data-theme="studiolight"],
[data-theme="studiolight"]{
  /* paper metaphor — studio has no stock, so both textures are inert */
  --paper:#FBFAF7;
  --paper-edge:#ECEAE4;
  --paper-texture:none;
  --plate-texture:none;
  --pencil:#1A1A1C;
  --plate:#1A1A1C;
  --plate-deep:#FBFAF7;
  --plate-text:#FBFAF7;
  --plate-ink-2:#c9c9c9;      /* studio paints no cover; kept coherent anyway */
  --plate-line:var(--line);

  --bg:#FBFAF7;
  --bg-2:#FFFFFF;
  --bg-3:#F1EFEA;
  --line:#DAD7D0;
  --line-soft:#E8E5DF;
  --line-2:#B4B0A8;
  --ink:#16161A;
  --ink-2:#4A4A4F;          /* 7.8:1 on --bg-2 */
  --ink-3:#66666B;          /* 5.6:1 on --bg-2 */
  --order:#2B2B30;
  --chaos:var(--brand-red);
  --chaos-soft:var(--brand-red-deep);
  --ok:#5fa357;
  --warn:var(--brand-grey);
  --miss:var(--brand-red-deep);

  --accent:var(--brand-red);
  /* Third documented departure, and the same reason as --ink-2/--ink-3:
     brand red measures 4.27:1 on the raised surface, so as SMALL TEXT — links,
     the lit tab label, the 9.5px scope chips — it fails AA. --accent-ink and
     --link are a lifted tint used only where the colour has to be read as
     words. --accent itself stays pure brand red for borders and fills, where
     contrast rules do not apply. (Measured in themetest.mjs.) */
  --accent-ink:#B8121A;
  --accent-line:rgba(224,57,47,.45);
  --accent-wash:rgba(224,57,47,.13);
  --link:#B8121A;
  --btn-bg:var(--brand-red);
  --btn-ink:#fff;
  --on-band:#fff;

  --ok-bg:#E7F2E5;   --ok-line:#9DC298;  --ok-ink:#1F5A22;
  --bad-bg:#FBE9E9;  --bad-bg-soft:#F4DADA; --bad-line:#D89A9A; --bad-ink:#961015;
  --neutral-bg:#EFEDE8; --neutral-ink:#3F3F44;
  --miss-bg:var(--brand-red-deep); --miss-ink:#FFFFFF; --miss-line:#b3161c;

  --band-order:#8C8375; --band-chaos:#C4161C;
  --band-act1:#8C8375;  --band-act2:#C4161C;  --band-act3:#5E5F62;
  --band-sm1:#8C8375;   --band-sm2a:#C4161C;  --band-sm2b:#D2585D; --band-sm3:#5E5F62;
  --band-tv0:#A79C8E;   --band-tv1:#8C8375;   --band-tv2:#C4161C;  --band-tv3:#D2585D;
  --band-tv4:#8E3A3E;   --band-tv5:#5E5F62;
  --band-fallback:#8b8377;
  --axis:#C2BEB6;
  --node-fill:#FFFFFF;

  --bar-bg:rgba(251,250,247,.94);
  --bar-bg-2:rgba(255,255,255,.96);
  --scrim:rgba(30,28,24,.45);
  --shadow:rgba(30,28,24,.16);

  --sans:var(--sys-sans);
  --serif:var(--sys-serif);
}

/* ---------------------------------------------------------------------------
   THEME: COMPOSITION — newsprint stock, blue ruling, one red margin.
   Prompts are printed navy; answers are graphite.
   Every ink here is measured against the surface it actually lands on;
   themetest.mjs re-measures them rather than trusting these comments.
   --------------------------------------------------------------------------- */
html[data-theme="composition"],
[data-theme="composition"]{
  --paper:#E5E3DA;
  --paper-edge:#D5D2C6;
  --pencil:#3C4038;

  /* The marbled cover. Dense white speckle over near-black — this is the one
     texture that is meant to be seen, and it carries the top bars. */
  --plate:#16181A;
  --plate-deep:#0C0E0F;
  --plate-text:#EDEBE4;
  --plate-ink-2:#B9B6AE;      /* 8.9:1 on the plate */
  --plate-line:#3A3D40;
  --plate-texture:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='120'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.93 0 0 0 0 0.92 0 0 0 0 0.89 0 0 0 -2.4 1.15'/%3E%3C/filter%3E%3Crect width='300' height='120' filter='url(%23m)'/%3E%3C/svg%3E");

  /* Newsprint fibre. Sparse, low-alpha, and cool-toned to match the stock. */
  --paper-texture:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.29 0 0 0 0 0.30 0 0 0 0 0.27 0 0 0 -1.25 0.44'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)'/%3E%3C/svg%3E");

  --bg:#D5D2C6;
  --bg-2:#E5E3DA;
  --bg-3:#F1EFE7;
  --line:#C3BFAF;
  --line-soft:#D2CEBE;
  --line-2:#A9A493;
  --ink:#1D2A45;            /* 11.0:1 on --bg-2 */
  --ink-2:#49546D;          /*  5.1:1 */
  --ink-3:#57637E;          /*  4.6:1 */
  --order:#1D2A45;
  --chaos:#9C3F2E;
  --chaos-soft:#BE5A4E;
  --ok:#3F7A42;
  --warn:#7A6A2E;
  --miss:#8E2B22;

  --accent:#9C3F2E;
  --accent-ink:#8A3728;
  --accent-line:rgba(156,63,46,.42);
  --accent-wash:rgba(156,63,46,.10);
  --link:#8A3728;
  --btn-bg:#1D2A45;
  --btn-ink:#E5E3DA;
  --on-band:#F1EFE7;

  --ok-bg:#D7E3CE;   --ok-line:#8FAA83;  --ok-ink:#2F6B33;
  --bad-bg:#F0D9D3;  --bad-bg-soft:#F4E2DD; --bad-line:#BC8B7E; --bad-ink:#8E2B22;
  --neutral-bg:#DEDBD0; --neutral-ink:#45474A;
  --miss-bg:#8E2B22; --miss-ink:#F4EDE6; --miss-line:#6E1F18;

  --band-order:#445777; --band-chaos:#9C3F2E;
  --band-act1:#445777;  --band-act2:#9C3F2E;  --band-act3:#5C6169;
  --band-sm1:#445777;   --band-sm2a:#9C3F2E;  --band-sm2b:#7A6A2E; --band-sm3:#5C6169;
  --band-tv0:#6E7480;   --band-tv1:#445777;   --band-tv2:#9C3F2E;  --band-tv3:#7A6A2E;
  --band-tv4:#7B4A3C;   --band-tv5:#5C6169;
  --band-fallback:#5C6169;
  --axis:#9FB2CB;
  --node-fill:#E5E3DA;

  --bar-bg:rgba(229,227,218,.94);
  --bar-bg-2:rgba(229,227,218,.96);
  --scrim:rgba(22,24,26,.55);
  --shadow:rgba(22,24,26,.22);

  --sans:var(--label);
  --serif:var(--hand);
}

/* ---------------------------------------------------------------------------
   THEME: LEGAL PAD — canary stock, double red margin, blue ballpoint.
   The yellow is the whole identity; it is not desaturated to make anything
   else easier.
   --------------------------------------------------------------------------- */
html[data-theme="legalpad"],
[data-theme="legalpad"]{
  --paper:#F4E6A6;
  --paper-edge:#DCCA83;
  --pencil:#1D3E86;

  /* The chipboard backing every legal pad is glued to. Coarser and warmer
     than the composition marble, so the two themes never read as the same
     texture in a different colour. */
  --plate:#54402B;            /* kraft brown, not the composition near-black */
  --plate-deep:#3E2F1F;
  --plate-text:#F4E6A6;       /* 7.7:1 on the plate */
  --plate-ink-2:#D8C79A;      /* 5.9:1 */
  --plate-line:#7A5F3C;
  --plate-texture:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='120'%3E%3Cfilter id='c'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' seed='23' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.86 0 0 0 0 0.78 0 0 0 0 0.58 0 0 0 -1.9 0.82'/%3E%3C/filter%3E%3Crect width='260' height='120' filter='url(%23c)'/%3E%3C/svg%3E");

  /* Canary stock is smoother than newsprint — finer grain, warmer tint. */
  --paper-texture:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.05' numOctaves='4' seed='13' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.36 0 0 0 0 0.32 0 0 0 0 0.18 0 0 0 -1.3 0.42'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");

  --bg:#DCCA83;
  --bg-2:#F4E6A6;
  --bg-3:#FAF2D2;
  --line:#D0BE79;
  --line-soft:#E2D492;
  --line-2:#AD9C5C;
  --ink:#2A2A22;            /* 11.4:1 on --bg-2 */
  --ink-2:#55523F;          /*  6.2:1 */
  --ink-3:#64614A;          /*  5.0:1 */
  --order:#1D3E86;
  --chaos:#A83A2C;
  --chaos-soft:#C0453C;
  --ok:#3F7A42;
  --warn:#7A5A1E;
  --miss:#8E2B22;

  --accent:#B03B31;
  --accent-ink:#93332B;
  --accent-line:rgba(176,59,49,.45);
  --accent-wash:rgba(176,59,49,.12);
  --link:#1D3E86;
  --btn-bg:#2A2A22;
  --btn-ink:#F4E6A6;
  --on-band:#F4E6A6;

  --ok-bg:#DDE8B4;   --ok-line:#A8B87E;  --ok-ink:#2F6B33;
  --bad-bg:#F2DBC2;  --bad-bg-soft:#F6E6D3; --bad-line:#C79A72; --bad-ink:#8E2B22;
  --neutral-bg:#E7DCAE; --neutral-ink:#45443A;
  --miss-bg:#8E2B22; --miss-ink:#F7EFD8; --miss-line:#6E1F18;

  --band-order:#1D3E86; --band-chaos:#A83A2C;
  --band-act1:#1D3E86;  --band-act2:#A83A2C;  --band-act3:#4E4E44;
  --band-sm1:#1D3E86;   --band-sm2a:#A83A2C;  --band-sm2b:#7A5A1E; --band-sm3:#4E4E44;
  --band-tv0:#6B6B5C;   --band-tv1:#1D3E86;   --band-tv2:#A83A2C;  --band-tv3:#7A5A1E;
  --band-tv4:#8A4032;   --band-tv5:#4E4E44;
  --band-fallback:#4E4E44;
  --axis:#7E9AC0;
  --node-fill:#F4E6A6;

  --bar-bg:rgba(244,230,166,.94);
  --bar-bg-2:rgba(244,230,166,.96);
  --scrim:rgba(42,42,34,.55);
  --shadow:rgba(42,42,34,.24);

  --sans:var(--label);
  --serif:var(--hand);
}

*{box-sizing:border-box}
/* Several elements below set display:flex/grid, which would otherwise beat the
   [hidden] attribute. The app toggles visibility with .hidden = true, so this
   rule has to win. */
[hidden]{display:none !important}
html,body{margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  background:var(--bg);
  color:var(--ink);
  font-family:var(--sans);
  font-size:16px;
  line-height:1.5;
  padding-bottom:calc(var(--tabh) + env(safe-area-inset-bottom));
  -webkit-tap-highlight-color:transparent;
  overscroll-behavior-y:none;
}
h1,h2,h3{font-weight:600;letter-spacing:-0.01em}

/* ---------- app bar ---------- */
.appbar{
  position:sticky;top:0;z-index:30;
  padding:calc(10px + env(safe-area-inset-top)) 16px 10px;
  background:var(--bar-bg);
  backdrop-filter:saturate(140%) blur(10px);
  border-bottom:1px solid var(--line-soft);
}
.appbar-row{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  max-width:var(--maxw);margin:0 auto;
}
/* ---------- framework switcher ----------
   Three story frameworks with nothing above them read as three view tabs, so
   the group carries a label. The bar is a recessed panel rather than a flat
   strip: on the paper themes it sits on a textured cover, and without its own
   surface it disappeared into the marble entirely. */
.fwgroup{max-width:var(--maxw);margin:12px auto 0}
.fwlabel{
  font-size:10px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 5px 2px;
}
.fwbar{
  display:flex;gap:4px;padding:3px;
  background:var(--bg-2);border:1px solid var(--line-2);border-radius:11px;
  box-shadow:inset 0 1px 3px rgba(0,0,0,.35);
}
.fwopt{
  flex:1;appearance:none;background:transparent;border:0;color:var(--ink-3);
  font:inherit;font-size:13.5px;font-weight:600;padding:9px 6px;border-radius:9px;cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:background .15s ease,color .15s ease;
}
.fwopt.is-on{background:var(--bg-3);color:var(--ink);box-shadow:inset 0 0 0 1px var(--line-2)}
/* The mark no longer repaints per framework. Its identity is the app's, not
   the active sheet's — see the note beside .mark below. */
.brand{display:flex;align-items:center;gap:10px;min-width:0}
/* THE WORDMARK — brand package v7, the circular-o lockup, as outlines.
   Replaces the v0.31.0 setting in live Archivo 900: the first "o" IS the mark,
   which no font can set, so the lockup has to be drawn.

   Sized by HEIGHT and left to find its own width — the viewBox is
   `0 6.3 489 123.5`, an aspect of 3.96, and the package's whole reason for
   that box is that its 15-unit vertical padding is symmetric, so plain
   vertical centring is correct and no magic offset is needed. Hard-coding a
   width would re-introduce exactly the ratio assumption the package moved off.

   The <style> block that shipped inside the SVG lives here instead, with its
   selectors namespaced. Inlining an SVG puts its <style> into the DOCUMENT: as
   delivered, `.l` and `.dot` would have become global class selectors, and
   `.dot` already meant the wordmark's full stop in this stylesheet. */
.brand-name{
  margin:0;line-height:0;display:flex;align-items:center;min-width:0;
}
/* The wordmark is a button now. Everything a button brings — padding, border,
   background, the UA font — is stripped, because the artwork is the control
   and any chrome around it would be a second thing on the bar. The negative
   inline margin keeps the lockup optically flush left after the touch padding
   is added, so the bar looks unchanged. */
.brandbtn{
  appearance:none;background:none;border:0;padding:6px 8px;margin:-6px -8px;
  font:inherit;color:inherit;line-height:0;cursor:pointer;
  border-radius:8px;display:flex;align-items:center;min-width:0;
}
.brandbtn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
/* 26px — the height the standalone icon used to occupy. The wordmark is the
   only brand element in the bar now, so it takes that space rather than
   sitting beside it. Sized by HEIGHT and left to find its own width: the box
   is `0 6.3 489 123.5`, and hard-coding a width would reintroduce the ratio
   assumption that box exists to remove. */
.wordmark{
  height:26px;width:auto;display:block;overflow:visible;
}

/* THE MOTION, in two movements.

   FIRST the o-mark, carrying the animation the standalone icon used to: the
   arc strokes along its own length while the disc rises under it. Its dash
   length is in USER UNITS (no pathLength) — the arc centreline is r=264.4, so
   half its circumference is 830.8, rounded up to 832 so the gap covers it at
   frame zero.

   THEN the letters, starting once the mark has landed. They keep the delay
   indices the package shipped, so there is a gap where --i:2 would be — that
   gap is the o, which is already on screen. The rhythm reads as the mark
   arriving and the name assembling around it.

   `.wm-l{opacity:1}` with `both`, NOT `opacity:0` with `forwards`: the
   backwards fill still supplies opacity 0 through the delay, so the motion is
   identical, but anywhere CSS animation is ignored (GitHub's SVG sanitiser,
   most email) the wordmark renders VISIBLE rather than blank. An invisible
   logo is the worse failure by a distance.

   `overflow:visible` because the rise starts 14 units below the baseline. */
@media (prefers-reduced-motion: no-preference){
  .wm-disc{ animation:wm-rise-disc 420ms cubic-bezier(.2,.9,.3,1) both; }
  .wm-arc {
    stroke-dasharray:832;
    animation:wm-draw 520ms cubic-bezier(.2,.9,.3,1) 90ms both;
  }
  .wm-l{
    animation:wm-rise .55s cubic-bezier(.22,1,.36,1) both;
    animation-delay:calc(620ms + var(--i) * 70ms);
  }
  .wm-dot{
    animation:wm-pop .45s cubic-bezier(.34,1.56,.64,1) both;
    animation-delay:calc(620ms + var(--i) * 70ms + 120ms);
    transform-box:fill-box;transform-origin:center;
  }
}
@keyframes wm-draw{
  from{ stroke-dashoffset:832; }
  to  { stroke-dashoffset:0; }
}
@keyframes wm-rise-disc{
  from{ opacity:0; transform:translateY(3px); }
  to  { opacity:1; transform:none; }
}
@keyframes wm-rise{
  from{ opacity:0; transform:translateY(14px); }
  to  { opacity:1; transform:translateY(0); }
}
@keyframes wm-pop{
  from{ opacity:0; transform:scale(0); }
  60% { opacity:1; transform:scale(1.25); }
  to  { opacity:1; transform:scale(1); }
}

/* ---------- the mark ----------
   The standalone mark left the app bar in v0.34.0 — the wordmark's "o" IS the
   mark, so both on screen was the same shape twice. What survives here is the
   TOKEN, because the wordmark's o-mark still needs it.

   THE ARC IS A VALUE CONTRAST, NOT A RED. White on a dark app bar, ink on a
   light one. That is what makes the mark read as arc-over-disc rather than a
   red circle with a bite taken out of it, and it is the only theme-dependent
   element in the whole brand package. Three of the four app bars are dark, so
   white is the default and studiolight is the single override — a token rather
   than a selector list, so a fifth theme declares one value.

   The disc is #E0392F in every theme. It does not take --accent and must not:
   an identity colour that shifts per theme is not an identity colour. */
html[data-theme="studiolight"]{ --mark-arc:#0C0E0F; }

/* THE LETTERS ARE A TOKEN TOO, as of v0.41.0 — and this is a real departure
   from the package, so it is written down rather than left to be discovered.

   The package says one red on every ground. That held while every app bar the
   wordmark sat on was dark enough to carry it. Legalpad's is not: measured
   against its tan chipboard plate the red is 2.24:1, which the package itself
   only ever sanctioned as large display. On the one plate where the identity
   colour is the weakest thing on screen, the lockup goes white and the arc
   goes to ink — a value contrast, which is the same principle the arc has
   always followed, applied one level up.

   `fill` on the paths is a PRESENTATION attribute, so any CSS rule beats it
   without touching a single byte of path data. That is why this is three lines
   and not a re-export. */
.wm-l path{fill:var(--wm-ink, #E0392F)}
.wm-disc{fill:var(--wm-disc, #E0392F)}

html[data-theme="legalpad"]{
  --wm-ink:#FFFFFF;
  --wm-disc:#FFFFFF;
  --mark-arc:#0C0E0F;
}

/* ---------- layout ---------- */
#views{max-width:var(--maxw);margin:0 auto;padding:16px}
.view{display:none;animation:fade .18s ease}
.view.is-active{display:block}
@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.sec-h{font-size:13px;text-transform:uppercase;letter-spacing:.09em;color:var(--ink-3);margin:26px 0 10px}
.sec-h:first-child{margin-top:4px}

/* ---------- settings tabs ----------
   Deliberately NOT styled like the tab bar at the foot of the app. That one is
   navigation between the four things the app does; this is a filter inside one
   of them, and making them look alike would claim they are the same kind of
   choice. Underline, not a pill. */
.settabs{display:flex;gap:2px;margin:0 0 4px;border-bottom:1px solid var(--line)}
.settab{
  appearance:none;background:none;border:0;border-bottom:2px solid transparent;
  font:inherit;font-size:13.5px;font-weight:550;color:var(--ink-3);
  padding:10px 14px;margin-bottom:-1px;cursor:pointer;white-space:nowrap;
}
.settab:hover{color:var(--ink-2)}
.settab.is-on{color:var(--accent-ink);border-bottom-color:var(--accent)}
.settab:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;border-radius:6px 6px 0 0}
/* A pane's first heading sits under the rule, so it does not need the 26px a
   heading needs when it follows a body of text. */
.setpane .sec-h:first-child{margin-top:18px}
@media (max-width:420px){
  .settabs{gap:0}
  .settab{padding:10px 9px;font-size:13px}
}

/* ---------- buttons ---------- */
.btn{
  appearance:none;border:1px solid var(--line);background:var(--bg-2);color:var(--ink);
  font:inherit;font-weight:550;padding:12px 18px;border-radius:11px;cursor:pointer;
  transition:transform .06s ease, background .15s ease, border-color .15s ease;
  min-height:46px;
}
.btn:active{transform:scale(.985)}
.btn-primary{background:var(--btn-bg);color:var(--btn-ink);border-color:var(--btn-bg)}
.btn-got{background:var(--ok-bg);border-color:var(--ok-line);color:var(--ok-ink);flex:1}
.btn-miss{background:var(--bad-bg);border-color:var(--bad-line);color:var(--bad-ink);flex:1}
.btn-danger-ghost{background:transparent;border-color:var(--bad-line);color:var(--bad-ink)}
.btn[disabled]{opacity:.45;pointer-events:none}
.ghost-btn{
  appearance:none;background:transparent;border:1px solid var(--line);color:var(--ink-2);
  font:inherit;font-size:13px;padding:7px 12px;border-radius:20px;cursor:pointer;white-space:nowrap;
}
.ghost-btn:active{background:var(--bg-2)}
.linkish{background:none;border:0;color:var(--ink-3);font:inherit;font-size:12px;text-decoration:underline;cursor:pointer;padding:0}
.actions{display:flex;gap:10px;margin-top:14px;flex-wrap:wrap}
.actions .btn{flex:1;min-width:120px}

/* ---------- chips / segments / toggle ---------- */
.chipbar{display:flex;gap:6px}
.chip{
  appearance:none;background:var(--bg-2);border:1px solid var(--line);color:var(--ink-3);
  font:inherit;font-size:12.5px;padding:6px 11px;border-radius:20px;cursor:pointer;
}
.chip.is-on{background:var(--bg-3);color:var(--ink);border-color:var(--line-2)}
.segbar{display:flex;gap:0;border:1px solid var(--line);border-radius:11px;overflow:hidden;margin-bottom:16px}
.seg{
  flex:1;appearance:none;background:transparent;border:0;color:var(--ink-3);
  font:inherit;font-size:14px;padding:11px 8px;cursor:pointer;
}
.seg.is-on{background:var(--bg-3);color:var(--ink)}
.seg .count{
  display:inline-block;min-width:19px;padding:0 5px;margin-left:5px;
  background:var(--line);border-radius:9px;font-size:11px;color:var(--ink-2)
}

.toggle-wrap{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:8px}
.toggle-label{display:flex;flex-direction:column;gap:1px}
.toggle-label>span{font-size:13px;text-transform:uppercase;letter-spacing:.09em;color:var(--ink-3)}
.toggle{display:flex;border:1px solid var(--line);border-radius:22px;padding:3px;background:var(--bg-2)}
.toggle-opt{
  appearance:none;background:transparent;border:0;color:var(--ink-3);
  font:inherit;font-size:13.5px;font-weight:600;padding:8px 18px;border-radius:20px;cursor:pointer;
}
.toggle-opt.is-on{background:var(--btn-bg);color:var(--btn-ink)}
.rubric-line{
  font-size:13px;line-height:1.55;color:var(--ink-2);background:var(--bg-2);
  border-left:2px solid var(--chaos);border-radius:0 8px 8px 0;padding:10px 12px;margin:0 0 18px;
}

/* ---------- flashcard ---------- */
/* Centred when the row fits, scrollable when it does not. `safe center` is the
   part that matters: plain centring on an overflowing flex row pushes the first
   chip past the scroll origin, where it cannot be reached. */
.chipscroll{
  overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 -16px 12px;padding:0 16px;
  scrollbar-width:none;display:flex;justify-content:center;justify-content:safe center;
}
.chipscroll::-webkit-scrollbar{display:none}
/* flex:none is required. As a flex child of the centring row the bar would
   otherwise shrink to the container and the chips would wrap their labels
   onto two lines instead of scrolling. */
.chipscroll .chipbar{flex:none;flex-wrap:nowrap;width:max-content;max-width:none}
.drill-meta{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:12px;
  font-size:12px;color:var(--ink-3)}

/* drill timer */
.timerwrap{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.timertrack{flex:1;height:4px;background:var(--bg-3);border-radius:3px;overflow:hidden}
.timertrack i{display:block;height:100%;width:100%;background:var(--order);
  transition:width .1s linear,background .3s ease}
.timertrack i.is-low{background:var(--chaos)}
.timertext{font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums;min-width:30px;text-align:right}
.hint.is-warn{color:var(--bad-ink)}
.card-answer.is-timeout{color:var(--bad-ink)}

.card{
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px;min-height:230px;display:flex;flex-direction:column;
}
.card-kicker{font-size:11.5px;text-transform:uppercase;letter-spacing:.11em;color:var(--ink-3);margin-bottom:14px}
.card-face{font-family:var(--serif);font-size:27px;line-height:1.3;color:var(--ink)}
.card-back{margin-top:18px;padding-top:16px;border-top:1px dashed var(--line);animation:fade .2s ease}
.card-answer{font-family:var(--serif);font-size:23px;color:var(--order);margin-bottom:8px}
.card-gloss{font-size:14.5px;color:var(--ink-2);margin:0 0 10px}
.card-cue{font-size:13px;color:var(--ink-3);margin:0;font-style:italic}
.card-foot{margin-top:auto;padding-top:16px}
.weightpill{font-size:11px;color:var(--ink-3);border:1px solid var(--line);border-radius:20px;padding:3px 9px}

.hint{font-size:12.5px;color:var(--ink-3);margin-top:14px;line-height:1.5}

/* ---------- quiz ---------- */
.beatcard{background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:20px;margin-bottom:16px}
.beat-text{font-family:var(--serif);font-size:20px;line-height:1.42;margin:0}
.beat-src{font-size:11.5px;color:var(--ink-3);margin:12px 0 0}
.choicegrid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-top:14px}
.choicegrid--num{grid-template-columns:repeat(5,1fr)}
.choicegrid .opt{
  appearance:none;background:var(--bg-2);border:1px solid var(--line);color:var(--ink);
  font:inherit;font-size:15px;font-weight:550;padding:14px 10px;border-radius:11px;cursor:pointer;text-align:left;
  min-height:48px;
}
.choicegrid--num .opt{text-align:center;font-family:var(--serif);font-size:19px;padding:12px 4px}
.choicegrid .opt .num{color:var(--ink-3);font-size:12px;margin-right:7px}
.choicegrid .opt.correct{border-color:var(--ok);background:var(--ok-bg);color:var(--ok-ink)}
.choicegrid .opt.wrong{border-color:var(--bad-line);background:var(--bad-bg);color:var(--bad-ink)}
.choicegrid.locked .opt{pointer-events:none}
.verdict{margin-top:16px;background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:18px}
.verdict-head{font-weight:650;margin-bottom:8px}
.verdict-head.good{color:var(--ok-ink)}
.verdict-head.bad{color:var(--bad-ink)}
.verdict-body{font-size:14.5px;color:var(--ink-2);margin:0 0 8px}
.verdict-note{font-size:14px;color:var(--ink);margin:0 0 14px;padding-left:11px;border-left:2px solid var(--line)}
.verdict-note:empty{display:none}

/* ---------- forms ---------- */
.field{display:block;margin-bottom:14px}
.field>span{display:block;font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-3);margin-bottom:6px}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
input[type=text],input[type=password],textarea,select{
  width:100%;background:var(--bg-2);border:1px solid var(--line);border-radius:11px;
  color:var(--ink);font:inherit;font-size:16px;padding:12px 13px;
}
textarea{resize:vertical;line-height:1.5}
input:focus,textarea:focus,select:focus{outline:2px solid var(--chaos-soft);outline-offset:1px;border-color:var(--chaos-soft)}
select{appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--ink-3) 50%),linear-gradient(135deg,var(--ink-3) 50%,transparent 50%);background-position:calc(100% - 18px) 22px,calc(100% - 13px) 22px;background-size:5px 5px;background-repeat:no-repeat}

.notice{
  background:var(--bg-2);border:1px solid var(--line);border-left:3px solid var(--chaos);
  border-radius:0 10px 10px 0;padding:12px 14px;font-size:13px;line-height:1.55;color:var(--ink-2);margin-bottom:16px;
}
.notice strong{color:var(--ink)}
.notice-warn{border-left-color:var(--accent)}
code{background:var(--bg-3);padding:1px 5px;border-radius:5px;font-size:12.5px}

.beatform{margin-bottom:22px}
.beatlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.beatlist li{background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:13px 14px}
.beatlist .bl-top{display:flex;justify-content:space-between;gap:10px;align-items:flex-start}
.beatlist .bl-text{font-size:14.5px;line-height:1.45;margin:0}
.beatlist .bl-meta{font-size:11.5px;color:var(--ink-3);margin-top:7px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.stepdot{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--ink-2);border:1px solid var(--line);border-radius:20px;padding:2px 8px}
.stepdot i{width:6px;height:6px;border-radius:50%;display:inline-block}
.bl-actions{display:flex;gap:6px;flex:none}
.icon-btn{appearance:none;background:transparent;border:1px solid var(--line);color:var(--ink-3);border-radius:8px;width:32px;height:32px;cursor:pointer;font-size:13px;line-height:1}

.empty{text-align:center;padding:42px 18px;border:1px dashed var(--line);border-radius:var(--radius)}
.empty h2{font-size:18px;margin:0 0 8px}
.empty p{font-size:14px;color:var(--ink-2);margin:0 auto 18px;max-width:38ch;line-height:1.55}

/* ---------- analyze result ---------- */
.status{font-size:14px;padding:14px;border-radius:11px;margin-top:16px;border:1px solid var(--line);background:var(--bg-2);color:var(--ink-2)}
.status.err{border-color:var(--bad-line);background:var(--bad-bg-soft);color:var(--bad-ink)}
.result-head{display:flex;align-items:center;justify-content:space-between;margin:26px 0 12px}
.result-head h2{font-size:16px;margin:0}
.mode-badge{font-size:11px;text-transform:uppercase;letter-spacing:.09em;border:1px solid var(--line);border-radius:20px;padding:4px 10px;color:var(--ink-2)}
.rows{display:flex;flex-direction:column;gap:8px}
.row{display:grid;grid-template-columns:auto 1fr;gap:12px;background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:13px 14px}
.row-l{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:88px}
.row-step{font-weight:650;font-size:14.5px}
.row-num{font-size:11px;color:var(--ink-3)}
.badge{font-size:10.5px;font-weight:700;letter-spacing:.08em;padding:3px 8px;border-radius:5px;text-transform:uppercase}
.badge.PRESENT{background:var(--ok-bg);color:var(--ok-ink);border:1px solid var(--ok-line)}
.badge.WEAK{background:var(--neutral-bg);color:var(--neutral-ink);border:1px solid var(--line-2)}
.badge.MISSING{background:var(--miss-bg);color:var(--miss-ink);border:1px solid var(--miss-line)}
.row-r{font-size:14px;color:var(--ink-2);line-height:1.5;align-self:center}
.overall{font-size:14px;color:var(--ink-2);line-height:1.6;margin-top:16px;padding:14px;background:var(--bg-2);border-radius:11px;border:1px solid var(--line)}
.overall:empty{display:none}

/* ---------- teaching cases ----------
   Deliberately quieter than the result it sits beside: this is a check on the
   TOOL, and it must never read as a verdict on your story. */
.calib{margin-top:14px;border:1px solid var(--line);border-radius:11px;background:var(--bg-2);padding:0 14px}
.calib > summary{cursor:pointer;padding:12px 0;font-size:13.5px;font-weight:600;color:var(--ink-2);list-style-position:inside}
.calib[open] > summary{border-bottom:1px solid var(--line);margin-bottom:12px}
.calib .hint{margin:0 0 12px}
.calib .field{margin-bottom:10px}
.calib .actions{margin:0 0 14px}
.calib-note{font-size:13px;line-height:1.55;color:var(--ink-2);background:var(--bg-3);border-radius:9px;padding:11px 12px;margin:0 0 12px}
.calib-note:empty{display:none}

.calib-score{margin-top:16px;border:1px solid var(--line);border-left-width:3px;border-radius:11px;background:var(--bg-2);padding:14px}
.calib-score.is-match{border-left-color:var(--ok-line)}
.calib-score.is-miss{border-left-color:var(--bad-line)}
.calib-score-h{font-size:13px;font-weight:700;letter-spacing:.02em;margin-bottom:10px}
.calib-score.is-match .calib-score-h{color:var(--ok-ink)}
.calib-score.is-miss .calib-score-h{color:var(--bad-ink)}
.calib-row{display:flex;flex-wrap:wrap;gap:6px 12px;align-items:baseline;font-size:13px;padding:7px 0;border-top:1px solid var(--line)}
.calib-step{font-weight:620;flex:1 1 40%}
.calib-want,.calib-got{font-size:11.5px;color:var(--ink-3);font-family:var(--serif)}
.calib-row.is-off .calib-got{color:var(--bad-ink)}
.calib-row.is-ok .calib-got{color:var(--ok-ink)}
.calib-foot{font-size:12.5px;color:var(--ink-3);line-height:1.55;margin:11px 0 0}

/* ---------- walk through a script ---------- */
.walk-h{font-size:15px;margin:26px 0 8px;padding-top:18px;border-top:1px solid var(--line)}
.walkfit{border:1px solid var(--line);border-left-width:3px;border-radius:11px;background:var(--bg-2);padding:13px 14px;margin-bottom:9px}
.walkfit.is-top{border-left-color:var(--ok-line);background:var(--ok-bg)}
.walkfit-h{display:flex;flex-wrap:wrap;gap:6px 10px;align-items:baseline;margin-bottom:7px}
.walkfit-rank{font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.walkfit.is-top .walkfit-rank{color:var(--ok-ink)}
.walkfit-name{font-weight:650;font-size:15px;flex:1}
.walkfit-score{font-size:11.5px;color:var(--ink-3);font-family:var(--serif)}
.walkfit-overall{font-size:13.5px;color:var(--ink-2);line-height:1.55;margin:0 0 7px}
.walkfit-overall:empty{display:none}
.walkfit-gaps{font-size:12.5px;color:var(--ink-3);line-height:1.5;margin:0}

.walkbeats-h{font-size:12px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-3);margin:16px 0 8px}
.walkbeat{border:1px solid var(--line);border-radius:11px;background:var(--bg-2);padding:11px 12px;margin-bottom:8px}
/* A flagged beat is marked, not hidden and not blocked — the judgement is the
   writer's, and a silent drop teaches nothing about why it was wrong. */
.walkbeat.is-flagged{border-color:var(--bad-line);background:var(--bad-bg-soft)}
.walkbeat-top{display:flex;align-items:center;gap:9px;cursor:pointer;margin-bottom:7px}
.walkbeat-top input{width:17px;height:17px;flex:none;accent-color:var(--ok)}
.walkbeat-step{font-weight:620;font-size:13.5px;flex:1}
.walkbeat-count{font-size:11px;color:var(--ink-3);font-family:var(--serif);flex:none}
.walkbeat-count.is-over{color:var(--bad-ink);font-weight:700}
.walkbeat-text{width:100%;box-sizing:border-box;font:inherit;font-size:13.5px;line-height:1.5;
  color:var(--ink);background:var(--bg);border:1px solid var(--line);border-radius:8px;padding:8px 9px;resize:vertical}
.walkbeat-why{font-size:12px;color:var(--ink-3);line-height:1.5;margin:7px 0 0}
.walkbeat-flag{font-size:12px;color:var(--bad-ink);line-height:1.5;margin:6px 0 0;font-weight:600}

.run-notes{font-size:12.5px;color:var(--ink-2);line-height:1.5;margin:8px 0 0;padding-left:9px;border-left:2px solid var(--line-2)}
.run-notes:empty{display:none}
.run-stub{font-size:11.5px;color:var(--ink-3);margin:6px 0 0}

/* ---------- first-run tour ---------- */
#tour{position:fixed;inset:0;z-index:120;pointer-events:none}
/* The scrim dims but does NOT block: the ring has to read as pointing at a
   live app, and clicking out is a legitimate way to leave. */
.tour-scrim{position:absolute;inset:0;background:rgba(0,0,0,.45);pointer-events:auto}
.tour-ring{
  position:absolute;border:2px solid var(--accent);border-radius:12px;
  box-shadow:0 0 0 9999px rgba(0,0,0,.45);
  transition:top .22s ease,left .22s ease,width .22s ease,height .22s ease;
  pointer-events:none;
}
/* The ring's own box-shadow IS the scrim once a step is showing, so the flat
   one underneath only covers the gap before the first placement. */
#tour .tour-scrim{background:transparent}
.tour-card{
  position:absolute;width:min(320px, calc(100vw - 24px));
  background:var(--bg-2);border:1px solid var(--line-2);border-radius:14px;
  padding:15px 16px;box-shadow:0 14px 40px rgba(0,0,0,.5);pointer-events:auto;
  transition:top .22s ease,left .22s ease;
}
.tour-count{font-size:10.5px;text-transform:uppercase;letter-spacing:.09em;color:var(--ink-3)}
.tour-title{font-size:16px;margin:5px 0 7px}
.tour-body{font-size:13.5px;color:var(--ink-2);line-height:1.55;margin:0}
.tour-actions{display:flex;align-items:center;gap:8px;margin-top:14px}
.tour-spacer{flex:1}
.tour-actions .btn{min-height:38px;padding:8px 14px;font-size:13.5px;flex:none;min-width:0}
.tour-skip{font-size:12.5px}
@media (max-width: 480px){
  .tour-card{width:calc(100vw - 24px)}
}

/* ---------- framework toggles ---------- */
.fwtoggles{display:flex;flex-direction:column;gap:8px;margin-bottom:6px}
.fwtoggle{
  display:flex;gap:11px;align-items:flex-start;cursor:pointer;
  background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:12px 13px;
}
.fwtoggle input{width:18px;height:18px;flex:none;margin-top:2px;accent-color:var(--accent)}
.fwtoggle input:disabled{cursor:not-allowed}
/* A switched-off framework is dimmed, not hidden — the point of the list is
   seeing what you have turned off. */
.fwtoggle.is-off{opacity:.55}
.fwtoggle-body{display:flex;flex-direction:column;gap:3px;min-width:0}
.fwtoggle-name{font-weight:640;font-size:14.5px}
.fwtoggle-meta{font-size:11.5px;color:var(--ink-3);font-family:var(--serif)}
.fwtoggle-blurb{font-size:12.5px;color:var(--ink-2);line-height:1.5}
.fwtoggle-lock{font-size:11px;color:var(--ink-3);font-style:italic;flex:none;align-self:center}

/* ---------- colophon ----------
   A table of facts, not prose: <dl> with a tracked-caps label column and an
   ink answer column. It replaced a stack of <h3>/<p> blocks in v0.35.0 — the
   old shape read as an essay, which is exactly what nobody reads.

   EVERY COLOUR HERE IS AN EXISTING TOKEN. No new values, so all four themes
   are covered by the tokens they already declare, and the contrast tests that
   walk each theme cover this block for free.

   One deliberate departure from the supplied mockup: the links take --link,
   not --accent-ink. Legalpad routes --link to blue ballpoint on purpose while
   its --accent-ink is a red-brown; using --accent-ink here would have quietly
   overridden that theme's own decision about what a link looks like. The
   underline keeps --accent, which is what the mockup was really after. */
.colophon{
  margin-top:18px;border-top:1px solid var(--line);padding-top:20px;
  font-family:var(--label);
}

.colo-mast{
  display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 12px;
  padding-bottom:14px;margin-bottom:18px;border-bottom:1px solid var(--line);
}
.colo-mast b{
  font-size:15px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink);
}
.colo-mast span{
  font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-2);
}
.colo-mast .colo-ver{
  margin-left:auto;font-variant-numeric:tabular-nums;
  color:var(--ink-2);font-size:10px;letter-spacing:.12em;
}

.colophon dl{margin:0;display:grid;grid-template-columns:132px minmax(0,1fr);gap:0}
.colophon dt{
  font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-2);
  padding:11px 0;border-top:1px solid var(--line);
}
.colophon dd{
  margin:0;padding:11px 0;border-top:1px solid var(--line);
  font-size:11px;line-height:1.75;color:var(--ink);max-width:62ch;
}
.colophon dt:first-of-type,.colophon dd:first-of-type{border-top:0}
.colo-credit{display:block}
.colo-credit i{font-style:normal;color:var(--ink-2)}
.colophon dd small{
  display:block;font-size:10px;color:var(--ink-2);line-height:1.7;margin-top:5px;
}
.colophon dd code{font-size:10px;color:var(--ink-2);font-family:var(--label)}

.colophon a{
  color:var(--link);text-decoration:none;
  border-bottom:1px solid var(--accent);padding-bottom:1px;
}
.colophon a:hover{border-bottom-width:2px}
.colophon a:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* The fold. Everything except the Frameworks credit lives in here — see the
   note in colophon.js for why that one row stays open. The inner <dl> reuses
   the grid above it, so open and closed look like one table rather than two. */
.colo-fold{margin-top:0}
.colo-fold > summary{
  list-style:none;cursor:pointer;
  padding:11px 0;border-top:1px solid var(--line);
  font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-2);
  display:flex;align-items:center;gap:8px;
}
.colo-fold > summary::-webkit-details-marker{display:none}
.colo-fold > summary::after{
  content:'+';font-size:12px;letter-spacing:0;line-height:1;color:var(--ink-3);
}
.colo-fold[open] > summary::after{content:'–'}
.colo-fold > summary:hover{color:var(--ink)}
.colo-fold > summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.colo-fold dt:first-of-type,.colo-fold dd:first-of-type{border-top:1px solid var(--line)}

.colo-rights{
  margin:18px 0 0;padding-top:14px;border-top:1px solid var(--line);
  font-size:10px;letter-spacing:.1em;color:var(--ink-2);
}

/* One column below 560px. The label sits directly over its answer rather than
   beside it, and the rule moves to the label so each fact still reads as a
   discrete row instead of a run-on. */
@media (max-width:560px){
  .colophon dl{grid-template-columns:1fr}
  .colophon dt{padding-bottom:2px;border-top:1px solid var(--line)}
  .colophon dd{padding-top:4px;border-top:0}
  .colophon dt:first-of-type{border-top:0}
}

/* At the foot of the reference sheet it is a footnote, not a section. */
.sheet .colophon{margin-top:22px;font-size:.95em}

/* ---------- dashboard ---------- */
.statrow{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:18px}
.stat{background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:14px 10px;text-align:center}
.stat b{display:block;font-size:24px;font-family:var(--serif);font-weight:500}
.stat span{display:block;font-size:11px;color:var(--ink-3);margin-top:3px}
.steptable{display:flex;flex-direction:column;gap:7px}
.srow{background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:12px 14px}
.srow-top{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.srow-name{font-weight:600;font-size:15px}
.srow-name .n{color:var(--ink-3);font-size:12px;margin-right:6px}
.srow-pct{font-family:var(--serif);font-size:17px}
.bar{height:5px;background:var(--bg-3);border-radius:3px;overflow:hidden;margin-top:9px;display:flex}
.bar i{display:block;height:100%}
.bar .b-drill{background:var(--order)}
.bar .b-quiz{background:var(--chaos)}
.srow-sub{font-size:11.5px;color:var(--ink-3);margin-top:7px;display:flex;gap:12px;flex-wrap:wrap}
.legend{display:flex;gap:14px;font-size:11.5px;color:var(--ink-3);margin:12px 0 4px}
.legend i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:5px;vertical-align:middle}

.runlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.runlist li{background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:13px 14px}
.run-top{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap}
.run-date{font-size:12.5px;color:var(--ink-2)}
.run-tally{display:flex;gap:6px;font-size:11px}
.run-tally span{border-radius:5px;padding:2px 7px;font-weight:650}
.t-p{background:var(--ok-bg);color:var(--ok-ink)}
.t-w{background:var(--neutral-bg);color:var(--neutral-ink)}
.t-m{background:var(--miss-bg);color:var(--miss-ink)}
.run-prev{font-size:13px;color:var(--ink-3);margin:9px 0 0;line-height:1.45}
.run-steps{display:flex;gap:4px;margin-top:10px}
.run-steps i{flex:1;height:6px;border-radius:2px}
.i-PRESENT{background:var(--ok)}.i-WEAK{background:var(--warn)}.i-MISSING{background:var(--chaos)}
.trendbox{background:var(--bg-2);border:1px solid var(--line);border-radius:11px;padding:14px;margin-bottom:14px;font-size:13px;color:var(--ink-2);line-height:1.6}
.trendbox b{color:var(--ink)}

/* ---------- tab bar ---------- */
.tabbar{
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  display:flex;background:var(--bar-bg-2);
  backdrop-filter:saturate(140%) blur(12px);
  border-top:1px solid var(--line-soft);
  padding-bottom:env(safe-area-inset-bottom);
}
.tab{
  flex:1;appearance:none;background:none;border:0;color:var(--ink-3);
  font:inherit;font-size:10.5px;letter-spacing:.02em;
  display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:9px 2px;height:var(--tabh);cursor:pointer;
}
.tab .ti{font-size:17px;line-height:1}
.tab.is-on{color:var(--accent-ink)}

/* ---------- sheet / modal ---------- */
.scrim{position:fixed;inset:0;background:var(--scrim);z-index:50;animation:fade .15s ease}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:60;max-height:86vh;
  background:var(--bg-2);border-top:1px solid var(--line);
  border-radius:18px 18px 0 0;display:flex;flex-direction:column;
  animation:slideup .22s cubic-bezier(.2,.8,.3,1);
  padding-bottom:env(safe-area-inset-bottom);
}
@keyframes slideup{from{transform:translateY(100%)}to{transform:none}}
.sheet-grab{width:38px;height:4px;background:var(--line);border-radius:3px;margin:9px auto 2px}
.sheet-head{display:flex;align-items:center;justify-content:space-between;padding:8px 18px 12px;border-bottom:1px solid var(--line-soft)}
.sheet-head h2{font-size:16px;margin:0}
.sheet-head-btns{display:flex;align-items:center;gap:6px;flex-shrink:0}
.sheet-body{overflow-y:auto;padding:14px 18px 26px;-webkit-overflow-scrolling:touch}
.axis-key{display:flex;gap:16px;font-size:11.5px;color:var(--ink-3);margin-bottom:14px}
.sw{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;vertical-align:middle}
.sw-order{background:var(--order)}.sw-chaos{background:var(--chaos)}
.reflist{list-style:none;margin:0;padding:0;counter-reset:s}
.reflist li{position:relative;padding:0 0 18px 34px;border-left:1px solid var(--line);margin-left:9px}
.reflist li:last-child{border-left-color:transparent;padding-bottom:4px}
.reflist li::before{
  counter-increment:s;content:counter(s);
  position:absolute;left:-10px;top:0;width:20px;height:20px;border-radius:50%;
  background:var(--bg-3);border:1px solid var(--line);color:var(--ink-2);
  font-size:11px;display:flex;align-items:center;justify-content:center;
}
.reflist li.chaos::before{border-color:var(--brand-red);color:var(--brand-red)}
.ref-name{font-family:var(--serif);font-size:19px;color:var(--ink)}
.ref-harmon{font-size:14.5px;color:var(--order);margin:2px 0 6px}
.ref-gloss{font-size:13.5px;color:var(--ink-2);margin:0 0 6px;line-height:1.55}
.ref-cue{font-size:12.5px;color:var(--ink-3);margin:0;font-style:italic}
.credit{font-size:11.5px;color:var(--ink-3);line-height:1.55;margin-top:18px}

.modal{
  position:fixed;z-index:60;left:50%;top:50%;transform:translate(-50%,-50%);
  width:calc(100% - 40px);max-width:440px;max-height:80vh;overflow-y:auto;
  background:var(--bg-2);border:1px solid var(--line);border-radius:16px;padding:22px;
}
.modal h2{font-size:17px;margin:0 0 12px}
.modal p{font-size:14px;color:var(--ink-2);line-height:1.6;margin:0 0 12px}

.toast{
  position:fixed;left:50%;bottom:calc(var(--tabh) + 18px + env(safe-area-inset-bottom));
  transform:translateX(-50%);z-index:70;
  background:var(--bg-3);border:1px solid var(--line);border-radius:22px;
  padding:10px 18px;font-size:13.5px;box-shadow:0 8px 26px var(--shadow);
  animation:fade .15s ease;max-width:calc(100% - 32px);text-align:center;
}

@media (min-width:700px){
  .tabbar{position:sticky;top:auto;border-radius:0}
  .card-face{font-size:30px}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

/* ==================== THE WHEEL (Story Circle) ==================== */
.wheel{display:block;width:100%;max-width:330px;margin:4px auto 6px;overflow:visible}
.wheel-node{cursor:pointer}
.wheel-node:focus{outline:none}
.wheel-node:focus circle{stroke-width:4}
.wheel-node:active circle{fill:var(--bg-3)}
.wt-num{fill:var(--ink);font-size:12px;font-weight:600;font-family:var(--sans)}
.wt-name{fill:var(--ink-2);font-size:11.5px;font-family:var(--sans)}
.wt-axis{fill:var(--ink-3);font-size:8.5px;letter-spacing:.14em;font-family:var(--sans)}
.wt-mid{fill:var(--ink-3);font-size:9px;letter-spacing:.1em;font-family:var(--sans)}

/* ================= THE TIMELINE (Save the Cat!) ================= */
.timeline{margin:2px 0 10px}
.tl-bands{display:flex;gap:3px;margin-bottom:12px}
.tl-band{
  padding:6px 8px;border-radius:6px;font-size:10.5px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;color:var(--on-band);text-align:center;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  appearance:none;border:0;font-family:inherit;line-height:1.2;
}
button.tl-band{cursor:pointer}
button.tl-band:active{filter:brightness(.92)}
button.tl-band:focus-visible{outline:2px solid var(--focus,currentColor);outline-offset:2px}
.tl-pins{display:flex;flex-direction:column;gap:4px}
.tl-pin{
  display:flex;align-items:baseline;gap:9px;width:100%;text-align:left;
  appearance:none;background:var(--bg-3);border:1px solid var(--line);
  border-left:3px solid var(--line);border-radius:0 8px 8px 0;
  color:var(--ink);font:inherit;font-size:13.5px;padding:8px 11px;cursor:pointer;
}
.tl-pin:active{background:var(--line-soft)}
.tl-pin-n{color:var(--ink-3);font-size:11px;min-width:16px;font-variant-numeric:tabular-nums}
.tl-pin-name{flex:1;font-weight:550}
.tl-pin-page{color:var(--ink-3);font-size:11px;white-space:nowrap}

/* reference list tweaks for both frameworks */
.reflist li{border-left:2px solid var(--line);padding-left:16px;margin-left:0;transition:background .3s ease}
.reflist li::before{display:none}
.reflist li.is-lit{background:var(--accent-wash);border-radius:0 8px 8px 0}
.ref-name{display:flex;align-items:baseline;gap:8px}
.ref-num{
  font-family:var(--sans);font-size:11px;color:var(--ink-3);
  border:1px solid var(--line);border-radius:20px;padding:1px 7px;flex:none;
}
.ref-page{margin-left:auto;font-family:var(--sans);font-size:11px;color:var(--ink-3);flex:none}

/* ==================== PROGRESS PERIODS ==================== */
.periodbar{margin-bottom:8px}
.periodnote{font-size:11.5px;color:var(--ink-3);margin:0 0 16px;line-height:1.5}
.srow{border-left:3px solid var(--line)}


/* ==================== BRAND BLOCKS ==================== */
.about{
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px 18px;text-align:center;
}
.about-logo{display:block;margin:15px 0 5px;line-height:0}
.about-logo img{display:inline-block;height:28px;width:auto}
.about-name{font-size:16px;font-weight:650;letter-spacing:-0.015em}
.about-by{font-size:13.5px;color:var(--ink-2);margin-top:3px}
.about-tag{font-size:12.5px;color:var(--ink-3);margin-top:7px;font-style:italic}
a{color:var(--link);text-underline-offset:2px}
a:active{opacity:.7}
.sheet-brand{
  margin-top:10px;padding-top:10px;border-top:1px solid var(--line-soft);
  letter-spacing:.04em;
}


/* ---------- per-framework settings labelling ---------- */
.scope-chip{
  display:inline-block;margin-left:8px;padding:2px 8px;border-radius:20px;
  font-size:9.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  background:var(--accent-wash);color:var(--accent-ink);border:1px solid var(--accent-line);
  vertical-align:middle;
}
.scope-chip.scope-global{
  background:var(--bg-3);color:var(--ink-3);border-color:var(--line);
}
.notice-scoped{border-left-color:var(--accent)}

/* bundled starter beats are visibly distinct from your own */
.starter-tag{
  font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--accent-ink);border:1px solid var(--accent-line);
  background:var(--accent-wash);border-radius:20px;padding:2px 7px;
}

.kbd{
  display:inline-block;margin-left:5px;padding:1px 5px;border-radius:4px;
  font-family:var(--sans);font-size:10px;font-weight:700;line-height:1.4;
  background:var(--bg-3);border:1px solid var(--line);color:var(--ink-3);
}

/* ---------- stories in play ---------- */
.workswitch{
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);
  padding:14px;margin-top:18px;
}
.workswitch-top{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.workswitch-h{font-size:14px;margin:0;font-weight:650}
.workswitch .hint{margin-top:8px}
.worklist{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
.workitem{
  display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  appearance:none;background:var(--bg-3);border:1px solid var(--line);
  border-radius:10px;color:var(--ink-3);font:inherit;font-size:13.5px;
  padding:9px 11px;cursor:pointer;
}
.workitem.is-on{color:var(--ink);border-color:var(--line-2)}
.workitem-box{
  flex:none;width:18px;height:18px;border-radius:5px;
  border:1px solid var(--line-2);background:transparent;
  display:flex;align-items:center;justify-content:center;
  font-size:11px;line-height:1;color:var(--btn-ink);
}
.workitem.is-on .workitem-box{background:var(--accent);border-color:var(--accent);color:var(--btn-ink)}
.workitem-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.workitem-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.workitem-by{font-size:11px;color:var(--ink-3)}
.workitem-n{
  flex:none;font-size:11px;color:var(--ink-3);border:1px solid var(--line);
  border-radius:20px;padding:1px 8px;font-variant-numeric:tabular-nums;
}
/* A story switched off leaves the bank list entirely, so there is no longer a
   dimmed-and-struck "not in play" state to style here. */

/* ---------- beat bank tools ---------- */
.banktools{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:18px}
.banktools .field{margin-bottom:6px}
/* Group headers have to be findable while thumbing a 100-beat list, so they
   are full-size type on a ruled band rather than small caps. */
.bl-group{
  background:var(--bg-2) !important;
  border:1px solid var(--line) !important;
  border-left:4px solid var(--accent) !important;
  border-radius:0 10px 10px 0 !important;
  padding:12px 14px !important;
  margin-top:20px;
}
.beatlist > .bl-group:first-child{margin-top:2px}
.bl-group.is-story{border-left-color:var(--order) !important}
.bl-group-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.bl-group-title{
  font-size:16px;font-weight:700;letter-spacing:-0.01em;color:var(--ink);
  text-align:left;line-height:1.25;
}
.bl-group-sub{font-size:12.5px;color:var(--ink-3);margin-top:3px;line-height:1.4}
.bl-group b{
  font-size:11px;color:var(--ink);background:var(--bg-3);
  border:1px solid var(--line);border-radius:20px;padding:2px 9px;flex:none;font-weight:700;
}

/* tappable source work */
.srclink{
  appearance:none;background:none;border:0;padding:0;font:inherit;
  color:var(--link);text-decoration:underline;text-underline-offset:2px;cursor:pointer;
}
.srclink::after{content:' ⓘ';text-decoration:none;font-size:.95em}
.srclink-plain{appearance:none;background:none;border:0;padding:0;font:inherit;cursor:pointer}
.srclink-plain::after{content:' ⓘ';color:var(--link);font-size:.8em;vertical-align:middle}
.srchint{margin-left:8px;font-size:11px;color:var(--ink-3);font-style:italic}
.work-by{font-size:12.5px;color:var(--ink-3);letter-spacing:.03em;margin:0 0 10px !important}
.work-note{
  font-size:12.5px;color:var(--ink-3);border-top:1px solid var(--line);
  padding-top:10px;margin-top:14px !important;font-style:italic;
}
.work-more{margin:14px 0 0;font-size:14px}
.work-more a{color:var(--link);font-weight:600}

.beatform{margin-top:4px}
.notice .linkish{margin-left:4px}

/* pre-release version badge */
.about-ver{margin-top:14px}
.verpill{
  display:inline-block;padding:3px 10px;border-radius:20px;
  font-size:11px;font-weight:700;letter-spacing:.06em;
  background:var(--accent-wash);color:var(--accent-ink);
  border:1px solid var(--accent-line);
}
.verpill-sm{font-size:9.5px;padding:1px 7px;letter-spacing:.05em}
.about-ver-note{font-size:11.5px;color:var(--ink-3);margin-top:7px}

/* explain-a-miss */
.btn-explain{width:100%;margin-bottom:12px;border-color:var(--bad-line);color:var(--bad-ink);background:var(--bad-bg-soft)}
.ex-h{
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);
  margin:18px 0 6px;font-weight:700;
}
.ex-h:first-child{margin-top:0}
.ex-quote{
  font-family:var(--serif);font-size:16px;color:var(--ink) !important;
  border-left:2px solid var(--accent);padding-left:12px;
}
.ex-why{color:var(--ink-3) !important;font-style:italic}
.ex-err{color:var(--bad-ink) !important}


/* ===========================================================================
   PAPER THEMES — surface treatment

   No ruling. Ruled lines fight everything laid on top of them: body copy at a
   line-height that has nothing to do with the pitch, choice buttons, badges,
   the reference list. The stock now carries the theme through colour and
   grain alone, which is also what lets the pen jitter go as high as it does.

   Grain is one tiled SVG turbulence per theme, painted as a background-image
   AFTER the shorthand `background` on each surface — the shorthand would
   otherwise reset it to none.
   =========================================================================== */
/* Archivo was self-hosted in v0.31.0 for one string — the wordmark set as live
   text. v0.33.0 replaced that with the package's outlined lockup, so the face
   had no remaining user and the 13 KB came back out of the precache. The
   outlines ARE Archivo 900; the font file was the redundant copy. */
@font-face{
  font-family:"Kalam";
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url("../fonts/kalam-latin-400.woff2") format("woff2");
}
@font-face{
  font-family:"Kalam";
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url("../fonts/kalam-latin-700.woff2") format("woff2");
}
@font-face{
  font-family:"IBM Plex Mono";
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url("../fonts/ibm-plex-mono-latin-500.woff2") format("woff2");
}

body{background-image:var(--paper-texture)}
.card,.beatcard,.sheet,.modal,.empty,.notice,.verdict,.srow,.stat,.runlist li,.beatlist li,.trendbox,.about,.status,.row,.overall{
  background-image:var(--paper-texture);
}

/* ---------------------------------------------------------------------------
   THE COVER — top bars

   A composition book is a marbled cover wrapped around white stock, so the
   chrome is the cover and the content is the page. The framework switcher and
   the Quiz/Beat-bank segments are cover, not page: dark, textured, with the
   selected option showing through as a pasted paper label.
   --------------------------------------------------------------------------- */
/* The cover itself — only the app bar is textured. */
html[data-theme="composition"] .appbar,
html[data-theme="legalpad"]  .appbar{
  background-color:var(--plate);
  background-image:var(--plate-texture);
  color:var(--plate-text);
}

/* The option bars are label plates stuck ON the cover: solid, recessed, and
   deliberately NOT textured. Sharing the marble made them vanish into it. */
html[data-theme="composition"] .fwbar,
html[data-theme="legalpad"]  .fwbar,
html[data-theme="composition"] .segbar,
html[data-theme="legalpad"]  .segbar,
html[data-theme="composition"] .toggle,
html[data-theme="legalpad"]  .toggle{
  background-color:var(--plate-deep);
  background-image:none;
  color:var(--plate-text);
  box-shadow:inset 0 1px 3px rgba(0,0,0,.5), 0 1px 0 rgba(255,255,255,.10);
}
html[data-theme="composition"] .appbar,
html[data-theme="legalpad"]  .appbar{
  border-bottom:0;
  backdrop-filter:none;      /* opaque board, not frosted glass */
}
html[data-theme="composition"] .fwbar,
html[data-theme="legalpad"]  .fwbar,
html[data-theme="composition"] .segbar,
html[data-theme="legalpad"]  .segbar,
html[data-theme="composition"] .toggle,
html[data-theme="legalpad"]  .toggle{
  border:1px solid var(--plate-line);
}
html[data-theme="composition"] .fwlabel,
html[data-theme="legalpad"]  .fwlabel{color:var(--plate-ink-2)}

/* The wordmark's own contrast is no longer a text question: it is outlines, and
   the only value that moves per theme is the o-mark's ARC, which takes the same
   --mark-arc token as the mark. The red is #E0392F on every ground.

   Measured against the actual app-bar plate: studio 4.80:1, studiolight 4.38:1,
   composition 4.07:1, legalpad 2.24:1. Legalpad is still the weak one — a tan
   leather plate — and the package's own note says #E0392F on canary is large
   display only. At 22px of solid 900-weight outline that is what this is. */
/* The paper themes used to repaint the slate's cut-outs and arm to the plate
   colours. Both rules died with the slate in v0.32.0: the v7 mark has no
   cut-outs, and both paper app bars are dark plates, so the arc's default
   white is already the right value contrast on them. */

html[data-theme="composition"] .appbar .ghost-btn,
html[data-theme="legalpad"]  .appbar .ghost-btn{
  border-color:var(--plate-line);color:var(--plate-ink-2);background:transparent;
}
html[data-theme="composition"] .appbar .kbd,
html[data-theme="legalpad"]  .appbar .kbd{
  background:transparent;border-color:var(--plate-line);color:var(--plate-ink-2);
}

html[data-theme="composition"] .fwopt,
html[data-theme="legalpad"]  .fwopt,
html[data-theme="composition"] .seg,
html[data-theme="legalpad"]  .seg,
html[data-theme="composition"] .toggle-opt,
html[data-theme="legalpad"]  .toggle-opt{color:var(--plate-ink-2)}

/* selected = a paper label pasted on the cover */
html[data-theme="composition"] .fwopt.is-on,
html[data-theme="legalpad"]  .fwopt.is-on,
html[data-theme="composition"] .seg.is-on,
html[data-theme="legalpad"]  .seg.is-on,
html[data-theme="composition"] .toggle-opt.is-on,
html[data-theme="legalpad"]  .toggle-opt.is-on{
  background:var(--paper);
  background-image:var(--paper-texture);
  color:var(--ink);
  box-shadow:none;
}
html[data-theme="composition"] .seg .count,
html[data-theme="legalpad"]  .seg .count{background:var(--plate-line);color:var(--plate-text)}
html[data-theme="composition"] .seg.is-on .count,
html[data-theme="legalpad"]  .seg.is-on .count{background:var(--line);color:var(--ink-2)}

/* Handwriting keeps the pitch as its line-height — it is the rhythm of the
   hand, not an alignment to anything drawn on the page. */
html[data-theme="composition"] .card-face,
html[data-theme="legalpad"]  .card-face,
html[data-theme="composition"] .beat-text,
html[data-theme="legalpad"]  .beat-text{
  font-size:24px;line-height:var(--pitch);font-weight:700;
  text-shadow:0 0 .6px currentColor;        /* fibre bleed */
}
html[data-theme="composition"] .card-answer,
html[data-theme="legalpad"]  .card-answer{
  font-size:22px;line-height:var(--pitch);color:var(--pencil);
}
html[data-theme="composition"] .card-gloss,
html[data-theme="legalpad"]  .card-gloss,
html[data-theme="composition"] .card-cue,
html[data-theme="legalpad"]  .card-cue{line-height:1.55}
html[data-theme="composition"] .ref-name,
html[data-theme="legalpad"]  .ref-name,
html[data-theme="composition"] .ex-quote,
html[data-theme="legalpad"]  .ex-quote{font-weight:700}
html[data-theme="composition"] .stat b,
html[data-theme="legalpad"]  .stat b{font-weight:700}

html[data-theme="composition"] .tabbar,
html[data-theme="legalpad"]  .tabbar{backdrop-filter:saturate(105%) blur(6px)}
html[data-theme="composition"] .card,
html[data-theme="legalpad"]  .card,
html[data-theme="composition"] .beatcard,
html[data-theme="legalpad"]  .beatcard,
html[data-theme="composition"] .sheet,
html[data-theme="legalpad"]  .sheet{
  box-shadow:0 1px 0 var(--shadow), 0 12px 28px -18px var(--shadow);
}

/* ===========================================================================
   WRITE-ON

   One visual line per .wl box, revealed left to right with clip-path. The
   duration is computed per line from its measured width, so a long line takes
   longer at the same pen speed — that is most of the illusion.

   Everything below is a fallback for when the animation never starts: the
   default state is FULLY VISIBLE, and JS opts a line into being hidden only
   at the moment it is about to animate it. A theme, a stylesheet load order
   change, or a thrown exception can therefore never leave text clipped out of
   existence.
   =========================================================================== */
/* width:fit-content is load-bearing. As a full-width block the clip-path inset
   percentages would resolve against the COLUMN, not the text, so a short line
   would finish revealing a third of the way through its own animation and then
   sit there — and every line would measure the same width, which is exactly
   the constant-duration look the pen-speed model exists to avoid. */
.wl{display:block;width:fit-content;max-width:100%;white-space:pre-wrap}
.wl.is-pending{clip-path:inset(-30% 100% -30% 0)}
.wl.is-done{clip-path:none}
@media (prefers-reduced-motion:reduce){
  .wl,.wl.is-pending{clip-path:none !important}
}
html[data-motion="off"] .wl,
html[data-motion="off"] .wl.is-pending{clip-path:none !important}

/* ---------- works: rows, editor, migration review ----------
   All of this reuses the existing loose .chip and .icon-btn treatments rather
   than introducing a new control vocabulary. The cover/plate treatment stays
   reserved for bounded segmented bars. */

.workrow{display:flex;align-items:stretch;gap:6px}
.workrow .workitem{flex:1;min-width:0}
.workitem-edit{
  flex:none;align-self:stretch;width:38px;border-radius:10px;
  border:1px solid var(--line);background:var(--bg-3);color:var(--ink-3);
}
.workitem-edit:hover{color:var(--ink);border-color:var(--line-2)}

.worksreview{
  margin:18px 0 0;padding:13px 14px;border:1px solid var(--line);
  border-radius:12px;background:var(--bg-2);
}
.wr-list{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:7px}
.wr-item{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  font-size:13px;color:var(--ink-2);
}
.wr-done,.wr-ask{
  flex:none;font-size:11px;letter-spacing:.04em;text-transform:uppercase;
  padding:2px 7px;border-radius:20px;border:1px solid var(--line-2);color:var(--ink-3);
}
.wr-ask{border-color:var(--accent);color:var(--accent-ink,var(--accent))}
.wr-text{flex:1;min-width:0;color:var(--ink)}

.workform{display:flex;flex-direction:column;gap:4px}
.workform input,.workform textarea{
  background:var(--bg-3);border:1px solid var(--line);border-radius:9px;
  color:var(--ink);font:inherit;font-size:14px;padding:9px 10px;width:100%;
}
.workform .fl{font-size:12.5px;color:var(--ink-3);margin-top:9px}
.workform .fl-opt{color:var(--ink-3);opacity:.75}
.wf-mediums{display:flex;gap:7px;flex-wrap:wrap;margin:2px 0 0}
.wf-count{font-size:12.5px;color:var(--ink-3);margin:12px 0 0}
.wf-actions{display:flex;gap:8px;margin-top:12px}
.btn-sm{font-size:12.5px;padding:5px 10px}
.btn-quiet{background:transparent;color:var(--ink-3);border:1px solid var(--line)}
.btn-quiet:hover{color:var(--ink);border-color:var(--line-2)}

/* ---------- medium scope, availability, Analyze medium ---------- */

/* The scope chips reuse .chip exactly — loose ink on paper, the same
   treatment as the drill-mode and Daily/Weekly chips. No cover/plate
   background: that is reserved for bounded segmented bars. */
[data-scopebar]{margin-bottom:14px}

.fwopt.is-unavailable{opacity:.4;cursor:not-allowed}
.fwblock{margin-bottom:18px}
.fwblock-head{margin:0 0 8px}

.periodnote.is-quiet{color:var(--ink-3);font-size:12.5px;margin-top:-6px}

/* ---------- settings: the per-framework note ----------
   Smaller than a full notice block, because it now sits beside the settings it
   describes rather than at the top of the page explaining the whole screen. */
.notice.is-small{
  font-size:12.5px;line-height:1.5;padding:10px 12px;margin-bottom:14px;
}

/* ---------- About logo ---------- */
.about-logo img{height:auto;width:104px;border-radius:12px}

/* ---------- paper stock on the quiz card and the answer ----------
   The texture is an OVERLAY, not a background swap: the base colour stays
   whatever the theme already painted, so studio is still Hoodworks black and
   the two paper themes keep their newsprint and canary. Blending rather than
   replacing is what makes one grey JPEG work in all three.

   Overlay strength is per theme because the same luminance texture reads far
   heavier on a near-black surface than on canary.

   Kept off the app background on purpose — a texture behind the whole page
   would fight the write-on animation and every list on top of it. */
:root{ --paper-strength:.05; --paper-blend:overlay; }
[data-theme="composition"]{ --paper-strength:.5; --paper-blend:multiply; }
[data-theme="legalpad"]{ --paper-strength:.42; --paper-blend:multiply; }

.beatcard,.verdict{position:relative;isolation:isolate;overflow:hidden}
.beatcard::before,.verdict::before{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:url('../img/paper-texture.jpg');
  background-size:340px 340px;
  background-repeat:repeat;
  mix-blend-mode:var(--paper-blend);
  opacity:var(--paper-strength);
}
/* The stock is decoration. If the user has asked for less motion they have not
   asked for less texture, so nothing here is gated on that — but a forced
   high-contrast mode wants the flat colour back. */
@media (forced-colors: active){
  .beatcard::before,.verdict::before{display:none}
}

/* ---------- beat length counter ----------
   The cap is a content rule, not a nicety, so the counter is always visible
   rather than appearing once you are already over it. */
.charcount{
  display:block;text-align:right;font-size:11.5px;color:var(--ink-3);margin-top:4px;
  font-variant-numeric:tabular-nums;
}
.charcount.is-over{color:var(--bad-ink);font-weight:600}

/* ---------- framework switcher: name over formats ----------
   The formats line is what stops "which of these four does television?" being
   a question you answer by flipping the medium chip and watching buttons grey
   out. Small, quiet, and always present. */
.fwopt{display:flex;flex-direction:column;align-items:center;gap:1px;line-height:1.15}
.fwopt-name{
  display:block;max-width:100%;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.fwopt-formats{
  display:block;font-size:9.5px;font-weight:500;letter-spacing:.02em;
  opacity:.62;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;
}
.fwopt.is-on .fwopt-formats{opacity:.8}
@media (max-width: 380px){
  .fwopt{font-size:12px}
  .fwopt-formats{font-size:9px}
}

/* ---------- character line ----------
   Quiet, and only present when a work actually has more than one arc. */
.line-tag{
  display:inline-block;margin-left:6px;padding:1px 7px;border-radius:20px;
  border:1px solid var(--line-2);font-size:10.5px;letter-spacing:.02em;color:var(--ink-3);
}
/* Genre is context, not identity — a filled chip rather than the outlined one
   a character line gets, so at a glance the two never read as the same kind of
   fact about the beat. */
.genre-tag{
  display:inline-block;margin-left:6px;padding:1px 7px;border-radius:20px;
  background:var(--line-soft);font-size:10px;font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-3);
}

/* ---------- reference button ----------
   Was a ghost button carrying a whole sentence at 12px, which is how you get a
   control nobody notices. Now a real button: a fixed "Reference" kicker over
   the framework name, so the line that changes is the short one and the
   width stops moving every time you switch. */
.refbtn{
  display:flex;align-items:center;gap:9px;
  appearance:none;cursor:pointer;font:inherit;text-align:left;
  padding:7px 11px;border-radius:11px;
  background:var(--bg-3);border:1px solid var(--line-2);color:var(--ink);
  box-shadow:0 1px 0 var(--shadow);
  transition:background .15s ease,border-color .15s ease;
}
.refbtn:hover,.refbtn:focus-visible{background:var(--bg-2);border-color:var(--accent)}
.refbtn-icon{font-size:14px;line-height:1;color:var(--accent-ink);flex:none}
.refbtn-text{display:flex;flex-direction:column;min-width:0;line-height:1.12}
.refbtn-kicker{
  font-size:8.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);
}
.refbtn-label{
  font-size:12.5px;font-weight:650;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:15ch;
}
.refbtn .kbd{flex:none}
@media (max-width:400px){ .refbtn-label{max-width:11ch} .refbtn .kbd{display:none} }

/* ---------- view titles ----------
   These were deliberately absent once, on the reasoning that the lit tab
   already says where you are. It does, at 10px, at the bottom of the screen.
   A heading at the top of the thing you are looking at is not redundancy. */
.viewhead{margin:0 0 16px}
.viewhead-title{
  font-size:23px;font-weight:700;letter-spacing:-.015em;margin:0;color:var(--ink);
}
.viewhead-sub{font-size:13px;color:var(--ink-3);margin:3px 0 0;line-height:1.45}

/* ---------- settings: headings that carry ---------- */
.sec-h{
  font-size:16.5px;font-weight:700;letter-spacing:-.01em;text-transform:none;
  color:var(--ink);margin:30px 0 4px;padding-top:14px;
  border-top:1px solid var(--line);
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
}
.sec-h:first-of-type{border-top:0;padding-top:0}
/* Explanations are the app talking about itself rather than labelling a
   control, so they are set apart from the controls in voice as well as size. */
#view-settings .hint{font-style:italic}
#view-settings .hint code,#view-settings .hint strong{font-style:normal}

/* ---------- theme picker ---------- */
.themegrid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin:6px 0 4px}
@media (max-width:420px){ .themegrid{grid-template-columns:1fr} }
.themecard{
  appearance:none;font:inherit;text-align:left;cursor:pointer;padding:0;overflow:hidden;
  background:var(--bg-2);border:1px solid var(--line);border-radius:13px;
  transition:border-color .15s ease,box-shadow .15s ease;
}
.themecard:hover{border-color:var(--line-2)}
.themecard.is-on{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
/* The preview paints itself from its own data-theme, so it is the real token
   set rather than a picture of one. */
.themeprev{
  background:var(--bg);color:var(--ink);padding:11px 12px 12px;border-bottom:1px solid var(--line);
}
.themeprev-kicker{
  font-size:8px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-3);margin-bottom:6px;
}
/* Same recipe as .beatcard, at scale — including the paper stock, which is
   half of what tells the two paper themes apart at thumbnail size. */
.themeprev-card{
  background:var(--bg-2);border:1px solid var(--line);border-radius:8px;padding:9px 10px;
  position:relative;isolation:isolate;overflow:hidden;
}
.themeprev-card::before{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:url('../img/paper-texture.jpg');
  background-size:200px 200px;background-repeat:repeat;
  mix-blend-mode:var(--paper-blend);opacity:var(--paper-strength);
}
@media (forced-colors: active){ .themeprev-card::before{display:none} }
.themeprev-beat{font-family:var(--serif);font-size:11.5px;line-height:1.34;color:var(--ink);margin:0}
.themeprev-src{font-size:7.5px;color:var(--ink-3);margin:7px 0 0}
.themeprev-opts{display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-top:7px}
.themeprev-opt{
  background:var(--bg-2);border:1px solid var(--line);border-radius:5px;
  font-size:8.5px;font-weight:550;padding:5px 6px;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.themeprev-optn{color:var(--ink-3);font-size:7.5px;font-style:normal;margin-right:5px}
.themecard-foot{padding:9px 11px 11px}
.themecard-name{font-size:13.5px;font-weight:650;color:var(--ink)}

/* ================= CROSS-FRAMEWORK COMPARE =================
   Columns, not a table. A table would need one row per step across frameworks
   with different step counts — eight against fifteen against twelve — and the
   rows would line up with nothing. Side-by-side columns say the true thing:
   these are separate sheets being read at the same time, not one grid.

   On a phone the columns scroll horizontally at a readable width rather than
   stacking, because stacking is just the beat bank again and loses the whole
   point of putting them beside each other. */
/* NO SIDEWAYS SCROLL. The columns share whatever width there is, and the grid
   breaks OUT of the app's 640px reading column to use the window — a
   side-by-side you have to drag is not a side-by-side, and the rest of the app
   is 640px because prose wants a measure, which this is not.

   Capped at 1240px so on a wide desktop the columns stop growing rather than
   becoming three empty fields, and `min-width:0` on the cells is what actually
   lets a grid track shrink below its content instead of forcing an overflow. */
.cmpgrid{
  display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);
  gap:12px;padding-bottom:6px;margin:4px 0 16px;
  /* --cmpcols is set by renderCompare to the number of columns actually drawn.
     Frameworks the medium rules out are no longer rendered as empty columns
     (v0.34.0), so the breakout has to shrink with the count — two sheets
     stretched across 1240px look like a layout bug rather than a comparison. */
  width:min(calc(100vw - 32px), calc(var(--cmpcols, 4) * 310px));
  max-width:min(calc(100vw - 32px), 1240px);
  margin-left:50%;transform:translateX(-50%);
}
.cmpcol{
  background:var(--bg-2);border:1px solid var(--line);
  border-radius:13px;padding:12px;min-width:0;overflow-wrap:anywhere;
}
/* The framework you arrived from leads, and says so quietly. */
.cmpcol.is-active{border-color:var(--line-2);background:var(--bg-3)}
.cmpcol.is-active .cmpcol-name::after{
  content:'active';margin-left:7px;font-size:9px;font-weight:600;letter-spacing:.07em;
  text-transform:uppercase;color:var(--accent-ink);vertical-align:middle;
}

/* Three columns inside a phone means about 120px each. Everything steps down
   together rather than letting one element decide the column width. */
@media (max-width: 700px){
  .cmpgrid{gap:7px}
  .cmpcol{padding:8px 7px;border-radius:10px}
  .cmpcol-name{font-size:12.5px}
  .cmpcol-score{font-size:16px}
  .cmpcol-note{font-size:10px}
  .cmprow{padding:5px 6px}
  .cmprow-step{font-size:9.5px}
  .cmprow-beat{font-size:11px;line-height:1.32}
  .cmpcol.is-active .cmpcol-name::after{content:none}
}
.cmpcol.is-unavailable{opacity:.55}
.cmpcol.is-empty{border-style:dashed}
.cmpcol-head{margin-bottom:10px}
.cmpcol-name{font-size:15px;font-weight:650;color:var(--ink)}
.cmpcol-score{font-family:var(--serif);font-size:20px;color:var(--ink);margin-top:2px}
.cmpbar{height:4px;border-radius:3px;background:var(--line-soft);overflow:hidden;margin:7px 0 5px}
.cmpbar i{display:block;height:100%;background:var(--accent);border-radius:3px}
.cmpcol-note{font-size:11.5px;color:var(--ink-3);font-style:italic}

.cmplist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
.cmprow{
  border-left:3px solid var(--line);border-radius:0 7px 7px 0;
  background:var(--bg-3);padding:7px 9px;
}
.cmprow-step{font-size:11px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.cmprow-beat{font-size:12.5px;color:var(--ink);line-height:1.38;margin-top:2px}
/* A gap is the finding, so it reads as an absence rather than as a beat. */
.cmprow.is-gap .cmprow-beat{color:var(--ink-3);font-style:italic}
.cmprow.is-gap{background:transparent;border-left-style:dashed}
/* The model's verdict laid over your own filing. The interesting cell is a
   step you filed that it read as MISSING — that one gets the loud edge. */
.cmprow[data-verdict="MISSING"]{box-shadow:inset 3px 0 0 var(--bad-line)}
.cmprow[data-verdict="WEAK"]{box-shadow:inset 3px 0 0 var(--warn, var(--ink-3))}
.cmprow[data-verdict="PRESENT"]{box-shadow:inset 3px 0 0 var(--ok)}

.cmpverdict{
  background:var(--bg-3);border:1px solid var(--line);border-radius:9px;
  padding:9px 10px;margin-bottom:9px;
}
.cmpverdict-h{font-size:11.5px;font-weight:650;color:var(--ink-2);letter-spacing:.02em}
.cmpverdict-b{font-size:12.5px;color:var(--ink-2);margin:5px 0 0;line-height:1.42}

/* ---------- beat bank: the story switch and the medium scope ----------
   These sat flush against each other, so the medium chips read as part of the
   switch list above them. They are different controls — one takes a story out
   of play, the other narrows the whole bank to a medium — and the gap plus a
   heading is what says so. */
.workswitch{margin-bottom:22px}
.workswitch #workSortBar{margin:10px 0 2px}
.worklist-head{
  list-style:none;margin:12px 0 4px;font-size:10.5px;font-weight:700;
  letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);
}
.worklist-head:first-child{margin-top:2px}
.banksection{margin:0 0 20px}
.banksection .sec-h{margin-bottom:2px}
.banksection-sub{margin:0 0 10px}
/* Title and its genre chip travel as one unit in the bank's meta row. */
.bl-work{display:inline-flex;align-items:center;gap:0;white-space:nowrap}

/* ---------- practice-log export form ----------
   Kept plain on purpose. This is a form you fill in once in a while, not a
   surface you look at, so it borrows the field and chip styles already in the
   app rather than introducing a fifth kind of control. */
.logform{margin-top:4px}
.logrow{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-end;margin-bottom:12px}
.field-inline{flex:1 1 150px;min-width:140px}
.logset{
  border:1px solid var(--line);border-radius:11px;
  padding:10px 14px 12px;margin:0 0 12px;
}
.logset > legend{
  font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-2);
  padding:0 6px;
}
.logchecks{display:flex;flex-wrap:wrap;gap:8px 18px}
.logchecks label{
  display:flex;align-items:center;gap:7px;
  font-size:13.5px;color:var(--ink);cursor:pointer;
}
.logchecks input{accent-color:var(--accent);width:16px;height:16px;flex:none}
#logPreview{font-variant-numeric:tabular-nums}
@media (max-width:420px){
  .logrow{gap:8px}
  .logchecks{gap:6px 12px}
}

/* The compare grid's account of itself. Given a rule and a little air because
   it is the only thing on the screen explaining why the table is the width it
   is — as a bare hint it read as a caption nobody needed. */
.cmp-fits{
  margin-top:14px;padding-top:12px;border-top:1px solid var(--line);
  max-width:70ch;
}
