/* Pangramist production styles, stage 1. Tokens and components carried
   from render round A (prototype/render-a/styles.css) with the fixed mockup
   stages replaced by fluid rules; no per-page restyling beyond this file. */
/* Pangramist render round A: shared styles.
   Tokens are DESIGN-V2 Direction A, exactly as decided:
   paper #FAF5EB, ink #22301F, cranberry #9E2B25, gold #B98A1E (trim only),
   tile face #FFFDF6, tray #F1E8D6.
   Functional states (tools only, always with a text label):
   known #386334, present #8A5A0B, absent #6E675E.
   Supporting tokens from DESIGN.md: ink-soft #55604F (secondary text),
   tile edge #D8CBAF (tile shadow tone only). */

@font-face {
  font-family: "Young Serif";
  src: url("fonts/young-serif-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Familjen Grotesk";
  src: url("fonts/familjen-grotesk-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Familjen Grotesk";
  src: url("fonts/familjen-grotesk-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Familjen Grotesk";
  src: url("fonts/familjen-grotesk-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Mansalva";
  src: url("fonts/mansalva-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

:root {
  --paper: #FAF5EB;
  --tray: #F1E8D6;
  --ink: #22301F;
  --ink-soft: #55604F;
  --cranberry: #9E2B25;
  --gold: #B98A1E;
  --tile: #FFFDF6;
  --tile-edge: #D8CBAF;
  --known: #386334;
  --present: #8A5A0B;
  --absent: #6E675E;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  font-family: "Familjen Grotesk", sans-serif;
  color: var(--ink);
}

/* Production stage: fluid, paper edge to edge under 1280, centred above. */
.stage {
  background: var(--paper);
  margin: 0 auto;
  min-height: 100vh;
  position: relative;
  max-width: 1280px;
}

/* Faint paper grain, kept off the working area by staying at page level. */
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: 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'/%3E%3CfeColorMatrix values='0 0 0 0 0.13 0 0 0 0 0.19 0 0 0 0 0.12 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

.page { position: relative; padding: 20px; }
@media (min-width: 900px) { .page { padding: 32px 52px; } }

h1, h2, h3 {
  font-family: "Young Serif", serif;
  font-weight: 400;
  line-height: 1.1;
  margin: 0;
}

a { color: var(--cranberry); }

/* Header and folio lines */
.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  border-bottom: 2px solid var(--ink);
  padding-bottom: 10px;
}
.wordmark {
  font-family: "Young Serif", serif;
  font-size: 30px;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
}
.nav { display: flex; gap: 18px; font-size: 14px; }
.nav a { color: var(--ink); text-decoration: none; }
.nav a[aria-current] { color: var(--cranberry); font-weight: 500; }
@media (max-width: 560px) { .nav { gap: 12px; font-size: 13px; } }

.folio {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 13px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--gold);
  padding: 8px 0;
}
.folio strong { color: var(--ink); font-weight: 500; }
.streak-square {
  display: inline-block;
  width: 10px; height: 10px;
  background: var(--cranberry);
  border-radius: 2px;
  vertical-align: -1px;
  margin-right: 5px;
}

/* The rack: one tile component everywhere */
.tray {
  background: var(--tray);
  border-radius: 12px;
  padding: 16px;
  box-shadow: inset 0 2px 5px rgba(34, 48, 31, 0.14);
}
.tiles { display: flex; gap: 6px; flex-wrap: wrap; }
.tile {
  width: 40px; height: 48px;
  background: var(--tile);
  border-radius: 6px;
  box-shadow: 0 2px 0 var(--tile-edge), 0 3px 4px rgba(34, 48, 31, 0.18);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Young Serif", serif;
  font-size: 23px;
  color: var(--ink);
}
@media (min-width: 900px) { .tile { width: 52px; height: 60px; font-size: 30px; } }
/* Build rule from render round A: tiles step down under a 380px viewport
   so a seven-tile rack holds one row at 360. */
@media (max-width: 380px) { .tile { width: 36px; height: 44px; font-size: 21px; } .tiles { gap: 5px; } }
.tile .value {
  position: absolute;
  right: 4px; bottom: 3px;
  font-family: "Familjen Grotesk", sans-serif;
  font-size: 10px;
  color: var(--ink-soft);
}
.tile.blank {
  background: transparent;
  border: 2px dotted var(--ink-soft);
  box-shadow: none;
}
.tile.state-known   { background: var(--known);   color: var(--paper); }
.tile.state-present { background: var(--present); color: var(--paper); }
.tile.state-absent  { background: var(--absent);  color: var(--paper); }
.tile.state-known .value,
.tile.state-present .value,
.tile.state-absent .value { color: var(--paper); }

.state-cell { text-align: center; }
.state-label { font-size: 12px; margin-top: 6px; color: var(--ink); }
.state-symbol { font-size: 13px; font-weight: 700; }

/* Solver controls */
.rack-input {
  width: 100%;
  font-family: "Familjen Grotesk", sans-serif;
  font-size: 20px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--tile);
  border: 1px solid var(--tile-edge);
  border-radius: 8px;
  padding: 12px 14px;
  margin-top: 14px;
}
.solve-btn {
  background: var(--cranberry);
  color: var(--paper);
  font-family: "Familjen Grotesk", sans-serif;
  font-size: 18px;
  font-weight: 500;
  border: none;
  border-radius: 8px;
  min-height: 52px;
  padding: 0 28px;
  box-shadow: 0 2px 0 #6E1D18;
  cursor: pointer;
  margin-top: 14px;
}
@media (max-width: 560px) { .solve-btn { width: 100%; } }
.list-line { font-size: 13px; color: var(--ink-soft); margin-top: 10px; }

/* Results as an index */
.summary-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 22px;
  font-size: 15px;
  border-top: 2px solid var(--ink);
  border-bottom: 1px solid var(--gold);
  padding: 10px 0;
  margin-top: 24px;
}
.summary-strip strong { font-weight: 700; font-variant-numeric: tabular-nums; }
.group-header {
  position: sticky;
  top: 0;
  background: var(--paper);
  font-size: 14px;
  font-weight: 700;
  padding: 14px 0 6px;
  border-bottom: 1px solid var(--tile-edge);
  z-index: 2;
}
.group-header .count { color: var(--ink-soft); font-weight: 400; }
.result-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 5px 0;
  border-bottom: 1px solid rgba(216, 203, 175, 0.55);
  font-size: 18px;
}
.result-row .word { font-weight: 500; letter-spacing: 0.02em; }
.result-row .tag {
  font-size: 11px;
  color: var(--ink-soft);
  border: 1px solid var(--tile-edge);
  border-radius: 4px;
  padding: 1px 5px;
}
.result-row .score {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  min-width: 2ch;
  text-align: right;
}
.result-row .blank-note { font-size: 12px; color: var(--ink-soft); }
@media (min-width: 900px) { .results-columns { columns: 2; column-gap: 56px; } .results-columns .group { break-inside: avoid; } }

/* Margin note: one per page, Mansalva, small rotation */
.margin-note {
  font-family: "Mansalva", cursive;
  font-size: 19px;
  color: var(--cranberry);
  transform: rotate(-1.5deg);
  display: inline-block;
}

/* Spec block: provenance printed like a dictionary's own furniture */
.spec-block {
  border: 1px solid var(--gold);
  padding: 12px 14px;
  font-size: 13px;
  line-height: 1.55;
  margin-top: 28px;
}
.spec-block .spec-title {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 11px;
  margin-bottom: 4px;
}

/* Daily game pieces */
.progress-line { font-size: 15px; margin-top: 16px; font-variant-numeric: tabular-nums; }
.share-box {
  border: 2px solid var(--ink);
  border-radius: 12px;
  padding: 16px;
  margin-top: 20px;
  font-size: 15px;
  line-height: 1.6;
}
.share-squares { font-size: 18px; letter-spacing: 3px; }
.share-squares .filled { color: var(--cranberry); }
.share-squares .open { color: var(--tile-edge); }
.tool-list { list-style: none; padding: 0; margin: 0; font-size: 16px; }
.tool-list li { padding: 9px 0; border-bottom: 1px solid var(--tile-edge); }
.tool-list a { color: var(--ink); text-decoration: none; font-weight: 500; }
.tool-list .go { color: var(--cranberry); }
.section-title { font-size: 22px; margin: 30px 0 6px; }
.ad-slot {
  border: 1px dashed var(--tile-edge);
  color: var(--ink-soft);
  font-size: 12px;
  text-align: center;
  padding: 18px 0;
  margin-top: 32px;
}

/* Stage 2: generated pages, tool forms, boards, footer */
.site-footer { margin-top: 36px; border-top: 2px solid var(--ink); padding-top: 14px; }
.footer-nav { display: flex; flex-wrap: wrap; gap: 8px 16px; font-size: 14px; margin-bottom: 10px; }
.footer-nav a { color: var(--ink); }
.fine-print { font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }
.field { margin: 0 0 12px; }
.field label { display: block; font-weight: 500; margin-bottom: 6px; }
.field-row { display: flex; gap: 14px; flex-wrap: wrap; }
.field-row .field { flex: 1 1 150px; }
.text-input { width: 100%; padding: 10px 12px; font: inherit; background: var(--tile); border: 1.5px solid var(--tile-edge); border-radius: 10px; color: var(--ink); }
.text-input.field-error { border-color: var(--cranberry); background: #f7e8e2; }
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0; }
.chip { font: inherit; font-size: 14px; padding: 7px 12px; border-radius: 999px; border: 1.5px solid var(--tile-edge); background: var(--tile); color: var(--ink); cursor: pointer; }
.chip:hover { border-color: var(--cranberry); }
.word-cloud p { line-height: 2; word-spacing: 0.35em; }
.word-cloud a { color: var(--cranberry); }
.counts-table { border-collapse: collapse; margin: 10px 0 16px; }
.counts-table caption { text-align: left; font-weight: 500; padding-bottom: 6px; }
.counts-table th, .counts-table td { border: 1px solid var(--tile-edge); padding: 5px 12px; text-align: left; font-variant-numeric: tabular-nums; }
.crumbs { font-size: 13.5px; color: var(--ink-soft); margin-top: 14px; }
.crumbs a { color: var(--ink-soft); }
.across-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; }
.across-list a { color: var(--cranberry); }
.tool-rail { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline; margin: 18px 0 4px; font-size: 14.5px; }
.tool-rail a { color: var(--cranberry); }
.guess-row { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0; align-items: flex-start; }
.tile-btn { background: none; border: none; padding: 0; cursor: pointer; display: flex; flex-direction: column; align-items: center; }
.tile-btn .state-label { max-width: 74px; }
.join { color: var(--cranberry); font-weight: 700; text-decoration: underline; }
.def-source { font-size: 13.5px; color: var(--ink-soft); }
.guide-body p { line-height: 1.65; }
.guide-body li { line-height: 1.6; margin-bottom: 5px; }
details { margin: 10px 0; }
summary { cursor: pointer; font-weight: 500; }

/* Stage 2: generated pages, tool forms, boards, footer */
.site-footer { margin-top: 36px; border-top: 2px solid var(--ink); padding-top: 14px; }
.footer-nav { display: flex; flex-wrap: wrap; gap: 8px 16px; font-size: 14px; margin-bottom: 10px; }
.footer-nav a { color: var(--ink); }
.fine-print { font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }
.field { margin: 0 0 12px; }
.field label { display: block; font-weight: 500; margin-bottom: 6px; }
.field-row { display: flex; gap: 14px; flex-wrap: wrap; }
.field-row .field { flex: 1 1 150px; }
.text-input { width: 100%; padding: 10px 12px; font: inherit; background: var(--tile); border: 1.5px solid var(--tile-edge); border-radius: 10px; color: var(--ink); }
.text-input.field-error { border-color: var(--cranberry); background: #f7e8e2; }
.chip-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0; }
.chip { font: inherit; font-size: 14px; padding: 7px 12px; border-radius: 999px; border: 1.5px solid var(--tile-edge); background: var(--tile); color: var(--ink); cursor: pointer; }
.chip:hover { border-color: var(--cranberry); }
.word-cloud p { line-height: 2; word-spacing: 0.35em; }
.word-cloud a { color: var(--cranberry); }
.counts-table { border-collapse: collapse; margin: 10px 0 16px; }
.counts-table caption { text-align: left; font-weight: 500; padding-bottom: 6px; }
.counts-table th, .counts-table td { border: 1px solid var(--tile-edge); padding: 5px 12px; text-align: left; font-variant-numeric: tabular-nums; }
.crumbs { font-size: 13.5px; color: var(--ink-soft); margin-top: 14px; }
.crumbs a { color: var(--ink-soft); }
.across-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; }
.across-list a { color: var(--cranberry); }
.tool-rail { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline; margin: 18px 0 4px; font-size: 14.5px; }
.tool-rail a { color: var(--cranberry); }
.guess-row { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0; align-items: flex-start; }
.tile-btn { background: none; border: none; padding: 0; cursor: pointer; display: flex; flex-direction: column; align-items: center; }
.tile-btn .state-label { max-width: 74px; }
.join { color: var(--cranberry); font-weight: 700; text-decoration: underline; }
.def-source { font-size: 13.5px; color: var(--ink-soft); }
.guide-body p { line-height: 1.65; }
.guide-body li { line-height: 1.6; margin-bottom: 5px; }
details { margin: 10px 0; }
summary { cursor: pointer; font-weight: 500; }

/* Feel pass (2026-11-04): the DESIGN-V2 motion keep list, built at last.
   Settle, flip, group rise, streak fill, tile lift, plus press states, a
   visible focus state, refusal shake, progress fills, and the finish
   moments. Transform and opacity only; every duration sits inside the
   motion budget (the flip is the one allowed exception, as designed).
   The reduced-motion block at the end makes all of it instant. */
@keyframes tile-settle {
  from { opacity: 0; transform: translateY(-7px) scale(1.05); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes tile-flip {
  0% { transform: rotateX(0deg); }
  50% { transform: rotateX(88deg); }
  100% { transform: rotateX(0deg); }
}
@keyframes tile-pop {
  0% { transform: scale(1); }
  40% { transform: scale(1.14); }
  100% { transform: scale(1); }
}
@keyframes tile-lift {
  0% { opacity: 0; transform: translateY(5px) scale(0.94); }
  60% { opacity: 1; transform: translateY(-3px) scale(1.04); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes group-rise {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes gentle-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  45% { transform: translateX(3px); }
  70% { transform: translateX(-2px); }
  88% { transform: translateX(1px); }
}
@keyframes streak-pop {
  0% { transform: scale(0.3); }
  55% { transform: scale(1.5); }
  100% { transform: scale(1); }
}
@keyframes fill-grow { from { width: 0; } }

/* Tiles settle into the tray as they render (racks are rebuilt by
   innerHTML on each keystroke, so the entry animation is the settle),
   staggered a breath apart by position. */
.tray .tile, #d-slots .tile { animation: tile-settle 0.18s ease-out both; }
.tray .tiles > :nth-child(2) .tile, .tray .tiles > .tile:nth-child(2), #d-slots > :nth-child(2) { animation-delay: 0.025s; }
.tray .tiles > :nth-child(3) .tile, .tray .tiles > .tile:nth-child(3), #d-slots > :nth-child(3) { animation-delay: 0.05s; }
.tray .tiles > :nth-child(4) .tile, .tray .tiles > .tile:nth-child(4), #d-slots > :nth-child(4) { animation-delay: 0.075s; }
.tray .tiles > :nth-child(5) .tile, .tray .tiles > .tile:nth-child(5), #d-slots > :nth-child(5) { animation-delay: 0.1s; }
.tray .tiles > :nth-child(6) .tile, .tray .tiles > .tile:nth-child(6), #d-slots > :nth-child(6) { animation-delay: 0.125s; }
.tray .tiles > :nth-child(7) .tile, .tray .tiles > .tile:nth-child(7), #d-slots > :nth-child(7) { animation-delay: 0.15s; }
.tray .tiles > :nth-child(n+8) .tile, .tray .tiles > .tile:nth-child(n+8), #d-slots > :nth-child(n+8) { animation-delay: 0.175s; }

/* JS-fired moments on tiles: flip for a state change, pop for an
   accepted move, shake for a refusal (the printed reason always stays). */
.tile.flip { animation: tile-flip 0.45s ease both; }
#d-slots .tile.flip { animation: tile-flip 0.45s ease both; }
.tile.pop { animation: tile-pop 0.32s ease-out both; }
.shake { animation: gentle-shake 0.3s ease; }

/* Results arrive by group, rising in with a short stagger. --i is set
   inline by the renderers, capped there so late groups never lag. */
.group { animation: group-rise 0.3s ease-out both; animation-delay: calc(var(--i, 0) * 45ms); }

/* The best word, shown as tiles and lifted out of the summary strip. */
.best-tiles { display: inline-flex; gap: 3px; vertical-align: middle; margin-left: 2px; }
.best-tiles .tile {
  width: 25px; height: 31px; font-size: 14px; border-radius: 4px;
  box-shadow: 0 3px 0 var(--gold), 0 4px 5px rgba(34, 48, 31, 0.2);
  animation: tile-lift 0.35s ease-out both;
}
.best-tiles .tile:nth-child(2) { animation-delay: 0.04s; }
.best-tiles .tile:nth-child(3) { animation-delay: 0.08s; }
.best-tiles .tile:nth-child(4) { animation-delay: 0.12s; }
.best-tiles .tile:nth-child(5) { animation-delay: 0.16s; }
.best-tiles .tile:nth-child(6) { animation-delay: 0.2s; }
.best-tiles .tile:nth-child(n+7) { animation-delay: 0.24s; }

/* Press states: the drawn shadow finally depresses. */
button { transition: transform 0.08s ease; }
button:active { transform: translateY(1px); }
.solve-btn { transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.12s ease; }
.solve-btn:hover { background: #8f2721; }
.solve-btn:active { transform: translateY(2px); box-shadow: 0 0 0 #6E1D18; }
.chip { box-shadow: 0 1px 0 var(--tile-edge); transition: transform 0.08s ease, box-shadow 0.08s ease, border-color 0.12s ease; }
.chip:active { transform: translateY(1px); box-shadow: 0 0 0 var(--tile-edge); }
.tile-btn:active { transform: translateY(1px); }
.tile-btn:active .tile { box-shadow: 0 1px 0 var(--tile-edge), 0 1px 2px rgba(34, 48, 31, 0.18); }

/* The visible focus state UI rule 9 promised. */
:focus-visible { outline: 3px solid var(--cranberry); outline-offset: 2px; border-radius: 4px; }

/* Progress toward a target, as a fill under the printed line. The fill
   grows from zero to its inline width each time the line re-renders. */
.progress-bar { height: 8px; background: rgba(216, 203, 175, 0.55); border-radius: 999px; margin-top: 6px; max-width: 520px; overflow: hidden; }
.progress-fill { height: 100%; background: var(--cranberry); border-radius: 999px; animation: fill-grow 0.5s ease-out; }

/* The finish moment: one panel, four moods. Complete carries the
   cranberry, a personal best the gold, settled stays plain, and a
   round that did not settle stays quiet: no motion beyond the fade. */
.finish-panel { animation: group-rise 0.3s ease-out both; }
.finish-score { font-family: "Young Serif", serif; font-size: 42px; line-height: 1.1; margin: 8px 0 2px; }
.finish-score .finish-score-word { font-family: "Familjen Grotesk", sans-serif; font-size: 15px; color: var(--ink-soft); }
.finish-complete .finish-line strong { color: var(--cranberry); }
.finish-complete .share-box { border-color: var(--cranberry); }
.finish-best .finish-line { border-left: 3px solid var(--gold); padding-left: 10px; }
.finish-best .share-box { border-color: var(--gold); }
.finish-quiet { animation: none; }
.streak-square.fill-now { animation: streak-pop 0.55s ease-out; }
.share-squares span { display: inline-block; animation: tile-pop 0.3s ease-out both; }
.share-squares.quiet span { animation: none; }
.share-squares.best .filled { color: var(--gold); }
.chain-pop { display: inline-block; animation: tile-pop 0.3s ease-out; color: var(--cranberry); font-weight: 700; }

/* Reduced motion: everything above becomes instant, per the design's
   closing rule. The count-up in play.js checks the same setting. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    transition-duration: 0.01ms !important;
  }
}

/* Stage 3: record calendar, game buttons, end screens. */
.cal-grid { display: flex; flex-wrap: wrap; gap: 5px; max-width: 420px; margin: 10px 0; }
.cal-cell { width: 22px; height: 22px; border-radius: 5px; background: transparent; }
.cal-done { background: var(--known, #386334); box-shadow: inset 0 0 0 2px rgba(0,0,0,0.08); }
.cal-spare { background: transparent; border: 2px solid var(--gold, #B98A1E); width: 18px; height: 18px; }
.tile-btn { background: none; border: none; padding: 0; cursor: pointer; }
.field-row { display: flex; gap: 16px; flex-wrap: wrap; }
details { margin: 14px 0; }
details summary { cursor: pointer; font-weight: 600; }
