/* The acrostic board, entry field and clue list.
   Layout is the POC's: the flex-wrap board, the two-column clue grid,
   width:fit-content and the 680px stacking breakpoint are all load-bearing and
   documented in DESIGN.md §3. What changed is colour, type, radius and size —
   and every colour comes from tokens.css. */

:root{
  --tile-w:32px; --tile-h:36px;
  --slot-w:25px; --slot-h:32px;
  /* --ans-col (the answer column width) is set per puzzle as an inline style on
     .clues by the server: longest answer in slots, computed, never authored.
     This is the fallback for a page rendered without it, and it must track
     SLOT/GAP in src/puzzles/puzzleService.ts. */
  --ans-col:272px;
}

/* progress hairline pinned to the very top */
#line{
  position:fixed;top:0;left:0;height:4px;width:0;background:var(--accent);
  border-radius:0 4px 4px 0;z-index:5;transition:width .35s var(--ease);
}

.wrap header{padding:22px 0 16px;display:flex;align-items:flex-end;gap:16px;flex-wrap:wrap}
.wrap h1{
  font-family:var(--display);font-weight:800;font-size:34px;letter-spacing:-.03em;margin:0;
}
.wrap h1 em{
  font-style:normal;color:var(--accent-ink);
}
.meta{margin-left:auto;display:flex;align-items:baseline;gap:16px}
#clock{
  font-family:var(--serif);font-weight:900;font-size:28px;
  font-variation-settings:"SOFT" 70,"WONK" 1;
  font-variant-numeric:tabular-nums;letter-spacing:.01em;
}
#count{font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);font-weight:800}
.dateline{
  flex-basis:100%;margin:4px 0 0;font-size:13px;letter-spacing:.01em;color:var(--dim);
}

/* ---------------- board ---------------- */
/* The board stays the darkest thing on the page: a revealed letter reads
   instantly against its blank neighbours because the tiles are light on dark.
   The hairline and bloom are the base colour at its full strength — the one
   surface dark enough to carry #3CFBF2 without it going to mush. */
.board{
  position:relative;
  background:var(--board);border:2px solid var(--board-line);border-radius:var(--radius-card);
  padding:28px 22px 26px;
  box-shadow:0 24px 50px -28px var(--shadow-board),inset 0 1px 0 var(--glow-line);
}
.grid{
  display:flex;flex-wrap:wrap;
  justify-content:center;      /* centres every wrapped line */
  align-items:flex-start;
  gap:12px 34px;               /* row gap / word gap */
}
/* one word, held together so it never breaks across lines. flex-wrap is the
   safety valve: a word too long for the viewport at the smallest tile size has
   to break somewhere, and breaking is better than overflowing the page. */
.chunk{display:inline-flex;gap:3px;align-items:flex-start;flex-wrap:wrap}
.cell{
  position:relative;width:var(--tile-w);height:var(--tile-h);
  background:var(--tile);border-radius:var(--radius-tile);
  display:grid;place-items:center;
  font-family:var(--serif);font-weight:900;font-size:18px;line-height:1;
  font-variation-settings:"SOFT" 70,"WONK" 1;
  color:transparent;
  transition:color .2s ease,transform .2s ease,background .2s ease;
}
.cell .n,.cell .g{
  position:absolute;top:2px;font-family:var(--ui);
  font-size:9px;line-height:1;font-weight:700;font-variant-numeric:tabular-nums;
  transition:opacity .25s ease;
}
.cell .n{left:4px;color:var(--tile-fig)}
.cell .g{display:none}
.cell.on{color:var(--tile-ink)}
.cell.on .n,.cell.on .g{opacity:0}
.cell.hl{background:var(--accent)}
.cell.hl .n{color:var(--on-accent)}
.cell.hl .g{color:var(--accent-ink)}
/* the spring is the whole character of the reveal: the tile overshoots, then
   settles. Flattened entirely under prefers-reduced-motion, below. */
.cell.pop{animation:pop .46s var(--spring)}
@keyframes pop{
  0%{transform:scale(1);background:var(--accent)}
  40%{transform:scale(1.22) rotate(-2deg);background:var(--accent)}
  100%{transform:scale(1);background:var(--tile)}
}
.punc{
  height:var(--tile-h);display:grid;place-items:end center;
  color:var(--punc);font-family:var(--serif);font-weight:700;font-size:20px;
  padding-bottom:3px;min-width:6px;
}

/* ---------------- entry ---------------- */
.entry{margin:26px auto 0;max-width:520px}
#guess{
  width:100%;padding:17px 20px;text-align:center;
  font-family:var(--ui);font-size:18px;font-weight:800;
  letter-spacing:.22em;text-transform:uppercase;color:var(--ink);
  background:var(--card);border:2.5px solid var(--accent-deep);border-radius:var(--radius-pill);
  outline:none;transition:border-color .15s,box-shadow .15s;
}
#guess::placeholder{color:var(--placeholder);letter-spacing:.16em;font-weight:700}
/* the field is the third pill on the page and takes the same rim and halo the
   card and the result button do. Three states have to stay apart while the field
   is focused the whole time, so they are told apart by how far the glow carries
   rather than by colour: holding the caret, the beat after a correct answer, and
   a word that was already found.

   `.hit` is a 500 ms flash (acrostic.js) fired while the field already has focus,
   so it has to bloom visibly wider than the focus glow it lands on top of —
   matching it would make a correct answer look like nothing happened. */
#guess:focus{border-color:var(--accent);box-shadow:0 0 20px 4px var(--accent-glow)}
#guess.hit{
  border-color:var(--accent);
  box-shadow:0 0 34px 12px var(--accent-glow);
}
#guess.dupe{border-color:var(--dupe-line);box-shadow:none}
.status{
  min-height:20px;font-size:13px;color:var(--slate);text-align:center;
  padding-top:11px;letter-spacing:.01em;
}
.status b{color:var(--ink);font-weight:800}

/* give up: deliberately quiet, and two-step — one stray click must not end a
   puzzle the player is still working on. The first press arms the button, the
   second reveals; typing again, or four seconds of silence, disarms it.
   At the foot of the clue list: the player looks here when stuck, and it keeps a
   destructive button away from the field they are typing into. */
.giveup{text-align:center;padding:24px 0 0}
.giveup.gone{display:none}
#giveup{
  background:var(--card);border:2px solid var(--rule-firm);border-radius:var(--radius-pill);
  padding:10px 22px;cursor:pointer;
  font-family:var(--ui);font-size:12px;font-weight:800;
  letter-spacing:.12em;text-transform:uppercase;color:var(--slate);
  transition:color .15s,border-color .15s,background .15s,transform .15s var(--spring);
}
#giveup:hover{color:var(--ink);border-color:var(--ink);transform:translateY(-1px)}
#giveup.armed{
  color:var(--accent-ink);border-color:var(--accent-deep);background:var(--accent-soft);
  box-shadow:0 0 14px 1px var(--accent-glow);
}

/* ---------------- clues ---------------- */
/* width:fit-content, not a fixed 740px. The rows are per-row grids whose tip
   track is 1fr, so the container width decides where the tip/answer divider
   falls: a fixed width hands the tip track ALL the leftover, pushing the
   divider — and with it every scrap of ink, since tips are right-aligned and
   answers left-aligned — off the page centre by (740 - ans-col)/2. Puzzle 4,
   whose longest answer is only 9 slots, drifted ~90px right of the centred
   board and note above and below it. fit-content resolves to the widest row
   natural size (longest tip + gap + ans-col); every row then shares that
   width, so 1fr still resolves identically in each and the squares stay
   column-aligned. No per-puzzle tuning, and no dependence on tip text width. */
/* The list sits on a card rather than straight on the page: it is the half of
   the screen a player actually reads, and a lighter, flatter ground under 16px
   text is worth more than the extra air was. */
.clues{
  width:fit-content;max-width:780px;margin:38px auto 0;
  background:var(--card);border:2px solid var(--rule);border-radius:var(--radius-card);
  padding:20px 24px 22px;
}
/* The answer column is fixed at the width of the longest answer, so every row's
   squares line up down the page instead of drifting with the tip length. The tip
   takes the slack and sits right-aligned against the gutter — the classic
   acrostic look, and safe now that a 5–8 word tip is one line. */
.clues-head,.clue{
  display:grid;grid-template-columns:minmax(0,1fr) var(--ans-col);gap:0 26px;
}
.clues-head span:first-child{text-align:right}
.clues-head{
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--dim);
  font-weight:800;padding-bottom:10px;border-bottom:2px solid var(--rule-firm);
}
.clue{
  align-items:center;padding:12px 10px;margin:0 -10px;
  border-bottom:1px solid var(--rule);
  border-radius:var(--radius-row);
  transition:background .15s ease;
}
/* hovering a row previews the tiles it owns on the board, so the row itself
   takes the accent wash — the same colour the preview uses up there */
.clue:hover{background:var(--accent-soft)}
#clues .clue:last-child{border-bottom:0}
/* The tips are the half of the page a player actually reads, so they are set at
   reading size in full ink rather than as a caption in a lighter tone. They
   were 14px/400 in --slate and went soft against a coloured ground. */
.tip{
  text-align:right;font-size:16px;font-weight:500;line-height:1.45;
  color:var(--ink);text-wrap:pretty;
}
.clue.done .tip{
  color:var(--muted);font-weight:400;
  text-decoration:line-through;text-decoration-thickness:1px;
}
.slots{display:flex;gap:5px;flex-wrap:wrap;justify-self:start}
/* word break inside a multi-word answer: DEEP END gets a gap, not a space
   character. Printed acrostics separate the words this way. */
.slots .gap{width:9px}
/* The tile number lives in the corner and the letter below it, which is why the
   slot carries top padding rather than centring its letter in the whole box: a
   solved slot shows both at once, and at this size they were landing on top of
   each other. */
.slot{
  position:relative;width:var(--slot-w);height:var(--slot-h);
  background:var(--card);border:2px solid var(--slot-line);border-radius:var(--radius-slot);
  display:grid;place-items:center;padding-top:7px;
  font-family:var(--serif);font-weight:900;font-size:16px;
  font-variation-settings:"SOFT" 70,"WONK" 1;color:transparent;
  transition:color .2s ease,border-color .2s ease;
}
.slot .n{
  position:absolute;top:1px;left:3px;font-family:var(--ui);
  font-size:8px;font-weight:700;color:var(--slot-fig);font-variant-numeric:tabular-nums;
}
.slot.lead{background:var(--accent);border-color:var(--accent-deep)}
.slot.lead .n{color:var(--on-accent)}
.slot.on{color:var(--ink)}
.slot.on .n{opacity:.4}
.slot.lead.on{color:var(--on-accent)}
.slot.lit{animation:lit .5s var(--ease)}
@keyframes lit{
  0%{background:var(--accent);border-color:var(--accent-deep)}
  100%{background:var(--card);border-color:var(--slot-line)}
}
.slot.lead.lit{animation:none}

.note{
  max-width:640px;margin:26px auto 0;font-size:14px;line-height:1.7;color:var(--slate);
  text-align:center;
}
.note b{color:var(--ink);font-weight:800}

/* ---------------- result (replaces the entry field) ---------------- */
.result{display:none;text-align:center}
.entry.done #guess,
.entry.done .status{display:none}
.entry.done .result{display:block;animation:rise .45s var(--spring)}
@keyframes rise{from{transform:translateY(12px);opacity:0}to{transform:none;opacity:1}}
.result .eyebrow{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--accent-ink);font-weight:800}
.result .final{
  font-family:var(--serif);font-weight:900;font-size:58px;line-height:1.05;
  font-variation-settings:"SOFT" 80,"WONK" 1;
  font-variant-numeric:tabular-nums;margin:8px 0 0;letter-spacing:-.01em;
}
.result .flabel{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--dim);margin-top:4px}
/* the accent is the rim of the pill, not a slab behind it. A hard offset shadow
   is at its worst on a full pill: the offset crescents around the round end
   instead of sitting as two clean bands, which is what made this one read as a
   printing error rather than a shadow. */
.result button{
  margin-top:20px;width:100%;padding:15px;border:2.5px solid var(--accent);border-radius:var(--radius-pill);
  background:var(--ink);color:var(--page);font-family:var(--ui);font-size:13px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;cursor:pointer;
  transition:background .15s,transform .15s var(--spring),box-shadow .15s var(--spring);
}
.result button:hover{
  background:var(--ink-lift);transform:translateY(-2px);
  box-shadow:0 0 18px 1px var(--accent-glow),0 14px 30px -14px var(--accent-glow);
}
/* pressed: the lift drops away and the halo tightens, so the button reads as
   going down into the page rather than off it */
.result button:active{
  transform:translateY(0);box-shadow:0 0 10px 0 var(--accent-glow);
}

/* ---------------- prev / next ---------------- */
.puzzle-nav{
  max-width:700px;margin:32px auto 0;display:flex;align-items:center;
  justify-content:space-between;gap:12px;font-size:13px;font-weight:700;
}
.puzzle-nav a{
  color:var(--slate);text-decoration:none;padding:9px 16px;
  border:2px solid var(--rule-firm);border-radius:var(--radius-pill);background:var(--card);
  transition:color .15s,border-color .15s,transform .15s var(--spring);
}
.puzzle-nav a:hover{color:var(--ink);border-color:var(--ink);transform:translateY(-2px)}

@media (max-width:680px){
  /* The tile is sized from the viewport rather than stepped through
     breakpoints, because what has to fit is the sentence's longest word and no
     breakpoint knows how long that is. The divisor is a worst-case 15-letter
     word: at 390px this lands near 21px, which fits puzzle 3's ARCHAEOLOGISTS
     with room to spare, and it degrades smoothly instead of overflowing the
     page the way a fixed 25px did. */
  :root{
    --tile-w:clamp(19px,calc((100vw - 52px) / 15 - 2px),26px);
    --tile-h:calc(var(--tile-w) + 4px);
    --slot-w:22px;--slot-h:28px;
  }
  .cell{font-size:calc(var(--tile-w) * .6)}
  .cell .n,.cell .g{font-size:8px}
  .cell .n{left:3px}
  .cell .g{right:3px}
  .chunk{gap:2px}
  .grid{gap:9px 18px}
  .board{padding:16px 11px 14px}
  .wrap{padding:0 14px}
  .punc{font-size:17px}
  /* narrow screens stack the tip above its answer squares — a tip and a
     9-square answer will not sit side by side at this width. Stacked, the tip
     reads left-aligned: right-aligned over left-aligned squares looks broken. */
  .tip{font-size:15px;text-align:left}
  .slot{font-size:15px;padding-top:6px}
  .clue{grid-template-columns:minmax(0,1fr);gap:10px 0;padding:14px 10px}
  .clues{width:auto;padding:14px 14px 16px;margin-top:30px}
  .clues-head{display:none}
  .wrap h1{font-size:27px}
  #clock{font-size:23px}
  #guess{font-size:16px;padding:15px 18px}
  .result .final{font-size:46px}
  .puzzle-nav{font-size:12px}

  /* The clue list is taller than a phone screen, so on the desktop layout the
     field scrolls off the top the moment the player starts reading the clues —
     and reading a clue is exactly when they want to type. Pinned to the foot of
     the viewport it stays under the thumb the whole way down the list.
     The result panel is not a bar: .done drops the block back into the flow,
     where it takes the field's place the way it does on a wide screen. */
  .entry{
    position:fixed;left:0;right:0;bottom:0;z-index:6;
    margin:0;max-width:none;
    padding:10px 14px calc(10px + env(safe-area-inset-bottom,0px));
    background:var(--page);
    border-top:2px solid var(--rule);
    box-shadow:0 -14px 28px -20px var(--shadow-board);
  }
  .status{padding-top:7px;min-height:16px;font-size:12px}
  /* the bar is out of the flow, so the page owes back the height it would have
     occupied — without this it covers the last clue and the footer */
  body{padding-bottom:calc(122px + env(safe-area-inset-bottom,0px))}
  .entry.done{
    position:static;max-width:520px;margin:26px auto 0;padding:0;
    background:none;border-top:0;box-shadow:none;
  }
  /* …and the debt is paid off once the bar is gone */
  body:has(.entry.done){padding-bottom:60px}
}
