/* -------------------------------------------------------
   Fonts (self-hosted, was Google Fonts CDN)
------------------------------------------------------- */
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("../fonts/space-grotesk-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* -------------------------------------------------------
   Tokens
------------------------------------------------------- */
:root {
  --bg: #0b0d10;
  --bg-elevated: #121519;
  --bg-elevated-2: #171b20;
  --line: #1f2328;
  --line-soft: #191d22;
  --text: #edeff1;
  --text-dim: #9098a1;
  --text-faint: #575d66;
  --accent: #ef4b3a;
  --accent-soft: rgba(239, 75, 58, 0.14);
  --accent-line: rgba(239, 75, 58, 0.35);

  /* Hero binary-field palette: the site's own original warm rust/red-orange,
     same hue as --accent (H 6°), held muted (L 0.41-0.54, S 0.14-0.23) so
     the resting digits read as quiet texture. -hud is the same brighter
     hover-orange used on .btn-primary:hover (#ff6250), for the cursor glow
     / corner brackets. -glitch is a vivid red (distinct hue from the
     orange field, so the flash actually reads as a flash) for the rare
     "signal glitch". Read by js/binary-field.js via getComputedStyle(hero)
     — these tokens are the single source of truth for every color in the
     hero; -base/-range: bright end = base + range (rgb(165, 120, 110) =
     #a57866). */
  --hero-field-rgb-base: 120, 95, 90;
  --hero-field-rgb-range: 45, 25, 20;
  --hero-hud: #ff6250;
  --hero-hud-rgb: 255, 98, 80;
  --hero-glitch: #ed271d;
  --hero-glitch-rgb: 237, 39, 29;

  /* Hero title glow gradient: two muted ember/red tones only (no white/ivory —
     that was still reading as white and glaring on dark-mode eyes), flowing
     slowly via background-position animation. Used by .hero-title below.
     -dark is the actual dark end of the gradient (was previously duplicating
     -orange's value by mistake). */
  --hero-flame-orange: #a12727;
  --hero-flame-red: #bf0000;
  --hero-flame-dark: #400000;

  --font-display: "Space Grotesk", "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;

  --container: 1080px;
  --edge: clamp(20px, 6vw, 64px);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* -------------------------------------------------------
   Reset
------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }

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

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

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

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  margin: 0;
  letter-spacing: -0.01em;
}

p { margin: 0; }
ul { list-style: none; margin: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
img, svg { display: block; max-width: 100%; }

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: #100;
  padding: 10px 16px;
  z-index: 999;
  font-weight: 600;
}
.skip-link:focus {
  left: 16px;
  top: 16px;
}

.grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.section-inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--edge);
}

.ext-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

/* -------------------------------------------------------
   Header / nav
------------------------------------------------------- */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: border-color 0.4s var(--ease), background-color 0.4s var(--ease);
}
.site-header.scrolled {
  background: rgba(11, 13, 16, 0.82);
  backdrop-filter: blur(10px);
  border-bottom-color: var(--line);
}

.header-inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 16px var(--edge);
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: nowrap;
}

.logo {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15px;
  flex: 0 0 auto;
}
.logo-mark {
  width: 20px;
  height: 20px;
  display: block;
  flex-shrink: 0;
}

.primary-nav {
  display: flex;
  align-items: center;
  gap: 28px;
  font-size: 13.5px;
  color: var(--text-dim);
  flex: 0 0 auto;
  margin-left: auto;
}
.primary-nav a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  position: relative;
  padding: 2px 0;
  transition: color 0.2s var(--ease);
}
.primary-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -4px;
  height: 1px;
  background: var(--accent);
  transition: right 0.28s var(--ease);
}
.primary-nav a:hover { color: var(--text); }
.primary-nav a:hover::after { right: 0; }

/* --- Side quests: letters hop up in a staggered wave, "+1" toast pops --- */
.nav-quest .nq-letters { display: inline-flex; }
.nav-quest .nq-space { display: inline-block; min-width: 0.3em; }
.nav-quest .nq-letter {
  display: inline-block;
  transition: transform 0.32s var(--ease), color 0.32s var(--ease);
}
.nav-quest:hover .nq-letter,
.nav-quest:focus .nq-letter {
  transform: translateY(-4px);
  color: var(--accent);
}
.nav-quest .nq-toast {
  position: absolute;
  top: -14px;
  right: -8px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
  opacity: 0;
  transform: translateY(4px) scale(0.85);
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease);
  pointer-events: none;
}
.nav-quest:hover .nq-toast,
.nav-quest:focus .nq-toast {
  opacity: 1;
  transform: translateY(-2px) scale(1);
  transition-delay: 0.14s;
}

/* --- Archive: normal at rest. One flicker plays when the pointer/focus
   enters (settling into an old-film tint), one plays when it leaves
   (settling back to normal). Neither loops. JS (nav-hover-effects.js)
   toggles .nav-archive-in / .nav-archive-out once per enter/leave. --- */
.nav-archive:hover,
.nav-archive:focus {
  filter: sepia(0.55) contrast(1.1) brightness(1);
}
.nav-archive.nav-archive-in {
  animation: nav-archive-flicker-in 0.45s steps(1, end) 1;
}
.nav-archive.nav-archive-out {
  animation: nav-archive-flicker-out 0.35s steps(1, end) 1;
}
@keyframes nav-archive-flicker-in {
  0%   { opacity: 1; filter: none; transform: translateX(0); text-shadow: none; }
  15%  { opacity: 0.4;  filter: sepia(0.6) contrast(1.3) brightness(0.55); transform: translateX(-1px); }
  30%  { opacity: 1;    filter: sepia(0.3) contrast(1.15) brightness(1.2); transform: translateX(0); }
  45%  { opacity: 0.7;  filter: sepia(0.65) contrast(1.35) brightness(0.65); text-shadow: 1px 0 0 rgba(255, 120, 60, 0.25); transform: translateX(1px); }
  60%  { opacity: 1;    filter: sepia(0.45) contrast(1.1) brightness(1); transform: translateX(0); text-shadow: none; }
  80%  { opacity: 0.55; filter: sepia(0.55) contrast(1.2) brightness(0.7); }
  100% { opacity: 1;    filter: sepia(0.55) contrast(1.1) brightness(1); }
}
@keyframes nav-archive-flicker-out {
  0%   { opacity: 1; filter: sepia(0.55) contrast(1.1) brightness(1); transform: translateX(0); text-shadow: none; }
  25%  { opacity: 0.5; filter: sepia(0.4) contrast(1.25) brightness(0.6); transform: translateX(1px); }
  50%  { opacity: 1;   filter: sepia(0.2) contrast(1.1) brightness(1.15); transform: translateX(0); }
  70%  { opacity: 0.7; filter: sepia(0.1) contrast(1.05) brightness(0.85); text-shadow: -1px 0 0 rgba(255, 120, 60, 0.15); }
  100% { opacity: 1; filter: none; text-shadow: none; }
}

/* --- API: brackets slide open around the label, terminal cursor blinks --- */
.nav-api .napi-brace {
  display: inline-block;
  width: 0;
  overflow: hidden;
  color: var(--accent);
  opacity: 0;
  transform: scaleX(0.4);
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease), width 0.22s var(--ease);
}
.nav-api:hover .napi-brace,
.nav-api:focus .napi-brace {
  width: 0.6em;
  opacity: 1;
  transform: scaleX(1);
}
.nav-api .napi-cursor {
  display: inline-block;
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.15s var(--ease);
}
.nav-api:hover .napi-cursor,
.nav-api:focus .napi-cursor {
  opacity: 1;
  animation: nav-api-blink 1s step-end infinite;
}
@keyframes nav-api-blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* --- GitHub: a small icon slides/fades in beside the label --- */
.nav-github .ngh-icon {
  display: inline-flex;
  opacity: 0;
  transform: translate(-3px, 3px);
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease);
}
.nav-github:hover .ngh-icon,
.nav-github:focus .ngh-icon {
  opacity: 1;
  transform: translate(0, 0);
}

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  margin-left: auto;
}
.nav-toggle span {
  display: block;
  width: 20px;
  height: 1.5px;
  background: var(--text);
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.mobile-nav {
  position: fixed;
  inset: 0;
  top: 0;
  background: var(--bg);
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s var(--ease), visibility 0.3s;
}
.mobile-nav.open { opacity: 1; visibility: visible; }
.mobile-nav nav { display: flex; flex-direction: column; gap: 28px; text-align: center; }
.mobile-nav a { font-family: var(--font-display); font-size: 30px; font-weight: 600; }

/* -------------------------------------------------------
   Hero
------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 140px var(--edge) 80px;
  gap: 44px;
}

.hero-inner {
  position: relative;
  z-index: 1;
  max-width: var(--container);
  margin: 0 auto;
  width: 100%;
  text-align: center;
}

.hero-eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  margin-bottom: 26px;
}
.hero-eyebrow .dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--text-faint);
  display: inline-block;
}

.hero-title {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 400;
  font-size: clamp(36px, 6.8vw, 78px);
  max-width: 15ch;
  margin: 0 auto;
}
.hero-title .line { display: block; overflow: hidden; padding-bottom: 0.08em; }
.hero-title .word {
  display: inline-block;
  will-change: transform;
}

/* Flowing glow gradient across the headline: two muted gold tones (see
   --hero-flame-* tokens), slowly animated so it reads as flowing rather than
   static. Applied per-word (that's where the actual glyphs are, inside the
   per-line reveal spans) but with a viewport-fixed background so every word
   samples the same gradient field at its own position on screen — the title
   reads as one continuous sweep, not a separate gradient restarting inside
   each word. No text-shadow glow and no white stops — kept flat/matte and
   fully gold so it stays comfortable on dark-mode eyes. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .hero-title .word {
    background-image: linear-gradient(100deg,
      var(--hero-flame-dark) 0%,
      var(--hero-flame-red) 22%,
      var(--hero-flame-orange) 45%,
      var(--hero-flame-red) 68%,
      var(--hero-flame-dark) 100%);
    background-attachment: fixed;
    background-size: 200% 100%;
    background-position: 0% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: hero-title-flow 10s ease-in-out infinite;
  }
}
@keyframes hero-title-flow {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-title .word { animation: none; background-position: 35% 50%; }
}

.hero-sub {
  margin: 30px auto 0;
  max-width: 50ch;
  font-size: 16px;
  color: var(--text-dim);
  line-height: 1.75;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 34px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 22px;
  border-radius: 0;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px));
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  border: 1px solid transparent;
  transition: transform 0.25s var(--ease), background-color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn-primary {
  background: var(--accent);
  color: #120604;
}
.btn-primary:hover { background: #ff6250; }
.btn-ghost {
  border-color: var(--line);
  color: var(--text);
}
.btn-ghost:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.btn-large { padding: 16px 28px; font-size: 13.5px; }

/* Hero CTAs: cut-corner clip-path shared with the rest of the site's
   buttons. The primary CTA now uses the site's normal orange accent style
   (same as .btn-primary everywhere else) instead of a separate monochrome
   look. Ghost CTA stays quieter. Scoped to .hero so the rest of the site's
   buttons (Featured, Contact, etc., which reuse .btn / .hero-actions) are
   left exactly as they were. */
.hero .hero-actions .btn {
  border-radius: 0;
  transition: opacity 0.2s var(--ease), background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
}
.hero .hero-actions .btn:hover { transform: none; }
.hero .hero-actions .btn-ghost {
  border-color: var(--line);
  color: var(--text-dim);
}
.hero .hero-actions .btn-ghost:hover {
  background: transparent;
  border-color: var(--text-faint);
  color: var(--text);
}

/* Hero binary field artwork: one full-bleed layer behind the whole hero.
   No centerpiece mark anymore (the star has been removed) — the field
   itself, plus the centered title card sitting on top of it, is the visual. */
.hero-visual {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: auto;
  overflow: hidden;
  z-index: 0;
}
.hero-visual[hidden] { display: none; }

.hv-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Sci-fi HUD flourish on top of the binary field: four corner brackets in
   --hero-hud (the site's own brighter hover-orange, #ff6250) so the hero
   stays inside the site's original warm palette. No ambient glow behind the
   headline anymore — it was washing out the title and glaring on dark-mode
   eyes. Lives inside .hero-visual, which is already aria-hidden — purely
   decorative, nothing interactive or informational. */

.hud-corner {
  position: absolute;
  width: 26px;
  height: 26px;
  opacity: 0.5;
  filter: drop-shadow(0 0 9px rgba(var(--hero-hud-rgb), 0.7));
}
.hud-corner--tl { top: 22px; left: 22px; border-top: 1.5px solid var(--hero-hud); border-left: 1.5px solid var(--hero-hud); }
.hud-corner--tr { top: 22px; right: 22px; border-top: 1.5px solid var(--hero-hud); border-right: 1.5px solid var(--hero-hud); }
.hud-corner--bl { bottom: 22px; left: 22px; border-bottom: 1.5px solid var(--hero-hud); border-left: 1.5px solid var(--hero-hud); }
.hud-corner--br { bottom: 22px; right: 22px; border-bottom: 1.5px solid var(--hero-hud); border-right: 1.5px solid var(--hero-hud); }


/* Badge demo */
.hero-badge-demo {
  align-self: flex-start;
}
.demo-caption {
  font-size: 12px;
  color: var(--text-faint);
  margin-bottom: 12px;
}
.badge-demo { position: relative; display: inline-block; }

.badge-chip {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 10px 18px 10px 12px;
  background: var(--bg-elevated);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 13.5px;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.badge-chip:hover, .badge-chip[aria-expanded="true"] {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  transform: translateY(-1px);
}
.badge-glyph { font-size: 16px; line-height: 1; }
.badge-glyph.large { font-size: 26px; }

.badge-tooltip {
  position: absolute;
  left: 0;
  top: calc(100% + 10px);
  background: var(--bg-elevated-2);
  border: 1px solid var(--line);
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 12px;
  color: var(--text-dim);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
}
.badge-demo:hover .badge-tooltip,
.badge-chip:focus-visible ~ .badge-tooltip {
  opacity: 1;
  transform: translateY(0);
}
.badge-popup[hidden] ~ .badge-tooltip { }
.badge-demo:has(.badge-popup:not([hidden])) .badge-tooltip { opacity: 0; }

.badge-popup {
  position: absolute;
  left: 0;
  top: calc(100% + 10px);
  width: min(320px, 82vw);
  background: var(--bg-elevated-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 18px;
  z-index: 5;
  box-shadow: 0 24px 48px rgba(0,0,0,0.45);
}
.badge-popup-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.badge-popup-name { font-family: var(--font-display); font-weight: 600; font-size: 15px; }
.badge-popup-desc { color: var(--text-dim); font-size: 13px; margin-top: 4px; }
.badge-popup-close {
  margin-left: auto;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--text-faint);
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.badge-popup-close:hover { background: var(--line-soft); color: var(--text); }
.badge-popup-close svg { width: 14px; height: 14px; }
.badge-popup-foot {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 11.5px;
  color: var(--text-faint);
  line-height: 1.6;
}

.scroll-cue {
  position: absolute;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  color: var(--text-faint);
  animation: float 2.4s ease-in-out infinite;
}
.scroll-cue svg { width: 18px; height: 18px; }
@keyframes float {
  0%, 100% { transform: translate(-50%, 0); }
  50% { transform: translate(-50%, 6px); }
}
@media (prefers-reduced-motion: reduce) { .scroll-cue { animation: none; } }

/* -------------------------------------------------------
   Shared section rhythm
------------------------------------------------------- */
section { padding: 100px 0; position: relative; z-index: 2; }
.eyebrow {
  font-size: 12.5px;
  color: var(--accent);
  margin-bottom: 14px;
  font-weight: 500;
}
section h2 { font-size: clamp(26px, 3.6vw, 38px); max-width: 22ch; }

/* -------------------------------------------------------
   Intro
------------------------------------------------------- */
.intro { border-top: 1px solid var(--line); }
.intro-grid {
  display: grid;
  grid-template-columns: 1fr 1.6fr;
  gap: 60px;
}
.intro-body p { color: var(--text-dim); max-width: 58ch; line-height: 1.8; }

.fact-list {
  display: flex;
  gap: 36px;
  margin-top: 34px;
  flex-wrap: wrap;
}
.fact-list li { display: flex; flex-direction: column; gap: 4px; }
.fact-num, .fact-num-static {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 600;
  color: var(--text);
  display: inline-block;
  letter-spacing: 0;
  transition: letter-spacing 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              color 0.4s ease;
}
.fact-list li:hover .fact-num,
.fact-list li:hover .fact-num-static {
  letter-spacing: 0.06em;
  transform: translateY(-3px);
  color: var(--accent);
}
.license-roll { display: inline-flex; align-items: baseline; gap: 0.25em; }
.roll-mask { display: inline-block; overflow: hidden; line-height: 1; }
.roll-word { display: inline-block; will-change: transform; }
.fact-label {
  font-size: 12px;
  color: var(--text-faint);
  transition: letter-spacing 0.4s cubic-bezier(0.16, 1, 0.3, 1), color 0.3s ease;
}
.fact-list li:hover .fact-label {
  letter-spacing: 0.03em;
  color: var(--text-dim);
}

/* -------------------------------------------------------
   Featured project
------------------------------------------------------- */
.featured { border-top: 1px solid var(--line); background: var(--bg-elevated); }
.featured-title { font-size: clamp(34px, 5.6vw, 58px); margin-bottom: 46px; }

.featured-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: 56px;
  align-items: start;
}
.featured-copy > p {
  color: var(--text-dim);
  line-height: 1.85;
  max-width: 62ch;
  font-size: 15.5px;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  margin: 30px 0 28px;
}
.feature-grid li {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 10px;
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.55;
  background: var(--bg);
}

.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 26px; }
.chip {
  font-size: 11.5px;
  padding: 6px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--text-dim);
}
.chip-accent { border-color: var(--accent-line); color: var(--accent); background: var(--accent-soft); }

.featured-side { display: flex; flex-direction: column; gap: 14px; }
.side-card {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 18px;
  background: var(--bg);
}
.side-card-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  margin-bottom: 8px;
}
.side-card-value { font-size: 13.5px; color: var(--text); line-height: 1.6; }

/* -------------------------------------------------------
   Side quests
------------------------------------------------------- */
.side-quests { border-top: 1px solid var(--line); }
.side-quests h2, .experiments h2, .archive h2 { margin-top: 4px; }

.quest-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  margin-top: 44px;
}
.quest-card {
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 26px;
  transition: border-color 0.3s var(--ease), transform 0.3s var(--ease), background-color 0.3s var(--ease);
}
.quest-card:hover {
  border-color: var(--accent-line);
  background: var(--bg-elevated);
  transform: translateY(-3px);
}
.quest-card h3 {
  font-size: 19px;
  margin-bottom: 12px;
}
.quest-card p {
  color: var(--text-dim);
  font-size: 13.5px;
  line-height: 1.7;
  margin-bottom: 18px;
}
.quest-links { display: flex; gap: 18px; margin-top: 18px; }
.quest-links a, .gist-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text);
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}
.quest-links a:hover, .gist-link:hover { border-color: var(--accent); color: var(--accent); }

/* -------------------------------------------------------
   Experiments (gists)
------------------------------------------------------- */
.experiments { border-top: 1px solid var(--line); background: var(--bg-elevated); }
.gist-list { margin-top: 44px; display: flex; flex-direction: column; }
.gist-item {
  padding: 24px 0;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: 220px 1fr auto;
  gap: 20px;
  align-items: start;
}
.gist-item:last-child { border-bottom: 1px solid var(--line); }
.gist-file { display: flex; align-items: center; gap: 10px; }
.gist-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
.gist-name { font-size: 14px; color: var(--text); }
.gist-desc { color: var(--text-dim); font-size: 13.5px; line-height: 1.7; }

/* -------------------------------------------------------
   Archive
------------------------------------------------------- */
.archive { padding-top: 140px; border-top: 0; }
.archive-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  border: 1px dashed var(--line);
  border-radius: 14px;
  padding: 26px;
  opacity: 0.82;
}
.archive-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.archive-head h3 { font-size: 18px; }
.archived-tag {
  font-size: 10.5px;
  letter-spacing: 0.04em;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid var(--text-faint);
  color: var(--text-faint);
}
.archive-card .gist-link { margin-top: auto; }
.archive-card p { color: var(--text-dim); font-size: 13.5px; line-height: 1.7; margin-bottom: 16px; }

/* -------------------------------------------------------
   Github stats
------------------------------------------------------- */
.github-section { border-top: 1px solid var(--line); background: var(--bg-elevated); }
.github-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 50px;
  align-items: center;
}
.github-copy {
  color: var(--text-dim);
  margin: 18px 0 30px;
  max-width: 46ch;
  line-height: 1.8;
  font-size: 14.5px;
}
.github-stats {
  display: flex;
  gap: 30px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.stat { display: flex; flex-direction: column; gap: 6px; }
.stat .fact-num, .stat .fact-num-static { font-size: 40px; }
.stat:hover .fact-num,
.stat:hover .fact-num-static {
  letter-spacing: 0.06em;
  transform: translateY(-3px);
  color: var(--accent);
}
.stat:hover .fact-label {
  letter-spacing: 0.03em;
  color: var(--text-dim);
}

/* -------------------------------------------------------
   Contact
------------------------------------------------------- */
.contact { border-top: 1px solid var(--line); text-align: center; }
.contact-inner { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.contact h2 { max-width: 16ch; }
.contact > .section-inner > p { color: var(--text-dim); max-width: 40ch; }
.community-note { margin-top: 10px; font-size: 13px; color: var(--text-faint); }
.community-note a { color: var(--text-dim); border-bottom: 1px solid var(--line); transition: color 0.2s var(--ease), border-color 0.2s var(--ease); }
.community-note a:hover { color: var(--accent); border-color: var(--accent); }
.community-note .ext-icon { display: inline-block; width: 12px; height: 12px; margin-left: 4px; vertical-align: -1px; }

/* -------------------------------------------------------
   Footer
------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--line); padding: 30px 0 40px; }
.footer-main {
  display: flex;
  flex-wrap: wrap;
  gap: 48px;
  padding: 8px var(--edge) 44px;
}
.footer-brand {
  flex: 1 1 320px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.dot-text { width: 100%; margin: 20px 0 24px; line-height: 0; }
.dot-text canvas { display: block; width: 100%; }
.footer-socials { display: flex; align-items: center; gap: 16px; }
.footer-socials a {
  color: var(--text-dim);
  display: inline-flex;
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}
.footer-socials a:hover,
.footer-socials a:focus-visible { color: var(--brand, var(--accent)); transform: scale(1.14); }
.footer-social-icon { width: 19px; height: 19px; overflow: visible; }
.footer-links { flex: 0 0 160px; margin-top: 44px; }
.footer-links-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
  margin: 0 0 16px;
}
.footer-links ul { display: flex; flex-direction: column; gap: 10px; }
.footer-links a { color: var(--text-dim); font-family: var(--font-mono); font-size: 13px; transition: color 0.2s var(--ease); }
.footer-links a:hover { color: var(--accent); }
.footer-links a:has(.ext-icon) { display: inline-flex; align-items: center; gap: 6px; }
.footer-links .ext-icon { width: 12px; height: 12px; }
.footer-credit-link { color: var(--text-faint); font-size: 11.5px; }
.footer-credit-link:hover { color: var(--accent); }
.footer-sep { border: none; border-top: 1px solid var(--line); margin: 0 0 24px; }
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 12.5px;
  color: var(--text-faint);
}
.back-to-top {
  color: var(--text-faint);
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.back-to-top:hover { color: var(--accent); border-color: var(--accent); }

/* -------------------------------------------------------
   Reveal states (only hidden when JS and Anime.js are active)
------------------------------------------------------- */
.js .reveal-up, .js .reveal-line, .js .scroll-cue { opacity: 0; }
.js .hero-title .word { transform: translateY(110%); }

/* -------------------------------------------------------
   Responsive
------------------------------------------------------- */
@media (max-width: 860px) {
  .primary-nav { display: none; }
  .nav-toggle { display: flex; }

  .intro-grid,
  .featured-grid,
  .github-grid { grid-template-columns: 1fr; }

  .github-stats { justify-content: flex-start; }

  .quest-grid { grid-template-columns: 1fr; }
  .feature-grid { grid-template-columns: 1fr; }

  .gist-item {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  section { padding: 72px 0; }
  .hero { padding-top: 120px; gap: 56px; }
}

@media (max-width: 520px) {
  .hero-title { font-size: clamp(32px, 11vw, 48px); }
  .hero-actions .btn { flex: 1 1 auto; justify-content: center; }
  .badge-popup { width: 84vw; }
  .footer-inner { flex-direction: column; gap: 12px; text-align: center; }
  .footer-main { flex-direction: column; gap: 32px; }
  .footer-brand { flex: 0 0 auto; align-items: center; text-align: center; max-width: none; }
  .footer-links { text-align: center; margin-top: 0; flex-basis: auto; }
}

/* -------------------------------------------------------
   Refinements
------------------------------------------------------- */
section { scroll-margin-top: 64px; }
body.nav-open { overflow: hidden; }

/* Featured project: lighter rows instead of stacked cards */
.feature-grid { gap: 0 32px; }
.feature-grid li { border: 0; border-top: 1px solid var(--line); border-radius: 0; background: none; padding: 12px 0; }
.featured-side { gap: 0; }
.side-card { border: 0; border-top: 1px solid var(--line); border-radius: 0; background: none; padding: 16px 0; }
.side-card-label { text-transform: none; letter-spacing: 0; font-size: 12px; }

/* Badge demo */
.demo-stage { margin-bottom: 28px; }
.demo-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.badge-chip { background: var(--bg); }
.btn-small { padding: 9px 14px; font-size: 12.5px; }.primary-nav a[aria-current] { color: var(--accent); }

/* Chip links: behave like buttons */
.chip-link {
  display: inline-block;
  cursor: pointer;
  transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), color 0.25s var(--ease), background-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.chip-link:hover, .chip-link:focus-visible {
  transform: translateY(-2px) scale(1.06);
  border-color: var(--accent-line);
  color: var(--accent);
  background: var(--accent-soft);
  box-shadow: 0 6px 16px rgba(239, 75, 58, 0.18);
}
.chip-link:active { transform: translateY(0) scale(0.97); box-shadow: none; }

/* License roll: spread on hover without changing layout width (stops the jitter).
   --roll-chars = characters that receive letter-spacing (TS / JS = 5, GPL / MIT = 7). */
.license-roll {
  --roll-chars: 5;
  transition: letter-spacing 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              margin-right 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
              color 0.4s ease;
}
.stat .license-roll { --roll-chars: 7; }
.fact-list li:hover .license-roll,
.stat:hover .license-roll {
  margin-right: calc(var(--roll-chars) * -0.06em);
}


/* Badge demo: editor style quick popup (hover) and detail card (click) */
/* Registered colors so the theme can glide from one badge to the next instead of snapping */
@property --bd-main { syntax: "<color>"; inherits: true; initial-value: #1d1d1d; }
@property --bd-second { syntax: "<color>"; inherits: true; initial-value: #1d1d1d; }
@property --bd-name { syntax: "<color>"; inherits: true; initial-value: #ffffff; }

.badge-demo, .demo-row {
  --bd-bg: linear-gradient(135deg, var(--bd-main), var(--bd-second));
  --bd-card-bg: linear-gradient(160deg, var(--bd-main), var(--bd-second));
  /* pointer colors sample the gradient where each one sits (card ~82% along, tooltip ~61%) */
  --bd-tail: color-mix(in srgb, var(--bd-second) 82%, var(--bd-main));
  --bd-mid: color-mix(in srgb, var(--bd-second) 61%, var(--bd-main));
  --bd-soft: color-mix(in srgb, var(--bd-name) 62%, transparent);
  transition: --bd-main 0.7s cubic-bezier(0.22, 1, 0.36, 1), --bd-second 0.7s cubic-bezier(0.22, 1, 0.36, 1), --bd-name 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.badge-demo {
  --tail-x: 115px;
  --card-x: 0px;
  --tip-shift: 0px;
  --tip-tx: calc(-50% + var(--tip-shift));
}

/* Quick popup: icon + name, centered above the badge, pointer at bottom middle */
.badge-demo .badge-tooltip {
  display: flex;
  align-items: center;
  gap: 9px;
  left: 50%;
  top: auto;
  bottom: calc(100% + 11px);
  padding: 7px 16px 7px 11px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 11px;
  background: var(--bd-bg);
  color: var(--bd-name);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.4);
  opacity: 0;
  transform: translateX(var(--tip-tx));
  z-index: 4;
}
.badge-demo .badge-tooltip::after {
  content: "";
  position: absolute;
  bottom: -6px;
  left: calc(50% - var(--tip-shift) - 6px);
  width: 12px;
  height: 7px;
  background: var(--bd-mid);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}
.badge-demo .badge-tooltip .badge-glyph { font-size: 20px; }
.badge-demo:hover .badge-tooltip,
.badge-chip:focus-visible ~ .badge-tooltip { opacity: 0; transform: translateX(var(--tip-tx)); }
.badge-demo .badge-tooltip[data-anim="scale"] { transform: translateX(var(--tip-tx)) scale(0.85); }
.badge-demo .badge-tooltip[data-anim="slide"] { transform: translateX(var(--tip-tx)) translateY(8px); }
.badge-demo .badge-tooltip.show { opacity: 1; transform: translateX(var(--tip-tx)); }

/* Detail card: centered over the badge, tail pointing at it (script keeps it on screen) */
.badge-demo .badge-popup {
  top: auto;
  bottom: calc(100% + 14px);
  left: 0;
  margin-left: var(--card-x);
  width: min(230px, 80vw);
  padding: 18px 16px 16px;
  background: var(--bd-card-bg);
  border: 0;
  border-radius: 14px;
  color: var(--bd-name);
  text-align: center;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
}
.badge-demo .badge-popup-head { flex-direction: column; align-items: center; gap: 6px; }
.badge-demo .badge-popup .badge-glyph.large { font-size: 34px; }
.badge-demo .badge-popup-name { color: var(--bd-name); font-size: 18px; font-weight: 700; }
.badge-demo .badge-popup-desc { color: var(--bd-soft); font-family: var(--font-display); font-size: 13px; margin-top: 4px; }
.badge-demo .badge-popup-close,
.badge-demo .badge-popup-foot { display: none; }
.bd-tail {
  position: absolute;
  bottom: -7px;
  left: calc(var(--tail-x) - 7px);
  width: 14px;
  height: 8px;
  background: var(--bd-tail);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

/* Badge button (and rotate button) follow the current badge's colors */
.badge-demo .badge-chip {
  background: var(--bd-bg);
  color: var(--bd-name);
  border-color: color-mix(in srgb, var(--bd-name) 22%, transparent);
}
.badge-demo .badge-chip:hover,
.badge-demo .badge-chip[aria-expanded="true"] {
  background: var(--bd-bg);
  border-color: color-mix(in srgb, var(--bd-name) 50%, transparent);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--bd-tail) 60%, transparent);
}
#badge-rotate { border-color: color-mix(in srgb, var(--bd-tail) 75%, transparent); }
#badge-rotate:hover,
#badge-rotate:focus-visible {
  background: var(--bd-bg);
  color: var(--bd-name);
  border-color: color-mix(in srgb, var(--bd-name) 45%, transparent);
}


/* Nav bar: more translucent once the page scrolls */
.site-header.scrolled {
  background: rgba(11, 13, 16, 0.5);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
}


/* Landing hero: full-bleed binary field behind a centered title card */
.hero {
  justify-content: center;
  padding-top: clamp(100px, 14vh, 136px);
  padding-bottom: 56px;
  gap: 40px;
}
.hero-eyebrow { margin-bottom: 24px; }
.hero-sub { margin-top: 26px; }
.hero-actions { margin-top: 32px; }


/* Badge icons are images now */
.badge-glyph { display: inline-flex; align-items: center; justify-content: center; }
.badge-glyph img { width: 1em; height: 1em; object-fit: contain; display: block; user-select: none; -webkit-user-drag: none; }
.badge-chip .badge-glyph { font-size: 20px; }

/* Keep the tooltip on one line and stop the icon from shrinking to nothing inside it */
.badge-demo .badge-tooltip { width: max-content; white-space: nowrap; }
.badge-glyph { flex: none; }


/* Rotate: ring pulse on the badge button, and no wrapping while its width morphs */
@keyframes bd-ring {
  from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--bd-tail) 80%, transparent); }
  to { box-shadow: 0 0 0 18px transparent; }
}
.badge-chip.bd-pulse { animation: bd-ring 0.8s ease-out; }
.badge-chip.morphing { white-space: nowrap; overflow: hidden; }


/* Links whose href is set aside while hovered (see script.js) still look clickable */
a[data-held] { cursor: pointer; }
/* -------------------------------------------------------
   Custom cursor (cursor.js)
------------------------------------------------------- */
html.cc-active,
html.cc-active * {
  cursor: none !important;
}

.cc-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 110px;
  height: 36px;
  pointer-events: none;
  z-index: 2147483647;
  opacity: 0;
  transition: opacity 0.18s ease;
  will-change: transform;
  overflow: visible;
  mix-blend-mode: difference;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.cc-cursor.cc-visible { opacity: 1; }
.cc-cursor.cc-native-hide { opacity: 0 !important; }

/* Elements that want their own cursor (e.g. the status graph's PNG cursor)
   instead of the custom shape above */
html.cc-active [data-native-cursor] { cursor: auto !important; }
/* -------------------------------------------------------
   Scrollbar
------------------------------------------------------- */
body {
  --sb-track-color: #2b1411;
  --sb-thumb-color: #ef4b3a;
  --sb-size: 4px;
}

body::-webkit-scrollbar {
  width: var(--sb-size)
}

body::-webkit-scrollbar-track {
  background: var(--sb-track-color);
  border-radius: 38px;
}

body::-webkit-scrollbar-thumb {
  background: var(--sb-thumb-color);
  border-radius: 38px;
}

@supports not selector(::-webkit-scrollbar) {
  body {
    scrollbar-width: thin;
    scrollbar-color: var(--sb-thumb-color)
                     var(--sb-track-color);
  }
}

/* Hero headline: two-line set, editorial serif tracking, no orphan wraps */
.hero-title {
  max-width: 19ch;
  line-height: 1.06;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.hero-title .line { padding-bottom: 0.12em; }

@media (max-width: 520px) {
  .hero-title { font-size: clamp(30px, 10vw, 42px); }
}

/* -------------------------------------------------------
   Preloader
   First-visit-only loading screen (see js/preloader.js):
   black full-bleed overlay, a segmented equalizer-style
   progress bar pinned edge-to-edge along the very top (with
   a live percentage readout at its right end) — squared off,
   not rounded, and darkening from the back as it fills, so
   only a bright comet head sits at the leading edge — and the
   wordmark fading in left-to-right — a soft-edged reveal
   front (mask-image gradient), not a hard clip cut — in the
   middle of the screen. On finish the wordmark pulses once,
   then the same front recedes right-to-left, fading it back
   out, before the whole overlay lifts and fades. Runs for roughly 4s
   (see MIN_VISIBLE_MS in
   preloader.js). Shown once per browser session (sessionStorage)
   — the .preloader-skip class on <html>, set by an inline head
   script before first paint, keeps repeat page loads in the
   same session flash-free.
------------------------------------------------------- */
.preloader-skip #preloader { display: none !important; }

/* Set on <html> by preloader.js only while the loading screen is on
   screen (removed the moment it starts fading out); hides the page's own
   scrollbar/scrolling so nothing shows through or scrolls behind the
   full-bleed overlay during the first-visit splash. */
html.preloader-lock,
html.preloader-lock body {
  overflow: hidden;
  height: 100%;
}

#preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease), visibility 0.6s var(--ease);
}
#preloader.is-hidden {
  opacity: 0;
  transform: translateY(-48px);
  visibility: hidden;
  pointer-events: none;
}

/* Loadbar: pinned full-width along the top edge of the screen, track + fill
   sharing the same segmented look, produced by a single
   repeating-linear-gradient overlay (stripes matching the page background)
   drawn on top of both — cheaper than generating dozens of real DOM bars.
   Its job ends the moment it hits 100% (preloader.js adds .is-done right
   then) — it lifts and fades on its own right away, independent of the
   "click anywhere to enter" gate below it, instead of sitting there idle
   for however long the visitor takes to click. */
.preloader-loadbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.preloader-loadbar.is-done {
  opacity: 0;
  transform: translateY(-22px);
  pointer-events: none;
}
#preloader-bar-track {
  position: relative;
  flex: 1;
  height: clamp(18px, 2.6vw, 24px);
  background: #0a140d;
  overflow: hidden;
}
#preloader-bar-fill {
  height: 100%;
  width: 0%;
  /* Stops are relative to the fill element's own box, so as it grows the
     already-covered ground keeps getting reinterpreted as further "back" —
     it darkens back down toward black, leaving only a bright head right at
     the leading edge (a comet trailing into darkness, not a solid bar that
     stays lit once painted). */
  background: linear-gradient(90deg,
    #04120a 0%,
    #04120a 62%,
    #1c6b3f 84%,
    #4dffa8 95%,
    #eafff2 100%);
  transition: width 0.2s linear;
}
/* During the final glide to 100% (preloader.js drives width every animation
   frame via requestAnimationFrame), the CSS transition is switched off so it
   doesn't lag behind or fight the JS-driven easing. */
#preloader-bar-fill.is-finishing {
  transition: none;
}
#preloader-bar-track::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(90deg,
    var(--bg) 0 2px,
    transparent 2px 9px);
  pointer-events: none;
}
#preloader-bar-percent {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--text);
  min-width: 3ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* The gradient below is fixed; only mask-position moves, and mask-position
   is a plain built-in property (like background-position) that every
   engine interpolates natively — nothing here depends on animating a
   custom property inside a gradient's calc(), which is what caused the
   snap-to-end jump in an earlier version of this effect.
   The mask image is drawn 2.5x the word's own width (mask-size), with
   solid on its left half, a soft ramp, then transparent on its right
   half. Sliding that oversized image across the word via mask-position
   sweeps the ramp across the visible box as a soft fade front — at
   mask-position 100% the box only sees the image's fully-transparent
   tail (word hidden); at 0% it only sees the fully-solid head (word
   shown). */
.preloader-word {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 45%, transparent 55%, transparent 100%);
  mask-image: linear-gradient(90deg, #000 0%, #000 45%, transparent 55%, transparent 100%);
  -webkit-mask-size: 250% 100%;
  mask-size: 250% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: 100% 0;
  mask-position: 100% 0;
  transition: -webkit-mask-position 0.9s var(--ease), mask-position 0.9s var(--ease), opacity 0.4s var(--ease);
}
#preloader.is-revealed .preloader-word {
  -webkit-mask-position: 0% 0;
  mask-position: 0% 0;
}
/* Finish sequence, driven by preloader.js once loading completes: once
   loading is done, mask-position is driven back to its starting value
   (100%). This reuses the exact same transition as the entrance (same
   duration/easing, on the base .preloader-word rule below) just run in
   reverse, so the exit is a literal mirror of the enter — sliding the
   same oversized mask back the other way pulls the transparent tail
   back across the word from the right edge inward, fading it out
   right-to-left, the exact reverse of the left-to-right fade-in. */
#preloader.is-revealed .preloader-word.is-leaving {
  -webkit-mask-position: 100% 0;
  mask-position: 100% 0;
}
/* --word-h drives the wordmark's size; --icon-h is deliberately smaller
   (a fraction of --word-h, not equal to it) since the gear reads as a
   small mark next to the "SHADOW" wordmark, not a same-size lockup.
   Shadow-Preloader.png is ~3.1:1 (2206×713), so width follows height
   automatically via width:auto below — no need to hand-tune both. */
.preloader-word {
  --word-h: clamp(90px, 15vw, 190px);
  --icon-h: calc(var(--word-h) * 0.42);
  gap: 6px; /* was 14px — pulls the gear in tight against the S */
}
.preloader-logo {
  display: block;
  height: var(--word-h);
  width: auto;
}
/* The favicon icon, placed as the first child of .preloader-word, before
   the wordmark. It rides the parent's mask-position sweep for free (it's
   inside the same masked box, so it fades in left-to-right and out
   right-to-left along with the wordmark, with no separate logic needed).
   Its spin is a plain looping @keyframes animation, not tied to the
   is-revealed / is-leaving timing at all — it just spins continuously,
   the whole time the icon exists in the DOM, and the mask fade is the
   only thing that ever makes it appear/disappear. (A transform
   transition bounded to those state changes is what caused the earlier
   version to visibly stop mid-way instead of spinning throughout.) */
@keyframes preloader-icon-spin {
  to { transform: rotate(360deg); }
}
.preloader-icon {
  display: block;
  height: var(--icon-h);
  width: auto;
  flex: none;
  animation: preloader-icon-spin 1.4s linear infinite;
}

/* "Click anywhere to enter" — shown once the bar hits 100% (see
   waitForEnterClick in preloader.js). Hidden/inert by default; the
   .is-shown class is what makes it visible AND clickable-feeling
   (pointer-events stays off until then so it can't be tapped a frame
   early). Fades in then blinks gently in one continuous keyframe
   animation rather than a transition, so there's no fade-in/blink
   handoff for the browser to snap between on the same property. */
.preloader-enter {
  margin: 20px 0 0;
  font: 600 12px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sb-thumb-color, #ef4b3a);
  opacity: 0;
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}
.preloader-enter.is-shown {
  opacity: 1;
  pointer-events: auto;
  /* Delay matches the transition above: during the delay the animation
     hasn't taken hold yet (no fill-mode: backwards), so the opacity
     0 -> 1 transition plays out normally first. Only once the delay
     ends does the animation take over, starting from the same opacity:1
     the transition just landed on — a seamless handoff into a loop
     whose own start/end values match (1 -> 0.35 -> 1), so the wrap
     point has nothing to jump across, unlike the old version. */
  animation: preloader-enter-cue 1.8s ease-in-out 0.4s infinite;
}
@keyframes preloader-enter-cue {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .preloader-word { transition: none; -webkit-mask-position: 0% 0; mask-position: 0% 0; }
  .preloader-word.is-leaving { opacity: 0; transition: opacity 0.2s linear; }
  .preloader-icon { animation: none; }
  .preloader-enter.is-shown { animation: none; opacity: 1; }
  #preloader { transition: opacity 0.2s linear; }
  #preloader.is-hidden { transform: none; }
  .preloader-loadbar { transition: opacity 0.2s linear; }
  .preloader-loadbar.is-done { transform: none; }
}