:root {
  --ink: #474350;
  --paper: #f8fff4;
  --cream: #fcffeb;
  --lemon: #fafac6;
  --peach: #fecdaa;
  /* Deep peach, used on the light accent surfaces (lemon, peach). Darkened from
     #b45a16 so it clears 4.5:1 on the lemon card, not just 4.43:1. */
  --peach-deep: #a8500f;
  /* Accent that sits on the page background, and flips with the theme so it
     always clears 4.5:1. --peach-deep stays the fixed brand color for the
     light accent surfaces (lemon, peach) it was drawn against. */
  --accent: #a8500f;
  --on-accent: #2f2b3a;
  --border: rgba(71, 67, 80, 0.14);
  --border-strong: rgba(71, 67, 80, 0.27);
  /* Lemon and peach are light brand surfaces: they do not flip with the theme.
     Rings drawn on them use this fixed tint, never the theme's --border-strong,
     which in dark mode is a white halo on a pale chip. */
  --border-on-accent: rgba(71, 67, 80, 0.27);
  --shadow: 0 12px 28px -16px rgba(71, 67, 80, 0.3);
  --shadow-hard: #474350;
  --focus-ring: #a8500f;
  --code-bg: #474350;
  --code-fg: #f8fff4;
  --code-line: rgba(248, 255, 244, 0.18);
  --code-string: #1f6b52;
  --surface: color-mix(in srgb, var(--cream) 55%, transparent);
  --surface-solid: var(--cream);
  --header-height: 86px;
  /* The bar floats over the page rather than sitting beside it, so it carries a
     slightly deeper tone than --paper: at the same value it reads as an empty
     strip with the content sliding underneath it. Light mode sinks toward the
     ink hue; dark mode has no headroom left to sink into, so it goes toward
     black instead. */
  --bar-tone: color-mix(in srgb, var(--paper) 93%, var(--ink));
  /* Secondary text tints from the ink hue rather than sitting at a low
     opacity, so it holds 4.5:1 on every surface it lands on. */
  --ink-muted: #625f69;
  --ink-faint: #6a6971;
  --on-accent-muted: #6b3a0d;
  /* Legibility floors. Functional text never drops below 11px; non-interactive
     micro-labels may sit at 10px. */
  --text-micro: 10px;
  --text-ui: 11px;
  --text-ui-lg: 12px;
  --text-nav: 13px;
  --mono: "DM Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  --sans: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  color-scheme: light;
}

html[data-theme="dark"] {
  --ink: #f8fff4;
  --paper: #474350;
  --ink-muted: #d5d9d3;
  --ink-faint: #ccd0cb;
  --on-accent-muted: #6b3a0d;
  /* The deep peach is a dark-mode failure: on the dark paper it lands at 2.0:1.
     Dark mode carries a light peach accent instead, which reads at 6.7:1. */
  --accent: #fecdaa;
  --border: rgba(248, 255, 244, 0.16);
  --border-strong: rgba(248, 255, 244, 0.3);
  --shadow: 0 12px 28px -16px rgba(0, 0, 0, 0.55);
  --shadow-hard: #1f1c26;
  --focus-ring: #fecdaa;
  --code-bg: #26232d;
  --code-fg: #f8fff4;
  --code-line: rgba(248, 255, 244, 0.14);
  --code-string: #a8e6c0;
--surface: color-mix(in srgb, #ffffff 7%, transparent);
    --surface-solid: color-mix(in srgb, #ffffff 12%, var(--paper));
  --bar-tone: color-mix(in srgb, var(--paper) 90%, black);
  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  html:not([data-theme]) {
    --ink: #f8fff4;
    --paper: #474350;
    --ink-muted: #d5d9d3;
    --ink-faint: #ccd0cb;
    --on-accent-muted: #6b3a0d;
    --accent: #fecdaa;
    --border: rgba(248, 255, 244, 0.16);
    --border-strong: rgba(248, 255, 244, 0.3);
    --shadow: 0 12px 28px -16px rgba(0, 0, 0, 0.55);
    --shadow-hard: #1f1c26;
    --focus-ring: #fecdaa;
    --code-bg: #26232d;
    --code-fg: #f8fff4;
    --code-line: rgba(248, 255, 244, 0.14);
  --code-string: #a8e6c0;
    --surface: color-mix(in srgb, #ffffff 7%, transparent);
    --surface-solid: color-mix(in srgb, #ffffff 12%, var(--paper));
  --bar-tone: color-mix(in srgb, var(--paper) 90%, black);
    color-scheme: dark;
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: auto;
  scroll-padding-top: calc(var(--header-height) + 24px);
}

body {
  margin: 0;
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  transition: none;
}

h1, h2, h3, h4, p, figure, blockquote, pre { margin-top: 0; }

h1 {
  font-size: clamp(44px, 5.6vw, 72px);
  line-height: 0.94;
  letter-spacing: -0.035em;
  font-weight: 800;
  text-wrap: balance;
}

h2 {
  font-size: clamp(34px, 4vw, 52px);
  line-height: 1;
  letter-spacing: -0.03em;
  font-weight: 800;
  text-wrap: balance;
  margin-bottom: 0;
}

h3 { font-weight: 700; }

h1 em, h2 em { color: var(--accent); font-style: normal; }
h2 span { color: var(--accent); }

img, svg, video { display: block; max-width: 100%; }

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

a {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

button, input, select { color: inherit; font: inherit; cursor: pointer; }

textarea { color: inherit; font: inherit; cursor: text; }

:where(a, button, input, textarea, select, [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: 2px;
}

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

.skip-link {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 50;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--paper);
  font: var(--text-ui)/1.4 var(--mono);
  transform: translateY(-250%);
  transition: transform 0.2s var(--ease);
}

.skip-link:focus-visible { transform: translateY(0); }

.container { width: min(1180px, calc(100% - 64px)); margin: 0 auto; }

.is-hidden { display: none; }

[hidden] { display: none !important; }

.section-kicker {
  color: var(--accent);
  font: var(--text-ui)/1 var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin: 0 0 26px;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  border: 1px solid var(--ink);
  padding: 15px 17px 15px 21px;
  font: var(--text-ui-lg)/1 var(--mono);
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease, color 0.12s ease;
}

.button:hover { transform: translateY(-1px); box-shadow: 3px 3px 0 var(--shadow-hard); }
.button--primary { background: var(--ink); color: var(--paper); }
.button--primary:hover { background: var(--peach); border-color: var(--on-accent); color: var(--on-accent); }
.button-arrow { font-size: 16px; line-height: 10px; }
.button--outline { border-color: var(--border-strong); margin-top: 29px; gap: 24px; }
.button--outline:hover { background: var(--lemon); color: var(--on-accent); border-color: var(--on-accent); }

.text-link, .card-link {
  font: var(--text-ui-lg)/1.4 var(--mono);
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 5px;
  transition: color 0.25s ease, border-color 0.25s ease;
}

.text-link span, .card-link span { margin-left: 9px; font-size: 14px; }
.text-link:hover, .card-link:hover { color: var(--accent); border-color: var(--accent); }

/* ---- Initial motion -------------------------------------------------------
   Under .js the page starts poised, then the inline boot at the end of each
   page marks the document ready and releases the blocks already on screen as
   soon as the markup is parsed, so the first screen never waits on the module
   bundle. If JS never boots, the head fallback strips .js after 1.5s and
   everything is simply visible, so motion can never withhold content. */

html.js .reveal {
  opacity: 0;
  transition: opacity 0.7s var(--ease);
}
html.js .reveal.is-visible { opacity: 1; }

/* Each direct child slides up into place, staggered by position in the block.
   --enter-base lets a delayed block push its whole cascade back in step. */
html.js .reveal { --enter-base: 0s; --enter-step: 0.07s; }
html.js .reveal--delay { --enter-base: 0.1s; }
html.js .reveal--delay-more { --enter-base: 0.2s; }
html.js .reveal > * {
  translate: 0 18px;
  transition: translate 0.7s var(--ease);
  transition-delay: var(--enter-base);
}
html.js .reveal.is-visible > * { translate: 0 0; }
html.js .reveal.is-visible > *:nth-child(2) { transition-delay: calc(var(--enter-base) + var(--enter-step)); }
html.js .reveal.is-visible > *:nth-child(3) { transition-delay: calc(var(--enter-base) + var(--enter-step) * 2); }
html.js .reveal.is-visible > *:nth-child(4) { transition-delay: calc(var(--enter-base) + var(--enter-step) * 3); }
html.js .reveal.is-visible > *:nth-child(5) { transition-delay: calc(var(--enter-base) + var(--enter-step) * 4); }
html.js .reveal.is-visible > *:nth-child(6) { transition-delay: calc(var(--enter-base) + var(--enter-step) * 5); }

.site-header {
  position: fixed;
  z-index: 20;
  top: 0;
  left: 0;
  width: 100%;
  /* --bar-height is scoped to the header rather than :root so the page's own
     offsets — scroll-padding, main's padding — stay put while the bar contracts.
     Once the page has moved, the bar has done its job as a landmark and gives
     the height back to the content. */
  --bar-height: var(--header-height);
  /* Kept slightly translucent so the page reads as passing underneath, with a
     blur behind it — without the blur the text scrolling through shows through
     the letters. */
  background: color-mix(in srgb, var(--bar-tone) 90%, transparent);
  -webkit-backdrop-filter: saturate(1.5) blur(12px);
  backdrop-filter: saturate(1.5) blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease, background 0.3s ease, opacity 0.5s var(--ease), translate 0.5s var(--ease);
}

html.js:not(.is-ready) .site-header { opacity: 0; translate: 0 -14px; }
html.js.is-ready .site-header { opacity: 1; translate: 0 0; }

.site-header.is-scrolled { --bar-height: calc(var(--header-height) - 22px); border-color: var(--border); }

.nav {
  height: var(--bar-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 25px;
  transition: height 0.3s var(--ease);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  width: max-content;
}
.site-header .brand-name { font-size: 20px; transition: font-size 0.3s var(--ease); }
.site-header.is-scrolled .brand-name { font-size: 17px; }
html.js:not(.is-ready) .site-header .brand { opacity: 0; translate: 0 -8px; }
html.js.is-ready .site-header .brand { animation: nav-drop 0.5s var(--ease) 0.05s backwards; }
.brand-name { font-size: 20px; font-weight: 800; letter-spacing: -0.03em; }
.brand-dot { color: var(--accent); }

.boa-mark { width: 31px; height: 31px; overflow: visible; transform: rotate(-12deg); transition: width 0.3s var(--ease), height 0.3s var(--ease); }
.site-header.is-scrolled .boa-mark { width: 26px; height: 26px; }
.boa-mark__coil { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.boa-mark__head { fill: var(--peach); stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; }
.boa-mark__eye { fill: var(--ink); }

.nav-links { display: flex; align-items: center; gap: 25px; margin-left: auto; }

/* Nav items are primary navigation, not micro-labels: they carry a real
   reading size and enough tap height to be usable. */
.nav-links a, .footer-links a {
  font: var(--text-nav)/1.4 var(--mono);
  letter-spacing: 0.01em;
  color: var(--ink-muted);
  transition: color 0.25s ease;
}

.nav-links a { padding: 10px 0; }

html.js:not(.is-ready) .site-header .nav-links a { opacity: 0; translate: 0 -8px; }
html.js.is-ready .site-header .nav-links a { animation: nav-drop 0.5s var(--ease) backwards; }
html.js.is-ready .site-header .nav-links a:nth-child(1) { animation-delay: 0.12s; }
html.js.is-ready .site-header .nav-links a:nth-child(2) { animation-delay: 0.17s; }
html.js.is-ready .site-header .nav-links a:nth-child(3) { animation-delay: 0.22s; }
html.js.is-ready .site-header .nav-links a:nth-child(4) { animation-delay: 0.27s; }
html.js.is-ready .site-header .nav-links a:nth-child(5) { animation-delay: 0.32s; }

.nav-links a:hover, .nav-links a.is-active, .footer-links a:hover {
  color: var(--accent);
}

.nav-actions { display: flex; gap: 8px; align-items: center; }

.icon-button, .menu-toggle {
  position: relative;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: transparent;
  transition:
    background 0.28s var(--ease), border-color 0.28s var(--ease), color 0.28s var(--ease),
    translate 0.4s var(--ease), scale 0.3s var(--ease), box-shadow 0.4s var(--ease);
}

html.js:not(.is-ready) .site-header .nav-actions > * { opacity: 0; translate: 0 -8px; }
html.js.is-ready .site-header .nav-actions > * { animation: nav-drop 0.5s var(--ease) backwards; }
html.js.is-ready .site-header .nav-actions > *:nth-child(1) { animation-delay: 0.3s; }
html.js.is-ready .site-header .nav-actions > *:nth-child(2) { animation-delay: 0.35s; }
html.js.is-ready .site-header .nav-actions > *:nth-child(3) { animation-delay: 0.4s; }
html.js.is-ready .site-header .nav-actions > *:nth-child(4) { animation-delay: 0.45s; }

@keyframes nav-drop {
  from { opacity: 0; translate: 0 -8px; }
  to { opacity: 1; translate: 0 0; }
}

/* The halo is drawn outside the button so the hover reads as a lift plus a
   ring, not just a colour swap. It doubles as the state-change ping. */
.icon-button::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--accent) 65%, transparent);
  opacity: 0;
  scale: 0.8;
  transition: opacity 0.3s var(--ease), scale 0.5s var(--ease);
  pointer-events: none;
}

/* Hover and active swap in the light brand surfaces, so the glyph must swap to
   the fixed dark tints too: --ink follows the theme and would put a near-white
   glyph on the lemon chip (1.05:1) in dark mode. */
.icon-button:hover, .menu-toggle:hover {
  background: var(--lemon);
  border-color: var(--border-on-accent);
  color: var(--on-accent);
  translate: 0 -2px;
  box-shadow: 0 9px 16px -11px var(--shadow-hard);
}
.icon-button:hover::before, .menu-toggle:hover::before { opacity: 1; scale: 1; }
.icon-button:active {
  background: var(--peach);
  border-color: var(--border-on-accent);
  color: var(--on-accent);
  scale: 0.94;
  translate: 0 0;
  box-shadow: none;
}
.icon-button svg { width: 15px; height: 15px; scale: 1; transition: scale 0.4s var(--ease); }
.icon-button:hover svg { scale: 1.16; }

@keyframes control-ping {
  0% { opacity: 0.9; scale: 0.85; }
  70% { opacity: 0.35; }
  100% { opacity: 0; scale: 1.75; }
}

/* Two icon systems share this slot. The brand marks (GitHub, Discord) are solid
   filled paths, so they must never also take a stroke — outlining a filled
   glyph fattens it and closes its counters. Only the line-drawn icons
   (theme, sound) are stroked. */
.icon-button svg:not([class]) { fill: currentColor; stroke: none; }
.icon-button svg[class] {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-button[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%) translateY(-3px);
  padding: 5px 7px;
  border-radius: 4px;
  background: var(--ink);
  color: var(--paper);
  font: var(--text-micro)/1.2 var(--mono);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.08s ease, transform 0.08s ease;
}

.icon-button[data-tooltip]:hover::after,
.icon-button[data-tooltip]:focus-visible::after { opacity: 1; transform: translateX(-50%) translateY(0); }

.icon-button { color: var(--ink); }
.theme-toggle .moon-icon { display: none; }
[data-theme="dark"] .theme-toggle .sun-icon { display: none; }
[data-theme="dark"] .theme-toggle .moon-icon { display: block; }

/* Sound is off by default, so the muted glyph is the resting state. When it is
   on the button wears a persistent peach chip: a glyph tint alone was too easy
   to miss, and the lemon hover chip used to erase the on/off distinction. */
.sound-toggle .sound-off-icon { display: none; }
.sound-toggle:not(.is-on) .sound-on-icon { display: none; }
.sound-toggle:not(.is-on) .sound-off-icon { display: block; }
.sound-toggle.is-on,
.sound-toggle.is-on:hover,
.sound-toggle.is-on:active {
  background: var(--peach);
  border-color: var(--border-on-accent);
  color: var(--on-accent);
}
.sound-toggle.is-on::before { border-color: color-mix(in srgb, var(--peach) 75%, transparent); }
.sound-toggle.is-pinging::before { animation: control-ping 0.6s var(--ease); }

.menu-toggle { display: none; border: 0; border-radius: 0; gap: 5px; }
.menu-toggle span { width: 18px; height: 1px; display: block; background: var(--ink); transform-origin: center; transition: transform 0.25s var(--ease), background 0.28s var(--ease); }
.menu-toggle:hover span { background: var(--on-accent); }
.menu-toggle[aria-expanded="true"] span:first-child { transform: translateY(3px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] span:last-child { transform: translateY(-3px) rotate(-45deg); }

.footer { border-top: 1px solid var(--border); }
.footer-inner { min-height: 90px; display: flex; align-items: center; justify-content: space-between; gap: 25px; }
.footer-copy { font: var(--text-ui)/1.6 var(--mono); color: var(--ink-muted); }
.footer-copy span { display: inline-block; margin-left: 15px; color: var(--ink-faint); }
.footer-links { display: flex; flex-wrap: wrap; gap: 24px; }

@media (max-width: 900px) {
  .nav-links { gap: 14px; }
}

@media (max-width: 700px) {
  :root { --header-height: 74px; }
  .container { width: min(100% - 36px, 560px); }
  .nav-links {
    position: absolute;
    /* The header is the containing block and its height is the bar's, so 100%
       tracks the bar as it contracts on scroll. */
    top: 100%;
    left: 18px;
    right: 18px;
    padding: 8px;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--paper);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
  }
  .nav-links.is-open { display: flex; }
  .nav-links a { padding: 14px 12px; border-bottom: 1px solid var(--border); }
  .nav-links a:last-child { border-bottom: 0; }
  .menu-toggle { display: grid; }
  html:not(.js) .site-header { position: static; }
  html:not(.js) main { padding-top: 0; }
  html:not(.js) .nav { height: auto; flex-wrap: wrap; padding: 14px 0; gap: 14px; }
  html:not(.js) .nav-links {
    position: static;
    order: 3;
    width: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 4px 18px;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
  }
  html:not(.js) .nav-links a { padding: 6px 0; border-bottom: 0; }
  html:not(.js) .menu-toggle { display: none; }
  .footer-inner { min-height: 145px; flex-wrap: wrap; padding: 25px 0; gap: 18px; }
  .footer-copy { order: 3; width: 100%; }
  .footer-copy span { margin-left: 0; display: block; }
  .footer-links { gap: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  html.js .reveal, html.js .reveal.is-visible { opacity: 1; transition: none; }
  html.js .reveal > *, html.js .reveal.is-visible > * { translate: none; transition: none; }
  /* The entrance rules carry an extra .is-ready class, so these overrides need
     !important to win: without it the nav sits behind its animation delay and
     stays invisible for the best part of a second. */
  html.js .site-header,
  html.js .site-header .brand,
  html.js .site-header .nav-links a,
  html.js .site-header .nav-actions > * { opacity: 1 !important; translate: none !important; animation: none !important; }
  .icon-button, .icon-button svg, .icon-button:hover, .icon-button:hover svg { translate: none; scale: none; box-shadow: none; transition: none; }
  .hero-glow, .site-header, .button, .floating-badge, .feature-card, .theme-card, .contributor-link { filter: none !important; }
}
