/* ══════════════════════════════════════════════════════════════════════════
   Site chrome — the one stylesheet for everything that frames a page:
   the site nav, the footer, and every game's header bar.

   Single source on purpose. Before this file existed, each game carried its
   own copy of these rules (about 180 of them across five stylesheets) and
   they had drifted into four different designs: three nav heights, three
   sets of nav links, two games whose whole nav was squeezed into a 680px
   column on desktop, titles hidden on mobile in three games and shown in two,
   and a footer on the root pages only.

   Served two ways, from this one file:
     - the root pages link it:     <link rel="stylesheet" href="/site-chrome.css">
     - every game bundles it:      import '../../site-chrome.css' in src/main.tsx

   It carries its own tokens (--chrome-*) and its own font stack, so it renders
   the same whatever page it sits on: the root pages and the games name their
   colour variables differently, and two games use a different font stack.

   Dark mode works both ways the site does it. The root pages follow the OS;
   the games set data-theme on <html> before first paint. An explicit
   data-theme wins over the OS preference in both directions.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  --chrome-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --chrome-nav-bg:        rgba(255, 255, 255, 0.72);
  --chrome-bar-bg:        rgba(255, 255, 255, 0.6);
  --chrome-border:        rgba(15, 15, 20, 0.09);
  --chrome-border-strong: rgba(15, 15, 20, 0.18);
  --chrome-text:          #111114;
  --chrome-muted:         #5f5f6e;
  --chrome-surface:       #ffffff;
  --chrome-track:         rgba(15, 15, 20, 0.07);
  --chrome-active-bg:     #18181b;
  --chrome-active-text:   #ffffff;
  --chrome-brand:         #7c3aed;
  --chrome-badge:         #ef4444;
  /* Game controls sit in a column this wide, centred, on every game. */
  --chrome-column:        720px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --chrome-nav-bg:        rgba(11, 11, 16, 0.72);
    --chrome-bar-bg:        rgba(20, 20, 26, 0.55);
    --chrome-border:        rgba(255, 255, 255, 0.09);
    --chrome-border-strong: rgba(255, 255, 255, 0.22);
    --chrome-text:          #ececf1;
    --chrome-muted:         rgba(236, 236, 241, 0.62);
    --chrome-surface:       rgba(255, 255, 255, 0.05);
    --chrome-track:         rgba(255, 255, 255, 0.08);
    --chrome-active-bg:     #ececf1;
    --chrome-active-text:   #111114;
  }
}

:root[data-theme="dark"] {
  --chrome-nav-bg:        rgba(11, 11, 16, 0.72);
  --chrome-bar-bg:        rgba(20, 20, 26, 0.55);
  --chrome-border:        rgba(255, 255, 255, 0.09);
  --chrome-border-strong: rgba(255, 255, 255, 0.22);
  --chrome-text:          #ececf1;
  --chrome-muted:         rgba(236, 236, 241, 0.62);
  --chrome-surface:       rgba(255, 255, 255, 0.05);
  --chrome-track:         rgba(255, 255, 255, 0.08);
  --chrome-active-bg:     #ececf1;
  --chrome-active-text:   #111114;
}

/* ── Page frame (games) ──────────────────────────────────────────────────
   nav + game + footer, with the footer at the bottom of the window when the
   game is short and after it when it is long — the same rule the root pages
   follow. A game that needs exactly one screen (Bulls & Cows) keeps its own
   fixed height, and the footer simply follows it. Root pages have no #root,
   so none of this touches them. */
#root {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
#root > .app { flex: 1 0 auto; }

/* ── Site nav ────────────────────────────────────────────────────────── */
.site-nav {
  /* Low on purpose. In a game the nav must sit *under* the game's own
     overlays - dialogs start at z-index 50 - or an open dialog leaves the
     nav bright and clickable above its dimmed backdrop. It only has to clear
     the page content and the bg glow; the sticky root-page nav below is the
     one that needs to ride above everything. */
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 70px;
  padding: 0 2.25rem;
  background: var(--chrome-nav-bg);
  border-bottom: 1px solid var(--chrome-border);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  font-family: var(--chrome-font);
  line-height: 1.6;
}

/* Root pages pin the nav. Games do not: they pin their own header bar
   instead, and two pinned bars would cost a phone over 100px of board. */
.site-nav--sticky {
  position: sticky;
  top: 0;
  z-index: 100; /* root pages have no dialogs, only content to ride over */
}

.site-nav__brand {
  /* The wordmark shows only when it actually fits. The brand takes whatever
     width the links leave; when that is too narrow for mark + wordmark, the
     wordmark wraps onto a second line, which the fixed height and overflow
     hide. That works whatever the font. A width breakpoint did not: the
     layout first shipped measured against Windows' Segoe UI, and the wider
     default font on Linux pushed "About Me" off a 360px screen - visible as a
     sideways scroll in two games and silently clipped in three. */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: flex-start;
  column-gap: 0.6rem;
  row-gap: 0;
  flex: 1 1 0;
  min-width: 22px;
  height: 28px;
  line-height: 28px;
  overflow: hidden;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--chrome-text);
  text-decoration: none;
}
.site-nav__mark   { flex-shrink: 0; display: block; }
.site-nav__zr     { color: var(--chrome-brand); }
.site-nav__builds { color: var(--chrome-text); }

.site-nav__links {
  display: flex;
  align-items: center;
  gap: 2rem;
  flex: 0 0 auto; /* the links are never what gives way */
}

.site-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px; /* tap target on phones, without making the bar taller */
  white-space: nowrap;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--chrome-muted);
  text-decoration: none;
  transition: color 0.15s;
}
.site-nav__link:hover,
.site-nav__link--active { color: var(--chrome-text); }

/* ── Footer ──────────────────────────────────────────────────────────── */
.site-footer {
  position: relative;
  z-index: 1;
  text-align: center;
  padding: 1.25rem;
  font-family: var(--chrome-font);
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--chrome-muted);
  border-top: 1px solid var(--chrome-border);
}
.site-footer a {
  color: var(--chrome-muted);
  text-decoration: none;
  transition: color 0.15s;
}
.site-footer a:hover { color: var(--chrome-text); }

/* ── Game header bar ─────────────────────────────────────────────────────
   The bar spans the window; its contents sit in a centred column, the same
   width on every game, so the controls stay near the board instead of
   drifting to the far edges of a wide screen. */
.header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--chrome-bar-bg);
  border-bottom: 1px solid var(--chrome-border);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  font-family: var(--chrome-font);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: var(--chrome-column);
  min-height: 60px;
  margin: 0 auto;
  padding: 8px 20px;
}

.header__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 0;
  min-width: 0;
  /* A size container, so the logo can step aside when the controls need the
     room (below) rather than being drawn underneath the toggle. The
     four-control headers (Codewords, Bulls & Cows) do that on a narrow phone
     with a wide font. */
  container: game-brand / inline-size;
}
.header__logo {
  font-size: 1.4rem;
  line-height: 1;
  flex-shrink: 0;
}
.header__title {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--chrome-text);
}

.header__center {
  display: flex;
  justify-content: center;
  flex: 0 0 auto;
}

.mode-toggle {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  background: var(--chrome-track);
}
.mode-btn {
  border: 0;
  background: transparent;
  color: var(--chrome-muted);
  padding: 6px 16px;
  border-radius: 999px;
  font: 600 0.85rem/1.2 var(--chrome-font);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.mode-btn:hover { color: var(--chrome-text); }
.mode-btn--active,
.mode-btn--active:hover {
  background: var(--chrome-active-bg);
  color: var(--chrome-active-text);
}

.header__nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex: 1 1 0;
}

.nav-btn {
  position: relative; /* for the count badges */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--chrome-border);
  border-radius: 10px;
  background: var(--chrome-surface);
  color: var(--chrome-text);
  font: 600 0.85rem/1 var(--chrome-font);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color 0.15s, opacity 0.15s;
}
.nav-btn:hover:not(:disabled) { border-color: var(--chrome-border-strong); }
.nav-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.nav-btn__icon { font-size: 0.95rem; line-height: 1; }

@container game-brand (max-width: 30px) {
  .header__logo { display: none; }
}

/* ── Game actions ──────────────────────────────────────────────────────────
   The bar under every board: Undo, Reset, Hint, Check, New
   (src/components/GameActions.tsx, identical in every game). Same look as the
   header's buttons, a size up, because these are pressed mid-game: every one
   is at least 44px tall, labelled in words, and the row shares the board's
   width equally. With four buttons on a narrow phone the icon goes above the
   word rather than the word going away. */
.game-actions {
  container: game-actions / inline-size;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 8px;
  width: 100%;
}

.game-action {
  position: relative; /* for the count */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 46px;
  padding: 6px 10px;
  border: 1px solid var(--chrome-border-strong);
  border-radius: 12px;
  background: var(--chrome-surface);
  color: var(--chrome-text);
  font: 600 0.92rem/1.15 var(--chrome-font);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, opacity 0.15s;
}
.game-action:hover:not(:disabled) { border-color: var(--chrome-text); }
.game-action:focus-visible { outline: 2px solid var(--chrome-brand); outline-offset: 2px; }
.game-action:disabled { opacity: 0.4; cursor: not-allowed; }
.game-action[aria-expanded="true"] {
  background: var(--chrome-active-bg);
  border-color: var(--chrome-active-bg);
  color: var(--chrome-active-text);
}

.game-action__icon {
  flex-shrink: 0;
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.game-action__text { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
.game-action__note { font-size: 0.72rem; font-weight: 500; color: var(--chrome-muted); }
.game-action[aria-expanded="true"] .game-action__note { color: inherit; opacity: 0.75; }

/* One or two actions (Bulls & Cows has only Hint) keep a button's width
   rather than stretching into a bar that reads as the main thing to press. */
.game-actions[data-count="1"],
.game-actions[data-count="2"] {
  grid-auto-columns: minmax(0, 200px);
  justify-content: center;
}

/* Hints taken, checks made. */
.game-action__count {
  position: absolute;
  top: -7px;
  right: -7px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: var(--chrome-active-bg);
  color: var(--chrome-active-text);
  font: 700 0.7rem/20px var(--chrome-font);
  text-align: center;
  pointer-events: none;
}

/* Check's result, pointing up at Check from just under the bar. It floats
   over whatever is below (a hint, the pad) for a few seconds rather than
   pushing it down, so nothing moves under the pointer; clicks pass through. */
.game-actions { position: relative; z-index: 2; }
.game-actions__result {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 0;
  pointer-events: none;
}
.game-actions__bubble {
  --arrow: 50%;
  position: absolute;
  top: 10px;
  left: 0;
  width: max-content;
  max-width: min(320px, 100%);
  margin: 0;
  padding: 9px 14px;
  border-radius: 10px;
  background: var(--chrome-active-bg);
  color: var(--chrome-active-text);
  font: 600 0.88rem/1.3 var(--chrome-font);
  text-align: center;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
  animation: game-actions-bubble 0.16s ease-out;
}
.game-actions__bubble::before {
  content: '';
  position: absolute;
  top: -6px;
  left: var(--arrow);
  width: 12px;
  height: 12px;
  margin-left: -6px;
  background: inherit;
  transform: rotate(45deg);
  border-radius: 2px;
}
@keyframes game-actions-bubble {
  from { opacity: 0; transform: translateY(-4px); }
}
@media (prefers-reduced-motion: reduce) {
  .game-actions__bubble { animation: none; }
}

/* Four buttons on a phone: icon above the word. */
@container game-actions (max-width: 420px) {
  .game-actions[data-count="4"] .game-action,
  .game-actions[data-count="5"] .game-action {
    flex-direction: column;
    gap: 3px;
    min-height: 54px;
    padding: 6px 4px;
    font-size: 0.8rem;
  }
  .game-actions[data-count="4"] .game-action__text,
  .game-actions[data-count="5"] .game-action__text { align-items: center; }
}

/* Three on the smallest phones, in a wide font (Linux's DejaVu, or Verdana
   to check it), clipped "Check" beside its icon: the same stacking. */
@container game-actions (max-width: 330px) {
  .game-actions[data-count="3"] .game-action {
    flex-direction: column;
    gap: 3px;
    min-height: 54px;
    padding: 6px 4px;
    font-size: 0.8rem;
  }
  .game-actions[data-count="3"] .game-action__text { align-items: center; }
}

/* ── Narrower windows ──────────────────────────────────────────────────── */

/* Button labels go first: icons only, square buttons. */
@media (max-width: 759px) {
  .nav-btn { width: 40px; height: 40px; padding: 0; }
  .nav-btn__label { display: none; }
}

@media (max-width: 620px) {
  .site-nav { height: 60px; padding: 0 1.25rem; }
  .site-nav__links { gap: 1.25rem; }
}

/* Phones. The title is the next thing to go, kept for screen readers: a
   name, the Daily/Free toggle and three buttons don't fit below this width,
   and showing the title on some games and not others is the inconsistency
   this file exists to remove. Buttons grow to the 44px tap target. */
@media (max-width: 520px) {
  .header__inner { gap: 6px; min-height: 56px; padding: 6px 8px; }
  .header__title {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .header__nav { gap: 2px; }
  .nav-btn { width: 44px; height: 44px; }
  .mode-btn { padding: 6px 11px; }
}

/* Compact nav for every phone, not just small ones. It used to start at
   380px, so a 390px iPhone got the roomier link spacing, ran out of space
   for the wordmark, and showed less than a 375px phone did. */
@media (max-width: 430px) {
  .site-nav { padding: 0 1rem; }
  .site-nav__brand { column-gap: 0.45rem; font-size: 0.95rem; }
  .site-nav__links { gap: 0.9rem; }
  .site-nav__link { font-size: 0.8rem; }
}

@media (max-width: 380px) {
  .mode-btn { padding: 6px 10px; }
}

/* The smallest phones (320-340px). The wordmark cannot fit beside four
   links, so the ZR mark stays alone and the link keeps its accessible name.
   The header's buttons used to shrink to 40px here, when two games had four
   of them; with three in every game they keep the 44px target. */
@media (max-width: 340px) {
  .site-nav__links { gap: 0.75rem; }
  .header__logo { font-size: 1.2rem; }
  .mode-btn { padding: 6px 9px; font-size: 0.8rem; }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav__link, .site-footer a, .mode-btn, .nav-btn, .game-action { transition: none; }
}
