/* CHOMPERS: a library card catalog got into a fight with an arcade.
   The catalog won the typography. The arcade won the buttons. Nobody won the carpet.

   docs/css-components.md is the reference: every component with its exact HTML.
   No web fonts, no <style> blocks (CSP), no JavaScript, ever. Per-element values
   arrive through inline custom properties such as style="--bar: 42%".

   Sections, in order:
    1 tokens           8 notices            15 feed and reactions   22 hall and awards
    2 base             9 forms              16 items and popover    23 settings
    3 view transitions 10 tabs              17 chomper sprites      24 landing
    4 shell and nav    11 race cabinet      18 customizer           25 rules
    5 type helpers     12 ledger            19 level ladder         26 empty and error
    6 buttons          13 chomp form        20 confetti             27 reduced motion
    7 cards, stamps    14 books, proof      21 profile */

/* 1 ─── tokens ──────────────────────────────────────────────────────────────── */

:root {
  color-scheme: light dark;

  --paper: #e9dbb8;          /* the desk */
  --drawer: #f3e9d2;         /* drawer fronts; matches theme-color in layout.rs */
  --card: #fffaee;           /* catalog stock */
  --card-2: #f6edd6;         /* older catalog stock */
  --ink: #1d2747;
  --ink-soft: #565a70;
  --rule: #c9b98f;
  --blue-rule: #b9cbe0;      /* the ruled lines on a catalog card */
  --hole: #d7c79f;

  --accent: #c8362b;         /* stamp red: fills, rules, large type */
  --accent-text: #a32a20;    /* stamp red for small type on paper */
  --accent-ink: #fff8ea;
  --accent-lip: #8a1f18;     /* the underside of an arcade button */
  --accent-2: #27386b;       /* inky navy */
  --accent-2-ink: #fff8ea;
  --accent-2-lip: #101a3c;
  --gold: #f2c14e;           /* marquee bulbs, lamp light */
  --gold-ink: #1d2747;
  --focus: #1447c0;

  /* The arcade cabinet stays dark in both modes. */
  --cab: #141b38;
  --cab-2: #1f2850;
  --cab-ink: #f4ecd5;
  --cab-soft: #aab0cf;
  --cab-edge: #05081a;
  --cab-focus: #ffe08a;
  --strip: #f6edd6;
  --strip-ink: #1d2747;

  --panel: #141b38;          /* bottom-nav control panel */
  --panel-ink: #f4ecd5;

  --shadow: rgb(29 39 71 / 0.18);
  --hard: 3px 3px 0 var(--ink);

  /* A sticker edge around sprites on dark backgrounds. A no-op filter on paper, since
     `none` would invalidate the level glows that append to it. */
  --halo: opacity(1);

  --font-display: Rockwell, "Rockwell Nova", "Roboto Slab", "DejaVu Serif", Georgia, serif;
  --font-type: "American Typewriter", "Courier Prime", "Courier New", Courier, monospace;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
  --font-scrawl: "Marker Felt", "Comic Sans MS", "Segoe Print", "Bradley Hand", cursive;
  --font-body: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;

  --touch: 44px;
  --nav-height: 68px;

  /* Rubber-stamp ink: a noise tile used as a mask, so stamps never print evenly. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' seed='4'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.6 2.35'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* "After hours in the stacks": dark green-black, one warm lamp left on. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #10150f;
    --drawer: #10150f;
    --card: #1b2319;
    --card-2: #232c20;
    --ink: #f0e3bd;
    --ink-soft: #b7ad8c;
    --rule: #424d36;
    --blue-rule: #2c3729;
    --hole: #0b0f0a;

    --accent: #f2c14e;
    --accent-text: #f2c14e;
    --accent-ink: #171b10;
    --accent-lip: #9a7420;
    --accent-2: #e2703a;
    --accent-2-ink: #171108;
    --accent-2-lip: #8d4019;
    --gold: #f2c14e;
    --gold-ink: #171b10;
    --focus: #ffe08a;

    --cab: #0a0e09;
    --cab-2: #182016;
    --cab-ink: #f0e3bd;
    --cab-soft: #a8a585;
    --cab-edge: #39432c;
    --strip: #e4d9b6;
    --strip-ink: #1b2319;

    --panel: #070a06;
    --panel-ink: #f0e3bd;

    --shadow: rgb(0 0 0 / 0.5);
    --hard: 3px 3px 0 #000;
    --halo: drop-shadow(0 0 1px #f0e3bd) drop-shadow(0 0 1px #f0e3bd);
  }
}

/* 2 ─── base ────────────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  background: var(--paper);
  scroll-padding-bottom: calc(var(--nav-height) + 40px);
}

body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: clip;
  overflow-wrap: anywhere;
  color: var(--ink);
  font: 1.0625rem/1.5 var(--font-body);
  background:
    radial-gradient(rgb(29 39 71 / 0.05) 1px, transparent 1.5px) 0 0 / 14px 14px,
    var(--paper);
}

@media (prefers-color-scheme: dark) {
  body {
    /* The lamp. */
    background:
      radial-gradient(ellipse 90% 340px at 50% 0, rgb(242 193 78 / 0.14), transparent 70%) no-repeat,
      var(--paper);
  }
}

body.has-bottom-nav { padding-bottom: calc(var(--nav-height) + 22px + env(safe-area-inset-bottom)); }

h1, h2, h3 { font-family: var(--font-display); line-height: 1.12; margin: 0 0 0.5em; font-weight: 900; }
h1 { font-size: clamp(1.9rem, 8vw, 3rem); letter-spacing: -0.015em; }
h2 { font-size: clamp(1.3rem, 5vw, 1.7rem); }
h3 { font-size: 1.1rem; }
p { margin: 0 0 0.8em; }
a { color: inherit; text-decoration-thickness: 2px; text-underline-offset: 2px; }
a:hover { color: var(--accent); }
img, svg { max-width: 100%; }
ul, ol { padding-left: 1.3em; }
small { font-size: 0.82em; }
hr { border: 0; border-top: 3px double var(--rule); margin: 24px 0; }
code, kbd { font-family: var(--font-mono); font-size: 0.9em; }

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

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* 3 ─── view transitions ────────────────────────────────────────────────────── */

@view-transition { navigation: auto; }

/* The old page gets bitten from above and below by two rows of teeth and the new
   page is underneath. The header and nav are named so they stay put. */
.topbar { view-transition-name: topbar; }
.bottom-nav { view-transition-name: bottom-nav; }

::view-transition-old(root) {
  z-index: 2;
  animation: page-chomp 300ms cubic-bezier(0.5, 0, 0.9, 0.4) both;
}
::view-transition-new(root) { z-index: 1; animation: none; }

@keyframes page-chomp {
  from {
    clip-path: polygon(0 0, 12.5% 0, 25% 0, 37.5% 0, 50% 0, 62.5% 0, 75% 0, 87.5% 0, 100% 0,
                       100% 100%, 87.5% 100%, 75% 100%, 62.5% 100%, 50% 100%, 37.5% 100%, 25% 100%, 12.5% 100%, 0 100%);
  }
  to {
    clip-path: polygon(0 50%, 12.5% 58%, 25% 50%, 37.5% 58%, 50% 50%, 62.5% 58%, 75% 50%, 87.5% 58%, 100% 50%,
                       100% 50%, 87.5% 42%, 75% 50%, 62.5% 42%, 50% 50%, 37.5% 42%, 25% 50%, 12.5% 42%, 0 50%);
  }
}

/* A <meta refresh> reload is not the reader going anywhere: no chomp every 2 seconds. */
html:has(meta[http-equiv="refresh"])::view-transition-old(root) { display: none; }

/* 4 ─── shell and nav ───────────────────────────────────────────────────────── */

.skip-link {
  position: absolute; left: 8px; top: -100px; z-index: 60;
  background: var(--card); color: var(--ink); padding: 12px 16px; border: 2px solid var(--ink);
  font-family: var(--font-type);
}
.skip-link:focus { top: 8px; }

/* The drawer front. */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: max(8px, env(safe-area-inset-top)) 16px 8px;
  background: var(--drawer);
  border-bottom: 3px double var(--ink);
}
.wordmark {
  display: inline-flex; align-items: center; min-height: var(--touch);
  font: 900 1.65rem/1 var(--font-display);
  letter-spacing: -0.02em; text-transform: uppercase; text-decoration: none;
  color: var(--accent);
  text-shadow: 2px 2px 0 var(--ink);
}
@media (prefers-color-scheme: dark) { .wordmark { text-shadow: 2px 2px 0 #7a2a12; } }
.wordmark:hover { color: var(--accent); }
.topbar-link {
  display: inline-flex; align-items: center; min-height: var(--touch); padding: 0 8px;
  font-family: var(--font-type);
}
/* Attract mode, on pages with room for it. */
.topbar:not(:has(.topbar-link))::after {
  content: "INSERT BOOK TO CONTINUE";
  content: "INSERT BOOK TO CONTINUE" / "";
  max-width: 7.5em; text-align: right;
  font: 700 0.625rem/1.15 var(--font-mono); letter-spacing: 0.08em;
  color: var(--ink-soft);
  animation: attract 1.6s steps(1) infinite;
}
@keyframes attract { 50% { opacity: 0.25; } }

/* clip, not hidden: sticky children keep working, and a stamp mid-slam can't widen the page. */
.page { flex: 1; width: 100%; max-width: 44rem; margin: 0 auto; padding: 20px 16px 32px; overflow-x: clip; }

.site-footer {
  padding: 16px; text-align: center;
  font: 0.875rem/1.4 var(--font-type); color: var(--ink-soft);
  border-top: 1px dashed var(--rule);
}
.site-footer p { margin: 0 0 4px; }
.site-footer a { display: inline-flex; align-items: center; min-height: var(--touch); padding: 0 12px; }
.zero-js { font-weight: 700; letter-spacing: 0.02em; }
.logout-form { margin: 0; }
.link-button {
  min-height: var(--touch); padding: 0 12px;
  background: none; border: 0; color: inherit; font: inherit; text-decoration: underline; cursor: pointer;
}

/* The control panel: dark steel, tab buttons and one enormous red button. */
.bottom-nav {
  --focus: var(--cab-focus);
  position: fixed; inset: auto 0 0; z-index: 30;
  display: grid; grid-template-columns: 1fr 1fr 1.45fr 1fr 1fr; align-items: stretch;
  height: calc(var(--nav-height) + env(safe-area-inset-bottom));
  padding: 0 max(2px, env(safe-area-inset-right)) env(safe-area-inset-bottom) max(2px, env(safe-area-inset-left));
  background: var(--panel); color: var(--panel-ink);
  border-top: 4px solid var(--gold);
}
.bottom-nav-item {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: var(--touch); min-width: 0;
  font: 700 0.75rem/1 var(--font-type); text-decoration: none; color: var(--panel-ink);
}
.bottom-nav-item:hover { color: var(--gold); }
.bottom-nav-item::before {
  content: ""; width: 24px; height: 24px; background: currentColor;
  -webkit-mask: var(--glyph) center / contain no-repeat; mask: var(--glyph) center / contain no-repeat;
}
.bottom-nav-item[aria-current="page"] { color: var(--gold); background: linear-gradient(transparent 92%, var(--gold) 92%); }

/* Drawer, book, rulebook, face. */
.bottom-nav-item[href="/home"] { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2'%3E%3Crect x='2.5' y='4' width='19' height='16' rx='1'/%3E%3Crect x='8' y='7.5' width='8' height='4' fill='%23000' stroke='none'/%3E%3Cpath d='M9 15.5h6' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E"); }
.bottom-nav-item[href="/books/new"] { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linejoin='round'%3E%3Cpath d='M4 4.5h13.5a2 2 0 0 1 2 2V21H6a2 2 0 0 1-2-2z'/%3E%3Cpath d='M4 19a2 2 0 0 1 2-2h13.5M9 8.5h6'/%3E%3C/svg%3E"); }
.bottom-nav-item[href="/rules"] { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3h9l4 4v14H6z'/%3E%3Cpath d='M9.5 11h6M9.5 14.5h6M9.5 18h3'/%3E%3C/svg%3E"); }
.bottom-nav-item[href="/me"] { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zM8.5 7a1.7 1.7 0 1 0 0 3.4 1.7 1.7 0 0 0 0-3.4zm7 0a1.7 1.7 0 1 0 0 3.4 1.7 1.7 0 0 0 0-3.4zM6 13.5l2 3.5 2-2.5 2 2.5 2-2.5 2 2.5 2-3.5z'/%3E%3C/svg%3E"); }

.nav-chomp {
  position: relative; z-index: 1;
  align-self: start; justify-self: center;
  width: min(100%, 92px); aspect-ratio: 1; margin-top: -26px;
  border-radius: 50%; border: 3px solid var(--cab-edge);
  background: radial-gradient(circle at 38% 30%, #ef5a4c, #c8362b 62%);
  box-shadow: 0 6px 0 #8a1f18, 0 8px 0 3px var(--cab-edge);
  color: #fff8ea;
  font: 900 0.9375rem/1 var(--font-display); letter-spacing: 0.01em;
  transition: transform 60ms, box-shadow 60ms;
}
.nav-chomp::before { display: none; }
button.nav-chomp { padding: 0; cursor: pointer; }
.nav-chomp:hover { color: #fff8ea; filter: brightness(1.08); }
.nav-chomp:active { transform: translateY(5px); box-shadow: 0 1px 0 #8a1f18, 0 3px 0 3px var(--cab-edge); }
.nav-chomp[aria-current="page"] { color: #fff8ea; background: radial-gradient(circle at 38% 30%, #ef5a4c, #c8362b 62%); text-decoration: underline; }
@media (prefers-color-scheme: dark) {
  .nav-chomp, .nav-chomp[aria-current="page"] { background: radial-gradient(circle at 38% 30%, #ffd978, #f2c14e 62%); color: #171b10; box-shadow: 0 6px 0 #9a7420, 0 8px 0 3px #000; }
  .nav-chomp:hover { color: #171b10; }
  .nav-chomp:active { box-shadow: 0 1px 0 #9a7420, 0 3px 0 3px #000; }
}

@media (min-width: 48rem) {
  .bottom-nav {
    left: 50%; right: auto; width: 44rem; transform: translateX(-50%);
    border: 4px solid var(--gold); border-bottom: 0; border-radius: 10px 10px 0 0;
  }
  .topbar { padding-inline: max(16px, calc(50vw - 22rem + 16px)); }
}

/* 5 ─── type helpers ────────────────────────────────────────────────────────── */

.page-head { margin: 0 0 18px; }
.page-head h1 { margin-bottom: 0.15em; }
.kicker {
  display: block; margin: 0 0 4px;
  font: 700 0.75rem/1.3 var(--font-mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent-text);
}
.lede { font-size: 1.125rem; }
.fine-print { font: 0.875rem/1.45 var(--font-type); color: var(--ink-soft); }
.scrawl { font-family: var(--font-scrawl); font-size: 1.15em; color: var(--accent-text); transform: rotate(-1deg); display: inline-block; }
.bites { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.joke-units { font: italic 0.85em var(--font-type); color: var(--ink-soft); white-space: nowrap; }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 0 0 12px; }
.row-between { justify-content: space-between; }
.stack { display: grid; gap: 12px; }
.section { margin: 0 0 28px; }
.section-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px;
  border-bottom: 3px double var(--ink); margin: 0 0 12px; padding-bottom: 4px;
}
.section-head h2 { margin: 0; }
.section-head a, .kicker a, .member > a { display: inline-flex; align-items: center; min-height: var(--touch); }
.section-head .row { margin: 0; }

/* 6 ─── buttons ─────────────────────────────────────────────────────────────── */

.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--touch); padding: 8px 18px;
  border: 2px solid var(--ink); border-radius: 3px;
  background: var(--card); color: var(--ink);
  font: 700 1rem/1.15 var(--font-type); text-align: center; text-decoration: none;
  cursor: pointer; box-shadow: var(--hard);
  transition: transform 50ms, box-shadow 50ms;
}
.button:hover { color: var(--ink); background: var(--card-2); }
.button:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }
.button-primary, .button-primary:hover { background: var(--accent); color: var(--accent-ink); }
.button-primary:hover { filter: brightness(1.07); }
.button-secondary, .button-secondary:hover { background: var(--accent-2); color: var(--accent-2-ink); }
.button-danger, .button-danger:hover { background: var(--ink); color: var(--paper); }
.button-big { width: 100%; min-height: 60px; font: 900 1.25rem/1.1 var(--font-display); letter-spacing: 0.02em; }
.button-quiet { border-style: dashed; box-shadow: none; background: transparent; }
.button-quiet:active { box-shadow: none; }
.button-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
button[disabled], .button[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }

/* 7 ─── cards, stamps, badges ───────────────────────────────────────────────── */

/* A catalog card: heavy stock, a red rule under the heading, and a rod hole at the
   bottom centre, which is where real ones have it. */
.card, .form-card, .error-card {
  position: relative; margin: 0 0 20px; padding: 18px 20px 34px;
  background: var(--card);
  box-shadow: inset 0 0 0 1px var(--rule);
}
.card::after, .form-card::after, .error-card::after {
  content: ""; position: absolute; bottom: 9px; left: 50%;
  width: 14px; height: 14px; margin-left: -7px; border-radius: 50%;
  background: var(--paper); box-shadow: inset 0 1px 2px var(--shadow), 0 0 0 1px var(--rule);
}
.card > :last-child, .form-card > :last-child, .error-card > :last-child { margin-bottom: 0; }

.card-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 12px;
  margin: -2px 0 12px; padding-bottom: 6px;
  border-bottom: 2px solid var(--accent);
}
.card-head h2, .card-head h3 { margin: 0; }
.card-call { font: 0.8125rem/1.2 var(--font-type); color: var(--ink-soft); white-space: nowrap; }

.card-ruled {
  background-image: repeating-linear-gradient(transparent 0 27px, var(--blue-rule) 27px 28px);
  background-position: 0 14px;
  line-height: 28px;
}
.card-plain { padding-bottom: 18px; }
.card-plain::after { display: none; }

/* Bite marks: one big circle off the edge with scallops around its rim, one layer per
   tooth. --by moves the bite down the edge; nth-child keeps two cards from matching. */
.card-bitten, .form-card, .error-card {
  --by: 46px;
  --bite-mask:
    radial-gradient(circle 21px at calc(100% + 7px) var(--by), #0000 97%, #000),
    radial-gradient(circle 7px at calc(100% - 15px) var(--by), #0000 96%, #000),
    radial-gradient(circle 7px at calc(100% - 12px) calc(var(--by) - 12px), #0000 96%, #000),
    radial-gradient(circle 7px at calc(100% - 12px) calc(var(--by) + 12px), #0000 96%, #000),
    radial-gradient(circle 7px at calc(100% - 3px) calc(var(--by) - 20px), #0000 96%, #000),
    radial-gradient(circle 7px at calc(100% - 3px) calc(var(--by) + 20px), #0000 96%, #000);
  -webkit-mask: var(--bite-mask);
  mask: var(--bite-mask);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
.card-bitten:nth-child(3n), .form-card:nth-child(3n) { --by: 92px; }
.card-bitten:nth-child(3n + 1) { --by: 64px; }
.card-bitten > .card-head, .form-card > .card-head, .form-card > h1, .form-card > h2 { padding-right: 34px; }

/* Rubber stamps. The grain mask makes them look hit, not printed. */
.stamp {
  display: inline-block; margin: 0 0 12px; padding: 2px 10px;
  transform: rotate(-3deg);
  border: 3px double currentColor; border-radius: 4px;
  color: var(--accent-text);
  font: 700 0.9375rem/1.3 var(--font-type); letter-spacing: 0.06em; text-transform: uppercase;
  -webkit-mask: var(--grain); mask: var(--grain);
}
.stamp:nth-of-type(even) { transform: rotate(2deg); }
.stamp-red { color: #c8362b; }
.stamp-navy { color: var(--accent-2); }
@media (prefers-color-scheme: dark) { .stamp-red { color: #ff7a5c; } }

/* The due-date stamp: small month over big day, the way a date band prints. */
.due-stamp {
  display: inline-grid; justify-items: center; align-content: center; min-width: 58px;
  padding: 3px 7px; transform: rotate(-4deg);
  border: 2px solid currentColor; border-radius: 3px;
  color: var(--accent-text);
  font: 700 0.625rem/1.1 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase;
  -webkit-mask: var(--grain); mask: var(--grain);
}
.due-stamp b { font-size: 1.375rem; line-height: 1.05; letter-spacing: 0; }
.due-stamp-navy { color: var(--accent-2); }

.badge {
  display: inline-block; padding: 1px 8px;
  border: 1px solid currentColor; border-radius: 2px;
  font: 700 0.75rem/1.5 var(--font-type); text-transform: uppercase; letter-spacing: 0.04em;
  white-space: nowrap;
}
.badge-shame { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.badge-self-reported, .badge-edited { color: var(--accent-2); border-style: dashed; }
.badge-suspicious { color: var(--accent-text); border-style: dashed; }
.badge-crown { background: var(--gold); color: var(--gold-ink); border-color: var(--gold-ink); }
.badge-level { background: var(--accent-2); color: var(--accent-2-ink); border-color: var(--accent-2); }
.badge-streak { color: var(--accent-text); font-family: var(--font-mono); }

/* Verdict stamps slam down once on load. */
.verdict {
  display: inline-block; margin: 8px 0 14px; padding: 6px 16px;
  transform: rotate(var(--tilt, -5deg));
  border: 5px double currentColor; border-radius: 6px;
  color: var(--accent);
  font: 900 clamp(1.5rem, 8vw, 2.25rem)/1.05 var(--font-display); letter-spacing: 0.03em; text-transform: uppercase;
  -webkit-mask: var(--grain); mask: var(--grain);
  animation: stamp-slam 260ms cubic-bezier(0.2, 0, 0.1, 1) both;
}
@keyframes stamp-slam {
  from { transform: rotate(calc(var(--tilt, -5deg) - 8deg)) scale(1.7); opacity: 0; }
  70% { transform: rotate(var(--tilt, -5deg)) scale(0.95); opacity: 1; }
}
.verdict-credited { color: #1f7a45; --tilt: -4deg; }
.verdict-busted { color: #c8362b; --tilt: -9deg; font-size: clamp(2.2rem, 13vw, 3.5rem); margin-bottom: 32px; }
.verdict-held { color: #c26a0b; --tilt: 3deg; }
.verdict-baseline, .verdict-needs_confirm { color: var(--accent-2); --tilt: -2deg; }
.verdict-stale, .verdict-failed { color: var(--ink-soft); --tilt: 4deg; }
.verdict-rejected { color: #c8362b; --tilt: 5deg; }
@media (prefers-color-scheme: dark) {
  .verdict-credited { color: #7bd58f; }
  .verdict-busted, .verdict-rejected { color: #ff7a5c; }
  .verdict-held { color: #f2a94e; }
}

/* 8 ─── notices ─────────────────────────────────────────────────────────────── */

.flash {
  margin: 0 0 16px; padding: 10px 14px;
  background: var(--card); box-shadow: inset 0 0 0 1px var(--rule);
  border-left: 8px solid var(--accent-2);
  font-family: var(--font-type);
}
.flash-error { border-left-color: var(--accent); font-weight: 700; }
.flash-ok { border-left-color: var(--accent-2); }
.flash-item { border-left-color: var(--gold); background: var(--card-2); }

/* The fake spoiler: hazard tape, in the voice of a tabloid. */
.spoiler-banner {
  margin: 0 0 18px; padding: 14px 16px;
  border: 3px solid #161b33;
  background:
    repeating-linear-gradient(-45deg, #f2c14e 0 14px, #161b33 14px 28px) top / 100% 10px no-repeat,
    repeating-linear-gradient(-45deg, #f2c14e 0 14px, #161b33 14px 28px) bottom / 100% 10px no-repeat,
    #fff8ea;
  color: #161b33;
  padding-block: 22px;
  font-family: var(--font-display);
}
.spoiler-banner strong { display: block; font-size: 1.25rem; line-height: 1.15; }
.spoiler-banner small { display: block; margin-top: 6px; font: 0.8125rem/1.3 var(--font-type); }

.crown-banner {
  display: flex; align-items: center; gap: 12px;
  margin: 0 0 18px; padding: 10px 14px;
  background: var(--gold); color: var(--gold-ink);
  border: 2px solid #161b33; box-shadow: var(--hard);
  font: 900 1.0625rem/1.2 var(--font-display);
}

/* 9 ─── forms ───────────────────────────────────────────────────────────────── */

.form-card form, form.form-stack { display: grid; gap: 6px; }
.form-card { padding-top: 22px; }

label, .label { font: 700 0.9375rem/1.3 var(--font-type); }
.form-card label:not(.pick):not(.radio-card):not(.check) { margin-top: 10px; }

.field { display: grid; gap: 4px; margin: 0 0 12px; }
.field-hint { font: 0.8125rem/1.35 var(--font-type); color: var(--ink-soft); }
.field-error { font: 700 0.875rem/1.35 var(--font-type); color: var(--accent-text); }

input:not([type="hidden"]):not([type="radio"]):not([type="checkbox"]):not([type="file"]), select, textarea {
  width: 100%; min-height: var(--touch); padding: 8px 10px;
  font: 1rem/1.3 var(--font-type); color: var(--ink);
  background: var(--card-2); border: 2px solid var(--ink); border-radius: 2px;
}
textarea { min-height: 88px; resize: vertical; }
input::placeholder, textarea::placeholder { color: var(--ink-soft); opacity: 1; }
input[aria-invalid="true"] { border-color: var(--accent); }
input[readonly] { background: transparent; border-style: dashed; }

input[type="radio"], input[type="checkbox"] { width: 22px; height: 22px; accent-color: var(--accent); }
.check {
  display: flex; align-items: center; gap: 10px; min-height: var(--touch);
  font-weight: 400;
}

fieldset { border: 0; margin: 0 0 14px; padding: 0; min-width: 0; }
legend { padding: 0; margin-bottom: 8px; font: 900 1.0625rem/1.2 var(--font-display); }

.form-card button[type="submit"]:not(.link-button) { margin-top: 14px; }
.form-card form > .button { justify-self: start; }

/* Generic radio cards: format, start point, search results. */
.radio-cards { display: grid; gap: 10px; }
.radio-cards-2 { grid-template-columns: 1fr 1fr; }
.radio-card { position: relative; display: block; cursor: pointer; font-weight: 400; }
.radio-card input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.radio-card-face {
  display: flex; align-items: center; gap: 12px; min-height: var(--touch); height: 100%;
  padding: 10px 12px;
  background: var(--card); border: 2px solid var(--rule); border-radius: 3px;
  font: 1rem/1.25 var(--font-type);
}
.radio-card-face small { display: block; color: var(--ink-soft); }
.radio-card-title { display: block; font: 900 1.0625rem/1.15 var(--font-display); }
.radio-card input:checked + .radio-card-face {
  border-color: var(--ink); background: var(--card-2);
  box-shadow: var(--hard), inset 6px 0 0 var(--accent);
  transform: translate(-1px, -1px);
}
.radio-card input:focus-visible + .radio-card-face { outline: 3px solid var(--focus); outline-offset: 2px; }
.radio-card input:disabled + .radio-card-face { opacity: 0.55; }

/* 10 ─── tabs ───────────────────────────────────────────────────────────────── */

/* Card-file dividers. The active one stands up out of the drawer. */
.tabs {
  display: flex; align-items: flex-end; gap: 2px; margin: 0 0 -3px; padding: 0 2px;
  font: 700 0.9375rem/1 var(--font-type);
}
.tab {
  flex: 1 1 0; display: flex; align-items: center; justify-content: center; min-height: var(--touch); min-width: 0;
  padding: 4px 6px; text-align: center; text-decoration: none;
  background: var(--card-2); color: var(--ink-soft);
  border: 2px solid var(--rule); border-bottom: 0; border-radius: 8px 8px 0 0;
  transform: translateY(3px);
}
.tab[aria-current="page"] {
  background: var(--cab); color: var(--gold);
  border-color: var(--cab-edge); transform: none; min-height: 50px;
  font-family: var(--font-display); font-weight: 900; font-size: 1.0625rem;
}
.tabs-paper .tab[aria-current="page"] { background: var(--card); color: var(--accent-text); border-color: var(--ink); }

/* 11 ─── race cabinet ───────────────────────────────────────────────────────── */

/* The Today board. An arcade cabinet that somebody has loaded with library tape. */
.cabinet {
  --focus: var(--cab-focus);
  --halo: drop-shadow(0 0 1px #fff8ea) drop-shadow(0 0 1px #fff8ea);
  --chomper-line: #161b33;
  position: relative; margin: 0 0 22px;
  background: var(--cab); color: var(--cab-ink);
  border: 4px solid var(--cab-edge);
  box-shadow: 5px 5px 0 var(--accent);
}
.cabinet a:hover { color: var(--gold); }
.cabinet-marquee {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 12px;
  padding: 10px 12px 8px;
  border-bottom: 2px dotted var(--gold);
}
.cabinet-title {
  margin: 0; font: 900 1.375rem/1.1 var(--font-display);
  color: var(--gold); text-transform: uppercase; letter-spacing: 0.04em;
  text-shadow: 2px 2px 0 #7a2a12;
}
.cabinet-clock {
  font: 700 0.75rem/1.3 var(--font-mono); letter-spacing: 0.08em; color: var(--cab-soft); text-transform: uppercase;
}
.cabinet-foot { padding: 8px 12px 10px; font: 0.8125rem/1.35 var(--font-type); color: var(--cab-soft); }

.race { list-style: none; margin: 0; padding: 0; }
.race-row { padding: 10px 12px 8px; border-bottom: 1px solid var(--cab-2); }
.race-row:last-child { border-bottom: 0; }
.race-row.is-you { background: var(--cab-2); box-shadow: inset 4px 0 0 var(--gold); }

.race-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.race-rank {
  flex: none; min-width: 2.2em;
  font: 700 0.875rem/1.2 var(--font-mono); color: var(--cab-soft);
}
.is-leader .race-rank { color: var(--gold); }
.race-name {
  flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 700 1.0625rem/1.5 var(--font-type); color: var(--cab-ink);
  overflow-wrap: normal;
}
a.race-name { padding-block: 9px; margin-block: -9px; text-decoration-color: var(--cab-soft); }
.race-you {
  flex: none; padding: 0 5px;
  background: var(--gold); color: #161b33;
  font: 700 0.6875rem/1.45 var(--font-mono); letter-spacing: 0.06em;
}
.race-score {
  flex: none;
  font: 700 1.1875rem/1.2 var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--gold); text-shadow: 0 0 8px rgb(242 193 78 / 0.45);
}

/* The lane. --bar is set on .race-track; the chomper rides it from 0 to 100%. */
.race-track {
  --eater: 56px;
  --strip-h: 30px;
  --chomper-size: var(--eater);
  position: relative; height: var(--eater);
  overflow: hidden;
  overflow: clip visible; /* hats and glows may leave the lane upward, crumbs may not leave sideways */
}
.race-strip {
  position: absolute; left: 0; right: 0; top: calc((var(--eater) - var(--strip-h)) / 2);
  height: var(--strip-h); padding: 0 8px; overflow: hidden; white-space: nowrap; overflow-wrap: normal;
  background: var(--strip);
  box-shadow: inset 0 2px 0 var(--accent), inset 0 -2px 0 var(--accent);
  color: var(--strip-ink);
  font: 700 0.9375rem/30px var(--font-type);
}
/* left + translateX of the same percent keeps the sprite inside the lane at both ends. */
.race-eater {
  position: absolute; top: 0; z-index: 1;
  left: var(--bar, 0%);
  width: var(--eater); height: var(--eater);
  transform: translateX(calc(var(--bar, 0%) * -1));
  animation: race-run 1200ms steps(16) both;
}
/* Everything behind the mouth is gone. What is left is crumbs. */
.race-eater::before {
  content: ""; position: absolute; top: 0; bottom: 0; right: 24%; width: 120vw;
  background:
    radial-gradient(circle 1.4px, var(--strip) 96%, #0000) 3px 16px / 17px 9px,
    radial-gradient(circle 1px, var(--cab-soft) 96%, #0000) 9px 20px / 11px 13px,
    var(--bg-lane, var(--cab));
  background-repeat: repeat-x, repeat-x, no-repeat;
}
.is-you .race-eater { --bg-lane: var(--cab-2); }
.race-eater .chomper { position: relative; filter: var(--halo); }
@keyframes race-run { from { left: 0; transform: translateX(0); } }

.race-row:nth-child(2n) .jaw { --chomp-speed: 780ms; }
.race-row:nth-child(3n) .jaw { --chomp-speed: 1040ms; }

.race-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin-top: 4px;
  font: 0.8125rem/1.3 var(--font-type); color: var(--cab-soft);
}
.race-foot:empty { display: none; }
.race-chip {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px;
  border: 1px solid var(--cab-soft); border-radius: 2px;
  font: 700 0.75rem/1.3 var(--font-type); color: var(--cab-ink); white-space: nowrap;
}
.race-chip-bad { border-color: #ff8f7a; color: #ffb9a8; }
.race-chip-good { border-color: #7bd58f; color: #b4ecc1; }
.race-throw {
  margin-left: auto; min-height: var(--touch); padding: 6px 14px;
  background: var(--accent); color: var(--accent-ink);
  border: 2px solid var(--cab-ink); border-radius: 3px;
  font: 700 0.9375rem/1 var(--font-type); cursor: pointer;
  box-shadow: 2px 2px 0 #000;
}
.race-throw:active { transform: translate(2px, 2px); box-shadow: none; }
@media (prefers-color-scheme: dark) { .race-throw { border-color: #000; } }

/* 12 ─── ledger (This Week, All Time) ───────────────────────────────────────── */

.ledger {
  width: 100%; margin: 0 0 22px; border-collapse: collapse;
  background: var(--card); box-shadow: inset 0 0 0 1px var(--rule);
  font: 1rem/1.25 var(--font-type);
}
.ledger caption { padding: 10px 12px 6px; text-align: left; font: 900 1.25rem/1.1 var(--font-display); }
.ledger th {
  padding: 6px 10px; text-align: left;
  font: 700 0.75rem/1.2 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-soft);
  border-bottom: 2px solid var(--accent);
}
.ledger td { padding: 8px 10px; border-bottom: 1px solid var(--blue-rule); vertical-align: middle; }
.ledger tr:last-child td { border-bottom: 0; }
.ledger .num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.ledger .rank { width: 2.4em; font-family: var(--font-mono); color: var(--ink-soft); }
.ledger tr.is-you td { background: var(--card-2); }
.ledger tr.is-you td:first-child { box-shadow: inset 5px 0 0 var(--accent); }
.ledger-who { display: flex; align-items: center; gap: 8px; --chomper-size: 40px; min-width: 0; }
.ledger-who a { display: inline-flex; align-items: center; min-height: var(--touch); min-width: var(--touch); }

/* 13 ─── chomp form ─────────────────────────────────────────────────────────── */

.chomp-form { display: grid; gap: 16px; }
.reading-list { display: grid; gap: 10px; }
.reading-card { position: relative; display: block; cursor: pointer; font-weight: 400; }
.reading-card input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.reading-card-face {
  --cover-w: 48px;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px;
  min-height: 64px; padding: 8px 12px;
  background: var(--card); border: 2px solid var(--rule); border-radius: 3px;
  font: 0.875rem/1.3 var(--font-type);
}
.reading-card-title { display: block; font: 900 1.0625rem/1.15 var(--font-display); }
.reading-card-sub { display: block; color: var(--ink-soft); }
.reading-card-tick { visibility: hidden; color: var(--accent); }
.reading-card input:checked + .reading-card-face {
  border-color: var(--ink); background: var(--card-2);
  box-shadow: var(--hard), inset 6px 0 0 var(--accent);
  transform: translate(-1px, -1px);
}
.reading-card input:checked + .reading-card-face .reading-card-tick { visibility: visible; }
.reading-card input:focus-visible + .reading-card-face { outline: 3px solid var(--focus); outline-offset: 2px; }

/* The mouth. A hungry label in front of a real, visible file input. */
.file-drop { display: grid; gap: 8px; }
.file-drop-label {
  --chomper-size: 96px;
  --chomp-speed: 1500ms;
  display: grid; justify-items: center; gap: 4px; padding: 16px 12px;
  background: var(--card); cursor: pointer; text-align: center;
  border: 3px dashed var(--ink); border-radius: 4px;
  font: 900 1.375rem/1.15 var(--font-display);
}
.file-drop-label small { display: block; font: 400 0.875rem/1.3 var(--font-type); color: var(--ink-soft); }
.file-drop-ready { display: none; }
.file-input {
  width: 100%; min-height: var(--touch); padding: 4px;
  font: 0.875rem/1.3 var(--font-type); color: var(--ink);
}
.file-input::file-selector-button {
  min-height: 40px; margin-right: 10px; padding: 6px 12px;
  background: var(--card-2); color: var(--ink);
  border: 2px solid var(--ink); border-radius: 2px;
  font: 700 0.9375rem var(--font-type); cursor: pointer;
}

.chomp-go {
  display: flex; align-items: center; justify-content: center; width: 100%; min-height: 76px;
  background: radial-gradient(ellipse at 40% 20%, #ef5a4c, #c8362b 60%);
  color: #fff8ea; cursor: pointer;
  border: 4px solid #161b33; border-radius: 8px;
  box-shadow: 0 7px 0 #8a1f18, 0 7px 0 4px #161b33;
  font: 900 2rem/1 var(--font-display); letter-spacing: 0.05em;
  transition: transform 50ms, box-shadow 50ms;
}
.chomp-go:active { transform: translateY(6px); box-shadow: 0 1px 0 #8a1f18, 0 1px 0 4px #161b33; }
@media (prefers-color-scheme: dark) {
  .chomp-go { background: radial-gradient(ellipse at 40% 20%, #ffd978, #f2c14e 60%); color: #171b10; border-color: #000; box-shadow: 0 7px 0 #9a7420, 0 7px 0 4px #000; }
  .chomp-go:active { box-shadow: 0 1px 0 #9a7420, 0 1px 0 4px #000; }
}

/* Without :has() the button simply stays visible, which still works. */
@supports selector(:has(*)) {
  .chomp-reveal { display: none; }
  .chomp-form:has(.file-input:valid) .chomp-reveal { display: grid; gap: 16px; animation: bite-in 180ms steps(4) both; }
  .chomp-form:has(.file-input:valid) .file-drop-idle { display: none; }
  .chomp-form:has(.file-input:valid) .file-drop-ready { display: block; color: var(--accent-text); }
  .chomp-form:has(.file-input:valid) .file-drop-label {
    --chomp-speed: 260ms;
    border-style: solid; background: var(--card-2);
    box-shadow: var(--hard);
  }
}
@keyframes bite-in { from { transform: scale(0.9); opacity: 0; } }

/* 14 ─── books and proof ────────────────────────────────────────────────────── */

.cover {
  flex: none; display: block; width: var(--cover-w, 72px); aspect-ratio: 2 / 3;
  object-fit: cover; background: var(--card-2);
  box-shadow: 2px 2px 0 var(--ink);
}
.generated-cover {
  position: relative; flex: none; overflow: hidden;
  display: flex; flex-direction: column; gap: 4px;
  width: var(--cover-w, 72px); aspect-ratio: 2 / 3;
  padding: calc(var(--cover-w, 72px) * 0.09) calc(var(--cover-w, 72px) * 0.08) calc(var(--cover-w, 72px) * 0.08) calc(var(--cover-w, 72px) * 0.16);
  background: var(--cloth, #27386b); color: var(--cloth-ink, #fff8ea);
  box-shadow: 2px 2px 0 var(--ink), inset calc(var(--cover-w, 72px) * 0.07) 0 0 rgb(0 0 0 / 0.28);
  font: 900 calc(var(--cover-w, 72px) * 0.125)/1.1 var(--font-display);
  overflow-wrap: anywhere;
  /* Somebody already had a go at the corner. */
  -webkit-mask: radial-gradient(circle calc(var(--cover-w, 72px) * 0.15) at 100% 100%, #0000 96%, #000);
  mask: radial-gradient(circle calc(var(--cover-w, 72px) * 0.15) at 100% 100%, #0000 96%, #000);
}
.generated-cover.cloth-0 { --cloth: #27386b; --cloth-ink: #fff8ea; }
.generated-cover.cloth-1 { --cloth: #8a1f18; --cloth-ink: #ffe9c8; }
.generated-cover.cloth-2 { --cloth: #2f5d3a; --cloth-ink: #fff8ea; }
.generated-cover.cloth-3 { --cloth: #e7b52c; --cloth-ink: #1d2747; }
.generated-cover.cloth-4 { --cloth: #5a3a2a; --cloth-ink: #f2d9a8; }
.generated-cover.cloth-5 { --cloth: #1f6f8b; --cloth-ink: #fff8ea; }
.generated-cover::before {
  content: ""; position: absolute; left: 16%; right: 8%; pointer-events: none;
  border-top: 2px solid currentColor; opacity: 0.6; top: 5%;
}
.generated-cover.ornament-1::before { top: auto; bottom: 5%; right: 24%; }
.generated-cover.ornament-2::before { top: 5%; border-top-style: double; border-top-width: 3px; }
.generated-cover-call { font: 400 0.75em/1 var(--font-mono); opacity: 0.75; margin-top: 2px; }
.generated-cover-title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5; overflow: hidden;
}
.generated-cover-author {
  margin-top: auto; font: 400 0.72em/1.1 var(--font-type); opacity: 0.85;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}

.book-row {
  display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start;
  padding: 10px 0; border-bottom: 1px solid var(--blue-rule);
}
.book-row:last-child { border-bottom: 0; }
.book-title { display: block; margin: 0; font: 900 1.125rem/1.15 var(--font-display); }
a.book-title { padding-block: 12px; margin-block: -12px; }
.book-author { display: block; font: italic 0.9375rem/1.3 var(--font-body); color: var(--ink-soft); }
.book-meta { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 4px; font: 0.8125rem/1.5 var(--font-type); color: var(--ink-soft); }
.lookup-grid { display: grid; gap: 14px; }

/* How far into a book. A tape with the eaten part already gone. */
.tape {
  position: relative; height: 22px; margin: 6px 0; overflow: hidden;
  background: var(--card-2); box-shadow: inset 0 0 0 1px var(--rule);
}
.tape::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: var(--bar, 0%);
  background: repeating-linear-gradient(90deg, var(--accent) 0 8px, color-mix(in srgb, var(--accent) 80%, var(--ink)) 8px 10px);
}
.tape::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: var(--bar, 0%); width: 8px;
  background: radial-gradient(circle 5px at 0 50%, var(--accent) 96%, #0000);
}
.tape-label { font: 0.8125rem/1.3 var(--font-type); color: var(--ink-soft); }

/* The proof, paperclipped to its card. */
.proof-figure { position: relative; margin: 0 0 16px; text-align: center; }
.proof-figure img {
  display: block; max-width: 100%; height: auto; max-height: 70vh; margin: 0 auto;
  border: 8px solid #fffdf6; box-shadow: 0 2px 10px var(--shadow), 0 0 0 1px var(--rule);
  transform: rotate(-0.8deg);
}
.proof-figure::before {
  content: ""; position: absolute; top: -9px; left: 22px; z-index: 1; width: 16px; height: 42px;
  border: 3px solid #8f97a8; border-radius: 9px; border-bottom-width: 3px;
  box-shadow: inset 0 0 0 2px transparent;
}
.proof-digested {
  display: grid; justify-items: center; align-content: center; gap: 6px; min-height: 200px; padding: 24px; text-align: center;
  background: repeating-linear-gradient(-45deg, var(--card-2) 0 10px, var(--card) 10px 20px);
  border: 2px dashed var(--rule);
  font: 900 1.375rem/1.15 var(--font-display);
}
.proof-digested small { display: block; font: 0.875rem/1.3 var(--font-type); color: var(--ink-soft); }

.readout { display: grid; grid-template-columns: auto 1fr; gap: 2px 14px; margin: 0 0 14px; font: 0.9375rem/1.35 var(--font-type); }
.readout dt { color: var(--ink-soft); }
.readout dd { margin: 0; font-weight: 700; }

/* A librarian's pencil note, in the margin, about you. */
.roast {
  position: relative; margin: 8px 0 16px; padding: 4px 0 4px 16px;
  border-left: 3px solid var(--accent);
  font: 1.1875rem/1.25 var(--font-scrawl); color: var(--accent-text);
  transform: rotate(-0.6deg);
}
.suspicions { margin: 0 0 14px; padding: 8px 12px 8px 30px; background: var(--card-2); border: 1px dashed var(--accent); font: 0.875rem/1.35 var(--font-type); }

/* BOOKSHIT and Vouch: two arcade buttons, side by side, one of them accusatory. */
.vote-bar { display: grid; grid-template-columns: 1.35fr 1fr; gap: 12px; margin: 12px 0 18px; }
.vote-bar form { display: grid; margin: 0; }
.vote {
  display: grid; align-content: center; justify-items: center; gap: 2px;
  min-height: 74px; padding: 8px 6px; cursor: pointer;
  border: 3px solid #161b33; border-radius: 8px;
  font: 900 1.25rem/1.05 var(--font-display);
  transition: transform 50ms, box-shadow 50ms;
}
.vote small { font: 700 0.75rem/1.2 var(--font-mono); opacity: 0.9; }
.vote-bookshit {
  background: radial-gradient(ellipse at 40% 15%, #ef5a4c, #c8362b 65%); color: #fff8ea;
  box-shadow: 0 6px 0 #8a1f18, 0 6px 0 3px #161b33;
  font-size: clamp(1.15rem, 6vw, 1.625rem); letter-spacing: 0.01em;
}
.vote-vouch {
  background: radial-gradient(ellipse at 40% 15%, #3c5196, #27386b 65%); color: #fff8ea;
  box-shadow: 0 6px 0 #101a3c, 0 6px 0 3px #161b33;
}
.vote:active, .vote.is-mine { transform: translateY(5px); }
.vote-bookshit:active, .vote-bookshit.is-mine { box-shadow: 0 1px 0 #8a1f18, 0 1px 0 3px #161b33; }
.vote-vouch:active, .vote-vouch.is-mine { box-shadow: 0 1px 0 #101a3c, 0 1px 0 3px #161b33; }
.vote.is-mine { text-decoration: underline; text-decoration-thickness: 3px; }
@media (prefers-color-scheme: dark) {
  .vote { border-color: #000; }
  .vote-bookshit { background: radial-gradient(ellipse at 40% 15%, #ff8c6a, #e2703a 65%); color: #1a0e06; box-shadow: 0 6px 0 #8d4019, 0 6px 0 3px #000; }
  .vote-vouch { background: radial-gradient(ellipse at 40% 15%, #4f7d58, #2f5d3a 65%); box-shadow: 0 6px 0 #173220, 0 6px 0 3px #000; }
  .vote-bookshit:active, .vote-bookshit.is-mine { box-shadow: 0 1px 0 #8d4019, 0 1px 0 3px #000; }
  .vote-vouch:active, .vote-vouch.is-mine { box-shadow: 0 1px 0 #173220, 0 1px 0 3px #000; }
}
.vote-status { margin: 0 0 16px; font: 0.875rem/1.4 var(--font-type); color: var(--ink-soft); }
.commissioner-box { margin-top: 18px; padding: 10px 12px; border: 2px dashed var(--accent-2); }
.commissioner-box h3 { margin-bottom: 6px; }

/* The chewing screen. A page goes in, crumbs come out, the meta refresh checks on it. */
.processing { display: grid; justify-items: center; gap: 12px; padding: 24px 0; text-align: center; }
.processing-stage {
  --chomper-size: 150px;
  --chomp-speed: 380ms;
  position: relative; width: 280px; max-width: 100%; height: 190px;
}
.processing-stage .chomper { position: absolute; left: 20px; top: 20px; z-index: 1; }
.processing-page {
  position: absolute; left: 118px; top: 74px; width: 150px; height: 64px;
  background:
    repeating-linear-gradient(transparent 0 7px, var(--ink-soft) 7px 8px) 8px 8px / 100% 100% no-repeat,
    var(--card);
  box-shadow: inset 0 0 0 2px var(--ink);
  transform-origin: 0 50%;
  animation: feed-page 2s linear infinite;
}
@keyframes feed-page {
  from { transform: translateX(60px) scaleX(0.7); }
  to { transform: translateX(-10px) scaleX(0.25); }
}
.processing-crumb {
  position: absolute; left: 128px; top: 118px; width: 7px; height: 7px;
  background: var(--card); box-shadow: 0 0 0 1.5px var(--ink);
  animation: crumb-fall 1000ms ease-in infinite;
}
.processing-crumb:nth-of-type(2n) { left: 148px; animation-delay: -330ms; width: 5px; height: 5px; }
.processing-crumb:nth-of-type(3n) { left: 112px; animation-delay: -660ms; transform: rotate(30deg); }
@keyframes crumb-fall {
  from { translate: 0 0; opacity: 1; }
  to { translate: 12px 62px; rotate: 200deg; opacity: 0; }
}
.processing-line { max-width: 28em; margin: 0; font: 1.125rem/1.35 var(--font-scrawl); color: var(--accent-text); min-height: 3em; }
.processing-note { font: 0.8125rem/1.3 var(--font-type); color: var(--ink-soft); margin: 0; }

/* 15 ─── feed and reactions ─────────────────────────────────────────────────── */

.feed { list-style: none; margin: 0 0 22px; padding: 0; background: var(--card); box-shadow: inset 0 0 0 1px var(--rule); }
.feed-item {
  --chomper-size: 44px;
  display: grid; grid-template-columns: 44px 1fr; gap: 0 10px;
  padding: 12px 12px 10px;
  border-bottom: 1px solid var(--blue-rule);
  scroll-margin-top: 12px;
}
.feed-item:last-child { border-bottom: 0; }
.feed-item:target { background: var(--card-2); box-shadow: inset 5px 0 0 var(--gold); }
.feed-item .chomper { grid-row: span 3; }
.feed-item .jaw { animation-play-state: paused; }
.feed-item:hover .jaw, .feed-item:target .jaw { animation-play-state: running; }
.feed-line { margin: 0; font: 0.9375rem/1.35 var(--font-type); }
.feed-line a { font-weight: 700; padding-block: 12px; }
.feed-when { display: block; font: 0.75rem/1.4 var(--font-mono); color: var(--ink-soft); }
.feed-roast { margin: 4px 0 0; font: 1.0625rem/1.25 var(--font-scrawl); color: var(--accent-text); }
.feed-body { grid-column: 2; margin: 4px 0 0; }
.feed-item .reactions { grid-column: 2; }

.feed-bust { background: color-mix(in srgb, var(--accent) 9%, var(--card)); }
.feed-bust .feed-line::before { content: "BUSTED "; color: var(--accent-text); font-weight: 700; letter-spacing: 0.04em; }
.feed-finish { background: color-mix(in srgb, var(--gold) 16%, var(--card)); }
.feed-crown { background: color-mix(in srgb, var(--gold) 30%, var(--card)); }
.feed-item_used .feed-line, .feed-item_blocked .feed-line { font-style: italic; }
.feed-join .feed-line { color: var(--ink-soft); }
/* Trash talk is a speech bubble. Everything else is a record. */
.feed-trash_talk .feed-body {
  position: relative; justify-self: start; padding: 6px 10px; max-width: 100%;
  background: var(--card-2); border: 2px solid var(--ink); border-radius: 10px;
  font: 1.0625rem/1.25 var(--font-scrawl);
}
.feed-trash_talk .feed-body::before {
  content: ""; position: absolute; left: -9px; top: 10px; width: 12px; height: 12px;
  background: var(--card-2); border-left: 2px solid var(--ink); border-bottom: 2px solid var(--ink);
  transform: rotate(45deg);
}

.reactions { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 0; }
.reactions form { margin: 0; }
.reaction {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-width: var(--touch); min-height: var(--touch); padding: 2px 8px;
  background: transparent; color: var(--ink); cursor: pointer;
  border: 1.5px solid var(--rule); border-radius: 22px;
  font: 700 0.875rem/1 var(--font-mono);
}
.reaction:hover { border-color: var(--ink); }
.reaction:active { transform: scale(0.9); }
.reaction.is-mine { background: var(--gold); color: var(--gold-ink); border-color: var(--gold-ink); }
.reaction-emoji { font-size: 1.125rem; line-height: 1; font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; }

.trash-form { display: grid; grid-template-columns: 1fr auto; gap: 8px; margin: 0 0 12px; }
.trash-form label { grid-column: 1 / -1; }
.trash-form .field-hint { grid-column: 1 / -1; }

/* 16 ─── items and popover ──────────────────────────────────────────────────── */

.bag { display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 8px; list-style: none; margin: 0 0 16px; padding: 0; }
.item-tile {
  display: grid; justify-items: center; align-content: start; gap: 2px;
  min-height: 92px; padding: 8px 4px; text-align: center;
  background: var(--card); box-shadow: inset 0 0 0 1px var(--rule);
  font: 700 0.8125rem/1.15 var(--font-type);
}
.item-tile small { font-weight: 400; color: var(--ink-soft); }
.item-emoji { font-size: 1.75rem; line-height: 1.2; font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; }
.item-attack { box-shadow: inset 0 0 0 1px var(--rule), inset 0 4px 0 #c8362b; }
.item-self { box-shadow: inset 0 0 0 1px var(--rule), inset 0 4px 0 #3a86c8; }
.bag-empty { font: 0.875rem/1.35 var(--font-type); color: var(--ink-soft); }

/* A drawer sliding up from the bottom. Hidden by the browser until opened; do not set
   display here, or it stops being hidden. */
.item-picker {
  position: fixed; inset: auto 0 0; width: min(100%, 30rem); max-height: 80dvh; margin: 0 auto;
  padding: 14px 16px calc(16px + env(safe-area-inset-bottom)); overflow-y: auto;
  background: var(--card); color: var(--ink);
  border: 0; border-top: 6px solid var(--accent); border-radius: 12px 12px 0 0;
  box-shadow: 0 -8px 30px rgb(0 0 0 / 0.35);
}
.item-picker:popover-open { animation: drawer-up 180ms cubic-bezier(0.2, 0.8, 0.3, 1) both; }
.item-picker::backdrop { background: rgb(8 12 28 / 0.6); }
@keyframes drawer-up { from { transform: translateY(100%); } }
@supports not selector(:popover-open) {
  .item-picker { position: static; margin: 10px 0; border-radius: 0; box-shadow: none; }
}
.item-picker-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 10px; }
.item-picker-head h2 { margin: 0; font-size: 1.25rem; }
.item-picker-close {
  flex: none; width: var(--touch); height: var(--touch);
  background: transparent; color: var(--ink); cursor: pointer;
  border: 2px solid var(--ink); border-radius: 50%;
  font: 700 1.125rem/1 var(--font-type);
}
.item-options { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.item-options form { margin: 0; }
.item-option {
  display: grid; grid-template-columns: 44px 1fr; align-items: center; gap: 2px 10px; width: 100%;
  min-height: 60px; padding: 8px 12px; text-align: left; cursor: pointer;
  background: var(--card-2); color: var(--ink);
  border: 2px solid var(--ink); border-radius: 3px; box-shadow: var(--hard);
  font: 700 1rem/1.2 var(--font-type);
}
.item-option:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }
.item-option small { grid-column: 2; font-weight: 400; color: var(--ink-soft); }
.item-option .item-emoji { grid-row: span 2; text-align: center; }
.item-option:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }

/* 17 ─── chomper sprites ────────────────────────────────────────────────────── */

.chomper {
  display: block; flex: none; overflow: visible;
  width: var(--chomper-size, 64px); height: var(--chomper-size, 64px);
}

/* The jaw opens slowly and snaps shut, like a stapler with a grudge. */
.chomper .jaw {
  transform: rotate(4deg);
  animation: chomp-jaw var(--chomp-speed, 900ms) infinite;
}
@keyframes chomp-jaw {
  0%, 100% { transform: rotate(3deg); }
  55% { transform: rotate(27deg); animation-timing-function: cubic-bezier(0.9, 0, 1, 0.6); }
  68% { transform: rotate(27deg); animation-timing-function: cubic-bezier(0.9, 0, 1, 0.6); }
  80% { transform: rotate(2deg); }
}
.chomper .jaw-lid {
  transform: rotate(-5deg);
  animation-name: chomp-lid;
}
@keyframes chomp-lid {
  0%, 100% { transform: rotate(-4deg); }
  55% { transform: rotate(-23deg); animation-timing-function: cubic-bezier(0.9, 0, 1, 0.6); }
  68% { transform: rotate(-23deg); animation-timing-function: cubic-bezier(0.9, 0, 1, 0.6); }
  80% { transform: rotate(-2deg); }
}
.chomper.is-still .jaw, .is-still .chomper .jaw { animation: none; transform: rotate(16deg); }
.chomper.is-still .jaw-lid, .is-still .chomper .jaw-lid { animation: none; transform: rotate(-15deg); }

.chomper .eye { transform-box: fill-box; transform-origin: center; animation: blink 5.3s infinite; }
@keyframes blink { 0%, 95%, 100% { transform: scaleY(1); } 97% { transform: scaleY(0.1); } }

.chomper .sway { animation: sway 1.4s ease-in-out infinite alternate; }
@keyframes sway { from { transform: rotate(-5deg); } to { transform: rotate(6deg); } }
.chomper .wiggle { animation: sway 700ms ease-in-out infinite alternate; }
.chomper .loll { animation: loll 900ms ease-in-out infinite alternate; }
@keyframes loll { to { transform: scaleY(1.12) rotate(2deg); } }
.chomper .scuttle { animation: scuttle 260ms steps(2) infinite alternate; }
.chomper .scuttle-b { animation-direction: alternate-reverse; }
@keyframes scuttle { from { transform: translateX(-1.5px); } to { transform: translateX(2px); } }
.chomper .propeller { transform-origin: 0 -17px; animation: propeller 300ms linear infinite; }
@keyframes propeller { 0%, 100% { transform: scaleX(1); } 50% { transform: scaleX(0.15); } }
.chomper .orbit { animation: orbit 7s linear infinite; }
@keyframes orbit { to { transform: rotate(360deg); } }

/* Glow arrives at Devourer and gets worse. */
.chomper { filter: var(--halo); }
.chomper.lvl-4 { filter: var(--halo) drop-shadow(0 0 3px rgb(242 193 78 / 0.8)); }
.chomper.lvl-5 { filter: var(--halo) drop-shadow(0 0 5px rgb(242 193 78 / 0.95)); animation: glow-pulse 2.2s ease-in-out infinite alternate; }
.chomper.lvl-6 { filter: var(--halo) drop-shadow(0 0 8px #ffd24d) drop-shadow(0 0 14px rgb(226 112 58 / 0.8)); animation: glow-pulse 1.2s ease-in-out infinite alternate; }
@keyframes glow-pulse { to { opacity: 0.86; } }
.race-eater .chomper.lvl-6 { filter: var(--halo) drop-shadow(0 0 5px #ffd24d); }

.avatar { --chomper-size: 96px; display: inline-block; }
.avatar-sm { --chomper-size: 40px; }
.avatar-lg { --chomper-size: 160px; }

/* 18 ─── customizer ─────────────────────────────────────────────────────────── */

.customizer { display: grid; gap: 14px; }
.customizer-stage { display: none; }
@supports selector(:has(*)) {
  .customizer-stage[hidden] {
    display: grid; justify-items: center; gap: 2px;
    position: sticky; top: 6px; z-index: 5;
    padding: 10px 10px 8px; text-align: center;
    background: var(--cab); color: var(--cab-ink);
    border: 3px solid var(--cab-edge);
    box-shadow: 4px 4px 0 var(--accent);
    --halo: drop-shadow(0 0 1px #fff8ea) drop-shadow(0 0 1px #fff8ea);
  }
}
.customizer-spotlight { --chomper-size: 112px; width: 112px; height: 112px; }
@media (min-width: 48rem) { .customizer-spotlight { --chomper-size: 160px; width: 160px; height: 160px; } }
.customizer-sprite, .customizer-bio { display: none; }
.customizer-caption { margin: 0; min-height: 2.6em; font: 0.875rem/1.3 var(--font-type); color: var(--cab-soft); }
.customizer-caption strong { display: block; font: 900 1.125rem/1.15 var(--font-display); color: var(--gold); }

/* Species: the matching sprite and bio appear. */
.customizer:has(input[name="species"][value="bookworm"]:checked) [data-species="bookworm"],
.customizer:has(input[name="species"][value="paper_goat"]:checked) [data-species="paper_goat"],
.customizer:has(input[name="species"][value="library_shark"]:checked) [data-species="library_shark"],
.customizer:has(input[name="species"][value="mimic_chest"]:checked) [data-species="mimic_chest"],
.customizer:has(input[name="species"][value="page_gremlin"]:checked) [data-species="page_gremlin"],
.customizer:has(input[name="species"][value="silverfish"]:checked) [data-species="silverfish"] { display: block; }

/* Color: every sprite in the customizer inherits it, thumbnails included. */
.customizer { --chomper-color: #c8362b; }
.customizer:has(input[name="color"][value="stamp_red"]:checked) { --chomper-color: #c8362b; }
.customizer:has(input[name="color"][value="inky_navy"]:checked) { --chomper-color: #27386b; }
.customizer:has(input[name="color"][value="lamp_yellow"]:checked) { --chomper-color: #e7b52c; }
.customizer:has(input[name="color"][value="stacks_green"]:checked) { --chomper-color: #3f7d4e; }
.customizer:has(input[name="color"][value="card_cream"]:checked) { --chomper-color: #e8d9b0; }
.customizer:has(input[name="color"][value="due_date_blue"]:checked) { --chomper-color: #3a86c8; }
.customizer:has(input[name="color"][value="bubblegum"]:checked) { --chomper-color: #e77fa8; }
.customizer:has(input[name="color"][value="tangerine"]:checked) { --chomper-color: #e6792b; }

/* Hats: every sprite on the stage carries the whole wardrobe, all hidden but one. */
.customizer-stage .hat { display: none; }
.customizer:has(input[name="hat"][value="beanie"]:checked) .customizer-stage .hat-beanie,
.customizer:has(input[name="hat"][value="glasses"]:checked) .customizer-stage .hat-glasses,
.customizer:has(input[name="hat"][value="wizard"]:checked) .customizer-stage .hat-wizard,
.customizer:has(input[name="hat"][value="top_hat"]:checked) .customizer-stage .hat-top_hat { display: inline; }

.picker { margin: 0; }
.picker-grid { display: grid; gap: 8px; }
.picker-species .picker-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); --chomper-size: 60px; }
.picker-color .picker-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.picker-color .pick-label { font-size: 0.6875rem; overflow-wrap: normal; }
@media (max-width: 359px) { .picker-color .picker-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.picker-hat .picker-grid { grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); }

.pick { position: relative; display: block; cursor: pointer; font-weight: 400; margin: 0; }
.pick input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.pick-face {
  display: grid; justify-items: center; align-content: center; gap: 4px; height: 100%; min-height: var(--touch);
  padding: 8px 4px; text-align: center;
  background: var(--card); border: 2px solid var(--rule); border-radius: 3px;
}
.pick-label { font: 700 0.75rem/1.15 var(--font-type); }
.pick-lock { font: 0.6875rem/1.15 var(--font-type); color: var(--ink-soft); }
.pick input:checked + .pick-face {
  border-color: var(--ink); background: var(--gold); color: var(--gold-ink);
  box-shadow: var(--hard); transform: translate(-1px, -1px) rotate(-1deg);
}
.pick input:focus-visible + .pick-face { outline: 3px solid var(--focus); outline-offset: 2px; }
.pick.is-locked { cursor: not-allowed; }
.pick.is-locked input { cursor: not-allowed; }
.pick.is-locked .pick-face { opacity: 0.6; border-style: dashed; }
.swatch {
  width: 34px; height: 34px; background: var(--swatch);
  border: 2px solid #161b33; border-radius: 50%;
}
.hat-thumb { display: block; width: 40px; height: 36px; overflow: visible; }

/* 19 ─── level ladder ───────────────────────────────────────────────────────── */

.level-ladder {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 8px;
  list-style: none; margin: 0 0 18px; padding: 0;
  --chomper-size: 64px;
}
.level-rung {
  display: grid; justify-items: center; gap: 2px; padding: 8px 4px; text-align: center;
  background: var(--card-2); box-shadow: inset 0 0 0 1px var(--rule);
}
.level-rung .jaw { animation-play-state: paused; }
.level-rung:hover .jaw, .level-rung.is-current .jaw { animation-play-state: running; }
.level-name { font: 900 0.875rem/1.1 var(--font-display); }
.level-bites { font: 0.6875rem/1.2 var(--font-mono); color: var(--ink-soft); }
.level-rung.is-current { background: var(--gold); color: var(--gold-ink); box-shadow: var(--hard); }
.level-rung.is-current .level-bites { color: inherit; }

/* 20 ─── confetti ───────────────────────────────────────────────────────────── */

.confetti { position: fixed; inset: 0; z-index: 50; overflow: hidden; pointer-events: none; }
.confetti .bit {
  position: absolute; top: -24px; left: var(--x); display: block;
  width: var(--size); height: calc(var(--size) * 0.66);
  animation: confetti-fall var(--fall) linear var(--delay) both;
}
@keyframes confetti-fall {
  from { transform: translate(0, 0) rotate(0); opacity: 1; }
  85% { opacity: 1; }
  to { transform: translate(var(--drift), 108vh) rotate(var(--spin)); opacity: 0; }
}
.confetti .c0 { background: #c8362b; }
.confetti .c1 { background: #27386b; }
.confetti .c2 { background: #f2c14e; }
.confetti .c3 { background: #fff8ea; box-shadow: 0 0 0 1px #161b33; }
.confetti .c4 { background: #3f7d4e; }
.confetti .c5 { background: #e77fa8; }
/* Paper chads and a stray date slip. */
.confetti .s1 { height: var(--size); border-radius: 50%; }
.confetti .s2 { height: calc(var(--size) * 1.5); clip-path: polygon(0 0, 100% 0, 100% 80%, 75% 100%, 50% 80%, 25% 100%, 0 80%); }

/* 21 ─── profile ────────────────────────────────────────────────────────────── */

.profile-head {
  --chomper-size: 128px;
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 4px 14px;
  margin: 0 0 18px;
}
.profile-head h1 { margin: 0 0 4px; }
.profile-badges { display: flex; flex-wrap: wrap; gap: 4px; }

.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(136px, 1fr)); gap: 8px;
  margin: 0 0 18px; padding: 0;
}
.stat { margin: 0; padding: 8px 12px; background: var(--card); box-shadow: inset 0 0 0 1px var(--rule); }
.stat dt { font: 700 0.6875rem/1.3 var(--font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); }
.stat dd { margin: 0; font: 700 1.5rem/1.15 var(--font-mono); font-variant-numeric: tabular-nums; color: var(--accent-text); }
.stat small { display: block; font: 0.75rem/1.25 var(--font-type); color: var(--ink-soft); }
.stat-shame dd { color: #c8362b; }

.comparison {
  margin: 0 0 18px; padding: 4px 0;
  font: 1.5rem/1.15 var(--font-scrawl); color: var(--accent-text);
  transform: rotate(-1deg);
}

/* Trophy shelf: finished books as spines, width by page count (--pages). */
.shelf {
  display: flex; align-items: flex-end; flex-wrap: wrap; gap: 14px 2px;
  list-style: none; margin: 0 0 20px; padding: 0 6px 8px;
  border-bottom: 10px solid #5a3a2a;
  box-shadow: 0 4px 0 -1px rgb(0 0 0 / 0.3);
}
.spine {
  display: flex; align-items: center; justify-content: center;
  width: clamp(44px, calc(var(--pages, 300) * 0.11px), 72px);
  height: clamp(130px, calc(120px + var(--pages, 300) * 0.05px), 170px);
  padding: 6px 2px; overflow: hidden; text-decoration: none;
  writing-mode: vertical-rl;
  background: var(--spine, #27386b); color: var(--spine-ink, #fff8ea);
  box-shadow: inset 3px 0 0 rgb(255 255 255 / 0.18), inset -3px 0 0 rgb(0 0 0 / 0.25);
  border-top: 5px double currentColor;
  font: 900 0.8125rem/1.05 var(--font-display);
}
.spine:hover { color: var(--spine-ink, #fff8ea); filter: brightness(1.12); }
.spine:nth-child(6n + 2) { --spine: #8a1f18; --spine-ink: #ffe9c8; }
.spine:nth-child(6n + 3) { --spine: #2f5d3a; }
.spine:nth-child(6n + 4) { --spine: #e7b52c; --spine-ink: #1d2747; }
.spine:nth-child(6n + 5) { --spine: #5a3a2a; --spine-ink: #f2d9a8; }
.spine:nth-child(6n) { --spine: #1f6f8b; }

.reading-row { display: grid; grid-template-columns: auto 1fr; gap: 10px 12px; padding: 12px 0; border-bottom: 1px solid var(--blue-rule); --cover-w: 56px; }
.reading-row:last-child { border-bottom: 0; }

/* The catalog drawers on /home: one drawer front per league, brass and all. */
.drawers { display: grid; gap: 10px; list-style: none; margin: 0 0 20px; padding: 0; }
.drawer-face {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px 12px; min-height: 84px;
  padding: 10px 14px; text-decoration: none;
  background: var(--drawer); color: var(--ink);
  border: 2px solid var(--ink); border-bottom-width: 5px; border-radius: 3px;
}
.drawer-face:hover { color: var(--ink); background: var(--card-2); }
.drawer-label {
  display: block; padding: 4px 10px;
  background: var(--card);
  border: 3px solid #b08a3a; outline: 1px solid #6e5420; outline-offset: 0;
  font: 900 1.1875rem/1.15 var(--font-display);
}
.drawer-sub { display: block; font: 0.8125rem/1.3 var(--font-type); color: var(--ink-soft); }
.drawer-pull {
  width: 36px; height: 20px;
  border: 3px solid #b08a3a; border-top-width: 6px; border-radius: 3px 3px 12px 12px;
  background: transparent;
}
@media (prefers-color-scheme: dark) {
  .drawer-face { background: var(--card); }
  .drawer-label { background: var(--card-2); }
}

/* 22 ─── hall and awards ────────────────────────────────────────────────────── */

.hall { list-style: none; margin: 0 0 20px; padding: 0; }
.hall-row {
  --chomper-size: 56px;
  display: grid; grid-template-columns: auto 56px 1fr auto; align-items: center; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid var(--blue-rule);
}
.hall-row .jaw { animation-play-state: paused; }
.hall-name { font: 900 1.0625rem/1.15 var(--font-display); }
.hall-note { display: block; font: 0.8125rem/1.25 var(--font-type); color: var(--ink-soft); }

.awards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); margin: 0 0 20px; padding: 0; list-style: none; }
.award {
  --chomper-size: 56px;
  position: relative; display: grid; justify-items: center; gap: 2px; padding: 12px 8px 14px; text-align: center;
  background: var(--card); box-shadow: inset 0 0 0 1px var(--rule), inset 0 0 0 4px var(--card), inset 0 0 0 5px var(--accent);
}
.award-title { margin: 0; font: 900 1.125rem/1.1 var(--font-display); color: var(--accent-text); }
.award-winner { font: 700 0.9375rem/1.2 var(--font-type); }
.award-value { font: 0.75rem/1.25 var(--font-mono); color: var(--ink-soft); }
.award-blurb { font: 0.8125rem/1.25 var(--font-type); color: var(--ink-soft); }

/* 23 ─── settings ───────────────────────────────────────────────────────────── */

/* A coat-check ticket holding a link. Without JS there is no copy button: tap and hold. */
.ticket {
  display: grid; gap: 6px; margin: 0 0 16px; padding: 12px 14px;
  background: var(--card-2);
  border: 2px dashed var(--ink);
}
.ticket-link {
  display: block; padding: 8px; overflow-wrap: anywhere; user-select: all; -webkit-user-select: all;
  background: var(--card);
  font: 700 0.875rem/1.35 var(--font-mono);
}
.member-list { list-style: none; margin: 0 0 16px; padding: 0; }
.member {
  --chomper-size: 44px;
  display: grid; grid-template-columns: 44px 1fr auto; align-items: center; gap: 4px 10px;
  padding: 8px 0; border-bottom: 1px solid var(--blue-rule);
}
.member .jaw { animation-play-state: paused; }
.member-actions { grid-column: 2 / -1; display: flex; flex-wrap: wrap; gap: 8px; }
.member-actions form { margin: 0; }
.danger-zone {
  margin: 24px 0 0; padding: 12px 14px;
  border: 3px solid transparent;
  border-image: repeating-linear-gradient(-45deg, #f2c14e 0 10px, #161b33 10px 20px) 3;
}

/* 24 ─── landing ────────────────────────────────────────────────────────────── */

.hero { position: relative; margin: 0 0 24px; padding: 8px 0 0; }
.hero-title {
  margin: 0 0 12px;
  font: 900 clamp(2.6rem, 14vw, 5rem)/0.92 var(--font-display);
  letter-spacing: -0.03em; text-transform: uppercase;
  color: var(--accent);
  text-shadow: 3px 3px 0 var(--ink);
}
@media (prefers-color-scheme: dark) { .hero-title { text-shadow: 3px 3px 0 #7a2a12; } }
/* Room for the wave, so wrapped wavy lines don't land on each other. */
.hero-title .wavy-word { display: inline-block; padding-block: 0.14em 0.06em; }
.hero-sub { max-width: 30em; font-size: 1.1875rem; }
.cast {
  --chomper-size: 96px;
  display: flex; justify-content: center; flex-wrap: wrap; gap: 4px 10px;
  list-style: none; margin: 0 0 24px; padding: 12px 8px;
  background: var(--cab); border: 4px solid var(--cab-edge); box-shadow: 5px 5px 0 var(--accent);
  --halo: drop-shadow(0 0 1px #fff8ea) drop-shadow(0 0 1px #fff8ea);
}
.cast li:nth-child(2n) .jaw { --chomp-speed: 760ms; }
.cast li:nth-child(3n) .jaw { --chomp-speed: 1140ms; }
.pitch { display: grid; gap: 10px; margin: 0 0 24px; padding: 0; list-style: none; counter-reset: pitch; }
.pitch li { display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: baseline; counter-increment: pitch; }
.pitch li::before {
  content: counter(pitch);
  display: inline-grid; place-items: center; width: 34px; height: 34px;
  border: 2px solid var(--accent); border-radius: 50%; color: var(--accent);
  font: 900 1rem var(--font-display);
}
.invite-only { font-family: var(--font-scrawl); font-size: 1.25rem; color: var(--accent-text); }

/* 25 ─── rules ──────────────────────────────────────────────────────────────── */

.rules-section { margin: 0 0 24px; }
.rules-section h2 { border-bottom: 2px solid var(--accent); padding-bottom: 4px; }
.table-scroll { overflow-x: auto; margin: 0 0 18px; }
.item-table { width: 100%; border-collapse: collapse; background: var(--card); font: 0.9375rem/1.3 var(--font-type); box-shadow: inset 0 0 0 1px var(--rule); }
.item-table th { text-align: left; padding: 6px 10px; border-bottom: 2px solid var(--accent); font: 700 0.75rem/1.2 var(--font-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-soft); }
.item-table td { padding: 8px 10px; border-bottom: 1px solid var(--blue-rule); vertical-align: top; }
.item-table tr:last-child td { border-bottom: 0; }

/* details as a pulled-out drawer. */
.drawer { margin: 0 0 10px; background: var(--card); box-shadow: inset 0 0 0 1px var(--rule); }
.drawer > summary {
  display: flex; align-items: center; min-height: var(--touch); padding: 8px 12px;
  cursor: pointer; list-style: none;
  font: 900 1.0625rem/1.2 var(--font-display);
}
.drawer > summary::-webkit-details-marker { display: none; }
.drawer > summary::after { content: "+"; margin-left: auto; font: 700 1.375rem/1 var(--font-mono); color: var(--accent); }
.drawer[open] > summary::after { content: "\2212"; }
.drawer-body { padding: 0 12px 12px; }

/* 26 ─── empty and error ────────────────────────────────────────────────────── */

.empty {
  --chomper-size: 96px;
  display: grid; justify-items: center; gap: 6px; padding: 24px 12px; margin: 0 0 18px; text-align: center;
  border: 2px dashed var(--rule);
  font: 1rem/1.35 var(--font-type);
}
.empty strong { font: 900 1.25rem/1.15 var(--font-display); }
.error-card h1 { color: var(--accent); }
.error-card { padding-top: 26px; }
.error-detail { font: 700 1rem/1.4 var(--font-type); }

/* 26½ ─── more things you don't need JS for ─────────────────────────────────── */

html { scrollbar-gutter: stable; }
h1, h2, h3 { text-wrap: balance; }
p, li { text-wrap: pretty; }

/* Typing on a phone: the nav ducks under the keyboard instead of riding on top of it. */
.bottom-nav { transition: translate 160ms ease-out; }
body:has(:is(input:not([type="file"], [type="radio"], [type="checkbox"], [type="hidden"]), textarea, select):focus) .bottom-nav {
  translate: 0 110%;
}

/* Wavy text: real trigonometry. --wave goes round once, and each letter sits on the
   sine wave at its own offset. Needs @property to animate; without it, it just sits there
   looking wobbly, which is also fine. */
@property --wave { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@keyframes wave-along { to { --wave: 360deg; } }
.wavy { animation: wave-along 2.4s linear infinite; }
.wavy-word { white-space: nowrap; }
.wavy-word > span {
  display: inline-block;
  translate: 0 calc(sin(var(--wave) + var(--i) * 32deg) * 0.14em);
  rotate: calc(cos(var(--wave) + var(--i) * 32deg) * 5deg);
}

/* Things that arrive slam in from nothing. @starting-style is the "before" frame, so
   there is no keyframe block and no script toggling a class. Pages that reload themselves
   every minute don't do it, or the crown would bounce forever. */
.flash, .spoiler-banner, .crown-banner {
  transition: opacity 220ms ease-out, translate 340ms cubic-bezier(0.2, 1.6, 0.4, 1), rotate 340ms cubic-bezier(0.2, 1.6, 0.4, 1);
}
.feed-item { transition: opacity 260ms ease-out, translate 260ms ease-out; }
.feed-item:nth-child(2) { transition-delay: 40ms; }
.feed-item:nth-child(3) { transition-delay: 80ms; }
.feed-item:nth-child(4) { transition-delay: 120ms; }
.feed-item:nth-child(5) { transition-delay: 160ms; }
.feed-item:nth-child(n + 6) { transition-delay: 200ms; }
@starting-style {
  html:not(:has(meta[http-equiv="refresh"])) :is(.flash, .spoiler-banner, .crown-banner) {
    opacity: 0; translate: 0 -16px; rotate: -2deg;
  }
  html:not(:has(meta[http-equiv="refresh"])) .feed-item { opacity: 0; translate: -14px 0; }
}

/* Complaints wait until you've actually typed something. */
input:user-invalid, select:user-invalid, textarea:user-invalid {
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent) 7%, var(--card-2));
}
.field:has(:user-invalid) .field-hint { color: var(--accent-text); font-weight: 700; }
.field:has(:user-invalid) .field-hint::before { content: "Spit that out and try again. "; }

/* The password field's verdict flips the moment it's long enough. */
.teeth-check { font: 700 0.875rem/1.35 var(--font-type); }
.teeth-dull { color: var(--ink-soft); }
.teeth-sharp { display: none; color: var(--accent-2); }
.field:has(input[type="password"]:valid) .teeth-dull { display: none; }
.field:has(input[type="password"]:valid) .teeth-sharp { display: inline-block; animation: bite-in 180ms steps(4) both; }

/* Confessions: <details name="cheats">, so opening one shuts the rest. */
.confession > summary::before { content: "\1F92B"; margin-right: 10px; }
.confession[open] { box-shadow: inset 6px 0 0 var(--accent), inset 0 0 0 1px var(--rule); }

/* Drawers glide open where the browser can animate to height: auto. */
@supports selector(::details-content) {
  :root { interpolate-size: allow-keywords; }
  .drawer::details-content {
    block-size: 0; overflow: clip;
    transition: block-size 220ms ease, content-visibility 220ms allow-discrete;
  }
  .drawer[open]::details-content { block-size: auto; }
}

/* 27 ─── reduced motion ─────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }

  /* Sprites hold a mid-chomp pose instead of snapping to a last keyframe. */
  .chomper .jaw { animation: none !important; transform: rotate(16deg); }
  .chomper .jaw-lid { animation: none !important; transform: rotate(-15deg); }
  .chomper .eye, .chomper .sway, .chomper .wiggle, .chomper .loll,
  .chomper .scuttle, .chomper .propeller, .chomper .orbit,
  .chomper.lvl-5, .chomper.lvl-6 { animation: none !important; }

  .race-eater, .verdict, .topbar::after { animation: none !important; }
  .processing-page { animation: none !important; transform: translateX(10px) scaleX(0.5); }
  .processing-crumb { animation: none !important; opacity: 0.8; translate: 0 22px; }
  .confetti { display: none; }
}
