:root {
  /* palette — three inks, two fills, one hairline, one accent */
  --ink:        #141414;
  --ink-soft:   #2b2b2b;
  --muted:      #595959;
  --paper:      #ffffff;
  --surface:    #eaeaea;
  --hair:       #e3e3e3;
  --gold:       #8c6f28;   /* the one accent — used sparingly; deep enough for AA text on white (~4.7:1) */

  /* type families */
  --serif:      "EB Garamond", Georgia, "Times New Roman", serif;   /* display: titles + headings */
  --sans:       "Lato", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;   /* everything but display: body, UI, stat blocks, dice */

  /* generated label text (localized via html[lang] below) */
  --label-example: "Example";

  /* type scale */
  --fs-micro:   .72rem;
  --fs-tiny:    .8rem;
  --fs-small:   .9rem;
  --fs-ui:      .95rem;
  --fs-label:   1rem;
  --fs-body:    1rem;
  --fs-deck:    1.15rem;
  --fs-h3:      1.35rem;
  --fs-h2:      1.8rem;
  --fs-h1:      clamp(2.4rem, 6vw, 3.4rem);

  /* weights */
  --w-semibold: 600;
  --w-bold:     700;

  /* tracking */
  --ls-tight:   -.01em;
  --ls-heading: .02em;
  --ls-title:   .04em;   /* spaced caps for the big page titles */
  --ls-caps:    .08em;
  --ls-label:   .12em;

  /* spacing scale — every margin/gap comes from here */
  --space-1:    .4rem;
  --space-2:    .7rem;
  --space-3:    1.15rem;
  --space-4:    1.6rem;
  --space-5:    2.5rem;
  --space-6:    3.5rem;

  /* layout */
  --measure:      38rem;   /* reading column (rulebook, generators card) */
  --sidebar:      20rem;
  --topbar:       3.25rem;
  /* shared page padding, so every standalone page lines up */
  --pad-block:    clamp(2.5rem, 7vw, 5rem);
  --pad-inline:   clamp(1.5rem, 6vw, 6rem);
}

/* localized generated labels (lang is set on <html> by the page scripts) */
html[lang="hu"] { --label-example: "Példa"; }

* { box-sizing: border-box; }

/* SCROLLBARS — squared black bars to match the book.
   The standard scrollbar-* props are gated to browsers WITHOUT
   ::-webkit-scrollbar (Firefox); otherwise modern Chrome/Edge would honor
   them and ignore the webkit rules below, capping the bar at "thin". */
@supports not selector(::-webkit-scrollbar) {
  * { scrollbar-width: thin; scrollbar-color: var(--ink) transparent; }
}
::-webkit-scrollbar { width: 14px; height: 14px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--ink); border: 3px solid var(--paper); }
::-webkit-scrollbar-corner { background: transparent; }
/* lighter thumb on the dark code blocks so it stays visible against the ink */
.doc pre::-webkit-scrollbar-thumb { background: var(--muted); border-color: var(--ink); }

.skip-link {
  position: fixed;
  top: -3rem; left: 1rem;
  z-index: 60;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-size: var(--fs-tiny);
  padding: .5rem .8rem;
  text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: .5rem; }

html, .scrollarea { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html, .scrollarea { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

/* app shell: a fixed top bar over a single scrolling region, so the page
   itself never scrolls and the content scrollbar starts below the bar */
body {
  margin: 0;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; }

/* reserve the scrollbar's space always, so the content width is identical
   whether or not a scrollbar is showing (no reflow when content grows past a
   screenful). The home cover opts out below — it wants no reserved gutter. */
.scrollarea { flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; scrollbar-gutter: stable; }

/* ===========================================================
   LAYOUT — the contents panel is a fixed overlay at every width,
   so toggling it never reflows the centered reading column
   =========================================================== */
.shell { display: flex; }

.sidebar {
  position: fixed;
  top: var(--topbar); left: 0;
  z-index: 35;
  width: var(--sidebar);
  height: calc(100vh - var(--topbar));
  height: calc(100dvh - var(--topbar));
  border-right: 1px solid var(--hair);
  padding: 0.5rem 0.9rem 0.5rem 1.75rem;   /* minimal top/bottom: list runs nearly edge to edge */
  overflow: hidden;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  transition: transform .26s ease;
}
.sidebar .toc { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: 1rem; scrollbar-gutter: stable; }

nav.toc ol { list-style: none; margin: 0; padding: 0; counter-reset: chap; }
nav.toc li { margin: 0; }
nav.toc a {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  text-decoration: none;
  padding: .34rem .55rem;
  font-size: var(--fs-ui);
  line-height: 1.3;
  color: var(--ink);
  border: 1px solid transparent;
  transition: background .12s ease, color .12s ease;
}
/* chapter numbers (01, 02 ...) encode real book order */
nav.toc a.lvl-2::before {
  counter-increment: chap;
  content: counter(chap, decimal-leading-zero);
  font-family: var(--sans);
  font-size: var(--fs-micro);
  color: var(--muted);
  flex: 0 0 auto;
  padding-top: .12em;
}
nav.toc a.lvl-3 { padding-left: 2.4rem; font-size: var(--fs-small); color: var(--muted); }
nav.toc a:hover { background: var(--surface); }
nav.toc a:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }
/* active chapter inverts to a solid black block */
nav.toc a.active { background: var(--ink); color: var(--paper); }
nav.toc a.active::before { color: var(--paper); }

main {
  flex: 1 1 auto;
  min-width: 0;
  padding: 3rem clamp(1.5rem, 6vw, 6rem) 7rem;
  display: flex;
  justify-content: center;
}
.doc { width: 100%; max-width: var(--measure); }

/* ===========================================================
   TYPOGRAPHY  (rendered markdown)
   =========================================================== */
/* shared page-title voice — one size, one casing, used by the rulebook h1,
   the generators heading, and the home hero (casing forced here, not in source) */
.doc h1,
.gen-heading,
.hero-title {
  font-family: var(--serif);
  font-weight: var(--w-semibold);
  font-size: var(--fs-h1);
  line-height: 1.05;
  letter-spacing: var(--ls-title);
  text-transform: uppercase;
}
.doc h1 {
  margin: 0 0 var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: 3px solid var(--gold);   /* masthead rule — the gold accent */
}
.doc h1 + p { /* deck / subtitle */
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--fs-deck);
  color: var(--muted);
  margin: 0 0 var(--space-5);
}

.doc h2 {
  font-family: var(--serif);
  font-weight: var(--w-semibold);
  font-size: var(--fs-h2);
  letter-spacing: var(--ls-heading);
  /* same top gap as h3 so every heading break is uniform (--space-5) */
  margin: var(--space-5) 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--ink);   /* chapter rule, mid-weight in the ladder */
  scroll-margin-top: 1rem;
}
.doc h3 {
  font-family: var(--serif);
  font-weight: var(--w-semibold);
  font-size: var(--fs-h3);
  letter-spacing: var(--ls-heading);
  margin: var(--space-5) 0 var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--hair);
  scroll-margin-top: 1rem;
}
/* h4 is demoted to the bold-serif "label" voice it shares with run-in
   rule terms — no longer a distinct mono heading */
.doc h4 {
  font-family: var(--serif);
  font-weight: var(--w-bold);
  font-size: var(--fs-label);
  margin: var(--space-4) 0 var(--space-1);
}

/* faint § anchor that appears on hover */
.doc h2, .doc h3 { position: relative; }
.heading-anchor {
  position: absolute;
  left: -1.2em; top: 0;
  width: 1.2em;
  text-align: center;
  text-decoration: none;
  color: var(--gold);
  opacity: 0;
  transition: opacity .12s ease;
}
.doc h2:hover .heading-anchor,
.doc h3:hover .heading-anchor,
.heading-anchor:focus-visible { opacity: 1; }

.doc p { margin: 0 0 var(--space-3); }

/* drop cap on a chapter's opening paragraph (tagged by rulebook.js) */
.doc p.dropcap::first-letter {
  float: left;
  font-weight: var(--w-semibold);
  font-size: 3.1em;
  line-height: .72;
  padding: .06em .1em 0 0;
}

/* run-in term labels: DWARF., Oracle:, INVISIBILITY. — one level below h3 */
.doc p.rule > strong:first-child,
.doc li > strong:first-child { font-weight: var(--w-bold); font-size: var(--fs-label); }

.doc a { text-underline-offset: 3px; text-decoration-thickness: 1px; text-decoration-color: var(--gold); }
.doc a:hover { text-decoration-thickness: 2px; }
.doc strong { font-weight: var(--w-semibold); }

.doc ul, .doc ol { margin: 0 0 var(--space-3); padding-left: 1.4rem; }
.doc li { margin: .3rem 0; padding-left: .3rem; }
.doc ul li::marker { content: "•  "; }
.doc ol li::marker { font-family: var(--sans); font-size: .85em; }
.doc li > ul, .doc li > ol { margin: .3rem 0; }

/* blockquote — worked-example callout, flagged with a small EXAMPLE label */
.doc blockquote {
  margin: var(--space-4) 0;
  padding: .1rem 0 .2rem 1.3rem;
  border-left: 3px solid var(--gold);   /* worked-example accent */
  font-style: italic;
  color: var(--ink-soft);
}
.doc blockquote::before {
  content: var(--label-example);
  display: block;
  font-family: var(--sans);
  font-style: normal;
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: .3rem;
}
.doc blockquote p:last-child { margin-bottom: 0; }

/* code — inline sizes in em so it tracks its surrounding text */
.doc code {
  font-family: var(--sans);
  font-size: .82em;
  background: var(--surface);
  padding: .1em .35em;
  border: 1px solid var(--hair);
}
.doc pre {
  font-family: var(--sans);
  background: var(--ink);
  color: var(--paper);
  padding: 1.1rem 1.3rem;
  overflow-x: auto;
  font-size: var(--fs-tiny);
  line-height: 1.55;
  margin: 0 0 var(--space-4);
}
.doc pre code { background: none; border: none; padding: 0; color: inherit; }

/* tables — ruled like a stat table; wrapped for horizontal scroll */
.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;   /* momentum scroll on touch devices */
  margin: var(--space-4) 0;
  max-width: min(48rem, 100%);
}
.table-wrap table { margin: 0; }
.doc table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.doc thead th {
  text-align: left;
  font-family: var(--sans);
  font-weight: var(--w-bold);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  padding: .55rem .7rem;
  border-bottom: 2px solid var(--ink);
  white-space: nowrap;
}
.doc tbody td { padding: .5rem .7rem; vertical-align: top; }
/* zebra rows instead of hairline rules; counted from the bottom so the last
   row is always shaded (the table closes on a stripe, no bottom rule needed) */
.doc tbody tr:nth-last-child(odd) { background: var(--surface); }
.doc table code { font-size: .78em; }

/* stat blocks (bestiary, hirelings) — a filled card: bold name, the special,
   then two stat rows (core attributes, then MRL/MOV/ATK) with bold keys */
.doc .statblock {
  border: 1px solid var(--ink);
  border-left: 3px solid var(--ink);
  padding: .9rem 1.1rem;
  margin: 0 0 var(--space-3);
  background: var(--surface);
}
.doc .stat-name {
  display: block;
  font-family: var(--serif);
  font-weight: var(--w-bold);
  font-size: var(--fs-deck);
  line-height: 1.2;
}
.doc .stat-special { display: block; margin: .2rem 0 .55rem; color: var(--ink-soft); }
.doc .stat-row {
  display: block;
  font-family: var(--sans);
  font-size: var(--fs-ui);
  line-height: 1.65;
}
.doc .stat-row b { font-weight: var(--w-bold); }

/* hr is inert: the chapter gap lives on .doc h2 so spacing stays uniform */
.doc hr { border: none; margin: 0; }

.doc img { max-width: 100%; height: auto; filter: grayscale(1); }
/* the ancestry party plate keeps its color; the grayscale house style is for
   the line-art spot illustrations */
.doc img[src$="ancestries.png"] { filter: none; }

/* loading / error message */
.doc .doc-status {
  font-family: var(--sans);
  font-size: var(--fs-small);
  color: var(--muted);
  line-height: 1.7;
}
.doc .doc-status strong { color: var(--ink); }
.doc .doc-status .inline-link {
  font: inherit;
  border: none;
  background: none;
  padding: 0;
  color: var(--ink);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ===========================================================
   TOP BAR
   =========================================================== */
.topbar {
  flex: 0 0 auto;   /* hold full height in the body flex column */
  position: relative;
  z-index: 50;
  display: flex;
  align-items: center;
  height: var(--topbar);
  padding: 0 .9rem;
  background: var(--paper);
  border-bottom: 1px solid var(--hair);
}
/* equal flanks keep the tab group centered */
.topbar-side { flex: 1 1 0; display: flex; align-items: center; min-width: 0; }
.topbar-right { justify-content: flex-end; }

.tabs {
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
.tabs-menu { display: flex; align-items: center; gap: .1rem; }
/* the collapse-to-menu button only appears on the narrowest phones */
.tabs-toggle { display: none; }
.tabs-toggle .chevron {
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .15s ease;
}
.tabs.open .tabs-toggle .chevron { transform: rotate(180deg); }
.tab {
  text-decoration: none;
  color: var(--muted);
  font-size: var(--fs-ui);
  font-weight: var(--w-semibold);
  padding: .3rem .7rem;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  transition: color .12s ease, border-color .12s ease;
}
.tab:hover { color: var(--ink); }
.tab-active { color: var(--ink); border-bottom-color: var(--gold); }
.tab[aria-disabled="true"] { color: var(--muted); opacity: .45; pointer-events: none; }

.lang { display: flex; align-items: center; flex: 0 0 auto; }
.lang-btn {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;    /* 44px tap target */
  border: none;
  background: none;
  cursor: pointer;
  font-family: var(--sans);
  font-size: var(--fs-small);
  letter-spacing: var(--ls-caps);
  color: var(--muted);
  padding: 0 .55rem;
  transition: color .12s ease;
}
/* short centered divider, independent of the (taller) tap-target height */
.lang-btn + .lang-btn { position: relative; }
.lang-btn + .lang-btn::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  height: 1.1rem;
  border-left: 1px solid var(--hair);
  transform: translateY(-50%);
}
.lang-btn:hover { color: var(--ink); }
.lang-btn[aria-pressed="true"] {
  color: var(--ink);
  font-weight: var(--w-bold);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.lang-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }

/* contents toggle: slides the panel out on desktop, opens the drawer on mobile */
.nav-toggle {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;     /* 44px tap target */
  min-height: 2.75rem;
  margin-right: .15rem;
  background: var(--paper);
  border: none;
  color: var(--ink);
  cursor: pointer;
  transition: color .12s ease;
}
.nav-toggle:hover { color: var(--gold); }
.nav-toggle:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.nav-toggle svg { display: block; }
.nav-toggle svg line { stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }

/* reading-progress line, tucked just under the top bar */
.progress {
  position: fixed;
  top: var(--topbar); left: 0;
  height: 2px; width: 0;
  background: var(--gold);
  z-index: 45;
}

/* ===========================================================
   GENERATORS PAGE — a tactile tool desk, not a rulebook page
   =========================================================== */
.gen .scrollarea {
  background:
    linear-gradient(90deg, rgba(140, 111, 40, .09) 0 1px, transparent 1px 100%),
    linear-gradient(180deg, rgba(140, 111, 40, .07) 0 1px, transparent 1px 100%),
    var(--paper);
  background-size: 3.5rem 3.5rem;
}
.gen-main {
  min-height: 100%;
  padding: clamp(1rem, 2.7vw, 2.1rem) clamp(1rem, 4vw, 4rem) clamp(1.4rem, 3.5vw, 2.5rem);
  align-items: center;
}
.gen-doc {
  width: min(100%, 74rem);
  display: grid;
  grid-template-columns: minmax(8.75rem, 11.5rem) minmax(0, 1fr);
  gap: clamp(.9rem, 2.2vw, 1.55rem);
  align-items: start;
}
.gen-list {
  position: sticky;
  top: calc(var(--topbar) + 1rem);
  display: grid;
  gap: .55rem;
  padding: .55rem;
  border: 1px solid var(--ink);
  background: var(--paper);
  box-shadow: .35rem .35rem 0 var(--ink);
}
.gen-switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 2.55rem;
  padding: .45rem .65rem;
  border: 1px solid transparent;
  color: var(--ink);
  text-decoration: none;
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}
.gen-switch::after {
  content: "→";
  color: var(--gold);
  opacity: 0;
  transform: translateX(-.25rem);
  transition: opacity .12s ease, transform .12s ease;
}
.gen-switch:hover { background: var(--surface); }
.gen-switch:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.gen-switch.active {
  background: var(--ink);
  color: var(--paper);
}
.gen-switch.active::after {
  opacity: 1;
  transform: translateX(0);
}
.gen-stage {
  position: relative;
  padding: clamp(1.15rem, 2.35vw, 1.85rem);
  border: 1px solid var(--ink);
  background: var(--paper);
  box-shadow: .45rem .45rem 0 var(--gold);
}
.gen-stage::before {
  display: none;
}
.gen-title-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-2);
  padding-bottom: .55rem;
  border-bottom: 3px solid var(--gold);   /* masthead rule, same as the rulebook h1 */
}
.gen-heading {
  position: relative;
  flex: 1 1 auto;
  margin: 0;
  padding: 0;
  border-bottom: none;
}
/* reroll — the shared ghost button voice, with a spin on hover */
.gen-reroll {
  flex: 0 0 auto;
  gap: .55rem;
  cursor: pointer;
}
.gen-reroll svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform .18s ease;
}
.gen-reroll:hover svg { transform: translateY(-1px) rotate(-70deg); }
/* deck under the masthead — same voice as the rulebook's h1 + p subtitle */
.gen-lead {
  position: relative;
  max-width: 42rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--fs-deck);
  line-height: 1.5;
  color: var(--muted);
  margin: 0 0 var(--space-3);
}
.gen-controls {
  position: relative;
  margin: 0 0 var(--space-3);
  padding: var(--space-2);
  border: 1px solid var(--hair);
  background: var(--paper);
}

/* the rolled character card — name up top, vitals + attributes in a side
   rail spanning both rows, labeled details below the name */
.pc-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(12.5rem, .55fr);
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "head   side"
    "detail side";
  gap: var(--space-3);
}
.pc-head { grid-area: head; }
.pc-name {
  font-family: var(--serif);
  font-weight: var(--w-semibold);
  font-size: clamp(2rem, 4vw, 2.65rem);
  line-height: 1;
  margin: 0;
}
.pc-sub {
  font-family: var(--sans);
  font-size: var(--fs-ui);
  font-style: normal;
  color: var(--muted);
  margin: .25rem 0 0;
}
.pc-side {
  grid-area: side;
  display: grid;
  gap: .55rem;
  align-content: start;
}
.pc-vitals {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .55rem;
}
.pc-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .55rem;
}
/* one shared stat-tile voice: micro-caps key over a bold figure */
.pc-vitals > span,
.pc-stat {
  display: grid;
  gap: .15rem;
  min-height: 3.8rem;
  place-content: center;
  padding: .45rem .35rem;
  border: 1px solid var(--ink);
  background: var(--paper);
  font-family: var(--sans);
  text-align: center;
}
.pc-vitals b,
.pc-stat b {
  font-family: var(--sans);
  font-size: var(--fs-micro);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--muted);
}
.pc-num {
  font-weight: var(--w-bold);
  font-size: 1.35rem;
  line-height: 1.1;
  white-space: nowrap;
}
.pc-num i {
  font-style: normal;
  font-weight: 400;
  font-size: var(--fs-small);
  color: var(--muted);
}
.pc-detail {
  grid-area: detail;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .9rem var(--space-3);
  align-content: start;
}
.pc-detail > div { display: grid; gap: .2rem; }
.pc-detail dt {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--gold);   /* gold key labels, same idiom as the EXAMPLE flags */
}
.pc-detail dd {
  margin: 0;
  line-height: 1.45;
}
/* ancestry trait — rules text, so it closes the stat rail as a mini
   statblock (same filled-card voice as the bestiary's .statblock) */
.pc-trait {
  padding: .6rem .8rem;
  border: 1px solid var(--ink);
  border-left: 3px solid var(--ink);
  background: var(--surface);
  font-family: var(--sans);
  font-size: var(--fs-small);
  line-height: 1.5;
}
.pc-trait b {
  display: block;
  margin-bottom: .15rem;
  font-size: var(--fs-micro);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

/* ----- dice roller ----- */
.dice-controls { display: grid; gap: var(--space-3); }
.dice-quick {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: .55rem;
}
.dice-chip {
  min-height: 2.75rem;
  padding: .4rem .65rem;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  cursor: pointer;
  transition: background .12s ease, color .12s ease, transform .12s ease;
}
.dice-chip:hover { background: var(--ink); color: var(--paper); transform: translateY(-1px); }
.dice-chip:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.dice-entry { display: flex; gap: var(--space-2); }
.dice-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 3rem;
  padding: .5rem .75rem;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
}
.dice-input:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.dice-entry .btn { flex: 0 0 auto; }

.dice-result {
  display: grid;
  place-items: center;
  min-height: clamp(10rem, 22vw, 15rem);
  border: 1px solid var(--ink);
  background: var(--paper);
  padding: var(--space-5);
  text-align: center;
}
.dice-expr {
  margin: 0 0 var(--space-1);
  font-family: var(--sans);
  font-size: var(--fs-small);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--muted);
}
.dice-total {
  display: block;
  font-family: var(--sans);
  font-weight: var(--w-bold);
  font-size: clamp(4rem, 14vw, 8rem);
  line-height: .9;
}
.dice-breakdown {
  margin: var(--space-2) 0 0;
  font-family: var(--sans);
  font-size: var(--fs-small);
  color: var(--ink-soft);
}
.dice-error {
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--hair);
  font-family: var(--sans);
  font-size: var(--fs-small);
  color: var(--ink-soft);
}

@media (max-width: 820px) {
  .gen-main { align-items: start; }
  .gen-doc { grid-template-columns: 1fr; }
  .gen-list {
    position: static;
    display: flex;
    overflow-x: auto;
    scrollbar-gutter: stable;
    box-shadow: .35rem .35rem 0 var(--ink);
  }
  .gen-switch { flex: 1 0 max-content; }
  .gen-switch::after { display: none; }
  /* stacked card: name first, then the stat rail, then the details */
  .pc-card {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-template-areas: "head" "side" "detail";
  }
  .pc-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .pc-detail {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }
  .pc-detail > div {
    grid-template-columns: 8rem 1fr;
    gap: var(--space-2);
  }
}

@media (max-width: 560px) {
  .gen-stage { padding: var(--space-3); box-shadow: .4rem .4rem 0 var(--gold); }
  .gen-stage::before { display: none; }
  .gen-title-row {
    align-items: center;
    gap: var(--space-2);
  }
  /* icon-only reroll: the tight title row has no room for the label */
  .gen-reroll { padding: .55rem .7rem .45rem; }
  .gen-reroll .gen-reroll-label { display: none; }
  .gen-controls { padding: var(--space-2); }
  .dice-quick { grid-template-columns: repeat(3, 1fr); }
  .dice-entry { flex-direction: column; }
  .dice-entry .btn { width: 100%; }
  .pc-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pc-detail > div { grid-template-columns: 1fr; gap: 0; }
}

@media (min-width: 1100px) and (min-height: 760px) {
  .gen-main { padding-top: 1.8rem; padding-bottom: 1.8rem; }
  .gen-doc { align-items: center; }
}

@media (min-width: 1280px) {
  .gen-doc { width: min(100%, 78rem); }
}

@media (max-height: 760px) and (min-width: 821px) {
  .gen-main { align-items: start; padding-top: 1rem; }
  .gen-stage { padding: 1rem 1.25rem; }
  .gen-lead { margin-bottom: var(--space-2); }
  .gen-controls { margin-bottom: var(--space-2); }
  .pc-card { gap: var(--space-2); }
  .pc-detail { gap: .55rem var(--space-2); }
}

/* shared button: solid (primary) + ghost (outline) — home CTAs + generators roll */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  /* right padding trimmed by one letter-spacing step to cancel the trailing
     space uppercase tracking leaves after the last glyph, so the icon+label
     group sits true-centered rather than nudged left.
     top > bottom by a hair: line-height:1 centers the line box, but all-caps
     glyphs sit in its upper ~70% (the unused descender space is at the bottom),
     so equal padding reads top-heavy — the extra top pad drops them to optical center */
  padding: .62rem calc(1.4rem - var(--ls-caps)) .48rem 1.4rem;
  text-decoration: none;
  font-family: var(--sans);
  font-weight: var(--w-bold);
  font-size: var(--fs-small);
  line-height: 1;   /* hug the caps so the icon centers true against the text */
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  border: 1.5px solid var(--ink);
  transition: background .12s ease, color .12s ease;
}
.btn-solid { background: var(--ink); color: var(--paper); }
.btn-solid:hover { background: var(--paper); color: var(--ink); }
.btn-ghost { background: var(--paper); color: var(--ink); }
.btn-ghost:hover { background: var(--ink); color: var(--paper); }
.btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ===========================================================
   HOME PAGE — full-height cover spread: title block beside the
   cover plate, then a full-width band of selling points
   =========================================================== */
/* the home page fills the scroll region exactly via flex-grow (no viewport
   math, so the top bar's 1px border can't push the cover plate past the fold,
   and the cover bleeds clean to the top/right/bottom edges) */
/* the cover wants the full width with no reserved gutter (and it never scrolls) */
body.home .scrollarea { display: flex; flex-direction: column; scrollbar-gutter: auto; }
/* override the generic <main> padding with a uniform gap, so the hero sits in
   an even frame of whitespace on all four sides (the old rule was 3/6/7rem —
   uneven top/sides/bottom) */
.home-page { display: flex; flex-direction: column; flex: 1 1 auto; padding: clamp(1.25rem, 3vw, 2.5rem); }

/* the masthead is the whole page: one screen, no scroll. Wide screens place the
   title block beside the cover; narrow screens stack (title, then the cover
   fills the remaining height). */
.hero {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr;
  flex: 1 1 auto;
}
@media (min-width: 821px) {
  .hero { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr; }
}

/* left: the title block, vertically centered and anchored left.
   container-type lets the CTA grid below stack based on THIS column's width,
   so the two-up buttons collapse to one column whenever their column is too
   narrow — on mobile, and equally in the narrow text-half of the wide hero */
.hero-text {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  align-items: flex-start;   /* text + every block share one left edge */
  justify-content: center;   /* vertically centered in the column */
  gap: var(--space-3);
  /* size the block explicitly and auto-center it, so it sits in the middle of
     the left half rather than hugging its edge — while items stay left-aligned.
     `width` (not max-width) is required: container-type below removes
     content-based sizing, so an auto-margin'd block needs a definite width or
     it collapses to zero. */
  width: min(38rem, 100%);
  margin-inline: auto;
  padding: var(--pad-block) clamp(1.5rem, 4vw, 2.5rem);
}
/* negative bottom margin claws back the empty descender space under the all-caps
   title (which has no descenders), so the equal flex gaps above/below the tagline
   read as visually equal — the tagline lands at the true midpoint. em-based, so it
   scales with the responsive title size. */
.hero-title { margin: 0 0 -0.15em; font-size: clamp(2.8rem, 7vw, 5rem); }
.hero-tagline {
  margin: 0;
  max-width: 32rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--fs-deck);
  color: var(--muted);
}
/* CTAs: the primary "Read" spans the full width on its own row, with Discord +
   itch sharing the row beneath it as two equal halves */
.hero-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
  /* no own margin: the parent flex `gap` already spaces this block, and a margin
     here would stack on top of it, double-spacing the CTAs out of the rhythm */
  max-width: 32rem;
}
.hero-actions .btn { width: 100%; min-width: 0; gap: .55rem; white-space: nowrap; }
.hero-actions .btn-solid { grid-column: 1 / -1; }
/* nudge the icon up a hair so it optically aligns with the cap-height of the
   uppercase label (which has no descender pulling it down) — text stays put */
.btn-icon { flex: 0 0 auto; width: 1.05rem; height: 1.05rem; display: block; transform: translateY(-1px); }
/* once the title column is too narrow to hold Discord + itch side by side
   (~31rem: two ~14.7rem nowrap labels plus the gap), drop all three CTAs into
   a single stacked column */
@container (max-width: 31rem) {
  .hero-actions { grid-template-columns: 1fr; max-width: 22rem; }
}
.hero-meta {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .4rem;
  font-family: var(--sans);
  font-size: var(--fs-small);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--muted);
}
.home-email {
  color: var(--ink);
  text-transform: none;   /* keep the address lowercase in the caps line */
  text-decoration: none;
  text-underline-offset: 3px;
  text-decoration-color: var(--gold);
}
.home-email:hover { text-decoration: underline; }

/* right: the cover plate — an ink panel with a gold inner frame (::after)
   holding the cover art (.hero-cover-img) */
.hero-cover {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-5);
  background: var(--ink);
  color: var(--paper);
  overflow: hidden;
  /* on desktop the grid stretches this to the hero's height; once stacked the
     art is absolutely positioned and gives no intrinsic height, so anchor the
     panel to a square ratio that matches the square 1:1 cover art */
  aspect-ratio: 1 / 1;
}
@media (min-width: 821px) { .hero-cover { aspect-ratio: auto; } }
.hero-cover::after {   /* inset gold frame around the art */
  content: "";
  position: absolute;
  inset: clamp(1rem, 2.5vw, 1.75rem);
  border: 2px solid var(--gold);
  pointer-events: none;
}
/* the img fills the area inside the gold frame; `contain` keeps the dragon's
   ratio (no crop). The art ships on a square 1:1 canvas with the dragon already
   centered, so it sits centered in the frame — no positional bias needed */
.hero-cover-img {
  position: absolute;
  top: clamp(1rem, 2.5vw, 1.75rem);
  left: clamp(1rem, 2.5vw, 1.75rem);
  width: calc(100% - 2 * clamp(1rem, 2.5vw, 1.75rem));
  height: calc(100% - 2 * clamp(1rem, 2.5vw, 1.75rem));
  object-fit: contain;
  object-position: 50% 50%;
}

/* stacked (mobile/tablet) hero: the big --pad-block top gap is there to balance
   the vertically-centered desktop column — once stacked there's nothing to
   center against, so trim it to a tight top and a modest gap before the cover */
@media (max-width: 820px) {
  .hero-text { padding-block: var(--space-3) var(--space-4); }
}

/* ===========================================================
   DESKTOP — slide the panel out; the panel's right-edge hairline
   (border-right) separates it from the content, no shadow needed
   =========================================================== */
@media (min-width: 821px) {
  body.sidebar-collapsed .sidebar { transform: translateX(-100%); }
}

/* ===========================================================
   MOBILE — same overlay, default-closed, with a tap-out scrim
   =========================================================== */
.scrim { display: none; }

@media (max-width: 820px) {
  .sidebar { width: min(82vw, 22rem); transform: translateX(-100%); }
  body.nav-open .sidebar { transform: translateX(0); }
  body.nav-open .scrim {
    display: block;
    position: fixed; inset: 0;
    /* the one intentional non-palette value: a scrim must be translucent to dim
       the page behind the open drawer, which no solid palette ink can do */
    background: rgba(0, 0, 0, .35);
    z-index: 32;
  }
  main { padding-top: 1.75rem; }
}

/* tight phones: trim bar padding, and shrink dense tables so fewer of them
   need sideways scrolling (the widest still scroll, now with momentum) */
@media (max-width: 560px) {
  .topbar { padding: 0 .5rem; }
  .tab { padding: .3rem .55rem; }
  .doc table { font-size: var(--fs-tiny); }
  .doc thead th, .doc tbody td { padding: .4rem .5rem; }
}

/* smallest phones: collapse the primary nav into an expandable menu so the
   top bar never crowds the language switch */
@media (max-width: 390px) {
  .tabs-toggle {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    min-height: 2.75rem;
    padding: 0 .55rem;
    border: none;
    background: none;
    cursor: pointer;
    font-family: var(--sans);
    font-size: var(--fs-small);
    color: var(--ink);
  }
  .tabs-toggle:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }

  .tabs-menu {
    display: none;
    position: absolute;
    top: var(--topbar); left: 50%;
    transform: translateX(-50%);
    flex-direction: column;
    align-items: stretch;
    min-width: 11rem;
    background: var(--paper);
    border: 1px solid var(--hair);
  }
  .tabs.open .tabs-menu { display: flex; }
  .tabs-menu .tab {
    justify-content: flex-start;
    min-height: 2.75rem;
    display: flex;
    align-items: center;
    padding: 0 1rem;
    border-bottom: none;
  }
  .tabs-menu .tab + .tab { border-top: 1px solid var(--hair); }
  .tabs-menu .tab-active { background: var(--surface); border-bottom: none; }
}

/* ===========================================================
   PRINT
   =========================================================== */
@media print {
  .topbar, .sidebar, .scrim, .heading-anchor,
  .skip-link, .nav-toggle, .progress { display: none !important; }
  main { padding: 0; }
  .doc { max-width: 100%; }
  /* undo the app-shell scroll lock so the whole book prints */
  body { height: auto; overflow: visible; display: block; font-size: 11pt; }
  .scrollarea { overflow: visible; height: auto; }
  .doc h2 { page-break-after: avoid; }
  .doc pre { border: 1px solid var(--ink); }
  .table-wrap { overflow: visible; max-width: 100%; }
  /* print drops background fills, so restore hairline rows for legibility */
  .doc tbody td { border-bottom: 1px solid var(--hair); }
  .doc .statblock { break-inside: avoid; }
}
