:root{
    --bg:#EDF1F4; --ink:#22303F; --ink-soft:#5B6B7B;
    --well:#D8E0E7; --well-outer:#CBD5DD; --zone:#E6ECF1;
    --tile:#FCFDFC; --tile-line:#B9C6D0;
    --accent:#2B59C3; --accent-soft:#DFE7F9;
    --good:#2E9E6B; --bad:#D9455C; --gold:#E9C31C; --purple:#7A5AD8;
    --charge:#2B59C3; --charge-press:#16307A;   /* word bank meter + Grid Check */
    --surface:#fff; --surface-soft:#F6F8FA;       /* cards, drawer, buttons */
    --track:#EEF1F4; --track-2:#DCE3E9;           /* unfilled meters */
    --divider:#EEF2F5;
    --o1:#F5C48C; --o2:#A9D9BE; --o3:#B5C7F0; --o4:#DDBEE8; --o5:#EFDE9C; --o6:#E8B3A6;
    --o7:#F2B8C8; --o8:#CBD3DA; --o9:#C9E39E;   /* extra colours for Create */
    --radius:14px;
  }
  /* ---------------------------------------------------------------- dark mode
     Same roles, darker surfaces. Tile tints are the light ones pulled down so
     letters (now light ink) keep their contrast. Switched on by html.dark, set
     before first paint by the snippet in index.html's <head>. */
  html.dark{
    color-scheme:dark;
    --bg:#12171D; --ink:#E4E9EE; --ink-soft:#97A5B3;
    --well:#1E262E; --well-outer:#192028; --zone:#232C35;
    --tile:#2A343E; --tile-line:#3B4854;
    --accent:#4F7FE0; --accent-soft:#22314F;
    --good:#3DB57F; --bad:#E55A6F; --purple:#8C6FE6;
    --charge:#4F7FE0; --charge-press:#3462C4;
    --o1:#7C5A35; --o2:#335E49; --o3:#3A4B7A; --o4:#5E4470; --o5:#6E6230; --o6:#74443B;
    --o7:#7A3E55; --o8:#4A545E; --o9:#4E6A2C;
    --surface:#1B2229; --surface-soft:#222A32;
    --track:#2A333C; --track-2:#323C46;
    --divider:#252E37;
  }
  /* As a home-screen app the page never scrolls or rubber-bands: it's pinned to the
     screen, and the game is centred in it. */
  @media (display-mode: standalone){
    html, body{overscroll-behavior:none;}
    body{position:fixed; inset:0; overflow:hidden; min-height:0;}
  }
  html.standalone, html.standalone body{overscroll-behavior:none;}
  /* arranging a start inside the Create page: only the board and its controls */
  html.arrange body{position:static !important; overflow:hidden !important; min-height:0 !important;
    justify-content:flex-start; padding:0 2px 6px !important; background:transparent;}
  html.arrange header, html.arrange #drawer, html.arrange #helpOverlay, html.arrange #overlay,
  html.arrange #introOverlay{display:none !important;}
  html.standalone body{position:fixed; inset:0; overflow:hidden; min-height:0;}
  *{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
  html,body{margin:0; padding:0;}
  body{
    background:var(--bg); color:var(--ink);
    font-family:'Archivo',system-ui,sans-serif;
    display:flex; flex-direction:column; align-items:center;
    justify-content:center;            /* the game sits centred on the screen */
    min-height:100vh; min-height:100dvh; padding:14px 14px 26px;
    /* as a home-screen app the page runs under the status bar / notch: clear them */
    padding-top:calc(14px + env(safe-area-inset-top, 0px));
    padding-left:calc(14px + env(safe-area-inset-left, 0px));
    padding-right:calc(14px + env(safe-area-inset-right, 0px));
  }
  /* the closed drawer's tab is 42px tall; 56 leaves the same 14px gap as at the top */
  body.has-drawer{padding-bottom:calc(56px + env(safe-area-inset-bottom, 0px)); transition:padding-bottom .2s;}
  /* the corner buttons live in the header, so they move with the centred game */
  header{position:relative; width:100%; max-width:var(--board-w, 560px); text-align:center; margin-bottom:6px;}

  /* menu: ☰ in the top-right corner unfolds downward into dark mode, timer, help */
  #menu{position:absolute; top:-2px; right:-2px; z-index:45; width:34px; height:34px;}
  #menu > button, #menu > a{
    position:absolute; top:0; right:0; z-index:1;
    width:34px; height:34px; border-radius:17px; cursor:pointer; padding:0;
    border:1px solid var(--tile-line); background:var(--surface); color:var(--ink-soft);
    font:inherit; font-weight:800; font-size:16px; line-height:1;
    display:flex; align-items:center; justify-content:center; touch-action:manipulation;
    transition:top .28s cubic-bezier(.3,1.3,.5,1), opacity .2s ease, transform .28s cubic-bezier(.3,1.3,.5,1);
  }
  #menu > button:hover, #menu > a:hover{color:var(--ink); border-color:var(--ink-soft);}
  #menuBtn{z-index:3 !important;}
  /* ☰ turns into ×: three bars, all centred in the button, offset up/down; open,
     the outer two slide to the middle and cross. (HTML bars, not SVG lines:
     WebKit puts an SVG line's transform-origin in the wrong place.) */
  #menuBtn .bar{position:absolute; left:50%; top:50%; width:16px; height:2px; margin:-1px 0 0 -8px;
    border-radius:1px; background:currentColor;
    transition:transform .28s cubic-bezier(.4,0,.2,1), opacity .18s ease;}
  #menuBtn .b1{transform:translateY(-5px);}
  #menuBtn .b3{transform:translateY(5px);}
  #menu.open #menuBtn .b1{transform:rotate(45deg);}
  #menu.open #menuBtn .b2{opacity:0; transform:scaleX(.2);}
  #menu.open #menuBtn .b3{transform:rotate(-45deg);}
  /* folded: tucked behind ☰ */
  #menu > #themeBtn, #menu > #timerBtn, #menu > #helpBtn, #menu > #createBtn{opacity:0; transform:scale(.6); pointer-events:none;}
  #menu.open > #themeBtn, #menu.open > #timerBtn, #menu.open > #helpBtn, #menu.open > #createBtn{opacity:1; transform:none; pointer-events:auto;}
  #menu.open > #themeBtn{top:40px;}
  #menu.open > #timerBtn{top:80px; transition-delay:.03s;}
  #menu.open > #helpBtn{top:120px; transition-delay:.06s;}
  #menu.open > #createBtn{top:160px; transition-delay:.09s;}
  #createBtn{box-sizing:border-box; text-decoration:none;}
  /* a timer that's on stays out under ☰ when the menu folds */
  #menu > #timerBtn.open{opacity:1; transform:none; pointer-events:auto; top:40px;}
  #menu.open > #timerBtn.open{top:80px;}
  #themeBtn .icon-sun{display:none;}
  /* the timer: a stopwatch; on, it widens leftward into a pill with the time */
  #menu > #timerBtn{
    width:auto; min-width:34px; padding:0 8px; gap:0; flex-direction:row-reverse;
    font-size:13px; font-variant-numeric:tabular-nums;
  }
  #timerBtn svg{flex:none;}
  #timerText{display:inline-block; max-width:0; overflow:hidden; white-space:nowrap; color:var(--ink);
    transition:max-width .25s ease;}
  #menu > #timerBtn.open{gap:5px; border-color:var(--accent); color:var(--accent);}
  #timerBtn.open #timerText{max-width:64px;}
  #menu > #timerBtn.long{font-size:11.5px;}   /* an hour or more: keep clear of the date line */
  /* the ? the first-time help folds into gets a brief ring */
  #helpBtn.landed{box-shadow:0 0 0 3px var(--accent-soft); color:var(--accent) !important;
    border-color:var(--accent) !important;}
  html.dark #themeBtn .icon-sun{display:block;}
  html.dark #themeBtn .icon-moon{display:none;}
  #dailyLine{
    margin-top:5px; font-size:12.5px; font-weight:700; color:var(--ink-soft);
    letter-spacing:.03em;
  }
  #dailyLine b{color:var(--accent);}
  /* ‹ yesterday's puzzle / › back to today */
  .day-nav{border:0; background:transparent; color:var(--ink-soft); font:inherit;
    font-size:17px; font-weight:800; line-height:1; padding:2px 8px; margin:-4px 2px;
    cursor:pointer; touch-action:manipulation; vertical-align:middle;}
  .day-nav:hover{color:var(--accent);}
  .day-link{color:var(--ink-soft); text-decoration:none; font-weight:800;}
  .day-link:hover{color:var(--accent);}
/* a custom puzzle: its title in the date line (tap for the note), and the intro card */
  .day-title{border:0; background:transparent; padding:0; font:inherit; color:inherit; cursor:pointer;
    touch-action:manipulation;}
  .day-title:disabled{cursor:default;}
  .info-i{display:inline-flex; align-items:center; justify-content:center; width:14px; height:14px;
    border-radius:50%; background:var(--accent); color:#fff; font-size:10px; font-weight:900;
    font-style:normal; vertical-align:1px;}
#introOverlay{position:fixed; inset:0; background:rgba(28,40,54,.45); display:none;
  align-items:center; justify-content:center; z-index:56; padding:20px;}
#introOverlay.show{display:flex;}
#introOverlay h2{margin:4px 0 10px; font-size:24px; overflow-wrap:anywhere;}
.intro-kicker{font-size:12px; font-weight:800; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink-soft);}
#introNote{margin:0; font-size:15px; line-height:1.5; color:var(--ink); white-space:pre-line;
  overflow-wrap:anywhere; text-align:left;}
#introNote[hidden]{display:none;}

/* "Have feedback?": a quiet text link; its heads-up card sits above everything */
.feedback-link{display:block; margin:10px auto 0; padding:4px 8px; border:0; background:transparent;
  font:inherit; font-size:13px; font-weight:700; color:var(--ink-soft); text-decoration:underline;
  text-underline-offset:3px; cursor:pointer; touch-action:manipulation;}
.feedback-link:hover{color:var(--ink);}
#feedbackOverlay{position:fixed; inset:0; background:rgba(28,40,54,.45); display:none;
  align-items:center; justify-content:center; z-index:70; padding:20px;}
#feedbackOverlay.show{display:flex;}
#feedbackOverlay h2{margin:0 0 10px; font-size:23px;}
#feedbackOverlay p{margin:0 0 10px; font-size:15px; line-height:1.5; color:var(--ink); text-align:left;}
#feedbackOverlay .btn{text-decoration:none; text-align:center;}

/* → the Create page (Tools & Tips, and the win card) */
.make-link{display:block; margin:12px auto 0; text-align:center; font-size:13.5px; font-weight:800;
  color:var(--accent); text-decoration:none; touch-action:manipulation;}
/* the menu's make-your-own icon (a grid with a + at its corner), inline with the text */
.make-icon{display:inline-block; vertical-align:-2px; margin-right:3px;}

#helpOverlay{
    position:fixed; inset:0; background:rgba(28,40,54,.45); display:none;
    align-items:center; justify-content:center; z-index:55; padding:12px;
  }
  #helpOverlay.show{display:flex;}
  #helpOverlay .card{
    text-align:left; position:relative;
    max-width:364px; padding:24px 20px 18px;
    max-height:calc(100vh - 24px);
  }
  #helpOverlay h2{margin:0 0 6px; font-size:23px;}
  #helpOverlay h2{text-align:center;}
  #helpClose{
    position:absolute; top:12px; right:12px; z-index:1;
    width:30px; height:30px; border-radius:50%; cursor:pointer;
    border:1px solid var(--tile-line); background:var(--surface); color:var(--ink-soft);
    font:inherit; font-weight:800; font-size:16px; line-height:1;
    display:flex; align-items:center; justify-content:center;
    touch-action:manipulation; padding:0;
  }
  #helpClose:hover{color:var(--ink); border-color:var(--ink-soft);}
  .help-page{display:none;}
  .help-page.active{display:block;}
  .help-body p{margin:0 0 12px; font-size:14.5px; line-height:1.5; color:var(--ink);}
  .help-list{list-style:none; margin:0; padding:0;}
  .help-list li{
    font-size:13.5px; line-height:1.38; color:var(--ink-soft);
    padding:8px 0; border-top:1px solid var(--divider);
    display:flex; align-items:flex-start; gap:10px;
  }
  #helpPage1 .help-list li{
    flex-direction:column; align-items:stretch; gap:7px;
  }
  #helpPage1 .help-list li > :first-child{align-self:center;}
  .hk-icon{
    flex:none; width:30px; height:30px; margin-top:1px; border-radius:9px;
    background:var(--surface); border:1px solid var(--tile-line); color:var(--ink);
    display:flex; align-items:center; justify-content:center;
  }
  .hk-icon svg{width:15px; height:15px;}
  /* ===================================================================
     One 12s story runs across all three rows of "How to play", so every
     animation below shares the same clock and is keyed by percentage:
        0-22%  scrambled RDWO at rest
       22-37%  RD lifts out, W/O shuffle left, RD drops -> WORD
       41-46%  WORD is a word: letters nod, blue check badge (no button needed)
       52-60%  the check funnels into the word bank tab; its bar fills
       60-63%  bar full: the tab pops. The Grid Check button (row 3) fills with it
       74-84%  Grid Check pressed -> WORD gets circled
       92-97%  reset
     Slots are 30px wide on a 34px pitch, so one slot-step is 34px.
     =================================================================== */
  .move-demo{position:relative; display:inline-block; flex:none; pointer-events:none;}
  .move-icon{
    position:relative; display:block; width:144px; height:48px; border-radius:14px;
    background:var(--well); box-shadow:inset 0 2px 6px rgba(25,40,55,.16);
  }
  .move-cell{
    position:absolute; top:6px; width:30px; height:36px; border-radius:9px;
    background:var(--well-outer);
  }
  .move-piece{position:absolute; top:6px; height:36px;}
  .mp-body{
    position:absolute; inset:0; border-radius:9px;
    background:var(--tile); box-shadow:inset 0 0 0 1px var(--tile-line);
    display:flex; align-items:center; justify-content:center;
    font-size:17px; font-weight:800; color:var(--ink);
    font-family:'Archivo',sans-serif; text-transform:uppercase;
  }
  /* multi-cell pieces are tinted like real ominos; singles stay plain --tile */
  .piece-rd .mp-body{background:var(--o4);}
  .mp-l{display:inline-block; animation:letterStory 12s ease-in-out infinite;}
  .piece-w{left:74px; width:30px; z-index:2; animation:mvW 12s ease-in-out infinite;}
  .piece-o{left:108px; width:30px; z-index:2; animation:mvO 12s ease-in-out infinite;}
  /* the fused domino spans two slots plus the gap between them, as one silhouette */
  .piece-rd{left:6px; width:64px; z-index:3; animation:mvRD 12s ease-in-out infinite;}
  .piece-rd .mp-body{animation:rdShadow 12s ease-in-out infinite;}
  .piece-rd .mp-l{
    position:absolute; top:0; height:100%; width:30px;
    display:flex; align-items:center; justify-content:center;
  }
  .mp-a{left:0;}
  .mp-b{left:34px;}
  .mp-seam{
    position:absolute; left:31px; top:6px; width:2px; height:24px;
    border-radius:2px; background:rgba(34,48,63,.14);
  }
  /* verdict badges, drawn just past the end of the word like the real ones */
  .vbadge{
    position:absolute; top:12px; left:150px;
    width:22px; height:22px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    font-weight:900; font-size:13px; line-height:1;
    opacity:0; z-index:1;
  }
  .vb-check{
    color:#fff; background:var(--charge);
    --fx:-62px; --fy:81px;            /* measured badge centre -> word bank bar centre */
    animation:vbCheck 12s ease-in-out infinite;
  }
  /* hand-drawn ring around the solved word, from the game's own sketch algorithm */
  .word-circle{
    position:absolute; left:0; top:0; width:144px; height:48px;
    overflow:visible; pointer-events:none; z-index:5;
  }
  .wc-path{
    fill:none; stroke:var(--ink); stroke-width:2.8; stroke-linecap:round;
    --len:324;        /* measured via getTotalLength() */
    stroke-dasharray:var(--len); stroke-dashoffset:var(--len); opacity:.8;
    animation:wordCircle 12s ease-out infinite;
  }
  /* letters nod when they make a word, reusing the real curve */
  @keyframes letterStory{
    0%,42.5%{transform:translate(0,0);}
    43.4%{transform:translate(0,-5px);}
    44.3%{transform:translate(0,1px);}
    45.6%,100%{transform:translate(0,0);}
  }
  @keyframes mvRD{
    0%,23%{transform:translate(0,0) scale(1); opacity:1;}
    25.5%,31%{transform:translate(0,-18px) scale(1.05); opacity:1;}
    34.5%{transform:translate(68px,-18px) scale(1.05); opacity:1;}
    36.5%,91.7%{transform:translate(68px,0) scale(1); opacity:1;}
    94%{transform:translate(68px,0) scale(1); opacity:0;}
    94.5%{transform:translate(0,0) scale(1); opacity:0;}
    96.7%,100%{transform:translate(0,0) scale(1); opacity:1;}
  }
  @keyframes rdShadow{
    0%,23%{box-shadow:inset 0 0 0 1px var(--tile-line);}
    25.5%,34.5%{box-shadow:inset 0 0 0 1px var(--tile-line), 0 6px 11px rgba(20,32,45,.3);}
    36.5%,100%{box-shadow:inset 0 0 0 1px var(--tile-line);}
  }
  @keyframes mvW{
    0%,26%{transform:translate(0,0); opacity:1;}
    29%,91.7%{transform:translate(-68px,0); opacity:1;}
    94%{transform:translate(-68px,0); opacity:0;}
    94.5%{transform:translate(0,0); opacity:0;}
    96.7%,100%{transform:translate(0,0); opacity:1;}
  }
  @keyframes mvO{
    0%,27%{transform:translate(0,0); opacity:1;}
    30%,91.7%{transform:translate(-68px,0); opacity:1;}
    94%{transform:translate(-68px,0); opacity:0;}
    94.5%{transform:translate(0,0); opacity:0;}
    96.7%,100%{transform:translate(0,0); opacity:1;}
  }
  /* the check appears, holds, then funnels down into the word bank bar */
  @keyframes vbCheck{
    0%,45.2%{opacity:0; transform:translate(0,0) scale(.4);}
    46.5%,51.7%{opacity:1; transform:translate(0,0) scale(1);}
    58%{opacity:1; transform:translate(var(--fx),var(--fy)) scale(.45);}
    59.5%,100%{opacity:0; transform:translate(var(--fx),var(--fy)) scale(.3);}
  }
  @keyframes wordCircle{
    0%,76%{stroke-dashoffset:var(--len); opacity:.8;}
    84%,91.7%{stroke-dashoffset:0; opacity:.8;}
    94%{stroke-dashoffset:0; opacity:0;}
    94.1%{stroke-dashoffset:var(--len); opacity:0;}
    96.7%,100%{stroke-dashoffset:var(--len); opacity:.8;}
  }
  /* the check falls past this row's text into the word bank below, so the row
     can't clip it and the text needs to sit above it in the stack */
  #helpPage1 .help-list li{position:relative;}
  /* opaque + above the check so the charge passes behind the copy */
  #helpPage1 .help-text{position:relative; z-index:2; background:var(--surface); text-align:center;}
  .help-h{display:block; color:var(--ink); font-weight:800; margin-bottom:2px;}
  /* -------- win condition: a solved 4x4 grid saluting row by row, then column by
     column (all eight words), then a confetti burst. Shares the 12s clock. -------- */
  .win-note{
    padding-top:10px; border-top:1px solid var(--divider);
    display:flex; align-items:center; justify-content:center; gap:12px;
  }
  .win-demo{position:relative; flex:none; width:56px; height:56px; pointer-events:none;}
  .win-grid{
    display:block; width:56px; height:56px;
    fill:none; stroke:var(--ink-soft); stroke-width:1.1; opacity:.55;
  }
  .wcell{
    position:absolute; width:14px; height:14px;
    display:flex; align-items:center; justify-content:center;
  }
  /* row hop and column hop live on separate elements so each cell can do both */
  .wr{display:flex; animation:rowHop 12s ease-in-out infinite;
      animation-delay:calc(var(--r) * .36s);}
  .wc2{display:flex; animation:colHop 12s ease-in-out infinite;
       animation-delay:calc(var(--c) * .36s);}
  .wchk{width:9px; height:9px; color:var(--ink);}
  @keyframes rowHop{
    0%,20%{transform:translateY(0);}
    20.9%{transform:translateY(-4px);}
    21.8%{transform:translateY(1px);}
    23%,100%{transform:translateY(0);}
  }
  @keyframes colHop{
    0%,36%{transform:translateY(0);}
    36.9%{transform:translateY(-4px);}
    37.8%{transform:translateY(1px);}
    39%,100%{transform:translateY(0);}
  }
  .conf{
    position:absolute; left:50%; top:50%; width:4px; height:6px;
    margin:-3px 0 0 -2px; border-radius:1px; opacity:0; pointer-events:none;
    animation:confBurst 12s ease-out infinite;
  }
  @keyframes confBurst{
    0%,48%{opacity:0; transform:translate(0,0) scale(.4) rotate(0deg);}
    49.5%{opacity:1; transform:translate(calc(var(--ax) * .35), calc(var(--ay) * .35 - 3px)) scale(1) rotate(70deg);}
    54%{opacity:1; transform:translate(calc(var(--ax) * .85), calc(var(--ay) * .85)) scale(1) rotate(210deg);}
    60%,100%{opacity:0; transform:translate(var(--ax), calc(var(--ay) + 10px)) scale(.75) rotate(320deg);}
  }
  .win-line{
    text-align:left; font-size:13.5px; line-height:1.35;
    color:var(--ink); font-weight:800;
  }
  /* -------- row 2: the word's check lands in a little word bank tab and fills
     its bar. Row 3's Grid Check fills on the same beat: they're one meter. -------- */
  .bank-demo{
    position:relative; flex:none; display:flex; flex-direction:column; align-items:center;
    gap:4px; padding:6px 20px 8px; border-radius:11px 11px 0 0;
    background:var(--surface); border:1px solid var(--tile-line); border-bottom:0;
    animation:bankPop 12s ease-in-out infinite;
  }
  .bd-label{font-size:11px; font-weight:800; color:var(--ink-soft);}
  .bd-bar{position:relative; display:block; width:56px; height:4px; border-radius:2px;
    background:var(--track-2); overflow:hidden;}
  .bd-bar i, .gc-fill{position:absolute; left:0; top:0; bottom:0; width:0;
    background:var(--charge); animation:bankFill 12s ease-in-out infinite;}
  @keyframes bankFill{
    0%,55.5%{width:0;}
    58%{width:40%;}
    60%,91.7%{width:100%;}
    95%,100%{width:0;}
  }
  @keyframes bankPop{
    0%,60%{transform:scale(1);}
    61.5%{transform:scale(1.08);}
    63%,100%{transform:scale(1);}
  }
  /* -------- row 3: Grid Check, full once the bar is, pressed -> WORD circled -------- */
  .gc-row{
    position:relative; flex:none;
    display:flex; align-items:center; justify-content:center;
    width:84px; height:32px;
  }
  .gc-demo{
    position:relative; overflow:hidden; isolation:isolate;
    display:flex; align-items:center; justify-content:center;
    width:84px; height:30px; border-radius:9px; background:var(--track);
    font-size:10.5px; font-weight:800; white-space:nowrap;
    animation:gcText 12s ease-in-out infinite, gcPress 12s ease-in-out infinite;
  }
  .gc-fill{z-index:-1;}
  @keyframes gcText{
    0%,59%{color:var(--ink-soft);}
    61%,91.7%{color:#fff;}
    95%,100%{color:var(--ink-soft);}
  }
  /* pressing it is what reveals the word */
  @keyframes gcPress{
    0%,74%{transform:scale(1);}
    74.8%{transform:scale(.93);}
    75.8%,100%{transform:scale(1);}
  }
  /* the word Grid Check confirms, circled with the same gesture the board gets */
  .mini-word{
    position:absolute; left:96px; top:50%; margin-top:-11px;
    width:48px; height:22px;
    display:flex; align-items:center; justify-content:center;
    opacity:0; pointer-events:none;
    animation:miniWordFade 12s ease-in-out infinite;
  }
  .mw-text{
    font-family:'Archivo',sans-serif; font-weight:800; font-size:9.5px;
    letter-spacing:.05em; color:var(--ink);
  }
  .mw-circle{position:absolute; left:0; top:0; width:48px; height:22px; overflow:visible;}
  .mwc-path{
    fill:none; stroke:var(--ink); stroke-width:1.5; stroke-linecap:round;
    --mlen:101.3;     /* measured via getTotalLength() */
    stroke-dasharray:var(--mlen); stroke-dashoffset:var(--mlen); opacity:.8;
    animation:miniCircle 12s ease-out infinite;
  }
  @keyframes miniWordFade{
    0%,71%{opacity:0;}
    73%,91.7%{opacity:1;}
    94%,100%{opacity:0;}
  }
  @keyframes miniCircle{
    0%,76%{stroke-dashoffset:var(--mlen); opacity:.8;}
    83%,91.7%{stroke-dashoffset:0; opacity:.8;}
    94%{stroke-dashoffset:0; opacity:0;}
    94.1%{stroke-dashoffset:var(--mlen); opacity:0;}
    96.7%,100%{stroke-dashoffset:var(--mlen); opacity:.8;}
  }
  /* gesture tips: tap counts instead of a drawing */
  .tap-icon{font-size:11px; font-weight:800; letter-spacing:-.02em;}
  .hk{
    display:inline-block; min-width:64px; font-weight:800; color:var(--ink);
  }
  .help-tip.stats-note{margin-top:12px; font-size:12px; font-style:normal;}
  .stats-note p{margin:0;}
  .share-time.stats-toggle{justify-content:flex-start; margin-top:8px; font-size:12.5px;}
  .help-tip{
    font-size:13px; font-style:italic; color:var(--ink-soft);
    background:var(--surface-soft); border-radius:9px; padding:9px 11px; margin:0;
  }
  .help-version{
    text-align:center; font-size:10.5px; font-weight:700; color:var(--tile-line);
    margin-top:12px; letter-spacing:.04em;
  }
    .eyebrow{
    font-size:11px; font-weight:700; letter-spacing:.18em; text-transform:uppercase;
    color:var(--ink-soft); margin-bottom:6px;
  }
  h1{
    font-family:'Fraunces',serif; font-weight:620; font-size:clamp(30px,7vw,42px);
    margin:0; letter-spacing:-.01em;
  }

  .tagline{color:var(--ink-soft); font-size:13.5px; max-width:340px; margin:8px auto 0; line-height:1.45;}

  .modes{display:none;}

  #boardWrap{width:100%; max-width:560px; display:flex; justify-content:center; margin-top:12px;}
  #board{
    position:relative; border-radius:18px; background:var(--well);
    box-shadow:inset 0 2px 6px rgba(25,40,55,.16);
    touch-action:none;
  }
  #board.free{background:var(--well-outer);}
  #zone{
    position:absolute; background:var(--zone);
    box-shadow:inset 0 0 0 1px var(--tile-line);
    display:block; pointer-events:none;
  }

  .tile{
    position:absolute; left:0; top:0;
    background:var(--tile);
    display:flex; align-items:center; justify-content:center;
    cursor:pointer; user-select:none;
    transition:transform .18s cubic-bezier(.3,.9,.4,1.1);
    will-change:transform;
  }
  .tile .letter{
    font-weight:800; color:var(--ink); text-transform:uppercase;
    display:inline-block; line-height:1;
  }
  .tile.sel{z-index:6; filter:brightness(1.04);}
  .tile.anchorsel{z-index:7;}
  .tile.anchorsel .letter{position:relative; z-index:2;}
  .tile.anchorsel::after{
    content:''; position:absolute;
    left:var(--sqoff); top:var(--sqoff);
    width:var(--sq); height:var(--sq);
    border-radius:8px;
    background:color-mix(in srgb, var(--ink) 15%, transparent);
    pointer-events:none; z-index:1;
  }
  .seam{position:absolute; background:rgba(34,48,63,.14); pointer-events:none; border-radius:2px;}

  .verdict-badge{
    position:absolute; left:0; top:0; display:flex; align-items:center; justify-content:center;
    border-radius:50%; font-weight:900; line-height:1;
    pointer-events:none; z-index:8; opacity:0;
    color:var(--ink); background:transparent;
  }
  .verdict-badge.star{background:var(--charge); color:#fff;}      /* Grid Check: in the puzzle */
  .verdict-badge.good.unique{background:var(--charge); color:#fff;}

  /* hand-drawn scribble across a word that's valid but not in the puzzle */
  .scribble{position:absolute; left:0; top:0; pointer-events:none; z-index:7;}
  .scribble-path{
    fill:none; stroke:var(--ink); stroke-width:2.5; stroke-linecap:round; opacity:.7;
  }
  .circle-path{stroke-width:2.8; opacity:.8;}

  /* flying word clone (board → meter, or board → word list) */
  .fly-dot{
    position:fixed; z-index:60; pointer-events:none; border-radius:50%;
    width:9px; height:9px; background:var(--charge);
    transform:translate(-50%,-50%); box-shadow:0 3px 10px rgba(20,32,45,.28);
  }

  /* Check sits alone at the end of the actions row */
  .check-group{display:flex; align-items:center;}
  .check-group[hidden]{display:none;}
  #submitBtn{
    flex:none; white-space:nowrap; height:44px; padding:0 24px;
    display:flex; align-items:center; justify-content:center;
    transition:background .12s ease;
  }
  .check-label{display:inline-block; white-space:nowrap;}
  #submitBtn.pressed{background:#16307A;}
  /* per-letter spans so a label can ripple as one phrase */
  .ltr{display:inline-block; will-change:transform;}

  /* Word bank: fixed drawer that folds up from the bottom, never pushes page content */
  #drawer{
    position:fixed; left:0; right:0; bottom:0; z-index:40; display:flex;
    flex-direction:column; align-items:stretch;
    padding-bottom:env(safe-area-inset-bottom, 0px);
    filter:drop-shadow(0 -2px 8px rgba(20,32,45,.10));
  }
  #drawer.open, #drawer.peek{padding-bottom:0;}
  /* wide screens: the word bank is a panel the width of the board, not a band
     across the whole monitor (phones keep it edge to edge) */
  @media (min-width:700px){
    #drawer{left:50%; right:auto; width:var(--board-w, 504px); transform:translateX(-50%);}
    #drawerPanel{box-shadow:inset 1.25px 0 0 var(--tile-line), inset -1.25px 0 0 var(--tile-line);}
  }
  /* the top edge — including the pull tab — is one continuous drawn shape */
  #drawerTop{position:relative; height:42px;}
  #drawerTopSvg{position:absolute; left:0; top:0; width:100%; height:100%; display:block;}
  #drawerFillPath{fill:var(--surface);}
  #drawerEdgePath{fill:none; stroke:var(--tile-line); stroke-width:1.25;}
  #drawerTab{
    position:absolute; left:50%; top:0; transform:translateX(-50%);
    height:42px; background:transparent; border:0; padding:0 24px;
    display:flex; align-items:center; justify-content:center; gap:8px;
    font:inherit; font-weight:800; font-size:14px; color:var(--ink-soft);
    cursor:pointer; touch-action:manipulation; z-index:2; white-space:nowrap;
  }
  #drawer.open #drawerTab, #drawer.peek #drawerTab{color:var(--ink);}
  #drawerTab .chevron{transition:transform .25s;}
  #drawer.open #drawerTab .chevron{transform:rotate(180deg);}
  #drawerPanel{
    background:var(--surface); max-height:0;
    overflow:hidden; transition:max-height .3s ease;
  }
  #drawer.open #drawerPanel{max-height:44vh; overflow-y:auto;}
  /* peek: a one-row ticker window used while Super Check banks words */
  #drawer.peek #drawerPanel{max-height:74px; overflow:hidden;}
  #wordLists{display:flex; gap:22px; justify-content:center; text-align:left;
    padding:4px 18px calc(18px + env(safe-area-inset-bottom, 0px));}
  .wl{flex:1; max-width:170px;}
  .wl-empty{margin:4px 0 0; max-width:320px; text-align:center; font-size:15px;
    line-height:1.45; color:var(--ink-soft);}
  /* found but not checked yet: quieter than the sorted lists */
  #wordLists{flex-wrap:wrap;}
  .wl.found{flex-basis:100%; max-width:none;}
  .wl.found ul{display:flex; flex-wrap:wrap; gap:0 14px;}
  .wl.found li{color:var(--ink-soft); opacity:.75; font-size:19px;}
  /* how many words are waiting to be sorted */
  .wl-count{display:inline-block; min-width:18px; margin-left:5px; padding:1px 5px;
    border-radius:8px; background:var(--track); color:var(--ink-soft);
    font-size:10.5px; letter-spacing:0; text-align:center; box-sizing:border-box;}

  /* charge bar under the word bank label (full = a Grid Check is ready) */
  /* label + chevron on one row, the bar centred under the whole tab */
  .tab-text{display:flex; flex-direction:column; align-items:center; gap:4px;}
  .tab-row{display:flex; align-items:center; gap:8px;}
  #drawerTabLabel{display:inline-flex; align-items:center;}
  .tab-counts{display:inline-flex; align-items:center; gap:6px; margin-left:8px;
    font-size:11.5px; font-weight:800; color:var(--ink);}
  .tc-in{display:inline-flex; align-items:center; justify-content:center;
    min-width:17px; height:17px; padding:0 3px; box-sizing:border-box;
    border:1.5px solid var(--ink); border-radius:9px;}
  .tc-found{color:var(--ink-soft); opacity:.8;}
  /* a drawn line rather than text-decoration, which sits off-centre on digits */
  .tc-out{position:relative; color:var(--ink-soft); padding:0 2px;}
  .tc-out::after{content:''; position:absolute; left:0; right:0; top:50%; height:1.5px;
    margin-top:-.75px; border-radius:1px; background:currentColor;}
  .bank-bar-wrap{position:relative; width:84px;}
  .bank-bar{display:block; height:4px; border-radius:2px; background:var(--track-2); overflow:hidden;
    transition:opacity .2s ease;}
  #bankBarFill{display:block; height:100%; width:0%; background:var(--charge);
    transition:width .4s cubic-bezier(.3,.9,.4,1);}
  #drawer.open .bank-bar{opacity:0;}          /* it became the Grid Check button */
  .bank-badge{position:absolute; min-width:15px; height:15px;
    padding:0 3px; border-radius:8px; background:var(--ink); color:var(--surface);
    font-size:9.5px; font-weight:800; display:none; align-items:center; justify-content:center;
    line-height:1; box-shadow:0 0 0 2px var(--surface); box-sizing:border-box;}
  .bank-badge.show{display:flex;}

  /* the Grid Check lives at the top of the open drawer; it's its own meter too —
     blue fills it left to right as it charges */
  .bank-actions{display:flex; flex-direction:column; align-items:center; gap:5px;
    padding:6px 18px 8px;}
  .btn.bank-check{position:relative; isolation:isolate; background:var(--track); color:var(--ink);
    padding:10px 26px;}
  .bank-check-fill{position:absolute; inset:0; border-radius:inherit; overflow:hidden; z-index:-1;}
  #bankCheckFill{position:absolute; left:0; top:0; bottom:0; width:var(--fill, 0%);
    background:var(--charge); transition:width .4s cubic-bezier(.3,.9,.4,1), background .12s ease;}
  .bank-check.no-anim #bankCheckFill{transition:none;}
  .btn.bank-check:disabled, .btn.bank-check.uncharged{opacity:1; color:var(--ink-soft);}
  .btn.bank-check.uncharged{cursor:pointer;}
  .btn.bank-check.pressed #bankCheckFill{background:var(--charge-press);}
  /* white copy of the label, clipped to the fill: white on blue, dark on gray */
  .bank-check-over{position:absolute; inset:0; display:flex; align-items:center;
    justify-content:center; color:#fff; pointer-events:none;
    clip-path:inset(0 calc(100% - var(--fill, 0%)) 0 0);
    transition:clip-path .4s cubic-bezier(.3,.9,.4,1);}
  .bank-check.no-anim .bank-check-over{transition:none;}
  .bank-check .bank-badge{top:-6px; right:-6px;}
  /* once the puzzle is solved, the button becomes Show solution (purple) */
  .bank-check .lbl-solve{display:none;}
  .bank-check.solution .lbl-check{display:none;}
  .bank-check.solution .lbl-solve{display:inline;}
  .btn.bank-check.solution{color:#fff;}
  .bank-check.solution #bankCheckFill{background:var(--purple);}
  .btn.bank-check.solution.pressed #bankCheckFill{background:#5E43B4;}
  #drawerTab.solved #bankBarFill{background:var(--purple);}
  /* Grid Check couldn't run: the empty squares of the 4×4 blink */
  .empty-flash{position:absolute; z-index:1; pointer-events:none;
    background:color-mix(in srgb, var(--charge) 14%, transparent);
    box-shadow:inset 0 0 0 2.5px var(--charge);}   /* a ring, so it can't pass for a tile */
  /* the tab's bar growing into the button as the drawer opens */
  .bar-morph{position:fixed; z-index:60; overflow:hidden; background:var(--track); pointer-events:none;}
  .bar-morph i{position:absolute; left:0; top:0; bottom:0; background:var(--charge);}
  /* Recent · A–Z: small text at the right end of the Found header line */
  .wl.found h4{display:flex; align-items:baseline; justify-content:space-between; gap:10px;}
  .wl-sortline{flex-basis:100%; display:flex; justify-content:flex-end; margin-bottom:-4px;}
  .bank-sort{display:inline-flex; align-items:baseline; gap:4px; font-size:10px; letter-spacing:.08em;
    text-transform:uppercase; font-weight:700; color:var(--ink-soft);}
  .bank-sort i{font-style:normal; opacity:.6;}
  .bank-sort button{border:0; background:transparent; padding:8px 3px; margin:-8px -3px; cursor:pointer;   /* small text, finger-sized target */
    font:inherit; letter-spacing:inherit; text-transform:inherit; color:inherit; opacity:.75;
    touch-action:manipulation;}
  .bank-sort button.on{color:var(--ink); opacity:1; font-weight:800; text-decoration:underline;
    text-underline-offset:3px; text-decoration-thickness:1.5px;}
  .bank-hint{font-size:12.5px; font-weight:600; color:var(--ink-soft); min-height:16px;}
  .wl h4{
    margin:0 0 6px; font-size:11px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--ink-soft); font-weight:800;
  }
  .wl ul{margin:0; padding:0; list-style:none;}
  .wl li{
    font-size:23px; font-weight:800; letter-spacing:.06em; padding:1px 0;
    color:var(--ink); border-radius:4px; line-height:1.28;
  }
  .wl.out li{color:var(--ink-soft); text-decoration:line-through;
    text-decoration-thickness:2px;}
  .wl.in h4{color:var(--good);}

  @keyframes nod{
    0%,100%{transform:translateY(0)} 30%{transform:translateY(-9px)} 60%{transform:translateY(2px)}
  }
  @keyframes shake{
    0%,100%{transform:translateX(0)} 20%{transform:translateX(-6px)} 40%{transform:translateX(6px)}
    60%{transform:translateX(-4px)} 80%{transform:translateX(4px)}
  }
  .letter.nod{animation:nod .37s both;}
  .letter.shake{animation:shake .33s both;}
  @keyframes tileshake{
    0%,100%{margin-left:0} 25%{margin-left:-4px} 75%{margin-left:4px}
  }
  .tile.jolt{animation:tileshake .3s 2;}

  #msg{
    min-height:20px; margin-top:10px; font-size:14px; font-weight:600;
    color:var(--ink-soft); text-align:center; padding:0 10px; transition:color .2s;
    max-width:var(--board-w, 560px); text-wrap:balance;
  }
  #msg.bad{color:var(--bad);} #msg.good{color:var(--good);}

  .actions{display:flex; gap:7px; margin-top:9px; align-items:center;
    max-width:100%; flex-wrap:nowrap;}
  .btn{
    font:inherit; font-weight:800; font-size:15px; border:0; cursor:pointer;
    border-radius:12px; padding:12px 26px; touch-action:manipulation;
  }
  .btn:focus-visible{outline:2px solid var(--ink); outline-offset:2px;}
  .btn.primary{background:var(--accent); color:#fff; transition:background .12s ease;}
  .btn.primary:active{background:#16307A;}
  .btn.ghost{background:transparent; color:var(--ink-soft); font-weight:700; padding:12px 10px;}
  .btn.ghost:hover{color:var(--ink);}
  .btn:disabled{opacity:.35; cursor:default;}
  .btn.icon{
    background:var(--surface); color:var(--ink); border:1px solid var(--tile-line);
    padding:0; width:44px; height:44px; font-size:20px; line-height:1;
    display:flex; align-items:center; justify-content:center;
  }
  .btn.icon:not(:disabled):hover{border-color:var(--accent); color:var(--accent);}

  .tile{cursor:grab; touch-action:none;}
  .tile.dragging{cursor:grabbing; z-index:20; transition:none; filter:brightness(1.03);}
  #board.dragging .tile:not(.dragging){transition:transform .16s cubic-bezier(.3,.9,.4,1.1);}

  /* ghost landing preview (contiguous silhouette drawn in JS) */
  .move-ghost{
    position:absolute; left:0; top:0; pointer-events:none; z-index:2;
    box-sizing:border-box;
    transition:transform .09s linear, opacity .12s;
  }

  .meta{
    display:flex; gap:18px; align-items:center; margin-top:18px;
    font-size:13px; font-weight:600; color:var(--ink-soft); flex-wrap:wrap; justify-content:center;
  }
  .nav{display:flex; align-items:center; gap:6px;}
  .nav button{
    border:1px solid var(--tile-line); background:var(--surface); border-radius:8px;
    width:28px; height:28px; cursor:pointer; font-weight:800; color:var(--ink);
    touch-action:manipulation;
  }
  #foundLabel b{color:var(--accent);}
  .solved{color:var(--good); font-weight:800; margin-left:2px;}
  #reveal{background:none; border:0; font:inherit; font-size:12.5px; color:var(--ink-soft);
    text-decoration:underline; cursor:pointer; margin-top:14px;}
  .footlinks{display:flex; gap:18px; justify-content:center; margin-top:14px;}
  .footlinks button{background:none; border:0; font:inherit; font-size:12.5px;
    color:var(--ink-soft); text-decoration:underline; cursor:pointer; touch-action:manipulation;}
  .footlinks button:hover{color:var(--ink);}
  #reveal{margin-top:0;}

  /* rating widget */

  #overlay{
    position:fixed; inset:0; background:rgba(28,40,54,.45); display:none;
    align-items:center; justify-content:center; z-index:50; padding:20px;
  }
  #overlay.show{display:flex;}
  .card{
    background:var(--surface); border-radius:20px; padding:30px 34px; text-align:center; max-width:330px;
    animation:pop .35s cubic-bezier(.2,1.4,.4,1) both;
    box-shadow:0 18px 50px rgba(20,32,45,.35);
    max-height:calc(100vh - 40px); overflow-y:auto; -webkit-overflow-scrolling:touch;
  }
  .card-actions{display:flex; flex-direction:column; gap:9px; margin-top:16px;}
  /* "Share my time": a small switch under the result, off unless the player turns it on */
  .share-time{display:flex; align-items:center; justify-content:center; gap:9px; margin-top:12px;
    font-size:13.5px; font-weight:700; color:var(--ink-soft); cursor:pointer; user-select:none;
    touch-action:manipulation;}
  .share-time[hidden]{display:none;}
  .share-time input{position:absolute; opacity:0; width:1px; height:1px;}
  .st-switch{position:relative; flex:none; width:34px; height:20px; border-radius:10px;
    background:var(--track-2); transition:background .2s ease;}
  .st-switch::after{content:''; position:absolute; top:2px; left:2px; width:16px; height:16px;
    border-radius:50%; background:var(--surface); box-shadow:0 1px 2px rgba(20,32,45,.25);
    transition:transform .2s ease;}
  .share-time input:checked + .st-switch{background:var(--accent);}
  .share-time input:checked + .st-switch::after{transform:translateX(14px);}
  .share-time input:focus-visible + .st-switch{outline:2px solid var(--ink); outline-offset:2px;}
  .share-timeline{margin-top:4px;}
  .card-actions .btn{width:100%; box-sizing:border-box; margin:0;}
  /* secondary buttons in cards: a soft fill so they read as buttons (flat, no shadow) */
  .card .btn.ghost{background:var(--track); color:var(--ink); padding:11px 14px;}
  .card .btn.ghost:hover{background:var(--track-2);}
  .card .btn.ghost:active, .card .btn.ghost.pressed{background:var(--track-2);}
  /* ← Back and the next page share a row */
  .card-nav{display:flex; gap:9px;}
  .card-nav .btn{flex:1; min-width:0;}

  .confetti{
    position:fixed; z-index:70; pointer-events:none;
    transform:translate(-50%,-50%); will-change:transform, opacity;
  }

  #nextIn{
    display:none; font-size:12.5px; font-weight:800; color:var(--ink-soft);
    margin-top:12px; letter-spacing:.03em;
  }
  #nextIn.show{display:block;}
  #shareNote{
    display:none; font-size:11px; font-weight:700; color:var(--ink-soft);
    margin-top:8px; letter-spacing:.02em;
  }
  #shareNote.show{display:block;}
  #shareFallback{
    display:none; width:100%; box-sizing:border-box; margin:8px 0 2px;
    font-family:inherit; font-size:16px; line-height:1.5; text-align:center;
    border:1px solid var(--tile-line); border-radius:10px; padding:8px;
    background:var(--surface-soft); color:var(--ink); resize:none;
  }
  #shareFallback.show{display:block;}

  /* win summary / share grid */
  #shareBlock{display:none; margin:2px 0 6px;}
  #shareBlock.show{display:block;}
  .share-title{
    font-weight:800; font-size:12px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--ink-soft); margin-bottom:7px;
  }
  .share-line{
    font-size:15px; line-height:1.65; letter-spacing:.02em; white-space:nowrap;
  }
  .share-count{
    font-size:12.5px; font-weight:800; color:var(--ink-soft); margin-top:7px;
    letter-spacing:.03em;
  }
  @keyframes pop{from{transform:scale(.7); opacity:0}}
  .card h2{font-family:'Fraunces',serif; font-weight:620; margin:0 0 8px; font-size:26px;}
  .card p{margin:0 0 18px; color:var(--ink-soft); font-size:14.5px; line-height:1.5;}
  .card .words{font-weight:800; letter-spacing:.14em; color:var(--ink); font-size:13px; margin-bottom:16px;}
  .card .words:empty{display:none;}
  .card p:empty{display:none;}

  @media (prefers-reduced-motion: reduce){
    .tile{transition:none;}
    .letter.nod,.letter.shake,.tile.jolt,.card{animation:none !important;}
  }
