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

/* Self-hosted so the game makes no third-party request and renders the same
   offline and over file://. Latin subsets of the three families the sam.ai
   design system uses; the first two are variable, covering every weight from
   one file. All three are SIL Open Font License 1.1 — see fonts/LICENSE-*.txt.
   Changing a face means changing its filename: these are cached hard. */

@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-tight-latin-variable.woff2") format("woff2-variations");
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-latin-variable.woff2") format("woff2-variations");
}

@font-face {
  font-family: "EB Garamond";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/eb-garamond-latin-400-italic.woff2") format("woff2");
}

/* ------------------------------------------------------------------ theme */

/* Warm-paper editorial palette, matching the sam.ai design system: cream
   canvas, warm near-black ink, ember accent. Surfaces are separated by
   hairline borders rather than shadows. The four group colours are the one
   addition — they are the game's own vocabulary and stay recognisable in
   both schemes, with dark ink on top of them either way. */
:root {
  --bg: #f7f7f4;
  --bg-tint: #f0efe9;
  --surface: #f7f7f4;
  --surface-2: #f0efe9;
  --surface-3: #e9e7df;
  --text: #26251e;
  --text-soft: #605d52;
  --muted: #8f8b7d;
  --line: #e1dfd6;
  --line-strong: #cfccbf;
  --accent: #f54e00;
  --accent-strong: #d04200;
  --accent-soft: #fdeae1;
  --accent-text: #fff6f1;
  --danger: #9c2136;
  --danger-soft: #f3cfd4;
  --good: #2f6f4f;
  --good-soft: #e3eee7;
  --warn-soft: #f7ecd2;
  --tile: #ece9df;
  --tile-hover: #e4e0d3;
  --tile-selected: #3a3830;
  --tile-selected-text: #f7f7f4;
  --yellow: #f6d96b;
  --green: #a5c66b;
  --blue: #aac2ee;
  --purple: #bb8cc8;
  --on-group: #26251e;
  --radius: 10px;
  --radius-sm: 8px;
  --shadow-float: 0 10px 34px rgba(38, 37, 30, .13);

  --font-sans: "Inter Tight", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-serif: "EB Garamond", Georgia, "Times New Roman", serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

[data-theme="dark"] {
  --bg: #14120b;
  --bg-tint: #1c1a12;
  --surface: #1c1a12;
  --surface-2: #262319;
  --surface-3: #332f22;
  --text: #f2f1ec;
  --text-soft: #aaa696;
  --muted: #7c786a;
  --line: #2b281d;
  --line-strong: #3d3929;
  --accent: #ff5c0f;
  --accent-strong: #ff7433;
  --accent-soft: #2b1608;
  --accent-text: #1c0d04;
  --danger: #ff8fa3;
  --danger-soft: #3d1620;
  --good: #6fc79a;
  --good-soft: #16291d;
  --warn-soft: #2e2612;
  --tile: #2a271c;
  --tile-hover: #363224;
  --tile-selected: #e6e3d8;
  --tile-selected-text: #14120b;
  --yellow: #dcbf4e;
  --green: #92b459;
  --blue: #8faadf;
  --purple: #ad80bb;
  --on-group: #14120b;
  --shadow-float: 0 10px 34px rgba(0, 0, 0, .55);
}

/* -------------------------------------------------------------- baseline */

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

/* Several components below set `display`, which would otherwise beat the
   user-agent rule for [hidden] and leave "hidden" elements on screen. */
[hidden] { display: none !important; }

/* Swapping themes repaints every surface at once. Without this the board and
   the buttons would each ease to their new colour and the page would look
   like it was reloading in pieces. */
.theme-switching *, .theme-switching *::before, .theme-switching *::after {
  transition: none !important;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
}

::selection { background: var(--accent); color: var(--accent-text); }

/* Display headings: regular weight with tight tracking, as on the site. */
h1, h2 { font-weight: 450; letter-spacing: -.03em; }
h3 { font-weight: 500; letter-spacing: -.02em; }

h1, h2, h3 { line-height: 1.25; margin: 0; }
p { margin: 0 0 .85em; }
p:last-child { margin-bottom: 0; }

button { font: inherit; color: inherit; }

kbd {
  display: inline-block;
  padding: .1em .45em;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: .78em;
  white-space: nowrap;
}

.tabular { font-variant-numeric: tabular-nums; }

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: .5rem;
  padding: .5rem 1rem;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-text);
  z-index: 100;
}
.skip-link:focus { left: .5rem; }

/* Read by screen readers, invisible to everyone else. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------- topbar */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .85rem clamp(.9rem, 3vw, 2rem);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.brand { display: flex; align-items: center; gap: .6rem; }

.brand-mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-text);
}

.brand-name { font-weight: 500; font-size: 1.15rem; letter-spacing: -.025em; }

.topbar-actions { display: flex; align-items: center; gap: .5rem; }

/* --------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  padding: .55rem .95rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-weight: 500;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, transform .06s;
}
.btn:hover { background: var(--surface-2); border-color: var(--text-soft); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn:disabled:hover { background: transparent; border-color: var(--line-strong); }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-text);
}
.btn-primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn-primary:disabled:hover { background: var(--accent); border-color: var(--accent); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--text-soft); }
.btn-ghost:hover { background: var(--surface-2); border-color: transparent; color: var(--text); }
.btn-ghost:disabled:hover { border-color: transparent; }

.btn-icon { padding: .5rem; width: 38px; }
.btn-small { padding: .38rem .7rem; font-size: .86rem; }
.btn-block { width: 100%; }
.btn-block + .btn-block { margin-top: .5rem; }

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

.layout {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(280px, 340px);
  gap: clamp(1rem, 3vw, 2.25rem);
  align-items: start;
  justify-content: center;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(1rem, 3vw, 2rem) clamp(.75rem, 3vw, 2rem);
}

.board-column { display: flex; flex-direction: column; gap: .85rem; min-width: 0; }
.side-column { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }

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

.board-meta {
  display: flex;
  align-items: center;
  gap: clamp(.75rem, 2.5vw, 1.5rem);
  padding: .6rem .95rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  width: min(92vw, 560px);
  align-self: center;
}

.meta-item { display: flex; flex-direction: column; line-height: 1.2; }
.meta-label {
  font-family: var(--font-mono);
  font-size: .625rem;
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--muted);
}
.meta-value { font-weight: 500; font-size: 1.02rem; letter-spacing: -.01em; }
.meta-mistakes { margin-left: auto; align-items: flex-end; }

.mistake-dots { display: inline-flex; align-items: center; gap: .4rem; height: 1.45rem; }
.dot {
  width: .8rem;
  height: .8rem;
  border-radius: 50%;
  background: var(--text-soft);
  transition: transform .3s, opacity .3s;
}
/* Spent dots vanish but keep their slot, so the row never jumps sideways. */
.dot.is-spent { transform: scale(0); opacity: 0; }

.board-prompt {
  align-self: center;
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.15rem;
  color: var(--text-soft);
  text-align: center;
}

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

.board-frame { align-self: center; width: min(92vw, 560px); }

.board {
  --tile-h: clamp(3.6rem, 14vw, 5.2rem);
  --gap: .5rem;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  width: 100%;
  /* Four rows tall whatever is showing, so the controls never jump when a
     group is solved and the grid shrinks. */
  min-height: calc(var(--tile-h) * 4 + var(--gap) * 3);
  touch-action: manipulation;
}

.solved-groups { display: flex; flex-direction: column; gap: var(--gap); }
.solved-groups:empty { display: none; }

.solved-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .1rem;
  min-height: var(--tile-h);
  padding: .5rem .85rem;
  border-radius: var(--radius-sm);
  color: var(--on-group);
  text-align: center;
  text-transform: uppercase;
  line-height: 1.25;
}
.group-title { font-weight: 700; font-size: .95rem; letter-spacing: .05em; }
.group-words { font-size: .88rem; letter-spacing: .02em; }

.group-yellow { background: var(--yellow); }
.group-green { background: var(--green); }
.group-blue { background: var(--blue); }
.group-purple { background: var(--purple); }

.solved-group.is-new { animation: row-in .76s ease-out; }
@keyframes row-in {
  from { opacity: 0; transform: scale(.94); }
  to { opacity: 1; transform: none; }
}
/* A row whose four tiles are still on their way up (see gather() in app.js). */
.solved-group.is-gathering { opacity: 0; }

.tiles {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gap);
}

.tile {
  display: grid;
  place-items: center;
  min-height: var(--tile-h);
  padding: .3rem .35rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--tile);
  color: var(--text);
  font-weight: 700;
  font-size: clamp(.7rem, 2.5vw, .98rem);
  line-height: 1.15;
  letter-spacing: .01em;
  text-transform: uppercase;
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background .12s, color .12s, transform .06s;
}
.tile:active { transform: scale(.97); }
@media (hover: hover) {
  .tile:hover { background: var(--tile-hover); }
  .tile.is-selected:hover { background: var(--tile-selected); }
}
.tile[data-size="long"] { font-size: clamp(.62rem, 2.2vw, .86rem); letter-spacing: 0; }
.tile[data-size="xlong"] { font-size: clamp(.55rem, 1.9vw, .76rem); letter-spacing: 0; }
.tile[data-size="xxlong"] { font-size: clamp(.5rem, 1.6vw, .66rem); letter-spacing: -.01em; }
.tile.is-selected { background: var(--tile-selected); color: var(--tile-selected-text); }
.tile:disabled { cursor: default; }

.tile.is-jumping { animation: jump .48s ease-out; }
.tile.is-shaking { animation: shake .42s ease-in-out; }

@keyframes jump {
  0% { transform: translateY(0); }
  40% { transform: translateY(-9px); }
  100% { transform: translateY(0); }
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}

/* After a correct guess, copies of the four tiles glide up into the solved
   section on a layer above the board, then melt into the coloured row. */
.ghost-layer { position: absolute; inset: 0; z-index: 5; pointer-events: none; }
.tile.tile-ghost {
  position: absolute;
  box-sizing: border-box;
  min-height: 0;
  transform-origin: 0 0;
  will-change: transform, opacity;
}

/* -------------------------------------------------------------- controls */

.controls {
  position: relative; /* anchors the toast beneath the buttons */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem;
  width: min(92vw, 560px);
  align-self: center;
}
.controls .btn { border-radius: 999px; padding: .6rem 1.15rem; }

/* --------------------------------------------------------------- results */

/* The results dialog shares the guide's modal chrome; it just needs to be
   narrower, centred, and free to scroll on a short phone screen. */
.modal-panel.result-panel {
  display: block;
  width: min(100%, 24rem);
  padding: 1.5rem 1.3rem 1.4rem;
  border-color: var(--good);
  text-align: center;
  overflow-y: auto;
}
.result-panel h2 { margin-bottom: .4rem; font-size: 1.35rem; }
.result-panel p { color: var(--text-soft); font-size: .92rem; }
.result-mark { font-size: 2.4rem; line-height: 1; margin-bottom: .3rem; }
.result-buttons { display: flex; gap: .5rem; justify-content: center; margin-top: 1rem; flex-wrap: wrap; }

.result-extra {
  margin-top: .5rem;
  padding-top: .6rem;
  border-top: 1px solid var(--line);
  font-size: .85rem;
  font-weight: 550;
  color: var(--good);
}

.result-next {
  margin-top: .6rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}

.share-grid {
  margin: .8rem 0 .2rem;
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.3;
  white-space: pre;
  color: var(--text);
}

/* ----------------------------------------------------------------- cards */

.card {
  padding: 1.05rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.card-title {
  margin-bottom: .75rem;
  font-family: var(--font-mono);
  font-size: .6875rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--muted);
}

.mode-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .4rem;
  margin-bottom: .6rem;
}

.mode-option {
  padding: .5rem .3rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  font-weight: 500;
  font-size: .92rem;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.mode-option:hover { background: var(--surface-2); border-color: var(--text-soft); }
.mode-option[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-text);
}

.play-blurb { min-height: 2.6em; font-size: .84rem; color: var(--text-soft); }

/* ------------------------------------------------------------- hint card */

.hint-text { font-size: .88rem; color: var(--text-soft); }
.hint-list { margin: 0 0 .8rem; padding-left: 1.1rem; font-size: .92rem; font-weight: 550; }
.hint-list li { margin-bottom: .2em; }

/* -------------------------------------------------------------- progress */

.stats-empty { font-size: .86rem; color: var(--muted); }

.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: .4rem;
  margin-bottom: 1rem;
  text-align: center;
}
.stat-value {
  display: block;
  font-size: 1.55rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--accent);
}
.stat-label {
  display: block;
  margin-top: .15rem;
  font-size: .62rem;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.stats-subtitle {
  margin-bottom: .45rem;
  font-family: var(--font-mono);
  font-size: .625rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .14em;
  color: var(--muted);
}

.histogram { display: grid; gap: .3rem; }
.histogram-row {
  display: grid;
  grid-template-columns: 2.4rem minmax(0, 1fr);
  align-items: center;
  gap: .5rem;
}
.histogram-label {
  font-family: var(--font-mono);
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-soft);
  text-align: right;
}
.histogram-bar {
  display: flex;
  justify-content: flex-end;
  min-width: 1.7rem;
  padding: .12rem .45rem;
  border-radius: 4px;
  background: var(--surface-3);
  font-size: .78rem;
  font-weight: 600;
  line-height: 1.4;
  transition: width .3s;
}
.histogram-row.is-loss .histogram-bar { background: var(--danger-soft); color: var(--danger); }
.histogram-row.is-current .histogram-bar { background: var(--accent); color: var(--accent-text); }

.stats-note { margin: .8rem 0; font-size: .78rem; color: var(--muted); }

.tips-card .tip { font-size: .88rem; color: var(--text-soft); min-height: 4.2em; }

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

.footer {
  padding: 1.5rem 1rem 2.5rem;
  text-align: center;
  font-size: .82rem;
  color: var(--muted);
}

/* ----------------------------------------------------------------- modal */

.modal { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 1rem; }
.modal[hidden] { display: none; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(9, 13, 25, .55); backdrop-filter: blur(2px); }

.modal-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(100%, 720px);
  max-height: min(88vh, 820px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-float);
  overflow: hidden;
}

.modal-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.15rem .85rem;
  border-bottom: 1px solid var(--line);
}
.modal-head h2 { font-size: 1.15rem; }

/* flex: none on the chrome, min-height: 0 on the body — otherwise the header
   and tabs get squeezed and the body refuses to scroll. */
.tabs {
  flex: none;
  display: flex;
  gap: .25rem;
  padding: .6rem .8rem 0;
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}
.tab {
  padding: .5rem .8rem;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--text-soft);
  font-weight: 550;
  font-size: .9rem;
  white-space: nowrap;
  cursor: pointer;
}
.tab:hover { color: var(--text); }
.tab.is-active { color: var(--accent); border-bottom-color: var(--accent); }

.modal-body { flex: 1 1 auto; min-height: 0; padding: 1.2rem 1.3rem 1.6rem; overflow-y: auto; }
.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

.modal-body h3 { margin: 1.6rem 0 .5rem; font-size: 1.0625rem; }
.modal-body h3:first-child { margin-top: 0; }
.modal-body .lede {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.15rem;
  line-height: 1.5;
  letter-spacing: -.005em;
  color: var(--text-soft);
  margin-bottom: 1.3rem;
}

.rule-list { margin: 0 0 1em; padding-left: 1.2rem; }
.rule-list li { margin-bottom: .35em; }

.technique { padding-top: .5rem; }
.technique + .technique { border-top: 1px solid var(--line); margin-top: 1.4rem; }

.callout {
  margin-top: 1.5rem;
  padding: .9rem 1rem;
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--accent-soft);
  font-size: .89rem;
}

.swatch {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  margin-right: .45em;
  vertical-align: -.2em;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
}
.swatch-yellow { background: var(--yellow); }
.swatch-green { background: var(--green); }
.swatch-blue { background: var(--blue); }
.swatch-purple { background: var(--purple); }

/* The shortcut table reserves a wide first column for key combinations;
   colour names are short, so claw that space back for the descriptions. */
.colour-key td:first-child { width: 22%; }

.shortcuts { width: 100%; border-collapse: collapse; font-size: .89rem; }
.shortcuts td { padding: .4rem .5rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.shortcuts td:first-child { width: 42%; white-space: nowrap; }
.shortcuts tr:last-child td { border-bottom: 0; }

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

/* Centred just below the board buttons, where the eye already is. */
.toast {
  position: absolute;
  top: calc(100% + .7rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 80;
  padding: .75rem 1.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow-float);
  font-size: 1.08rem;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  animation: toast-in .2s ease-out;
}
.toast[hidden] { display: none; }
@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 8px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* ------------------------------------------------------------ responsive */

@media (max-width: 900px) {
  .layout { grid-template-columns: minmax(0, 1fr); max-width: 580px; }
  .side-column { order: 2; }
}

@media (max-width: 420px) {
  .board-meta { gap: .6rem; padding: .5rem .6rem; flex-wrap: wrap; }
  .brand-name { display: none; }
  .controls .btn { padding: .55rem .9rem; font-size: .9rem; }
  .group-title { font-size: .84rem; }
  .group-words { font-size: .76rem; }
}

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