/* 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;
  /* a textarea: one row that shrinks to fit, and wraps past the floor (app.js fitName) */
  display: block;
  resize: none;
  overflow: hidden;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.name-measure { position: absolute; left: -9999px; top: 0; visibility: hidden; white-space: nowrap; pointer-events: none; }
.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 10px; 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); }
/* Export and Roll up this character are words (.cmd, the dice block): a quiet one and the go word */
.sheet-head-row.quiet .cmd { margin-block: -8px; }

/* 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 { margin-top: .4rem; }
/* ✕ ✎ ✓: a glyph in the muted ink on a 44px target (the dice block sizes it where it stands) */
.row-remove { position: relative; background: none; border: none; color: var(--muted); cursor: pointer; padding: .2rem; font: inherit; }
.row-remove:hover, .row-remove:focus-visible { color: var(--line); }
.row-remove:not(.item-promote):not(.item-edit):not(.pick-edit):not(.chip-learn):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; width: auto; height: auto; 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.
   Locked, a swipe on a chip scrolls the page (pan-y); unlocked, the chip owns
   the touch. The unlocked chip wears the accent ring. */
.scrub-dial.scrub-dial { touch-action: pan-y; }
.scrub-dial.scrub-dial.armed { touch-action: none; }
.scrub-dial.armed { outline: 2px solid var(--accent); outline-offset: 2px; }
.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 a tap throws (.chip-die, src/die-glyphs.js) is drawn in the dice block at the end of this file */
/* the value lifts to the accent under a resting pointer. A phone's tap leaves :hover behind, so there it is the
   roll's own states that colour it (the dice block) */
@media (hover: hover) { .chip.rollable:hover .chip-val { color: var(--accent); } }
.chip.rollable:focus-visible .chip-val { color: var(--accent); }
/* 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); }
/* 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); }

/* ---- a section's standalone rolls: a row of roll tiles (.roll-tile, the dice block at the end of this file) */
.chip-row[data-tier="actions"] { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* 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; }
/* landed, or on its way out, the felt lets a tap through: the stat tapped next rolls
   on that first tap and the host puts the dice away as it does (src/tray-overlay.js) */
.tray-overlay.is-settled, .tray-overlay.is-hiding { pointer-events: none; }
.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 { 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 */
.share-flag.absent .share-dot { background: var(--muted); }
/* the table's seats on the home page, and a seat's sheet handed over read-only */
.table-seat .char-name { display: block; }
.table-seat.locked { opacity: .6; cursor: default; }
.sheet-foreign { display: flex; align-items: center; gap: .6rem; margin: 0 0 6px; font-family: var(--mono); font-size: 11px; letter-spacing: .04em; color: var(--muted); }
.share-sheet { display: inline-flex; align-items: center; gap: .4em; font-size: 13px; color: var(--muted); cursor: pointer; }
.share-sheet input { margin: 0; }
.read-only .chip, .read-only .list-field button, .read-only .list-add, .read-only .choice-val, .read-only .item-track, .read-only .portrait-box, .read-only .sheet-name-input { pointer-events: none; }
.read-only .sheet-name-input { border-color: transparent; }
.read-only .folio { opacity: .92; }
.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: rgba(122, 31, 31, .92); white-space: pre-wrap; z-index: 99; max-height: 45%; overflow: hidden; pointer-events: none; }
.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; }

/* 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; }
/* Dicebox's Owlbear block in the share menu (dicebox style.css), so the two panels read as one */
.room-obr { border-top: 0; padding-top: 4px; }
.room-obr-note { margin: 0; font-size: 11px; line-height: 1.35; }
.room-obr-note + .room-obr-note { margin-top: 6px; }
.room-obr-note[data-status="unsaved"], .box-state[data-status="unsaved"] { color: var(--warn, #b8862b); }
.room-obr-switch { display: flex; gap: 8px; align-items: flex-start; }
/* the share menu's one control per block, and Settings' label-and-a-line */
.share-toggle .line { display: block; color: var(--muted); font-weight: 400; }
.share-toggle > span > b { color: var(--line); font-weight: 600; }
.room-pop .room-toggle { margin-top: 8px; font-size: 12.5px; color: var(--line); }
.room-pop .room-toggle b { font-weight: 500; }
.room-pop .room-toggle .line { font-size: 12px; }
.settings-link { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.shared-mark { appearance: none; background: none; cursor: pointer; font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); border: 1px solid var(--accent); border-radius: var(--r-pill); padding: 2px 8px; }
.shared-mark[hidden] { display: none; }
.room-obr-switch-text { display: flex; flex-direction: column; gap: 2px; }
.room-subhint { color: var(--muted); font-size: 11px; line-height: 1.35; }
.room-subhint[data-status="unsaved"] { color: var(--warn, #b8862b); }
.room-claim { border-top: 1px solid var(--hair); padding-top: 10px; }
.claim-list { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.claim-row { display: flex; align-items: center; gap: 8px; }
.claim-name { font-weight: 500; }
.claim-meta { color: var(--muted); font-size: 12px; margin-right: auto; }
.claim-btn { flex: 0 0 auto; }
/* a claim asks first, in the row: the question on its own line, then the two buttons */
.claim-confirm { flex: 1 1 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.claim-confirm span { flex: 1 1 100%; font-size: 13px; line-height: 1.45; }
/* the home list's trash: a character another seat or device took off this browser */
.trash-item {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: .75rem;
  padding: .8rem .95rem;
  border: 1px dashed var(--hair); border-radius: var(--r-card);
}
.trash-name { font-weight: 650; }
.trash-row .trash-restore { width: auto; height: auto; min-height: 36px; align-self: center; padding: .35rem .7rem; white-space: nowrap; font-size: .82rem; }
.trash-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;
}
.trash-delete:hover, .trash-delete:focus-visible { color: var(--danger); border-color: var(--danger); }
.kept-ways { padding-left: 1.1em; display: flex; flex-direction: column; gap: 6px; }

.help-actions button[hidden], .help-actions[hidden] { display: none; }
.portrait-url { display: flex; gap: 8px; align-items: stretch; }
.portrait-url input { flex: 1 1 auto; min-width: 0; }
.sheet-foreign.gm-edit { color: var(--accent, inherit); }
.box-link { font-family: var(--mono, ui-monospace, monospace); font-size: 12px; word-break: break-all; user-select: all; }
.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; }
/* The Owlbear popover is exactly 420px, where the site hides the wordmark; the
   panel keeps its name the way Dicebox's does. The game badge gives way: at this
   width the two cannot both fit, and the picker button beside them already
   wears the game's own glyph. */
html[data-owlbear] .wordmark { display: inline; }
html[data-owlbear] .system-badge { display: none; }

/* ---- 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; }
.field-head .table-chip.inline { margin: 0; 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); }
.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 { position: relative; appearance: none; font: inherit; font-size: inherit; background: none; border: 0; padding: 0; color: var(--line); cursor: pointer; text-underline-offset: 3px; }
.chip-tier::after { content: ""; position: absolute; inset: -12px -4px; }
.chip-tier:hover, .chip-tier:focus-visible { text-decoration: underline; }

/* 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 { position: relative; appearance: none; align-self: flex-start; margin: -6px 0 0; padding: 0; border: 0; background: none; font: inherit; font-size: 12px; font-weight: 500; line-height: 1.45; letter-spacing: .01em; color: var(--line); cursor: pointer; text-underline-offset: 3px; }
/* a quiet word: it reads as a line of the entry, and its target reaches 44px past the letters */
.entry-more::after { content: ""; position: absolute; left: -10px; right: -10px; top: 50%; height: var(--tap); transform: translateY(-50%); }
.entry-more:hover, .entry-more:focus-visible { text-decoration: underline; }
.entry-more[hidden] { display: none; }
.entry-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.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; }
/* the numbers wrap at the row's edge, as a card's do: a gun's seven stats ran a 390 px picker sideways */
.entry-meta .item-stats { display: inline-flex; flex-wrap: wrap; min-width: 0; gap: 4px 12px; font-family: var(--mono); font-size: 12px; }
.dice-in-text { display: inline-flex; gap: 8px; }
/* a die in an entry's text is a small roll tile under it (.roll-tile.text-die, the dice block) */
.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; align-items: center; gap: 8px; }
/* a follow-up that throws is a roll tile wearing its die (Willpower's mind, Blood Surge's drop). One that
   only spends is a go word. The confirm throws, so it is a tile. Cancel is a quiet word */
.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; align-items: center; gap: 8px; }
/* 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: var(--tap); min-height: var(--tap);
  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"],
.readout-head[data-variant="crows-tier1"],
.readout-head[data-variant="crows-doom"],
.readout-head[data-variant="crows-out"] { 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 */
.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; }

/* ============================================================================
   Dice language B (design/canvas page 5, the owner's pick). A roll wears the
   die it throws, drawn in Dicebox's own hand (src/die-glyphs.js, every shape
   with its source line). A roll is a tile, Dicebox's die button laid flat
   (style.css .die-btn): the die, the verb, the notation in the mono voice. A
   check is the stat itself, its die named once in the section head. A command
   is a word, and one filled button commits a surface. A tag is quiet text.
   Seven tokens only. At rest a die is the muted ink over a faint fill of its
   own colour; the accent means armed, in the air or just rolled.
   ========================================================================== */

/* The three inks the block's words take, as mixes of the tokens (tools/test-die-glyphs.mjs checks each
   clears 4.5:1 on paper, face and the delete row's tint in all twenty palettes):
     go       color-mix(in srgb, var(--accent) 70%, var(--line))   a word that starts something
     danger   color-mix(in srgb, var(--danger) 70%, var(--line))   a word that destroys something
     note     color-mix(in srgb, var(--muted) 80%, var(--line))    a notation, a tag, a count
   The pure accent and danger stay on the dice themselves, which need 3:1. */

/* ---- the glyph */
.dg { display: block; flex: none; overflow: visible; color: var(--muted); transition: color 140ms ease; }
.dg path, .dg rect, .dg circle, .dg polygon { stroke-linejoin: round; stroke-linecap: round; transition: fill-opacity 160ms ease, stroke 160ms ease, fill 160ms ease; }
.dg .o { fill: currentColor; fill-opacity: .16; }             /* .die-ico's faint fill (Dicebox style.css:555-560) */
.dg .o.nf { fill-opacity: 0; }                                /* the V5 marks carry none at rest (:512-513) */
.dg.ns polygon { fill: currentColor; fill-opacity: .1; stroke-width: 1.3px; vector-effect: non-scaling-stroke; } /* Mothership's solids (:1555) */
.dg .rear { opacity: .7; }                                    /* the far die of a pair; a dropped keep die is full ink, as Dicebox draws it (:1111, :1648) */
.dg .fade { opacity: .35; }
.dg .keep { stroke: var(--accent); fill: var(--accent); fill-opacity: .18; } /* the keep dice (:1111-1113, :1648-1650) */
.dg .chev { stroke: var(--accent); }
/* V5's Rouse keeps its blood at rest, as Dicebox colours it (:508-509) */
.dg[data-die="rouse"] { color: var(--accent); }
/* armed or in the air: the die fills to Dicebox's count state (.34, :716) in the accent */
.is-armed > .dg, .is-throwing > .dg, .is-rolled > .dg { color: var(--accent); }
.is-armed > .dg .o, .is-throwing > .dg .o, .is-armed > .dg.ns polygon, .is-throwing > .dg.ns polygon { fill-opacity: .34; }
/* just rolled: the die goes solid and its inner lines and pips turn paper, a change of shape and not of colour
   alone. Mothership's faceted solids fill without paper edges: cut in paper at a corner mark's 12px they fall
   into shards, filled with their own accent edges they keep the pair's outline */
.is-rolled > .dg .o { fill-opacity: 1; }
.is-rolled > .dg.ns polygon { fill-opacity: .82; }
.is-rolled > .dg .in { stroke: var(--paper); }
.is-rolled > .dg .pips { fill: var(--paper); }

/* ---- the roll tile: 44px, a 12px card edge, the die, the verb in the ink, the notation mono */
.roll-tile {
  display: inline-flex; align-items: center; justify-content: flex-start; gap: 6px;
  min-height: var(--tap); max-width: 100%; padding: 0 12px 0 10px; box-sizing: border-box;
  border: var(--hair-w) solid color-mix(in srgb, var(--muted) 40%, var(--hair)); border-radius: var(--r-card);
  background: none; color: var(--line);
  font-family: var(--sans); font-size: 13px; font-weight: 500; line-height: 1.25; letter-spacing: 0; text-align: left;
  cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: border-color 140ms ease, background-color 140ms ease, transform 120ms ease;
}
.roll-tile[hidden] { display: none; }
.roll-tile > .chip-label { min-width: 0; color: var(--line); letter-spacing: 0; overflow-wrap: anywhere; transition: color 140ms ease; }
.roll-tile > .roll-tag { min-width: 0; color: color-mix(in srgb, var(--muted) 80%, var(--line)); font-weight: 400; overflow-wrap: anywhere; }
.roll-tile > .chip-sub { flex: none; font-family: var(--mono); font-size: 12px; font-weight: 400; color: color-mix(in srgb, var(--muted) 80%, var(--line)); white-space: nowrap; font-variant-numeric: tabular-nums; transition: color 140ms ease; }
.roll-tile > .chip-sub[hidden] { display: none; }
/* a hover lifts a tile to the ink only where there is a pointer to rest: on a phone the tapped tile keeps
   :hover after the tap, and would hide the accent of the die it just threw */
@media (hover: hover) {
  .roll-tile:not(.is-preview):hover { border-color: color-mix(in srgb, var(--line) 45%, var(--hair)); }
  .roll-tile:not(.is-preview):not(.is-armed):not(.is-throwing):not(.is-rolled):not(.danger):hover > .dg:not([data-die="rouse"]) { color: var(--line); }
}
.roll-tile:active { transform: scale(.96); }                  /* Dicebox's press (style.css:629, :735) */
.roll-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.roll-tile:disabled { opacity: .5; cursor: default; transform: none; }
.roll-tile.is-armed { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.roll-tile.is-armed > .chip-sub, .roll-tile.is-rolled > .chip-sub { color: var(--line); }
.roll-tile.danger > .chip-label { color: color-mix(in srgb, var(--danger) 70%, var(--line)); }
/* a table roll leads with a mono #, the way its results are written. Once the field holds a row the verb goes quiet */
.roll-tile.table-roll > .hash { font-family: var(--mono); font-size: 12px; font-weight: 400; color: color-mix(in srgb, var(--muted) 80%, var(--line)); margin-right: -2px; }
.roll-tile.table-roll.is-quiet > .chip-label { color: color-mix(in srgb, var(--muted) 80%, var(--line)); }
/* a die in an entry's text: the die and its notation (and its stat's word when it comes from one), no verb. It
   rides the entry's foot line beside the page and the numbers, so it is drawn 32px tall with Dicebox's small
   die-button corner (.dbtn). Its target still reaches 46px, into the gaps around it */
.roll-tile.text-die { position: relative; min-height: 32px; gap: 5px; padding: 0 10px 0 8px; border-radius: var(--r-ctl); }
.roll-tile.text-die::before { content: ""; position: absolute; left: 0; right: 0; top: -7px; bottom: -7px; }
/* the composer's preview reads as the sheet will and never rolls: a dashed edge says it is a drawing of the tile */
.roll-tile.is-preview { cursor: default; border-style: dashed; }
.roll-tile.is-preview:active { transform: none; }
/* an item's rolls sit on their own row: the first at the name's edge, the next in a fixed column */
.chip-row.item-rolls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; justify-items: start; align-items: center; }
.chip-row.item-rolls[hidden] { display: none; }
.dice-in-text { flex-wrap: wrap; }
.readout-chips { gap: 8px; }

/* ---- the check: the stat is the target, and the head names its die */
/* The head's label keeps its line: the book's cite gives way first. The cite takes only its page tag for its
   own (the book's words are sized as a container, which counts for nothing when the row is laid out), then
   whatever the label leaves, the book ellipsising into it. A book with no room for a word of it is dropped
   whole, never shown as a letter and an ellipsis. The page tag is never cut. */
.section > h2 .head-label { flex: 0 1 auto; }
.section > h2 .cite { flex: 1 1 auto; min-width: auto; justify-content: flex-end; overflow: visible; }
.section > h2 .cite .cite-page { flex: 0 1 auto; white-space: normal; text-align: right; }
.cite-ref { white-space: nowrap; }
.section > h2 .cite .cite-book { container-type: inline-size; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: clip; }
.section > h2 .cite .cite-book-text { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
@container (max-width: 8ch) { .section > h2 .cite .cite-book-text { visibility: hidden; } }
/* the head die flows with the label's words: before the rule ("Stats · [die] roll under"), or after the name */
.section > h2 .head-die { display: inline-flex; align-items: center; gap: 4px; vertical-align: -.2em; margin: -4px .4em -4px 0; color: var(--muted); }
.section > h2 .head-die.after-name { margin: -4px 0 -4px .4em; }
.section > h2 .head-die.mode { vertical-align: -.4em; margin-block: -8px; }
.section > h2 .head-die[hidden] { display: none; }
/* a stat that throws the head's die wears none at rest: the mark keeps its place, so nothing moves when it shows */
[data-head-die] .chip.rollable:not(.roll-tile):not(.own-die):not(.is-armed):not(.is-throwing):not(.is-rolled) > .chip-die { visibility: hidden; }
/* a stamped box's number fills it, so its corner mark is drawn at 12px (renderChip), tucked into the corner */
.chip.hero > .chip-die { top: 5px; right: 5px; }
[data-sig-hero="stamp"] .chip.hero > .chip-die { top: 4px; right: 4px; }
[data-sig-hero="block"] .chip.hero > .chip-die { top: auto; bottom: 6px; right: 6px; }
.chip.stat2 > .chip-die, .chip.row > .chip-die { align-self: center; }
/* a rating or a track shows its die only while armed, in the air or just rolled, or when it is its section's
   one roll of that die: beside its name or its count */
.chip.dots > .chip-die, .chip.track > .chip-die { display: none; }
.chip.dots > .chip-die { margin-right: auto; margin-left: -4px; }
.chip.track > .chip-die { align-self: center; margin-right: 2px; }
.chip.dots.is-armed > .chip-die, .chip.dots.is-throwing > .chip-die, .chip.dots.is-rolled > .chip-die, .chip.dots.own-die > .chip-die,
.chip.track.is-armed > .chip-die, .chip.track.is-throwing > .chip-die, .chip.track.is-rolled > .chip-die, .chip.track.own-die > .chip-die { display: block; }
/* a derived track that rolls (V5's Willpower test) takes a 44px target around its die and count, reaching into
   the empty head row to its left. The "of 5" after it is its own dial and stays on top */
.chip.derived.track.rollable { position: relative; }
.chip.derived.track.rollable::after { content: ""; position: absolute; left: -16px; right: -2px; top: 50%; height: var(--tap); transform: translateY(-50%); }
/* hovered, a stat's die lifts to the ink (only where a pointer rests), and the value keeps the accent it always took */
@media (hover: hover) {
  .chip.rollable:hover > .chip-die { color: var(--line); }
}
.chip.rollable:focus-visible > .chip-die { color: var(--line); }
/* the states outrank the lift, and a roll the template tones (the Panic Check) keeps the danger ink through them */
.chip.rollable.is-armed > .chip-die, .chip.rollable.is-throwing > .chip-die, .chip.rollable.is-rolled > .chip-die { color: var(--accent); }
.chip.rollable.danger > .chip-die, .roll-tile.danger > .dg { color: var(--danger); }
/* the value says it just rolled too, on purpose and not by a sticky hover */
.chip.rollable.is-rolled:not([data-tone="danger"]) > .chip-val { color: color-mix(in srgb, var(--accent) 70%, var(--line)); }
/* a press on a value that is not a box: a faint accent wash and the value in the accent while the finger is down,
   on the chip's own 140ms colour transition */
.chip.rollable:not(.hero):active { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.chip.rollable:not(.hero):not([data-tone="danger"]):active > .chip-val { color: color-mix(in srgb, var(--accent) 70%, var(--line)); }
/* an unlocked dial sits on the accent well (Dicebox's loaded state). Only a roll brings its die up */
.chip.hero.armed { background: color-mix(in srgb, var(--accent) 12%, transparent); }

/* ---- the command: a word on a 44px target. Quiet in the ink, go and danger in their inks (see the top of this
   block), and the one filled button a surface commits with, filled in the ink as Dicebox fills its Roll
   (style.css:2574-2588). A danger word is underlined at rest, so it never passes for a go word where a
   system's accent and danger are the same red */
.cmd.cmd {
  appearance: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: auto; height: auto; min-width: var(--tap); min-height: var(--tap); margin: 0; padding: 0 6px; box-sizing: border-box;
  border: 0; border-radius: var(--r-ctl); background: none; box-shadow: none;
  color: var(--line); font-family: var(--sans); font-size: 13px; font-weight: 500; line-height: 1.2; letter-spacing: .01em;
  text-transform: none; text-decoration: none; white-space: nowrap;
  cursor: pointer; text-underline-offset: 3px; text-decoration-thickness: 1px;
  transition: color 140ms ease, background-color 140ms ease, opacity 120ms ease;
}
.cmd.cmd[hidden] { display: none; }
.cmd.cmd:hover { text-decoration: underline; }
.cmd.cmd:active { opacity: .55; }                              /* the press under the finger: no motion, so it stays under reduced motion */
.cmd.cmd:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cmd.cmd:disabled { opacity: .5; cursor: default; text-decoration: none; }
.cmd.cmd-go { color: color-mix(in srgb, var(--accent) 70%, var(--line)); }
.cmd.cmd-danger { color: color-mix(in srgb, var(--danger) 70%, var(--line)); text-decoration: underline; text-decoration-color: var(--danger); }
.cmd.cmd-danger:hover { text-decoration-thickness: 2px; }
.cmd.cmd.cmd-strong { padding: 0 22px; border-radius: var(--r-card); background: var(--line); color: var(--paper); font-size: 14px; font-weight: 600; letter-spacing: .01em; }
.cmd.cmd.cmd-strong:hover { text-decoration: none; background: color-mix(in srgb, var(--line) 86%, var(--paper)); }
.cmd.cmd.cmd-strong:active { opacity: .8; }
.cmd.cmd.cmd-strong .chip-label { color: inherit; letter-spacing: inherit; }
/* the list's own add words read as a margin note, not a line of content: the ink, smaller and lighter */
.cmd.cmd.list-add { font-size: 12px; font-weight: 400; }
/* a word leads its row at the text's edge: its padding hangs into the gutter */
.list-add-row > .cmd:first-child, .shop > .cmd:first-child, .help-actions > .cmd:first-child, .history-actions > .cmd:first-child,
.followup-actions > .cmd:first-child, .followup-menu > .cmd:first-child, .char-confirm > .cmd.cmd-danger, .claim-confirm > .cmd.cmd-go { margin-left: -6px; }
.help-close.cmd { margin: 8px 0 0 -6px; }
/* the words that stood apart still do: Clear at the history's far edge, a picker's Done or Cancel at its head's */
.history-actions > .history-clear.cmd, .picker-head > .picker-close.cmd { margin-left: auto; }
.picker-head > .picker-close.cmd { margin-right: -6px; }
/* the pack list: a game's name and its pack on one line, its words (Blank pack, Example) on their own line under
   it at the full 44px, so a long name never strands one word on a line of its own */
.pack-list li { row-gap: 0; }
.pack-list li::before { content: ""; flex-basis: 100%; order: 1; }
.pack-list li > .pack-blank { order: 2; margin-left: -5px; }
.pack-list li > .pack-example { order: 3; }
.pack-list .cmd.cmd { min-width: 0; padding: 0 5px; font-size: 12px; }
.shared-mark.cmd { font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }
.log-more-button.cmd { font-size: 12px; }
.new-row .cmd.cmd-strong { min-height: var(--tap); }
.wizard-foot .cmd-quiet:first-child { margin-left: -6px; }
.composer-foot .cmd-strong { min-width: 9rem; }
/* the way back to the roster is a quiet word like Export beside it: the same ink, the same weight */
.sheet-head-row.quiet .back-link { color: var(--line); font-weight: 500; letter-spacing: .01em; text-underline-offset: 3px; }
.sheet-head-row.quiet .back-link:hover, .sheet-head-row.quiet .back-link:focus-visible { color: var(--line); text-decoration: underline; }

/* ---- the torch's words: Light the torch and Relight go, Snuff is quiet (src/clock.js draws the buttons) */
.torch-clock-btn, .torch-clock[data-phase="guttering"] .torch-clock-btn.reset {
  appearance: none; display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap); min-width: var(--tap); padding: 0 6px; margin: 0;
  border: 0; border-radius: var(--r-ctl); background: none;
  font-family: var(--sans); font-size: 13px; font-weight: 500; letter-spacing: .01em; color: var(--line);
  text-underline-offset: 3px; text-decoration: none; cursor: pointer;
}
.torch-clock-btn:hover, .torch-clock-btn:focus-visible { text-decoration: underline; }
.torch-clock-btn:active { opacity: .55; }
.torch-clock-btn.light, .torch-clock-btn.light:hover, .torch-clock-btn.light:focus-visible,
.torch-clock[data-phase="guttering"] .torch-clock-btn.reset { color: color-mix(in srgb, var(--accent) 70%, var(--line)); border: 0; background: none; }
.torch-clock-btn.snuff, .torch-clock-btn.reset, .torch-clock-btn.snuff:hover, .torch-clock-btn.snuff:focus-visible,
.torch-clock-btn.reset:hover, .torch-clock-btn.reset:focus-visible { color: var(--line); border: 0; background: none; }
.torch-clock-actions { gap: 4px 10px; }

/* ---- a tag is quiet text: 12px, never boxed */
.entry-sub { font-size: 12px; color: color-mix(in srgb, var(--muted) 80%, var(--line)); letter-spacing: .01em; }
.chip.skill > .chip-sub { font-family: var(--sans); font-size: 12px; letter-spacing: .01em; color: color-mix(in srgb, var(--muted) 80%, var(--line)); }
.chip.skill > .chip-tier { color: var(--line); }

/* ---- a field head that carries its table's roll: the label, its page under it, the roll at the row's edge */
.field-head.with-roll { align-items: center; }
.field-head.with-roll > label .cite { display: block; margin: 3px 0 0; }

/* ---- a glyph command (✕ ✎ ✓ and the steppers) keeps its glyph and gets a 44px target */
.entry-head .row-remove, .item-group-choice > .row-remove, .portrait-remove {
  display: inline-flex; align-items: center; justify-content: center; min-width: var(--tap); min-height: var(--tap); margin: -10px -6px; padding: 0;
}
.entry-head .row-remove.item-promote { min-width: var(--tap); padding: 0 6px; margin: -10px 0; font-size: 13px; color: var(--line); }
.entry-head .row-remove + .row-remove { margin-left: -4px; }
.catalogue-chosen .chip.skill .row-remove, .picker-training .chip.skill .row-remove { position: relative; }
.catalogue-chosen .chip.skill .row-remove::after, .picker-training .chip.skill .row-remove::after { content: ""; position: absolute; inset: -9px -5px; }
.portrait-box.has-img .portrait-remove { display: inline-flex; top: 0; right: 0; margin: 0; background: color-mix(in srgb, var(--paper) 72%, transparent); color: var(--line); border-radius: 0 var(--r-card) 0 var(--r-ctl); }
.item-track-step { min-width: var(--tap); min-height: var(--tap); }
.history-dialog .sheet-close { width: var(--tap); height: var(--tap); }

/* the roll-up's rows: a tile each at one width so the results line up. Roll them all takes the step's width:
   it is the step's action while anything is unrolled */
.wizard-row > .roll-tile { min-width: 11.5rem; }
.wizard-body > .roll-tile.wizard-rollall { align-self: stretch; justify-content: center; }

/* ---- a die that lands under the answer card is scrolled clear of it (revealSource): the column keeps room */
body.has-readout .page { padding-bottom: 14rem; }

/* ---- motion is testimony: with reduced motion the states still switch, nothing slides or scales */
@media (prefers-reduced-motion: reduce) {
  .dg, .dg path, .dg rect, .dg circle, .dg polygon, .roll-tile, .roll-tile > .chip-sub, .roll-tile > .chip-label, .cmd.cmd, .torch-clock-btn { transition: none; }
  .roll-tile:active, .chip.hero:active, .die-chip:active { transform: none; }
}
