@charset "UTF-8";
/* ---------------------------------------------------------- */
/* Was $blue-glass — rebranded to a muted dark-amber glass so the
   play/setter buttons sit warm in the brand hue without reading as
   orange blocks. */
/* Border ladder in the brand hue — same lightness steps as the old grays
   (gray-300/400/500/600) so the visual hierarchy is unchanged. */
/* Resting chrome (board page refresh, 2026-09-24): near-invisible neutral
   borders — separation comes from elevation (the home cards' light-based
   treatment), and the brand orange is reserved for accents, active
   states, and focus. */
/* Brand accent — the vesalabs dark orange (#EF9F27, the main site's
   $accent-orange). Dark/glass variants derived from it for gradient stops
   and translucent glows. */
/* Matrix-style digit rain (user idea, funky exploration): sudoku digits in
   the brand orange drifting slowly down the black ground, very faint. Three
   repeating SVG tile layers give parallax — nearer layers use bigger digits,
   higher fill-opacity, and a faster fall. Each layer travels an integer
   number of its own tile heights per loop, so the animation is seamless. */
.background {
  position: fixed;
  width: 100%;
  height: 100%;
  background-color: black;
  /* Ambient brand warmth underneath the rain: two soft amber glows
     drifting very slowly in opposite corners. */
  background-image: radial-gradient(60rem 40rem at 18% -12%, hsla(36, 86%, 55%, 0.13), transparent 70%), radial-gradient(70rem 45rem at 108% 112%, hsla(36, 86%, 45%, 0.1), transparent 70%);
  background-repeat: no-repeat;
  z-index: -1;
  overflow: hidden;
}
@media (prefers-reduced-motion: no-preference) {
  .background {
    animation: ambient-drift 26s ease-in-out infinite alternate;
  }
}
.background::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='420' height='1100'><g fill='%23EF9F27' font-family='monospace'><text x='60' y='120' font-size='34' fill-opacity='0.9'>5</text><text x='64' y='420' font-size='26' fill-opacity='0.6'>2</text><text x='58' y='760' font-size='30' fill-opacity='0.8'>9</text><text x='62' y='1020' font-size='24' fill-opacity='0.5'>4</text><text x='220' y='240' font-size='28' fill-opacity='0.7'>7</text><text x='224' y='580' font-size='34' fill-opacity='0.9'>1</text><text x='218' y='900' font-size='24' fill-opacity='0.55'>6</text><text x='370' y='80' font-size='24' fill-opacity='0.5'>8</text><text x='366' y='500' font-size='30' fill-opacity='0.8'>3</text><text x='372' y='840' font-size='26' fill-opacity='0.65'>5</text></g></svg>"), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='320' height='860'><g fill='%23EF9F27' font-family='monospace'><text x='40' y='90' font-size='22' fill-opacity='0.7'>1</text><text x='44' y='330' font-size='16' fill-opacity='0.45'>8</text><text x='38' y='600' font-size='20' fill-opacity='0.6'>6</text><text x='42' y='820' font-size='16' fill-opacity='0.4'>3</text><text x='170' y='180' font-size='20' fill-opacity='0.65'>4</text><text x='174' y='460' font-size='22' fill-opacity='0.7'>9</text><text x='168' y='740' font-size='16' fill-opacity='0.45'>7</text><text x='290' y='60' font-size='16' fill-opacity='0.4'>2</text><text x='286' y='400' font-size='22' fill-opacity='0.7'>5</text><text x='292' y='680' font-size='18' fill-opacity='0.55'>8</text></g></svg>"), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='640'><g fill='%23EF9F27' font-family='monospace'><text x='22' y='60' font-size='14' fill-opacity='0.5'>7</text><text x='26' y='210' font-size='11' fill-opacity='0.35'>3</text><text x='20' y='380' font-size='13' fill-opacity='0.45'>1</text><text x='24' y='550' font-size='11' fill-opacity='0.3'>9</text><text x='116' y='130' font-size='12' fill-opacity='0.4'>2</text><text x='114' y='300' font-size='14' fill-opacity='0.5'>8</text><text x='118' y='470' font-size='11' fill-opacity='0.3'>5</text><text x='112' y='620' font-size='13' fill-opacity='0.45'>6</text><text x='204' y='90' font-size='13' fill-opacity='0.45'>9</text><text x='206' y='260' font-size='11' fill-opacity='0.3'>2</text><text x='200' y='430' font-size='14' fill-opacity='0.5'>5</text><text x='204' y='590' font-size='12' fill-opacity='0.4'>7</text></g></svg>");
  background-size: 420px 1100px, 320px 860px, 240px 640px;
  background-position: 0 0, 0 0, 0 0;
  /* "Very faint": the digits already carry per-glyph fill-opacity;
     this caps the whole rain layer. */
  opacity: 0.16;
}
@media (prefers-reduced-motion: no-preference) {
  .background::before {
    animation: digit-rain 80s linear infinite;
  }
}

@keyframes ambient-drift {
  to {
    background-position: 6% 4%, -5% -4%;
  }
}
@keyframes digit-rain {
  to {
    /* 2, 1 and 2 tile heights respectively — integer multiples keep the
       loop seamless; the different distances are the parallax speeds. */
    background-position: 0 2200px, 0 860px, 0 1280px;
  }
}
.bordered {
  --border-width: 1px;
  border-radius: 24px;
  position: relative;
  height: fit-content;
  width: fit-content;
}
.bordered .bordered-backdrop {
  position: absolute;
  inset: -12px;
  border-radius: 36px;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 12px solid transparent;
  mask: linear-gradient(white) content-box, linear-gradient(white) padding-box;
  mask-composite: intersect;
}
.bordered .bordered-glow {
  inset: -2px;
  border-radius: 26px;
  border: 2px solid #EF9F27;
  position: absolute;
  filter: blur(5px);
  mask: linear-gradient(white) content-box, linear-gradient(white) padding-box;
  mask-composite: intersect;
}
.bordered .bordered-inner {
  border-radius: inherit;
  background: rgba(50, 50, 50, 0.05);
  color: white;
  text-align: center;
  position: relative;
}
.bordered .bordered-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: var(--border-width) solid transparent;
  filter: blur(5px);
  background: linear-gradient(#EF9F27, hsl(36, 86%, 40%)) border-box;
  mask: linear-gradient(white) border-box, linear-gradient(white) padding-box;
  mask-composite: subtract;
}

a {
  color: hsl(0, 0%, 80%);
  text-decoration: none;
}

ul {
  margin-left: 1rem;
}

img {
  transition: opacity 0.5s ease-in-out, scale 0.5s ease-in-out;
}
img:hover {
  opacity: 1;
  scale: 110%;
}

:focus-visible {
  outline: 2px solid hsl(0, 0%, 75%);
  outline-offset: 3px;
  border-radius: 0.5rem;
}

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  position: relative;
  box-sizing: border-box;
}

.header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3.5rem;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(7px);
  border-bottom: 1px solid hsla(36, 86%, 55%, 0.35);
}
.header .header-content {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  width: 100%;
  padding: 0 1.5rem;
}
.header .header-content .navbar-logo {
  display: flex;
  align-items: center;
  text-decoration: none;
}
.header .header-content .navbar-logo .logo-text {
  font-size: 150%;
  font-weight: 700;
  color: hsl(0, 0%, 100%);
  letter-spacing: -0.02em;
  /* Brand shimmer: mostly-white text with an orange band
     sweeping through every few seconds. Falls back to plain
     white where background-clip: text is unsupported. */
  background: linear-gradient(100deg, hsl(0, 0%, 100%) 20%, #EF9F27 42%, hsl(36, 90%, 72%) 50%, #EF9F27 58%, hsl(0, 0%, 100%) 80%);
  /* Tile exactly 2× the text width: the keyframes below then
     move the tiled background one whole tile per cycle, so
     the loop restart is pixel-identical (a 250% tile with the
     old 200%→-50% sweep moved 1.5 tiles and jumped). */
  background-size: 200% 100%;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
@media (prefers-reduced-motion: no-preference) {
  .header .header-content .navbar-logo .logo-text {
    animation: logo-shimmer 7s linear infinite;
  }
}
.header .header-content .nav-center {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.header .header-content .nav-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
@keyframes logo-shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: 0% 0;
  }
}
.header .header-content .navbar-item {
  text-decoration: none;
  color: hsl(0, 0%, 80%);
  padding: 0.5rem 1rem;
  border-radius: 0.7rem;
  font-size: 80%;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  transition: background 0.5s ease, color 0.5s ease;
}
.header .header-content .navbar-item:hover {
  background: rgba(255, 255, 255, 0.1);
  color: hsl(0, 0%, 100%);
}
.header .header-content .navbar-item.login-btn {
  border: 1px solid hsl(36, 80%, 52%);
  background: rgba(255, 255, 255, 0.08);
  color: hsl(0, 0%, 100%);
}
.header .header-content .navbar-item.login-btn:hover {
  background: rgba(255, 255, 255, 0.16);
}

.timed-button {
  border-radius: 2000vmin;
  --border-width: 1px;
  position: relative;
  height: fit-content;
  width: fit-content;
  transition: transform 0.2s ease, filter 0.2s ease;
}
.timed-button .timed-button-backdrop {
  position: absolute;
  inset: -12px;
  border-radius: 2000vmin;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 12px solid transparent;
  mask: linear-gradient(white) content-box, linear-gradient(white) padding-box;
  mask-composite: intersect;
}
.timed-button .timed-button-glow {
  inset: 0;
  border-radius: 2000vmin;
  position: absolute;
  filter: blur(10px);
  background-image: linear-gradient(transparent, 90%, hsl(0, 0%, 75%), hsl(0, 0%, 75%));
  mask: linear-gradient(white) content-box, linear-gradient(white) padding-box;
  mask-composite: intersect;
}
.timed-button .timed-button-inner {
  border-radius: 2000vmin;
  background: rgba(50, 50, 50, 0.05);
  color: white;
  text-align: center;
  position: relative;
  padding: 1rem;
}
.timed-button .timed-button-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: var(--border-width) solid transparent;
  filter: blur(2px);
  background: linear-gradient(hsl(0, 0%, 75%), 20%, hsl(220, 10%, 15%), hsl(220, 10%, 10%)) border-box;
  mask: linear-gradient(white) border-box, linear-gradient(white) padding-box;
  mask-composite: subtract;
}
.timed-button p {
  padding: 0rem 1rem;
  font-size: 150%;
}
.timed-button:not(.timed-button-inactive):hover {
  transform: translateY(-2px);
  filter: brightness(1.35);
}

.timed-button-inactive {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

.glassy-box {
  --border-width: 1px;
  backdrop-filter: blur(5px);
  background-color: var(--glass-colour);
  position: relative;
}
.glassy-box::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: var(--border-width) solid transparent;
  filter: blur(5px);
  background: linear-gradient(hsl(36, 86%, 40%), #EF9F27) border-box;
  mask: linear-gradient(white) border-box, linear-gradient(white) padding-box;
  mask-composite: subtract;
}

/* effects – add new effect imports here */
/* ── Login / auth form pages ── */
.login-page {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 3.5rem 1rem 1rem;
}

/* ── Card ── */
.login-card,
form.bg-white {
  background: hsla(0, 0%, 10%, 0.6);
  backdrop-filter: blur(7px);
  border: 1px solid hsl(36, 86%, 40%);
  border-radius: 1rem;
  padding: 2.5rem;
  width: 100%;
  max-width: 24rem;
}

.login-heading {
  font-size: 200%;
  font-weight: 700;
  color: hsl(0, 0%, 100%);
  margin-bottom: 2rem;
  text-align: center;
}

.login-field {
  margin-bottom: 1.25rem;
}

.login-label {
  display: block;
  font-size: 80%;
  font-weight: 600;
  color: hsl(0, 0%, 80%);
  margin-bottom: 0.4rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.login-actions {
  margin-top: 1.5rem;
}

.login-submit {
  width: 100%;
  padding: 0.75rem;
  font-size: 100%;
  font-weight: 600;
  justify-content: center;
}

.login-footer {
  margin-top: 1.25rem;
  text-align: center;
}

.login-link {
  font-size: 80%;
  color: hsl(210, 80%, 65%);
  cursor: pointer;
}
.login-link:hover {
  color: hsl(210, 80%, 45%);
}

/* ── Shared form inputs ── */
.w-full {
  width: 100%;
}

.max-w-md {
  max-width: 28rem;
  margin: 0 auto;
  padding: 0 1rem;
}

/* ── Typography ── */
.text-xl {
  font-size: 150%;
}

.text-sm {
  font-size: 80%;
}

.font-bold {
  font-weight: 700;
}

.text-gray-700 {
  color: hsl(0, 0%, 80%);
}

.text-white {
  color: hsl(0, 0%, 100%);
}

/* ── Spacing ── */
.mb-2 {
  margin-bottom: 0.5rem;
}

.mb-4 {
  margin-bottom: 1rem;
}

.mb-6 {
  margin-bottom: 1.5rem;
}

.p-2 {
  padding: 0.5rem;
}

/* ── Layout ── */
.block {
  display: block;
}

.inline-block {
  display: inline-block;
}

.flex {
  display: flex;
}

.items-center {
  align-items: center;
}

.justify-between {
  justify-content: space-between;
}

/* ── Form inputs ── */
.shadow {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.appearance-none {
  appearance: none;
}

input[type=text],
input[type=password],
input[type=email] {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border-radius: 0.7rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: rgba(255, 255, 255, 0.06);
  color: hsl(0, 0%, 100%);
  font-size: 100%;
  line-height: 1.25;
  outline: none;
  transition: border-color 0.15s ease;
}
input[type=text]::placeholder,
input[type=password]::placeholder,
input[type=email]::placeholder {
  color: hsl(220, 10%, 60%);
}
input[type=text]:focus,
input[type=password]:focus,
input[type=email]:focus {
  border-color: hsl(0, 0%, 75%);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.08);
}

.border-red-500,
input.border-red-500 {
  border-color: hsl(0, 70%, 55%);
}

/* ── Buttons ── */
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem 1.25rem;
  border-radius: 0.7rem;
  border: 1px solid hsl(36, 80%, 52%);
  background: rgba(255, 255, 255, 0.08);
  color: hsl(0, 0%, 100%);
  font-size: 100%;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
button:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.14);
  border-color: hsl(36, 75%, 62%);
}
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── SVG icons in buttons ── */
.h-5 {
  height: 1.25rem;
}

.w-5 {
  width: 1.25rem;
}

.ml-4 {
  margin-left: 1rem;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.animate-spin {
  animation: spin 0.8s linear infinite;
}

/* ── Error banner ── */
.bg-red-500 {
  background: hsl(0, 70%, 45%);
  border-radius: 0.7rem;
  padding: 0.5rem;
  font-weight: 700;
  margin-bottom: 1rem;
}

/* ── Links ── */
/* Class names are legacy (Tailwind-era markup); the colours are brand
   orange now. */
.text-blue-500 {
  color: hsl(36, 86%, 62%);
}

a.text-blue-500:hover,
.hover\:text-blue-800:hover {
  color: hsl(36, 86%, 40%);
}

.align-baseline {
  vertical-align: baseline;
}

/* ── Heading inside form ── */
form h2 {
  display: block;
  color: hsl(0, 0%, 80%);
}

.home-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
  gap: 0.75rem;
  /* Clear the fixed 3.5rem menu bar (same clearance as the settings
     page) — without this a long puzzle list slides under the header. */
  padding: 5rem 1rem 2rem;
}

.home-subtitle {
  color: hsl(220, 10%, 45%);
  font-size: 100%;
}

.home-search {
  width: min(480px, 92vw);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid hsl(36, 86%, 40%);
  border-radius: 0.7rem;
  color: hsl(0, 0%, 100%);
  font-size: 100%;
  padding: 0.5rem 0.9rem;
}
.home-search::placeholder {
  color: hsl(220, 10%, 45%);
}
.home-search:focus {
  outline: none;
  border-color: hsl(36, 80%, 72%);
}

/* Uniform card grid (docs/game/ui.md § Puzzle cards). */
.puzzle-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 0.9rem;
  width: min(1000px, 92vw);
}

.home-error {
  color: hsl(220, 10%, 45%);
  grid-column: 1/-1;
}

.puzzle-card {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  position: relative;
  background: hsla(0, 0%, 10%, 0.6);
  /* Dimmed ember at rest (vs $border-3 elsewhere): the cursor glow needs
     range in both directions — far borders sink toward the ground, the
     pool near the pointer burns bright. */
  border: 1px solid hsl(36, 60%, 30%);
  border-radius: 10px;
  padding: 0.8rem;
  backdrop-filter: blur(6px);
  /* Cursor-tracking border glow: a radial highlight at the pointer's
     position relative to this card (--card-mx/--card-my, written per
     card by the index.html listener), masked to the 1px border ring —
     every card's border lights up where the mouse is, and because the
     offsets share one screen-space origin the glow hands off seamlessly
     between neighbouring cards. Off-screen default until the pointer
     first moves, so touch/keyboard users see the static border. */
  /* Elevation on the pure-black page ground: dark shadows are invisible
     there, so depth comes from light instead — a soft ambient glow plus
     an inset top-edge highlight (the "lit from above" cue), deepening on
     hover with a small lift. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 14px 44px rgba(255, 255, 255, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.14);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
  /* Single-variant cards play on click anywhere (docs/game/ui.md
     § Puzzle cards); nested buttons/links stop the bubble. */
  /* Square preview pane on top; the SVG scales inside it. */
  /* Player-count badge (duo+): the preview hides seat rules, the badge
     explains the sparseness. */
  /* Hover popover: puzzle details as a real overlay. It lives inside
     .puzzle-actions (position: relative below) with its BOTTOM pinned
     just above the buttons — however many lines they wrap to — so the
     play buttons can never be covered: longer rule lists grow the panel
     upward past the card's top edge, floating over the row above (the
     hovered card's z-index raise keeps it on top) instead of clipping.
     Pure CSS and pointer-events: none, so the card stays fully
     clickable underneath; the transition delay keeps quick
     mouse-throughs from flashing it. Content-sized: exactly as tall as
     its text, nothing more. */
  /* One play button per active implementation (variant), pinned to the
     card's bottom edge so uneven meta blocks don't stagger the buttons. */
  /* Nested chrome: inside the already-bordered card, the buttons carry a
     faint top-lit gradient line instead of another full-strength border —
     solid lines inside lines inside the grid read as noise. Same
     border-gradient mask technique as .glassy-box. */
}
.puzzle-card::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 10px;
  border: 1px solid transparent;
  background: radial-gradient(24rem circle at var(--card-mx, -100vmax) var(--card-my, -100vmax), hsl(44, 100%, 92%), hsl(38, 100%, 70%) 25%, hsla(36, 90%, 52%, 0.7) 50%, transparent 78%) border-box;
  mask: linear-gradient(white) border-box, linear-gradient(white) padding-box;
  mask-composite: subtract;
  pointer-events: none;
}
.puzzle-card:hover {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 18px 56px rgba(255, 255, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.22);
  transform: translateY(-3px);
}
.puzzle-card.puzzle-card--playable {
  cursor: pointer;
}
.puzzle-card .puzzle-preview-pane {
  position: relative;
  aspect-ratio: 1;
  border-radius: 6px;
  overflow: hidden;
  display: grid;
  place-items: center;
}
.puzzle-card .puzzle-players {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  background: rgba(20, 24, 34, 0.75);
  color: hsl(0, 0%, 80%);
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 5px;
  padding: 0.15rem 0.4rem;
}
.puzzle-card .puzzle-popover {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  /* Bleed over the card's 0.8rem padding to full card width. */
  left: -0.8rem;
  right: -0.8rem;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.7rem 0.8rem;
  background: rgba(10, 12, 18, 0.95);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  box-shadow: 0 14px 44px rgba(255, 255, 255, 0.1);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.puzzle-card .puzzle-popover .puzzle-popover-facts {
  color: hsl(220, 10%, 45%);
  font-size: 0.75rem;
  margin: 0;
}
.puzzle-card .puzzle-popover .puzzle-popover-rule {
  color: hsl(0, 0%, 80%);
  font-size: 0.78rem;
  line-height: 1.35;
  margin: 0;
}
.puzzle-card .puzzle-popover .puzzle-popover-hint {
  color: hsl(220, 10%, 45%);
  font-size: 0.72rem;
  font-style: italic;
  margin: 0;
}
.puzzle-card:hover {
  /* Above sibling cards, so an outgrown popover floats over the next
     row instead of sliding under it. */
  z-index: 2;
}
.puzzle-card:hover .puzzle-popover {
  opacity: 1;
  transition-delay: 0.35s;
}
.puzzle-card .puzzle-preview {
  width: 100%;
  height: 100%;
  /* The board SVG is play-bright white; dimmed here (card previews
     only — the real board is untouched) so it sits into the dark
     page instead of glaring. */
  filter: brightness(0.65);
}
.puzzle-card .puzzle-preview-loading {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  color: hsl(220, 10%, 45%);
  font-size: 0.85rem;
  background: rgba(255, 255, 255, 0.05);
}
.puzzle-card .puzzle-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 0.1rem;
}
.puzzle-card .puzzle-title {
  color: hsl(0, 0%, 80%);
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
}
.puzzle-card .puzzle-solved {
  color: hsl(0, 0%, 100%);
  font-size: 0.9rem;
}
.puzzle-card .puzzle-author {
  color: hsl(220, 10%, 45%);
  font-size: 0.85rem;
}
.puzzle-card .puzzle-facts {
  color: hsl(220, 10%, 45%);
  font-size: 0.8rem;
}
.puzzle-card .puzzle-actions {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  /* Positioning parent for the hover popover (anchored above it). */
  position: relative;
}
.puzzle-card .puzzle-unavailable {
  color: hsl(220, 10%, 45%);
  font-size: 0.85rem;
  align-self: center;
}
.puzzle-card .puzzle-variant {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}
.puzzle-card .puzzle-play, .puzzle-card .puzzle-edit {
  position: relative;
  border: 1px solid transparent;
}
.puzzle-card .puzzle-play::after, .puzzle-card .puzzle-edit::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: linear-gradient(hsla(36, 85%, 62%, 0.65), hsla(36, 85%, 45%, 0.12)) border-box;
  mask: linear-gradient(white) border-box, linear-gradient(white) padding-box;
  mask-composite: subtract;
  opacity: 0.75;
  transition: opacity 0.15s ease;
  pointer-events: none;
}
.puzzle-card .puzzle-play:hover::after, .puzzle-card .puzzle-edit:hover::after {
  opacity: 1;
}
.puzzle-card .puzzle-edit {
  color: hsl(220, 10%, 45%);
  font-size: 0.85rem;
  text-decoration: none;
  border-radius: 6px;
  padding: 0.3rem 0.45rem;
}
.puzzle-card .puzzle-edit:hover {
  color: hsl(0, 0%, 100%);
}
.puzzle-card .puzzle-add-variant {
  align-self: center;
}
.puzzle-card .puzzle-play {
  background: hsla(36, 35%, 24%, 0.45);
  color: hsl(0, 0%, 80%);
  border-radius: 6px;
  padding: 0.4rem 1.1rem;
  cursor: pointer;
}

.friends-page {
  max-width: 46rem;
  margin: 0 auto;
  padding: 5rem 1.5rem 2rem;
}

.friends-title {
  font-size: 200%;
  font-weight: 700;
  color: hsl(0, 0%, 100%);
  margin-bottom: 1.5rem;
}

.friends-banner {
  padding: 0.6rem 1rem;
  border-radius: 0.7rem;
  margin-bottom: 1rem;
  font-size: 80%;
}
.friends-banner--error {
  background: rgba(220, 38, 38, 0.18);
  color: hsl(0, 70%, 72%);
  border: 1px solid hsla(0, 60%, 45%, 0.5);
}

/* --- search --- */
.friends-search {
  margin-bottom: 2rem;
}

.friends-search-input {
  width: 100%;
  padding: 0.7rem 1rem;
  border-radius: 0.7rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: rgba(255, 255, 255, 0.06);
  color: hsl(0, 0%, 100%);
  font-size: 100%;
}
.friends-search-input::placeholder {
  color: hsl(220, 10%, 45%);
}
.friends-search-input:focus {
  outline: none;
  border-color: hsl(36, 75%, 62%);
}

.friends-results {
  margin-top: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.friends-hint {
  color: hsl(220, 10%, 45%);
  font-size: 80%;
  padding: 0.5rem 0.25rem;
}

/* --- sections + rows --- */
.friends-section {
  margin-bottom: 2rem;
}

.friends-section-title {
  font-size: 100%;
  font-weight: 600;
  color: hsl(0, 0%, 80%);
  margin-bottom: 0.75rem;
}

.friend-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.65rem 0.85rem;
  border-radius: 0.7rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: hsla(0, 0%, 10%, 0.6);
  backdrop-filter: blur(7px);
  margin-bottom: 0.5rem;
}

.friend-avatar {
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.1);
  color: hsl(0, 0%, 100%);
  font-weight: 600;
}

.friend-row-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.friend-name {
  color: hsl(0, 0%, 100%);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.friend-sub {
  font-size: 80%;
  color: hsl(220, 10%, 45%);
}

.friend-actions {
  display: flex;
  gap: 0.4rem;
}

.friend-tag {
  font-size: 80%;
  color: hsl(220, 10%, 45%);
  padding: 0.3rem 0.6rem;
}

.friend-btn {
  padding: 0.4rem 0.85rem;
  border-radius: 0.5rem;
  border: 1px solid hsl(36, 80%, 52%);
  background: rgba(255, 255, 255, 0.08);
  color: hsl(0, 0%, 100%);
  font-weight: 600;
  font-size: 80%;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.friend-btn:hover {
  background: rgba(255, 255, 255, 0.16);
}
.friend-btn--add, .friend-btn--accept {
  border-color: hsla(142, 60%, 45%, 0.6);
  color: hsl(142, 71%, 72%);
}
.friend-btn--add:hover, .friend-btn--accept:hover {
  background: rgba(34, 197, 94, 0.18);
}
.friend-btn--decline {
  border-color: hsla(0, 60%, 50%, 0.5);
  color: hsl(0, 70%, 72%);
}
.friend-btn--decline:hover {
  background: rgba(220, 38, 38, 0.16);
}
.friend-btn--ghost {
  color: hsl(0, 0%, 80%);
}

.friends-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 20vh;
  color: hsl(220, 10%, 45%);
  font-size: 150%;
  text-align: center;
}
.friends-empty.friends-error {
  color: hsl(0, 70%, 65%);
  font-size: 100%;
}

.settings-page {
  max-width: 40rem;
  margin: 0 auto;
  padding: 5rem 1.5rem 2rem;
}

.settings-header {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  margin-bottom: 2rem;
}

.settings-back {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid hsl(36, 86%, 40%);
  border-radius: 0.7rem;
  color: hsl(220, 10%, 45%);
  font-size: 80%;
  padding: 0.35rem 0.75rem;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.settings-back:hover {
  background: rgba(255, 255, 255, 0.16);
  color: hsl(0, 0%, 100%);
}

.settings-title {
  font-size: 200%;
  font-weight: 700;
  color: hsl(0, 0%, 100%);
  margin-bottom: 0;
}

.settings-section {
  margin-bottom: 2rem;
}

.settings-section-title {
  font-size: 80%;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: hsl(220, 10%, 45%);
  margin-bottom: 0.75rem;
}

.settings-card {
  background: hsla(0, 0%, 10%, 0.6);
  backdrop-filter: blur(7px);
  border: 1px solid hsl(36, 86%, 40%);
  border-radius: 1rem;
  overflow: hidden;
}

.settings-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 1.5rem;
}
.settings-row + .settings-row {
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.settings-label {
  font-size: 100%;
  color: hsl(0, 0%, 80%);
  font-weight: 500;
}

.settings-value {
  font-size: 100%;
  color: hsl(0, 0%, 100%);
}
.settings-value--muted {
  color: hsl(220, 10%, 45%);
  font-style: italic;
}

/* --- banners + status --- */
.settings-banner {
  padding: 0.6rem 1rem;
  border-radius: 0.7rem;
  margin-bottom: 1rem;
  font-size: 80%;
}
.settings-banner--error {
  background: rgba(220, 38, 38, 0.18);
  color: hsl(0, 70%, 72%);
  border: 1px solid hsla(0, 60%, 45%, 0.5);
}

.settings-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 20vh;
  color: hsl(220, 10%, 45%);
  font-size: 150%;
  text-align: center;
}
.settings-empty.settings-error {
  color: hsl(0, 70%, 65%);
  font-size: 100%;
}

.settings-hint {
  color: hsl(220, 10%, 45%);
  font-size: 80%;
  padding: 0.25rem 0.25rem 0.75rem;
}

/* --- form cards --- */
.settings-card--form {
  padding: 1.25rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.settings-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.settings-field-label {
  font-size: 80%;
  color: hsl(220, 10%, 45%);
  font-weight: 600;
}

.settings-input {
  width: 100%;
  padding: 0.6rem 0.85rem;
  border-radius: 0.7rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: rgba(255, 255, 255, 0.06);
  color: hsl(0, 0%, 100%);
  font-size: 100%;
  font-family: inherit;
}
.settings-input::placeholder {
  color: hsl(220, 10%, 45%);
}
.settings-input:focus {
  outline: none;
  border-color: hsl(36, 75%, 62%);
}
.settings-input--area {
  resize: vertical;
  min-height: 4rem;
}

.settings-select {
  cursor: pointer;
}

.settings-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

.settings-btn {
  padding: 0.45rem 1rem;
  border-radius: 0.5rem;
  border: 1px solid hsl(36, 80%, 52%);
  background: rgba(255, 255, 255, 0.08);
  color: hsl(0, 0%, 100%);
  font-weight: 600;
  font-size: 80%;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.settings-btn:hover {
  background: rgba(255, 255, 255, 0.16);
}
.settings-btn:disabled {
  opacity: 0.6;
  cursor: default;
}
.settings-btn--primary {
  border-color: hsla(210, 70%, 55%, 0.6);
  color: hsl(210, 80%, 78%);
}
.settings-btn--primary:hover {
  background: rgba(59, 130, 246, 0.18);
}
.settings-btn--ghost {
  color: hsl(0, 0%, 80%);
}
.settings-btn--danger {
  border-color: hsla(0, 60%, 50%, 0.5);
  color: hsl(0, 70%, 72%);
}
.settings-btn--danger:hover {
  background: rgba(220, 38, 38, 0.16);
}

/* --- avatar --- */
.settings-avatar-row {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.settings-avatar-img,
.settings-avatar-placeholder {
  flex-shrink: 0;
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  object-fit: cover;
  background: rgba(255, 255, 255, 0.1);
}

.settings-avatar-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: hsl(0, 0%, 100%);
  font-weight: 600;
  font-size: 150%;
}

.settings-avatar-actions {
  display: flex;
  gap: 0.5rem;
}

.settings-upload {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}

.settings-file-input {
  display: none;
}

.settings-check {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: hsl(0, 0%, 80%);
  font-size: 80%;
  white-space: nowrap;
  cursor: pointer;
}

/* Play settings: long labels wrap instead of clipping. */
.settings-check--wrap {
  white-space: normal;
  align-items: flex-start;
}
.settings-check--wrap input {
  margin-top: 0.2rem;
  flex: none;
}

/* The two keyboard-scheme radios, stacked. */
.settings-scheme {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.admin-page {
  max-width: 52rem;
  margin: 0 auto;
  padding: 5rem 1.5rem 2rem;
}

.admin-title {
  font-size: 200%;
  font-weight: 700;
  color: hsl(0, 0%, 100%);
  margin-bottom: 1.5rem;
}

.admin-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}

.admin-tab {
  padding: 0.5rem 1rem;
  border-radius: 1rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: rgba(255, 255, 255, 0.05);
  color: hsl(220, 10%, 45%);
  font-size: 100%;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.admin-tab:hover {
  background: rgba(255, 255, 255, 0.1);
  color: hsl(0, 0%, 100%);
}
.admin-tab--active {
  border-color: hsla(210, 70%, 55%, 0.6);
  background: rgba(59, 130, 246, 0.18);
  color: hsl(210, 80%, 78%);
}

.admin-section {
  margin-bottom: 2rem;
}

.admin-section-title {
  font-size: 80%;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: hsl(220, 10%, 45%);
  margin-bottom: 0.75rem;
}

.admin-card {
  background: hsla(0, 0%, 10%, 0.6);
  backdrop-filter: blur(7px);
  border: 1px solid hsl(36, 86%, 40%);
  border-radius: 1rem;
  overflow: hidden;
}

.admin-card--form {
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.admin-empty {
  color: hsl(220, 10%, 45%);
  font-style: italic;
  padding: 1.5rem 0;
}

.admin-error {
  color: hsl(0, 70%, 72%);
}

.admin-banner {
  padding: 0.75rem 1rem;
  border-radius: 1rem;
  margin-bottom: 1rem;
  font-size: 100%;
}
.admin-banner--error {
  background: rgba(220, 38, 38, 0.18);
  color: hsl(0, 70%, 72%);
}
.admin-banner--ok {
  background: rgba(34, 197, 94, 0.16);
  color: hsl(140, 60%, 72%);
}

.admin-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 1.25rem;
}
.admin-row + .admin-row {
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.admin-row-info {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.admin-row-title {
  font-size: 100%;
  color: hsl(0, 0%, 100%);
  font-weight: 500;
  word-break: break-all;
}

.admin-row-sub {
  font-size: 80%;
  color: hsl(220, 10%, 45%);
}

.admin-row-actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-shrink: 0;
}

.admin-tag {
  font-size: 80%;
  padding: 0.15rem 0.5rem;
  border-radius: 0.5rem;
  background: rgba(255, 255, 255, 0.1);
  color: hsl(0, 0%, 80%);
}
.admin-tag--muted {
  color: hsl(220, 10%, 45%);
}
.admin-tag--warn {
  background: rgba(220, 38, 38, 0.18);
  color: hsl(0, 70%, 72%);
}

.admin-input {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border-radius: 0.5rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: rgba(255, 255, 255, 0.06);
  color: hsl(0, 0%, 100%);
  font-size: 100%;
}
.admin-input::placeholder {
  color: hsl(220, 10%, 45%);
}
.admin-input:focus {
  outline: none;
  border-color: hsl(36, 75%, 62%);
}

.admin-form-row {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.admin-form-row > * {
  flex: 1 1 12rem;
}

.admin-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

.admin-btn {
  padding: 0.5rem 0.9rem;
  border-radius: 0.5rem;
  border: 1px solid hsl(36, 86%, 40%);
  background: rgba(255, 255, 255, 0.08);
  color: hsl(0, 0%, 100%);
  font-size: 80%;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease;
}
.admin-btn:hover {
  background: rgba(255, 255, 255, 0.16);
}
.admin-btn:disabled {
  opacity: 0.5;
  cursor: default;
}
.admin-btn--primary {
  border-color: hsla(210, 70%, 55%, 0.6);
  color: hsl(210, 80%, 78%);
  background: rgba(59, 130, 246, 0.18);
}
.admin-btn--primary:hover {
  background: rgba(59, 130, 246, 0.3);
}
.admin-btn--danger {
  border-color: hsla(0, 60%, 50%, 0.5);
  color: hsl(0, 70%, 72%);
  background: rgba(220, 38, 38, 0.14);
}
.admin-btn--danger:hover {
  background: rgba(220, 38, 38, 0.26);
}
.admin-btn--ghost {
  background: transparent;
}
.admin-btn--ghost:hover {
  background: rgba(255, 255, 255, 0.1);
}

/* The board surface — values from docs/game/ui.md (approved 2026-09-19). */
/* Conflicting entries (docs/game/ui.md § Live validation) — the ui.md Red. */
/* One input-cluster "big square" (pad buttons, mode buttons) and the gap
   between them. The ink strip derives its width from these — change them
   together. */
/* Chrome refresh (2026-09-24): one radius scale (panel / button / chip),
   the home cards' light-based elevation (dark shadows are invisible on
   the black page ground), and one shared hover-transition timing. */
/* Halo in the board-surface colour so numbers stay legible on top of
   square colours and rule graphics (the original stroked digits in the
   background colour for the same reason). Em-based: scales with the text. */
.play-page {
  display: flex;
  justify-content: center;
  /* The menu bar is fixed, 3.5rem tall — clear it. */
  padding: 5rem 1rem 2rem;
}

.board-shell {
  --cell-size: clamp(36px, min(8.5vw, 8.5vh), 72px);
  outline: none;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: 1.25rem;
  background: hsla(0, 0%, 10%, 0.6);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 12px;
  padding: 1rem 1.25rem 0.9rem;
  backdrop-filter: blur(6px);
  box-shadow: 0 14px 44px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.board-shell:focus-visible {
  border-color: hsla(36, 86%, 55%, 0.4);
  box-shadow: 0 14px 44px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 0 0 2px hsla(36, 86%, 55%, 0.4);
}

.board-grid {
  display: grid;
  position: relative;
  background: hsl(220, 12%, 90%);
  border: 2px solid hsl(222, 14%, 30%);
  border-radius: 4px;
  user-select: none;
  touch-action: manipulation;
}

.sq {
  width: var(--cell-size);
  height: var(--cell-size);
  position: relative;
  border-right: 1px solid hsl(220, 10%, 72%);
  border-bottom: 1px solid hsl(220, 10%, 72%);
  display: grid;
  place-items: center;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.sq .d {
  position: relative;
  z-index: 2;
  text-shadow: -0.05em -0.05em 0 hsl(220, 12%, 90%), 0.05em -0.05em 0 hsl(220, 12%, 90%), -0.05em 0.05em 0 hsl(220, 12%, 90%), 0.05em 0.05em 0 hsl(220, 12%, 90%), 0 0 0.15em hsl(220, 12%, 90%), 0 0 0.15em hsl(220, 12%, 90%);
  font-size: calc(var(--cell-size) * 0.56);
  line-height: 1;
  /* Digits have no descenders, so the line box's descent space floats
     them ~0.05em above true centre — visible on thermo bulbs/arrow
     circles. Nudge back down. */
  transform: translateY(0.11em);
}
.sq .d.given {
  color: hsl(222, 15%, 14%);
  font-weight: 600;
}
.sq .d.entry {
  color: hsl(226, 55%, 38%);
  font-weight: 500;
}
.sq .d.conflict {
  color: hsl(4, 72%, 55%);
}
.sq .corner-mark {
  position: absolute;
  z-index: 2;
  text-shadow: -0.05em -0.05em 0 hsl(220, 12%, 90%), 0.05em -0.05em 0 hsl(220, 12%, 90%), -0.05em 0.05em 0 hsl(220, 12%, 90%), 0.05em 0.05em 0 hsl(220, 12%, 90%), 0 0 0.15em hsl(220, 12%, 90%), 0 0 0.15em hsl(220, 12%, 90%);
  transform: translate(-50%, -50%);
  font-size: calc(var(--cell-size) * 0.24);
  color: hsl(222, 10%, 45%);
}
.sq .center-marks {
  position: relative;
  z-index: 2;
  text-shadow: -0.05em -0.05em 0 hsl(220, 12%, 90%), 0.05em -0.05em 0 hsl(220, 12%, 90%), -0.05em 0.05em 0 hsl(220, 12%, 90%), 0.05em 0.05em 0 hsl(220, 12%, 90%), 0 0 0.15em hsl(220, 12%, 90%), 0 0 0.15em hsl(220, 12%, 90%);
  font-size: calc(var(--cell-size) * 0.26);
  color: hsl(222, 10%, 45%);
  letter-spacing: 0.05em;
}

.board-side {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  width: fit-content;
  max-width: 92vw;
}

.input-cluster {
  display: flex;
  gap: 0.4rem;
}

/* Mode column beside the pad (CTC-style): one mode cell per pad row, plus
   the pen. */
.mode-col {
  display: grid;
  grid-template-rows: repeat(5, 3.6rem);
  gap: 0.4rem;
  width: 3.6rem;
  flex: none;
}

/* Mode buttons as miniature board cells wearing the mode's preview.
   Inactive faces are dimmed so the active one is unmistakable on the
   light surface. */
.mode-btn.mode-face {
  position: relative;
  padding: 0;
  background: hsl(220, 12%, 90%);
  display: grid;
  place-items: center;
  opacity: 0.5;
  /* The pen face wears the current draw colour. */
}
.mode-btn.mode-face:hover {
  opacity: 0.8;
}
.mode-btn.mode-face .pad-digit {
  color: hsl(222, 15%, 14%);
  font-size: 1.5rem;
  font-weight: 600;
}
.mode-btn.mode-face .pad-corner {
  color: hsl(222, 10%, 45%);
  position: absolute;
  top: 0.25rem;
  left: 0.45rem;
  font-size: 0.8rem;
}
.mode-btn.mode-face .pad-center {
  color: hsl(222, 10%, 45%);
  font-size: 0.85rem;
}
.mode-btn.mode-face .mode-pie {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  /* On the light board-coloured face — a board ink, not chrome. */
  border: 1px solid hsl(220, 10%, 72%);
}
.mode-btn.mode-face .pad-pen {
  font-size: 1.4rem;
}
.mode-btn.mode-face.active {
  opacity: 1;
  /* Brand orange reads on the light face; white vanished there.
     Re-assert the face colour: the generic .mode-btn.active tint
     must not repaint the miniature board cell. */
  background: hsl(220, 12%, 90%);
  border: 2px solid #EF9F27;
}

/* The input pad: 7 8 9 / 4 5 6 / 1 2 3 / 0 0 erase — big, tablet-first.
   Buttons wear the current mode's face (digit / pencil-mark preview /
   colour swatch), original menu semantics. */
.pad {
  display: grid;
  grid-template-columns: repeat(3, 3.6rem);
  grid-auto-rows: 3.6rem;
  gap: 0.4rem;
  /* Bottom row (level with the pen mode button): undo / redo / settings.
     The settings shortcut is an anchor wearing the button look. */
}
.pad .pad-btn {
  position: relative;
  background: hsl(220, 10%, 15%);
  color: hsl(0, 0%, 80%);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 8px;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.pad .pad-btn:hover {
  border-color: hsla(0, 0%, 100%, 0.22);
  background: hsl(220, 10%, 20%);
}
.pad .pad-btn:active {
  border-color: hsl(0, 0%, 100%);
}
.pad .pad-erase {
  font-size: 1.3rem;
}
.pad .pad-multi {
  font-size: 1.3rem;
  color: hsl(220, 10%, 45%);
}
.pad .pad-multi.active {
  background: hsla(36, 86%, 55%, 0.4);
  border-color: #EF9F27;
  color: hsl(0, 0%, 100%);
}
.pad .pad-digit {
  font-size: 1.7rem;
  font-weight: 600;
  transform: translateY(0.11em);
}
.pad .pad-inert {
  opacity: 0.3;
}
.pad .pad-action {
  font-size: 1.3rem;
  color: hsl(220, 10%, 45%);
  text-decoration: none;
}
.pad .pad-action:disabled {
  opacity: 0.35;
  cursor: default;
}
.pad .pad-action:disabled:hover {
  border-color: hsla(0, 0%, 100%, 0.1);
  background: hsl(220, 10%, 15%);
}
.pad .pad-corner {
  position: absolute;
  top: 0.3rem;
  left: 0.45rem;
  font-size: 0.85rem;
  color: hsl(220, 10%, 45%);
}
.pad .pad-center {
  font-size: 0.95rem;
  color: hsl(220, 10%, 45%);
}
.pad .pad-swatch {
  /* Sized against the button box itself — immune to the inline/grid
     percentage-resolution quirks that collapsed earlier attempts. */
  position: absolute;
  inset: 20%;
  border-radius: 6px;
  border: 1px solid hsla(0, 0%, 100%, 0.22);
}

/* The ink strip: default-ink swatch + the ten pickable colours. Sits under
   the input cluster; greyed out (not removed) in colour mode so the layout
   never shifts and the picked ink stays visible. */
.ink-strip {
  /* Exactly the input cluster's width (3 pad columns + the mode column
     + their gaps) — don't stretch to the sidebar, whose width the hint
     text below can push wider. */
  width: calc(4 * 3.6rem + 3 * 0.4rem);
  display: grid;
  grid-template-columns: repeat(11, 1fr);
  gap: 0.25rem;
  /* "Auto": the layer-default ink, worn as a mark-grey/entry-blue split. */
}
.ink-strip.ink-strip--disabled .ink-btn {
  opacity: 0.35;
  cursor: default;
  filter: grayscale(0.6);
}
.ink-strip.ink-strip--disabled .ink-btn:hover {
  border-color: hsla(0, 0%, 100%, 0.22);
}
.ink-strip .ink-btn {
  aspect-ratio: 1;
  border: 1px solid hsla(0, 0%, 100%, 0.22);
  border-radius: 4px;
  cursor: pointer;
  padding: 0;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.ink-strip .ink-btn:hover {
  border-color: hsl(0, 0%, 80%);
}
.ink-strip .ink-btn.active {
  border: 2px solid hsl(0, 0%, 100%);
}
.ink-strip .ink-auto {
  background: linear-gradient(135deg, hsl(222, 10%, 45%) 0 50%, hsl(226, 55%, 38%) 50% 100%);
}

.mode-btn {
  background: hsl(220, 10%, 15%);
  color: hsl(0, 0%, 80%);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 8px;
  padding: 0.55rem 0.8rem;
  cursor: pointer;
  font-size: 0.95rem;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.mode-btn:hover:not(:disabled) {
  border-color: hsla(0, 0%, 100%, 0.22);
}
.mode-btn.active {
  background: hsla(36, 86%, 55%, 0.4);
  border-color: #EF9F27;
  color: hsl(0, 0%, 100%);
}
.mode-btn:disabled {
  opacity: 0.45;
  cursor: default;
}

/* ── Session page ─────────────────────────────────────────── */
.session-page {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 1.5rem;
  /* The menu bar is fixed, 3.5rem tall — clear it. */
  padding: 5rem 1rem 2rem;
}

/* Overlay anchor for the solved celebration. */
.session-board {
  position: relative;
}

/* The board is veiled via backdrop-filter ON THE OVERLAY, never `filter`
   on the board itself: GPU compositors silently drop huge blurred layers
   (the board vanished to black on real hardware; software raster hid the
   bug in headless checks). Two strengths: the lobby HIDES the board
   (nobody studies givens before the clock runs), the solved celebration
   merely recedes it — the finished board stays admirable. */
.board-blur-wrap.veiled,
.board-blur-wrap.solved {
  pointer-events: none;
}

.solved-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  backdrop-filter: blur(3px);
}

.lobby-overlay {
  /* Strong veil + a tint as belt-and-braces where backdrop-filter is
     unsupported: givens must not be studyable pre-start. */
  backdrop-filter: blur(14px);
  background: rgba(10, 12, 18, 0.55);
}

.solved-card {
  background: hsla(0, 0%, 10%, 0.6);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 12px;
  padding: 1.6rem 2.2rem;
  text-align: center;
  backdrop-filter: blur(6px);
  box-shadow: 0 14px 44px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.solved-card h2 {
  color: hsl(0, 0%, 80%);
  font-size: 1.6rem;
  margin: 0 0 0.4rem;
}
.solved-card p {
  /* $content-2 was too dim over the blurred board. */
  color: hsl(0, 0%, 100%);
  margin: 0 0 1rem;
}

.session-waiting {
  color: #EF9F27;
  font-size: 0.9rem;
}

/* Pre-start lobby (docs/game/ui.md § Lobby & timer): rides the solved
   overlay's blur; the card holds rules to read, member ready states, and
   the ready button. */
.lobby-card {
  max-width: min(30rem, 90%);
  text-align: left;
}
.lobby-card h2 {
  text-align: center;
}
.lobby-card .lobby-rules {
  max-height: 14rem;
  overflow-y: auto;
  margin-bottom: 0.8rem;
  /* Spacing separates the rules; no hairline between rows. */
}
.lobby-card .lobby-rules .rule {
  color: hsl(0, 0%, 80%);
  font-size: 0.88rem;
  padding: 0.35rem 0;
}
.lobby-card .lobby-members {
  margin-bottom: 0.8rem;
}
.lobby-card .lobby-member {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  color: hsl(0, 0%, 80%);
  padding: 0.2rem 0;
}
.lobby-card .lobby-member .player-name {
  flex: 1;
  min-width: 0;
}
.lobby-card .lobby-member small {
  color: hsl(220, 10%, 45%);
}
.lobby-card .lobby-ready-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 2px solid hsla(0, 0%, 100%, 0.22);
  flex: none;
}
.lobby-card .lobby-ready-dot.ready {
  background: hsl(0, 0%, 100%);
  border-color: hsl(0, 0%, 100%);
}
.lobby-card .lobby-waiting {
  color: hsl(220, 10%, 45%);
  text-align: center;
}
.lobby-card .lobby-ready-btn {
  display: block;
  width: 100%;
  background: hsla(36, 86%, 55%, 0.4);
  color: hsl(0, 0%, 100%);
  border: 1px solid #EF9F27;
  border-radius: 8px;
  padding: 0.6rem;
  font-size: 1.05rem;
  font-weight: 600;
  cursor: pointer;
  margin-bottom: 0.6rem;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
  /* The CTA brightens instead of glowing. */
}
.lobby-card .lobby-ready-btn:hover {
  background: hsla(36, 86%, 55%, 0.55);
}

.session-title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
}
.session-title-row .session-timer {
  font-variant-numeric: tabular-nums;
  color: hsl(220, 10%, 45%);
}
.session-title-row .session-timer.done {
  color: hsl(0, 0%, 100%);
  font-weight: 600;
}

.session-side {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: min(280px, 92vw);
}

.session-panel {
  background: hsla(0, 0%, 10%, 0.6);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 12px;
  padding: 0.9rem 1.1rem;
  backdrop-filter: blur(6px);
  box-shadow: 0 14px 44px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  /* Aligned columns: dot | name (flexes, ellipsizes) | away | seat | ✓.
     The name absorbs the free space so every trailing item lines up in
     the same place on every row. */
  /* Spacing separates the rules; no hairline between rows. */
}
.session-panel h2 {
  color: hsl(0, 0%, 80%);
  font-size: 1.05rem;
  margin: 0 0 0.6rem;
}
.session-panel .player {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  color: hsl(220, 10%, 45%);
  padding: 0.25rem 0;
}
.session-panel .player.online {
  color: hsl(0, 0%, 80%);
}
.session-panel .player .dot {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  flex: none;
}
.session-panel .player .player-name {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.session-panel .player small {
  color: hsl(220, 10%, 45%);
  flex: none;
}
.session-panel .player .player-completed {
  color: hsl(0, 0%, 100%);
  font-weight: 700;
  flex: none;
  /* Reserve the column even when unearned, so seat chips align
     between finished and unfinished rows. */
  width: 1em;
  text-align: center;
}
.session-panel .player .player-slot {
  border: 1px solid hsla(0, 0%, 100%, 0.22);
  border-radius: 4px;
  padding: 0 0.3rem;
  font-size: 0.7rem;
}
.session-panel .colour-picker {
  /* Spacing separates the picker from the player rows; no hairline. */
  margin-top: 0.9rem;
}
.session-panel .colour-picker .colour-picker-label {
  display: block;
  color: hsl(220, 10%, 45%);
  font-size: 0.78rem;
  margin-bottom: 0.35rem;
}
.session-panel .colour-picker .colour-picker-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.session-panel .colour-picker .colour-swatch {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  /* Neutral hairline so the dark swatches keep an edge. */
  border: 2px solid hsla(0, 0%, 100%, 0.22);
  cursor: pointer;
  padding: 0;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.session-panel .colour-picker .colour-swatch:hover {
  border-color: hsl(220, 10%, 45%);
}
.session-panel .colour-picker .colour-swatch.selected {
  border-color: hsl(0, 0%, 100%);
}
.session-panel .rule {
  color: hsl(0, 0%, 80%);
  font-size: 0.88rem;
  line-height: 1.4;
  margin: 0;
  padding: 0.4rem 0;
}
.session-panel .share-btn {
  width: 100%;
  margin-top: 0.5rem;
  background: hsl(220, 10%, 15%);
  color: hsl(0, 0%, 80%);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 8px;
  padding: 0.45rem 0.8rem;
  cursor: pointer;
  font-size: 0.9rem;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.session-panel .share-btn:hover {
  border-color: hsla(0, 0%, 100%, 0.22);
}
.session-panel .share-btn.copied {
  border-color: hsl(0, 0%, 100%);
  color: hsl(0, 0%, 100%);
}
.session-panel .share-btn.copy-failed {
  border-color: #EF9F27;
  color: #EF9F27;
}

.session-reconnecting {
  color: #EF9F27;
  font-size: 0.9rem;
}

.session-error {
  color: hsl(220, 10%, 45%);
}

.board-hint {
  color: hsl(220, 10%, 45%);
  font-size: 0.75rem;
  margin: 0;
  text-align: center;
  max-width: 100%;
}

/* Rule graphics (derived, docs/game/rules.md): between square backgrounds
   and square content. Drawings (annotation lines): above fills and rule
   graphics but below digits/marks (drawing over a cell must not obscure
   its digit). Selections: every player's cursor as a cage outline in
   their colour, above content. All ignore the pointer. */
.board-overlay,
.drawings-overlay,
.selection-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.board-overlay {
  z-index: 1;
}

/* Same layer as the rule graphics; later DOM order paints it above them,
   while square content (z-index 2) stays on top. */
.drawings-overlay {
  z-index: 1;
}

.selection-overlay {
  z-index: 3;
}

/* Draw mode: the pointer is a pen. */
.board-grid.draw-mode,
.board-grid.draw-mode .sq {
  cursor: crosshair;
}

/* Press-and-drag corner handle: resizes the board (persisted). */
.resize-handle {
  position: absolute;
  right: -6px;
  bottom: -6px;
  width: 22px;
  height: 22px;
  z-index: 4;
  cursor: nwse-resize;
  border-right: 4px solid hsla(0, 0%, 100%, 0.35);
  border-bottom: 4px solid hsla(0, 0%, 100%, 0.35);
  border-radius: 0 0 6px 0;
  opacity: 0.7;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.resize-handle:hover {
  opacity: 1;
  border-color: hsl(0, 0%, 100%);
}

/* The puzzle setter (/create) — same glassy panel language as the session
   page (board.scss), with a form-heavy side panel. */
.setter-page {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 1.5rem;
  /* The menu bar is fixed, 3.5rem tall — clear it. */
  padding: 5rem 1rem 2rem;
}

.setter-gate {
  flex-direction: column;
  align-items: center;
  color: hsl(220, 10%, 45%);
}
.setter-gate h1 {
  color: hsl(0, 0%, 80%);
}

.setter-login-link {
  color: hsl(0, 0%, 100%);
  font-weight: 600;
}

.setter-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: min(320px, 92vw);
}

.setter-section {
  background: hsla(0, 0%, 10%, 0.6);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 12px;
  padding: 0.9rem 1.1rem;
  backdrop-filter: blur(6px);
  box-shadow: 0 14px 44px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.setter-section h2 {
  color: hsl(0, 0%, 80%);
  font-size: 1.05rem;
  margin: 0 0 0.6rem;
}

.setter-field {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin: 0 0 0.55rem;
  color: hsl(220, 10%, 45%);
  font-size: 0.85rem;
}
.setter-field input,
.setter-field select {
  background: hsla(36, 35%, 24%, 0.45);
  border: 1px solid hsla(0, 0%, 100%, 0.22);
  border-radius: 8px;
  color: hsl(0, 0%, 80%);
  padding: 0.35rem 0.5rem;
  font-size: 0.9rem;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.setter-field input:focus,
.setter-field select:focus {
  outline: none;
  border-color: hsl(36, 80%, 72%);
}

.setter-check {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}

.setter-field-row {
  display: flex;
  gap: 0.75rem;
}
.setter-field-row .setter-field {
  flex: 1;
}

.setter-hint {
  color: hsl(220, 10%, 45%);
  font-size: 0.78rem;
  line-height: 1.35;
  margin: 0 0 0.55rem;
}

.setter-error {
  color: #EF9F27;
  font-size: 0.85rem;
  margin: 0 0 0.55rem;
}

.setter-rule-list {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
}

/* Spacing separates the rules; no hairline between rows. */
.setter-rule {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  color: hsl(0, 0%, 80%);
  font-size: 0.85rem;
  line-height: 1.35;
  padding: 0.35rem 0;
}

.setter-rule-text {
  flex: 1;
}

/* Rules outside the previewed seat's view: listed but visibly inert. */
.setter-rule-dimmed {
  opacity: 0.4;
}

.setter-rule-remove {
  background: none;
  border: 1px solid hsla(0, 0%, 100%, 0.22);
  border-radius: 4px;
  color: hsl(220, 10%, 45%);
  cursor: pointer;
  line-height: 1;
  padding: 0.1rem 0.4rem;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.setter-rule-remove:hover {
  color: #EF9F27;
}

.setter-composer-actions {
  display: flex;
  gap: 0.6rem;
}
.setter-composer-actions button {
  flex: 1;
  background: hsla(36, 35%, 24%, 0.45);
  border: 1px solid hsla(0, 0%, 100%, 0.1);
  border-radius: 8px;
  color: hsl(0, 0%, 80%);
  cursor: pointer;
  padding: 0.45rem 0.5rem;
  font-size: 0.85rem;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease, opacity 0.12s ease, box-shadow 0.12s ease;
}
.setter-composer-actions button:hover {
  border-color: hsla(0, 0%, 100%, 0.22);
}

.setter-save {
  width: 100%;
  background: hsl(0, 0%, 100%);
  border: none;
  border-radius: 8px;
  color: hsla(0, 0%, 40%, 0.5);
  cursor: pointer;
  font-size: 1rem;
  font-weight: 600;
  padding: 0.6rem;
}
.setter-save:disabled {
  opacity: 0.6;
  cursor: default;
}

html {
  width: 100%;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.35) transparent;
  scroll-behavior: smooth;
}

html::-webkit-scrollbar {
  width: 4px;
}

html::-webkit-scrollbar-track {
  background: transparent;
}

html::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.35);
  border-radius: 2px;
}

html::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.55);
}

body {
  width: 100%;
  font-size: 100%;
  font-family: Helvetica, sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: hsl(0, 0%, 80%);
  overflow-x: hidden;
  gap: 5rem;
  background-color: black;
}

main {
  width: 100%;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: 0;
  z-index: 1000;
  padding: 1rem 1.5rem;
  background: white;
  color: black;
  font-weight: bold;
  text-decoration: none;
}
.skip-link:focus {
  top: 0;
}

@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;
  }
}
