/* styles.css — Box of Sheets. Palette comes entirely from the seven Dicebox
   chrome custom properties, retinted per system by theme.js (SYSTEM_THEMES).
   Defaults here are the sage-green numeric chrome; JS overrides on load. */

:root {
  --paper: #0B0D0C;
  --face: #141715;
  --line: #DEE3DD;
  --hair: #232823;
  --muted: #6F7A70;
  --accent: #9BB07A;
  --danger: #D2605A;

  color-scheme: dark light;

  /* Dicebox's three voices, minus the serif: the interface speaks Inter
     Tight, dice data speaks mono and tabular so the math looks like math. */
  --sans: "Inter Tight", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Iosevka stays first by name, so a device that has it uses it; the
     vendored Plex Mono (the canvas's stand-in, build.mjs:35) carries the rest */
  --mono: "Iosevka Etoile", "IBM Plex Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
  --tap: 44px;

  /* The signature: one display face for the name, the section headers and
     the page titles, and nothing else. src/signature.js sets these per
     template; the defaults are the interface voice, so the home page and a
     sheet before its script runs read as they always did. */
  --sig-family: var(--sans);
  --sig-sc: var(--sans);
  --sig-name-size: 30px; --sig-name-weight: 700; --sig-name-track: -.01em; --sig-name-lh: 1.05;
  --sig-head-size: 15px; --sig-head-weight: 600; --sig-head-track: .02em;
  --sig-title-size: 22px; --sig-title-weight: 700; --sig-title-track: 0; --sig-title-lh: 1.1;

  /* The shape vocabulary (design/docs/brief.md:90-91): a card, a control, a
     pill, one floating shadow, the hairline and the rule. Every radius and
     shadow below is one of these. */
  --r-card: 12px;
  --r-ctl: 8px;
  --r-pill: 999px;
  --shadow-float: 0 12px 32px rgba(0, 0, 0, .28);
  --hair-w: 1px;
  --rule-w: 2px;
  /* the flame's gold, dicebox/app.js TORCH_FLAME.gold */
  --amber: #F2C14E;
}

/* ---------- the faces, self-hosted ----------
   Every file in fonts/ is a format conversion of the google/fonts ofl/ TTF
   (woff2_compress, no glyph removed) with its OFL.txt beside it; NOTICE
   carries the record. Each rule names its weight and style outright so
   nothing is synthesised, and a browser fetches a face only when text uses
   it, so a Mothership sheet never downloads Grenze. The URLs resolve under
   <base href="/"> at any slug depth. */
@font-face { font-family: "Inter Tight"; src: url("fonts/InterTight-Variable.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("fonts/IBMPlexMono-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("fonts/IBMPlexMono-Medium.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("fonts/IBMPlexMono-SemiBold.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Barlow Condensed"; src: url("fonts/BarlowCondensed-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Alfa Slab One"; src: url("fonts/AlfaSlabOne-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "IM Fell English"; src: url("fonts/IMFellEnglish-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "IM Fell English SC"; src: url("fonts/IMFellEnglishSC-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Courier Prime"; src: url("fonts/CourierPrime-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Grenze"; src: url("fonts/Grenze-Variable.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--paper);
  color: var(--line);
  font: 16px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  min-height: 100dvh;
  transition: background-color .25s ease, color .25s ease;
}

/* The Owlbear panel (tools/build-owlbear.mjs marks the root): a phone-shaped
   window on a desktop, where the classic scrollbar is a fifteen-pixel bite out
   of a 420px popover. Thin and quiet, still there to grab. */
html[data-owlbear] { scrollbar-width: thin; scrollbar-color: var(--hair) transparent; }
html[data-owlbear]::-webkit-scrollbar { width: 6px; height: 6px; }
html[data-owlbear]::-webkit-scrollbar-thumb { background: var(--hair); border-radius: 3px; }
html[data-owlbear]::-webkit-scrollbar-track { background: transparent; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- brand ---------- */
.brand {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  text-decoration: none;
  color: var(--line);
  min-width: 0;
}
.brand-mark {
  width: 26px;
  height: 26px;
  color: var(--accent);
  flex: none;
}
.ghost-btn {
  background: none;
  border: 1px solid var(--hair);
  color: var(--muted);
  border-radius: var(--r-ctl);
  width: 34px; height: 34px;
  font-size: 1rem;
  cursor: pointer;
}
.ghost-btn:hover, .ghost-btn:focus-visible { color: var(--accent); border-color: var(--accent); }

/* ---------- views ---------- */
.view {
  padding: 1.1rem clamp(.75rem, 3vw, 1.5rem) 4rem;
  max-width: 780px;
  margin: 0 auto;
}

h1.page-title {
  font-size: 1.05rem;
  letter-spacing: .06em;
  margin: .4rem 0 1rem;
  color: var(--line);
}
.page-sub { color: var(--muted); font-size: .85rem; margin-top: -.7rem; }

/* ---------- portrait: a card-cornered box, the bust glyph until an image lands ---------- */
.portrait-box {
  position: relative;
  width: 64px;
  height: 64px;
  flex: none;
  border: var(--hair-w) solid var(--hair);
  border-radius: var(--r-card);
  overflow: hidden;
  background: none;
  color: var(--muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.portrait-box:hover, .portrait-box:focus-visible { color: var(--accent); border-color: var(--accent); }
.portrait-box img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.portrait-box .portrait-glyph { width: 28px; height: 28px; display: block; }
.portrait-remove {
  position: absolute;
  top: 4px; right: 4px;
  background: rgba(0,0,0,.65);
  color: #fff;
  border: none;
  border-radius: var(--r-ctl);
  width: 22px; height: 22px;
  font-size: .8rem;
  cursor: pointer;
  display: none;
}
.portrait-box.has-img .portrait-remove { display: block; }

/* character cards */
.char-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .6rem; }
.char-card {
  display: flex;
  align-items: center;
  gap: .75rem;
  background: var(--face);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  padding: .8rem .95rem;
  cursor: pointer;
  color: inherit;
  width: 100%;
  text-align: left;
  font: inherit;
}
.char-card:hover, .char-card:focus-visible { border-color: var(--accent); }
.char-portrait-thumb {
  width: 42px; height: 42px;
  border-radius: var(--r-ctl);
  object-fit: cover;
  flex: none;
  background: var(--paper);
  border: 1px solid var(--hair);
}
.char-name { font-weight: 650; }
.char-meta { color: var(--muted); font-size: .78rem; margin-top: .15rem; }
.char-row { display: flex; align-items: stretch; gap: .35rem; }
.char-row .char-card { flex: 1 1 auto; min-width: 0; }
.char-delete {
  background: none; border: 1px solid transparent; border-radius: var(--r-ctl);
  color: var(--muted); cursor: pointer;
  font-size: .95rem; padding: .3rem .6rem; min-width: 44px;
}
.char-delete:hover, .char-delete:focus-visible { color: var(--danger); border-color: var(--danger); }
.char-confirm {
  flex: 1 1 auto;
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  padding: .6rem .8rem;
  border: 1px solid var(--danger);
  border-radius: var(--r-card);
  background: color-mix(in srgb, var(--danger) 10%, var(--face));
  font-size: .88rem;
}
.char-confirm span { flex: 1 1 12rem; }
.danger-btn {
  background: var(--danger); color: var(--paper);
  border: none; border-radius: var(--r-ctl);
  padding: .45rem .8rem; font: inherit; font-weight: 700; cursor: pointer;
}

.primary-btn {
  background: var(--accent);
  color: var(--paper);
  border: none;
  border-radius: var(--r-ctl);
  padding: .65rem 1.1rem;
  font-weight: 700;
  font-size: .9rem;
  cursor: pointer;
  letter-spacing: .03em;
}
.primary-btn:focus-visible, .char-card:focus-visible,
button:focus-visible, input:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.empty-state {
  color: var(--muted);
  text-align: center;
  padding: 3rem 1rem;
  border: 1px dashed var(--hair);
  border-radius: var(--r-card);
  margin-top: 1rem;
}

/* The name field, Create, and Roll up on one line where they fit, and the
   Roll up wrapping under when they do not (a 420px Owlbear popover): a text
   input's intrinsic width is a flex-item minimum unless min-width says
   otherwise, and without it the row overflowed the panel and dragged in a
   horizontal scrollbar. */
.new-row { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1rem; }
.new-row .primary-btn, .new-row .rollup-btn { flex: none; }
.new-row input[type="text"] {
  flex: 1 1 10rem;
  min-width: 0;
  background: var(--face);
  border: 1px solid var(--hair);
  color: var(--line);
  border-radius: var(--r-ctl);
  padding: .6rem .8rem;
  font: inherit;
}

/* ---------- sheet: a document, not a dashboard ----------
   The identity header: portrait, the name, the byline, a quiet row of links,
   on a hairline (design/canvas/build.mjs identity). */
.sheet-head {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 22px 0 18px;
  margin: 0;
  border-bottom: var(--hair-w) solid var(--hair);
}
.sheet-head-main { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.sheet-name-input {
  background: none;
  border: 0;
  border-radius: 0;
  color: var(--line);
  font: inherit;
  font-family: var(--sig-family);
  font-size: var(--sig-name-size);
  font-weight: var(--sig-name-weight);
  line-height: var(--sig-name-lh);
  letter-spacing: var(--sig-name-track);
  padding: 0;
  margin: 0;
  width: 100%;
  max-width: 100%;
  min-width: 0;
}
.sheet-name-input::placeholder { color: var(--muted); }
.sheet-byline { margin: 0; font-size: 13px; line-height: 1.3; letter-spacing: .01em; color: var(--muted); }
.sheet-byline[hidden] { display: none; }
.sheet-head-row.quiet { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; margin-top: 2px; font-size: 13px; color: var(--muted); }
.back-link { color: var(--muted); text-decoration: none; font-size: 13px; }
.back-link:hover, .back-link:focus-visible { color: var(--accent); }
.sheet-head-row.quiet .export-btn {
  appearance: none; background: none; border: 0; border-radius: 0; padding: 0; margin: 0;
  width: auto; height: auto; font: inherit; font-size: 13px; color: var(--muted); cursor: pointer;
}
.sheet-head-row.quiet .export-btn:hover, .sheet-head-row.quiet .export-btn:focus-visible { color: var(--accent); }
/* the roll-up is an action, so it keeps the pill */
.sheet-head-row.quiet .rollup-btn {
  width: auto; height: auto; min-height: 36px; padding: 0 14px; margin: 0;
  background: none; border: var(--hair-w) solid var(--accent); border-radius: var(--r-pill); color: var(--accent);
  font: inherit; font-size: 13px; font-weight: 500; white-space: nowrap; cursor: pointer;
}
.sheet-head-row.quiet .rollup-btn:hover, .sheet-head-row.quiet .rollup-btn:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }

/* Section = a run of the document under a ruled header, never a card */
.section {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 22px 0 0;
  margin: 0 0 .9rem;
  position: relative;
}
.section > h2 {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  border-bottom: var(--hair-w) solid var(--hair);
  padding-bottom: 8px;
  margin: 0 0 12px;
  font-family: var(--sig-family);
  font-size: var(--sig-head-size);
  font-weight: var(--sig-head-weight);
  letter-spacing: var(--sig-head-track);
  text-transform: none;
  color: var(--line);
  min-width: 0;
}
/* The signature's case, from the template (signature.name / signature.heads).
   Small caps are the SC file's own glyphs, never font-variant, which would
   synthesise them over the file (design/docs/impl/fonts-signatures.md §4.3). */
[data-sig-name="caps"] .sheet-name-input { text-transform: uppercase; }
[data-sig-heads="caps"] .section > h2,
[data-sig-heads="caps"] .picker-head h2,
[data-sig-heads="caps"] .wizard-head h2 { text-transform: uppercase; }
[data-sig-heads="smallcaps"] .section > h2 { font-family: var(--sig-sc); font-synthesis: none; text-transform: none; }

.field-grid {
  display: grid;
  /* a document field needs room for a name: a phone page pairs fields at most (build.mjs grid(2, …)) */
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 14px 12px;
}

/* the cap: a field's label, 10px tracked caps in the muted ink (build.mjs .cap) */
.field > label, .field-head > label {
  display: block;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}
/* a ruled line, the way a printed sheet takes a pen: no well, the value sits on a hairline */
.field > input[type="number"], .field > input[type="text"], .field > textarea, .field > .choice {
  width: 100%;
  background: none;
  color: var(--line);
  border: 0;
  border-bottom: var(--hair-w) solid var(--hair);
  border-radius: 0;
  padding: 12px 0 6px;
  min-height: 44px;
  font: inherit;
  font-size: 16px;
  line-height: 1.3;
}
.field > input::placeholder, .field > textarea::placeholder { color: var(--muted); opacity: 1; }
/* focus turns the rule to the ink; the shared ring stays off these */
.field > input[type="number"]:focus-visible, .field > input[type="text"]:focus-visible, .field > textarea:focus-visible, .field > .choice:focus-visible {
  outline: none;
  border-bottom-color: var(--line);
}
.field > textarea { resize: vertical; min-height: 44px; display: block; }
/* a filled text's editor waits hidden beside the note; display: block above must not wake it */
.field > textarea[hidden] { display: none; }
/* where the browser can size a textarea to its text, it grows on its own and loses the resize grip */
@supports (field-sizing: content) { .field > textarea { field-sizing: content; resize: none; } }
/* a document field runs the width of the page: a name, a concept, a desire need the whole rule
   (the canvas pairs Chronicle/Sire by hand; that pairing is S2's plan, not a default) */
.field-grid > .field:not(.checkbox-field) { grid-column: 1 / -1; }
.field.wide { grid-column: 1 / -1; }
/* a choice's longest option must never size the page: grid children take the track, not the other way round */
.page > *, .field-grid > * { min-width: 0; }

/* ---- the chevron choice (S5, src/choice.js): a button wearing the value on the ruled line, the listbox in a pop (choice, build.mjs:198).
   No native select anywhere: the pop is the list, a bottom sheet under a scrim on a phone, a dropdown under the row wider than 640px. */
.choice {
  appearance: none; display: flex; align-items: flex-end; justify-content: space-between; gap: 8px;
  min-height: 44px; padding: 12px 0 6px; box-sizing: border-box;
  background: none; border: 0; border-bottom: var(--hair-w) solid var(--hair); border-radius: 0;
  color: var(--line); font: inherit; font-size: 16px; line-height: 1.3; text-align: left; cursor: pointer;
}
.choice:hover, .choice[aria-expanded="true"] { border-bottom-color: var(--line); }
.choice-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.choice.unset .choice-val { color: var(--muted); }
.choice > .choice-chev { flex: none; width: 12px; height: 12px; margin-bottom: 4px; color: var(--muted); transition: transform 160ms ease; }
.choice[aria-expanded="true"] > .choice-chev { transform: rotate(180deg); }
.choice-pop {
  position: fixed; z-index: 40; box-sizing: border-box;
  display: flex; flex-direction: column; overflow: hidden;
  max-height: min(60vh, 440px);
  background: var(--face); color: var(--line);
  border: 1px solid var(--hair); border-radius: var(--r-card); box-shadow: var(--shadow-float);
  animation: pop-in 160ms ease both;
}
.choice-pop[hidden] { display: none; }
.choice-scrim { display: none; }
.choice-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 4px 0; outline: none; }
.choice-group { padding: 12px 14px 4px; }
.choice-opt {
  appearance: none; display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 44px; padding: 0 14px 0 12px; box-sizing: border-box;
  background: none; border: 0; border-left: var(--rule-w) solid transparent;
  color: var(--line); font: inherit; font-size: 15px; line-height: 1.3; text-align: left; cursor: pointer;
}
.choice-opt + .choice-opt { border-top: var(--hair-w) solid var(--hair); }
.choice-opt[hidden] { display: none; }
.choice-opt-check { flex: none; width: 14px; height: 14px; color: var(--accent); visibility: hidden; }
.choice-opt-label { flex: 1 1 auto; min-width: 0; }
.choice-opt[aria-selected="true"] { border-left-color: var(--accent); }
.choice-opt[aria-selected="true"] .choice-opt-check { visibility: visible; }
.choice-opt.active, .choice-opt:hover { background: color-mix(in srgb, var(--line) 7%, transparent); }
.choice-opt:focus-visible { outline: none; }
/* the search rule at the top when the list runs long (Shadowdark's eighteen classes) */
.choice-search { flex: none; display: flex; align-items: center; gap: 8px; padding: 6px 14px; border-bottom: var(--hair-w) solid var(--hair); color: var(--muted); }
.choice-search-glyph { flex: none; width: 16px; height: 16px; }
.choice-search-input { flex: 1 1 auto; min-width: 0; padding: 8px 0; background: none; border: 0; color: var(--line); font: inherit; font-size: 15px; }
.choice-search-input:focus-visible { outline: none; }
.choice-search:focus-within { border-bottom-color: var(--line); color: var(--line); }
.choice-search-input::placeholder { color: var(--muted); opacity: 1; }
@media (max-width: 639px) {
  .choice-scrim { display: block; position: fixed; inset: 0; z-index: 40; background: rgba(0, 0, 0, .45); animation: scrim-in 160ms ease both; }
  .choice-pop.sheet {
    left: 0; right: 0; top: auto; bottom: 0; width: auto; max-height: min(70vh, 560px);
    border-bottom: 0; border-radius: var(--r-card) var(--r-card) 0 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    animation: sheet-in 200ms ease both;
  }
}
@keyframes scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes sheet-in { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .choice-pop, .choice-pop.sheet, .choice-scrim { animation: none; } .choice > .choice-chev { transition: none; } }
/* derived (read-only) values: the same ruled footprint, quietly computed */
.field.derived output {
  display: block;
  width: 100%;
  box-sizing: border-box;
  background: transparent;
  color: var(--accent);
  border: 0;
  border-bottom: var(--hair-w) solid var(--hair);
  border-radius: 0;
  padding: 12px 0 6px;
  min-height: 44px;
  font-size: 16px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.list-field ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
.list-field li { display: flex; gap: .4rem; align-items: center; }
/* a typed line is a ruled line, as a field is (S1): the box is the rule, 44px, 16px */
.list-field li input {
  flex: 1; min-width: 0; box-sizing: border-box;
  background: none; color: var(--line);
  border: 0; border-bottom: var(--hair-w) solid var(--hair); border-radius: 0;
  padding: 12px 0 6px; min-height: var(--tap);
  font: inherit; font-size: 16px;
}
.list-field li input::placeholder { color: var(--muted); opacity: 1; }
.list-add {
  background: none; border: 1px dashed var(--hair); color: var(--muted);
  border-radius: var(--r-ctl); padding: .35rem .6rem; cursor: pointer; font-size: .8rem;
  margin-top: .4rem;
}
.list-add:hover { color: var(--accent); border-color: var(--accent); }
.row-remove { background:none;border:none;color:var(--muted);cursor:pointer;padding:.2rem; }
.row-remove:hover { color: var(--danger); }

/* the toggle (build.mjs:226): a drawn box that takes the accent and the check when on; the native input is
   visually hidden beside it, still focusable, still the thing a reader names (.visually-hidden, kept) */
.checkbox-field > label.toggle { position: relative; display: flex; align-items: center; gap: 8px; min-height: 44px; margin: 0; font-size: 14px; letter-spacing: 0; text-transform: none; color: var(--muted); cursor: pointer; }
.toggle-box { flex: none; width: 16px; height: 16px; box-sizing: border-box; border: 1.5px solid var(--line); border-radius: 3px; display: flex; align-items: center; justify-content: center; color: var(--accent); }
.toggle-check { width: 11px; height: 11px; visibility: hidden; }
.toggle input:checked ~ .toggle-box { border-color: var(--accent); }
.toggle input:checked ~ .toggle-box .toggle-check { visibility: visible; }
.toggle input:checked ~ .toggle-label { color: var(--line); }
.toggle input:focus-visible ~ .toggle-box { outline: 2px solid var(--accent); outline-offset: 2px; }

.sys-icon {
  width: 20px;
  height: 20px;
  color: var(--accent);
  flex: none;
  margin-right: .5rem;
}
h1.page-title { display: flex; align-items: center; }
.char-card .sys-icon { width: 18px; height: 18px; }

/* dialog */
.help-dialog {
  background: var(--face);
  color: var(--line);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  width: min(400px, calc(100vw - 20px));
  max-height: min(80vh, 640px);
  padding: 12px 16px 14px;
  box-shadow: var(--shadow-float);
}
.help-dialog::backdrop { background: rgba(0,0,0,.55); }
.help-title { margin: 0 0 8px; font-size: .95rem; font-weight: 650; letter-spacing: .01em; }
.syntax {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1px 14px;
  margin: 0;
  align-items: baseline;
}
.syntax dt {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--line);
  text-align: right;
  white-space: nowrap;
}
.syntax dd { margin: 0; font-size: 12.5px; color: var(--muted); }
.help-dialog .note { margin: 12px 0 0; font-size: 12px; line-height: 1.5; color: var(--muted); max-width: 44ch; }
.help-dialog .note b { color: var(--line); font-weight: 600; }
.help-dialog .status:empty { display: none; }
.help-game[hidden] { display: none; }
.pack-list { list-style: none; padding: 0; margin: 8px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5; }
.pack-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; }
.pack-list strong { color: var(--line); font-weight: 600; }
.pack-list button { font: inherit; font-size: 11.5px; min-height: 0; min-width: 0; padding: 1px 9px; margin: 0; border-radius: var(--r-pill); background: transparent; border: 1px solid var(--hair); color: var(--line); cursor: pointer; }
.pack-list button::before, .pack-list button::after { content: none; }
.help-actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; }
.help-dialog .colophon { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; row-gap: 4px; margin: 12px 0 0; font-size: 12px; color: var(--muted); }
.help-dialog .colophon a { color: var(--line); }
.colophon-sep { opacity: .5; }
.disclaimer { margin: 10px 0 0; font-size: 10.5px; line-height: 1.5; color: var(--muted); opacity: .85; }
.help-close { margin-top: 12px; }
.colophon { color: var(--muted); font-size: .76rem; }

@media (min-width: 640px) {
  .view { padding-top: 1.6rem; }
}

/* ============================================================================
   Values — every number on the sheet is a barrel (Dicebox's scrub dial), and a
   stat's tap is its roll. The base .chip carries no shape (docs/CONTRACT.md
   rule 2): the shape is the tier's (.chip.hero, .chip.stat2, .chip.row, .chip.of
   inside a .chip-row[data-tier] the section loop stamps from the plan), the
   pill's (.chip.action, the one pill) or the choice row's. Anatomy: label,
   value, [mod], [die glyph]. The accent is spent on a rollable value under
   the finger, a loaded state (armed, at a bound) and the result.
   ========================================================================== */
.chip-row { display: flex; flex-wrap: wrap; gap: .45rem; }
.chip {
  display: inline-flex;
  align-items: baseline;
  gap: .5rem;
  min-height: var(--tap);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .8rem;
  line-height: 1.25;
  text-align: left;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: border-color 140ms ease, background-color 140ms ease, color 140ms ease, transform 120ms ease;
}
/* Two classes beat one: no later button rule may take the gesture back. */
.scrub-dial.scrub-dial { touch-action: none; }
.chip-label { color: var(--muted); letter-spacing: .01em; }
.chip-val {
  font-family: var(--mono);
  font-size: 1.05rem;
  line-height: 1.25rem;
  font-variant-numeric: tabular-nums;
  color: var(--line);
}
.chip-sub {
  font-family: var(--mono);
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
/* the die says what a tap rolls: a 12px glyph after the value, muted until the finger is on it */
.chip-die {
  width: 12px; height: 12px;
  align-self: center;
  flex: none;
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
  transition: stroke 140ms ease, fill 140ms ease;
}
.chip.rollable:hover .chip-val, .chip.rollable:focus-visible .chip-val { color: var(--accent); }
.chip.rollable:hover .chip-die, .chip.rollable:focus-visible .chip-die { stroke: var(--accent); }
.chip.danger .chip-die { stroke: var(--danger); }
/* a tracked stat at its bound (Stress at 20, Hunger at 5) reads in the danger ink */
.chip.tracked.at-bound .chip-val { color: var(--danger); }
/* a value the template tones (Stress) reads in the danger ink, always */
.chip[data-tone="danger"] .chip-val { color: var(--danger); }
/* an armed pool chip waits for its partner */
.chip.armed .chip-label, .chip.armed .chip-val { color: var(--accent); }
.chip.armed .chip-die { stroke: var(--accent); fill: color-mix(in srgb, var(--accent) 35%, transparent); }
/* a computed value: shown, never touched; its number in the accent */
.chip.derived { cursor: default; }
.chip.derived.rollable { cursor: pointer; }
.chip.derived .chip-val { color: var(--accent); }

/* the cap: 10px tracked caps in the muted ink (build.mjs .cap) */
.cap { font-size: 10px; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
/* a group of values under its own cap (Physical · Social · Mental) */
.value-group { padding: 0 0 4px; }

/* ---- hero: the system's boxed stats, --cols across, a 2px rule in the ink (msStat build.mjs:161, sdAbility :167) */
.chip-row[data-tier="hero"] { display: grid; grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr)); gap: 8px; }
.chip.hero {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; width: 100%; min-height: 76px; padding: 10px 4px; box-sizing: border-box;
  border: var(--rule-w) solid var(--line); border-radius: var(--r-ctl);
  text-align: center;
}
.chip.hero:active { transform: scale(.97); }
.chip.hero.derived:active { transform: none; }
.chip.hero .chip-val { font-size: 34px; font-weight: 600; line-height: 1; }
.chip.hero .chip-label { font-size: 10px; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); line-height: 1.2; }
.chip.hero .chip-sub { font-size: 12px; }
.chip.hero .chip-die { position: absolute; top: 6px; right: 6px; }
.chip.hero.armed { border-color: var(--accent); }
.chip.hero.tracked.at-bound { border-color: var(--danger); }
/* stamp: the number, the cap label under it; a modifier (CoC's half value) small and muted below */
[data-sig-hero="stamp"] .chip.hero .chip-val { order: 1; }
[data-sig-hero="stamp"] .chip.hero .chip-label { order: 2; }
[data-sig-hero="stamp"] .chip.hero .chip-sub { order: 3; color: var(--muted); }
/* block: the cap label above in the ink at .2em, the number, the signed modifier under it */
[data-sig-hero="block"] .chip.hero { min-height: 88px; gap: 2px; border-radius: var(--r-card); }
[data-sig-hero="block"] .chip.hero .chip-label { color: var(--line); letter-spacing: .2em; }
[data-sig-hero="block"] .chip.hero .chip-val { font-size: 32px; }
[data-sig-hero="block"] .chip.hero .chip-sub { font-size: 13px; font-weight: 500; }
[data-sig-hero="block"] .chip.hero .chip-die { top: auto; bottom: 6px; }
.chip.hero .chip-sub[data-sign="neg"] { color: var(--danger); }
/* a long label in a narrow box (Intelligence in three columns on a phone) gives up some tracking, never a letter */
.chip-row[data-tier="hero"] > .chip.hero { container-type: inline-size; }
@container (max-width: 112px) { [data-sig-hero="block"] .chip.hero .chip-label { font-size: 9px; letter-spacing: .12em; } }
@container (max-width: 78px) { .chip.hero .chip-label, [data-sig-hero] .chip.hero .chip-label { font-size: 9px; letter-spacing: .1em; } }

/* ---- secondary: the cap label over a 24px number (stat2, build.mjs:175), --cols across */
.chip-row[data-tier="secondary"] { display: grid; grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr)); gap: 12px; align-items: start; }
.chip.stat2 {
  display: grid; grid-template-columns: auto auto minmax(0, 1fr); grid-template-areas: "label label label" "val sub die";
  align-items: baseline; align-content: center; justify-content: start; column-gap: 6px; row-gap: 4px;
  width: 100%; min-width: 0; min-height: 44px;
}
.chip.stat2 .chip-label { grid-area: label; font-size: 10px; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.chip.stat2 .chip-val { grid-area: val; font-size: 24px; font-weight: 500; line-height: 1; }
.chip.stat2 .chip-sub { grid-area: sub; font-size: 13px; }
.chip.stat2 .chip-die { grid-area: die; justify-self: start; }

/* ---- tertiary: the ruled list row (.lrow, build.mjs:64) — the name left, the number right in the accent, the modifier as its note */
.chip-row[data-tier="tertiary"] { display: flex; flex-direction: column; gap: 0; }
.chip.row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "label val die" "sub val die";
  align-items: center; column-gap: 12px; row-gap: 0;
  width: 100%; min-height: 44px; padding: 4px 0; box-sizing: border-box;
  border-bottom: var(--hair-w) solid var(--hair);
}
.chip.row .chip-label { grid-area: label; font-size: 15px; letter-spacing: 0; color: var(--line); }
.chip.row .chip-val { grid-area: val; font-size: 15px; line-height: 1.3; color: var(--accent); justify-self: end; }
.chip.row .chip-sub { grid-area: sub; font-size: 12px; line-height: 1.3; color: var(--muted); margin-top: 2px; }
.chip.row .chip-die { grid-area: die; }

/* ---- a pool: the host over its max ("16 / 16"), the bar under the pair (build.mjs MS.centre Health, SD.centre Hit points).
   The folded fields keep their own element, dial and aria (CONTRACT rule 1): the max as "/ N", any other part under its cap. */
.pool { min-width: 0; }
.stat-pair { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 0 8px; min-width: 0; }
.stat-pair > .chip:not(.of) { width: auto; }
.chip.of { display: inline-flex; align-items: baseline; gap: 4px; min-height: 0; padding: 0 0 2px; color: var(--muted); }
.chip.of .chip-label { font-size: 9px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.chip.of .chip-val { font-size: 14px; line-height: 1; font-weight: 400; color: var(--muted); }
.chip.of[data-role="max"] .chip-label { display: none; }
.chip.of[data-role="max"] .chip-val::before { content: "/ "; }
.chip.of.scrub-dial:hover .chip-val, .chip.of.scrub-dial:focus-visible .chip-val { color: var(--line); }
.pool-bar { height: 3px; margin-top: 6px; border-radius: var(--r-pill); background: var(--hair); overflow: hidden; }
.pool-bar::after { content: ""; display: block; height: 100%; width: calc(var(--frac, 0) * 100%); background: var(--line); transition: width 200ms ease; }

/* ---- the World of Darkness marks (S9): a rating as dots, damage as a track of
   boxes marked / and X, Hunger and Humanity as boxes that fill. All ink, all
   drawn (build.mjs:272-296). A marks run stacks full width, hairline to hairline. */
.chip-row.marks { display: flex; flex-direction: column; gap: 0; }

/* dots: the label left on a ruled row, the filled/empty circles right (rating, build.mjs:275) */
.chip.dots {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; min-height: 44px; padding: 4px 0; box-sizing: border-box;
  border-bottom: var(--hair-w) solid var(--hair);
}
.chip.dots .chip-label { font-size: 15px; letter-spacing: 0; color: var(--line); }
.chip.dots .chip-die { display: none; }
.dots { display: inline-flex; align-items: center; gap: 5px; flex: none; }
.dot { width: 11px; height: 11px; box-sizing: border-box; border-radius: var(--r-pill); border: 1.5px solid var(--line); cursor: pointer; }
.dot.on { background: var(--line); }
.chip.dots.armed .dot.on, .chip.dots.rollable:hover .dot.on, .chip.dots.rollable:focus-visible .dot.on { background: var(--accent); border-color: var(--accent); }
/* hero ratings read larger (the nine Attributes, the Discipline levels) */
.chip-row[data-tier="hero"] .chip.dots .chip-label { font-size: 16px; font-weight: 600; }
.chip-row[data-tier="hero"] .dots { gap: 6px; }
.chip-row[data-tier="hero"] .dot { width: 14px; height: 14px; }

/* a damage track: the clear count over the max, boxes marked / then X (trackRow, build.mjs:286) */
.track-row { display: flex; flex-direction: column; gap: 8px; width: 100%; min-height: 44px; padding: 10px 0; box-sizing: border-box; border-bottom: var(--hair-w) solid var(--hair); }
.track-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.track-count { display: inline-flex; align-items: baseline; gap: 4px; }
.chip.track { min-height: 0; }
.chip.track .chip-val { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.chip.track.rollable:hover .chip-val, .chip.track.rollable:focus-visible .chip-val { color: var(--accent); }
.track-count .chip.of { padding: 0; }
.track-count .chip.of .chip-val { font-size: 12px; }
.track-count .chip.of[data-role="max"] .chip-val::before { content: "of "; }
.track { display: flex; flex-wrap: wrap; gap: 5px; }
.track-marks { display: inline-flex; align-items: center; gap: 12px; }

/* a box on a track or a Hunger/Humanity row: 18px, the mark glyph inside */
.tbox {
  width: 18px; height: 18px; box-sizing: border-box; flex: none; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line); border-radius: 2px; background: none;
  color: var(--line); cursor: pointer;
}
.tbox svg { width: 12px; height: 12px; }
.tbox.over { margin-left: 12px; }
.track .tbox[data-mark="sup"], .track .tbox[data-mark="agg"] { background: none; }

/* Hunger and Humanity: the cap and its "N of M" over a row of filling boxes */
.chip.boxes {
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; row-gap: 8px;
  width: 100%; min-height: 44px; padding: 10px 0; box-sizing: border-box;
  border-bottom: var(--hair-w) solid var(--hair);
}
/* Humanity carries its Stains beside it: the host keeps its own value, the Stains ride the top-right */
.boxes-pair { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "host stains"; align-items: start; border-bottom: var(--hair-w) solid var(--hair); }
.boxes-pair > .chip.boxes { grid-area: host; border-bottom: 0; }
.boxes-pair > .chip.mark { grid-area: stains; margin-top: 14px; }
.chip.boxes .chip-label { margin-right: auto; }
.chip.boxes .chip-val { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.chip.boxes .boxes-of { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.chip.boxes .chip-die { display: none; }
.boxes { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 5px; }
.boxes .tbox.full { background: var(--line); border-color: var(--line); }
.boxes.blood .tbox.full { background: var(--accent); border-color: var(--accent); }
.boxes .tbox.stain { color: var(--danger); border-color: var(--danger); background: none; }

/* a folded damage counter or the Stains: a tiny dial chip, its glyph then its count */
.chip.mark { display: inline-flex; align-items: center; gap: 3px; min-height: 0; padding: 0; color: var(--muted); }
.chip.mark .mark-glyph { width: 11px; height: 11px; flex: none; }
.chip.mark .chip-val { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.chip.mark[data-role="stains"] { color: var(--danger); }
.chip.mark[data-role="stains"] .chip-val { color: var(--danger); }

/* ---- the choice row: a cycle select's states, the cap label over the value and the chevron on a hairline (choice, build.mjs:198) */
.chip-row[data-tier="controls"] { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.chip-row[data-tier="controls"] .chip.cycle {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto minmax(44px, auto); grid-template-areas: "label label" "val chev";
  align-items: end; row-gap: 4px; column-gap: 8px;
  width: 100%; padding: 0 0 6px; box-sizing: border-box; border-bottom: var(--hair-w) solid var(--hair);
}
.chip-row[data-tier="controls"] .chip.cycle .chip-label { grid-area: label; font-size: 10px; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.chip-row[data-tier="controls"] .chip.cycle .chip-val { grid-area: val; font-family: var(--sans); font-size: 16px; line-height: 1.3; color: var(--line); }
.chip-row[data-tier="controls"] .chip.cycle .choice-chev { grid-area: chev; width: 12px; height: 12px; margin-bottom: 4px; color: var(--muted); }
.chip-row[data-tier="controls"] .chip.cycle:hover, .chip-row[data-tier="controls"] .chip.cycle:focus-visible { border-bottom-color: var(--line); }

/* ---- the pill: the one shape an action keeps (action, build.mjs:205) — 44px, the accent border, the danger ink when the roll says so */
.chip-row[data-tier="actions"] { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.chip.action {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  min-height: var(--tap); padding: 0 18px;
  border: var(--hair-w) solid var(--accent); border-radius: var(--r-pill); background: none;
  color: var(--accent); font-size: 13px; font-weight: 500; white-space: nowrap;
}
.chip.action:active { transform: scale(.97); }
.chip.action .chip-label { color: inherit; letter-spacing: 0; }
.chip.action .chip-sub { color: var(--muted); font-size: .74rem; font-weight: 400; }
.chip.action .chip-die, .chip.action:hover .chip-die, .chip.action:focus-visible .chip-die { stroke: currentColor; width: 14px; height: 14px; }
.chip.action:hover, .chip.action:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.chip.action.danger { border-color: var(--danger); color: var(--danger); }
.chip.action.danger:hover, .chip.action.danger:focus-visible { background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* chips that are neither a tiered value nor an action — the catalogue's chosen skills and the shop's tabs (S7),
   a shop group's choice (S6), the wizard's and the readout's picks (S8) — keep the old pill until their slice */
.chip.skill, .item-group-choice .chip, .wizard .chip-row .chip:not(.action), .consequence-pick .chip {
  padding: .6rem .95rem .6rem .8rem; border: var(--hair-w) solid var(--hair); border-radius: var(--r-pill); background: var(--face);
}
.item-group-choice .chip:hover, .wizard .chip-row .chip:not(.action):hover, .consequence-pick .chip:hover,
.item-group-choice .chip:focus-visible, .wizard .chip-row .chip:not(.action):focus-visible, .consequence-pick .chip:focus-visible { border-color: color-mix(in srgb, var(--accent) 55%, var(--hair)); }
.wizard .chip-row .chip.armed, .consequence-pick .chip.armed { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--face)); }
.chip.cycle .chip-val { font-family: var(--sans); font-size: .82rem; color: var(--line); }

.gesture-hint { margin: .45rem 0 0; color: var(--muted); font-size: .78rem; }

/* ---- typed entry: a numeric field floated over the chip, never inside it */
.scrub-entry {
  position: fixed;
  z-index: 41;
  box-sizing: border-box;
  padding: 0 6px;
  border: 1px solid var(--accent);
  border-radius: var(--r-pill);
  background: var(--face);
  color: var(--line);
  font-family: var(--mono);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  text-align: center;
  outline: none;
}

/* ---- the rail: a wireframe drum, fixed over the chip, posed from JS */
.scrub-rail {
  position: fixed;
  z-index: 40;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0;
  transition: opacity 150ms ease;
}
.scrub-rail[data-show="1"] { opacity: 1; }
.scrub-rail-col { position: relative; width: 150px; height: 212px; }
.scrub-rail-val {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 44px;
  height: 24px;
  padding: 0 10px;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--paper) 84%, transparent);
  font-family: var(--mono);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--line);
}
.scrub-rail-tag { font-family: var(--sans); font-size: 10px; letter-spacing: .01em; color: var(--muted); }
.scrub-d1 { opacity: .6; }
.scrub-d2 { opacity: .35; }
.scrub-d3 { opacity: .15; }
@media (prefers-reduced-motion: reduce) {
  .scrub-rail { transition: none; }
}

/* ---- the dice tray: Dicebox's felt over the sheet (src/tray-overlay.js, on
   by Options → Dice). One full-viewport canvas at 20: over the sheet, the
   folio and the bar (10), under the readout (30), the popovers (40) and the
   dial's rail and typed entry (40, 41), so the answer and every control the
   sheet floats stay reachable while the dice are on the felt. It draws with
   the sheet's own tokens, read off :root by the host. --tray-reserve is the
   room the card takes when it lands (body.has-readout below, plus the safe
   area), registered so the host reads it back in px and the dice never
   settle behind the answer. */
@property --tray-reserve { syntax: '<length>'; inherits: false; initial-value: 0px; }
.tray-overlay {
  position: fixed;
  inset: 0;
  /* a canvas is a replaced element: inset alone leaves it at its bitmap's size */
  width: 100%;
  height: 100%;
  display: block;
  z-index: 20;
  touch-action: none;
  background: color-mix(in srgb, var(--paper) 72%, transparent);
  opacity: 1;
  transition: opacity 160ms ease;
  --tray-reserve: calc(8.5rem + env(safe-area-inset-bottom, 0px));
}
.tray-overlay.is-hiding { opacity: 0; }
.tray-overlay[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .tray-overlay { transition: none; } }

/* ---- the readout: the largest visual event on the sheet */
.readout {
  position: fixed;
  left: 50%;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  transform: translateX(-50%);
  width: min(560px, calc(100vw - 24px));
  padding: 20px 22px 16px;
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  background: var(--face);
  color: var(--line);
  box-shadow: var(--shadow-float);
  cursor: pointer;
  animation: readout-in 160ms ease-out;
  touch-action: none;
  transition: transform 180ms ease, opacity 180ms ease;
}
.readout.dragging { transition: none; }
.readout[hidden] { display: none; }
@keyframes readout-in { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
@media (prefers-reduced-motion: reduce) { .readout { animation: none; } }
/* the headline is the largest event on the sheet: a number in the mono face,
   a word (a dice-pool verdict) in the system's signature title face. The kind
   is stamped from the headline itself (showReadout). */
.readout-head {
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  overflow-wrap: anywhere;
}
.readout-head[data-kind="number"] {
  font-family: var(--mono);
  font-size: 4.5rem;
  font-weight: 600;
  letter-spacing: -.01em;
}
.readout-head[data-kind="word"] {
  font-family: var(--sig-family);
  font-size: 2.5rem;
  font-weight: var(--sig-title-weight);
  letter-spacing: var(--sig-title-track);
  line-height: var(--sig-title-lh);
}
/* Panic is its own mark: the mono face at 44px in danger, whatever the kind */
.readout-head[data-variant="ms-panic"] {
  font-family: var(--mono);
  font-size: 2.75rem;
  font-weight: 600;
  letter-spacing: 0;
}
/* the verdict beneath a number headline: "Success" under the percentile face */
.readout-word { font-size: 1.125rem; font-weight: 600; color: var(--line); margin-top: .3rem; overflow-wrap: anywhere; }
.readout-word[hidden] { display: none; }
.readout-detail { margin-top: .55rem; color: var(--muted); font-family: var(--mono); font-size: .75rem; line-height: 1.5; overflow-wrap: anywhere; white-space: pre-line; }
.readout-detail::first-line { color: var(--line); }
/* the source, the mono footnote at the foot of the card (build.mjs:609) */
.readout-source {
  display: block;
  margin-top: .6rem;
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .02em;
  color: var(--muted);
}
.readout-source[hidden] { display: none; }
.readout.arming { border-color: color-mix(in srgb, var(--accent) 45%, var(--hair)); }
.readout.arming .readout-head { font-family: var(--sans); font-size: 1.15rem; font-weight: 650; color: var(--line); }
.readout.error { border-color: var(--danger); }
.readout.error .readout-head { font-family: var(--sans); font-size: 1.15rem; font-weight: 650; color: var(--danger); }
body.has-readout { padding-bottom: 8.5rem; }

/* ghost buttons that carry words are not 34px squares */
.char-confirm .ghost-btn {
  width: auto; height: auto; min-height: 36px;
  padding: .35rem .7rem; white-space: nowrap; font-size: .82rem;
}
/* the wordmark yields to the game badge on a phone; the mark stays */
@media (max-width: 480px) {
  .wordmark { display: none; }
}

/* ============================================================================
   Home: the front door. First run picks a game (rows in Dicebox's mode-picker
   shape, each wearing its own accent); after that, everyone you play, grouped.
   ========================================================================== */
.home-hero { margin: 1.2rem 0 1.4rem; }
.home-title { font-size: 1.6rem; letter-spacing: -.01em; margin: 0 0 .35rem; }
.home-sub { margin: 0; color: var(--muted); font-size: .9rem; max-width: 34rem; }
.sys-list { display: flex; flex-direction: column; gap: 2px; }
.sys-row {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .7rem .8rem;
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  background: var(--face);
  color: var(--line);
  text-decoration: none;
  min-height: 52px;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.sys-row .sys-icon { width: 22px; height: 22px; margin: 0; color: var(--sys, var(--accent)); }
.sys-row:hover, .sys-row:focus-visible {
  border-color: color-mix(in srgb, var(--sys, var(--accent)) 55%, var(--hair));
  background: color-mix(in srgb, var(--sys, var(--accent)) 9%, var(--face));
}
.sys-row-name { font-weight: 650; font-size: .95rem; letter-spacing: .01em; }
.sys-row-sub { margin-left: auto; color: var(--muted); font-size: .72rem; text-align: right; }
.home-group h2 { display: flex; align-items: center; gap: .5rem; }
.home-group-title { display: inline-flex; align-items: center; gap: .4rem; color: inherit; text-decoration: none; }
.home-group-title .sys-icon { width: 18px; height: 18px; margin: 0; color: var(--sys, var(--accent)); }
.home-group-title:hover, .home-group-title:focus-visible { color: var(--sys, var(--accent)); }
.home-group-count { font-family: var(--mono); font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.home-new { display: inline-block; margin-top: .6rem; text-decoration: none; }
.home-group.other .sys-row { background: transparent; }

/* a line from the book under a control (a class's bonuses, a hint) */
.field-note { margin-top: 6px; color: var(--muted); font-size: 12px; line-height: 1.45; }
.field-note[hidden] { display: none; }

/* the torch clock (Shadowdark §14): a real-time countdown in the Torch section,
   the flame beside the mm:ss (mono, tabular, like every other number), one action
   pill, and a hairline bar. The pool of light sits behind the section (below). */
.torch-clock {
  margin-top: .25rem;
  display: flex;
  flex-direction: column;
  gap: .55rem;
}
.torch-clock[hidden] { display: none; }
/* snuffed but the source is still a timed one: the ticking countdown goes out,
   leaving only the relight. (None hides the whole clock — that is [hidden].) */
.torch-clock.is-unlit .torch-clock-remaining,
.torch-clock.is-unlit .torch-clock-track { display: none; }
.torch-clock-face { display: flex; align-items: center; justify-content: space-between; gap: .65rem; }
.torch-clock-flame { display: flex; color: var(--accent); }
.torch-clock.is-unlit .torch-clock-flame { color: var(--muted); }
.torch-clock-readout { display: flex; align-items: baseline; gap: .55rem; flex: 1; min-width: 0; flex-wrap: wrap; }
.torch-clock-remaining {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 28px;
  font-weight: 500;
  line-height: 1;
  color: var(--line);
  letter-spacing: .01em;
}
.torch-clock[data-phase="guttering"] .torch-clock-remaining { color: var(--accent); }
.torch-clock-state { color: var(--muted); font-size: .74rem; text-transform: lowercase; }
.torch-clock-track {
  height: 3px;
  border-radius: var(--r-pill);
  background: var(--hair);
  overflow: hidden;
}
.torch-clock-bar {
  height: 100%;
  width: 0;
  border-radius: var(--r-pill);
  background: var(--line);
  transition: width 1s linear;
}
.torch-clock[data-phase="guttering"] .torch-clock-bar { background: var(--accent); }
.torch-clock.reduce-motion .torch-clock-bar { transition: none; }
.torch-clock-actions { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
/* one pill: Light accent while unlit, Snuff a ghost while lit, Relight an accent
   pill while guttering; the plain Reset is demoted to a small text link. */
.torch-clock-btn {
  min-height: 34px;
  padding: .3rem .9rem;
  border: 1px solid var(--hair);
  border-radius: var(--r-pill);
  background: var(--paper);
  color: var(--line);
  font: inherit;
  font-size: .82rem;
  cursor: pointer;
}
.torch-clock-btn.light { border-color: var(--accent); color: var(--accent); }
.torch-clock-btn.snuff { border-color: var(--hair); color: var(--muted); }
.torch-clock-btn.snuff:hover, .torch-clock-btn.snuff:focus-visible { border-color: var(--danger); color: var(--danger); }
.torch-clock-btn.light:hover, .torch-clock-btn.light:focus-visible { border-color: var(--accent); color: var(--line); }
/* Relight is a ghost pill while burning normally, a sibling to Snuff (it
   inherits the base .torch-clock-btn pill, only recolouring)... */
.torch-clock-btn.reset { border-color: var(--hair); color: var(--muted); }
.torch-clock-btn.reset:hover, .torch-clock-btn.reset:focus-visible { border-color: var(--accent); color: var(--accent); }
/* ...and the primary accent pill while guttering, where snuff steps aside. */
.torch-clock[data-phase="guttering"] .torch-clock-btn.reset {
  min-height: 34px;
  padding: .3rem .9rem;
  border: 1px solid var(--accent);
  background: var(--paper);
  color: var(--accent);
  font-size: .82rem;
  font-weight: 600;
  text-decoration: none;
}
.torch-clock[data-phase="guttering"] .torch-clock-btn.snuff { display: none; }
.torch-clock-btn[hidden] { display: none; }

/* the pool of light behind the Torch section: a flat amber-nudged ground with a
   drawn wavering edge, never a gradient (src/torch-pool.js, design/canvas
   build.mjs:56-64). It breathes; it stutters while guttering; motion off freezes
   it to a static blob. svg.pool is qualified so the value-pool div .pool (above)
   is untouched. */
@keyframes flame-breathe { 0%, 100% { transform: scale(1); } 38% { transform: scale(1.06) translateY(-1px); } 62% { transform: scale(.97); } }
@keyframes pool-breathe { 0%, 100% { opacity: 1; } 45% { opacity: .92; } 70% { opacity: .97; } }
@keyframes sd-gutter { 0%, 100% { opacity: 1; } 34% { opacity: .55; } 52% { opacity: .85; } 71% { opacity: .5; } 84% { opacity: .75; } }
.flame { transform-origin: 50% 90%; animation: flame-breathe 3.1s ease-in-out infinite; }
svg.pool { animation: pool-breathe 4.7s ease-in-out infinite; }
.gutter .flame, .gutter svg.pool { animation: sd-gutter 2.8s ease-in-out infinite; }
/* while a torch burns, the sections it reaches warm toward the flame's gold */
.torchlit .warm { color: color-mix(in srgb, var(--line) 82%, var(--amber) 18%); }
.torchlit .warm-note { color: color-mix(in srgb, var(--muted) 78%, var(--accent) 22%); }
@media (prefers-reduced-motion: reduce) {
  .flame, svg.pool, .gutter .flame, .gutter svg.pool { animation: none; }
}

/* catalogue lists (Mothership skills): chosen skills as tiered chips + a picker */
.catalogue-chosen .chip.skill { cursor: default; padding-right: .4rem; gap: .4rem; }
.catalogue-chosen .chip.skill:active { transform: none; }
.catalogue-chosen .chip.skill .chip-label { color: var(--line); }
.catalogue-chosen .chip.skill .row-remove { padding: 0 .2rem; font-size: .8rem; }
.chip.skill.tier-e { border-color: color-mix(in srgb, var(--accent) 35%, var(--hair)); }
.chip.skill.tier-m { border-color: var(--accent); }
.chip.skill.unmet { border-style: dashed; }
.chip.skill.unmet .chip-sub { color: var(--danger); }
/* the catalogue and the shop are a page, not a card: the app bar sits under the
   top layer, so each dialog carries its own head with a Done pill (build.mjs:256) */
.picker {
  background: var(--face);
  color: var(--line);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  padding: 1rem 1.1rem 1.1rem;
  width: min(880px, calc(100vw - 20px));
  max-height: min(86vh, 900px);
  box-shadow: var(--shadow-float);
}
.picker::backdrop { background: rgba(0, 0, 0, .55); }
.picker-page {
  inset: 0; width: 100%; max-width: none; height: 100dvh; max-height: none; margin: 0;
  border: 0; border-radius: 0; padding: 0 20px; background: var(--paper); box-shadow: none;
  overflow-y: auto; overscroll-behavior: contain;
}
.picker-page::backdrop { background: none; }
.picker-head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .4rem 1rem; padding-top: 22px; margin-bottom: .4rem; }
.picker-head h2 { margin: 0; flex: 1 1 12rem; font-family: var(--sig-family); font-size: var(--sig-title-size); font-weight: var(--sig-title-weight); letter-spacing: var(--sig-title-track); line-height: var(--sig-title-lh); text-transform: none; }
.picker-sub { flex-basis: 100%; margin: 0; color: var(--muted); font-size: .78rem; order: 3; }
.picker-close { width: auto; height: auto; padding: .35rem .8rem; font-size: .82rem; margin-left: auto; flex: none; }

/* The composer (PLAN §12 S15): a page, not a form. It rides the picker-page
   shell; its own parts are the kind tabs, the ruled fields, and the live
   "On the sheet" that renders the entry exactly as it will read. */
.composer { padding-bottom: 40px; }
.composer-kinds { display: flex; gap: 20px; overflow-x: auto; border-bottom: var(--hair-w) solid var(--hair); margin-top: 6px; }
.composer-kinds[hidden] { display: none; }
.composer-kind { flex: none; min-height: 44px; padding: 12px 0 10px; background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap; font-size: 13px; color: var(--muted); cursor: pointer; }
.composer-kind.on { color: var(--line); font-weight: 600; border-bottom-color: var(--accent); }
.composer-fields { display: flex; flex-direction: column; gap: 18px; padding-top: 18px; }
.composer-field { display: flex; flex-direction: column; gap: 4px; }
.composer-input, .composer-choice, .composer-prose { width: 100%; background: none; border: 0; border-bottom: var(--hair-w) solid var(--hair); border-radius: 0; padding: 8px 0 6px; font: inherit; font-size: 16px; color: var(--line); box-sizing: border-box; }
.composer-input.mono, .composer-choice.mono { font-family: var(--mono); }
.composer-input::placeholder, .composer-prose::placeholder { color: var(--muted); opacity: 1; }
.composer-input:focus-visible, .composer-choice:focus-visible, .composer-prose:focus-visible { outline: 0; border-bottom-color: var(--accent); }
.composer-choice { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 44px; text-align: left; cursor: pointer; }
.composer-choice .choice-val { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composer-choice.unset .choice-val { color: var(--muted); }
.composer-choice .choice-chev { flex: none; color: var(--muted); }
.composer-prose { resize: vertical; min-height: 96px; line-height: 1.5; }
@supports (field-sizing: content) { .composer-prose { field-sizing: content; resize: none; } }
.composer-hint { margin-top: 2px; }
.composer-field.invalid .composer-input, .composer-input.invalid { border-bottom-color: var(--danger); }
.composer-field.invalid .composer-hint { color: var(--danger); }
.composer-preview { margin-top: 22px; }
.composer-onsheet > h2 { display: flex; align-items: baseline; gap: 1rem; }
.composer-onsheet > h2 .cite { margin-left: auto; color: var(--muted); }
.composer-onsheet-field { margin-top: 8px; }
.composer-onsheet-field > ul { list-style: none; margin: 0; padding: 0; }
.composer-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 22px 0 8px; }
/* the search rule and the jump strip ride above the tiers; the strip sticks (build.mjs:253) */
/* the search rule: a magnifier ahead of the filter input, the ruled line under the pair
   (build.mjs:253 draws gSearch before the placeholder) */
.search-rule {
  display: flex; align-items: center; gap: 10px; min-height: var(--tap); margin: .2rem 0;
  border-bottom: var(--hair-w) solid var(--hair); color: var(--muted);
}
.search-rule:focus-within { border-bottom-color: var(--line); color: var(--line); }
.search-glyph { flex: none; width: 16px; height: 16px; }
.picker-search, .shop-search {
  flex: 1 1 auto; width: 100%; min-width: 0;
  background: none; color: var(--line); border: 0; border-radius: 0;
  padding: 6px 0; font: inherit; font-size: 16px;
}
.picker-search:focus, .shop-search:focus { outline: none; }
.picker-search::placeholder, .shop-search::placeholder { color: var(--muted); opacity: 1; }
.picker-jump {
  position: sticky; top: 0; z-index: 1;
  display: flex; gap: 16px; overflow-x: auto; padding: 8px 0;
  background: var(--paper); border-bottom: var(--hair-w) solid var(--hair);
}
.picker-jump[hidden] { display: none; }
.picker-jump-link {
  appearance: none; flex: none; padding: 0; min-height: 28px; border: 0; background: none;
  font: inherit; font-size: .78rem; letter-spacing: .04em; color: var(--muted); white-space: nowrap; cursor: pointer;
}
.picker-jump-link:hover, .picker-jump-link:focus-visible { color: var(--accent); }
/* tiers stack as sections, never tab panels: each h3 is a section header ruled
   below, its bonus and cite the footnote (build.mjs:364-376) */
.picker-tiers { display: flex; flex-direction: column; gap: 0; }
.picker-tier { padding-top: 18px; }
.picker-tier h3 {
  margin: 0 0 .2rem; padding-bottom: 8px; font-size: .72rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
  display: flex; align-items: baseline; gap: .5rem; border-bottom: var(--hair-w) solid var(--hair);
}
.picker-bonus { margin-left: auto; font-family: var(--mono); color: var(--accent); letter-spacing: 0; text-transform: none; }
.picker-tier h3 .cite { margin-left: auto; }
.picker-tier h3 .cite + .picker-bonus { margin-left: .5rem; }
/* a pick is a rulebook entry, never a card: a hairline below, the check and the
   accent rule when taken (build.mjs:225, S6 renderEntry) */
.pick {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px;
  width: 100%; text-align: left; min-width: 0;
  padding: 12px 0; border: 0; border-bottom: var(--hair-w) solid var(--hair);
  background: none; color: var(--line);
  font: inherit; font-size: 15px; cursor: pointer;
}
.pick:hover, .pick:focus-visible { outline: none; color: var(--accent); }
.pick .pick-name { flex: 1 1 auto; min-width: 0; font-weight: 600; }
.pick-check { flex: none; width: 15px; height: 15px; color: var(--accent); display: none; }
.pick.on { border-left: var(--rule-w) solid var(--accent); padding-left: 12px; margin-left: -14px; }
.pick.on .pick-check { display: block; }
.pick.locked { color: var(--muted); }
.pick.locked .pick-name { font-weight: 500; }
/* the prerequisite reads as a sub under the name, as the canvas draws it (build.mjs:225) */
.pick-needs { flex-basis: 100%; font-size: 12px; color: var(--muted); }
/* the entry wrapper already rules itself; the pick inside drops its own line */
.entry-head .pick { padding: 0; border-bottom: 0; }
.entry-head .pick.on { margin-left: 0; padding-left: 0; border-left: 0; }
.entry.pick-row:has(.pick.on) { border-left: var(--rule-w) solid var(--accent); padding-left: 12px; margin-left: -14px; }

/* cards are links now: no underline, and a group's cards wear its colour */
.char-card, .char-card:hover { text-decoration: none; color: var(--line); }
.char-card .char-meta { text-decoration: none; }
.home-group .char-card .sys-icon { color: var(--sys, var(--accent)); }
.sys-row-name { flex: 1 1 auto; min-width: 0; }
.sys-row-sub { flex: 0 1 auto; max-width: 48%; }

/* ---- page tags: where in the book this lives, as a footnote in the dice voice (build.mjs section cite) */
.cite {
  margin-left: .5rem;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--muted);
  border: 0;
  background: none;
  padding: 0;
  vertical-align: baseline;
  white-space: nowrap;
}
.section > h2 .cite { margin-left: auto; flex: 0 1 auto; min-width: 0; max-width: 55%; display: inline-flex; align-items: baseline; overflow: hidden; }
/* the book and its page tag are two spans everywhere a citation renders; the space between them lives here */
.cite .cite-book + .cite-page { margin-left: .32em; }
.section > h2 .cite .cite-book { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.section > h2 .cite .cite-page { flex: none; white-space: nowrap; }
/* the count of a citation's other sources: a small pill in the footnote's voice; a tap opens the list */
.cite-more {
  flex: none; margin-left: .35em; padding: 0 .45em; min-height: 0; height: auto; width: auto;
  font: inherit; font-size: 10px; line-height: 1.5; letter-spacing: .04em;
  color: var(--muted); background: none; border: var(--hair-w) solid var(--hair); border-radius: var(--r-pill);
  cursor: pointer;
}
.cite-more:disabled { cursor: default; }
.cite-more:not(:disabled):hover, .cite-more:not(:disabled):focus-visible { color: var(--line); border-color: var(--line); }
.cite-full {
  list-style: none; margin: 6px 0 0; padding: 0;
  font-family: var(--mono); font-size: 10px; letter-spacing: .04em; color: var(--muted); line-height: 1.6;
}
.cite-full li { padding-left: 1em; text-indent: -1em; }
.cite-full li::before { content: '· '; }
/* the Owlbear line in the room panel: a dot in the flag's colour, then the sentence */
.room-owlbear { display: flex; gap: .5em; align-items: baseline; }
.room-owlbear::before { content: ''; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--muted); position: relative; top: -1px; }
.room-owlbear[data-status="connected"]::before { background: var(--accent); }
.room-owlbear[data-status="searching"]::before { background: var(--muted); animation: room-owlbear-pulse 1.6s ease-in-out infinite; }
@keyframes room-owlbear-pulse { 50% { opacity: .35; } }
/* the panel's error surface: only ever created by an uncaught error, only in Owlbear */
.panel-errors { position: fixed; left: 0; right: 0; bottom: 0; margin: 0; padding: 6px 10px; font: 11px/1.4 var(--mono); color: #fff; background: #7a1f1f; white-space: pre-wrap; z-index: 99; }
.field label .cite { margin-left: .5rem; letter-spacing: .04em; text-transform: none; white-space: normal; }

/* ---- filled text: something the sheet wrote for you reads as a note on the same ruled line */
.filled-text {
  position: relative;
  border: 0;
  border-bottom: var(--hair-w) solid var(--hair);
  border-radius: 0;
  padding: 12px 0 6px;
  background: none;
  color: var(--line);
  font-size: 16px;
  line-height: 1.4;
  cursor: default;
  user-select: none;
  -webkit-user-select: none;
  min-height: 44px;
}
.filled-text:hover, .filled-text:focus-visible { outline: none; border-bottom-color: var(--line); }
/* "hold to edit" waits for a hover or a focus (brief.md:182-183) */
.filled-hint {
  position: absolute; right: 0; bottom: 6px;
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
  opacity: 0; transition: opacity 120ms ease;
}
.filled-text:hover .filled-hint, .filled-text:focus-visible .filled-hint { opacity: 1; }
.field.filled > textarea { min-height: 3.2em; }

/* ---- table chips beside a field's label */
.table-chip { margin: .1rem 0 .45rem; }

/* ---- roll up: the book's steps, one at a time */
.wizard {
  background: var(--face);
  color: var(--line);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  padding: 1rem 1.1rem 1rem;
  width: min(640px, calc(100vw - 20px));
  max-height: min(88vh, 900px);
  box-shadow: var(--shadow-float);
  display: flex; flex-direction: column; gap: .8rem;
}
.wizard:not([open]) { display: none; }
.wizard::backdrop { background: rgba(0, 0, 0, .55); }
.wizard-step { font-family: var(--mono); font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.wizard-head h2 { margin: .2rem 0 .3rem; font-family: var(--sig-family); font-size: var(--sig-title-size); font-weight: var(--sig-title-weight); letter-spacing: var(--sig-title-track); line-height: var(--sig-title-lh); display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.wizard-text { margin: 0 0 .4rem; color: var(--muted); font-size: .88rem; line-height: 1.45; }
.wizard-body { flex: 1 1 auto; overflow-y: auto; display: flex; flex-direction: column; gap: .6rem; }
.wizard-rolls { display: flex; flex-direction: column; gap: .4rem; }
.wizard-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.wizard-row .chip-val { min-width: 2.2rem; text-align: right; }
.wizard-result { color: var(--muted); font-size: .78rem; font-family: var(--mono); }
.wizard-status { margin: 0; font-size: .88rem; color: var(--line); }
.wizard-foot { display: flex; align-items: center; gap: .5rem; border-top: 1px solid var(--hair); padding-top: .7rem; }
.wizard-spacer { flex: 1 1 auto; }
.wizard .ghost-btn { width: auto; height: auto; padding: .45rem .8rem; font-size: .85rem; }
.rollup-btn, .head-btn { width: auto; height: auto; padding: .35rem .7rem; font-size: .82rem; white-space: nowrap; }

/* the publishers' notices in the help panel */

/* a book pack's text sits under ours, marked as the book's */
.field-note.book { margin-top: 8px; color: var(--line); }
.pick-text { font-size: .72rem; color: var(--muted); line-height: 1.35; }
.pack-remove { width: auto; height: auto; padding: .15rem .5rem; font-size: .72rem; margin-left: .5rem; }

/* ---- the book's equipment picker */
.shop { margin: .2rem 0 .5rem; }
/* the shop's group tabs are underlined text, the count in mono muted beside each,
   scrolling on a hairline (build.mjs:250) — never pills */
.shop-tabs { display: flex; gap: 20px; overflow-x: auto; margin: 6px 0 0; border-bottom: var(--hair-w) solid var(--hair); }
.shop-tabs .chip {
  display: flex; align-items: baseline; gap: 6px; flex: none; min-height: var(--tap); padding: 12px 0 0;
  border: 0; border-radius: 0; background: none; white-space: nowrap;
  font-size: 13px; color: var(--muted); cursor: pointer;
}
.shop-tabs .chip .chip-label { color: inherit; }
.shop-tabs .chip .chip-sub { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.shop-tabs .chip:hover, .shop-tabs .chip:focus-visible { outline: none; color: var(--line); }
.shop-tabs .chip[aria-selected="true"] { color: var(--line); font-weight: 600; margin-bottom: -1px; border-bottom: var(--rule-w) solid var(--accent); }
.shop-list { display: flex; flex-direction: column; gap: 0; }
/* the cost sits at the row's right edge, mono and muted (build.mjs:240 renderEntry) */
.pick .pick-cost { flex: none; margin-left: auto; font-family: var(--mono); font-size: 12px; color: var(--muted); }

/* ============================================================================
   The header, as Dicebox draws it: wordmark, a badge naming the game, and a
   row of round ghost buttons. Popovers hang under their buttons.
   ========================================================================== */
.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: 14px clamp(.75rem, 3vw, 1.5rem) 6px;
  max-width: 780px;
  margin: 0 auto;
}
.bar .brand { gap: .5rem; }
.bar .brand-mark { width: 22px; height: 22px; color: var(--muted); }
.wordmark {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}
.system-badge {
  appearance: none;
  margin: 0 auto 0 10px;
  border: 1px solid var(--accent);
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  cursor: pointer;
  white-space: nowrap;
  max-width: 40vw;
  overflow: hidden;
  text-overflow: ellipsis;
}
.system-badge[hidden] { display: none; }
.bar-actions { display: flex; align-items: center; gap: 6px; flex: none; }
.ghost {
  appearance: none;
  border: 1px solid var(--hair);
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  min-height: 32px;
  padding: 0 12px;
  border-radius: var(--r-pill);
  cursor: pointer;
  text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color 120ms ease, border-color 120ms ease;
}
.ghost:hover, .ghost:focus-visible { color: var(--accent); border-color: var(--accent); }
.ghost[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
.ghost.icon { width: 32px; padding: 0; font-size: 14px; letter-spacing: 0; }
.ghost.icon.lit { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 60%, var(--hair)); }
.share-flag {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent); margin-right: 2px; white-space: nowrap;
}
.share-flag[hidden] { display: none; }
.share-flag.busy { color: var(--muted); }
.share-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: share-pulse 2.4s ease-in-out infinite; }
@keyframes share-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .share-dot { animation: none; } }
/* the theme button shows the icon for the scheme you are in */
[data-theme-mode="dark"] [data-icon="sun"], :root:not([data-theme-mode="dark"]) [data-icon="moon"] { display: none; }
@media (max-width: 420px) { .wordmark { display: none; } .share-flag-text { display: none; } }
/* the Owlbear panel is exactly that wide, and a lone dot there says nothing: keep the words */
html[data-owlbear] .share-flag-text { display: inline; }

/* ---- popovers: the game picker (Dicebox's mode sheet) and the table panel */
.mode-pop, .room-pop {
  position: fixed;
  z-index: 40;
  background: var(--face);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-float);
  animation: pop-in 160ms ease both;
}
@keyframes pop-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .mode-pop, .room-pop { animation: none; } }
.mode-pop[hidden], .room-pop[hidden] { display: none; }
.mode-pop { width: 260px; max-height: min(84vh, 640px); overflow-y: auto; padding: 6px; display: flex; flex-direction: column; gap: 1px; }
.mode-row {
  appearance: none; display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 7px 9px; border: 0; border-radius: var(--r-ctl); background: none; color: var(--line);
  font: inherit; text-align: left; cursor: pointer; transition: background 120ms ease;
}
.mode-row:hover { background: color-mix(in srgb, var(--line) 7%, transparent); }
.mode-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.mode-row[aria-pressed="true"] {
  background: color-mix(in srgb, var(--sys, var(--accent)) 13%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sys, var(--accent)) 50%, transparent);
}
.mode-row-pinned { border-bottom: 1px solid var(--hair); border-radius: var(--r-ctl) var(--r-ctl) 0 0; margin-bottom: 3px; padding-bottom: 9px; }
.mode-row-ico { width: 20px; height: 20px; flex: 0 0 auto; color: var(--sys, var(--muted)); margin: 0; }
.mode-row-name { font-size: 13px; font-weight: 650; letter-spacing: 0.01em; white-space: nowrap; }
.mode-row-sub { margin-left: auto; font-size: 10.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-left: .5rem; }

.room-pop { width: min(340px, calc(100vw - 20px)); max-height: min(78vh, 620px); overflow-y: auto; padding: 12px 16px 14px; }
.pop-title, .room-label {
  margin: 0 0 8px; font-family: var(--mono); font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
}
.room-label { display: block; font-size: 11px; margin: 0 0 6px; }
.room-block { padding: 12px 10px; border-top: 1px solid var(--hair); }
.room-block-lead { border-top: 0; padding-top: 4px; }
.room-live { padding: 12px 10px; border-top: 0; }
.room-hint { margin: 8px 0 0; font-size: 12px; line-height: 1.5; color: var(--muted); max-width: 46ch; }
.room-phrase, .room-you {
  margin: 0 0 12px; font-family: var(--mono); font-size: 15px; line-height: 1.5; color: var(--accent);
  word-spacing: 0.3em; word-break: break-word; cursor: pointer; user-select: all; -webkit-user-select: all;
}
.room-you { color: var(--line); cursor: default; user-select: text; font-size: 14px; }
.room-pop input[type="text"] {
  width: 100%; background: var(--paper); color: var(--line); border: 1px solid var(--hair); border-radius: var(--r-ctl);
  padding: .5rem .6rem; font: inherit; font-family: var(--mono); font-size: .86rem; margin-bottom: 8px;
}
.room-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.room-actions .ghost { flex: 1 1 auto; min-height: 34px; padding: 0 8px; }
.room-leave { flex: 0 0 auto !important; color: var(--danger) !important; }
.room-roster { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 2px; max-height: 26vh; overflow-y: auto; font-size: 13px; }
.room-roster-label { margin-top: 6px; }
.room-state { margin: 10px 0 0; font-size: 12px; color: var(--muted); }
.room-state.live { color: var(--accent); }
.room-state.failed { color: var(--danger); }
.roll {
  appearance: none; min-height: var(--tap); padding: 0 22px; border: 0; border-radius: var(--r-ctl);
  background: var(--line); color: var(--paper); font: inherit; font-size: 15px; font-weight: 500; letter-spacing: 0.04em; cursor: pointer; width: 100%;
}
/* the help dialog's buttons wear the same ghost */
.help-dialog button { border-radius: var(--r-pill); }

/* ---------- the roll log — Dicebox's, in its place and voice ---------- */
.log { max-width: 780px; margin: 0 auto; padding: 0 clamp(.75rem, 3vw, 1.5rem) 5rem; }
.log[hidden] { display: none; }
.log ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.log li { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; padding: 3px 0; border-top: 1px solid var(--hair); }
.log-line { display: flex; justify-content: space-between; gap: 12px; }
.log-label { display: flex; flex-wrap: wrap; gap: 0 .5em; min-width: 0; }
.log-who { color: var(--accent); }
.log-who[data-self] { color: var(--muted); opacity: .75; }
.log-what { color: var(--line); }
.log-notation { font-family: var(--mono); }
.log li b, .history-full li b { color: var(--line); font-weight: 600; white-space: nowrap; }
.log-detail { display: block; font-size: 11px; opacity: .85; overflow-wrap: anywhere; white-space: pre-line; }
.log li[data-remote] { border-left: 2px solid var(--accent); padding-left: 6px; margin-left: -8px; }
.log-empty { border-top: 0 !important; }
.log-more { margin: 4px 0 0; text-align: center; }
.log-more-button { appearance: none; border: 0; background: none; color: var(--muted); font: inherit; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; padding: 3px 6px; cursor: pointer; }
.log-more-button:hover, .log-more-button:focus-visible { color: var(--accent); }
.log-count { font-variant-numeric: tabular-nums; text-transform: none; letter-spacing: 0; opacity: .8; }
.history-dialog {
  background: var(--face); color: var(--line);
  border: 1px solid var(--hair); border-radius: var(--r-card);
  width: min(640px, calc(100vw - 20px)); max-height: min(84vh, 720px);
  padding: 10px 14px 14px; box-shadow: var(--shadow-float);
}
.history-dialog[open] { display: flex; flex-direction: column; }
.history-dialog::backdrop { background: rgba(0,0,0,.55); }
.sheet-title { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; font-weight: 650; font-size: .95rem; }
.sheet-close { margin-left: auto; }
.history-full { list-style: none; margin: 0; padding: 0 2px; overflow-y: auto; scrollbar-width: thin; flex: 1 1 auto; min-height: 0; font-size: 13px; }
.history-full li { line-height: 1.4; color: var(--muted); font-variant-numeric: tabular-nums; padding: 6px 8px; border-bottom: 1px solid var(--hair); }
.history-full li:last-child { border-bottom: 0; }
.history-full li[data-remote] { border-left: 2px solid var(--accent); padding-left: 6px; }
.history-full .log-detail { font-size: .92em; }
.history-time { font-family: var(--mono); font-size: .9em; opacity: .75; min-width: 7em; }
.history-empty { color: var(--muted); }
.history-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.history-clear { margin-left: auto; }

/* ---------- the folio: three columns, the center first ---------- */
.view.folio-view { max-width: 780px; }
/* the tab rail: text on a hairline, the page in view underlined in the accent (build.mjs tabs) */
.folio-tabs {
  display: flex;
  margin: 4px 0 0;
  border: 0; border-bottom: var(--hair-w) solid var(--hair); border-radius: 0; overflow: visible;
  background: none;
}
.folio-tab {
  flex: 1 1 0; appearance: none; font: inherit; font-size: 13px; letter-spacing: .01em;
  min-height: 44px; min-width: 0; padding: 0 6px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  background: none; border: 0; color: var(--muted);
  transition: color 140ms ease;
}
.folio-tab .tab-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.folio-tab .tab-arrow { display: flex; line-height: 1; }
.folio-tab .tab-arrow svg { width: 12px; height: 12px; display: block; }
.folio-tab:hover, .folio-tab:focus-visible { color: var(--line); }
.folio-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.folio-tab[aria-current] {
  color: var(--line);
  font-weight: 600;
  margin-bottom: -1px;
  border-bottom: var(--rule-w) solid var(--accent);
  background: none;
}
.folio {
  --gutter: clamp(.75rem, 3vw, 1.5rem);
  /* no peek of the next page: without cards a sliver of a neighbour is a fragment of text, and the tab
     rail's chevrons say a page is a swipe away; the gap is the gutter so the neighbour sits just offscreen */
  --peek: 0px;
  display: flex; gap: var(--gutter);
  margin: 0 calc(-1 * var(--gutter)); padding: 0 var(--gutter);
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; scroll-padding-inline: var(--gutter);
  overscroll-behavior-x: contain; scrollbar-width: none;
}
.folio::-webkit-scrollbar { display: none; }
.page {
  flex: 0 0 calc(100% - var(--peek));
  scroll-snap-align: start; scroll-snap-stop: always;
  display: grid; gap: 0; align-content: start;
  max-height: calc(100dvh - var(--folio-top, 220px));
  overflow-y: auto; overscroll-behavior-y: contain; scrollbar-width: none;
  padding-bottom: 7rem;
}
.page::-webkit-scrollbar { display: none; }
.page .section { margin: 0; }
/* the section's body stacks at the canvas's rhythm (build.mjs section: gap 12px under the header) */
.page .section > h2 { margin-bottom: 0; }
.page .section > * + * { margin-top: 12px; }
.page .section > * + .value-group { margin-top: 14px; }
.page .section > h2 + .value-group { margin-top: 4px; }
.page .log { max-width: none; margin: 0; padding: 22px 0 0; }
/* the values' grids come from their tier (.chip-row[data-tier]), the same on every page */
.page-center .gesture-hint { margin-top: .1rem; }
/* wide: the three pages side by side, a hairline between columns, the name at 44px (build.mjs desktop) */
@media (min-width: 900px) {
  .view.folio-view { max-width: 1320px; }
  .folio-tabs { display: none; }
  .folio {
    display: grid; gap: 0; align-items: start;
    margin: 8px 0 0; padding: 0; overflow: visible; scroll-snap-type: none;
  }
  .folio[data-cols="left center right"] { grid-template-columns: minmax(250px, 1fr) minmax(360px, 1.5fr) minmax(250px, 1fr); }
  .folio[data-cols="left center"] { grid-template-columns: minmax(250px, 1fr) minmax(360px, 1.5fr); }
  .folio[data-cols="center right"] { grid-template-columns: minmax(360px, 1.5fr) minmax(250px, 1fr); }
  .folio[data-cols="center"] { grid-template-columns: minmax(360px, 1fr); }
  .page { max-height: none; overflow: visible; padding: 0 36px; }
  .page:first-child { padding-left: 0; }
  .page:last-child { padding-right: 0; }
  .page + .page { border-left: var(--hair-w) solid var(--hair); }
  .sheet-name-input { font-size: 44px; }
  .portrait-box { width: 88px; height: 88px; }
}

/* a picker is a full page on a phone; from 900px it is a right-anchored sheet with a hairline
   down its left, the app bar visible to its left (PLAN §3 S7 Container) */
@media (min-width: 900px) {
  .picker-page {
    inset: 0 0 0 auto; width: min(560px, 100%); height: 100dvh;
    border-left: var(--hair-w) solid var(--line);
  }
}

/* a field's label line carries its table's roll chip; the entry box grows to fit */
.field-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .3rem; }
.field-head label { margin: 0; }
.chip.action.table-chip.inline { margin: 0; min-height: 32px; padding: .2rem .7rem .2rem .55rem; font-size: .78rem; flex: none; }
.field textarea.grow { resize: none; overflow: hidden; min-height: 2.4em; line-height: 1.35; }

/* an edit in the log: quieter than a roll */
.log li[data-event] { color: var(--muted); }
.log-event { color: var(--muted); }

/* skills in training, skills of your own, and the picker's rows */
.chip.skill.training { border-style: dashed; }
.chip.skill.custom .chip-sub { font-style: italic; }
.chip-learn { color: var(--accent); }
.pick.training .pick-name { color: color-mix(in srgb, var(--accent) 70%, var(--muted)); font-weight: 500; font-style: italic; }
.pick-custom { display: flex; gap: .35rem; margin-top: .45rem; }
.pick-custom input { flex: 1 1 auto; min-width: 0; font: inherit; font-size: .82rem; padding: .35rem .55rem; border-radius: var(--r-ctl); border: 1px solid var(--hair); background: var(--paper); color: var(--line); }
.pick-custom .ghost-btn { width: auto; height: auto; padding: .3rem .6rem; font-size: .78rem; white-space: nowrap; }
.pack-sources { display: inline-flex; flex-wrap: wrap; gap: .2rem .6rem; }
.pack-source { display: inline-flex; align-items: baseline; gap: .35rem; }

/* the share setting reads as one paragraph with its box */
.share-toggle { display: flex; gap: .6rem; align-items: flex-start; cursor: pointer; }
.share-toggle input { margin-top: .2em; flex: none; accent-color: var(--accent); }
.export-dialog[open] { display: block; }

/* a custom skill's tier is a control: tap to cycle Trained → Expert → Master */
.chip-tier { appearance: none; font: inherit; font-size: inherit; background: none; border: 0; border-bottom: 1px dashed currentColor; padding: 0; color: inherit; cursor: pointer; }
.chip-tier:hover, .chip-tier:focus-visible { color: var(--accent); }

/* skills in training: a column of their own in the picker */
.picker-training .chip-row { margin-bottom: .5rem; }
.picker-training .choice, .pick-custom .choice { align-items: center; min-height: 36px; font-size: .82rem; padding: .35rem .5rem; border-radius: var(--r-ctl); border: 1px solid var(--hair); background: var(--paper); color: var(--line); max-width: 100%; }
.picker-training .choice:hover, .pick-custom .choice:hover, .picker-training .choice[aria-expanded="true"], .pick-custom .choice[aria-expanded="true"] { border-color: color-mix(in srgb, var(--accent) 55%, var(--hair)); }
.picker-training .choice > .choice-chev, .pick-custom .choice > .choice-chev { margin-bottom: 0; }
.picker-training .train-pick { width: 100%; }
.pick-custom .choice { flex: none; }
/* the wizard's guide over the picker: the rule, and where the picks stand */
.picker-guide { margin: .5rem 0 .2rem; padding: .55rem .75rem; border: 1px solid var(--hair); border-radius: var(--r-card); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.picker-guide[hidden] { display: none; }
.picker-guide-text { margin: 0; font-size: .82rem; color: var(--line); }
.picker-guide-status { margin: .3rem 0 0; font-size: .8rem; color: var(--muted); }
.picker-guide-status[data-state="met"] { color: var(--accent); }
.picker-guide-status[data-state="over"] { color: var(--danger); }
.wizard-standing { margin: .2rem 0 0; }
/* options: sections under one roof */
.opt-h { margin: 14px 0 4px; font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.opt-radios { display: grid; gap: .35rem; }
.opt-radios label { display: flex; gap: .5rem; align-items: baseline; cursor: pointer; }
.opt-radios input { accent-color: var(--accent); flex: none; }
.opt-radios b { color: var(--line); font-weight: 600; }
.options-dialog[open] { display: block; }
/* one column: every page stands in order, at any width */
[data-layout="single"] .folio-tabs { display: none; }
[data-layout="single"] .folio { display: block; margin: 0; padding: 0; overflow: visible; scroll-snap-type: none; }
[data-layout="single"] .page { max-height: none; overflow: visible; padding: 0; margin-bottom: .7rem; border-left: 0; }
[data-layout="single"] .view.folio-view { max-width: 780px; }

/* the picker's own-skill rows fit a phone: the tier choice yields to the name */
.pick-custom { flex-wrap: wrap; }
.pick-custom input { flex: 1 1 8rem; min-width: 0; }
.pick-custom .choice.train-tier { flex: 0 1 auto; max-width: 42%; min-width: 0; }

/* ---- the rulebook entry (build.mjs:229): bold name, mono stat line, prose set for reading, the page as a
   footnote. Never a card: a hairline below, nothing behind. One shape for an item on a list, a typed line, a
   table's row, a picker's row and the book's note under a choice; the consumer's controls ride the head. */
.entry, .list-field li.entry { display: flex; flex-direction: column; align-items: stretch; gap: 8px; padding: 12px 0; border-bottom: var(--hair-w) solid var(--hair); min-width: 0; }
.entry.line, .list-field li.entry.line { padding: 0; border-bottom: 0; }   /* a typed line rules itself */
.entry-head { display: flex; align-items: baseline; gap: 12px; min-width: 0; }
.entry-head:has(textarea) { align-items: flex-start; }
.entry-title { flex: 1 1 auto; min-width: 0; font-size: 15px; font-weight: 600; color: var(--line); }
.entry-cost { flex: none; font-family: var(--mono); font-size: 12px; color: var(--muted); white-space: nowrap; }
.entry-sub { margin: -4px 0 0; font-size: 12px; line-height: 1.45; color: var(--muted); }
.entry-stats { display: flex; flex-wrap: wrap; gap: 4px 12px; font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; }
.item-stat { display: inline-flex; gap: 5px; align-items: baseline; }
.item-stat-k { color: var(--muted); letter-spacing: .1em; text-transform: uppercase; font-size: 10px; }
.item-stat-v { font-family: var(--mono); color: var(--line); }
.entry-text { font-size: 14px; line-height: 1.5; color: color-mix(in srgb, var(--line) 80%, var(--muted)); }
/* the two-line clamp (build.mjs:68): data-clamped once measured over, "more" beneath, a tap opens, "less" folds */
.clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.clamp[data-clamped] { cursor: pointer; }
.clamp.expanded { display: block; -webkit-line-clamp: unset; overflow: visible; cursor: auto; }
.entry-more { appearance: none; align-self: flex-start; margin: -6px 0 0; padding: 0; border: 0; background: none; font: inherit; font-size: 12px; line-height: 1.45; color: var(--muted); cursor: pointer; }
.entry-more:hover, .entry-more:focus-visible { color: var(--accent); }
.entry-more[hidden] { display: none; }
.entry-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.entry-actions .chip.action { padding: 0 14px; font-size: 12px; }
.entry-actions[hidden], .entry-tracks[hidden] { display: none; }
.item-cite { font-size: 10px; }
/* the head's own controls: an item's name and cost (ruled when they are yours to type), a row's text box, a line */
.entry-head .item-name { flex: 1 1 auto; min-width: 0; min-height: 0; background: none; border: 0; border-radius: 0; padding: 0; font: inherit; font-size: 15px; font-weight: 600; color: var(--line); }
.entry.hand-made .entry-head .item-name { border-bottom: var(--hair-w) solid var(--hair); padding: 4px 0; }
.entry-head .item-cost-input { flex: 0 1 6rem; width: auto; min-width: 0; min-height: 0; background: none; border: 0; border-bottom: var(--hair-w) solid var(--hair); border-radius: 0; padding: 4px 0; font-family: var(--mono); font-size: 12px; color: var(--muted); text-align: right; }
.entry-head textarea.grow { flex: 1 1 auto; width: auto; min-width: 0; resize: none; overflow: hidden; background: none; border: 0; border-radius: 0; padding: 0; min-height: 1.5em; font: inherit; font-size: 14px; line-height: 1.5; color: color-mix(in srgb, var(--line) 80%, var(--muted)); }
/* a line you typed on a table-backed list is a textarea too: it keeps the ruled line a typed input has */
.entry.line .entry-head textarea.grow { min-height: var(--tap); padding: 12px 0 6px; box-sizing: border-box; border-bottom: var(--hair-w) solid var(--hair); font-size: 16px; line-height: 1.3; color: var(--line); }
.entry-head .pick { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.entry-head .row-remove, .entry-head .item-promote { flex: none; align-self: center; }
/* a picker's row with the book's note: the button as the head, the note as the entry's text */
.entry.pick-row { padding: 0 0 8px; margin-bottom: 4px; }

/* an entry's foot, wherever it renders: the page tag, its numbers, and a chip per die in either */
.entry-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-width: 0; }
.entry-meta .cite { margin-left: 0; }
.entry-meta .item-stats { display: inline-flex; gap: 4px 12px; font-family: var(--mono); font-size: 12px; }
.dice-in-text { display: inline-flex; gap: 8px; }
/* a die in the prose: an inline mono link in the accent (build.mjs:216), still a button that rolls it */
.chip.action.text-die { min-height: 24px; padding: 0 2px; border: 0; border-radius: 0; gap: 4px; font-family: var(--mono); font-size: 11px; }
.chip.action.text-die .chip-sub { color: var(--accent); font-family: var(--mono); font-size: 11px; }
.chip.action.text-die .chip-die { width: 12px; height: 12px; }
.chip.action.text-die:hover, .chip.action.text-die:focus-visible { background: none; text-decoration: underline; }
.field .entry-meta { margin-top: .3rem; }
.readout-chips { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .5rem; }
.readout-chips[hidden] { display: none; }

/* ---- the post-roll follow-up surface: the second beat, in the readout ---- */
.readout-actions { margin-top: .6rem; padding-top: .55rem; border-top: 1px solid var(--hair); }
.readout-actions[hidden] { display: none; }
.followup-menu { display: flex; flex-wrap: wrap; gap: .4rem; }
.followup-btn {
  appearance: none; font: inherit; font-size: .82rem; font-weight: 600;
  min-height: 34px; padding: .3rem .8rem;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--hair));
  border-radius: var(--r-pill); background: var(--face); color: var(--line); cursor: pointer;
}
.followup-btn:hover, .followup-btn:focus-visible { border-color: var(--accent); }
.followup-btn:active { transform: scale(.97); }
.followup-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--paper); }
.followup-btn.primary:disabled { opacity: .5; cursor: default; transform: none; }
.followup-btn.ghost { border-color: var(--hair); color: var(--muted); }
.followup-note { margin: .45rem 0 0; font-size: .74rem; color: var(--muted); }
.followup-pick { display: flex; flex-direction: column; gap: .5rem; }
.followup-pick .followup-note { margin: 0; }
.followup-actions { display: flex; flex-wrap: wrap; gap: .4rem; }
/* the pool's dice, as tappable chips — a BoS-native picker, no felt tray */
.readout-dice { display: flex; flex-wrap: wrap; gap: .35rem; }
/* a die from the pool as a tappable chip: 40×44, ink by default, a Hunger die
   in the accent (the token the felt paints, DESIGN.md's tray/UI agreement),
   a picked one a 2px accent box with a faint tint, a locked one dimmed. */
.die-chip {
  appearance: none; font: inherit; width: 40px; min-width: 40px; height: 44px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line); border-radius: var(--r-ctl); background: var(--face);
  color: var(--line); cursor: pointer; font-variant-numeric: tabular-nums;
}
.die-chip .die-chip-val { font-family: var(--mono); font-size: 1.125rem; font-weight: 600; color: inherit; }
.die-chip:hover:not(.locked), .die-chip:focus-visible { border-color: var(--accent); }
.die-chip:active:not(.locked) { transform: scale(.94); }
.die-chip.picked { border-width: 2px; border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); }
.die-chip.hunger { border-color: var(--accent); color: var(--accent); }
.die-chip.locked { cursor: default; opacity: .45; }
.followup-count { display: inline-flex; align-items: center; gap: .55rem; }
.followup-count-val { min-width: 1.75rem; text-align: center; font-family: var(--mono); font-size: 1.75rem; font-weight: 500; color: var(--accent); font-variant-numeric: tabular-nums; }
.followup-step {
  appearance: none; font: inherit; font-size: 1.15rem; line-height: 1; min-width: 34px; min-height: 34px;
  border: 1px solid var(--hair); border-radius: var(--r-pill); background: var(--face); color: var(--line); cursor: pointer;
}
.followup-step:hover, .followup-step:focus-visible { border-color: var(--accent); color: var(--accent); }

/* The outcome's tint collapses to the two tokens (PLAN §3 S8): a win keeps the
   base accent, a loss turns danger, and a plain CoC miss stays muted. No
   off-token hexes — the readout speaks the sheet's own two colours. */
.readout-head[data-variant="roll-failure"] { color: var(--muted); }
.readout-head[data-variant="fear"],
.readout-head[data-variant="roll-crit-failure"],
.readout-head[data-variant="ms-failure"],
.readout-head[data-variant="ms-crit-failure"],
.readout-head[data-variant="ms-panic"],
.readout-head[data-variant="sd-failure"],
.readout-head[data-variant="sd-fumble"] { color: var(--danger); }
/* a field-kind stat found its field (solid) or did not (dashed underline) */
.item-stat.resolved .item-stat-v { text-decoration: underline dotted; text-underline-offset: .2em; }
.item-stat.unresolved .item-stat-v { color: var(--muted); }

/* the entry's tracks: what the character marks on an item — the printed sheet's own marks (build.mjs:222, :226) */
.entry-tracks { display: flex; flex-wrap: wrap; align-items: center; gap: 0 18px; }
.item-track { display: inline-flex; align-items: center; gap: 8px; min-height: var(--tap); font-size: 12px; color: var(--line); }
.item-track-step { appearance: none; font: inherit; font-size: 1rem; line-height: 1; min-width: 30px; min-height: 30px; border: 0; border-radius: var(--r-pill); background: none; color: var(--muted); cursor: pointer; }
.item-track-step:hover, .item-track-step:focus-visible { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.item-track-val { font-family: var(--mono); font-variant-numeric: tabular-nums; min-width: 1.4em; text-align: center; color: var(--line); }
.list-field li .item-track input[type="number"] { flex: none; width: 3.6rem; min-height: 0; padding: 4px 0; font-family: var(--mono); font-size: 12px; text-align: center; }
/* ammo: a row of 12px boxes, filled while the shot is still there, then the count in the mono voice; the − and +
   keep the keyboard and the reader, quiet after the caption */
.ammo { display: inline-flex; gap: 4px; margin-right: 6px; }
.ammo-box { display: block; width: 12px; height: 12px; box-sizing: border-box; border: 1.5px solid var(--line); border-radius: 2px; cursor: pointer; }
.ammo-box.on { background: var(--line); }
.ammo-track { gap: 0 4px; }
.ammo-track .item-track-val, .ammo-of { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.ammo-track .item-track-val { min-width: 0; }
.ammo-track .item-track-step { order: 2; min-width: 24px; min-height: 24px; font-size: .9rem; }
.ammo-track .ammo-of { margin-right: 4px; }
/* the equip check and any tick on an item: the canvas toggle drawn on the label; the native box rides over the
   drawn one at opacity 0, so it stays the tap, the focus and the checkbox a reader hears */
.item-track.checkbox { position: relative; color: var(--muted); cursor: pointer; }
.item-track.checkbox .toggle-box { position: relative; flex: none; width: 14px; height: 14px; box-sizing: border-box; border: 1.5px solid var(--line); border-radius: 3px; display: flex; align-items: center; justify-content: center; color: var(--accent); }
.list-field li .item-track.checkbox input[type="checkbox"] { position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0; margin: 0; padding: 0; border: 0; opacity: 0; cursor: pointer; }
.item-track.checkbox .toggle-check { width: 11px; height: 11px; visibility: hidden; }
.item-track.checkbox input:checked ~ .toggle-check { visibility: visible; }
.item-track.checkbox:has(input:checked) { color: var(--line); }
.item-track.checkbox:has(input:checked) .toggle-box { border-color: var(--accent); }
.item-track.checkbox:has(input:focus-visible) .toggle-box { outline: 2px solid var(--accent); outline-offset: 2px; }
/* an item of your own: an input per declared stat, ruled, in the mono voice */
.item-inputs { gap: 4px 12px; }
.item-input { display: inline-flex; flex-direction: column; gap: 2px; flex: 1 1 6.5rem; min-width: 0; max-width: 12rem; }
.list-field li .item-input input { width: 100%; min-height: 0; padding: 4px 0; font-family: var(--mono); font-size: 12px; }
/* a typed line's way to become an item, and the choice of group under the add row or the line */
.item-promote { font-size: .72rem; white-space: nowrap; }
.item-promote:hover, .item-promote:focus-visible { color: var(--accent); }
.list-add-row { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.list-add-row .list-add { margin-top: .4rem; }
.item-group-choice { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; margin-top: .4rem; }
.list-field li.item-group-choice { margin: 0; padding: .2rem 0; }
