/* cache-bust: styles.64ed0214.css was poisoned at the Cloudflare edge — a 404
   returned during a deploy got stamped immutable/1yr by the worker, so that URL
   answers 404 for a year no matter what is deployed. Changing this file changes
   the hash, which is a fresh URL with no cached failure. The worker no longer
   caches non-2xx as immutable, so this cannot recur. */
/* used the RL ufonts,
   warm  page accent, and the DelMar loading wheel in the main view */

/* the real Rocket Racing typeface (Psyonix RL Fonts) */
@font-face { font-family:"RL Display"; src:url(fonts/RLLarge-D800.woff2) format("woff2"); font-weight:800; font-style:normal; font-display:swap; }
@font-face { font-family:"RL Display"; src:url(fonts/RLLarge-E900.woff2) format("woff2"); font-weight:900; font-style:normal; font-display:swap; }
@font-face { font-family:"RL Text"; src:url(fonts/RLSmall-Regular.woff2) format("woff2"); font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:"RL Text"; src:url(fonts/RLSmall-Medium.woff2) format("woff2"); font-weight:500; font-style:normal; font-display:swap; }
@font-face { font-family:"RL Text"; src:url(fonts/RLSmall-Semibold.woff2) format("woff2"); font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:"RL Text"; src:url(fonts/RLSmall-Bold.woff2) format("woff2"); font-weight:700; font-style:normal; font-display:swap; }

:root {
  --bg:      #06080b;
  --bg-2:    #0a0d12;
  --panel:   rgba(255,255,255,0.022);
  --ink:     #eef1f3;
  --dim:     #9aa4ad;
  --faint:   #69737d;
  --line:    rgba(255,255,255,0.085);
  --line-2:  rgba(255,255,255,0.14);
  --accent:  #ff6a2b;
  --disp: "RL Display", "Arial Narrow", system-ui, sans-serif;
  --text: "RL Text", ui-sans-serif, system-ui, sans-serif;
  --chrome-h: 60px;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  /* small racing car on users cursor; the clickable thing at the car's centre so
     clicks register where the icon visually sits hopefully,(cuz nose tip felt inaccurate for some reason) */
  --cur-car: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNiIgaGVpZ2h0PSIzMCIgdmlld0JveD0iMCAwIDI2IDMwIj48ZyBzdHJva2U9IiMwYTBiMGUiIHN0cm9rZS13aWR0aD0iMS4yIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cmVjdCB4PSIyLjQiIHk9IjcuNSIgd2lkdGg9IjQuMiIgaGVpZ2h0PSI2LjQiIHJ4PSIxLjgiIGZpbGw9IiMwYTBiMGUiLz48cmVjdCB4PSIxOS40IiB5PSI3LjUiIHdpZHRoPSI0LjIiIGhlaWdodD0iNi40IiByeD0iMS44IiBmaWxsPSIjMGEwYjBlIi8+PHJlY3QgeD0iMi40IiB5PSIxNy42IiB3aWR0aD0iNC4yIiBoZWlnaHQ9IjYuNCIgcng9IjEuOCIgZmlsbD0iIzBhMGIwZSIvPjxyZWN0IHg9IjE5LjQiIHk9IjE3LjYiIHdpZHRoPSI0LjIiIGhlaWdodD0iNi40IiByeD0iMS44IiBmaWxsPSIjMGEwYjBlIi8+PHBhdGggZD0iTTEzIDEuNCBDMTQuNSAyLjggMTUuNiA1LjYgMTUuNiA5LjMgTDE1LjYgMjMuNCBDMTUuNiAyNi43IDE0LjQgMjguMyAxMyAyOC4zIEMxMS42IDI4LjMgMTAuNCAyNi43IDEwLjQgMjMuNCBMMTAuNCA5LjMgQzEwLjQgNS42IDExLjUgMi44IDEzIDEuNCBaIiBmaWxsPSIjZmY2YTJiIi8+PHJlY3QgeD0iNy44IiB5PSI4LjQiIHdpZHRoPSIxMC40IiBoZWlnaHQ9IjIuNCIgcng9IjEuMiIgZmlsbD0iIzBhMGIwZSIgc3Ryb2tlPSJub25lIi8+PGVsbGlwc2UgY3g9IjEzIiBjeT0iMTYuMiIgcng9IjEuOSIgcnk9IjIuNyIgZmlsbD0iIzBhMGIwZSIgc3Ryb2tlPSJub25lIi8+PC9nPjwvc3ZnPgo=") 13 15;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--chrome-h) + 24px); -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: var(--text); font-size: 16.5px; line-height: 1.75; font-weight: 400;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow-x: hidden;
}
body.modal-open { overflow: hidden; }
::selection { background: rgba(255,106,43,0.26); }
/* racing car cursor site everywhere; clickable things keep it (pointer fallback),
   text fields keep a caret so typing feels normal. IsIgnored on touch devices */
body { cursor: var(--cur-car), auto; }
a, button, [role="button"], summary, .btn, .sc, .comp-card, .feature-media, .pg, .support-btn { cursor: var(--cur-car), pointer; }
input, textarea, select, [contenteditable="true"] { cursor: text; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

/* site everywhere liquid glass ambient bg (basically behind everything) */
#liquid-bg { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -2; opacity: 0; transition: opacity 2.4s ease; }
body.revealed #liquid-bg { opacity: 1; }
#liquid-fallback { position: fixed; inset: 0; z-index: -3; background: url(media/liquid.webp) center / cover; filter: brightness(0.26) saturate(0.82) contrast(1.05); animation: liquidpan 100s ease-in-out infinite alternate; }
@keyframes liquidpan { from { transform: scale(1.06) translate(0, 0); } to { transform: scale(1.16) translate(-2.4%, -1.8%); } }

/* progress */
#progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 90;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
}

/* chrome top */
.chrome {
  position: fixed; top: 0; left: 0; right: 0; height: var(--chrome-h); z-index: 80;
  display: flex; align-items: center; justify-content: space-between; padding: 0 28px;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(12px); border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 11px; }
.brand-mark { color: var(--accent); display: inline-flex; }
.brand-name { font-family: var(--disp); font-weight: 800; font-size: 15px; letter-spacing: 0.005em; }
.brand-name em { color: var(--dim); font-style: normal; font-weight: 400; }
.chrome-right { display: flex; align-items: center; gap: 18px; }
.chrome-here { font-size: 12.5px; color: var(--dim); max-width: 42vw; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; background: none; border: 0; font-family: var(--text); padding: 8px 0; cursor: pointer; transition: color .2s; }
.chrome-here:hover { color: var(--accent); }

/* skip-to-content (via keyboard only) */
.skip-link { position: fixed; top: -52px; left: 16px; z-index: 200; background: var(--accent); color: #0a0b0e; font-weight: 600; font-size: 13px; padding: 9px 16px; border-radius: 8px; transition: top .2s; }
.skip-link:focus { top: 12px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.chrome-btn { display: inline-flex; align-items: center; gap: 8px; background: none; border: 0; color: var(--ink); font-family: var(--text); font-weight: 500; font-size: 13px; padding: 8px 2px; transition: color .2s; }
.chrome-btn:hover { color: var(--accent); }
/* header search,not just an icon but looks tapable */
#search-btn { padding: 7px 12px; border: 1px solid var(--line-2); border-radius: 999px; color: var(--dim); position: relative; z-index: 1; }
#search-btn:hover { border-color: var(--accent); color: var(--accent); }
/* this gold glow mythic around the search button so users can find it: base radial + particle canvas
   particles fade with distance so the canvas edge never shows as a square, so it comes basically from the button self */
.sbtn-wrap { position: relative; display: inline-flex; }
.sbtn-wrap::before { content: ""; position: absolute; left: 50%; top: 55%; width: 150px; height: 150px; transform: translate(-50%, -50%); border-radius: 50%; pointer-events: none; z-index: 0;
  background: radial-gradient(closest-side, rgba(255,176,74,0.22), rgba(255,150,40,0.08) 45%, transparent 72%); }
.sbtn-glow { position: absolute; left: 50%; top: 55%; width: 180px; height: 150px; transform: translate(-50%, -50%); pointer-events: none; z-index: 0; }
.chrome-btn kbd, .search-hint kbd { font-family: var(--text); font-size: 10px; padding: 3px 6px; border: 1px solid var(--line-2); border-radius: 4px; color: var(--dim); }
.chrome-index::before { content: ""; width: 15px; height: 1px; background: currentColor; box-shadow: 0 5px 0 currentColor, 0 -5px 0 currentColor; }

/* index overlay */
#scrim { position: fixed; inset: 0; z-index: 95; background: rgba(3,4,6,0.55); opacity: 0; pointer-events: none; transition: opacity .3s; }
#scrim.open { opacity: 1; pointer-events: auto; }
.index-overlay {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(540px, 92vw); z-index: 100;
  background: var(--bg-2); border-left: 1px solid var(--line);
  transform: translateX(100%); transition: transform .5s var(--ease-out); overflow-y: auto; overscroll-behavior: contain;
}
.index-overlay.open { transform: translateX(0); }
.index-inner { padding: calc(var(--chrome-h) + 32px) 40px 64px; }
.index-head { display: flex; align-items: baseline; justify-content: space-between; padding-bottom: 22px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.index-kicker { font-family: var(--disp); font-weight: 800; font-size: 20px; }
.index-count { font-size: 11px; color: var(--faint); }
.index-list { display: flex; flex-direction: column; }
#index-filter { width: 100%; margin: 16px 0 2px; padding: 10px 14px; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; color: var(--ink); font-family: var(--text); font-size: 13px; outline: none; transition: border-color .2s; }
#index-filter:focus { border-color: var(--accent); }
#index-filter::placeholder { color: var(--faint); }
.index-sep { font-size: 11px; color: var(--faint); margin: 30px 0 6px; }
.nav-sec { display: flex; align-items: baseline; gap: 16px; padding: 12px 0; color: var(--dim); border-bottom: 1px solid var(--line); transition: color .18s, padding-left .2s var(--ease-out); }
.nav-sec:hover { color: var(--ink); padding-left: 8px; }
.nav-sec.active { color: var(--accent); }
.nav-num { font-family: var(--text); font-weight: 500; font-size: 12px; color: var(--faint); min-width: 24px; font-variant-numeric: tabular-nums; }
.nav-sec:hover .nav-num, .nav-sec.active .nav-num { color: var(--accent); }
.nav-label { font-family: var(--disp); font-weight: 800; font-size: 17px; line-height: 1.2; }

/* main / typography */
#main { padding-top: var(--chrome-h); position: relative; z-index: 2; }
.wrap { max-width: 46rem; margin: 0 auto; padding: 0 32px; }
.prose { max-width: 46rem; margin: 0 auto; padding: 80px 32px 128px; }

.kicker { font-family: var(--text); font-weight: 600; font-size: 11px; letter-spacing: 0.24em; text-transform: uppercase; color: var(--accent); margin-bottom: 16px; }
.sec-head { margin-bottom: 40px; }
.sec-head h1 { font-family: var(--disp); font-weight: 900; font-size: clamp(31px, 5vw, 52px); line-height: 1.02; letter-spacing: -0.01em; margin: 0; }

.prose h2, .prose h3, .prose h4 { font-family: var(--disp); letter-spacing: -0.005em; scroll-margin-top: calc(var(--chrome-h) + 24px); }
.prose h2 { font-size: 26px; font-weight: 800; margin: 64px 0 20px; padding-top: 30px; border-top: 1px solid var(--line); }
.prose h3 { font-size: 20px; font-weight: 800; margin: 42px 0 12px; }
.prose h4 { font-size: 13px; font-weight: 600; font-family: var(--text); margin: 30px 0 10px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--dim); }
.prose p { margin: 0 0 20px; }
.prose strong { font-weight: 600; color: #fff; }
.prose em { color: #dfe4e8; }
.prose a:not(.btn) { color: var(--accent); border-bottom: 1px solid rgba(255,106,43,0.32); transition: border-color .2s; }
.prose a:not(.btn):hover { border-bottom-color: var(--accent); }
.prose h2 a, .prose h3 a, .prose h4 a { color: inherit; border: 0; }
.prose h2 a:hover, .prose h3 a:hover { color: var(--accent); }

.prose ul, .prose ol { margin: 0 0 20px; padding-left: 24px; }
.prose li { margin: 8px 0; }
.prose li::marker { color: var(--accent); }
.prose ol li::marker { color: var(--faint); font-family: var(--text); font-size: 13px; }
.prose blockquote { margin: 26px 0; padding: 4px 24px; border-left: 2px solid var(--accent); color: #dbe0e5; }
.prose blockquote p:last-child { margin-bottom: 0; }
.prose code { font-family: ui-monospace, "Cascadia Mono", monospace; font-size: 0.85em; background: rgba(255,255,255,0.055); border: 1px solid var(--line); padding: 1px 6px; border-radius: 4px; color: #ffb083; overflow-wrap: anywhere; word-break: break-word; }
.prose pre { background: #04050a; border: 1px solid var(--line); border-radius: 10px; padding: 18px 20px; overflow-x: auto; margin: 26px 0; }
.prose pre code { background: none; border: 0; padding: 0; color: #ccd4de; font-size: 13px; }
.prose hr { border: 0; border-top: 1px solid var(--line); margin: 46px 0; }

.prose table { width: 100%; border-collapse: collapse; margin: 28px 0; font-size: 13.5px; display: block; overflow-x: auto; }
.prose td, .prose th { min-width: 5.5em; }
.prose td a, .prose th a { white-space: nowrap; }
.prose thead th { text-align: left; font-family: var(--disp); font-weight: 800; color: #fff; padding: 11px 14px; border-bottom: 2px solid var(--line-2); }
.prose tbody td { padding: 10px 14px; border-bottom: 1px solid var(--line); color: var(--dim); vertical-align: top; }
.prose tbody tr:hover td { color: var(--ink); }

.prose .fig { margin: 36px 0; }
.prose .fig img { display: block; width: 100%; height: auto; border-radius: 8px; border: 1px solid var(--line); background: #0c0d18; }
.prose figcaption { margin-top: 12px; font-size: 12.5px; color: var(--faint); padding-left: 16px; border-left: 2px solid var(--line); }
.prose .datamine-clip { margin: 36px 0; clear: both; }
.prose .datamine-clip video { display: block; width: 100%; height: auto; min-width: 0; max-width: 100%; border-radius: 8px; border: 1px solid var(--line); background: #0c0d18; }
.prose details { margin: 24px 0; border: 1px solid var(--line); border-radius: 8px; padding: 2px 18px; }
.prose summary { cursor: pointer; font-weight: 600; padding: 13px 0; font-family: var(--disp); }
.prose summary:hover { color: var(--accent); }
audio.track { display: block; width: 100%; max-width: 440px; margin: 10px 0 4px; height: 36px; }

.footnotes { margin-top: 64px; padding-top: 26px; border-top: 1px solid var(--line); font-size: 13px; color: var(--dim); }
.footnotes hr { display: none; }
/* the footnote plugin's own separator would double the .footnotes border top, this prevents it */
.prose hr.footnotes-sep { display: none; }
.footnotes ol { padding-left: 20px; }
.footnotes li { margin: 6px 0; overflow-wrap: anywhere; }
.footnote-ref a { border: 0; font-size: 0.78em; padding: 0 2px; color: var(--accent); }
.footnote-backref { border: 0; }

/* pager thing */
.pager { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 80px; }
.pg { display: flex; flex-direction: column; gap: 7px; padding: 20px 22px; border: 1px solid var(--line); border-radius: 8px; transition: border-color .2s, background .2s; }
.pg:hover { border-color: var(--line-2); background: var(--panel); }
.pg span { font-family: var(--text); font-size: 11.5px; color: var(--faint); }
.pg b { font-family: var(--disp); font-weight: 800; font-size: 16px; line-height: 1.2; }
.pg-next { text-align: right; }

/* key art header, jump nav, floating figs */
.sec-hero { position: relative; min-height: clamp(520px, 62vh, 780px); display: flex; align-items: flex-end; }
/* key art fades into the liquid background with a vertical mask,
   same as the home page */
.sec-hero-art { position: absolute; inset: 0; background-image: var(--img); background-size: cover; background-position: center 34%; z-index: 0;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 98%);
  mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 98%); }
/* darken behind the title only and a soft vignette; made it to keep focus so
   key art shows, faded out before the bottom edge */
.sec-hero-scrim { position: absolute; inset: 0; z-index: 1; background:
  radial-gradient(92% 90% at 20% 106%, rgba(6,8,11,0.64), transparent 58%),
  linear-gradient(180deg, rgba(6,8,11,0.28) 0%, transparent 44%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 70%, transparent 97%);
  mask-image: linear-gradient(180deg, #000 0%, #000 70%, transparent 97%); }
.sec-hero-inner { position: relative; z-index: 2; max-width: 64rem; width: 100%; margin: 0 auto; padding: 0 32px 34px; }
.sec-hero .kicker { margin-bottom: 12px; }
.sec-hero h1 { font-family: var(--disp); font-weight: 900; font-size: clamp(30px, 5.2vw, 56px); line-height: 1.0; letter-spacing: -0.015em; margin: 0; max-width: 20ch; text-shadow: 0 4px 30px rgba(0,0,0,0.6); }

.section-shell { max-width: 64rem; margin: 0 auto; padding: 0 32px; display: grid; grid-template-columns: minmax(0, 1fr) 208px; gap: 50px; align-items: start; }
.section-shell.no-aside { grid-template-columns: minmax(0, 46rem); justify-content: center; }
.section-shell .prose { max-width: none; padding: 44px 0 120px; margin: 0; }
.jump-nav { position: sticky; top: calc(var(--chrome-h) + 28px); padding-top: 48px; max-height: calc(100vh - var(--chrome-h) - 56px); overflow-y: auto; overscroll-behavior: contain; }
.jump-title { font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--faint); margin-bottom: 14px; }
.jump-list { list-style: none; margin: 0; padding: 0; border-left: 1px solid var(--line); }
.jump-list a { display: block; padding: 7px 0 7px 16px; margin-left: -1px; border-left: 1px solid transparent; font-size: 12.5px; color: var(--dim); line-height: 1.35; transition: color .2s, border-color .2s; }
.jump-list a:hover { color: var(--ink); border-left-color: var(--accent); }
.jump-list a.active { color: var(--accent); border-left-color: var(--accent); }

/* floating figs: image on the side, text wraps beside it .e.t.c. */
@media (min-width: 940px) {
  .prose .fig { float: right; width: 48%; margin: 6px 0 24px 34px; }
  .prose .fig.reveal-xl { float: left; margin: 6px 34px 24px 0; }
  .prose h2, .prose h3 { clear: both; }
}
.reveal-xl { transform: translateX(-38px); }
.reveal-xr { transform: translateX(38px); }
.reveal-xl.is-in, .reveal-xr.is-in { transform: none; }

/* custom inline marks (no emojis) Some generated text by crawlers contains emojis, this prevents it to look like an emoji */
.mk { display: inline-flex; width: 0.92em; height: 0.92em; vertical-align: -0.1em; margin: 0 0.08em; }
.mk svg { width: 100%; height: 100%; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.mk-ok svg { stroke: #63c98a; }
.mk-warn svg { stroke: var(--accent); }
.mk-warn svg circle { fill: var(--accent); stroke: none; }
.mk-star svg { fill: var(--accent); stroke: none; }
.mk-no svg { stroke: #e2574c; }

/* GFM task list checkboxes (rendered as inline SVG boxes by the generated machine text/build) */
.prose li.task { list-style: none; }
.task-box { display: inline-flex; width: 0.95em; height: 0.95em; vertical-align: -0.12em; margin-right: 0.5em; }
.task-box svg { width: 100%; height: 100%; fill: none; stroke: var(--dim); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
li.task-done .task-box svg { stroke: #63c98a; }

/* per sections search ( made a scope to the open section only) */
.sec-search { position: relative; margin: 0 0 34px; }
.sec-search-ico { position: absolute; left: 15px; top: 14px; width: 18px; height: 18px; fill: none; stroke: var(--faint); stroke-width: 1.7; stroke-linecap: round; pointer-events: none; }
#sec-search-input { width: 100%; padding: 13px 16px 13px 44px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; color: var(--ink); font-family: var(--text); font-size: 14px; outline: none; transition: border-color .2s, background .2s; }
#sec-search-input:focus { border-color: var(--accent); background: rgba(255,255,255,0.03); }
#sec-search-input::placeholder { color: var(--faint); }
.sec-search-results { position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 40; background: #0a0d13; border: 1px solid var(--line-2); border-radius: 10px; box-shadow: 0 14px 44px rgba(0,0,0,0.45); max-height: 62vh; overflow: hidden auto; display: none; }
.sec-search-results.open { display: block; }
.ss-item { display: block; width: 100%; text-align: left; background: none; border: 0; border-left: 2px solid transparent; padding: 12px 16px; cursor: pointer; }
.ss-item:hover, .ss-item.sel { background: var(--panel); border-left-color: var(--accent); }
.ss-head { display: block; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); margin-bottom: 4px; }
.ss-snip { display: block; font-size: 12.5px; color: var(--dim); line-height: 1.45; font-family: var(--text); }
.ss-snip mark, .sr-snip mark { background: rgba(255,106,43,0.24); color: #fff; border-radius: 2px; }
.ss-empty { padding: 16px; color: var(--faint); font-size: 13px; }

/* flash when the section search jumps to a match for better visibility */
.hit-flash { animation: hitflash 2.4s ease; border-radius: 5px; }
@keyframes hitflash { 0%, 100% { box-shadow: 0 0 0 0 rgba(255,106,43,0); background: transparent; } 12%, 45% { box-shadow: 0 0 0 8px rgba(255,106,43,0.13); background: rgba(255,106,43,0.13); } }

/* "buy me an Ice Tea" */
.support { display: flex; flex-wrap: wrap; align-items: center; gap: 26px; padding: 30px 34px; margin-top: 100px; border: 1px solid var(--line); border-radius: 16px; background: var(--panel); }
.support-ico { flex: none; color: var(--accent); width: 42px; height: 42px; }
.support-ico svg { width: 100%; height: 100%; }
.support-text { flex: 1; min-width: 0; }
.support-text h3 { font-family: var(--disp); font-weight: 800; font-size: 21px; margin: 0 0 6px; }
.support-text p { font-size: 13.5px; color: var(--dim); line-height: 1.6; margin: 0; max-width: 54ch; }
.support-btn { flex: none; }
/* "are u sure" shown in the Ice Tea card when the donation button is clicked */
.support-msg { flex-basis: 100%; width: 100%; margin: 4px 0 0; font-size: 17px; font-weight: 700; color: #ff5a5a; text-align: center; letter-spacing: 0.01em; opacity: 0; visibility: hidden; transform: translateY(-4px); transition: opacity .3s ease, transform .3s var(--ease-out); }
.support-msg.show { opacity: 1; visibility: visible; transform: none; }

/* screen shake for the support button's "Are you Sure?" step (the form
   cooldown triggers it too); soooo the second click opens Kofi normally now */
@keyframes screenshake {
  0%, 100% { transform: translate(0, 0); }
  10% { transform: translate(-6px, -4px); }
  20% { transform: translate(7px, 3px); }
  30% { transform: translate(-5px, 5px); }
  40% { transform: translate(6px, -6px); }
  50% { transform: translate(-7px, 2px); }
  60% { transform: translate(5px, 5px); }
  70% { transform: translate(-4px, -5px); }
  80% { transform: translate(6px, 3px); }
  90% { transform: translate(-3px, -2px); }
}
/* shake only the content wrapper, dont shake everything, because there is a bug with the bg so the fixed bg canvas is
   not reparented. that caused the giant background stretch when tested on localhost */
#main.shake { animation: screenshake 0.6s cubic-bezier(.36,.07,.19,.97) both; will-change: transform; }

.maker { color: var(--accent); border-bottom: 1px solid rgba(255,106,43,0.32); transition: border-color .2s; }
.maker:hover { border-bottom-color: var(--accent); }
.foot-links { font-size: 12px; color: var(--faint); letter-spacing: 0.02em; margin-top: 10px; }
.foot-links a { color: var(--dim); }
.foot-links a:hover { color: var(--accent); }
/* "POWERED BY VISION FORCE" — the studio credit, set FAT on purpose: the
   label stays small and quiet, the name itself is heavy display type */
.foot-powered { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--faint); margin-top: 18px; }
.foot-powered a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  /* line-height 1 + middle alignment keep the wordmark sitting ON the same
     baseline as "Powered by" — without them the taller inline-flex box rides
     up and lifts the whole name off the line */
  line-height: 1;
  vertical-align: middle;
  font-family: var(--disp), var(--text), sans-serif;
  font-weight: 800;
  font-size: 19px;
  letter-spacing: 0.03em;
  color: var(--ink);
  text-decoration: none;
  transition: color 0.2s, text-shadow 0.2s;
}
/* the Vision Force emblem, sized to the cap height so it reads as part of
   the wordmark rather than a pasted-on icon */
.foot-powered .vf-mark {
  height: 18px;
  width: auto;
  display: block;
  opacity: 0.9;
  transition: opacity 0.2s;
}
.foot-powered a:hover { color: var(--accent); text-shadow: 0 0 22px rgba(255, 106, 43, 0.45); }
.foot-powered a:hover .vf-mark { opacity: 1; }
/* machine generated disclosure line in the footers */
.foot-ai { font-size: 12px; color: var(--faint); line-height: 1.6; margin-top: 10px; max-width: 74ch; }
.foot-ai a { color: var(--dim); border-bottom: 1px solid rgba(255,106,43,0.28); }
.foot-ai a:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* reader contribution form */
.contribute { margin: 96px 0 0; padding: 40px 34px; border: 1px solid var(--line); border-radius: 16px; background: var(--panel); scroll-margin-top: 90px; }
.contribute-head { max-width: 48rem; }
.contribute-kick { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); }
.contribute-head h2 { font-family: var(--disp); font-weight: 900; font-size: clamp(23px, 3vw, 31px); line-height: 1.08; margin: 12px 0 12px; }
.contribute-head p { color: var(--dim); font-size: 14.5px; line-height: 1.7; margin: 0; }
.contribute-form { margin-top: 28px; display: flex; flex-direction: column; gap: 16px; }
.cf-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.cf-field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.cf-field > span { font-size: 12.5px; font-weight: 600; color: var(--ink); }
.cf-field em { font-style: normal; font-weight: 400; color: var(--faint); }
.cf-field input, .cf-field select, .cf-field textarea { width: 100%; font-family: var(--text); font-size: 14px; color: var(--ink); background: color-mix(in srgb, var(--bg) 55%, transparent); border: 1px solid var(--line-2); border-radius: 9px; padding: 11px 13px; outline: none; transition: border-color .2s, background .2s; }
.cf-field textarea { resize: vertical; min-height: 112px; line-height: 1.55; }
.cf-field select { appearance: none; -webkit-appearance: none; cursor: pointer; }
.cf-field input:focus, .cf-field select:focus, .cf-field textarea:focus { border-color: var(--accent); background: color-mix(in srgb, var(--bg) 38%, transparent); }
.cf-field input::placeholder, .cf-field textarea::placeholder { color: var(--faint); }
.cf-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.cf-foot { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin-top: 4px; }
.cf-status { font-size: 13px; font-weight: 600; }
.cf-status.cf-ok { color: #57d29a; }
.cf-status.cf-err, .cf-status.cf-warn { color: var(--accent); }
.cf-status.cf-sending { color: var(--dim); }
.cf-note { font-size: 12px; color: var(--faint); margin: 2px 0 0; }
@media (max-width: 720px) { .cf-row { grid-template-columns: 1fr; } .contribute { padding: 30px 22px; } }

/* essential cookie notice in corner card that never blocks the page from scrolling cuz its not mandatory */
.cookie-gate { position: fixed; right: 18px; bottom: 18px; z-index: 200; max-width: 380px; padding: 0; pointer-events: none; }
.cookie-gate[hidden] { display: none; }
.cookie-card { pointer-events: auto; padding: 18px 20px; background: #ffffff; color: #1b1b1b; border-radius: 10px; box-shadow: 0 14px 44px rgba(0,0,0,0.45); font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; }
.cookie-card h2 { font-family: inherit; font-weight: 700; font-size: 14px; line-height: 1.3; margin: 0 0 8px; color: #1b1b1b; letter-spacing: 0; }
.cookie-card p { font-family: inherit; font-size: 12.5px; line-height: 1.55; color: #444; margin: 0 0 14px; }
.cookie-card a { color: #1a56db; text-decoration: underline; }
.cookie-btn { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; font-weight: 600; font-size: 13px; padding: 8px 18px; border-radius: 6px; border: 0; background: #1b1b1b; color: #fff; cursor: pointer; transition: background .2s; }
.cookie-btn:hover { background: #333; }
.cookie-gate a, .cookie-gate button { cursor: pointer; }
@media (max-width: 520px) { .cookie-gate { left: 14px; right: 14px; bottom: 14px; max-width: none; } }

/* click a content image to view it full size EVERYWHERE */
.prose img { cursor: zoom-in; }
.prose a img { cursor: pointer; }
.lightbox { position: fixed; inset: 0; z-index: 190; display: none; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 28px; background: rgba(3,5,8,0.93); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); cursor: zoom-out; }
.lightbox.open { display: flex; }
.lightbox img { max-width: 96vw; max-height: 86vh; width: auto; height: auto; border-radius: 6px; box-shadow: 0 24px 80px rgba(0,0,0,0.65); }
.lightbox-cap { color: var(--dim); font-size: 13px; line-height: 1.5; text-align: center; max-width: 74ch; }

.legal { padding-bottom: 100px; }
.legal .prose { padding-top: 40px; }

/* HOME */
/* Main page with those RR key art loading screens, */
.hero { position: relative; min-height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: calc(var(--chrome-h) + 36px) 32px 84px; text-align: center; overflow-x: clip; }
/* machine generated disclosure pinned to the top of the mani page (hero) */
.hero-ai { position: absolute; top: calc(var(--chrome-h) + 14px); left: 50%; transform: translateX(-50%); z-index: 4; display: flex; align-items: flex-start; gap: 11px; width: max-content; max-width: min(93vw, 720px); padding: 9px 16px 9px 10px; text-align: left; background: rgba(6,8,11,0.55); border: 1px solid rgba(255,255,255,0.13); border-radius: 13px; -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); box-shadow: 0 12px 34px rgba(0,0,0,0.42); }
.hero-ai-tag { flex: none; margin-top: 1px; font-family: var(--text); font-weight: 700; font-size: 9.5px; letter-spacing: 0.13em; text-transform: uppercase; color: #0a0b0e; background: var(--accent); padding: 4px 9px; border-radius: 999px; }
.hero-ai p { margin: 0; font-size: 12px; line-height: 1.5; color: rgba(255,255,255,0.86); }
.hero-ai-link { color: var(--accent); font-weight: 600; border-bottom: 1px solid rgba(255,106,43,0.4); transition: border-color .2s; }
.hero-ai-link:hover { border-bottom-color: var(--accent); }
.hero-ai-motto { color: rgba(255,255,255,0.6); font-style: italic; }
@media (max-width: 640px) { .hero-ai { top: calc(var(--chrome-h) + 10px); gap: 9px; padding: 8px 13px 8px 9px; } .hero-ai p { font-size: 11.5px; } }
/* the clip wrapper carries the dissolve mask (straight fallback here, swapped
   for a generated noisy edge at runtime) and contains the ken burns overdraw */
.hero-clip { position: absolute; inset: 0; z-index: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 54%, transparent 96%);
  mask-image: linear-gradient(180deg, #000 0%, #000 54%, transparent 96%); }
.hero-art { position: absolute; inset: 0; background: url(media/hero-keyart.webp) center/cover no-repeat; opacity: 0; transition: opacity 1.6s ease; }
body.revealed .hero-art { opacity: 1; }
/* confetti */
.hero-fx { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none; }
/* keep the middle readable but let the image live to its dissolve line; the
   scrim itself must dissolve too or it paints a straight seam at the boundary and looks off a bit */
.hero-scrim { position: absolute; inset: 0; z-index: 1; background:
  radial-gradient(78% 60% at 50% 40%, rgba(6,8,11,0.24), rgba(6,8,11,0.44) 60%, transparent 82%),
  linear-gradient(180deg, rgba(6,8,11,0.55) 0%, transparent 30%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 52%, transparent 76%);
  mask-image: linear-gradient(180deg, #000 0%, #000 52%, transparent 76%); }
/* z-index 5 puts this ABOVE .hero-ai (4), and it has to be here rather than on
   the bubble itself. A speech bubble sets z-index 6 and still lost to the
   notice, because .hero-inner is a stacking context and .hero-logo-wrap adds a
   second one with its drop-shadow filter: a descendant can never out-sort an
   ancestor's sibling, whatever number it carries. Reported by a reader and
   reproduced on a phone, where the notice wraps to twelve lines and reaches
   down into the space the bubbles pop into. */
.hero-inner { position: relative; z-index: 5; max-width: 46rem; width: 100%; }
/* the wordmark with the DelMar loading indicator v2 as the O of ROCKET */
.hero-logo-wrap { position: relative; width: clamp(240px, 32vw, 380px); margin: 0 auto 26px; filter: drop-shadow(0 6px 30px rgba(0,0,0,0.75)); }
.hero-logo { display: block; width: 100%; height: auto; image-rendering: -webkit-optimize-contrast; }
/* playful speech bubble that pops from the logo (de Blob squish, low poly bob) */
.logo-bubble { position: absolute; left: 50%; bottom: calc(100% + 2px); transform: translateX(-50%); z-index: 6; pointer-events: none; }
.logo-bubble.show { animation: bubbleFloat 1.6s .55s steps(7) infinite; }
.lb-inner { display: inline-block; transform-origin: 50% 128%; transform: scale(0); opacity: 0; max-width: min(74vw, 250px); padding: 9px 15px; border-radius: 15px; background: #fbfbfb; color: #0d0f13; font-family: var(--text); font-weight: 700; font-size: 12.5px; line-height: 1.32; text-align: center; box-shadow: 0 12px 30px rgba(0,0,0,0.5); }
.lb-inner::after { content: ""; position: absolute; left: 50%; top: 100%; transform: translateX(-50%); border: 8px solid transparent; border-top-color: #fbfbfb; margin-top: -1px; }
.logo-bubble.show .lb-inner { animation: bubblePop .55s cubic-bezier(.34,1.7,.5,1) forwards; }
.logo-bubble.hide .lb-inner { animation: bubbleHide .34s ease-in forwards; }
@keyframes bubblePop {
  0% { transform: scale(0) rotate(-5deg); opacity: 0; }
  50% { transform: scale(1.16) rotate(3deg); opacity: 1; }
  68% { transform: scale(0.9) rotate(-2deg); }
  84% { transform: scale(1.06) rotate(1deg); }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}
@keyframes bubbleHide {
  0% { transform: scale(1) rotate(0); opacity: 1; }
  100% { transform: scale(0) rotate(4deg); opacity: 0; }
}
@keyframes bubbleFloat {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(-6px); }
}
/* THE O IS A CANVAS, AND THE DEFAULT MUST SURVIVE IT NEVER PAINTING.
 *
 * The wordmark ships twice: .logo-cut has the O physically deleted, .logo-full
 * is whole. The live DelMar wheel is drawn into the hole. This used to default
 * to the cut image and only swap in the whole one when the WebGPU probe
 * REPORTED failure, so every other way of failing left a permanent hole and the
 * hero read "R CKET RACING". A reader saw exactly that and asked whether it was
 * on purpose.
 *
 * Inverted: the whole wordmark shows unless the wheel proves it is running, at
 * which point .gpu-ok cross-fades it out from under the canvas. Now a refused
 * context, a probe that resolves but paints nothing, a slow first frame, and a
 * screenshot taken during the fade all show a correct O instead of a gap.
 *
 * .logo-cut stays in flow so it keeps defining the wrap's box, which is what
 * .hero-o's percentage geometry resolves against. */
.logo-full { position: absolute; left: 0; top: 0; width: 100%; height: auto; opacity: 1; transition: opacity .45s ease; }
/* the cut out ellipse in the wordmark: center (94.5, 31.2), rx 32.2, ry 31.6 of 328x128 */
.hero-o { position: absolute; left: 19.0%; top: 0; width: 19.63%; height: 49.1%; }
#hero-canvas { width: 100%; height: 100%; display: block; opacity: 0; transition: opacity 1.2s ease .2s; }
/* The O is the loading wheel, and the wheel must be the ONLY thing in that hole.
 *
 * Leaving the solid wordmark underneath sounded safe and was not: the static O
 * showed through the animation, so the logo read as an ordinary O and the whole
 * point of the wheel was lost. The solid one is a FALLBACK, so it has to get
 * out of the way the moment the wheel is running.
 *
 * gpu-ok is added only after mountDelMarHero resolves ok and two frames have
 * passed. That is still a promise, not proof of paint, and it is the open bug:
 * a machine where the mount reports success but nothing draws gets the hole
 * back. Fixing that properly means asking the canvas whether it has real
 * pixels, not asking the mount whether it thinks it worked. */
.hero-logo-wrap.gpu-ok .logo-full { opacity: 0; }
.hero-logo-wrap.gpu-ok #hero-canvas { opacity: 1; }
/* no JS: nothing can paint the hole, so the whole wordmark is all there is */
.no-js .hero-o { display: none; }
.hero-tag { font-size: clamp(15px, 2.1vw, 19px); color: #fff; max-width: 38rem; margin: 0 auto 38px; text-shadow: 0 2px 22px rgba(0,0,0,0.65); }
.wide { max-width: 72rem; margin: 0 auto; padding: 0 32px; }
.hero-cta { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
/* the big hero search field in middle */
.hero-search { position: relative; width: min(90vw, 440px); margin: 32px auto 0; }
.hs-field { position: relative; z-index: 1; display: flex; align-items: center; gap: 11px; height: 52px; padding: 0 12px 0 15px; border-radius: 13px; background: rgba(10,12,16,0.62); border: 1px solid rgba(255,190,110,0.28); box-shadow: 0 10px 34px rgba(0,0,0,0.4), inset 0 0 0 1px rgba(255,255,255,0.03); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); cursor: text; transition: border-color .25s, box-shadow .25s; }
.hs-field:hover, .hs-field:focus-within { border-color: rgba(255,190,110,0.62); box-shadow: 0 12px 40px rgba(0,0,0,0.45), 0 0 28px rgba(255,150,50,0.2); }
.hs-ico { flex: none; width: 19px; height: 19px; color: rgba(255,205,140,0.85); }
.hs-field input { flex: 1; min-width: 0; background: none; border: 0; outline: 0; font-family: var(--text); font-size: 15px; color: var(--ink); }
.hs-field input::placeholder { color: rgba(255,255,255,0.44); }
.hs-field input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.hs-kbd { flex: none; font-family: var(--text); font-size: 11px; color: var(--dim); background: rgba(255,255,255,0.06); border: 1px solid var(--line-2); border-radius: 6px; padding: 3px 7px; }
/* pulse the contribution form when a reader jumps to it from a "contribute" link */
@keyframes cfPulse { 0% { border-color: var(--accent); box-shadow: 0 0 0 0 rgba(255,106,43,0.45); } 100% { border-color: var(--line); box-shadow: 0 0 0 22px rgba(255,106,43,0); } }
.contribute.cf-highlight { animation: cfPulse 1.7s ease; }
/* structured "island" buttons with a nested icon and a hover zoom to recreate this minimalistic professional effect I saw on cool websites */
.btn { display: inline-flex; align-items: center; gap: 12px; padding: 11px 13px 11px 24px; border-radius: 999px; font-family: var(--text); font-weight: 600; font-size: 14px; border: 1px solid var(--line-2); color: var(--ink); transition: transform .25s var(--ease-out), border-color .2s, background .2s; }
.btn:hover { transform: scale(1.035); border-color: var(--dim); }
.btn-ico { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(255,255,255,0.08); font-size: 13px; transition: transform .25s var(--ease-out), background .2s; }
.btn:hover .btn-ico { transform: translateX(2px); background: rgba(255,255,255,0.15); }
.btn-primary { background: var(--accent); color: #0a0b0e; border-color: var(--accent); font-weight: 700; }
.btn-primary .btn-ico { background: rgba(0,0,0,0.18); }
.btn-primary:hover { background: #ff7d45; border-color: #ff7d45; }
.btn-primary:hover .btn-ico { background: rgba(0,0,0,0.24); }

/* image and text feature bands */
.features { padding-top: 104px; }
.feature { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 52px; align-items: center; margin-bottom: 104px; }
.feature-rev .feature-media { order: 2; }
.feature-media { display: block; overflow: hidden; border-radius: 12px; border: 1px solid var(--line); aspect-ratio: 16 / 10; background: #0c0d15; }
.feature-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .7s var(--ease-out); }
.feature-media:hover img { transform: scale(1.045); }
.feature-kick { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); }
.feature-title { font-family: var(--disp); font-weight: 900; font-size: clamp(24px, 3vw, 34px); line-height: 1.06; letter-spacing: -0.01em; margin: 14px 0 16px; }
.feature-text p { color: var(--dim); font-size: 15px; line-height: 1.7; margin: 0 0 22px; }
.feature-link { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px; transition: gap .2s, color .2s; }
.feature-link:hover { color: var(--accent); gap: 12px; }
.fl-go { color: var(--accent); }

.provenance { font-size: 13.5px; color: var(--dim); padding: 22px 26px; margin: 72px 0 56px; border: 1px solid var(--line); border-radius: 10px; }
.provenance blockquote { margin: 0 0 12px; border-left-width: 2px; }
.provenance blockquote:last-of-type { margin-bottom: 0; }
.prologue { padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; max-width: none; }
.prologue h2 { border-top: 0; padding-top: 0; font-family: var(--disp); font-weight: 900; font-size: clamp(27px, 4vw, 40px); margin: 0 0 24px; }

.index-title { display: flex; align-items: baseline; justify-content: space-between; margin: 112px 0 20px; }
.index-title h2 { font-family: var(--disp); font-weight: 800; font-size: 24px; margin: 0; }
.index-title span { font-size: 12px; color: var(--faint); }

/* bento mosaic */
.sec-mosaic { display: grid; grid-template-columns: repeat(auto-fill, minmax(228px, 1fr)); grid-auto-rows: 184px; grid-auto-flow: dense; gap: 14px; }
.sc { position: relative; overflow: hidden; border-radius: 14px; border: 1px solid var(--line); background: var(--panel); display: flex; flex-direction: column; justify-content: flex-end; padding: 22px; transition: transform .3s var(--ease-out), border-color .2s; }
.sc:hover { transform: translateY(-4px); border-color: var(--line-2); }
.sc-num { font-family: var(--text); font-weight: 600; font-size: 12px; color: var(--accent); letter-spacing: 0.05em; position: relative; z-index: 2; }
.sc-title { font-family: var(--disp); font-weight: 800; font-size: 18px; line-height: 1.14; margin-top: 8px; position: relative; z-index: 2; }
.sc-teaser { font-size: 12px; color: var(--dim); line-height: 1.5; margin-top: 9px; position: relative; z-index: 2; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.sc-go { position: absolute; top: 16px; right: 18px; color: #fff; font-size: 14px; opacity: 0; transform: translate(-3px, 3px); transition: opacity .25s, transform .25s var(--ease-out); z-index: 3; }
.sc:hover .sc-go { opacity: 0.9; transform: none; }
/* image tiles */
.sc-img { grid-column: span 2; border-color: transparent; }
.sc-img::before { content: ""; position: absolute; inset: 0; background-image: var(--img); background-size: cover; background-position: center; transition: transform .8s var(--ease-out); z-index: 0; }
.sc-img::after { content: ""; position: absolute; inset: 0; z-index: 1; background: linear-gradient(180deg, rgba(6,8,11,0.05) 18%, rgba(6,8,11,0.5) 52%, rgba(6,8,11,0.93)); }
.sc-img:hover::before { transform: scale(1.06); }
.sc-img .sc-num { color: #fff; opacity: 0.85; }
.sc-img .sc-title { font-size: clamp(19px, 2vw, 22px); text-shadow: 0 2px 14px rgba(0,0,0,0.5); }
.sc-big { grid-row: span 2; }
.sc-big .sc-title { font-size: clamp(23px, 2.4vw, 32px); }
/* typographic tiles get a ghost number */
.sc-txt::before { content: attr(data-n); position: absolute; right: 12px; bottom: -20px; font-family: var(--disp); font-weight: 900; font-size: 96px; line-height: 1; color: rgba(255,255,255,0.035); z-index: 0; letter-spacing: -0.04em; transition: color .3s; }
.sc-txt:hover::before { color: rgba(255,106,43,0.09); }

/* companion cards */
.comp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.comp-card { display: flex; flex-direction: column; gap: 10px; padding: 26px; border: 1px solid var(--line); border-radius: 14px; background: var(--panel); transition: transform .3s var(--ease-out), border-color .2s; }
.comp-card:hover { transform: translateY(-4px); border-color: var(--line-2); }
.comp-kick { font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); }
.comp-title { font-family: var(--disp); font-weight: 800; font-size: 21px; }
.comp-teaser { font-size: 13px; color: var(--dim); line-height: 1.6; flex: 1; }
.comp-go { font-family: var(--text); font-weight: 600; font-size: 13px; color: var(--ink); transition: color .2s; }
.comp-card:hover .comp-go { color: var(--accent); }

.site-foot { margin: 112px 0 48px; padding-top: 34px; border-top: 1px solid var(--line); }
/* slim footer on inner pages (sections, companions, terms) */
.slim-foot { max-width: 64rem; margin: 0 auto; padding: 30px 32px 48px; }
.slim-foot p { font-size: 12px; color: var(--faint); line-height: 1.7; margin: 0 0 6px; }
.slim-foot .foot-links { margin-top: 0; }

/* back to top */
#backtop { position: fixed; right: 22px; bottom: 22px; z-index: 85; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: 50%; border: 1px solid var(--line-2); background: color-mix(in srgb, var(--bg) 82%, transparent); backdrop-filter: blur(10px); color: var(--dim); cursor: pointer; opacity: 0; pointer-events: none; transform: translateY(8px); transition: opacity .25s, transform .25s var(--ease-out), color .2s, border-color .2s; }
#backtop.show { opacity: 1; pointer-events: auto; transform: none; }
#backtop:hover { color: var(--accent); border-color: var(--dim); }
#backtop svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.foot-mark { font-family: var(--disp); font-weight: 800; font-size: 14px; color: var(--dim); margin-bottom: 16px; }
.site-foot p { font-size: 12px; color: var(--faint); line-height: 1.7; max-width: 54rem; margin: 0 0 8px; }
.foot-meta { letter-spacing: 0.04em; }

/* SEARCH */
#search-modal { position: fixed; inset: 0; z-index: 110; display: flex; justify-content: center; align-items: flex-start; padding-top: 12vh; opacity: 0; pointer-events: none; transition: opacity .2s; }
#search-modal.open { opacity: 1; pointer-events: auto; }
.search-panel { width: min(640px, 92vw); background: #0a0d13; border: 1px solid var(--line-2); border-radius: 12px; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.35); transform: translateY(-8px); transition: transform .2s var(--ease-out); }
#search-modal.open .search-panel { transform: translateY(0); }
#search-input { width: 100%; border: 0; border-bottom: 1px solid var(--line); background: none; color: var(--ink); font-family: var(--text); font-size: 15.5px; padding: 18px 22px; outline: none; }
#search-input::placeholder { color: var(--faint); }
.search-results { max-height: 54vh; overflow-y: auto; }
.search-results:empty { display: none; }
.sr-item { display: flex; flex-direction: column; gap: 3px; padding: 13px 22px; border-left: 2px solid transparent; }
.sr-item:hover, .sr-item.sel { background: var(--panel); border-left-color: var(--accent); }
.sr-kick { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.sr-title { font-family: var(--disp); font-weight: 800; font-size: 15px; }
.sr-snip { font-size: 12.5px; color: var(--faint); line-height: 1.45; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.sr-snip mark { background: rgba(255,106,43,0.24); color: #fff; border-radius: 2px; }
.sr-empty { padding: 26px; color: var(--faint); text-align: center; }
.search-hint { display: flex; gap: 8px; align-items: center; padding: 11px 22px; border-top: 1px solid var(--line); color: var(--faint); font-size: 11px; }

/* 404 */
.notfound { padding: 24vh 32px 30vh; text-align: center; }
.nf-code { font-family: var(--disp); font-weight: 900; font-size: clamp(64px, 12vw, 116px); color: var(--accent); line-height: 1; }
.notfound h1 { font-family: var(--disp); font-weight: 800; font-size: 28px; margin: 12px 0 16px; }
.notfound p { color: var(--dim); max-width: 34rem; margin: 0 auto 28px; }
.nf-index { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 2px 30px; max-width: 56rem; margin: 48px auto 0; text-align: left; }
.nf-index a { display: flex; gap: 12px; padding: 9px 4px; font-size: 13px; color: var(--dim); border-bottom: 1px solid var(--line); transition: color .2s; }
.nf-index a:hover { color: var(--accent); }
.nf-index a span { color: var(--faint); font-variant-numeric: tabular-nums; }

/* MOTION. scroll appearance only */
/* Hiding is OPT-IN, gated on a class only the bundle can add.
 *
 * This used to be an unconditional `[data-reveal] { opacity: 0 }` with a
 * `.no-js` escape hatch, and the escape hatch never fired: an inline script in
 * the head replaces the whole className with "js" before any of this is
 * evaluated, so `.no-js` was gone within milliseconds on every load. That left
 * exactly one thing able to reveal the page, app.js, and when app.js 404'd the
 * entire site rendered as a blank dark screen with 64 elements stuck at
 * opacity 0. It shipped that way and was invisible to visitors and to Google.
 *
 * Now the default is VISIBLE. reveal.ts adds `reveal-ready` to <html> before it
 * starts observing, so the animation only exists once the code that can finish
 * it is running. A missing or broken bundle degrades to plain, readable
 * content instead of nothing at all. */
.reveal-ready [data-reveal] { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease-out), transform .7s var(--ease-out); transition-delay: var(--reveal-delay, 0ms); }
.reveal-ready [data-reveal].is-in { opacity: 1; transform: none; }

/* RESPONSIVE */
/* device band fixes, placed after base rules so they win on source order */
/* iPad portrait/landscape (721-1000px): the sticky 208px jump nav squeezes the
   prose to a cramped column, so drop the aside and read single column, centred
   (Below 720px the mobile block that replaces over) */
@media (max-width: 1000px) {
  .section-shell { grid-template-columns: minmax(0, 46rem); justify-content: center; }
  .jump-nav { display: none; }
}
/* collapse the home feature bands to one column before they get cramped on tablet */
@media (max-width: 900px) {
  .feature { grid-template-columns: 1fr; gap: 24px; margin-bottom: 72px; }
  .feature-rev .feature-media { order: 0; }
  .features { padding-top: 72px; }
}
/* footer links which give each a tappable box on touch without changing the look */
@media (pointer: coarse) {
  .foot-links a { display: inline-block; padding: 6px 2px; }
}
/* inputs must be >=16px on touch or iOS Safari zooms the whole page on focus */
@media (max-width: 1024px) {
  #search-input, #sec-search-input, #index-filter, .hs-field input,
  .cf-field input, .cf-field select, .cf-field textarea { font-size: 16px; }
}
/* let the visual grid appear on very large screens; reading column stays put */
@media (min-width: 2200px) {
  .wide, .features { max-width: 84rem; }
}

@media (max-width: 720px) {
  .chrome { padding: 0 18px; }
  .chrome-here { display: none; }
  .wrap, .prose { padding-left: 20px; padding-right: 20px; }
  .prose { padding-top: 56px; }
  .hero { padding-left: 20px; padding-right: 20px; }
  .pager { grid-template-columns: 1fr; }
  .section-shell { grid-template-columns: minmax(0, 1fr); padding: 0 20px; gap: 0; }
  .section-shell .prose { padding-top: 34px; }
  .jump-nav { display: none; }
  .sec-hero { min-height: 232px; }
  .sec-hero-inner { padding: 0 20px 26px; }
  .wide { padding-left: 20px; padding-right: 20px; }
  .features { padding-top: 64px; }
  .feature { grid-template-columns: 1fr; gap: 22px; margin-bottom: 64px; }
  .feature-rev .feature-media { order: 0; }
  .sec-mosaic { grid-template-columns: 1fr 1fr; grid-auto-rows: 150px; gap: 10px; }
  .sc-img { grid-column: span 2; }
  .sc-big { grid-row: span 1; }
  .index-title { margin-top: 80px; }
  .support { flex-direction: column; align-items: flex-start; padding: 24px 22px; margin-top: 60px; }
  /* trim the airy desktop spacing thing so phones do NOTT scroll through empty gaps */
  .contribute { margin-top: 60px; }
  .provenance { margin: 44px 0 40px; }
  .site-foot { margin-top: 68px; }
  .index-title { margin-top: 64px; }
  .prose h2 { margin-top: 42px; padding-top: 22px; }
  .prose h3 { margin-top: 32px; }
  .prose hr { margin: 34px 0; }
}
@media (max-width: 440px) {
  .sec-mosaic { grid-template-columns: 1fr; }
  /* one column grid. stop image tiles from spanning 2 and spawning a crushed column */
  .sc-img { grid-column: auto; }
}
@media (max-width: 480px) {
  .brand-name em { display: none; }
  .chrome-btn span { display: none; }
  /* the index button collapses to just the hamburger glyph: this should do it more realistically */
  #index-btn { min-width: 44px; min-height: 44px; justify-content: center; padding: 8px; }
}

/* device support across phones, tablets, laptops */
@media (max-width: 720px) {
  .hero-search { width: 100%; margin-top: 26px; }
  .hs-field { height: 50px; }
  .hero-ai { max-width: 94vw; }
}
@media (max-width: 480px) {
  /* the header search stays a readable affordance on touch. this(drop the kbd hint) */
  #search-btn { padding: 6px 11px; }
  #search-btn span { display: inline; }
  #search-btn kbd { display: none; }
  .hero-ai { gap: 8px; padding: 8px 12px 8px 8px; }
  .hero-ai p { font-size: 11px; line-height: 1.45; }
  .hero-ai-tag { font-size: 9px; padding: 3px 7px; letter-spacing: 0.1em; }
  .hs-field input { font-size: 16px; }   /* >=16px stops iOS zoom-on-focus */
}
/* short viewports (landscape phones) */
/* short viewports (incl. common laptops maximized at ~660-732px tall) */
@media (max-height: 760px) {
  /* This is why the notice reads as a full width strip rather than a chunk: on
     a short viewport it drops out of its absolute position and, with max-width
     100%, stretches to the whole hero column. Common laptops and most ultrawide
     panels are under 760px tall, so it is the usual case, not an edge one.
     min() keeps the phone behaviour identical and caps the wide case. */
  .hero-ai { position: static; transform: none; margin: 0 auto 14px; max-width: min(100%, 72rem); }
  .sec-hero { min-height: 60vh; }
}
/* very short (landscape phones so everything fits */
@media (max-height: 620px) {
  .hero { padding-top: calc(var(--chrome-h) + 14px); justify-content: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
  [data-reveal] { opacity: 1; transform: none; }
  /* still gated on the wheel actually running: forcing the canvas visible when
     it never painted would put an empty hole over the solid O */
  .hero-logo-wrap.gpu-ok #hero-canvas { opacity: 1; }
  /* animations are off a bit, so show the shown bubble statically */
  .logo-bubble.show .lb-inner { transform: none; opacity: 1; }
}


/* the 14.1 music pack vinyl: floats free like a pickup item, 3d idle tilt.
   perspective makes the receding edge shrink so the tilts read as depth.
   the three motions (rotateY, rotateX, bob) run on separate layers with
   different periods, so they drift in and out of phase and never all rest
   at once: continuous life instead of tick-pause-tick */
.prose .fig-3d { perspective: 640px; max-width: 232px; margin: 30px auto; }
.prose .fig-3d .i3a, .prose .fig-3d .i3b { display: block; transform-style: preserve-3d; will-change: transform; }
.prose .fig-3d .i3a { animation: idle-ry 7.3s ease-in-out -3.1s infinite alternate; }
.prose .fig-3d .i3b { animation: idle-rx 9.1s ease-in-out -1.4s infinite alternate; }
.prose .fig-3d img { border: 0; background: none; border-radius: 0; filter: drop-shadow(0 20px 24px rgba(0,0,0,0.55)); animation: idle-bob 5.2s ease-in-out -2.2s infinite alternate; will-change: transform; }
.prose .fig-3d figcaption { text-align: center; }
@media (min-width: 940px) {
  .prose .fig.fig-3d { width: 256px; max-width: 256px; }
}
@keyframes idle-ry { from { transform: rotateY(-7deg); } to { transform: rotateY(7deg); } }
@keyframes idle-rx { from { transform: rotateX(-5deg); } to { transform: rotateX(5.5deg); } }
@keyframes idle-bob { from { transform: translateY(-2px); } to { transform: translateY(-11px); } }

/* ── Vaelora Velocity showcase card ─────────────────────────────────────────
   The biggest card on the page. Its DEFAULT glow is the exact Vision Force orb
   "Okay" hover effect ported over: a tight white neon rim plus an feTurbulence
   "vape smoke" bleed (media/va-smoke.png pushed through #va-smokef). On hover
   the art zooms like the archive tiles and a full-screen focus vignette dims
   the rest of the page so only this card stays lit. Fast fade in, long fade
   out, keyed off :hover so it needs no JS. .vaelora and .vaelora-wrap are kept
   free of transform/opacity so they never become stacking contexts, which is
   what lets the fixed vignette cover the viewport and the raised card poke
   through it. */
.vaelora-wrap { position: relative; margin: 168px auto 192px; }
.va-defs { position: absolute; width: 0; height: 0; }
.vaelora { position: relative; }

.vaelora-vignette {
  position: fixed; inset: 0; z-index: 90; pointer-events: none; opacity: 0;
  background: radial-gradient(170% 160% at 50% 46%, rgba(3,5,11,0.84) 0%, rgba(1,2,7,0.93) 45%, rgba(0,0,3,0.975) 100%);
  transition: opacity 1.7s ease;
}
.vaelora:hover .vaelora-vignette { opacity: 1; transition: opacity 0.4s ease; }

.vaelora-smoke {
  position: absolute; inset: -140px; z-index: 0; pointer-events: none; opacity: 1;
  filter: blur(6px) url(#va-smokef);
  /* a soft envelope that HUGS the whole card — every edge and corner — feathering
     to nothing before the box edge (two axis gradients intersected → rounded, no
     hard sides). the tiled smoke beneath DRIFTS continuously (va-flow-*) so the
     clouds actually billow instead of sitting frozen; that movement plus the
     #va-smokef displacement dissolve the envelope so it never reads as a shape. */
  -webkit-mask:
    linear-gradient(to right, transparent 0, #000 13%, #000 87%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 17%, #000 83%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask:
    linear-gradient(to right, transparent 0, #000 13%, #000 87%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 17%, #000 83%, transparent 100%);
  mask-composite: intersect;
  transition: opacity 0.5s ease;
  animation: va-smoke-drift 9s ease-in-out infinite alternate;
}
/* the pseudos overscan the smoke box by 60px so the drifting texture never pulls
   a bare edge into view as it scrolls */
.vaelora-smoke::before, .vaelora-smoke::after { content: ""; position: absolute; inset: -60px; }
/* the REAL smoke.png tiled at native density, its position ANIMATED so the puffs
   billow (va-flow-*); offsets are whole-tile multiples so the loop is seamless */
.vaelora-smoke::before {
  background: rgba(255,255,255,0.6);
  mask: url(media/va-smoke.png) luminance 0 0 / 320px 320px repeat;
  -webkit-mask: url(media/va-smoke.png) luminance 0 0 / 320px 320px repeat;
  animation: va-flow-a 26s linear infinite;
}
.vaelora-smoke::after {
  background: rgba(255,255,255,0.42);
  mask: url(media/va-smoke.png) luminance 0 0 / 384px 384px repeat;
  -webkit-mask: url(media/va-smoke.png) luminance 0 0 / 384px 384px repeat;
  transform: scaleX(-1);
  animation: va-flow-b 34s linear infinite;
}
/* fallback where luminance masks are unsupported: procedural soft blobs */
@supports not (mask-mode: luminance) {
  .vaelora-smoke::before { mask: none; -webkit-mask: none; background:
    radial-gradient(40% 36% at 22% 40%, rgba(255,255,255,0.5), transparent 66%),
    radial-gradient(38% 34% at 74% 30%, rgba(255,255,255,0.42), transparent 68%),
    radial-gradient(34% 30% at 50% 74%, rgba(255,255,255,0.4), transparent 70%); }
  .vaelora-smoke::after { mask: none; -webkit-mask: none; background:
    radial-gradient(36% 32% at 30% 70%, rgba(255,255,255,0.4), transparent 68%),
    radial-gradient(34% 30% at 78% 66%, rgba(255,255,255,0.36), transparent 70%); }
}
/* hover: the smoke all but vanishes so it stops competing with the focused card,
   but the card's own rim glow stays (that lives on .vaelora-frame, untouched) */
.vaelora:hover .vaelora-smoke { opacity: 0.08; }
@keyframes va-smoke-drift { from { transform: translate3d(0,3px,0) rotate(-1.2deg) scale(1.01); } to { transform: translate3d(0,-4px,0) rotate(1.2deg) scale(1.05); } }
@keyframes va-flow-a { from { mask-position: 0 0; -webkit-mask-position: 0 0; } to { mask-position: -640px 320px; -webkit-mask-position: -640px 320px; } }
@keyframes va-flow-b { from { mask-position: 0 0; -webkit-mask-position: 0 0; } to { mask-position: 384px -768px; -webkit-mask-position: 384px -768px; } }

.vaelora-frame {
  position: relative; z-index: 1; display: block; aspect-ratio: 16 / 9;
  border-radius: 18px; overflow: hidden; border: 1px solid var(--line); background: #05060a;
  box-shadow: 0 0 16px rgba(255,255,255,0.5), 0 0 48px rgba(255,255,255,0.22);
  transition: transform 0.6s var(--ease-out), box-shadow 0.55s ease;
}
.vaelora-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.9s var(--ease-out); }
.vaelora-scrim { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, rgba(5,6,10,0) 44%, rgba(5,6,10,0.5) 76%, rgba(5,6,10,0.92) 100%); }
.vaelora-copy { position: absolute; left: 0; bottom: 0; z-index: 2; max-width: 34rem; padding: clamp(22px,3vw,44px); }
.vaelora-kick { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); }
.vaelora-title { font-family: var(--disp); font-weight: 900; font-size: clamp(34px,5.5vw,64px); line-height: 1.0; letter-spacing: -0.01em; margin: 10px 0 12px; text-shadow: 0 2px 30px rgba(0,0,0,0.75); }
.vaelora-copy p { color: #d7dde4; font-size: 15px; line-height: 1.6; margin: 0 0 20px; text-shadow: 0 1px 12px rgba(0,0,0,0.7); }
.vaelora-link { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px; color: #fff; transition: gap 0.2s, color 0.2s; }

.vaelora-frame:hover .vaelora-art { transform: scale(1.05); }
.vaelora:hover .vaelora-frame { transform: translateY(-4px); box-shadow: 0 0 22px rgba(255,255,255,0.72), 0 0 64px rgba(206,230,252,0.4), 0 24px 70px rgba(0,0,0,0.6); z-index: 92; }
.vaelora:hover .vaelora-smoke { z-index: 91; }
.vaelora:hover .vaelora-link { color: var(--accent); gap: 12px; }

@media (prefers-reduced-motion: reduce) {
  .vaelora-vignette, .vaelora-smoke, .vaelora-art, .vaelora-frame { transition: none; }
  .vaelora-smoke, .vaelora-smoke::before, .vaelora-smoke::after { animation: none; }
}
@media (max-width: 640px) { .vaelora-wrap { margin-bottom: 72px; } .vaelora-frame { aspect-ratio: 4 / 5; } }

/* ── page crack: the fissure from the countdown down to the Vaelora card ─────
   Positioned by src/page-crack.ts, which measures the two elements and spans
   between them. A wide blurred glow pass under a thin bright core, the same
   cold white as the rift, drawn over the content (pointer-events none) so it
   reads as one break travelling down the page. */
/* z-index -1 drops the whole tear BEHIND the page content (text, cards) while
   still sitting over the liquid background; the vertical mask fades it IN from
   the countdown at the top and OUT into the card at the bottom */
.page-crack { position: absolute; left: 0; width: 100%; z-index: -1; pointer-events: none;
  -webkit-mask: linear-gradient(to bottom, transparent 0, #000 8%, #000 88%, transparent 100%);
  mask: linear-gradient(to bottom, transparent 0, #000 8%, #000 88%, transparent 100%); }
.page-crack svg { width: 100%; height: 100%; display: block; overflow: visible; }
/* the cut is the countdown void carried down the page: a DARK open fissure with
   light ONLY on its two separated edges — never a bright centre line. layered
   back→front so the void covers the inward half of the lip bloom and the centre
   always reads black. colours are the rift's real values (rift-gl.ts): lip
   #DBF0FF, outer halo #B3D1EB, void edge #030508, void deep-centre #010102. */
/* The tear is a DARK jagged fissure with NO bright white lines anywhere — only a
   dim, cool haze bleeding off its edges (like a real crack, not a neon stroke).
   Layered back→front so the black void covers the inward half of the edge haze
   and the centre always reads as an empty dark gap. */
/* faint cool haze around the whole tear — a soft column, never a line */
.pc-halo { fill: none; stroke: rgba(150,178,205,0.12); stroke-width: 6; stroke-linecap: round; stroke-linejoin: round; filter: blur(12px); }
/* the edge haze — dim, cool, heavily blurred; the void below covers its inward
   half so it only ghosts along the outside of the fissure. deliberately NOT
   white and NOT crisp, so it never reads as a drawn line */
.pc-lip-bloom { fill: none; stroke: rgba(158,186,212,0.34); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; filter: blur(5px); }
/* the fissure itself: opaque near-black, the darkest thing on the page */
.pc-void { fill: #04060b; stroke: none; }
.pc-void-core { fill: #010104; stroke: none; filter: blur(1.5px); }
/* branch fractures — faint dark capillaries with the same dim cool ghost */
.pc-shard-glow { fill: none; stroke: rgba(150,178,205,0.1); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; filter: blur(3.5px); }
.pc-shard-core { fill: none; stroke: rgba(150,178,205,0.28); stroke-width: 0.8; stroke-linecap: round; stroke-linejoin: round; filter: blur(0.6px); opacity: 0.6; }
/* the weaker dust surfacing along the extended crack — a viewport-sized canvas
   that only emits along whatever slice of the crack is on screen, so one small
   framebuffer covers a crack thousands of pixels tall (see page-crack.ts) */
.page-crack-dust { position: fixed; inset: 0; z-index: 1; pointer-events: none; }
.no-js .page-crack { display: none; }
.no-js .page-crack-dust { display: none; }
@media (prefers-reduced-motion: reduce) { .pc-lip-bloom { filter: blur(3px); } .page-crack-dust { display: none; } }
