/* chess-engine demo
   Direction: a precision instrument, not a chess website. The engine's
   internals are the feature, so the data typography carries as much weight as
   the board.

   Two themes, one instrument. Dark is the lit panel; light is the printed
   manual it shipped with. The light theme is not an inversion: the accents are
   re-picked for contrast on paper, because amber that glows on slate turns
   into illegible mustard on white.

   Token names describe the dark theme's appearance, which is awkward for
   theming, so the ROLE of each is written out below and the light theme
   overrides by role. */

:root {
  color-scheme: dark;

  --ink:          #10141C;   /* recessed surface: code blocks, eval track      */
  --slate:        #1A2030;   /* page ground                                    */
  --slate-2:      #222B3D;   /* panel surface                                  */
  --slate-3:      #2E3A50;   /* raised or active chip                          */
  --line:         #37435C;   /* borders and rules                              */
  --stone:        #CBC5B7;   /* primary text                                   */
  --stone-dim:    #8D93A3;   /* secondary text                                 */
  --amber:        #E8A33D;   /* primary accent                                 */
  --cyan:         #5BC8D4;   /* data accent                                    */
  --rose:         #D9556B;   /* danger: check, loss                            */

  --sq-light:     #C7C1B3;
  --sq-dark:      #3A465E;

  --pc-white:     #F4F0E6;
  --pc-black:     #191F2B;
  --pc-shadow:    rgba(0, 0, 0, 0.45);
  --glow:         rgba(91, 200, 212, 0.07);

  /* The eval bar means "white's share of the position", so its fill has to
     stay light and its track dark in BOTH themes. Deriving it from text
     colours inverts the meaning the moment the theme flips. */
  --eval-track:   #10141C;
  --eval-fill-lo: #CBC5B7;
  --eval-fill-hi: #EDE8DC;

  --font-display: "Instrument Serif", Georgia, serif;
  --font-ui:      "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --r: 4px;
}

:root[data-theme="light"] {
  color-scheme: light;

  --ink:          #E7E1D3;
  --slate:        #F7F4ED;
  --slate-2:      #FDFBF5;
  --slate-3:      #E5DECD;
  --line:         #D2C9B6;
  --stone:        #1E2530;
  --stone-dim:    #6E6A60;
  --amber:        #8A5A0C;
  --cyan:         #146273;
  --rose:         #A82F45;

  /* The board keeps its contrast ratio but lifts, so it sits on paper without
     turning into a hole punched through the page. */
  --sq-light:     #DED7C6;
  --sq-dark:      #78859F;

  --pc-white:     #FBF9F3;
  --pc-black:     #161C26;
  --pc-shadow:    rgba(40, 34, 24, 0.35);
  --glow:         rgba(20, 98, 115, 0.06);

  --eval-track:   #5C6879;
  --eval-fill-lo: #F2EFE7;
  --eval-fill-hi: #FFFFFF;
}

* { box-sizing: border-box; }

/* `display` on a component class beats the UA rule for [hidden], so restate it. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--slate);
  color: var(--stone);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background-image:
    radial-gradient(ellipse 80% 50% at 50% -10%, var(--glow), transparent 70%);
}

/* ---------------------------------------------------------- header */

.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem clamp(1rem, 4vw, 2.5rem) 0.9rem;
  border-bottom: 1px solid var(--line);
}

.wordmark {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 4vw, 2rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--stone);
}
.wordmark-dim { color: var(--stone-dim); }

.topnav { display: flex; align-items: center; gap: 1.1rem; }
.topnav a {
  display: inline-flex;
  align-items: center;
  gap: 0.42rem;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--stone-dim);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color 0.15s, border-color 0.15s;
}
.topnav a:hover, .topnav a:focus-visible { color: var(--amber); border-bottom-color: var(--amber); }

/* Brand marks inherit the link colour, so they theme themselves and light up
   on hover with the label rather than sitting there as static artwork. */
.ico { width: 1rem; height: 1rem; flex: none; fill: currentColor; }

/* Below the wide breakpoint the labels go and the marks carry the meaning. */
@media (max-width: 640px) {
  .topnav a span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .topnav a { gap: 0; border-bottom: 0; }
  .ico { width: 1.15rem; height: 1.15rem; }
}

.lang-btn {
  font-family: var(--font-ui);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.32rem 0.7rem;
  color: var(--stone-dim);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.lang-btn:hover, .lang-btn:focus-visible { color: var(--amber); border-color: var(--amber); }

.theme-btn {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  color: var(--stone-dim);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background-color 0.15s;
}
.theme-btn:hover, .theme-btn:focus-visible {
  color: var(--amber);
  border-color: var(--amber);
}
.theme-btn svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
/* One button, two glyphs: show the theme you would switch TO. */
.theme-btn .moon { display: none; }
:root[data-theme="light"] .theme-btn .moon { display: block; }
:root[data-theme="light"] .theme-btn .sun { display: none; }

/* ---------------------------------------------------------- layout */

.shell {
  flex: 1;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: clamp(1rem, 3vw, 2rem) clamp(1rem, 4vw, 2.5rem) 2rem;
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(300px, 0.85fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  align-items: start;
}

@media (max-width: 900px) {
  .shell { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------- board */

.board-col { min-width: 0; }

.board-wrap {
  display: flex;
  gap: 0.75rem;
  align-items: stretch;
}

/* Signature: evaluation as an instrument scale beside the board */
.evalbar { width: 14px; flex: none; }
.evalbar-track {
  position: relative;
  height: 100%;
  background: var(--eval-track);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.evalbar-fill {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 50%;
  background: linear-gradient(to top, var(--eval-fill-lo), var(--eval-fill-hi));
  transition: height 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Playing black flips the board, so the bar flips with it and your own side
   stays at the bottom where you are looking. */
.evalbar.flip .evalbar-fill {
  bottom: auto; top: 0;
  background: linear-gradient(to bottom, var(--eval-fill-lo), var(--eval-fill-hi));
}
.evalbar-mid {
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  background: var(--amber);
  opacity: 0.9;
}
.evalbar-tick {
  position: absolute;
  left: 0; width: 5px;
  top: var(--at);
  height: 1px;
  background: var(--line);
}

/* Keep the whole board plus its controls inside one viewport, so a visitor
   never has to scroll to find the difficulty switch. */
.board-stack {
  position: relative;
  flex: 1;
  min-width: 0;
  max-width: min(100%, calc(100svh - 15rem));
}

.board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  /* Rows must be declared. Left implicit, empty ranks collapse to their
     content height and the squares stop being square. */
  grid-template-rows: repeat(8, 1fr);
  aspect-ratio: 1;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  user-select: none;
  touch-action: manipulation;
}

.sq {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  background: var(--sq-light);
  transition: background-color 0.12s;
}
.sq.dark { background: var(--sq-dark); }
.sq:disabled { cursor: default; }

/* Pieces are drawn, not typeset. Same silhouettes for both sides, separated by
   fill, with one hairline accent picking out the interior. */
.pc {
  pointer-events: none;
  width: 84%;
  height: 84%;
  display: block;
  filter: drop-shadow(0 1px 1.5px var(--pc-shadow));
  animation: place 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
.pc.w { fill: var(--pc-white); }
.pc.b { fill: var(--pc-black); }
/* On paper a near-white piece sitting on a near-white square needs a contour
   of its own, which the drop shadow alone does not provide. */
:root[data-theme="light"] .pc.w {
  stroke: #8A8172;
  stroke-width: 0.9;
  stroke-linejoin: round;
}
.pc .ac {
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
}
.pc.w .ac { stroke: rgba(90, 80, 64, 0.55); }
.pc.b .ac { stroke: rgba(226, 232, 244, 0.42); }
.pc.b .hole { fill: #C9CEDA; }
.pc.w .hole { fill: #6B6252; }

@keyframes place {
  from { transform: scale(0.86); opacity: 0.4; }
  to   { transform: scale(1); opacity: 1; }
}

/* Coordinates, printed like a diagram in a chess book */
.coord {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 0.5rem;
  font-weight: 500;
  opacity: 0.55;
  pointer-events: none;
}
.coord-f { right: 3px; bottom: 1px; }
.coord-r { left: 3px; top: 1px; }
.sq:not(.dark) .coord { color: var(--sq-dark); }
.sq.dark .coord { color: var(--sq-light); }

.sq.sel { background: var(--amber); }
.sq.sel.dark { background: #B9822C; }

.sq.last::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--cyan);
  opacity: 0.16;
  pointer-events: none;
}

/* Legal destinations: a dot for a quiet move, a ring for a capture */
.sq.dest::before {
  content: "";
  position: absolute;
  width: 22%; height: 22%;
  border-radius: 50%;
  background: var(--cyan);
  opacity: 0.75;
  pointer-events: none;
}
.sq.dest.cap::before {
  width: 82%; height: 82%;
  background: transparent;
  border: 3px solid var(--cyan);
  opacity: 0.8;
}

.sq.check { background: var(--rose); }
.sq.check.dark { background: #A93E52; }

.board.thinking { pointer-events: none; }

/* Promotion overlay */
.promo {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 0.75rem;
  background: rgba(16, 20, 28, 0.9);
  backdrop-filter: blur(2px);
  border-radius: var(--r);
  z-index: 5;
}
.promo-title {
  margin: 0;
  text-align: center;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--stone-dim);
}
.promo-row { display: flex; gap: 0.5rem; }
.promo-row button {
  width: 3.25rem; height: 3.25rem;
  font-size: 1.9rem;
  line-height: 1;
  color: #F2EEE4;
  background: var(--slate-3);
  border: 1px solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  transition: background-color 0.14s, border-color 0.14s;
}
.promo-row button:hover, .promo-row button:focus-visible {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--ink);
}

/* Game over. The result is the one moment the page should raise its voice, and
   it is also where the display serif earns its place. Dismissible, because the
   first thing a player wants after a mate is to look at the final position. */
.over {
  position: absolute;
  inset: 0;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.15rem;
  padding: 1.5rem;
  text-align: center;
  background: rgba(16, 20, 28, 0.87);
  backdrop-filter: blur(3px);
  border-radius: var(--r);
  z-index: 6;
  animation: overIn 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}

.over-kind {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--stone-dim);
}

.over-head {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 9vw, 4rem);
  line-height: 1.05;
  font-weight: 400;
  color: var(--stone);
}
.over.win  .over-head { color: var(--amber); }
.over.loss .over-head { color: var(--rose); }
.over.draw .over-head { color: var(--cyan); }

.over-detail {
  margin: 0.5rem 0 0;
  max-width: 26ch;
  font-size: 0.88rem;
  color: var(--stone-dim);
}

.over-actions { display: flex; gap: 0.5rem; margin-top: 1.4rem; }

@keyframes overIn {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}

/* Once dismissed the result still has to stay legible, so the status line
   below the board takes over as a standing marker. */
.status.final {
  font-family: var(--font-display);
  font-size: 1.5rem;
  color: var(--stone);
}
.status.final .win  { color: var(--amber); }
.status.final .loss { color: var(--rose); }
.status.final .draw { color: var(--cyan); }

/* ---------------------------------------------------------- status + controls */

.status {
  margin: 0.9rem 0 1rem;
  font-size: 1rem;
  min-height: 1.5rem;
  color: var(--stone);
}
.status .accent { color: var(--amber); }
.status .danger { color: var(--rose); }
.status.thinking::after {
  content: "";
  display: inline-block;
  width: 0.4em; height: 0.4em;
  margin-left: 0.45em;
  border-radius: 50%;
  background: var(--cyan);
  animation: pulse 0.9s ease-in-out infinite;
  vertical-align: middle;
}
@keyframes pulse { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

.controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.25rem;
  justify-content: space-between;
  align-items: end;
}

.ctl-group { display: flex; flex-direction: column; gap: 0.35rem; }
.ctl-label {
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--stone-dim);
}
.ctl-set { display: flex; flex-wrap: wrap; gap: 0.75rem; }

.seg { display: inline-flex; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.seg button {
  font-family: var(--font-ui);
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.5rem 0.85rem;
  color: var(--stone-dim);
  background: transparent;
  border: 0;
  border-right: 1px solid var(--line);
  cursor: pointer;
  transition: background-color 0.14s, color 0.14s;
}
.seg button:last-child { border-right: 0; }
.seg button:hover { color: var(--stone); }
.seg button.on { background: var(--slate-3); color: var(--amber); }

.btn-row { display: flex; gap: 0.5rem; }
.btn {
  font-family: var(--font-ui);
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.55rem 1rem;
  color: var(--stone);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  transition: background-color 0.14s, border-color 0.14s, color 0.14s;
}
.btn:hover:not(:disabled) { border-color: var(--stone-dim); }
.btn:disabled { opacity: 0.4; cursor: default; }
.btn-primary { background: var(--amber); border-color: var(--amber); color: var(--ink); font-weight: 500; }
.btn-primary:hover { background: #F0B255; border-color: #F0B255; }

/* ---------------------------------------------------------- engine panels */

.engine-col { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }

.panel {
  background: var(--slate-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 1rem 1.1rem 1.1rem;
}
.panel-quiet { background: transparent; }

.panel-head {
  margin: 0 0 0.85rem;
  font-family: var(--font-ui);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--stone-dim);
}

.readout { margin: 0; }
.readout .row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0.34rem 0;
  border-bottom: 1px dotted var(--line);
}
.readout .row:last-child { border-bottom: 0; }
.readout dt { font-size: 0.85rem; color: var(--stone-dim); }
.readout dd { margin: 0; }

.num {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
}
.num.hot { color: var(--rose); }

.hash-block { margin-top: 0.9rem; }
.hash-label {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--stone-dim);
  margin-bottom: 0.35rem;
}
.hash {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  line-height: 1.5;
  color: var(--amber);
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 0.5rem 0.6rem;
  word-break: break-all;
}

/* Move log, set like a scoresheet. Capped at roughly nine move pairs, then it
   scrolls. The scrollbar is styled rather than left to the OS, because macOS
   overlay scrollbars stay invisible until you touch them and the panel just
   looks like it grew. */
.movelog {
  margin: 0;
  padding: 0 0.15rem 0 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  height: 11rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: grid;
  grid-template-columns: 2.2rem 1fr 1fr;
  gap: 0.1rem 0.4rem;
  align-content: start;
  scrollbar-width: thin;
  scrollbar-color: var(--slate-3) transparent;
}
.movelog::-webkit-scrollbar { width: 9px; }
.movelog::-webkit-scrollbar-track { background: var(--ink); border-radius: 5px; }
.movelog::-webkit-scrollbar-thumb {
  background: var(--slate-3);
  border-radius: 5px;
  border: 2px solid var(--ink);
}
.movelog::-webkit-scrollbar-thumb:hover { background: var(--line); }
.movelog li { padding: 0.1rem 0; }
.movelog .n { color: var(--stone-dim); font-size: 0.75rem; }
.movelog .mv { color: var(--stone); }
.movelog .mv.bot { color: var(--cyan); }
/* The log keeps its height when empty so the layout never jumps as moves come
   in. Centring the placeholder makes that reserved space read as deliberate
   rather than as a panel that failed to fill. */
.movelog.is-empty { align-content: center; justify-items: center; }
.movelog-empty {
  grid-column: 1 / -1;
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--stone-dim);
}

.note { margin: 0 0 0.85rem; font-size: 0.84rem; color: var(--stone-dim); }
.note code {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--stone);
}

.snippet {
  margin: 0;
  padding: 0.6rem 0.7rem;
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow-x: auto;
}
.snippet code {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--amber);
}

/* ---------------------------------------------------------- footer */

.foot {
  padding: 1rem clamp(1rem, 4vw, 2.5rem) 1.6rem;
  border-top: 1px solid var(--line);
  font-size: 0.78rem;
  color: var(--stone-dim);
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  justify-content: center;
}
.foot-sep { opacity: 0.5; }
.foot a {
  color: var(--stone);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  transition: color 0.15s, border-color 0.15s;
}
.foot a:hover, .foot a:focus-visible { color: var(--amber); border-bottom-color: var(--amber); }

/* ---------------------------------------------------------- a11y floor */

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

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