/* Self-hosted webfonts. Served from this origin so a page load makes no
   third-party request; subset ranges and font-display are carried over from
   the Google Fonts CSS these files came from. Fraunces is one variable file
   per subset, declared at both weights it is used at.
   Licenses: fonts/OFL-Atkinson-Hyperlegible.txt, fonts/OFL-Fraunces.txt */

@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/atkinson-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/atkinson-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/atkinson-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Atkinson Hyperlegible';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/atkinson-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/fraunces-var-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/fraunces-var-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/fraunces-var-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/fraunces-var-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   BigType Puzzles — ink & paper design system
   Warm paper ground, near-black warm ink, deep ink-blue accent.
   Atkinson Hyperlegible lives ON THE SHEETS only; all chrome is
   a plain humanist system sans at a 17px base. No gradients.
   ============================================================ */

:root {
  --bg: #faf7f0;
  --card: #ffffff;
  --ink: #1a1814;
  --ink-2: #4a453c;
  --hint: #6f6656;
  --rule: #ddd6c8;
  --rule-strong: #c9c0ae;
  --accent: #1f4e6b;
  --accent-ink: #163a50;
  --tint: #e4eef4;
  --marigold: #f2c14e;
  --marigold-soft: #fdf0cf;
  --hit: #ffe9a8;
  --ok: #2f6b46;
  --warn: #8a5a12;
  --err: #9c2f22;
  --r-sm: 3px;
  --r-md: 4px;
  --r-lg: 6px;
  --shadow-page: 0 1px 2px rgba(26, 24, 20, 0.08), 0 10px 26px rgba(26, 24, 20, 0.10);
  --pz-pt: 28;
}

* , *::before, *::after { box-sizing: border-box; }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

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

.skip-link {
  position: absolute;
  left: -9999px; top: 0;
  z-index: 100;
  background: var(--accent);
  color: #fff;
  font-weight: 700;
  padding: 12px 18px;
  border-radius: 0 0 var(--r-md) 0;
  text-decoration: none;
}
.skip-link:focus { left: 0; }

/* ---------- site chrome ---------- */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 8px 28px;
  background: rgba(250, 247, 240, 0.95);
  border-bottom: 1px solid var(--rule);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  text-decoration: none;
  color: var(--ink);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.01em;
}

.brand-mark {
  width: 32px; height: 32px;
  border-radius: var(--r-md);
  background: var(--accent);
  color: var(--marigold-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: Georgia, "Times New Roman", serif;
  font-weight: 700;
  font-size: 14px;
}

.brand-sub { color: var(--hint); font-weight: 400; }

.nav-links {
  margin-left: auto;
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
}

.nav-links a {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 10px 14px;
  text-decoration: none;
  color: var(--ink-2);
  font-size: 16px;
  border-radius: var(--r-md);
  border-bottom: 3px solid transparent;
}

.nav-links a:hover { color: var(--accent); background: var(--tint); }

.nav-links a.active {
  color: var(--accent);
  font-weight: 700;
  border-bottom-color: var(--accent);
}

.tool-strip {
  padding: 28px 32px 0;
  max-width: 1460px;
  margin: 0 auto;
  width: 100%;
}

.tool-strip h1 {
  margin: 0;
  font-size: clamp(26px, 3vw, 34px);
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 700;
}

.tool-sub {
  margin: 8px 0 0;
  color: var(--hint);
  font-size: 17px;
  max-width: 66ch;
}

/* ---------- mode segmented control ---------- */

.mode-seg {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin: 18px 0 0;
  padding: 0;
  border: 0;
}

.mode-seg legend { position: absolute; left: -9999px; }

.mode-seg label { cursor: pointer; }

.mode-seg input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.mode-seg span {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 10px 18px;
  border: 1px solid var(--rule);
  border-bottom-width: 3px;
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--ink-2);
  font-size: 16px;
}

.mode-seg input:checked + span {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 700;
}

.mode-seg input:focus-visible + span {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- layout ---------- */

.layout {
  display: grid;
  grid-template-columns: 360px minmax(0, 1fr);
  gap: 32px;
  align-items: start;
  padding: 24px 32px 0;
  max-width: 1460px;
  margin: 0 auto;
  width: 100%;
}

@media (max-width: 1180px) {
  .layout { grid-template-columns: 300px minmax(0, 1fr); }
}

@media (max-width: 1100px) {
  .layout { grid-template-columns: minmax(0, 1fr); }
  .preview { order: -1; overflow: hidden; }
  .site-nav, .tool-strip, .layout, .seo-copy, .site-footer { padding-left: 18px; padding-right: 18px; }
}

/* ---------- controls: two-step accordion groups ---------- */

.controls {
  display: grid;
  gap: 14px;
}

.ctl-group {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
}

.ctl-group summary {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 12px 16px;
  cursor: pointer;
  font-weight: 700;
  font-size: 17px;
  list-style: none;
}

.ctl-group summary::-webkit-details-marker { display: none; }

.ctl-group summary::after {
  content: "";
  width: 9px; height: 9px;
  border-right: 2px solid var(--hint);
  border-bottom: 2px solid var(--hint);
  transform: rotate(45deg);
  margin-left: 8px;
  flex: none;
}

.ctl-group[open] summary::after { transform: rotate(-135deg); }

.step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  flex: none;
  border-radius: 50%;
  background: var(--tint);
  color: var(--accent);
  font-size: 15px;
  font-weight: 700;
}

.sum-val {
  margin-left: auto;
  margin-right: 6px;
  color: var(--hint);
  font-weight: 400;
  font-size: 15px;
}

.ctl-body {
  padding: 2px 16px 18px;
  display: grid;
  gap: 12px;
}

/* ---------- fields ---------- */

label, .field-label {
  display: block;
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
}

.hint {
  color: var(--hint);
  font-weight: 400;
  font-size: 15px;
}

input[type="text"], textarea, select {
  width: 100%;
  font: inherit;
  font-size: 17px;
  color: var(--ink);
  padding: 11px 12px;
  min-height: 48px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-md);
  background: #fff;
}

input[type="text"]:focus, textarea:focus, select:focus { border-color: var(--accent); }

textarea {
  resize: vertical;
  text-transform: uppercase;
  line-height: 1.5;
  min-height: 150px;
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  align-items: end;
}

.checkbox-label {
  display: flex;
  gap: 10px;
  align-items: center;
  min-height: 48px;
  font-weight: 400;
  cursor: pointer;
}

.checkbox-label input {
  width: 20px; height: 20px;
  flex: none;
  accent-color: var(--accent);
}

.radio-set {
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  padding: 4px 12px 8px;
  display: grid;
  margin: 0;
}

.radio-set legend {
  font-size: 16px;
  font-weight: 700;
  padding: 0 4px;
}

.notice {
  margin: 0;
  background: var(--marigold-soft);
  border: 1px solid var(--marigold);
  border-radius: var(--r-md);
  padding: 8px 10px;
  font-size: 15px;
  color: var(--ink-2);
}

.warning {
  margin: 0;
  color: var(--warn);
  font-size: 15px;
  font-weight: 700;
}

/* ---------- theme chips: index-card tabs ---------- */

.preset-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.preset-btn {
  font: inherit;
  font-size: 16px;
  padding: 10px 14px;
  min-height: 48px;
  border-radius: var(--r-md);
  border: 1px solid var(--rule);
  border-bottom: 3px solid var(--rule-strong);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
}

.preset-btn:hover {
  border-color: var(--accent);
  border-bottom-color: var(--accent);
  color: var(--accent);
  background: var(--tint);
}

.theme-all { margin-top: 4px; }

.theme-all summary { list-style: none; display: inline-flex; align-items: center; }
.theme-all summary::-webkit-details-marker { display: none; }

.theme-groups {
  display: grid;
  gap: 10px;
  padding: 12px 2px 2px;
}

.theme-group-label {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--hint);
}

/* ---------- action bar ---------- */

.action-bar {
  display: grid;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  position: sticky;
  bottom: 12px;
  box-shadow: var(--shadow-page);
}

.bar-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

.bar-label { font-size: 15px; color: var(--hint); font-weight: 400; }

.bar-select { width: auto; flex: 1; min-width: 110px; }

.grow { flex: 1; width: auto; }

.bar-btns { display: flex; gap: 8px; flex-wrap: wrap; }
/* `display: flex` above outranks the UA stylesheet's `[hidden] { display:
   none }`, so syncResultButtons() setting .hidden would otherwise have no
   visible effect. Needed for the quiet row (Shuffle / Copy link). */
.bar-btns[hidden] { display: none; }

.btn {
  font: inherit;
  font-size: 17px;
  font-weight: 700;
  padding: 12px 18px;
  min-height: 48px;
  border-radius: var(--r-md);
  border: 1px solid var(--rule-strong);
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}

.btn:hover { border-color: var(--ink-2); }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent-ink);
  color: #fff;
}

.btn-primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }

.btn-quiet {
  background: transparent;
  border-color: transparent;
  color: var(--accent);
  font-weight: 400;
  text-decoration: underline;
}

.btn-quiet:hover { color: var(--accent-ink); border-color: transparent; }

.btn[disabled] { opacity: 0.55; cursor: default; }

#status {
  margin: 2px 0 0;
  font-size: 15px;
  color: var(--ink-2);
  min-height: 1.4em;
}

#status.ok { color: var(--ok); }
#status.warn { color: var(--warn); }
#status.err { color: var(--err); }

/* Fixed to the viewport at every width, not just mobile: Print/PDF/Shuffle
   stay reachable regardless of scroll position or which column the mouse
   is over. (Previously the rail scrolled internally so a sticky bar could
   dock inside it without overlapping content — that traded the overlap bug
   for a worse one: the rail captured the scroll wheel, so the controls
   below the word list were invisible unless the cursor happened to be
   hovering that column. One page, one scroll, always-visible actions.) */
.has-bar .action-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  margin: 0;
  border-left: 0;
  border-right: 0;
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding-bottom: calc(14px + env(safe-area-inset-bottom));
}
/* Desktop: Print/PDF and the quiet links share one row instead of stacking,
   which is what made the fixed bar tall enough to cover the sheet below it.
   The 700px query further down already merges rows for narrow screens. */
@media (min-width: 701px) {
  .has-bar .action-bar { grid-template-columns: 1fr auto; align-items: center; }
  .has-bar .action-bar .bar-row { grid-column: 1 / -1; }
  .has-bar .action-bar .bar-btns:nth-of-type(2) { grid-column: 1; }
  .has-bar .action-bar .bar-btns:nth-of-type(3) { grid-column: 2; justify-self: end; }
  .has-bar .action-bar #status { grid-column: 1 / -1; }
}

/* First-frame fallback only: syncActionBarPadding() in js/shared.js measures
   the bar and overwrites this with an inline padding-bottom, so this value
   just needs to be in the right ballpark before that runs. */
body.has-bar { padding-bottom: 235px; }

@media (max-width: 700px) {
  /* Two-line nav: brand on its own row, links wrap beneath it, fully opaque.
     No hamburger, no horizontal scroll — for this audience every link stays
     visible with a big tap target rather than hidden behind a gesture.
     Arithmetic at the 375px floor (18px side padding from the 1100px rule
     above, so 339px of content width): brand ~199px fits row 1 alone. Link
     row 2 needs Word Search 114 + Sudoku 72 + Bingo 59 + Print Tips 85 +
     About 61 = 391px plus gaps — wider than 339px, so nav-links wraps onto
     its own two lines; the widest single link (114px) is well under 339px,
     so nothing is ever clipped or pushed off-screen. */
  .site-nav { flex-wrap: wrap; row-gap: 6px; gap: 10px; background: var(--bg); }
  .nav-links { flex: 1 1 100%; margin-left: 0; flex-wrap: wrap; gap: 4px; }
  .nav-links a { min-height: 44px; padding: 8px 10px; font-size: 15px; white-space: nowrap; }

  /* Compact fixed action bar: Print/PDF full-width row, utilities on one wrap row. */
  .has-bar .action-bar { display: flex; flex-wrap: wrap; gap: 8px; padding: 10px 12px calc(10px + env(safe-area-inset-bottom)); }
  .action-bar .bar-row + .bar-btns { order: -1; flex: 1 1 100%; }
  .action-bar .bar-btns .btn { flex: 1; }
  .action-bar .bar-label { display: none; }
  .action-bar .bar-select { min-width: 0; min-height: 44px; flex: 0 1 auto; }
  .action-bar .btn-quiet { min-height: 44px; padding: 6px 8px; font-size: 15px; white-space: nowrap; }
  .action-bar #status { flex: 1 1 100%; min-height: 0; margin: 0; }
  .action-bar #status:empty { display: none; }
  body.has-bar { padding-bottom: 140px; }
}

/* ---------- type-size slider ---------- */

.size-block { display: grid; gap: 6px; }

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 48px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}

/* Flat two-tone fill (hard stop — solid colors, not a decorative gradient) */
input[type="range"]::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent) var(--fill, 40%), var(--rule) var(--fill, 40%));
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px; height: 28px;
  margin-top: -10px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--accent);
  box-shadow: 0 1px 4px rgba(26, 24, 20, 0.3);
  cursor: pointer;
}

input[type="range"]::-moz-range-track {
  height: 8px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent) var(--fill, 40%), var(--rule) var(--fill, 40%));
}

input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--accent);
  cursor: pointer;
}

output { font-weight: 700; color: var(--accent); }

/* ---------- preview: the page is the product ---------- */

.print-only { display: none; }

.preview {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  scroll-margin-top: 80px;
}

.preview-live {
  width: 100%;
  display: grid;
  gap: 10px;
  justify-items: center;
}

.sheet {
  background: #fff;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  box-shadow: var(--shadow-page);
  width: 100%;
  max-width: 800px;
  padding: 40px 44px 46px;
  font-family: "Atkinson Hyperlegible", "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: calc(var(--pz-pt) * 1pt);
  line-height: 1.45;
  color: #111;
}

@media screen {
  .sheet { aspect-ratio: 8.5 / 11; overflow: hidden; }
  body.paper-a4 .sheet { aspect-ratio: 210 / 297; }
  /* Outranks the A4 rule above (0,3,1 vs 0,2,1) so the empty placeholder
     stays content-height on both paper sizes. See .sheet.is-empty below. */
  body.paper-a4 .sheet.is-empty { aspect-ratio: auto; }
}

@media (max-width: 1100px) {
  /* Natural page width; JS applies `zoom` so the whole sheet fits the screen. */
  .preview-live .sheet { width: 800px; max-width: none; height: auto; }
  .preview-live .sheet.is-empty { width: 100%; max-width: 100%; }
}

@media (max-width: 480px) {
  .sheet { padding: 22px 20px 26px; }
}

/* An empty sheet is NOT a page preview — there is no page yet. Holding the
   8.5/11 aspect ratio here produced a ~1035px-tall white rectangle whose
   centred message landed at y≈812, underneath the fixed action bar, so the
   guidance was invisible at laptop heights and the panel read as broken.
   Shrink to content instead: the placeholder is a caption for an absence,
   not a simulation of paper. */
.sheet.is-empty {
  aspect-ratio: auto;
  height: auto;
  min-height: 0;
  overflow: visible;
  border-style: dashed;
  display: grid;
  gap: 18px;
  justify-items: center;
  align-content: start;
  padding: 40px 32px 44px;
  text-align: center;
  color: var(--hint);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  font-size: 17px;
}

.empty-note { margin: 0; line-height: 1.6; }

.empty-note strong {
  display: block;
  font-size: 21px;
  font-weight: 700;
  color: var(--ink-2);
  margin-bottom: 4px;
}

.empty-themes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  align-items: center;
}

.empty-themes-label { margin: 0; font-size: 15px; }

.sheet-caption {
  margin: 0;
  font-size: 15px;
  color: var(--hint);
  text-align: center;
}

/* thumbnail strip for multi-page outputs */

.thumb-strip {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
  max-width: 800px;
  padding-top: 6px;
}

.thumb { margin: 0; width: 116px; }

.thumb-inner {
  position: relative;
  width: 116px;
  aspect-ratio: 8.5 / 11;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: #fff;
  pointer-events: none;
}

body.paper-a4 .thumb-inner { aspect-ratio: 210 / 297; }

.thumb-inner .sheet {
  position: absolute;
  top: 0; left: 0;
  width: 780px;
  max-width: none;
  aspect-ratio: auto;
  overflow: visible;
  box-shadow: none;
  transform: scale(0.14872);
  transform-origin: top left;
}

.thumb-fit { aspect-ratio: 8.5 / 11; }
.thumb-fit > * { position: absolute; top: 0; left: 0; transform-origin: top left; }

.thumb figcaption {
  font-size: 13px;
  color: var(--hint);
  text-align: center;
  padding-top: 4px;
}

/* ---------- on-sheet artifact typography (demoted headings) ---------- */

.sheet-title {
  margin: 0 0 6px;
  text-align: center;
  font-size: calc(var(--pz-pt) * 1.35pt);
  letter-spacing: 0.04em;
  font-weight: 700;
  line-height: 1.2;
}

.pack-label {
  margin: 0 0 10px;
  text-align: center;
  color: var(--ink-2);
  font-size: max(11pt, calc(var(--pz-pt) * 0.45pt));
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.sheet-meta {
  margin: 0 0 20px;
  font-size: max(11pt, calc(var(--pz-pt) * 0.55pt));
  color: var(--ink-2);
}

.meta-blank {
  display: inline-block;
  width: 3.2em;
  border-bottom: 1px solid var(--ink);
  vertical-align: baseline;
  margin-right: 1.4em;
}

.meta-blank-short { width: 2.4em; margin-right: 0; }

.list-heading {
  margin: 22px 0 6px;
  font-size: max(14pt, calc(var(--pz-pt) * 0.75pt));
  font-weight: 700;
}

/* ---------- word search grid ---------- */

.grid-host { display: flex; justify-content: center; }

/* Static pre-generated puzzle on theme landing pages (tools/build-theme-pages.js).
   Not .sheet: that class holds a page aspect ratio with overflow:hidden, which
   would clip a static grid. This is a content card, not a page preview. */
.static-puzzle {
  --pz-pt: 20;
  background: #fff;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  box-shadow: var(--shadow-page);
  padding: 28px 24px 32px;
  margin: 24px 0;
  display: grid;
  gap: 20px;
  justify-items: center;
  font-family: "Atkinson Hyperlegible", "Segoe UI", Helvetica, Arial, sans-serif;
  color: #111;
  overflow-x: auto;
}
@media (max-width: 640px) { .static-puzzle { --pz-pt: 12; padding: 18px 8px 22px; } }
.static-puzzle .word-list { justify-content: center; }

table.ws {
  border-collapse: collapse;
  table-layout: fixed;
  width: max-content;
  max-width: none;
  font-size: calc(var(--pz-pt) * 1pt);
}

table.ws td {
  border: 1px solid #000;
  width: 1.55em;
  height: 1.55em;
  text-align: center;
  vertical-align: middle;
  font-weight: 700;
  font-size: 1em;
  padding: 0;
  user-select: none;
}

table.ws td.hit { background: var(--hit); border-radius: 2px; }

body.hide-grid table.ws td { border-color: transparent; }
body.hide-grid table.ws.key td.sol { text-decoration-thickness: 2.5px; }

table.ws.key td.sol { font-weight: 700; text-decoration: underline; }
table.ws.key td.nonsol { color: transparent; }

/* word list: flex wrap with measured min-width (no column collisions) */

.word-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  column-gap: 30px;
  row-gap: 2px;
  font-size: max(14pt, calc(var(--pz-pt) * 0.78pt));
}

@media screen {
  .word-list li { min-width: var(--wl-min, 0); }
}

.word-list li {
  break-inside: avoid;
  padding: 5px 4px;
  cursor: pointer;
  letter-spacing: 0.05em;
  border-radius: var(--r-sm);
}

.word-list li:hover { background: var(--tint); }
.word-list li.found { text-decoration: line-through; opacity: 0.45; }
.word-list li.static { cursor: default; }
.word-list li.static:hover { background: none; }

.answer-sheet { display: none; }
body.show-key .answer-sheet { display: block; }

.pack-page { break-before: page; }

.key-block + .key-block { margin-top: 28px; break-before: page; }
.key-block .list-heading:empty { display: none; }

/* ---------- bingo ---------- */

.cards {
  display: grid;
  /* Cards per page is a page layout, not a row count: 1-up is one card per
     page (handled separately via .up-1 below), 2-up is 2 side by side, and
     4-up is a 2x2 grid (2 columns, wrapping to a new row every 2 cards) so
     it matches the quarter-page layout js/pdf-export.js produces. Capping
     at 2 columns here is what makes --up:4 wrap into rows of 2 instead of
     laying out 4 continuous columns. */
  grid-template-columns: repeat(min(var(--up, 2), 2), 1fr);
  gap: 16px;
  align-items: start;
  width: 100%;
  max-width: 860px;
  position: relative;
}

.cards-empty {
  width: 100%;
  min-height: 420px;
  border: 2px dashed var(--rule-strong);
  border-radius: var(--r-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--hint);
  font-size: 17px;
  padding: 20px;
}

.bcard {
  background: #fff;
  border: 2px solid #000;
  border-radius: var(--r-lg);
  padding: 14px;
  break-inside: avoid;
  box-shadow: var(--shadow-page);
  /* Bingo cards live outside .sheet, so they need the puzzle face applied
     here too — the page copy promises Atkinson Hyperlegible on the cards. */
  font-family: "Atkinson Hyperlegible", "Segoe UI", Helvetica, Arial, sans-serif;
}

.bcard-title {
  text-align: center;
  font-weight: 700;
  margin: 0 0 6px;
  font-size: max(14pt, calc(var(--pz-pt) * 0.55pt));
  letter-spacing: 0.03em;
}

.bingo-letters { display: flex; margin-bottom: 8px; }

.bingo-letters span {
  flex: 1;
  text-align: center;
  font-weight: 700;
  font-size: max(16pt, calc(var(--pz-pt) * 0.65pt));
  color: var(--accent);
}

table.bgrid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.bgrid td { border: 1.5px solid #000; padding: 0; }

.bcell {
  aspect-ratio: 1 / 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-weight: 700;
  font-size: calc(var(--pz-pt) * 1pt);
  line-height: 1.15;
  white-space: nowrap;
  overflow: hidden;
  padding: 2px;
}

.bcell.free {
  font-style: italic;
  outline: 3px double #000;
  outline-offset: -5px;
}

/* WORK ITEM 1 (bingo fixes): shrinkCells() in js/bingo.js adds this when an
   entry still overflows at the 9px floor even after shrinking — wrap at
   spaces instead of silently clipping the text under nowrap+overflow:hidden. */
.bcell-wrap {
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.05;
}

.entry-count { margin: 0; font-size: 15px; font-weight: 700; }
.entry-count.warn { color: var(--warn); }
.entry-count.ok { color: var(--ok); }

.call-sheet { margin-top: 28px; }

body:not(.show-call) .call-sheet { display: none; }

.call-list {
  columns: 5;
  column-gap: 30px;
  font-size: max(12pt, calc(var(--pz-pt) * 0.5pt));
  padding-left: 1.2em;
}

.call-list li { break-inside: avoid; padding: 0.15em 0; }

/* cut guides
   Only a center vertical line is drawn, for both cut-2 and cut-4. As of
   the 2026-08-31 fix, .cards caps at min(--up, 2) columns, so cut-2 and
   cut-4 are BOTH a 2-column grid (cut-4 just runs more rows of it, to
   match js/pdf-export.js's 2x2-per-page quarter-card layout instead of
   the old N-across layout). That makes the vertical line simple and
   exact for either case: with 2 equal 1fr columns and an even gap, the
   container's horizontal midpoint always lands in the middle of the gap
   between those two columns: true for every row, on every page, no
   matter how many rows the set runs to.
   A horizontal guide for cut-4 is intentionally left out, even though a
   real 2x2 page is now the intended physical layout. Reasoning, traced
   against the actual markup (js/bingo.js render()/configureGrid()):
   .cards.cut-4 is one continuous grid holding every card in the set, with
   no `break-after`/`break-before` rule forcing exactly 2 rows (4 cards)
   onto each printed page the way .cards.up-1 forces exactly 1 card per
   page. Row height is also not guaranteed uniform: js/bingo.js's
   shrinkCells() shrinks each .bcell's font size independently based on
   that cell's own text, so two cards with different-length entries can
   render at slightly different heights. Without a forced per-page break
   and with non-guaranteed row heights, no fixed CSS position (a % of the
   container, or a repeating background) can be pinned to a real page
   boundary: the same "not knowable in CSS" problem the original horizontal
   guide had, just no longer for the column layout, now for the page
   break. Forcing a break-after every 2 rows would fix this, but that's a
   pagination behavior change (possible blank trailing space per page),
   not a pure cut-guide fix, so it's left for a follow-up rather than
   guessed at here. Cutting rows apart is left to the printed sheet's own
   row spacing, same as cut-2 already does. */

.cards.cut-2::before,
.cards.cut-4::before {
  content: "";
  position: absolute;
  pointer-events: none;
  z-index: 1;
  left: 50%; top: -8px; bottom: -8px;
  border-left: 2px dashed var(--rule-strong);
}

/* ---------- sudoku ---------- */

table.sud {
  border-collapse: collapse;
  margin: 0 auto;
  border: 3px solid #000;
  font-size: calc(var(--pz-pt) * 1pt);
}

.sud td {
  border: 1px solid #b9b9b9;
  width: 1.55em;
  height: 1.55em;
  text-align: center;
  vertical-align: middle;
  font-weight: 700;
  font-size: 1em;
  padding: 0;
  user-select: none;
}

.sud td:nth-child(3n) { border-right: 2.5px solid #000; }
.sud td:nth-child(9n) { border-right: none; }
.sud tr:nth-child(3n) td { border-bottom: 2.5px solid #000; }
.sud tr:nth-child(9n) td { border-bottom: none; }

.sud-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin: 0 0 18px;
  font-size: max(11pt, calc(var(--pz-pt) * 0.45pt));
  color: var(--hint);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
}

.sud-meta .sud-diff { color: var(--accent); }

/* ---------- word scramble ---------- */

.scramble-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 40px;
  row-gap: 26px;
  margin-top: 8px;
}

@media (max-width: 620px) {
  .scramble-list { grid-template-columns: 1fr; }
}

.scr-item { margin: 0; display: flex; flex-direction: column; gap: 10px; }

.scr-num {
  font-weight: 700;
  color: var(--accent);
  font-size: max(12pt, calc(var(--pz-pt) * 0.5pt));
}

.scr-word {
  font-weight: 700;
  letter-spacing: 0.28em;
  font-size: calc(var(--pz-pt) * 1pt);
  word-break: break-all;
}

.scr-line {
  display: block;
  width: 92%;
  height: calc(var(--pz-pt) * 1.2pt);
  border-bottom: 1.5px solid #555;
}

.scr-key {
  columns: 3;
  column-gap: 34px;
  list-style-position: inside;
  font-size: max(14pt, calc(var(--pz-pt) * 0.72pt));
  padding-left: 0.4em;
}

@media (max-width: 620px) {
  .scr-key { columns: 2; }
}

.scr-key li { break-inside: avoid; padding: 0.15em 0; font-weight: 700; letter-spacing: 0.04em; }

/* ---------- crawlable copy & prose pages ---------- */

.seo-copy {
  max-width: 72ch;
  margin: 56px auto 0;
  padding: 0 32px;
}

.seo-copy h2 {
  font-size: 24px;
  margin: 34px 0 10px;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

.seo-copy h3 { font-size: 19px; margin: 22px 0 6px; }

.seo-copy p, .seo-copy li { color: var(--ink-2); font-size: 17px; }

.seo-copy a { color: var(--accent); }

.seo-copy ol, .seo-copy ul { padding-left: 22px; }
.seo-copy li { margin: 6px 0; }

.cross-link { border-top: 1px solid var(--rule); padding-top: 14px; margin-top: 22px; }

.type-note { color: var(--hint); font-style: italic; }

.prose {
  max-width: 68ch;
  margin: 0 auto;
  padding: 8px 32px 40px;
}

.prose h2 { font-size: 24px; margin: 30px 0 10px; line-height: 1.25; }
.prose p, .prose li { color: var(--ink-2); }
.prose a { color: var(--accent); }
.prose ul { padding-left: 22px; }
.prose li { margin: 6px 0; }

/* ---------- footer ---------- */

.site-footer {
  margin-top: 64px;
  padding: 24px 32px 34px;
  border-top: 1px solid var(--rule);
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: center;
  color: var(--hint);
  font-size: 15px;
  max-width: 1460px;
  margin-left: auto;
  margin-right: auto;
  width: 100%;
}

.site-footer .foot-links { display: flex; gap: 8px; flex-wrap: wrap; }

.site-footer a {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 8px 10px;
}

.site-footer a:hover { color: var(--accent); text-decoration: underline; }

.site-footer .spacer { margin-left: auto; }

.site-footer .foot-label {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 8px 0 8px 10px;
}

/* ---------- high contrast ---------- */

@media (prefers-contrast: more) {
  :root {
    --hint: #4a453c;
    --rule: #b9b0a0;
    --rule-strong: #8f8672;
  }
  .btn, .preset-btn, input[type="text"], textarea, select { border-color: var(--ink-2); }
}

/* ---------- print ----------
   @page size comes from css/page-letter.css or css/page-a4.css, whichever
   js/paper.js has enabled for the Letter/A4 control.
   Geometry here is verified by tests/print-qa.js — change deliberately. */

@media print {
  /* js/shared.js sets an inline body padding-bottom (measured from the
     fixed action bar's rendered height, ~140-235px on screen) so the bar
     never covers page content. That padding has no meaning on paper —
     the action bar is hidden below — but an inline style always wins over
     an unmarked rule, so this needs !important to actually clear it. */
  body { background: #fff; padding-bottom: 0 !important; }

  .site-nav, .site-footer, .screen-only, .tool-strip, .skip-link,
  .mode-seg, .action-bar, .seo-copy, .sheet-caption, .thumb-strip { display: none !important; }

  .layout { display: block; padding: 0; }
  .preview { display: block; }
  .print-only { display: block; }

  .sheet {
    max-width: none;
    width: auto;
    aspect-ratio: auto;
    overflow: visible;
    box-shadow: none;
    outline: none;
    border: none;
    border-radius: 0;
    padding: 0;
    background: #fff;
  }

  /* Theme landing pages (public/word-search/): printing the page directly
     must yield a clean puzzle sheet — title, grid, word list — not the
     marketing prose and dead CTA buttons around it. The h1 lives in
     .tool-strip, which the block above hides globally, so it is re-shown
     here (later + more specific beats the earlier !important at equal
     importance). 28pt on paper honors the pages' "large print" claim —
     screen sizes are layout, print size is the promise. */
  .theme-page .tool-strip { display: block !important; }
  .theme-page .tool-strip .tool-sub { display: none; }
  .theme-page .prose > *:not(.static-puzzle) { display: none; }
  .theme-page .static-puzzle {
    --pz-pt: 28;
    box-shadow: none;
    border: none;
    border-radius: 0;
    padding: 0;
    margin: 0;
    overflow: visible;
  }

  .answer-sheet, .pack-page { break-before: page; }
  body:not(.show-key) .answer-sheet { display: none !important; }
  #printSheets:empty { display: none; }

  .sheet-title { font-size: calc(var(--pz-pt) * 1.15pt); margin-bottom: 2px; }
  .sheet-meta { margin: 0 0 10px; }
  .list-heading { margin: 10px 0 4px; }
  .pack-label { margin: 0 0 6px; }

  /* print restores tidy columns; screen uses measured flex to avoid collisions */
  .word-list {
    display: block;
    columns: 3;
    column-gap: 28px;
    font-size: max(12pt, calc(var(--pz-pt) * 0.62pt));
  }

  /* Belt-and-braces: JS should never mark a print-sheet <li> "found" — reset the look anyway in case it ever does. */
  .word-list li.found { text-decoration: none; opacity: 1; }

  .cards { gap: 10px; max-width: none; }
  .bcard { page-break-inside: avoid; box-shadow: none; }

  body.show-call .call-sheet { display: block !important; }
  .call-sheet {
    background: none;
    box-shadow: none;
    max-width: none;
    padding: 0;
    break-before: page;
  }

  .cards.up-1 { display: block; }
  .cards.up-1 .bcard {
    margin: 0 auto;
    width: min(100%, 8in);
    break-after: page;
  }
  .cards.up-1 .bcard:last-child { break-after: auto; }
}

/* ============================================================
   Personality pass — 2026-08-23
   Signature motif: marigold highlighter swash (H1 keyword,
   active nav, found grid cells). Display face: Fraunces.
   Paper staging, settle animation, dressed controls, docked
   action bar. All motion behind prefers-reduced-motion.
   ============================================================ */

:root { --display: "Fraunces", Georgia, "Times New Roman", serif; }

/* ---- ground: warm light + faint paper grain, not a flat void ---- */
body {
  background:
    radial-gradient(1100px 480px at 50% -140px, rgba(255, 252, 244, 0.9), rgba(255, 252, 244, 0) 70%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.42 0 0 0 0 0.38 0 0 0 0 0.30 0 0 0 0.045 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E"),
    var(--bg);
}

/* ---- wordmark ---- */
.brand { gap: 10px; }
.brand-mark {
  background: #fff;
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 3px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  box-shadow: 2.5px 2.5px 0 0 var(--marigold);
}
.brand > span:last-child { font-family: var(--display); font-weight: 700; font-size: 20px; letter-spacing: -0.01em; }
.brand-sub { font-family: var(--display); font-weight: 600; }

/* ---- display type ---- */
.tool-strip h1, .prose h1, .seo-copy h2 {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.tool-strip h1 { font-size: clamp(30px, 3.6vw, 42px); }
.seo-copy h2 { font-size: 26px; }
.seo-copy h3 { font-weight: 700; }

/* ---- the highlighter swash ---- */
.hl {
  position: relative;
  white-space: nowrap;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 20' preserveAspectRatio='none'%3E%3Cpath d='M2 13 Q28 7 62 9 T98 10 L97.4 17 Q60 21 30 19.5 T2.6 18 Z' fill='%23f2c14e' fill-opacity='0.75'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: 100% 0.5em;
  background-position: 0 88%;
  padding: 0 0.08em;
  margin: 0 -0.08em;
}
.nav-links a { border-bottom: 0; }
.nav-links a.active {
  color: var(--ink);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 20' preserveAspectRatio='none'%3E%3Cpath d='M2 13 Q28 7 62 9 T98 10 L97.4 17 Q60 21 30 19.5 T2.6 18 Z' fill='%23f2c14e' fill-opacity='0.8'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: calc(100% - 20px) 8px;
  background-position: 10px calc(100% - 8px);
}

/* ---- staging the paper: stacked-copies edge + settle-in ---- */
.preview-live .sheet {
  box-shadow:
    var(--shadow-page),
    6px 7px 0 -2px #fff,
    7px 8px 0 -1px var(--rule-strong);
}
@media (prefers-reduced-motion: no-preference) {
  .preview-live .sheet.anim-in,
  .preview-live .cards.anim-in { animation: sheet-settle 0.28s cubic-bezier(0.2, 0.7, 0.3, 1); }
  @keyframes sheet-settle {
    from { opacity: 0; transform: translateY(10px) rotate(-0.4deg); }
    to   { opacity: 1; transform: none; }
  }
  table.ws td.hit {
    background: linear-gradient(var(--hit), var(--hit)) no-repeat 0 0 / 100% 100%;
    animation: hit-sweep 0.3s ease-out;
  }
  @keyframes hit-sweep {
    from { background-size: 0% 100%; }
    to   { background-size: 100% 100%; }
  }
}

/* ---- dressed controls ---- */
select {
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1.5 L6 6.5 L11 1.5' fill='none' stroke='%234a453c' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 34px;
}
input[type="checkbox"] {
  width: 22px; height: 22px;
  accent-color: var(--accent);
}
input[type="range"]::-webkit-slider-thumb {
  width: 30px; height: 30px;
  margin-top: -11px;
  border-width: 3px;
  box-shadow: 0 1px 4px rgba(26, 24, 20, 0.3), 2px 2px 0 0 var(--marigold-soft);
}
input[type="range"]::-moz-range-thumb {
  width: 24px; height: 24px;
  box-shadow: 0 1px 4px rgba(26, 24, 20, 0.3), 2px 2px 0 0 var(--marigold-soft);
}

/* ---- print safety: no motif, no staging, no animation on paper ---- */
@media print {
  .sheet { transform: none !important; animation: none !important; box-shadow: none !important; }
  body { background: #fff; }
}

/* ---- consent banner (js/consent-banner.js) ----
   Normal document flow at the top, not fixed. The three maker pages already
   pin an action bar to the bottom of the viewport (.has-bar below); a second
   fixed element there hid the Print/PDF buttons underneath it. Top-of-page,
   in-flow avoids the collision — it costs one reflow when the banner appears
   or is dismissed, which is a fine trade for something shown at most once
   per visitor. */
.consent-banner {
  background: var(--card);
  border-bottom: 1px solid var(--rule-strong);
  padding: 14px 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 16px;
  align-items: center;
  justify-content: space-between;
}
.consent-banner p {
  margin: 0;
  font-size: 15px;
  color: var(--ink-2);
  flex: 1 1 320px;
  line-height: 1.5;
}
.consent-banner a { color: var(--accent); }
/* Keeps the focused skip-link (position:absolute, top:0 — see .skip-link
   above) clear of the banner instead of rendering underneath its text.
   Only matches while .consent-banner exists in the DOM, so top:0 applies
   again on its own once js/consent-banner.js removes it. */
.consent-banner ~ .skip-link:focus { top: var(--cb-h, 0px); }
.consent-actions { display: flex; gap: 8px; flex: 0 0 auto; }

@media print { .consent-banner { display: none !important; } }

/* Inline text-link-styled button, e.g. privacy.html's "review your choice"
   control — a <button> because it runs JS, but should read as prose, not
   a UI control competing with the page's real buttons. */
.link-btn {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}
.link-btn:hover { color: var(--accent-ink); }
