/* ==========================================================================
   NoClue — application stylesheet

   CONTENTS
     1. Design tokens        light + dark, system pref with manual override
     2. Reset
     3. Base elements        themed
     4. Utilities
     5. Design system        the reskin: shell, home, play, modals, panels
     6. Legacy layer         Bulma compatibility shim — DELETE AS YOU RESKIN

   Section 6 keeps the not-yet-reskinned pages rendering as they did under
   Bulma 1.0.2. Those pages carry `class="legacy"` on <body>, which pins them
   to the old light palette so theming can't reach them mid-migration.

   Reskinned: base.html (shell), index, noclue4x, stats, account, signin, share
   Still legacy: admin, privacy
   ========================================================================== */


/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */

:root {
  --paper:   oklch(0.972 0.012 85);
  --paper2:  oklch(0.945 0.016 82);
  --card:    oklch(0.995 0.004 85);

  --ink:     oklch(0.24 0.018 60);
  --ink2:    oklch(0.44 0.014 60);
  /* Handoff specifies 0.56, which measures 4.31:1 on --paper and misses AA.
     0.545 gives 4.52:1. Most labels sit on --paper, not --card. */
  --ink3:    oklch(0.545 0.014 60);

  /* --rule is decorative and may sit below 3:1.
     --edge is for anything the user acts on and must clear it.
     Do not collapse these into one. */
  --rule:    oklch(0.80 0.014 70);
  --edge:    oklch(0.62 0.016 70);

  --clay:    oklch(0.52 0.14 32);
  --moss:    oklch(0.46 0.12 148);
  --sky:     oklch(0.48 0.12 245);
  --focus:   oklch(0.52 0.14 32);

  --curtain:    oklch(0.20 0.016 60);
  --curtain-fg: oklch(0.97 0.008 85);
  --scrim:      color-mix(in oklab, oklch(0.24 0.018 60) 55%, transparent);

  --btn-solid-fg: var(--paper);
}

:root[data-theme="dark"] {
  --paper:   oklch(0.205 0.012 70);
  --paper2:  oklch(0.255 0.013 70);
  --card:    oklch(0.238 0.013 70);

  --ink:     oklch(0.955 0.008 85);
  --ink2:    oklch(0.79 0.010 85);
  --ink3:    oklch(0.67 0.012 85);

  --rule:    oklch(0.37 0.012 70);
  --edge:    oklch(0.52 0.014 70);

  --clay:    oklch(0.72 0.12 42);
  --moss:    oklch(0.70 0.11 150);
  --sky:     oklch(0.74 0.10 240);
  --focus:   oklch(0.72 0.12 42);

  --scrim:   color-mix(in oklab, oklch(0.12 0.012 70) 78%, transparent);

  /* solid buttons and filled tiles need dark ink on a light fill */
  --btn-solid-fg: oklch(0.19 0.012 70);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:   oklch(0.205 0.012 70);
    --paper2:  oklch(0.255 0.013 70);
    --card:    oklch(0.238 0.013 70);

    --ink:     oklch(0.955 0.008 85);
    --ink2:    oklch(0.79 0.010 85);
    --ink3:    oklch(0.67 0.012 85);

    --rule:    oklch(0.37 0.012 70);
    --edge:    oklch(0.52 0.014 70);

    --clay:    oklch(0.72 0.12 42);
    --moss:    oklch(0.70 0.11 150);
    --sky:     oklch(0.74 0.10 240);
    --focus:   oklch(0.72 0.12 42);

    --scrim:   color-mix(in oklab, oklch(0.12 0.012 70) 78%, transparent);
    --btn-solid-fg: oklch(0.19 0.012 70);
  }
}


/* ==========================================================================
   2. RESET
   ========================================================================== */

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

html, body, p, ol, ul, li, dl, dt, dd, blockquote, figure, fieldset, legend,
textarea, pre, iframe, hr, h1, h2, h3, h4, h5, h6 { margin: 0; padding: 0; }

h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal; }
ul { list-style: none; }
button, input, select, textarea { margin: 0; }
img, video { height: auto; max-width: 100%; }
svg { height: auto; width: auto; }
iframe { border: 0; }
fieldset { border: none; }
table { border-collapse: collapse; border-spacing: 0; }
td, th { padding: 0; }
td:not([align]), th:not([align]) { text-align: inherit; }
article, aside, figure, footer, header, hgroup, section { display: block; }
input[type="checkbox"], input[type="radio"] { vertical-align: baseline; }
span { font-style: inherit; font-weight: inherit; }

button {
  appearance: none;
  background: none;
  border: none;
  color: inherit;
  font-family: inherit;
  font-size: 1em;
  margin: 0;
  padding: 0;
}


/* ==========================================================================
   3. BASE ELEMENTS
   ========================================================================== */

html {
  font-size: 1em;
  min-width: 300px;
  overflow-x: hidden;
  overflow-y: scroll;
  text-rendering: optimizeLegibility;
  text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: Archivo, Helvetica, Arial, sans-serif;
  font-size: 1em;
  font-weight: 400;
  line-height: 1.5;
  text-wrap: pretty;
}

body, button, input, optgroup, select, textarea {
  font-family: Archivo, Helvetica, Arial, sans-serif;
}

a { color: var(--clay); cursor: pointer; text-decoration: none; }
a:hover { color: var(--ink); }
a strong { color: currentColor; }

strong { color: var(--ink); font-weight: 600; }
small { font-size: 0.875em; }

hr { background: var(--rule); border: none; display: block; height: 1px; margin: 1.5rem 0; }

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

[hidden] { display: none !important; }

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


/* ==========================================================================
   4. UTILITIES
   ========================================================================== */

.sr-only,
.sr,
.is-sr-only {
  border: none !important;
  clip: rect(0, 0, 0, 0) !important;
  clip-path: inset(50%) !important;
  height: 0.01em !important;
  overflow: hidden !important;
  padding: 0 !important;
  position: absolute !important;
  white-space: nowrap !important;
  width: 0.01em !important;
}

.hidden, .is-hidden { display: none !important; }

[x-cloak] { display: none !important; }

/* Inline SVG icons, replacing the Font Awesome webfont. */
.ic {
  display: inline-block;
  fill: currentColor;
  height: 1em;
  vertical-align: -0.125em;
  width: 1em;
}
.ic-lg { font-size: 1.25em; }
.ic-2x { font-size: 2em; }


/* ==========================================================================
   5. DESIGN SYSTEM
   ========================================================================== */

.wrap { max-width: 680px; margin: 0 auto; padding: 0 20px; }

.serif { font-family: "Instrument Serif", Georgia, serif; font-weight: 400; }

.lbl {
  color: var(--ink3);
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.center { text-align: center; }
.note   { color: var(--ink3); font-size: 13.5px; line-height: 1.55; }
.stack  { display: grid; gap: 16px; justify-items: center; width: 100%; }
.hr     { background: var(--rule); height: 1px; margin: 24px 0; }

.tnum { font-variant-numeric: tabular-nums; }

/* --- shell ---------------------------------------------------------------- */

/* The translucent blur lives on a pseudo-element rather than on the header
   itself. In Safari a sticky element that is its own backdrop root leaves
   stale paint in the region below it when that content changes height — which
   is exactly what happens on the home page when Alpine swaps the loading
   state for the taller solved state. The result was half-drawn glyphs and
   text runs that never painted, cleared by any scroll or resize.

   Moving the backdrop-filter into ::before scopes the backdrop root to the
   pseudo-element and keeps the header out of the content's paint path;
   isolation gives it its own stacking context. Visually identical.

   Deliberately no transform/will-change here: promoting the layer that way
   is the other common workaround, but a transform on a sticky element can
   break the stickiness in some Safari versions, which would be a worse
   regression than the artifact. */
header.site {
  background: transparent;
  border-bottom: 1px solid var(--rule);
  isolation: isolate;
  position: sticky;
  top: 0;
  z-index: 30;
}
header.site::before {
  background: color-mix(in oklab, var(--paper) 90%, transparent);
  content: "";
  inset: 0;
  position: absolute;
  z-index: -1;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

/* Play view: the header scrolls away rather than holding 62px of viewport for
   the whole game. It's still there at the top — noclue4x.html nudges the page
   past it on arrival so the board starts at the top of the screen, and
   scrolling up brings it back. */
body.play header.site { position: static; }
.bar {
  align-items: center;
  display: flex;
  gap: 20px;
  height: 62px;
  margin: 0 auto;
  max-width: 680px;
  padding: 0 20px;
}
.mark {
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 27px;
  line-height: 1;
  padding: 0;
  text-decoration: none;
}
.mark i { color: var(--clay); font-style: italic; }

nav.top { align-items: center; display: flex; gap: 20px; margin-left: auto; }
nav.top a {
  color: var(--ink2);
  cursor: pointer;
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-decoration: none;
  text-transform: uppercase;
}
nav.top a:hover { color: var(--ink); }
nav.top a[aria-current="page"] { color: var(--ink); box-shadow: 0 6px 0 -5px var(--clay); }

/* Play is disabled once today's puzzle is solved — there is nothing to play
   until the next rollover. Muted rather than hidden so the nav doesn't shift. */
nav.top a[aria-disabled="true"],
.drawer a[aria-disabled="true"] {
  color: var(--ink3);
  cursor: default;
  pointer-events: none;
}
nav.top a[aria-disabled="true"]:hover,
.drawer a[aria-disabled="true"]:hover { color: var(--ink3); }

.themebtn {
  background: none;
  border: 1px solid var(--edge);
  border-radius: 2px;
  color: var(--ink2);
  cursor: pointer;
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  padding: 7px 11px;
  text-transform: uppercase;
}
.themebtn:hover { border-color: var(--edge); color: var(--ink); }

.burger {
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: 2px;
  cursor: pointer;
  display: none;
  height: 38px;
  margin-left: auto;
  padding: 0;
  place-items: center;
  width: 38px;
}
.burger span { background: var(--ink); display: block; height: 1.5px; margin: 3px auto; width: 16px; }

.drawer { background: var(--card); border-bottom: 1px solid var(--rule); display: none; }
.drawer.open { display: block; }
.drawer a {
  border-top: 1px solid var(--rule);
  color: var(--ink2);
  display: block;
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  padding: 14px 20px;
  text-decoration: none;
  text-transform: uppercase;
}
.drawer a:first-child { border-top: 0; }

/* --- buttons -------------------------------------------------------------- */

.btn {
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 2px;
  color: var(--btn-solid-fg);
  cursor: pointer;
  display: inline-block;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 13px 22px;
  text-align: center;
  text-decoration: none;
}
.btn:hover { background: var(--clay); border-color: var(--clay); color: var(--btn-solid-fg); }
.btn.ghost { background: none; color: var(--ink); }
.btn.ghost:hover { background: var(--ink); color: var(--btn-solid-fg); }
.btn.sm { font-size: 13px; padding: 9px 15px; }
.btn.lg { font-size: 16px; padding: 16px 40px; }
.btn[disabled],
.btn.is-loading {
  background: var(--paper2);
  border-color: var(--rule);
  color: var(--ink3);
  cursor: not-allowed;
  opacity: 0.45;
}
.btn[disabled]:hover,
.btn.is-loading:hover { background: var(--paper2); border-color: var(--rule); color: var(--ink3); }

.tool {
  background: none;
  border: 1px solid var(--edge);
  border-radius: 2px;
  color: var(--ink2);
  cursor: pointer;
  font: inherit;
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  padding: 8px 13px;
  text-transform: uppercase;
}
.tool:hover { border-color: var(--edge); color: var(--ink); }
.tools { display: flex; gap: 10px; justify-content: center; padding: 6px 0 0; }

.spin {
  animation: sp 0.9s linear infinite;
  border: 2px solid var(--rule);
  border-radius: 50%;
  border-top-color: var(--clay);
  height: 26px;
  margin: 0 auto;
  width: 26px;
}
@keyframes sp { to { transform: rotate(360deg); } }

/* --- home ----------------------------------------------------------------- */

/* Vertical only. `.home` sits on the same element as `.wrap`, so a padding
   shorthand here would reset .wrap's 20px side padding and run the content
   into the edge of the screen. Same for .page below. */
.home { padding-top: 52px; padding-bottom: 70px; text-align: center; }
.home h1 {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(44px, 10vw, 68px);
  font-weight: 400;
  letter-spacing: -0.015em;
  line-height: 0.96;
  margin: 0;
}
.home h1 em { color: var(--clay); font-style: normal; }
.home .sub  { color: var(--ink2); font-size: 16px; line-height: 1.5; margin: 16px 0 0; }
.home .date { margin-top: 22px; }

.homeslot { display: grid; margin-top: 34px; min-height: 220px; place-items: center; }

.guest {
  align-items: center;
  background: var(--card);
  border: 1px solid var(--rule);
  color: var(--ink2);
  display: flex;
  flex-wrap: wrap;
  font-size: 13.5px;
  gap: 12px;
  justify-content: center;
  line-height: 1.5;
  margin: 30px 0 0;
  padding: 14px 16px;
  text-align: left;
}
.guest b  { color: var(--ink); font-weight: 600; }
.guest .gt { flex: 1; min-width: 210px; }
.guest .ga { display: flex; flex-wrap: wrap; gap: 8px; }

.status {
  align-items: center;
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: 2px;
  color: var(--ink2);
  display: inline-flex;
  font-size: 13.5px;
  gap: 9px;
  padding: 9px 15px;
}
.status .dot { background: var(--sky); border-radius: 50%; height: 8px; width: 8px; }
.status.done .dot { background: var(--moss); }

.scorewrap { display: grid; gap: 2px; justify-items: center; }
.bigscore {
  color: var(--clay);
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 92px;
  font-variant-numeric: tabular-nums;
  line-height: 0.9;
}
.bigscore small { color: var(--ink3); font-size: 26px; letter-spacing: 0.02em; }

.solveline { color: var(--ink2); font-size: 16px; line-height: 1.55; max-width: 34ch; }
.solveline b {
  color: var(--ink);
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 22px;
  font-weight: 400;
}

.rowbtns { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.credit  { color: var(--ink3); font-size: 13.5px; margin-top: 44px; }
.empty   { background: var(--card); border: 1px solid var(--rule); max-width: 420px; padding: 26px 22px; }

/* --- grid + tiles --------------------------------------------------------- */

.gridwrap { display: grid; gap: 14px; justify-items: center; }

.puz {
  display: grid;
  gap: 7px;
  grid-auto-rows: 68px;
  grid-template-columns: repeat(4, 68px);
}
.cell {
  background: var(--card);
  border: 1px solid var(--edge);
  display: grid;
  padding: 5px;
  place-items: center;
  position: relative;
}
/* .drag-over / .drag-over-unplaced are toggled directly by the pointer-drag
   code in noclue4x.html; they mean the same thing as .over. */
.cell.over,
.cell.drag-over {
  background: color-mix(in oklab, var(--clay) 7%, var(--card));
  border-color: var(--clay);
  border-style: dashed;
}
.cell.tgt { border-color: var(--clay); border-style: dashed; }

/* Brief highlight as each letter of a newly correct word locks in. */
.tile.flash-correct {
  animation: flashCorrect 0.7s ease;
  z-index: 1;
}
@keyframes flashCorrect {
  0%   { transform: scale(1); }
  30%  { transform: scale(1.12); }
  100% { transform: scale(1); }
}

.tile {
  background: var(--card);
  border: 1px solid var(--edge);
  color: var(--ink);
  cursor: grab;
  display: grid;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 31px;
  height: 100%;
  line-height: 1;
  place-items: center;
  position: relative;
  transition: transform 0.12s ease, background 0.15s, border-color 0.15s, color 0.15s;
  user-select: none;
  width: 100%;

  /* Required for the pointer-drag path. Without it the browser treats a drag
     that starts on a letter as a scroll gesture and never emits the
     pointermove events, so the page scrolls instead of the tile moving. */
  touch-action: none;
}
.tile:active { cursor: grabbing; }

@media (pointer: coarse) {
  .tile { -webkit-user-drag: none; }
}

.tile.start   { background: var(--moss); border-color: var(--moss); color: var(--paper); cursor: default; }
.tile.placed  { background: var(--card); border-color: var(--sky);  color: var(--sky); }
.tile.correct { background: var(--moss); border-color: var(--moss); color: var(--paper); cursor: default; }

/* correct and start differ from placed by fill AND a mark, not hue alone */
.tile.correct::after,
.tile.start::after {
  background: color-mix(in oklab, var(--paper) 60%, transparent);
  bottom: 5px;
  content: "";
  height: 1px;
  left: 6px;
  position: absolute;
  right: 6px;
}

.tile.hint { background: var(--clay); border-color: var(--clay); color: var(--paper); cursor: not-allowed; }
.tile.hint::after {
  background: var(--paper);
  border-radius: 50%;
  content: "";
  height: 5px;
  position: absolute;
  right: 5px;
  top: 5px;
  width: 5px;
}

.tile.checking { animation: pulse 1s ease-in-out infinite; border-color: var(--ink3); color: var(--ink3); }
@keyframes pulse { 50% { opacity: 0.45; } }

.tile.wrong { border-color: var(--edge); border-style: dashed; color: var(--ink2); }

.tile.sel { background: var(--sky); border-color: var(--sky); color: var(--paper); transform: translateY(-3px); }

.tray {
  background: var(--paper2);
  border: 1px solid var(--edge);
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  justify-content: center;
  max-width: 400px;
  min-height: 60px;
  padding: 11px;
  width: 100%;
}
.tray.over,
.tray.drag-over-unplaced { border-color: var(--clay); border-style: dashed; }
.tray .tile { border-color: var(--sky); color: var(--sky); font-size: 26px; height: 46px; width: 46px; }

/* --- play chrome ---------------------------------------------------------- */

.stage { min-height: 520px; position: relative; }

.playbar {
  align-items: center;
  border-bottom: 1px solid var(--rule);
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr auto 1fr;
  padding: 22px 0 18px;
}
.tmr { display: grid; gap: 2px; justify-items: start; }
.mvs { display: grid; gap: 2px; justify-items: end; }
.tmr b, .mvs b {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 32px;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1;
}

.hintbox { align-items: center; display: flex; gap: 8px; }
/* pips carry a state, so they use --edge and differ by fill, not hue alone */
.pip { border: 1px solid var(--clay); background: var(--clay); border-radius: 50%; height: 8px; width: 8px; }
.pip.used { background: transparent; border-color: var(--edge); }

.playfoot { padding: 26px 0 70px; text-align: center; }

/* --- pre-roll ------------------------------------------------------------- */

.preroll {
  background: var(--curtain);
  color: var(--curtain-fg);
  display: grid;
  inset: 0;
  place-items: center;
  position: absolute;
  text-align: center;
  z-index: 20;
}
.preroll .inner { display: grid; gap: 18px; justify-items: center; padding: 24px; }
.preroll h2 {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(38px, 9vw, 60px);
  font-weight: 400;
  line-height: 0.95;
  margin: 0;
}
.preroll .lbl { color: color-mix(in oklab, var(--curtain-fg) 70%, transparent); }

.prebar {
  background: color-mix(in oklab, var(--curtain-fg) 25%, transparent);
  height: 3px;
  overflow: hidden;
  width: min(280px, 70vw);
}
.prebar i {
  animation: shrink 3s linear forwards;
  background: var(--curtain-fg);
  display: block;
  height: 100%;
  transform-origin: right;
  width: 100%;
}
@keyframes shrink { to { width: 0; } }

/* Paused: the board must stop accepting input while the clock is stopped.
   Previously this was an invisible pointer blocker on the album-cover layer;
   the curtain now does the same job, but visibly. */
.preroll.paused .prebar { display: none; }

/* While the server is scoring the finished grid the timer is also paused, but
   there is nothing to say — stay invisible and just keep blocking input, which
   is what the old .ghost-blocker did. */
.preroll.blocking { background: transparent; }

/* --- modals --------------------------------------------------------------- */

.scrim {
  background: var(--scrim);
  display: none;
  inset: 0;
  padding: 20px;
  place-items: center;
  position: fixed;
  z-index: 50;
}
.scrim.on { display: grid; }

.sheet {
  background: var(--card);
  border: 1px solid var(--edge);
  box-shadow: 0 24px 60px -28px oklch(0.24 0.018 60 / 0.5);
  max-width: 420px;
  padding: 34px 28px 26px;
  position: relative;
  text-align: center;
  width: 100%;
}
.sheet h3 {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 36px;
  font-weight: 400;
  line-height: 1;
  margin: 6px 0 0;
}
.sheet .scorewrap { margin: 18px 0 4px; }
.sheet .rowbtns   { margin-top: 24px; }
.sheet.wide { max-width: 520px; text-align: left; }
.sheet.wide h3 { text-align: center; }

.htp { color: var(--ink2); display: grid; font-size: 14.5px; gap: 14px; line-height: 1.6; margin-top: 20px; }
.htp ol { display: grid; gap: 10px; margin: 0; padding-left: 20px; list-style: decimal; }

.legend { border-top: 1px solid var(--rule); display: grid; gap: 8px; padding-top: 16px; }
.legend div { align-items: center; color: var(--ink2); display: flex; font-size: 13.5px; gap: 11px; }
.chip {
  border: 1px solid var(--edge);
  display: grid;
  flex: none;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 15px;
  height: 26px;
  place-items: center;
  width: 26px;
}
.chip.moss { background: var(--moss); border-color: var(--moss); color: var(--paper); }
.chip.sky  { border-color: var(--sky); color: var(--sky); }
.chip.clay { background: var(--clay); border-color: var(--clay); color: var(--paper); }

/* --- alert ---------------------------------------------------------------- */

.alert {
  background: color-mix(in oklab, var(--clay) 7%, var(--card));
  border: 1px solid var(--clay);
  display: grid;
  gap: 4px;
  margin: 0 auto;
  max-width: 420px;
  padding: 14px 16px;
}
.alert b {
  color: var(--clay);
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 20px;
  font-weight: 400;
}
.alert p { color: var(--ink2); font-size: 13.5px; line-height: 1.5; margin: 0; }

/* --- interior pages: stats, account, sign in, share ------------------------ */

.page { padding-top: 46px; padding-bottom: 80px; }
.page h1 {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: clamp(34px, 7vw, 46px);
  font-weight: 400;
  line-height: 1.05;
  /* Handoff says 4px. At 46px the serif descenders sit almost on top of the
     standfirst underneath, so this is 8px. */
  margin: 0 0 8px;
}

/* standfirst directly under a page heading */
.page h1 + .note { max-width: 46ch; }

/* Streaks — Current / All time.
   Deliberately unboxed and on one baseline: this used to be two bordered
   panels roughly 340px tall, which pushed Groups off the first screen on a
   phone. Same numbers, about a fifth of the height. */
.streaks-head { display: block; margin: 24px 0 10px; }

.streaks {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 34px;
  margin-top: 0;
}
.streak { align-items: baseline; display: flex; gap: 9px; }
.streak b {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 30px;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1;
}
.streak .days { color: var(--ink2); font-size: 13px; }

.panel {
  background: var(--card);
  border: 1px solid var(--rule);
  margin-top: 26px;
  padding: 24px 22px;
}
.panel h2 {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 24px;
  font-weight: 400;
  margin: 0 0 8px;
}
.panel p { color: var(--ink2); font-size: 14.5px; line-height: 1.6; margin: 0; }

/* Section 6 is fully scoped under body.legacy, so these need no guard. */
.field { display: grid; gap: 7px; margin-top: 20px; }
.field label {
  color: var(--ink2);
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.field input {
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: 2px;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  padding: 12px 13px;
}
.field input:disabled { color: var(--ink3); cursor: not-allowed; }
.field .help { color: var(--ink3); font-size: 12.5px; }

/* time / moves row on the share page */
.metarow { display: flex; gap: 34px; justify-content: center; margin-top: 22px; }
.metarow div { text-align: center; }
.metarow b {
  display: block;
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 30px;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1;
}

/* --- groups + leaderboards ------------------------------------------------ */

.groups { margin-top: 40px; }

.groups-head {
  align-items: baseline;
  display: flex;
  gap: 14px;
  justify-content: space-between;
  margin-bottom: 14px;
}

.group {
  border: 1px solid var(--rule);
  margin-top: 18px;
}

.group-top {
  align-items: baseline;
  border-bottom: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  justify-content: space-between;
  padding: 18px 20px;
}

.group-name {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 25px;
  font-weight: 400;
  line-height: 1.1;
}

/* Day / Week / Month. A radio group, not buttons: only one can be current, and
   arrow-key navigation between them comes free with the roving tabindex. */
.seg {
  border: 1px solid var(--rule);
  display: inline-flex;
  overflow: hidden;
}

.seg button {
  background: none;
  border: 0;
  border-right: 1px solid var(--rule);
  color: var(--ink3);
  cursor: pointer;
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  padding: 8px 14px;
  text-transform: uppercase;
}

.seg button:last-child { border-right: 0; }
.seg button:hover { color: var(--ink); }
.seg button[aria-pressed="true"] { background: var(--ink); color: var(--btn-solid-fg); }

/* Grid rather than a table: the row is a list item semantically, and this keeps
   the rank and score columns aligned without table layout quirks on narrow
   screens. */
.lb-row {
  align-items: baseline;
  border-bottom: 1px solid var(--rule);
  display: grid;
  gap: 14px;
  grid-template-columns: 34px 1fr auto auto;
  padding: 13px 20px;
}

.lb-row:last-child { border-bottom: 0; }

/* A period switch keeps the old board in place so the page height — and so the
   scroll position — doesn't move; this just marks it as stale. */
.group .is-reloading { opacity: 0.45; transition: opacity 120ms ease; }
.lb-row.is-you { background: var(--paper2); }

.lb-rank {
  color: var(--ink3);
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.lb-row.is-you .lb-rank,
.lb-row.is-you .lb-name { color: var(--ink); }

.lb-name {
  color: var(--ink2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lb-you {
  color: var(--ink3);
  font-size: 12px;
  margin-left: 6px;
}

.lb-score {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 22px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  min-width: 46px;
  text-align: right;
}

/* Average and days sit together in a fixed-width column so the numbers line up
   down the board rather than drifting with name length. */
.lb-meta {
  color: var(--ink3);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  min-width: 92px;
  text-align: right;
}

.lb-idle .lb-score,
.lb-idle .lb-name { color: var(--ink3); }

.lb-head {
  border-bottom: 1px solid var(--rule);
  color: var(--ink3);
  display: grid;
  font-family: "Archivo Narrow", Archivo, sans-serif;
  font-size: 11px;
  font-weight: 600;
  gap: 14px;
  grid-template-columns: 34px 1fr auto auto;
  letter-spacing: 0.11em;
  padding: 10px 20px;
  text-transform: uppercase;
}

.lb-head span:nth-child(3) { min-width: 46px; text-align: right; }
.lb-head span:nth-child(4) { min-width: 92px; text-align: right; }

.invite-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 17px;
  letter-spacing: 0.08em;
}

.group-foot {
  align-items: center;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: space-between;
  padding: 14px 20px;
}

/* --- group manage panel ---------------------------------------------------
   Expands inside the card. Tinted rather than bordered so it reads as a mode of
   the card it belongs to and not as a second card stacked underneath it. */

.group-manage { background: var(--paper2); }

/* Separator on the top edge, not the bottom: the blocks are a mix of divs and
   a form, interleaved with Alpine <template> nodes, so neither :last-of-type
   nor an adjacent-sibling rule can find the last one. Every block ruling its
   own top edge means the first one doubles as the panel's divider and there is
   no last-child case to special-case. */
.gm-block {
  border-top: 1px solid var(--rule);
  padding: 18px 20px;
}

.gm-code { margin: 8px 0 10px; }

.gm-actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}

.group-foot .gm-actions { margin-top: 0; }
.gm-block .field + .gm-actions { margin-top: 16px; }

/* The confirm step swaps in beside the button it replaces, so the row keeps its
   shape and the answer stays next to the question. */
.gm-confirm {
  align-items: center;
  display: inline-flex;
  flex-wrap: wrap;
  gap: 10px;
}

.gm-member {
  align-items: center;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: space-between;
  min-height: 46px;
  padding: 8px 0;
}

.gm-member-name {
  color: var(--ink2);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Destructive actions are outlined in clay rather than filled: they sit next to
   Cancel, and a filled button beside a ghost one reads as the recommended
   choice, which is exactly backwards here. */
.btn.danger {
  background: none;
  border-color: var(--clay);
  color: var(--clay);
}

.btn.danger:hover {
  background: var(--clay);
  border-color: var(--clay);
  color: var(--btn-solid-fg);
}

@media (max-width: 480px) {
  .lb-row, .lb-head { grid-template-columns: 26px 1fr auto; gap: 10px; }
  /* The average/days column is the first thing to go: the total is the ranking
     metric, so it's what has to survive. */
  .lb-row .lb-meta, .lb-head span:nth-child(4) { display: none; }
  .group-top { padding: 15px 16px; }
  .lb-row, .lb-head { padding-left: 16px; padding-right: 16px; }
  .gm-block { padding-left: 16px; padding-right: 16px; }
}

/* --- share / completed grid ----------------------------------------------- */

.sharegrid {
  display: grid;
  gap: 6px;
  grid-auto-rows: 58px;
  grid-template-columns: repeat(4, 58px);
  justify-content: center;
  margin-top: 28px;
}

/* --- responsive ----------------------------------------------------------- */

@media (max-width: 640px) {
  nav.top { display: none; }
  .burger { display: grid; }
  .puz { grid-auto-rows: min(19vw, 68px); grid-template-columns: repeat(4, min(19vw, 68px)); }
  .tray .tile { font-size: 23px; height: 42px; width: 42px; }
  .sharegrid { grid-auto-rows: 52px; grid-template-columns: repeat(4, 52px); }

  /* Keep Time | Hint | Moves on one row. Dropping the hint control to its own
     centred row cost about 50px of height on the screens with least to spare;
     the three items fit across 280px of content at the sizes below. */
  .playbar { gap: 10px; padding: 16px 0 14px; }
  .tmr b, .mvs b { font-size: 28px; }

  .streaks { gap: 8px 22px; }
  .streak b { font-size: 27px; }
  .metarow { gap: 24px; }
}

@media (max-width: 360px) {
  .playbar { gap: 8px; }
  .tmr b, .mvs b { font-size: 24px; }
  .hintbox { gap: 6px; }
  .hintbox .btn.sm { padding: 9px 12px; }
}


/* ==========================================================================
   6. LEGACY LAYER - Bulma 1.0.2 compatibility
   --------------------------------------------------------------------------
   Only admin.html and privacy.html still depend on this. Both carry
   class="legacy" on <body> (the base.html default). Every rule below is
   scoped to body.legacy, so this layer cannot reach a reskinned page.

   Values were resolved from the Bulma source that used to be loaded, so those
   two pages render as they always have. Pruned to exactly what they use.

   When they are reskinned: delete this whole section and the `legacy` default
   in base.html.

   Reference palette:
     text-strong  #2e333d      text        #404654      text-weak  #69748c
     border       #d6d9e0      light       #f3f4f6      white      #ffffff
     link         #2942ff      primary     #00d1b2      danger     #ff6685
   ========================================================================== */

body.legacy {
  background: #ffffff;
  color: #404654;
  font-family: Inter, "SF Pro", "Segoe UI", Roboto, Oxygen, Ubuntu,
               "Helvetica Neue", Helvetica, Arial, sans-serif;
}
body.legacy a { color: #2942ff; }
body.legacy a:hover { color: #2942ff; }
body.legacy strong { color: #2e333d; }
body.legacy hr { background-color: #f3f4f6; height: 2px; }

/* layout */

body.legacy .section { padding: 3rem 1.5rem; }
body.legacy .container { flex-grow: 1; margin: 0 auto; position: relative; width: 100%; }

@media screen and (min-width: 1024px) {
  body.legacy .section { padding: 3rem 3rem; }
  body.legacy .container { max-width: 960px; }
}
@media screen and (min-width: 1216px) {
  body.legacy .container { max-width: 1152px; }
}
@media screen and (min-width: 1408px) {
  body.legacy .container { max-width: 1344px; }
}

body.legacy .columns {
  margin-inline-start: -0.75rem;
  margin-inline-end: -0.75rem;
  margin-top: -0.75rem;
}
body.legacy .columns:last-child { margin-bottom: -0.75rem; }
body.legacy .columns.is-mobile { display: flex; }
body.legacy .column { display: block; flex-basis: 0; flex-grow: 1; flex-shrink: 1; padding: 0.75rem; }
body.legacy .columns.is-mobile > .column.is-2 { flex: none; width: 16.6666666667%; }

@media screen and (min-width: 769px), print {
  body.legacy .columns:not(.is-mobile) { display: flex; }
  body.legacy .column.is-2 { flex: none; width: 16.6666666667%; }
}

/* box, titles */

body.legacy .box {
  background-color: #ffffff;
  border-radius: 0.75rem;
  box-shadow: 0 0.5em 1em -0.125em rgba(10, 11, 13, 0.1),
              0 0 0 1px rgba(10, 11, 13, 0.02);
  color: #404654;
  display: block;
  padding: 1.25rem;
}

body.legacy .title,
body.legacy .subtitle { word-break: break-word; }
body.legacy .title:not(:last-child),
body.legacy .subtitle:not(:last-child) { margin-bottom: 1.5rem; }
body.legacy .title:not(.is-spaced) + .subtitle { margin-top: -1.25rem; }
body.legacy .title { color: #2e333d; font-size: 2rem; font-weight: 800; line-height: 1.125; }
body.legacy .subtitle { color: #404654; font-size: 1.25rem; font-weight: 400; line-height: 1.25; }

/* button */

body.legacy .button {
  align-items: center;
  appearance: none;
  background-color: #ffffff;
  border: 1px solid #d6d9e0;
  border-radius: 0.375rem;
  box-shadow: 0 0.0625em 0.125em rgba(51, 51, 51, 0.05),
              0 0.125em 0.25em rgba(51, 51, 51, 0.05);
  color: #2e333d;
  cursor: pointer;
  display: inline-flex;
  font-size: 1rem;
  font-weight: 500;
  height: auto;
  justify-content: center;
  line-height: 1.5;
  padding: calc(0.5em - 1px) calc(1em - 1px);
  position: relative;
  text-align: center;
  vertical-align: top;
  white-space: nowrap;
  user-select: none;
}
body.legacy .button:hover  { background-color: #f0f2f4; border-color: #c8ccd5; }
body.legacy .button:active { background-color: #e2e4e9; box-shadow: none; }

body.legacy .button.is-primary {
  background-color: #00d1b2;
  border-color: transparent;
  box-shadow: none;
  color: #001f1a;
}
body.legacy .button.is-primary:hover  { background-color: #00b89c; }
body.legacy .button.is-primary:active { background-color: #009e86; }

body.legacy .button.is-fullwidth { display: flex; width: 100%; }

body.legacy .button[disabled],
body.legacy fieldset[disabled] .button {
  background-color: #ffffff;
  border-color: #d6d9e0;
  box-shadow: none;
  cursor: not-allowed;
  opacity: 0.5;
}

/* Spinner border is a fixed ink, not currentColor: the button colour is
   forced transparent to hide the label, so currentColor would be invisible. */
body.legacy .button.is-loading {
  box-shadow: none;
  color: transparent !important;
  pointer-events: none;
}
body.legacy .button.is-loading::after {
  animation: spinAround 500ms infinite linear;
  border: 2px solid #2e333d;
  border-radius: 9999px;
  border-right-color: transparent;
  border-top-color: transparent;
  content: "";
  display: block;
  height: 1em;
  left: calc(50% - 0.5em);
  position: absolute !important;
  top: calc(50% - 0.5em);
  width: 1em;
}

@keyframes spinAround {
  from { transform: rotate(0deg); }
  to   { transform: rotate(359deg); }
}

/* forms - admin.html */

body.legacy .field:not(:last-child) { margin-bottom: 0.75rem; }
body.legacy .field.has-addons { display: flex; justify-content: flex-start; }
body.legacy .field.has-addons .control:not(:last-child) { margin-right: -1px; }
body.legacy .field.has-addons .control:first-child:not(:only-child) .button,
body.legacy .field.has-addons .control:first-child:not(:only-child) .input {
  border-bottom-right-radius: 0;
  border-top-right-radius: 0;
}
body.legacy .field.has-addons .control:last-child:not(:only-child) .button,
body.legacy .field.has-addons .control:last-child:not(:only-child) .input {
  border-bottom-left-radius: 0;
  border-top-left-radius: 0;
}

body.legacy .control {
  box-sizing: border-box;
  clear: both;
  font-size: 1rem;
  position: relative;
  text-align: inherit;
}
body.legacy .control.is-expanded { flex-grow: 1; flex-shrink: 1; }

body.legacy .input {
  align-items: center;
  appearance: none;
  background-color: #ffffff;
  border: 1px solid #d6d9e0;
  border-radius: 0.375rem;
  box-shadow: inset 0 0.0625em 0.125em rgba(10, 11, 13, 0.05);
  color: #2e333d;
  display: inline-flex;
  font-size: 1rem;
  height: 2.5em;
  justify-content: flex-start;
  line-height: 1.5;
  max-width: 100%;
  padding: calc(0.5em - 1px) calc(0.75em - 1px);
  position: relative;
  vertical-align: top;
  width: 100%;
}
body.legacy .input::placeholder { color: rgba(64, 70, 84, 0.3); }
body.legacy .input:hover { border-color: #c8ccd5; }
body.legacy .input:focus {
  border-color: #2942ff;
  box-shadow: 0 0 0 0.125em rgba(41, 66, 255, 0.25);
  outline: none;
}

body.legacy .help { display: block; font-size: 0.75rem; margin-top: 0.25rem; }

/* table - admin.html */

body.legacy .table-container {
  max-width: 100%;
  overflow: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}

body.legacy .table { background-color: #ffffff; color: #2e333d; }
body.legacy .table td,
body.legacy .table th {
  border: 0 solid #d6d9e0;
  border-bottom-width: 1px;
  padding: 0.5em 0.75em;
  vertical-align: top;
}
body.legacy .table th { color: #2e333d; }
body.legacy .table thead td,
body.legacy .table thead th { border-width: 0 0 2px; color: #2e333d; }
body.legacy .table.is-fullwidth { width: 100%; }
body.legacy .table.is-striped tbody tr:not(.is-selected):nth-child(even) { background-color: #f9fafb; }
body.legacy .table.is-hoverable tbody tr:not(.is-selected):hover { background-color: #f9fafb; }

/* prose - privacy.html */

body.legacy .content:not(:last-child) { margin-bottom: 1.5rem; }
body.legacy .content li + li { margin-top: 0.25em; }
body.legacy .content p:not(:last-child),
body.legacy .content ol:not(:last-child),
body.legacy .content ul:not(:last-child),
body.legacy .content blockquote:not(:last-child) { margin-bottom: 1em; }

body.legacy .content h1,
body.legacy .content h2,
body.legacy .content h3,
body.legacy .content h4,
body.legacy .content h5,
body.legacy .content h6 { color: #2e333d; font-weight: 600; line-height: 1.125; }
body.legacy .content h1 { font-size: 2em;    margin-bottom: 0.5em; }
body.legacy .content h2 { font-size: 1.75em; margin-bottom: 0.5714em; }
body.legacy .content h3 { font-size: 1.5em;  margin-bottom: 0.6666em; }
body.legacy .content h1:not(:first-child) { margin-top: 1em; }
body.legacy .content h2:not(:first-child) { margin-top: 1.1428em; }
body.legacy .content h3:not(:first-child) { margin-top: 1.3333em; }
body.legacy .content ul { list-style: disc outside; margin-left: 2em; margin-top: 1em; }
body.legacy .content ol { list-style: decimal outside; margin-left: 2em; margin-top: 1em; }

/* utilities still referenced */

body.legacy .has-text-centered { text-align: center !important; }
body.legacy .has-text-grey     { color: #69748c !important; }
body.legacy .has-text-danger   { color: #ff6685 !important; }
body.legacy .is-size-7 { font-size: 0.75rem !important; }

body.legacy .mb-2 { margin-bottom: .5rem !important; }
body.legacy .mb-3 { margin-bottom: .75rem !important; }
body.legacy .mb-4 { margin-bottom: 1rem !important; }

/* .heading is a no-op: Bulma 1.0.2 dropped the rule, so the two usages in
   admin.html already rendered unstyled. Noted so nobody "restores" it. */
