/* ═══════════════════════════════════════
   THEME — variables & shared base styles
   ═══════════════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500&display=swap');

:root {
  --bg: #0a0a12;
  --surface: #10101a;
  --surface-2: #14141f;
  --border: #252535;
  --text: #e8e8f0;
  --muted: #555570;
  --accent: #a0e0ff;
  --accent-2: #80e0a0;
  --warn: #f0c060;
  --danger: #f08080;
  /* Text color when sitting directly on --accent (buttons, active toggles).
     Light themes that use a dark accent must override this to a light value
     or the text becomes unreadable. */
  --on-accent: #0a0a12;
  --dur: 800ms;
  --ease: cubic-bezier(0.4, 0.0, 0.2, 1);
}

/* ── Alternate themes ─────────────────────────────
   Switched via <html data-theme="..."> from site.js. Each block
   overrides the colour variables only; structural CSS (sizes, fonts,
   animations) is theme-agnostic. */
html[data-theme="dracula"] {
  --bg: #282a36;
  --surface: #21222c;
  --surface-2: #343746;
  --border: #44475a;
  --text: #f8f8f2;
  --muted: #6272a4;
  --accent: #bd93f9;
  --accent-2: #50fa7b;
  --warn: #f1fa8c;
  --danger: #ff5555;
}
html[data-theme="light"] {
  /* Warm "paper" palette: off-white background, white cards that
     stand slightly proud, soft warm borders. The accent is a deep
     dusty teal instead of saturated blue (which fought the rest of
     the UI on the previous iteration), and accent-2 is a muted sage.
     Picked to read as a deliberate light theme rather than an
     inverted dark one. */
  --bg: #f7f5ee;
  --surface: #ffffff;
  --surface-2: #efece1;
  --border: #d6d1bf;
  --text: #1c1a14;
  --muted: #6d685a;
  --accent: #1f6f7a;
  --accent-2: #5e8a4a;
  --warn: #b46a1a;
  --danger: #b13a3a;
  /* Dark teal accent — needs a light text color sitting on it. */
  --on-accent: #f7f5ee;
}
html[data-theme="monokai"] {
  --bg: #272822;
  --surface: #1e1f1c;
  --surface-2: #3e3d32;
  --border: #4a4a3f;
  --text: #f8f8f2;
  --muted: #75715e;
  --accent: #66d9ef;
  --accent-2: #a6e22e;
  --warn: #fd971f;
  --danger: #f92672;
}
html[data-theme="rose"] {
  --bg: #1a1014;
  --surface: #221820;
  --surface-2: #2c2028;
  --border: #4a2a3a;
  --text: #fce8f0;
  --muted: #8a6878;
  --accent: #ffb0c8;
  --accent-2: #ffd6b0;
  --warn: #ffe080;
  --danger: #ff7090;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 300;
  min-height: 100vh;
  /* Crisper rendering for the IBM Plex glyphs against the dark theme. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Defence-in-depth against tooltips / animations / scroll-3d sections
     that occasionally overshoot the viewport by a pixel or two — without
     this, the body briefly grows wider than the viewport and the page
     twitches as the scrollbar appears, then vanishes. `clip` is preferred
     over `hidden` because it doesn't create a new scroll container that
     could break sticky/fixed positioning inside the page. */
  overflow-x: clip;
}

/* Branded text selection */
::selection { background: rgba(160, 224, 255, 0.25); color: var(--text); }
::-moz-selection { background: rgba(160, 224, 255, 0.25); color: var(--text); }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ── Inputs ─────────────────────────────────────── */
input[type=text], input[type=number], textarea, select {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 0.88rem;
  padding: 10px 13px;
  outline: none;
  transition: border-color .2s;
}
input[type=text]:focus, input[type=number]:focus, textarea:focus, select:focus {
  border-color: var(--accent);
}
input[type=text].invalid { border-color: var(--danger); }

/* ── Range slider (cross-browser) ───────────────────
   Native range styling differs wildly across Chrome / Firefox / Safari
   (and worse on iOS). We strip the default chrome and rebuild the
   track + thumb so every browser renders the same flat, cyan-accented
   slider that matches the rest of the UI. The selectors below are
   intentionally duplicated rather than comma-grouped — Chrome and
   Firefox each drop the entire rule if they don't recognise *any*
   selector in the list, so combining ::-webkit and ::-moz pseudos
   would break both. */
input[type=range] {
  -webkit-appearance: none;
  appearance: none;
  width: 130px;
  height: 18px;
  background: transparent;
  cursor: pointer;
  padding: 0;
  margin: 0;
  vertical-align: middle;
}
input[type=range]:focus { outline: none; }

/* WebKit / Blink (Chrome, Safari, Edge) */
input[type=range]::-webkit-slider-runnable-track {
  height: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 13px;
  height: 13px;
  /* Pull the thumb up by (track + border − thumb) / 2 so it sits
     centred on the track; otherwise it floats above on WebKit. */
  margin-top: -6px;
  background: var(--accent);
  border: none;
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgba(160, 224, 255, 0.12);
  transition: box-shadow .15s ease, transform .15s ease;
}
input[type=range]::-webkit-slider-thumb:hover,
input[type=range]:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(160, 224, 255, 0.22);
}
input[type=range]:active::-webkit-slider-thumb {
  transform: scale(1.1);
}

/* Firefox */
input[type=range]::-moz-range-track {
  height: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 2px;
}
input[type=range]::-moz-range-progress {
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
}
input[type=range]::-moz-range-thumb {
  width: 13px;
  height: 13px;
  background: var(--accent);
  border: none;
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgba(160, 224, 255, 0.12);
  cursor: pointer;
  transition: box-shadow .15s ease, transform .15s ease;
}
input[type=range]::-moz-range-thumb:hover,
input[type=range]:focus::-moz-range-thumb {
  box-shadow: 0 0 0 4px rgba(160, 224, 255, 0.22);
}
input[type=range]:active::-moz-range-thumb {
  transform: scale(1.1);
}

/* ── Buttons ─────────────────────────────────────── */
.btn {
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: .12em;
  padding: 10px 16px;
  cursor: pointer;
  text-transform: uppercase;
  transition: opacity .15s;
}
.btn:hover { opacity: .85; }
.btn:disabled { opacity: 0.3; cursor: not-allowed; }

.btn-sec {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
}
.btn-sec:hover { border-color: var(--accent); color: var(--accent); opacity: 1; }

.btn-toggle {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
}
.btn-toggle.active {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}

/* ── Top navigation ─────────────────────────────────────── */
.topnav {
  position: fixed;
  top: 0; right: 0;
  z-index: 5000;
  display: flex;
  gap: 0;
}
.nav-toggle {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;
  border-right: none;
  color: var(--text);
  width: 44px; height: 44px;
  cursor: pointer;
  font-size: 1.1rem;
  display: flex; align-items: center; justify-content: center;
  position: relative;
  transition: color .18s ease;
}
.nav-toggle:hover { color: transparent; }
/* The λ overlay lives on ::before so it doesn't collide with the
   .tt[data-tt]:hover::after tooltip — the button is also a tooltip
   trigger and that rule has higher specificity, which would otherwise
   replace the λ glyph with the tooltip text on hover. */
.nav-toggle::before {
  content: 'λ';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(0deg);
  opacity: 0;
  transition: opacity .22s ease, transform .42s var(--ease);
  pointer-events: none;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 1.35rem;
  color: var(--accent);
}
.nav-toggle:hover::before {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(360deg);
}
@media (prefers-reduced-motion: reduce) {
  .nav-toggle::before { transition: opacity .15s; }
  .nav-toggle:hover::before { transform: translate(-50%, -50%); }
}
.nav-drawer {
  position: fixed;
  top: 0; right: -300px;
  width: 280px;
  /* `100vh` doesn't shrink for the mobile URL bar, so the bottom links
     could end up cut off on phones; svh/dvh tracks the real visible
     viewport, with vh as a fallback for older browsers. */
  height: 100vh;
  height: 100svh;
  height: 100dvh;
  max-width: 90vw;
  background: var(--surface);
  border-left: 1px solid var(--border);
  padding: 60px 0 20px 0;
  transition: right .28s var(--ease);
  z-index: 4900;
  display: flex; flex-direction: column;
  /* Make the link list scrollable when there are more links than fit on a
     small screen — previously, bottom entries (Cheatsheet, About) were
     unreachable on short viewports. `overscroll-behavior: contain` keeps
     scroll inside the drawer rather than rubber-banding the page beneath. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.nav-drawer.open { right: 0; }

/* ── Theme picker (injected at the bottom of every nav drawer by
   site.js). Five swatches showing the palette of each theme; click
   to switch + persist. The active swatch wears a cyan ring. */
.theme-picker {
  margin-top: auto;
  padding: 16px 24px 20px;
  border-top: 1px solid var(--border);
}
.theme-picker-label {
  font-size: 0.65rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 10px;
}
.theme-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.theme-swatch {
  background: var(--surface-2);
  border: 1px solid var(--border);
  cursor: pointer;
  padding: 5px 6px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  transition: border-color .15s, transform .15s;
}
.theme-swatch:hover { border-color: var(--accent); }
.theme-swatch.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(160, 224, 255, 0.18);
}
.theme-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
}
.nav-drawer a {
  padding: 14px 24px;
  color: var(--text);
  text-decoration: none;
  font-size: 0.85rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  transition: background .15s, color .15s;
  /* Lock each link's height so flex layout doesn't squash entries when
     the drawer is shorter than the link list — the user needs to be able
     to scroll to whatever didn't fit. */
  flex: 0 0 auto;
}
.nav-drawer a:hover { background: var(--surface-2); color: var(--accent); }
.nav-drawer a.active { color: var(--accent); }
.nav-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.4);
  opacity: 0; pointer-events: none;
  transition: opacity .28s;
  z-index: 4800;
}
.nav-overlay.open { opacity: 1; pointer-events: auto; }

/* ── Mobile baseline ───────────────────────────────────────────────────
   These rules apply to every page that pulls in theme.css. Page-specific
   layouts (visualizer, play) layer their own breakpoints on top. */
@media (max-width: 700px) {
  /* Inputs run wider so the on-screen keyboard's autocomplete bar
     doesn't obscure tiny target areas. */
  input[type=text], input[type=number], textarea, select {
    font-size: 16px;     /* prevents iOS Safari from auto-zooming on focus */
    padding: 10px 12px;
  }
  .btn { font-size: 0.78rem; padding: 11px 16px; }
  /* Slightly bigger tap targets on the burger so it's reachable with a
     thumb without zooming in. */
  .nav-toggle { width: 48px; height: 48px; font-size: 1.2rem; }
  .nav-drawer { width: 260px; }
  /* Tooltips hide on touch — they trigger on tap and stick around blocking
     the next tap, which is worse than no tooltip at all. */
  .tt[data-tt]:hover::after,
  .tt[data-tt]:hover::before { display: none; }
}

/* ── Tooltip ─────────────────────────────────────── */
.tt {
  position: relative;
}
.tt[data-tt]:hover::after {
  content: attr(data-tt);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 5px 9px;
  font-size: 0.7rem;
  /* Explicit line-height so icon buttons (which use line-height:0 to
     vertically align their SVG) don't collapse the tooltip's text. */
  line-height: 1.4;
  white-space: nowrap;
  letter-spacing: .04em;
  text-transform: none;
  pointer-events: none;
  z-index: 9999;
  font-weight: 300;
}
.tt[data-tt-pos="below"]:hover::after {
  bottom: auto;
  top: calc(100% + 6px);
}
/* Right-anchored tooltip: for buttons sitting near the right edge of the
   viewport (e.g. Draw at the end of the .ir row), centring the tooltip on
   the button extended it past the viewport edge — which briefly created a
   horizontal scrollbar and twitched the whole page. Pin its right edge to
   the button's right instead so the tooltip grows inward. */
.tt[data-tt-align="right"]:hover::after {
  left: auto;
  /* Nudged 1px past the button's right edge — the tooltip is pixel-aligned
     per spec, but reads as slightly inset to the eye because the box's
     border sits 1px inside the right edge of the visible glyphs. */
  right: -1px;
  transform: none;
}
.tt[data-tt-align="left"]:hover::after {
  left: 0;
  right: auto;
  transform: none;
}

/* ── Toast / warnings ─────────────────────────────────────── */
.toast {
  position: fixed;
  bottom: 24px; left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 12px 20px;
  font-size: 0.78rem;
  color: var(--text);
  z-index: 9000;
  opacity: 0;
  pointer-events: none;
  transition: opacity .22s, transform .22s;
  max-width: 70vw;
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.toast.warn { border-color: var(--warn); color: var(--warn); }
.toast.danger { border-color: var(--danger); color: var(--danger); }
.toast.ok { border-color: var(--accent-2); color: var(--accent-2); }

/* ── Cross-page toast (site.js) ───────────────────────── */
.site-toast-host {
  position: fixed;
  top: 22px; left: 50%;
  transform: translateX(-50%);
  z-index: 10000;
  display: flex; flex-direction: column; gap: 8px;
  pointer-events: none;
}
.site-toast {
  background: var(--surface);
  border: 1px solid var(--accent);
  color: var(--text);
  padding: 10px 18px;
  font-size: 0.78rem;
  letter-spacing: .04em;
  display: inline-flex; align-items: center; gap: 10px;
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity .22s, transform .22s;
  box-shadow: 0 6px 24px rgba(0,0,0,.4);
}
.site-toast.show { opacity: 1; transform: translateY(0); }
.site-toast-glyph {
  font-family: Georgia, serif;
  font-size: 1.1rem;
  color: var(--accent);
}

/* Achievement-unlock toast: clickable, jumps to /achievements/.
   Visual nudge ("→") on the right + hover lift make the
   click-affordance obvious without being shouty. */
.site-toast.ach-toast { transition: opacity .22s, transform .22s, border-color .15s, box-shadow .15s; }
.site-toast.ach-toast:hover {
  border-color: var(--accent);
  box-shadow: 0 8px 28px rgba(0,0,0,.5), 0 0 0 1px color-mix(in srgb, var(--accent) 18%, transparent);
}
.ach-toast-arrow {
  color: var(--muted);
  margin-left: 4px;
  transition: transform .15s, color .15s;
}
.site-toast.ach-toast:hover .ach-toast-arrow {
  color: var(--accent);
  transform: translateX(3px);
}

/* ── Fun fact strip (site.js) ─────────────────────────── */
.fun-fact {
  max-width: 720px;
  margin: 28px auto 16px;
  padding: 12px 18px;
  border: 1px dashed var(--border);
  font-size: 0.78rem;
  color: var(--muted);
  text-align: center;
  line-height: 1.55;
  font-weight: 300;
}
.fun-fact code { background: rgba(255,255,255,0.05); padding: 1px 6px; border-radius: 3px; }
.fun-fact-label {
  color: var(--accent);
  letter-spacing: .14em;
  text-transform: uppercase;
  font-size: 0.68rem;
  margin-right: 6px;
}

/* ── No-JS banner ──────────────────────────────────────── */
.noscript-banner {
  display: block;
  background: var(--warn);
  color: #1a1206;
  padding: 12px 20px;
  text-align: center;
  font-size: 0.85rem;
  letter-spacing: .03em;
}
.noscript-banner a { color: #1a1206; text-decoration: underline; font-weight: 500; }

/* Scrollbar styling */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); }
::-webkit-scrollbar-thumb:hover { background: #353550; }
