/* =====================================================================
   LARGE PRINT MODE — the accessibility scale layer for the word/letter
   dailies (Wise Word Finder, Anagram Ladder, Daily Decode, Mini Crossword).

   Engaged by feed/large-print.js setting `data-large-print="on"` on <html>
   (and, pre-paint, by the inline bootstrap in functions/_render.js doc()).

   LOADING: an @import from BOTH feed.css and post.css, preloaded in the SSR
   shell alongside word-find.css and board.css. It is deliberately NOT loaded on
   demand: the toggle button sits in four game toolbars at NORMAL size too, and
   a lazily-injected sheet left it rendering as a bare default browser button
   until the mode was first switched on — and made switching the mode back off
   leave a 1px trace in those toolbars. ~2KB gzipped, in flight with the other
   two sheets, so it costs no extra round trip.

   DESIGN NOTES — why this is not a zoom:
   - No `zoom` / `transform:scale()`. Those blur text, break hit-testing, and
     would wreck word-find's capsule math (which measures getBoundingClientRect
     and stores %). Everything here is a real type/size/spacing override, so
     letters stay crisp and taps land where they look.
   - It scales the WHOLE puzzle, not just the grid: timers, goal lines, the
     found-words list, toolbars, hint costs and status text all come up too. A
     grid that doubles while its labels stay at 11px has missed the point.
   - It is a SIZE axis only. The colour axis already exists as the free
     "High Contrast" scheme (feed/xp.js THEMES, localStorage fb-theme), so this
     sheet touches no palette tokens — the two compose instead of fighting.
     Everything below inherits --ink / --line / --crimson, so equipping High
     Contrast recolours large print for free.
   - Selectors mirror the original rule's shape prefixed with the attribute, so
     they out-specify the base rules they override (several base rules are
     three classes deep, e.g. `.dw-card .dc-actions .dc-hint`, which beats a
     naive two-part selector).
   ===================================================================== */

html[data-large-print="on"]{
  --lp-prose: 24px;    /* the quote / verse — the thing being read */
  --lp-body:  19px;    /* secondary reading text */
  --lp-label: 15px;    /* small labels: author, progress, status, hint cost */
  --lp-btn:   16px;    /* button text */
  --lp-tap:   52px;    /* min tap target — above the 44px floor, for shaky aim */
}

/* ---------------------------------------------------------------------
   SHARED PLAY SHELL (.dc-*) — used by Wise Word Finder and Daily Chess.
   Scoped to the word card so chess's compact bar is left alone.
   ------------------------------------------------------------------- */
html[data-large-print="on"] .dw-card .dc-timer{ font-size:30px }
/* the goal line is the CLEAR GOAL for the loop ("Find the 4 missing words") and
   sits at 11px uppercase by default — the single worst offender on the card at
   large sizes. Drop the uppercase too: all-caps is measurably harder to read at
   low vision because the word shape flattens. */
html[data-large-print="on"] .dw-card .dc-goal{
  font-size:17px; letter-spacing:.03em; text-transform:none }
html[data-large-print="on"] .dw-card .dc-flash{ font-size:17px; padding:4px 12px }
html[data-large-print="on"] .dw-card .dc-status{ font-size:17px }
html[data-large-print="on"] .dw-card .dc-play{ font-size:var(--lp-btn); min-height:var(--lp-tap); padding:12px 24px }

/* The word card's toolbar was deliberately shrunk to 11px ghost chips so the
   grid stays the focus (owner ask 2026-06-15). That trade is right at normal
   size and wrong here — in large print these are the controls a low-vision
   player most needs to find. Restore them to full-size, full-opacity buttons
   with a real border. Four classes deep to beat the base rule. */
html[data-large-print="on"] .dw-card .dc-actions{ gap:10px; margin:14px 0 4px }
html[data-large-print="on"] .dw-card .dc-actions .dc-hint,
html[data-large-print="on"] .dw-card .dc-actions .dc-reset{
  font-size:var(--lp-btn); font-weight:600; padding:11px 18px; border-radius:11px;
  min-height:var(--lp-tap); opacity:1;
  color:var(--ink); border:2px solid color-mix(in srgb, var(--line) 100%, transparent) }
html[data-large-print="on"] .dw-card .dc-actions .dc-hint-cost{ font-size:var(--lp-label); opacity:.85 }

/* ---------------------------------------------------------------------
   WISE WORD FINDER (.wf-*)
   ------------------------------------------------------------------- */
/* The play area's width formula caps at 520px. Lift the cap so a desktop grid
   genuinely gets bigger; the `min(100%, …)` in the base rule still keeps it
   inside the card, so phones are unaffected by this line (their win comes from
   the letter scaling below plus fullscreen). */
html[data-large-print="on"] .wf-grid-area{
  --wf-w:min(760px, max(440px, calc((var(--wfn,6) - 8) * 60px + 440px))) }

/* Letters: raise the clamp ceiling 22px → 42px AND the cell-fraction .56 → .68
   so the glyph fills more of its cell instead of floating in a big empty tile.
   font-weight 700 → 800 thickens the stroke, which is what actually helps a
   low-vision reader far more than size alone. */
html[data-large-print="on"] .wf-cell{
  font-weight:800;
  font-size:clamp(20px, calc(min(var(--wf-w, 440px), 92vw) / var(--wfn, 6) * .68), 42px) }
/* a touch more air between tiles so adjacent letters don't visually merge at size */
html[data-large-print="on"] .wf-grid{ gap:3px; padding:4px; border-radius:14px;
  border-width:3px }
html[data-large-print="on"] .wf-cell{ border-radius:6px }
/* the selected start cell and the trace need a heavier ring to read at size */
html[data-large-print="on"] .wf-cell.wf-start{ box-shadow:inset 0 0 0 5px #d9a514 }

/* The quote IS the found-words list here — each blank is a word to find, and it
   fills in as you find it. It has to scale with the grid or the player is
   reading 17px targets to hunt for 42px letters. */
html[data-large-print="on"] .wf-quote{
  font-size:var(--lp-prose); line-height:1.75; max-width:680px }
html[data-large-print="on"] .wf-intro{ font-size:var(--lp-label) }
html[data-large-print="on"] .wf-author{ font-size:var(--lp-body) }
/* thicker rule under each blank — a 2px underline under 24px text reads as a
   hairline; and the found/strike states need proportional weight too */
html[data-large-print="on"] .wf-blank{ border-bottom-width:3px; min-width:2.5ch }
html[data-large-print="on"] .wf-quote.wf-strike-on .wf-blank-filled{
  text-decoration-thickness:3px }

/* ---------------------------------------------------------------------
   ANAGRAM LADDER (.ag-*)
   ------------------------------------------------------------------- */
html[data-large-print="on"] .ag-h{ font-size:var(--lp-prose); line-height:1.35 }
html[data-large-print="on"] .ag-verse{ font-size:26px; line-height:1.6; border-left-width:4px; padding-left:18px }
html[data-large-print="on"] .ag-word.blank{ letter-spacing:.16em }
html[data-large-print="on"] .ag-author{ font-size:var(--lp-body) }
html[data-large-print="on"] .ag-progress{ font-size:var(--lp-label); letter-spacing:.04em }
html[data-large-print="on"] .ag-msg{ font-size:var(--lp-body) }
html[data-large-print="on"] .ag-done{ font-size:var(--lp-prose); line-height:1.55 }

/* Tiles and slots are the touch targets — 40×46 becomes 60×68. They will wrap
   to more rows on a phone, and that is the correct trade: an extra row costs
   nothing, a 36px tile costs a misfire. */
html[data-large-print="on"] .ag-slots{ gap:8px; min-height:68px }
html[data-large-print="on"] .ag-slot{ width:58px; height:66px; font-size:34px; border-radius:12px; border-width:3px }
html[data-large-print="on"] .ag-rack{ gap:9px }
html[data-large-print="on"] .ag-tile{ width:60px; height:68px; font-size:34px; border-radius:13px; border-width:2px }
html[data-large-print="on"] .ag-actions{ gap:10px; flex-wrap:wrap }
html[data-large-print="on"] .ag-btn,
html[data-large-print="on"] .ag-again{ font-size:var(--lp-btn); padding:12px 22px; min-height:var(--lp-tap) }
/* PHONES ARE WIDTH-BOUND, and honesty about that produces a better layout than
   wishful thinking. A ~390px screen fits seven tiles and no more, whatever the
   type size — the base sheet already shrinks them to 36px for exactly that
   reason. Pushing tiles to 54px here made a 7-letter day wrap 5+2, and a word
   whose SLOTS break across two lines is harder to read than one set in smaller
   type, which is the opposite of the point.
   So on phones large print buys HEIGHT and LETTER SIZE (the parts that are not
   width-constrained) and leaves the row intact: letters go 20px → 26px (+30%)
   and the target grows 36×44 → 42×56, still one clean row of seven. Tablets and
   desktop, which have the room, keep the full 60×68 treatment above. */
@media (max-width:480px){
  html[data-large-print="on"] .ag-slots,
  html[data-large-print="on"] .ag-rack{ gap:5px; justify-content:center }
  /* Width comes from the CONTAINER, not a magic number: a hard-coded px width
     orphans a tile onto its own row the moment the card's padding changes by a
     few pixels, and that lone tile is exactly what reads broken. This says
     "seven across, or 52px if there's room for more" and stays true at any card
     width. border-box so the slot's border doesn't push it back over. */
  html[data-large-print="on"] .ag-slot,
  html[data-large-print="on"] .ag-tile{
    box-sizing:border-box; width:min(52px, calc((100% - 30px) / 7));
    height:56px; font-size:26px }
  html[data-large-print="on"] .ag-slot{ border-width:2px }
  html[data-large-print="on"] .ag-slots{ min-height:56px }
}

/* ---------------------------------------------------------------------
   DAILY DECODE (.dd-*) — near-free on the shared seam
   ------------------------------------------------------------------- */
html[data-large-print="on"] .dd-h{ font-size:var(--lp-prose); line-height:1.35 }
html[data-large-print="on"] .dd-glyph{ font-size:30px }
html[data-large-print="on"] .dd-letter{ font-size:24px; height:26px; border-bottom-width:3px }
html[data-large-print="on"] .dd-punct{ font-size:28px }
html[data-large-print="on"] .dd-gap{ width:20px }
html[data-large-print="on"] .dd-prompt-glyph{ font-size:44px }
html[data-large-print="on"] .dd-prompt-q{ font-size:var(--lp-prose) }
html[data-large-print="on"] .dd-hop{ font-size:var(--lp-label) }
html[data-large-print="on"] .dd-progress{ font-size:var(--lp-label); letter-spacing:.04em }
html[data-large-print="on"] .dd-key{ width:52px; height:58px; font-size:26px; border-radius:12px }
html[data-large-print="on"] .dd-rack{ gap:8px }
html[data-large-print="on"] .dd-btn,
html[data-large-print="on"] .dd-again{ font-size:var(--lp-btn); padding:12px 22px; min-height:var(--lp-tap) }
html[data-large-print="on"] .dd-msg{ font-size:var(--lp-body) }
html[data-large-print="on"] .dd-done{ font-size:var(--lp-prose); line-height:1.55 }
html[data-large-print="on"] .dd-reveal{ font-size:var(--lp-body) }
html[data-large-print="on"] .dd-author{ font-size:var(--lp-body) }
@media (max-width:480px){
  html[data-large-print="on"] .dd-key{ width:48px; height:54px; font-size:24px }
  html[data-large-print="on"] .dd-rack{ gap:6px; justify-content:center }
}

/* ---------------------------------------------------------------------
   MINI CROSSWORD (.cw-*) — near-free on the shared seam
   ------------------------------------------------------------------- */
/* the grid is capped at 288px, which is small even at normal size */
html[data-large-print="on"] .cw-grid{ max-width:min(100%, 460px); gap:4px }
html[data-large-print="on"] .cw-cell input{ font-size:30px; font-weight:700 }
html[data-large-print="on"] .cw-cell{ border-width:2px }
html[data-large-print="on"] .cw-cell.cw-cur{ box-shadow:inset 0 0 0 4px var(--crimson) }
/* clues are the reading surface — 13px is the real barrier here, not the grid */
html[data-large-print="on"] .cw-clue{ font-size:var(--lp-body); line-height:1.45; min-height:var(--lp-tap) }
html[data-large-print="on"] .cw-clues-h{ font-size:var(--lp-label); letter-spacing:.04em }
html[data-large-print="on"] .cw-btn{ font-size:var(--lp-btn); min-height:var(--lp-tap); padding:11px 20px }
/* two clue columns at 19px is too narrow to read — go single-column much later */
@media (max-width:900px){
  html[data-large-print="on"] .cw-clues{ grid-template-columns:1fr; gap:12px }
}

/* ---------------------------------------------------------------------
   THE LANDING PAGES (the two `largePrint` hubs in functions/_hubs.js, served at
   /games/daily-large-print-word-search/ and -crossword). These render in large print
   themselves, so the hub's own prose has to come up with everything else — a
   page that promises big type and then serves 15px body copy is the broken
   promise this whole feature exists to fix.
   ------------------------------------------------------------------- */
/* Prose size is DERIVED from --reader-size (post.css: the A-/A+ control in
   feed/reader.js writes that token), so large print raises the token rather than
   overriding the rule. Two wins: it composes with the reader's own text-size
   preference instead of fighting a computed value, and a reader who has set an
   explicit size still beats us, because reader.js writes --reader-size inline on
   article.post and inline styles outrank a stylesheet. */
html[data-large-print="on"] article.post.hub{ --reader-size:21px; --reader-lh:1.75 }
html[data-large-print="on"] .post.hub .how-steps li{ font-size:20px; line-height:1.6 }
html[data-large-print="on"] .post.hub .how-steps li::before{ font-size:16px }
html[data-large-print="on"] .post.hub .hub-h2{ font-size:19px; letter-spacing:.06em }
html[data-large-print="on"] .post.hub .hub-h3{ font-size:23px }
html[data-large-print="on"] .post.hub .byline{ font-size:20px }
html[data-large-print="on"] .post.hub .hub-cta{ font-size:20px; min-height:60px; padding:14px 28px }
html[data-large-print="on"] .post.hub .hub-cta-note{ font-size:16px }
/* the note that explains the mode + carries the off switch. Column, not a row:
   the control reads as the thing you press about the sentence above it, and an
   icon button leading a paragraph made the sentence start on a picture. */
.hub-lp-note{ display:flex; flex-direction:column; align-items:center;
  gap:10px; margin:16px auto 0; max-width:52ch; font-size:14px; line-height:1.5;
  color:var(--ink-soft); text-align:center }
html[data-large-print="on"] .hub-lp-note{ font-size:18px; max-width:46ch }
/* on a prose page an icon alone has no toolbar to give it meaning, so this one
   instance shows its words (see the .lp-slot mount in feed/large-print.js) */
.lp-btn-label{ font-weight:600 }

/* ---------------------------------------------------------------------
   FOCUS — visible keyboard focus at a weight that survives the bigger type.
   The grids are keyboard-playable (roving tabindex), so this is load-bearing,
   not decoration.
   ------------------------------------------------------------------- */
html[data-large-print="on"] .wf-cell:focus-visible,
html[data-large-print="on"] .ag-tile:focus-visible,
html[data-large-print="on"] .ag-slot:focus-visible,
html[data-large-print="on"] .dd-key:focus-visible,
html[data-large-print="on"] .cw-cell input:focus-visible,
html[data-large-print="on"] .dc-hint:focus-visible,
html[data-large-print="on"] .dc-reset:focus-visible,
html[data-large-print="on"] .ag-btn:focus-visible,
html[data-large-print="on"] .dd-btn:focus-visible,
html[data-large-print="on"] .cw-btn:focus-visible,
html[data-large-print="on"] .lp-btn:focus-visible{
  outline:4px solid var(--crimson); outline-offset:3px; border-radius:6px }

/* ---------------------------------------------------------------------
   THE CONTROL ITSELF (.lp-btn) — a calm ghost chip that sits in whatever
   toolbar it is mounted into. Icon-first (owner preference), with an
   aria-label carrying the words. Deliberately NOT crimson at rest: it is a
   utility, not the primary action.
   ------------------------------------------------------------------- */
.lp-btn{ font:inherit; font-family:var(--ui); font-size:13px; font-weight:600; line-height:1;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  min-width:40px; min-height:40px; padding:8px 12px; cursor:pointer;
  border-radius:10px; border:1px solid var(--line); background:transparent;
  color:var(--ink-soft); transition:.15s ease;
  touch-action:manipulation; -webkit-tap-highlight-color:transparent }
.lp-btn:hover{ color:var(--crimson); border-color:var(--crimson) }
.lp-btn .lp-ico{ display:block }
/* When mounted into a toolbar that has its own button shape, borrow that shape
   so the control doesn't read as a foreign object dropped into the row. Two
   classes, so this beats the bare .lp-btn radius above whatever the load order. */
.lp-btn.ag-btn, .lp-btn.dd-btn{ border-radius:999px }
/* These rows default to align-items:stretch, so the control's 40px minimum was
   quietly making every sibling button 1px taller the moment this sheet loaded —
   a feature that is switched OFF should leave no trace in the layout. Centring
   lets the control be the size it needs without resizing its neighbours. */
.ag-actions, .cw-actions, .dd-actions, .dw-card .dc-actions{ align-items:center }
/* engaged state: filled, so "it's on" is obvious without reading anything */
.lp-btn[aria-pressed="true"]{ color:var(--crimson); border-color:var(--crimson);
  background:color-mix(in srgb, var(--crimson) 12%, transparent) }
/* in large print the control must obey its own rules */
html[data-large-print="on"] .lp-btn{ font-size:var(--lp-btn); min-height:var(--lp-tap);
  min-width:var(--lp-tap); padding:11px 16px; border-width:2px; color:var(--ink) }
html[data-large-print="on"] .lp-btn .lp-ico{ width:24px; height:24px }
@media (prefers-reduced-motion:reduce){ .lp-btn{ transition:none } }

/* ---------------------------------------------------------------------
   FULLSCREEN OVERLAY (.lp-fs) — the same contract as the Daily Dungeon's
   .nh-fs, kept generic so any card can wear it. On a phone this is where the
   real win is: the card stops being a 320px column inside a feed and becomes
   the whole screen, which is worth far more than any type bump.
   ------------------------------------------------------------------- */
html.lp-fs-lock, body.lp-fs-lock{ overflow:hidden }
/* z-index must beat the site's FIXED edge furniture, which sits at ~2147483000
   (the EXP pill, the notepad panel, the narration bar) — at a mere 9999 they
   all paint over the overlay, i.e. on desktop always, since native fullscreen's
   top layer only masks it on mobile. Same number the dungeon settled on.
   transform/box-shadow are pinned because the card is still a .feed-card and
   the global :hover lift would shift a fixed inset:0 overlay by 2px. */
.lp-fs{ position:fixed; inset:0; z-index:2147483200; margin:0; border:0; border-radius:0;
  transform:none; box-shadow:none; background:var(--paper); overflow-y:auto;
  display:block; max-width:none; width:auto;
  /* the notch and the home indicator must never cover a control */
  padding:calc(12px + env(safe-area-inset-top)) calc(12px + env(safe-area-inset-right))
          calc(16px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left)) }
/* the grid should use the height it just gained, not stay pinned to a card width */
.lp-fs .wf-grid-area{ max-width:min(100%, 96vh) }
/* the exit control has to be findable without hunting: park it top-right, above
   the card's own content, with the same dot treatment the dungeon uses */
.lp-fs .lp-fs-btn{ position:fixed; top:calc(8px + env(safe-area-inset-top));
  right:calc(8px + env(safe-area-inset-right)); z-index:3 }
@media (prefers-reduced-motion:reduce){ .lp-fs{ transition:none } }
