/* Encrypted Connect Four: theme (FE-THEME).
   A clean dark interface: dark background, one aqua accent, Barlow (self-hosted
   from ./fonts, SIL OFL), filled buttons, rounded panels. The board frame is a
   sharp rectangle like the toy (Luke, 2026-09-30); nothing else on the page
   is squared. No glow, no scanlines, no rules between header, stage and
   footer, no images, no external requests. Tokens per web/CONTRACT.md 8.4.
   Sections marked ---- . */

/* ---- fonts ------------------------------------------------------------- */

@font-face {
  font-family: "Barlow";
  src: url("./fonts/Barlow-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Barlow";
  src: url("./fonts/Barlow-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Barlow";
  src: url("./fonts/Barlow-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---- tokens ------------------------------------------------------------ */

:root {
  --bg: #06090b;
  --panel: #0b1114;
  --line: #163238;
  --line-hover: #1d4048;
  --phos: #4de3d2;
  --phos-hover: #7aeee0;
  /* contract value #1d7d74 is 3.84:1 on --panel; raised to 4.91:1 because it
     carries small readable text (section labels). */
  --phos-dim: #22908a;
  --text: #cfe6e2;
  /* secondary text: 7.2:1 on --panel */
  --muted: #8da3a0;
  --ok: #57ff6a;
  --bad: #ff5757;
  /* 3.44:1 on --panel: used only for disabled controls and decorative marks */
  --unknown: #5f6b6a;
  --frame: #0f3d6b;
  --frame-edge: rgba(77, 227, 210, 0.35);
  --disc-red: #ff3b4e;
  --disc-yellow: #ffd23f;
  --win: #ffffff;
  --radius: 6px;
  --radius-panel: 10px;
  --font: "Barlow", "Avenir Next", "Segoe UI", system-ui, sans-serif;
  color-scheme: dark;
}

/* ---- base -------------------------------------------------------------- */

* { box-sizing: border-box; }

/* explicit display values below would otherwise defeat the hidden attribute */
[hidden] { display: none !important; }

html {
  height: 100%;
  overflow-x: clip;          /* belt and braces: nothing below should overflow */
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; cursor: pointer; }
a { color: var(--phos); }

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- keyframes --------------------------------------------------------- */

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }

@keyframes winpulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--win); }
  50% { box-shadow: 0 0 0 4px var(--win); }
}

/* ---- small text styles ------------------------------------------------- */

/* The title is the one uppercase thing on the page. */
.tagline {
  margin: 0.25rem 0 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* Explanation of why you cannot act ("Match in play"): a filled block with an
   aqua left edge. */
.why {
  display: inline-block;
  max-width: 100%;
  margin: 0.9rem 0 0;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-left: 3px solid var(--phos);
  border-radius: var(--radius);
  padding: 0.5rem 0.8rem;
  font-size: 0.9rem;
}

.hint {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---- page frame -------------------------------------------------------- */

#app {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: 1.3rem clamp(1rem, 4vw, 3rem) 1rem;
}

#top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.6rem 1.4rem;
  padding-bottom: 1rem;
}
.brand { min-width: 0; }

#title {
  margin: 0;
  color: var(--phos);
  font-size: clamp(1.15rem, 2.6vw, 1.7rem);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.15;
}

/* The footer holds only the kiosk direct link and collapses to nothing when
   that is hidden: no rule, no padding of its own. */
#footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  color: var(--muted);
  font-size: 0.85rem;
}

/* Kiosk footer: the direct link is a small filled chip that may wrap its URL. */
#direct-link {
  max-width: 100%;
  margin-top: 0.9rem;
  border-radius: var(--radius);
  background: var(--line);
  padding: 0.4rem 0.8rem;
  color: var(--text);
  font-size: 0.85rem;
  text-decoration: none;
  overflow-wrap: anywhere;
  transition: background-color 0.12s;
}
#direct-link:hover, #direct-link:focus-visible { background: var(--line-hover); }
#direct-link-text { color: var(--phos); font-weight: 600; }

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

/* One column by default; two (board, panel) at 1024 px and up. */
#stage {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 1.4rem;
  padding: 1.4rem 0;
}

#board-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-self: center;
  max-width: 100%;
}

#panel {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  min-width: 0;
}

.panel-box {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  padding: 1rem 1.1rem;
}

@media (min-width: 720px) and (max-width: 1023.98px) {
  #panel {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
  }
}

@media (min-width: 1024px) {
  #stage {
    grid-template-columns: auto minmax(17rem, 21rem);
    justify-content: center;
    gap: clamp(1.5rem, 4vw, 3.5rem);
  }
  #board-wrap { justify-self: end; }
}

@media (max-width: 719.98px) {
  #app { padding: 1rem 16px 0.8rem; }
  #title { letter-spacing: 0.04em; }
  #controls { flex-direction: column; }
  #controls button { width: 100%; }
}

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

/* --cell is set on the board and on its two siblings so the ghost row and
   the column labels share the pitch even without #board-wrap around them.
   At 1024 px and up the pitch also respects the viewport height, leaving
   about 15 rem for header, footer, ghost row and labels. */
#board-wrap, #board, .board, #ghost-row, #col-labels { --cell: clamp(40px, 9vw, 72px); }
@media (min-width: 1024px) {
  #board-wrap, #board, .board, #ghost-row, #col-labels {
    --cell: clamp(40px, min(9vw, (100vh - 15rem) / 7), 72px);
  }
}

.board {
  position: relative;
  width: calc(var(--cols, 7) * var(--cell));
  height: calc(var(--rows, 6) * var(--cell));
}

/* before board.js has rendered: keep the space, draw a dashed placeholder */
#board:empty {
  width: calc(7 * var(--cell));
  height: calc(6 * var(--cell));
  border: 1px dashed var(--line);
}

.board > .disc-layer,
.board > .frame-layer,
.board > .col-layer { position: absolute; inset: 0; }

/* discs sit in a dark well; the frame's holes reveal them */
.disc-layer { z-index: 1; background: var(--bg); }

.frame-layer {
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(var(--cols, 7), var(--cell));
  grid-auto-rows: var(--cell);
  pointer-events: none;
  /* square corners: the toy's grid is a plain rectangle */
  overflow: hidden;
  box-shadow: 0 0 0 1px var(--frame-edge), 0 12px 32px rgba(0, 0, 0, 0.45);
}

/* each cell is --frame with a round hole cut out of its centre; a thin dark
   rim just inside the hole gives the cut some depth */
.cell {
  --hole: calc(var(--cell) * 0.43);
  width: var(--cell);
  height: var(--cell);
  background: radial-gradient(circle at 50% 50%,
    transparent calc(var(--hole) - 1px),
    rgba(0, 0, 0, 0.55) var(--hole),
    var(--frame) calc(var(--hole) + 2px));
}

.col-layer {
  z-index: 3;
  display: grid;
  grid-template-columns: repeat(var(--cols, 7), var(--cell));
  overflow: hidden;
}

/* transparent full-height hit targets over the columns */
.col {
  appearance: none;
  margin: 0;
  padding: 0;
  border: 0;
  width: var(--cell);
  height: 100%;
  background: transparent;
  color: transparent;
  cursor: pointer;
  transition: background-color 0.12s;
}
.col.hover { background: rgba(77, 227, 210, 0.12); }
.col:focus-visible { outline: 2px solid var(--phos); outline-offset: -3px; }
.col:disabled, .board[data-enabled="0"] .col { cursor: default; }
.board .col.full { cursor: not-allowed; }
.board .col.full.hover { background: rgba(255, 87, 87, 0.08); }

/* discs: 82 percent of a cell, positioned from --row (0 = bottom) and --col
   (0 = left) plus a 9 percent centring offset on each side */
.disc {
  position: absolute;
  width: calc(var(--cell) * 0.82);
  height: calc(var(--cell) * 0.82);
  left: calc(var(--col) * var(--cell) + var(--cell) * 0.09);
  bottom: calc(var(--row) * var(--cell) + var(--cell) * 0.09);
  border-radius: 50%;
  /* any screen reader label inside is pushed out of view */
  overflow: hidden;
  color: transparent;
  text-indent: 100%;
  white-space: nowrap;
}
/* soft inner shading: a darker rim and a lighter crown */
.disc::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow:
    inset 0 0 calc(var(--cell) * 0.14) rgba(0, 0, 0, 0.5),
    inset 0 calc(var(--cell) * 0.04) calc(var(--cell) * 0.06) rgba(255, 255, 255, 0.25);
}
.disc[data-player="cpu"] { background: var(--disc-red); }
.disc[data-player="human"] { background: var(--disc-yellow); }
/* The ghost above the hovered column is exactly a placed yellow disc: same
   colour, same shading, full opacity. Its position tells it apart. */
.disc.ghost { opacity: 1; }
.disc.dim { opacity: 0.55; }
.disc.win { z-index: 2; animation: winpulse 1.2s ease-in-out infinite; }
.disc.dropping { z-index: 3; will-change: transform; }

/* seven slots the width of a cell, above the board */
#ghost-row {
  display: grid;
  grid-template-columns: repeat(7, var(--cell));
  width: calc(7 * var(--cell));
  height: var(--cell);
}
.ghost-slot { position: relative; width: var(--cell); height: var(--cell); }
.ghost-slot .disc {
  left: calc(var(--cell) * 0.09);
  bottom: calc(var(--cell) * 0.09);
}

#col-labels {
  display: grid;
  grid-template-columns: repeat(7, var(--cell));
  width: calc(7 * var(--cell));
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* ---- panel: status, controls ------------------------------------------- */

#status-title {
  margin: 0;
  color: var(--phos);
  font-size: clamp(1.15rem, 2.2vw, 1.4rem);
  font-weight: 600;
  line-height: 1.25;
}
#status[data-turn="none"] #status-title { color: var(--phos); }
#status[data-turn="cpu"] #status-title { color: var(--disc-red); }
#status[data-turn="human"] #status-title { color: var(--disc-yellow); }

/* the idle countdown, shown only in the last minute before a forfeit */
#status-countdown { margin: 0.35rem 0 0; font-variant-numeric: tabular-nums; }

#controls { display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* Primary: solid aqua, dark text. Secondary (.ghost): a quiet filled button. */
#controls button, .center-panel button {
  flex: 1 1 auto;
  min-height: 44px;
  border: 0;
  border-radius: var(--radius);
  background: var(--phos);
  color: var(--bg);
  padding: 0.7rem 1.3rem;
  font-size: 1rem;
  font-weight: 600;
  transition: background-color 0.12s, color 0.12s;
}
#controls button:hover, .center-panel button:hover { background: var(--phos-hover); }
#controls button.ghost, .center-panel button.ghost { background: var(--line); color: var(--text); }
#controls button.ghost:hover, .center-panel button.ghost:hover { background: var(--line-hover); }
#controls button:disabled, .center-panel button:disabled {
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--unknown);
  cursor: not-allowed;
  animation: none;
}

/* ---- overlays ----------------------------------------------------------- */

.overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 1rem;
  overflow: auto;
  background: rgba(4, 7, 9, 0.92);
  z-index: 20;
}

.center-panel {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  align-items: center;
  text-align: center;
  width: min(100%, 30rem);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  padding: 2.2rem clamp(1.2rem, 5vw, 3rem);
}
.center-panel h2 {
  margin: 0;
  color: var(--phos);
  font-size: clamp(1.5rem, 4vw, 2rem);
  font-weight: 700;
  line-height: 1.15;
}
.center-panel button { flex: 0 0 auto; min-width: 12rem; }
.center-panel.bad { border-color: var(--bad); }
.center-panel.bad h2 { color: var(--bad); }
.center-panel.bad .hint { color: var(--text); }

/* warming panel: a title, the elapsed time and the estimate */
#warming-timer { color: var(--text); font-variant-numeric: tabular-nums; }
/* a game is waiting for the engine: the one line that answers "then what?" */
#warming-note { color: var(--text); }

#status-result { margin: 0.45rem 0 0; color: var(--text); }
#go-countdown { margin: 0.35rem 0 0; color: var(--phos); font-variant-numeric: tabular-nums; }

/* ---- toast -------------------------------------------------------------- */

#toast {
  position: fixed;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(70ch, calc(100vw - 32px));
  background: var(--panel);
  border: 1px solid var(--bad);
  border-radius: var(--radius);
  color: var(--text);
  padding: 0.7rem 1.2rem;
  font-size: 0.95rem;
  z-index: 100;
}

/* ---- screen-specific touches --------------------------------------------- */

body[data-screen="attract"] #btn-start { animation: pulse 1.6s ease-in-out infinite; }
body[data-screen="starting"] #status-title,
body[data-screen="cpu_turn"] #status-title,
body[data-screen="human_processing"] #status-title { animation: pulse 1.6s ease-in-out infinite; }
body[data-screen="spectator"] .board .col { cursor: default; }
body[data-screen="out_of_order"] #top { opacity: 0.45; }
body[data-screen="out_of_order"] #stage { opacity: 0.6; }

/* station shell: nothing to select or drag */
body[data-kiosk="1"] { user-select: none; -webkit-user-select: none; }

/* ---- integration tweak: the result panel must not hide the winning line -- */
