/* ==========================================================================
   Chess — styles.css
   --------------------------------------------------------------------------
   Contents
     1.  Design tokens
     2.  Base / full-bleed background
     3.  Row 1 — title + status
     4.  Row 2 — toolbar
     5.  Board shell, coordinates, evaluation bar, frame + squares
     6.  Selection, legal-move, last-move and check indicators
     7.  Pieces
     8.  Effects layer (slide, capture, promotion, shake)
     9.  Captured trays, legend, scripture line
     10. Modals (promotion chooser, help, seats, settings, coach, carry on)
     11. Game-over overlay + confetti
     12. Responsive + reduced-motion + print
   --------------------------------------------------------------------------
   Sizing note: --cell-size is written by Scripts.js (Fx.measure) whenever the
   board is laid out, so the piece glyphs scale with the real pixel size of a
   square instead of guessing from viewport units. The value below is a sane
   default used before the first measurement and if JS is unavailable.
   ========================================================================== */

/* -------------------------------------------------------------------------- */
/* 1. Design tokens                                                           */
/* -------------------------------------------------------------------------- */

:root {
  /* Page background — deep, rich, and applied to <html> so it covers the
     whole viewport, the overscroll area and any scrolled region. Midnight and
     royal blue under a warm light falling from above the page: the colours of
     a stained-glass window seen from inside, which is where the whole scheme
     comes from. */
  --bg-deep: #0a1526;
  --bg-mid: #16294a;
  --bg-glow: rgba(255, 208, 120, 0.34);

  /* Board.
     --board-size is the wooden frame's outside width, written once because
     three other things have to agree with it exactly: the frame itself, the
     ceiling on the move list beside the board, and the width the move list
     takes when it drops underneath. .has-eval below re-declares it, and every
     user of it inherits the new value for free. */
  --board-size: min(640px, 90vw, 62vh);
  --frame-wood-1: #7a4a24;
  --frame-wood-2: #43260f;
  --frame-wood-3: #9a6236;
  --frame-border: clamp(9px, 2.2vw, 16px);
  --square-light: #f6e3c3;
  --square-light-2: #e9d1a8;
  --square-dark: #8d5a34;
  --square-dark-2: #6f4324;

  /* Text + panels */
  --text: #f4ecdd;
  --text-dim: #cbbba2;
  --panel-bg: rgba(255, 250, 240, 0.96);
  --panel-ink: #2b1c0d;
  --panel-border: rgba(255, 214, 148, 0.55);

  /* Pieces — the filled glyph set is used for both sides, so the colour and
     its contrasting outline are what tell them apart. */
  --white-fill: #fffdf4;
  --white-line: #2a1a08;
  --black-fill: #17130e;
  --black-line: #f7e6c6;

  --gold-1: #fff3b0;
  --gold-2: #ffcc33;
  --gold-3: #b7860b;

  /* Indicators — chosen for maximum contrast on the brown squares */
  --go-core: #b9f6ca;
  --go-edge: #00c853;
  --take: #ff1744;
  --select: #00e5ff;
  --warn: #ffab00;
  --last-move: rgba(255, 214, 79, 0.55);

  /* Buttons — royal blue rather than slate, so they belong to the window
     behind them instead of sitting on top of it. */
  --btn-bg: #2b3f6b;
  --btn-bg-hover: #3a5289;
  --btn-ink: #f4ecdd;
  --btn-primary-1: #ffb300;
  --btn-primary-2: #ef6c00;

  /* Motion (Snappy preset) */
  --dur-slide: 230ms;
  --dur-capture: 640ms;
  --dur-promote: 700ms;

  /* Written by JS; default keeps the page sane without scripting. */
  --cell-size: 64px;

  /* A stack with the classic chess glyphs on Windows, macOS and Linux. */
  --font-chess: 'Segoe UI Symbol', 'Apple Symbols', 'Noto Sans Symbols 2',
                'DejaVu Sans', 'Arial Unicode MS', sans-serif;
}

/* -------------------------------------------------------------------------- */
/* 2. Base / full-bleed background                                            */
/* -------------------------------------------------------------------------- */

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

html {
  min-height: 100%;
  background-color: var(--bg-deep);
  background-image:
    radial-gradient(ellipse 120% 72% at 50% -12%,
                    var(--bg-glow) 0%,
                    rgba(255, 198, 92, 0.11) 36%,
                    rgba(255, 198, 92, 0) 64%),
    linear-gradient(170deg, var(--bg-mid) 0%, var(--bg-deep) 55%, #04080f 100%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-size: cover;
}

body {
  min-height: 100vh;
  margin: 0;
  padding: 14px 12px 28px;
  background: transparent;
  color: var(--text);
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  text-align: center;
  -webkit-text-size-adjust: 100%;
}

.noscript {
  max-width: 32rem;
  margin: 1rem auto;
  padding: 1rem;
  border-radius: 10px;
  background: var(--panel-bg);
  color: var(--panel-ink);
  font-weight: 700;
}

/* Shared focus ring — visible on every interactive control. */
button:focus-visible,
.square:focus-visible {
  outline: 3px solid var(--select);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------- */
/* 3. Row 1 — title + status                                                  */
/* -------------------------------------------------------------------------- */

.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 20px;
  margin: 0 auto 12px;
  max-width: 1000px;
}

.title {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  font-size: clamp(1.7rem, 5.2vw, 2.9rem);
  font-weight: 900;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
}

/* Gradient lettering with a carved 3D drop, plus a plain-colour fallback for
   engines without background-clip:text. */
.title__text {
  position: relative;
  color: var(--gold-2);
  background-image: linear-gradient(180deg, #fff8d6 0%, var(--gold-2) 45%, #e08b00 70%, #ffe27a 100%);
  -webkit-background-clip: text;
  background-clip: text;
  text-shadow:
    0 1px 0 #7a4a00,
    0 2px 0 #5e3800,
    0 3px 0 #472a00,
    0 4px 0 #2f1c00,
    0 6px 14px rgba(0, 0, 0, 0.7);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .title__text {
    -webkit-text-fill-color: transparent;
  }

  /* Re-create the 3D shadow behind the (now transparent) glyphs. */
  .title__text::before {
    content: attr(data-text);
    position: absolute;
    inset: 0;
    z-index: -1;
    -webkit-text-fill-color: #4a2c00;
    color: #4a2c00;
    text-shadow:
      0 2px 0 #382100,
      0 4px 10px rgba(0, 0, 0, 0.75);
  }
}

/* A gilded cross either side of the name. The font stack is the chess one
   because it is the stack already proven to carry uncommon symbols on every
   platform the site is used on, and U+271D lives in the same fonts. */
.title__chip {
  font-family: var(--font-chess);
  font-size: clamp(1.35rem, 4.1vw, 2.3rem);
  line-height: 1;
  color: var(--gold-2);
  text-shadow:
    0 0 12px rgba(255, 214, 130, 0.8),
    0 1px 0 #8a5a00, 0 2px 0 #6b4400,
    0 4px 10px rgba(0, 0, 0, 0.7);
  animation: chip-bob 3.2s ease-in-out infinite;
}

/* The second one breathes out of step with the first, so the pair reads as
   two ornaments rather than one animation played twice. */
.title__chip--late { animation-delay: 1.6s; }

/* A rise rather than the tumble the chess glyphs used to do — a cross that
   rolls from side to side reads as a decoration coming loose. */
@keyframes chip-bob {
  0%, 100% { transform: translateY(0);    opacity: 0.9; }
  50%      { transform: translateY(-5px); opacity: 1; }
}

/* Status chip ---------------------------------------------------------- */

.status {
  min-width: min(340px, 90vw);
  margin: 0;
  padding: 10px 18px;
  border-radius: 999px;
  background: var(--panel-bg);
  border: 2px solid var(--panel-border);
  color: var(--panel-ink);
  font-size: clamp(0.95rem, 2.4vw, 1.1rem);
  font-weight: 700;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  transition: background-color 0.2s ease, color 0.2s ease;
}

.status.is-thinking { color: #4a3a1a; font-style: italic; }
.status.is-win      { background: #1b7f3b; color: #fffdf5; border-color: #79ffa8; }
.status.is-loss     { background: #8e1a12; color: #fff3f0; border-color: #ff9c92; }
.status.is-draw     { background: #4a5560; color: #f4f7fa; border-color: #b6c4d0; }
.status.is-error    { background: #6d1f00; color: #ffe9de; border-color: #ff9a63; }
.status.is-tip      { background: #123a52; color: #e8f7ff; border-color: #6fd0f5; }

/* "You are in check" has to be impossible to miss. */
.status.is-alert {
  background: linear-gradient(180deg, #ff5252, #c50e29);
  color: #fff;
  border-color: #ffd0cc;
  animation: alert-pulse 0.9s ease-in-out infinite;
}

@keyframes alert-pulse {
  0%, 100% { transform: scale(1);    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4); }
  50%      { transform: scale(1.04); box-shadow: 0 6px 22px rgba(255, 23, 68, 0.85); }
}

/* -------------------------------------------------------------------------- */
/* 4. Row 2 — toolbar                                                         */
/* -------------------------------------------------------------------------- */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 0 auto 14px;
  /* Wide enough that all nine controls sit on one line on a desktop, which is
     what keeps the promise of only two rows of chrome above the board. */
  max-width: min(1240px, 98vw);
}

/* The link back to the Bible Games hub is an <a> wearing .btn, so it is the
   same object as every other control in the toolbar and needs no styling of
   its own — only an anchor's underline removed. */
a.btn {
  text-decoration: none;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 13px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 9px;
  background: var(--btn-bg);
  color: var(--btn-ink);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.15);
  transition: background-color 0.15s ease, transform 0.08s ease, box-shadow 0.15s ease;
}

.btn:hover:not(:disabled) { background: var(--btn-bg-hover); }

.btn:active:not(:disabled) {
  transform: translateY(2px);
  box-shadow: 0 0 0 rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  box-shadow: none;
}

.btn--primary {
  background: linear-gradient(180deg, var(--btn-primary-1), var(--btn-primary-2));
  color: #331c00;
  border-color: rgba(255, 255, 255, 0.4);
}

.btn--primary:hover:not(:disabled) {
  background: linear-gradient(180deg, #ffc740, #ff7f1a);
}

.btn--quiet {
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-dim);
}

.btn--quiet:hover:not(:disabled) { background: rgba(255, 255, 255, 0.16); }

.btn--icon {
  padding: 8px 11px;
  font-size: 1.05rem;
}

.btn__icon { font-size: 1.02em; line-height: 1; }

/* Segmented level picker ------------------------------------------------ */

.segmented {
  display: inline-flex;
  padding: 3px;
  border-radius: 11px;
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.seg {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 9px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 0.84rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
}

.seg__glyph { font-size: 1.08em; line-height: 1; }
.seg__num { font-variant-numeric: tabular-nums; }

.seg:hover:not(.is-active) { background: rgba(255, 255, 255, 0.1); color: var(--text); }

/* Each level gets its own colour, cool through to hot. */
.seg.is-active { color: #06280a; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45); }

.seg[data-level="1"].is-active { background: linear-gradient(180deg, #9be59b, #2e9e2e); color: #06280a; }
.seg[data-level="2"].is-active { background: linear-gradient(180deg, #cbe86b, #8bb800); color: #1d2900; }
.seg[data-level="3"].is-active { background: linear-gradient(180deg, #ffd45e, #e8a000); color: #3a2600; }
.seg[data-level="4"].is-active { background: linear-gradient(180deg, #ffab6b, #e06a00); color: #3a1a00; }
.seg[data-level="5"].is-active { background: linear-gradient(180deg, #ff8a7a, #d32f2f); color: #38060a; }

/* A [hidden] button still lays out as inline-flex without this. */
.btn[hidden] { display: none; }

.timer {
  padding: 8px 12px;
  border-radius: 9px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  font-size: 0.95rem;
  min-width: 68px;
}

/* -------------------------------------------------------------------------- */
/* 5. Board shell, coordinates, evaluation bar, frame + squares               */
/* -------------------------------------------------------------------------- */

.board-area {
  display: block;
}

/* Ranks down the left, files along the bottom. Keeping them OUTSIDE the frame
   means #board and #fx-layer stay the only children of the offset parent, so
   the effects layer's pixel maths is unaffected. */
/* Four columns: the rank gutter, the board, the evaluation bar and the move
   list. The third track is `auto`, so while the bar is hidden it measures
   zero and the layout is exactly what it was before the bar existed. Items
   are placed explicitly because they are no longer in reading order. */
.board-shell {
  display: inline-grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-rows: auto auto;
  align-items: stretch;
}

.coords--ranks { grid-column: 1; grid-row: 1; }
.board-frame { grid-column: 2; grid-row: 1; }
.eval { grid-column: 3; grid-row: 1; }
.coords--corner { grid-column: 1; grid-row: 2; }
.coords--files { grid-column: 2; grid-row: 2; }
.eval__num { grid-column: 3; grid-row: 2; }
.history { grid-column: 4; grid-row: 1; }

.coords {
  color: var(--text-dim);
  font-size: clamp(0.62rem, 1.7vw, 0.82rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  user-select: none;
}

/* The padding matches the frame's border so the labels line up with the
   squares rather than with the wooden surround. */
.coords--ranks {
  display: grid;
  grid-template-rows: repeat(8, 1fr);
  align-items: center;
  padding: var(--frame-border) 6px var(--frame-border) 0;
}

.coords--files {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  padding: 5px var(--frame-border) 0;
}

/* The rank gutter and the body padding sit outside this width, which is why
   the viewport share is 90 rather than 94 — see the phone rules in §12, which
   trim the body padding to keep the board as large as it can safely be. */
.board-frame {
  position: relative;                       /* offset parent for .square + .fx-layer */
  width: var(--board-size);
  /* The board is the one thing on the page that is never allowed to change
     size because something beside it grew. Stretching is the grid's default,
     so it is refused here outright rather than only prevented by the move
     list's height cap below. */
  align-self: start;
  border: var(--frame-border) solid var(--frame-wood-1);
  border-radius: 10px;
  background-image: linear-gradient(135deg, var(--frame-wood-3), var(--frame-wood-2) 55%, var(--frame-wood-1));
  box-shadow:
    0 14px 40px rgba(0, 0, 0, 0.6),
    0 0 0 2px rgba(0, 0, 0, 0.5),
    /* A hairline of gilding round the wood, the way an icon is framed. */
    0 0 0 3px rgba(255, 204, 51, 0.42),
    inset 0 0 0 3px var(--frame-wood-2);
}

/* The bar costs about 30px of width, so the board gives that much back rather
   than pushing the page sideways on a phone. Re-declaring the token rather
   than the width keeps the move list in step with the board automatically. */
.board-shell.has-eval { --board-size: min(640px, calc(90vw - 34px), 62vh); }

/* Evaluation bar ---------------------------------------------------------
   White's share is painted up from the bottom of a black track, so the bar
   reads the same way round as the board: the side nearest you is the side at
   the bottom. Flipping the board flips the bar with it. */
.eval {
  display: flex;
  justify-content: center;
  margin-left: 8px;
  /* Matches the frame's border, so the bar lines up with the squares rather
     than with the wooden surround — the same trick .coords--ranks uses. */
  padding: var(--frame-border) 0;
}

.eval[hidden],
.eval__num[hidden] { display: none; }

.eval__bar {
  position: relative;
  flex: 1 1 auto;
  width: 16px;
  min-height: 60px;
  overflow: hidden;
  border: 2px solid var(--frame-wood-2);
  border-radius: 999px;
  background: var(--black-fill);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5);
}

.eval__fill {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 50%;
  background: var(--white-fill);
  transition: height var(--dur-slide) ease-out;
}

.eval.is-flipped .eval__fill { top: 0; bottom: auto; }

/* Sits in the same row as the file letters, level with a-h. */
.eval__num {
  margin-left: 8px;
  padding-top: 5px;
  font-size: 0.66rem;
  font-weight: 800;
  line-height: 1;
  text-align: center;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  user-select: none;
}

/* Move list --------------------------------------------------------------
   A fourth column beside the board on a wide screen; §12 drops it underneath
   on anything narrower. Like the evaluation bar it sits in row 1 only, so its
   top and bottom line up with the squares rather than with the file letters
   below them. The panel is always drawn, even before a move has been played:
   a box that appeared halfway through the first move would resize the board
   under a child's hand. */
.history {
  display: flex;
  flex-direction: column;
  width: 162px;
  /* The height cap is the whole reason the board keeps still. Row 1 is an
     `auto` track, so without it a move list longer than the board grows the
     row, and a strip of bare wood appears under the squares, taller with
     every move. Capped at the frame's own outside height the row can never be
     anything but the board's height, and the list scrolls inside instead. */
  max-height: var(--board-size);
  margin-left: 10px;
  padding: 8px 5px 9px 11px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(0, 0, 0, 0.3);
  text-align: left;
}

.history__title {
  margin: 0 0 5px;
  color: var(--text-dim);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.history__list {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  padding: 0 6px 0 0;
  list-style: none;
  overflow-y: auto;
  line-height: 1.55;
  scrollbar-width: thin;
}

/* Before the first move the list must not grow, or it would push the line
   that explains what the panel is for down to the foot of an empty box. */
.history__list:empty { flex: 0 0 auto; }

/* The number is its own column, so the moves line up under each other however
   long the notation gets. */
.history__row {
  display: grid;
  grid-template-columns: 2em 1fr 1fr;
  align-items: baseline;
  gap: 0 3px;
}

.history__num {
  color: var(--text-dim);
  font-size: 0.76rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.history__san {
  font-family: var(--font-chess);
  font-size: 0.95rem;
  font-weight: 700;
  white-space: nowrap;
}

/* Each move is drawn in the colour of the side that played it, with the same
   outline the captured trays use — that is what keeps a near-black glyph
   legible on a dark panel. */
.history__san--white { color: var(--white-fill); text-shadow: 0 0 2px var(--white-line), 0 1px 2px rgba(0, 0, 0, 0.8); }
.history__san--black { color: var(--black-fill); text-shadow: 0 0 2px var(--black-line), 0 0 4px var(--black-line); }

.history__empty {
  margin: 0;
  color: var(--text-dim);
  font-size: 0.74rem;
  line-height: 1.4;
}

.history__empty[hidden] { display: none; }

/* Input is suspended while a move animates or the computer is thinking. */
.board-frame.is-busy { pointer-events: none; }

.board {
  display: grid;
  grid-template-rows: repeat(8, 1fr);
  width: 100%;
  aspect-ratio: 1 / 1;
}

/* Rows exist for accessibility (role="grid" needs role="row" children) and
   double as the column grid. */
.board-row {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  min-height: 0;
}

@supports not (aspect-ratio: 1 / 1) {
  .board { height: calc(var(--board-size) - var(--frame-border) * 2); }
}

.square {
  position: relative;
  width: 100%;
  height: 100%;
}

.square.light {
  background-color: var(--square-light);
  background-image: linear-gradient(135deg, #fdf0d8, var(--square-light-2));
}

.square.dark {
  background-color: var(--square-dark);
  background-image: linear-gradient(135deg, var(--square-dark), var(--square-dark-2));
}

.square.playable { cursor: pointer; }

/* -------------------------------------------------------------------------- */
/* 6. Selection, legal-move, last-move and check indicators                   */
/* -------------------------------------------------------------------------- */

/* Where the last move came from and went to — chess is much easier to follow
   when the computer's reply is still visible. */
.square.is-last::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--last-move);
  pointer-events: none;
  z-index: 1;
}

/* Selected square: thick white/cyan halo that pulses. Impossible to miss. */
.square.is-selected::after {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 8px;
  box-shadow:
    inset 0 0 0 4px #ffffff,
    inset 0 0 0 8px var(--select),
    0 0 20px 7px rgba(0, 229, 255, 0.85);
  pointer-events: none;
  z-index: 3;
  animation: select-pulse 1s ease-in-out infinite;
}

@keyframes select-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.62; }
}

/* The king that is currently in check. */
.square.is-check::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 6px;
  background: radial-gradient(circle at 50% 50%, rgba(255, 23, 68, 0.75) 0%, rgba(255, 23, 68, 0) 72%);
  box-shadow: inset 0 0 0 5px var(--take);
  pointer-events: none;
  z-index: 3;
  animation: check-pulse 0.8s ease-in-out infinite;
}

@keyframes check-pulse {
  0%, 100% { opacity: 0.75; }
  50%      { opacity: 1; }
}

/* Legal destination: bright core, dark rim, white halo — reads clearly on
   both the light and dark squares. */
.move-marker,
.capture-marker {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
  z-index: 4;
  animation: marker-pulse 1.15s ease-in-out infinite;
}

.move-marker {
  width: 38%;
  height: 38%;
  background: radial-gradient(circle at 50% 38%, #ffffff 0%, var(--go-core) 42%, var(--go-edge) 100%);
  border: 3px solid rgba(0, 0, 0, 0.8);
  box-shadow:
    0 0 0 3px rgba(255, 255, 255, 0.95),
    0 0 16px 5px rgba(0, 200, 83, 0.8);
}

.capture-marker {
  width: 86%;
  height: 86%;
  border: 5px solid var(--take);
  background: radial-gradient(circle, rgba(255, 23, 68, 0) 52%, rgba(255, 23, 68, 0.3) 70%, rgba(255, 23, 68, 0) 100%);
  box-shadow:
    0 0 0 2px rgba(255, 255, 255, 0.9),
    inset 0 0 0 2px rgba(255, 255, 255, 0.85),
    0 0 16px 4px rgba(255, 23, 68, 0.7);
}

@keyframes marker-pulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50%      { transform: translate(-50%, -50%) scale(1.12); }
}

/* Hint flash */
.square.is-hint::after {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 8px;
  box-shadow: inset 0 0 0 5px #ffffff, inset 0 0 0 9px #29b6f6, 0 0 22px 7px rgba(41, 182, 246, 0.9);
  pointer-events: none;
  z-index: 5;
  animation: select-pulse 0.55s ease-in-out infinite;
}

/* -------------------------------------------------------------------------- */
/* 7. Pieces                                                                  */
/* -------------------------------------------------------------------------- */

/* Both sides use the *filled* glyph set (U+265A..U+265F). Colour plus a
   contrasting outline is what separates them, which keeps the shapes solid and
   chunky on every platform instead of relying on thin outline glyphs. */
.piece {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-chess);
  font-size: calc(var(--cell-size) * 0.8);
  line-height: 1;
  pointer-events: none;
  user-select: none;
  z-index: 2;
  transition: transform 0.16s ease, filter 0.2s ease;
}

.piece--white {
  color: var(--white-fill);
  text-shadow:
    2px 0 0 var(--white-line), -2px 0 0 var(--white-line),
    0 2px 0 var(--white-line), 0 -2px 0 var(--white-line),
    1px 1px 0 var(--white-line), -1px 1px 0 var(--white-line),
    1px -1px 0 var(--white-line), -1px -1px 0 var(--white-line),
    0 4px 6px rgba(0, 0, 0, 0.55);
}

.piece--black {
  color: var(--black-fill);
  text-shadow:
    2px 0 0 var(--black-line), -2px 0 0 var(--black-line),
    0 2px 0 var(--black-line), 0 -2px 0 var(--black-line),
    1px 1px 0 var(--black-line), -1px 1px 0 var(--black-line),
    1px -1px 0 var(--black-line), -1px -1px 0 var(--black-line),
    0 4px 6px rgba(0, 0, 0, 0.55);
}

/* --- Interaction states ------------------------------------------------ */

/* The lifted, obviously-picked-up piece. */
.piece.is-selected {
  transform: translateY(-8%) scale(1.14);
  filter: drop-shadow(0 8px 10px rgba(0, 0, 0, 0.6));
}

/* The enemy piece the selected piece is able to take. */
.piece.is-doomed {
  animation: doomed-wobble 0.9s ease-in-out infinite;
}

@keyframes doomed-wobble {
  0%, 100% { transform: rotate(-4deg) scale(0.97); }
  50%      { transform: rotate(4deg) scale(1.03); }
}

/* The king under attack. */
.piece.is-checked {
  animation: checked-throb 0.8s ease-in-out infinite;
}

@keyframes checked-throb {
  0%, 100% { transform: scale(1);    filter: drop-shadow(0 0 4px rgba(255, 23, 68, 0.8)); }
  50%      { transform: scale(1.12); filter: drop-shadow(0 0 14px rgba(255, 23, 68, 1)); }
}

/* Refused click feedback. */
.piece.is-shaking { animation: shake 0.36s ease-in-out; }

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-14%) rotate(-7deg); }
  45%      { transform: translateX(12%) rotate(6deg); }
  70%      { transform: translateX(-8%) rotate(-4deg); }
}

/* Hidden at its origin square while its ghost slides across the board. */
.piece.is-travelling { visibility: hidden; }

/* -------------------------------------------------------------------------- */
/* 8. Effects layer                                                           */
/* -------------------------------------------------------------------------- */

.fx-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 6;
}

/* A square-sized wrapper positioned in px by JS; it holds a cloned .piece so
   all the normal piece styling applies unchanged. */
.fx-cell {
  position: absolute;
  will-change: transform;
}

.fx-cell--slide {
  animation-name: fx-slide;
  animation-duration: var(--dur-slide);
  animation-timing-function: cubic-bezier(0.25, 0.85, 0.35, 1.05);
  animation-fill-mode: forwards;
  z-index: 8;
}

@keyframes fx-slide {
  0% {
    transform: translate(0, 0) scale(1);
  }
  45% {
    transform: translate(calc(var(--dx) * 0.45), calc(var(--dy) * 0.45 - var(--hop))) scale(1.12);
  }
  100% {
    transform: translate(var(--dx), var(--dy)) scale(1);
  }
}

/* Captured piece: flash bright, spin, shrink away — with a sad face. */
.fx-cell--capture {
  animation: fx-capture var(--dur-capture) ease-in forwards;
  z-index: 7;
}

@keyframes fx-capture {
  0%   { transform: scale(1)    rotate(0deg);   opacity: 1;   filter: brightness(1); }
  12%  { transform: scale(1.3)  rotate(-10deg); opacity: 1;   filter: brightness(2.4) saturate(1.6); }
  26%  { transform: scale(1.12) rotate(9deg);   opacity: 1;   filter: brightness(1); }
  40%  { transform: scale(1.2)  rotate(-7deg);  opacity: 1;   filter: brightness(2.4) saturate(1.6); }
  55%  { transform: scale(0.95) rotate(20deg);  opacity: 0.95; filter: brightness(1.2); }
  100% { transform: scale(0)    rotate(200deg); opacity: 0;   filter: brightness(1); }
}

/* Part way through the capture the piece pulls an unhappy face — the glyph is
   swapped by JS, and this rule drops the outline that suits chess pieces but
   not emoji. */
.piece.is-sad {
  color: initial;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
  font-family: 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', var(--font-chess);
  font-size: calc(var(--cell-size) * 0.55);
}

/* Promotion burst */
.fx-cell--promote {
  animation: fx-promote var(--dur-promote) ease-out forwards;
  z-index: 9;
}

.fx-crown {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: calc(var(--cell-size) * 0.62);
  line-height: 1;
  filter: drop-shadow(0 0 10px rgba(255, 215, 0, 0.95));
}

@keyframes fx-promote {
  0%   { transform: scale(0.2) rotate(-40deg); opacity: 0; }
  35%  { transform: scale(1.5) rotate(10deg);  opacity: 1; }
  60%  { transform: scale(1.15) rotate(-5deg); opacity: 1; }
  100% { transform: scale(2.2) rotate(0deg);   opacity: 0; }
}

/* -------------------------------------------------------------------------- */
/* 9. Captured trays, legend, scripture line                                  */
/* -------------------------------------------------------------------------- */

.trays {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 14px;
  margin: 12px auto 0;
  max-width: min(680px, 96vw);
  min-height: 30px;
}

.tray {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.tray__who {
  color: var(--text-dim);
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.tray__pieces {
  font-family: var(--font-chess);
  font-size: 1.15rem;
  line-height: 1.1;
  min-width: 1.2em;
  letter-spacing: -0.06em;
}

/* Captured pieces are always drawn in the colour they were taken from. */
.tray__pieces--white { color: var(--white-fill); text-shadow: 0 0 2px var(--white-line), 0 1px 2px rgba(0, 0, 0, 0.8); }
.tray__pieces--black { color: var(--black-fill); text-shadow: 0 0 2px var(--black-line), 0 1px 2px rgba(0, 0, 0, 0.8); }

.tray__score {
  padding: 3px 11px;
  border-radius: 999px;
  background: linear-gradient(180deg, #ffd45e, #e8a000);
  color: #3a2600;
  font-size: 0.82rem;
  font-weight: 900;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
}

.tray__score:empty { display: none; }
.tray__score.is-behind { background: linear-gradient(180deg, #ff8a7a, #d32f2f); color: #fff2f0; }

.legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px 18px;
  margin: 12px auto 0;
  max-width: min(680px, 96vw);
  color: var(--text-dim);
  font-size: 0.82rem;
  font-weight: 600;
}

.legend__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.legend__swatch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 17px;
  height: 17px;
  font-family: var(--font-chess);
  font-size: 1.05rem;
  font-style: normal;
  line-height: 1;
}

.legend__swatch--you { color: var(--white-fill); text-shadow: 0 0 2px var(--white-line), 1px 1px 0 var(--white-line), -1px -1px 0 var(--white-line); }
.legend__swatch--cpu { color: var(--black-fill); text-shadow: 0 0 2px var(--black-line), 1px 1px 0 var(--black-line), -1px -1px 0 var(--black-line); }

.legend__swatch--move {
  border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, #fff, var(--go-edge));
  border: 2px solid rgba(0, 0, 0, 0.8);
}

.legend__swatch--jump {
  border-radius: 50%;
  background: transparent;
  border: 3px solid var(--take);
}

/* -------------------------------------------------------------------------- */
/* 10. Modals — promotion, help, seats, settings, coach, carry on             */
/* -------------------------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: radial-gradient(circle at 50% 40%, rgba(10, 25, 40, 0.72), rgba(3, 8, 14, 0.93));
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: overlay-in 0.24s ease-out both;
  overflow-y: auto;
}

.modal[hidden] { display: none; }

.modal__card {
  position: relative;
  width: min(460px, 94vw);
  margin: auto;
  padding: 22px 22px 20px;
  border-radius: 20px;
  background: linear-gradient(180deg, #fffaf0, #f2e3c9);
  border: 4px solid var(--gold-2);
  color: var(--panel-ink);
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.7), inset 0 0 0 2px rgba(255, 255, 255, 0.7);
  animation: card-pop 0.4s cubic-bezier(0.18, 1.3, 0.4, 1) both;
}

.modal__card--help { width: min(560px, 94vw); text-align: left; }

.modal__icon {
  font-size: 2.6rem;
  line-height: 1;
  animation: icon-cheer 1.4s ease-in-out infinite;
}

.modal__title {
  margin: 6px 0 6px;
  font-size: clamp(1.25rem, 4.4vw, 1.7rem);
  font-weight: 900;
  color: #8a4b00;
  text-shadow: 0 2px 0 #fff;
  text-align: center;
}

.modal__msg {
  margin: 0 0 14px;
  font-size: 0.95rem;
  font-weight: 600;
  color: #5c4426;
  text-align: center;
}

/* Promotion buttons — four big, obvious targets. */
.promo__row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.promo__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 4px 8px;
  border: 3px solid #d8b57a;
  border-radius: 14px;
  background: #fffdf6;
  color: #4a3416;
  font: inherit;
  font-size: 0.78rem;
  font-weight: 800;
  cursor: pointer;
  transition: transform 0.1s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.promo__btn:hover,
.promo__btn:focus-visible {
  border-color: var(--btn-primary-2);
  background: #fff3d6;
  transform: translateY(-3px);
}

.promo__glyph {
  font-family: var(--font-chess);
  font-size: 2.2rem;
  line-height: 1;
  color: var(--white-fill);
  text-shadow:
    2px 0 0 var(--white-line), -2px 0 0 var(--white-line),
    0 2px 0 var(--white-line), 0 -2px 0 var(--white-line),
    1px 1px 0 var(--white-line), -1px -1px 0 var(--white-line);
}

/* Help card ------------------------------------------------------------- */

.help__list {
  margin: 0 0 14px;
  padding: 0;
  list-style: none;
}

.help__item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid rgba(90, 66, 32, 0.16);
}

.help__item:last-child { border-bottom: 0; }

.help__glyph {
  flex: 0 0 auto;
  width: 1.5em;
  font-family: var(--font-chess);
  font-size: 1.9rem;
  line-height: 1;
  text-align: center;
  color: var(--black-fill);
}

.help__text { font-size: 0.9rem; line-height: 1.4; color: #4a3416; }

.help__note {
  margin: 0 0 16px;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(255, 204, 51, 0.22);
  font-size: 0.88rem;
  line-height: 1.45;
  color: #5c4426;
}

.help__note--small { font-size: 0.8rem; text-align: center; }

#help-close { display: block; margin: 0 auto; }

/* Seat chooser — the "who's playing?" card ------------------------------ */

.modal__card--seats { text-align: center; }

.seat__row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}

.seat__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 14px 8px 11px;
  border: 3px solid #d8b57a;
  border-radius: 16px;
  background: #fffdf6;
  color: #4a3416;
  font: inherit;
  cursor: pointer;
  text-align: center;
  transition: transform 0.1s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.seat__btn:hover,
.seat__btn:focus-visible {
  border-color: var(--btn-primary-2);
  background: #fff3d6;
  transform: translateY(-3px);
}

/* The seating already in play, so it is obvious what is running. */
.seat__btn.is-current {
  border-color: #2e9e2e;
  background: #f0fbef;
  box-shadow: inset 0 0 0 2px rgba(46, 158, 46, 0.35);
}

.seat__glyph {
  font-family: var(--font-chess), 'Segoe UI Emoji', 'Apple Color Emoji', sans-serif;
  font-size: 2rem;
  line-height: 1;
}

/* Only the two king glyphs are chess pieces and want the piece outline. */
.seat__btn[data-seat="white"] .seat__glyph {
  color: var(--white-fill);
  text-shadow:
    2px 0 0 var(--white-line), -2px 0 0 var(--white-line),
    0 2px 0 var(--white-line), 0 -2px 0 var(--white-line),
    1px 1px 0 var(--white-line), -1px -1px 0 var(--white-line);
}

.seat__btn[data-seat="black"] .seat__glyph { color: var(--black-fill); }

.seat__title { font-size: 0.92rem; font-weight: 800; }
.seat__blurb { font-size: 0.74rem; font-weight: 600; color: #7a6444; line-height: 1.25; }

/* .btn--quiet is coloured for the dark page; on a cream card it needs ink
   dark enough to read, the same way the overlay's own quiet button does. */
#newgame-close {
  display: block;
  margin: 0 auto;
  background: rgba(90, 66, 32, 0.1);
  color: #6b5535;
  border-color: rgba(90, 66, 32, 0.25);
  box-shadow: none;
}

#newgame-close:hover:not(:disabled) { background: rgba(90, 66, 32, 0.2); color: #4a3416; }

/* Settings card ---------------------------------------------------------- */

/* Everything optional lives here rather than in the toolbar, so row 2 stays
   one readable line on a phone (see §12) and the board keeps its two rows of
   chrome. A child never has to open this card: the coach turns itself on for
   the two easiest levels, and every other setting has a sensible default. */
.modal__card--settings { width: min(520px, 94vw); text-align: left; }

.set__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid rgba(90, 66, 32, 0.16);
}

.set__row:last-of-type { border-bottom: 0; }

/* Rows that only make sense in one mode (the watch-mode levels) are hidden
   outright rather than disabled — a greyed-out control invites a click. */
.set__row[hidden] { display: none; }

.set__text {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
}

.set__name {
  display: block;
  font-size: 0.95rem;
  font-weight: 800;
  color: #4a3416;
}

.set__blurb {
  display: block;
  margin-top: 2px;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.35;
  color: #7a6444;
}

/* A pill switch with the word beside it, so it reads as On/Off rather than
   relying on colour alone. */
.switch {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 8px;
  padding: 4px;
  border: 0;
  background: none;
  color: #7a6444;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 800;
  cursor: pointer;
}

.switch__track {
  position: relative;
  display: block;
  width: 46px;
  height: 26px;
  border: 3px solid #d8b57a;
  border-radius: 999px;
  background: #efe0c4;
  transition: background-color 0.16s ease, border-color 0.16s ease;
}

.switch__knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fffdf6;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  transition: transform 0.16s ease;
}

.switch.is-on .switch__track { background: var(--go-edge); border-color: #00863a; }
.switch.is-on .switch__knob { transform: translateX(20px); }
.switch.is-on { color: #00863a; }

.switch:focus-visible .switch__track { outline: 3px solid var(--btn-primary-2); outline-offset: 2px; }

.switch__word { min-width: 2.1em; text-align: left; }

/* Rows whose control is too wide to sit beside its label drop underneath it
   instead, which is also what keeps the card usable on a phone. */
.set__row--stack {
  display: block;
  padding-bottom: 14px;
}

.set__sides {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}

.set__side { display: block; }

.set__sidename {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 4px;
  font-size: 0.8rem;
  font-weight: 800;
  color: #6b5535;
}

/* The filled king for both sides, told apart by colour and an outline — the
   same rule the board itself follows. */
.set__sideglyph {
  font-family: var(--font-chess);
  font-size: 1.15rem;
  line-height: 1;
}

.set__sideglyph--white {
  color: var(--white-fill);
  text-shadow:
    1.5px 0 0 var(--white-line), -1.5px 0 0 var(--white-line),
    0 1.5px 0 var(--white-line), 0 -1.5px 0 var(--white-line),
    1px 1px 0 var(--white-line), -1px -1px 0 var(--white-line);
}

.set__sideglyph--black { color: var(--black-fill); }

/* Native controls on purpose: they get the platform's own picker on a phone,
   they are keyboard-accessible for free, and the card stays compact. */
.set__select,
.set__range {
  display: block;
  width: 100%;
  box-sizing: border-box;
}

.set__select {
  padding: 7px 8px;
  border: 3px solid #d8b57a;
  border-radius: 12px;
  background: #fffdf6;
  color: #4a3416;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
}

.set__select:focus-visible,
.set__range:focus-visible { outline: 3px solid var(--btn-primary-2); outline-offset: 2px; }

.set__range {
  height: 28px;
  margin: 6px 0 2px;
  accent-color: var(--btn-primary-2);
  cursor: pointer;
}

.set__value {
  display: block;
  text-align: center;
  font-size: 0.82rem;
  font-weight: 800;
  color: #6b5535;
}

#settings-close { display: block; margin: 16px auto 0; }

/* Coach and resume cards -------------------------------------------------- */

/* Two stacked choices. The safe one is the primary button and comes first,
   because a child reading down the card should meet "think again" before
   "play it anyway", and "carry on" before "start a new game". */
.card__choices {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: stretch;
}

.card__choices .btn { justify-content: center; }

/* .btn--quiet is coloured for the dark page; on a cream card it needs ink
   dark enough to read. */
#coach-go,
#resume-no {
  background: rgba(90, 66, 32, 0.1);
  color: #6b5535;
  border-color: rgba(90, 66, 32, 0.25);
  box-shadow: none;
}

#coach-go:hover:not(:disabled),
#resume-no:hover:not(:disabled) { background: rgba(90, 66, 32, 0.2); color: #4a3416; }

/* Scripture line ---------------------------------------------------------
   Below the board, never above it — the two-rows-of-chrome promise is about
   what a child has to look past to reach the squares. */

.verse {
  max-width: min(680px, 96vw);
  margin: 16px auto 0;
  color: var(--gold-1);
  font-size: 0.88rem;
  font-style: italic;
  line-height: 1.55;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.75);
}

.verse__mark {
  margin-right: 7px;
  color: var(--gold-2);
  font-style: normal;
}

/* The typographer's LORD: a full-size L and small capitals after it, which is
   how the divine name has been set in English Bibles for four centuries. */
.verse__lord {
  font-variant: small-caps;
  font-style: normal;
  letter-spacing: 0.04em;
}

.verse__ref {
  display: inline-block;
  margin-left: 8px;
  color: var(--text-dim);
  font-size: 0.74rem;
  font-style: normal;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* Engine credit --------------------------------------------------------- */

.credit {
  max-width: min(680px, 96vw);
  margin: 18px auto 0;
  color: var(--text-dim);
  font-size: 0.72rem;
  line-height: 1.5;
  opacity: 0.75;
}

.credit a { color: inherit; }

/* -------------------------------------------------------------------------- */
/* 11. Game-over overlay + confetti                                           */
/* -------------------------------------------------------------------------- */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: radial-gradient(circle at 50% 40%, rgba(10, 25, 40, 0.72), rgba(3, 8, 14, 0.93));
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: overlay-in 0.28s ease-out both;
}

.overlay[hidden] { display: none; }

@keyframes overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.overlay__confetti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.overlay__card {
  position: relative;
  z-index: 1;
  width: min(430px, 92vw);
  padding: 26px 24px 22px;
  border-radius: 20px;
  background: linear-gradient(180deg, #fffaf0, #f2e3c9);
  border: 4px solid var(--gold-2);
  color: var(--panel-ink);
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.7), inset 0 0 0 2px rgba(255, 255, 255, 0.7);
  animation: card-pop 0.45s cubic-bezier(0.18, 1.3, 0.4, 1) both;
}

@keyframes card-pop {
  from { transform: scale(0.7) translateY(24px); opacity: 0; }
  to   { transform: scale(1) translateY(0);      opacity: 1; }
}

.overlay__icon {
  font-size: 4rem;
  line-height: 1;
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.35));
  animation: icon-cheer 1.4s ease-in-out infinite;
}

@keyframes icon-cheer {
  0%, 100% { transform: scale(1) rotate(-6deg); }
  50%      { transform: scale(1.14) rotate(6deg); }
}

.overlay__title {
  margin: 8px 0 6px;
  font-size: clamp(1.7rem, 6vw, 2.4rem);
  font-weight: 900;
  letter-spacing: 0.02em;
  color: #8a4b00;
  text-shadow: 0 2px 0 #fff, 0 3px 6px rgba(0, 0, 0, 0.2);
}

.overlay__msg {
  margin: 0 0 18px;
  font-size: 1rem;
  font-weight: 600;
  color: #5c4426;
}

.btn--big {
  padding: 14px 26px;
  font-size: 1.2rem;
  border-radius: 12px;
}

.overlay__close {
  display: block;
  margin: 12px auto 0;
  font-size: 0.82rem;
  background: transparent;
  color: #7a6444;
  box-shadow: none;
  border-color: transparent;
}

.overlay__close:hover:not(:disabled) { background: rgba(0, 0, 0, 0.06); }

/* -------------------------------------------------------------------------- */
/* 12. Responsive + reduced motion + print                                    */
/* -------------------------------------------------------------------------- */

/* Keeping the toolbar on one line is a budget, spent in this order as the
   window narrows: first the level names, then the secondary button labels,
   then the level numbers. "New Game" never loses its label — it is the one
   control a child has to be able to find unaided, and every icon-only button
   keeps both an aria-label and a title.
   The widths below are not round numbers: each one is the width at which the
   toolbar it produces stops fitting in 98vw, measured rather than guessed. Get
   them wrong by ten pixels and the last control — the timer — drops onto a
   line of its own, which is exactly what these steps exist to prevent. */

/* 1. The level names go first — that alone saves nearly 200px. */
@media (max-width: 1259px) {
  .seg__word { display: none; }
}

/* 2. Then the secondary actions become icons only. */
@media (max-width: 1075px) {
  #undo .btn__label,
  #hint .btn__label,
  #help .btn__label,
  #flip .btn__label,
  #pause .btn__label,
  #resign .btn__label { display: none; }

  #undo,
  #hint,
  #help,
  #flip,
  #pause,
  #resign { padding: 8px 10px; font-size: 1rem; }
}

/* The move list keeps its own breakpoint: below this width it would start
   eating the board, so it drops underneath instead — still inside the shell,
   so it lands above the captured trays and costs no chrome above the board.
   The moves then flow across in rows rather than down a column, which keeps
   it short. */
@media (max-width: 1010px) {
  .history {
    /* Column 2 is the board's column, and the width is the board's width, so
       the panel lines up under the squares exactly. Both matter: spanning the
       whole shell with an `auto` width made the move list the widest thing in
       the grid, and the spare space landed in the board's flexible column —
       which is what used to leave the evaluation bar stranded out to the
       right, as though the fourth column were still there. */
    grid-column: 2;
    grid-row: 3;
    width: var(--board-size);
    max-height: 84px;
    margin: 10px 0 0;
    padding: 7px 11px 8px;
  }

  .history__list {
    display: flex;
    flex-wrap: wrap;
    gap: 0 13px;
    padding: 0;
  }

  .history__row { display: inline-flex; gap: 4px; }
}

/* 3. Then the level numbers go, leaving the five animals. */
@media (max-width: 820px) {
  .seg__num { display: none; }
}

/* 4. Below this the buttons themselves tighten. Under ~640px there is simply
   more toolbar than phone and it wraps to two lines; the one-line rule is a
   desktop/tablet promise and readability wins on a phone. */
@media (max-width: 769px) {
  .toolbar { gap: 6px; }
  .btn { padding: 7px 10px; font-size: 0.84rem; }
  .seg { padding: 6px 7px; font-size: 0.8rem; }
  .status { padding: 8px 14px; }
  /* The clock is the last thing on the row, so it is the thing that drops
     onto a line by itself when the budget runs out. Ten pixels here buys the
     whole toolbar another seventy of window. */
  .timer { padding: 7px 9px; font-size: 0.88rem; min-width: 60px; }
}

@media (max-width: 520px) {
  /* Give the board back the room the page padding was using, so 90vw plus the
     rank gutter still fits inside the narrowest phones without side-scrolling. */
  body { padding-left: 6px; padding-right: 6px; }
  .coords--ranks { padding-right: 4px; }

  .seat__row { grid-template-columns: 1fr 1fr; gap: 8px; }
  .seat__glyph { font-size: 1.7rem; }
  .seat__title { font-size: 0.84rem; }
  .seat__blurb { font-size: 0.68rem; }

  /* Only the animal is left in each level button, so it can afford to be
     bigger. The buttons' own sizing is step 5's job now and is deliberately
     not repeated here: a second, looser copy of it at this width used to undo
     the tightening and put the clock back on a line of its own. */
  .seg { font-size: 0.95rem; }
  .segmented { padding: 2px; }
  .status { min-width: 0; width: 100%; }

  .legend { font-size: 0.74rem; gap: 6px 12px; }
  .tray__who { font-size: 0.66rem; }
  .promo__glyph { font-size: 1.8rem; }
  .help__glyph { font-size: 1.6rem; }
}

/* 5. The last of the budget. This buys the final sixty pixels of one-line
   toolbar, and below that it is what keeps ten controls on two rows instead
   of three — the alternative both times being the clock stranded on a line of
   its own. Only the horizontal padding gives way; every target stays 31px
   tall, which is what a child's finger actually needs. */
@media (max-width: 702px) {
  .toolbar { gap: 3px; }
  .btn { padding: 8px 6px; }
  .btn--icon { padding: 8px 7px; }
  .seg { padding: 7px 2px; }
  .segmented { padding: 2px; }
  .timer { padding: 8px 6px; font-size: 0.8rem; min-width: 46px; }
}

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

@media print {
  html { background: #fff; }
  body { color: #000; }
  .toolbar,
  .overlay,
  .modal,
  .legend { display: none !important; }
}
