/* ===========================================================================
   VAULT  —  base: fonts, tokens, reset, type, containers
   ---------------------------------------------------------------------------
   ONE DARK CANVAS, LIT RATHER THAN DIVIDED.

   The version before this alternated two materials — dark green "felt" and
   off-white "paper" — and swapped between them to separate sections. It read
   as a magazine. A shop reads better as one continuous surface with things
   raised out of it, so sections are now separated by LIGHT (an ambient glow,
   a gradient hairline, a change of elevation) rather than by a change of
   material. Nothing on the page flips to a white background any more.

   GOLD IS THE ACCENT AND IT IS RARE. It marks exactly three things: the buy,
   the current position, and a live number. Everything else is one of four
   greys. An accent used on everything marks nothing.

   TYPE IS ONE FAMILY. Inter, variable, 48 KB, served from this domain — the
   headings are the same face as the body at 800 with the tracking pulled in,
   which is what modern product pages do and what the old Impact fallback
   could never look like. Uppercase is for labels and buttons only; headlines
   are sentence case, because a page that shouts every heading has no way to
   emphasise the one that matters.
   =========================================================================== */

@font-face {
  font-family: 'InterVar';
  src: url('/assets/fonts/inter-var-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrainsMonoVar';
  src: url('/assets/fonts/jetbrains-mono-var-latin.woff2') format('woff2');
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ---- ground and the things raised out of it ---- */
  --bg:        #0a0b0d;
  --bg-lift:   #0e1013;   /* a band that needs to sit forward of the page */
  --bg-sink:   #070809;   /* and one that needs to sit behind it */
  --surf:      #131519;   /* a card */
  --surf-2:    #191c21;   /* a card under the cursor */
  --line:      rgba(255, 255, 255, .075);
  --line-2:    rgba(255, 255, 255, .14);

  /* ---- text: four greys, and that is the whole set ---- */
  --tx:        #f2f4f7;
  --tx-2:      #a7aeb9;
  --tx-3:      #767d88;
  --tx-4:      #4d545e;

  /* ---- gold: the accent, and the only gradient on the site ---- */
  --gold:      #e0a83c;
  --gold-lit:  #f7cd6b;
  --gold-dim:  #8d6a24;
  --gold-wash: rgba(224, 168, 60, .12);
  --gold-grad: linear-gradient(135deg, #f7cd6b 0%, #e0a83c 45%, #c88a24 100%);

  /* ---- the crest's red, kept for danger and for the mark ---- */
  --red:       #d63a34;
  --red-lit:   #ef5a52;
  --green:     #45c07a;

  --font:    'InterVar', 'Inter', 'Segoe UI Variable Text', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --mono:    'JetBrainsMonoVar', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  /* ONE RADIUS SCALE. Squared corners were an in-game rule carried onto the
     web where it does not apply; on a storefront they read as unfinished. */
  --r1: 8px;
  --r2: 12px;
  --r3: 18px;
  --r4: 26px;
  --rp: 999px;

  --sh-1: 0 1px 2px rgba(0, 0, 0, .5);
  --sh-2: 0 14px 40px -14px rgba(0, 0, 0, .8);
  --sh-3: 0 44px 90px -28px rgba(0, 0, 0, .9);
  --sh-gold: 0 12px 34px -12px rgba(224, 168, 60, .5);

  --ease: cubic-bezier(.22, 1, .36, 1);
  --snap: cubic-bezier(.34, 1.4, .64, 1);

  /* THE SPACING SCALE. Every gap and pad on this site is one of these. */
  --s1: 6px;  --s2: 12px; --s3: 18px; --s4: 26px;
  --s5: 40px; --s6: 64px; --s7: 96px; --s8: 136px;

  --pad: clamp(20px, 4.5vw, 56px);
  --col: 1200px;
  --bar-h: 66px;
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

/* overflow-x: `clip`, on html, and not `hidden` on body. `hidden` promotes
   body into its own scroll container, so window.scrollY stays 0 forever and
   every scroll-driven thing here silently stops working. */
html {
  overflow-x: clip;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--bar-h) + var(--s4));
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--bg);
  color: var(--tx-2);
  font-family: var(--font);
  font-size: 16.5px;
  line-height: 1.65;
  font-feature-settings: 'cv11' 1, 'ss01' 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

/* THE GRAIN. A fixed, non-interactive film of noise over the whole page at
   3.5% — the one thing that stops large flat dark areas from banding on a
   cheap panel, and it costs a single generated texture with no request. */
body::after {
  content: '';
  position: fixed; inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

img, svg, video { display: block; max-width: 100%; }
/* An <img> carries width/height so the box is reserved before the file lands.
   Without `height: auto` the width scales to the column and the height stays
   at the attribute, which is what squashes art into a letterbox. */
img { height: auto; }
svg.i { width: 1em; height: 1em; fill: currentColor; flex: none; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }

::selection { background: var(--gold); color: #14100a; }

:focus-visible { outline: 2px solid var(--gold-lit); outline-offset: 3px; border-radius: 3px; }

.skip {
  position: fixed; top: 10px; left: 10px; z-index: 200;
  padding: 12px 20px; border-radius: var(--r1);
  background: var(--gold); color: #14100a; font-weight: 700;
  transform: translateY(-200%);
  transition: transform .2s var(--ease);
}
.skip:focus { transform: none; }

/* ------------------------------------------------------------- typography */

h1, h2, h3, h4 {
  color: var(--tx);
  font-weight: 800;
  line-height: 1.06;
  letter-spacing: -.028em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.5rem, 5.6vw, 4.1rem); letter-spacing: -.038em; line-height: 1.02; }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.85rem); letter-spacing: -.032em; }
h3 { font-size: 1.12rem; letter-spacing: -.018em; }
h4 { font-size: .98rem; }

p { text-wrap: pretty; }
strong, b { color: var(--tx); font-weight: 650; }

/* The paragraph under a heading. Big enough to read rather than scan, and
   held near 58 characters so the eye finds the next line without hunting. */
.lead {
  font-size: clamp(1.02rem, 1.35vw, 1.18rem);
  line-height: 1.6;
  color: var(--tx-2);
  max-width: 58ch;
}

/* A second paragraph after a lead. The reset zeroes every p margin, so the two
   ran together as one wall with no break between them. Only this pairing needs
   the gap - a lead followed by a .cta or a list already has its own spacing. */
.lead + p { margin-top: var(--s4, 18px); max-width: 58ch; color: var(--tx-3); }

/* Small caps are a seasoning: .14em of tracking, never below 12px. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: .76rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--gold);
}
.eyebrow::before {
  content: ''; width: 18px; height: 1px; background: currentColor; opacity: .6;
}
.eyebrow.plain::before { display: none; }

.mono { font-family: var(--mono); font-feature-settings: normal; }
.num  { font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- container */

.shell { width: 100%; max-width: var(--col); margin: 0 auto; padding: 0 var(--pad); }
.shell-narrow { max-width: 860px; }

/* ONE SECTION RHYTHM. Every band is the same air top and bottom, so the page
   has a beat rather than a series of guesses. */
.sec { position: relative; padding: var(--s8) 0; }
.sec-sm { padding: var(--s6) 0; }
.sec-t0 { padding-top: 0; }
.sec-b0 { padding-bottom: 0; }
@media (max-width: 760px) { .sec { padding: var(--s7) 0; } }

.lift { background: var(--bg-lift); }
.sink { background: var(--bg-sink); }

/* The seam between two bands: a hairline that fades out at both ends, so the
   page is divided by light rather than by a ruled line across it. */
.seam { position: relative; }
.seam::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-2) 22%, var(--line-2) 78%, transparent);
}

/* AMBIENT LIGHT. A soft blur of gold sitting behind a section, clipped by it.
   This is what separates the hero from the band under it. */
.glow { position: relative; overflow: clip; isolation: isolate; }
.glow::before {
  content: ''; position: absolute; z-index: -1;
  left: 50%; top: var(--glow-y, -30%);
  width: min(1100px, 130vw); aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle at center,
              rgba(224, 168, 60, var(--glow-a, .14)) 0%,
              rgba(224, 168, 60, .05) 32%, transparent 62%);
  pointer-events: none;
}

/* A field of dots behind a hero, masked to fade out.

   It was a 64px grid of squares, which is the background every dark template
   ships with and it read as graph paper behind the headline. Dots at 24px are
   a texture you feel rather than a pattern you count. */
.dots::after {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, .17) 1px, transparent 1px);
  background-size: 24px 24px;
  -webkit-mask-image: radial-gradient(ellipse 78% 62% at 50% 12%, #000 4%, transparent 72%);
          mask-image: radial-gradient(ellipse 78% 62% at 50% 12%, #000 4%, transparent 72%);
}

.head { max-width: 66ch; margin-bottom: var(--s6); }
.head h2 { margin-top: var(--s3); }
.head .lead { margin-top: var(--s3); }
.head.mid { margin-left: auto; margin-right: auto; text-align: center; }
.head.mid .lead { margin-left: auto; margin-right: auto; }
.head.mid .eyebrow::before { display: none; }

/* ---------------------------------------------------- reveal on scroll ----
   THE PAGE IS VISIBLE UNTIL PROVEN OTHERWISE. `.rise` hides nothing until JS
   has put `js-rise` on <html>, which it only does after confirming an
   IntersectionObserver exists — and site.js shows everything anyway if the
   observer has not reported inside two seconds. An observer is driven by the
   same rendering a page may not be doing (an embed, a background tab, a
   preview pane), so it may reveal content and must never be the only thing
   standing between a reader and it. */
.js-rise .rise {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
.js-rise .rise.in { opacity: 1; transform: none; }
.js-rise .d1 { transition-delay: .07s; }
.js-rise .d2 { transition-delay: .14s; }
.js-rise .d3 { transition-delay: .21s; }
.js-rise .d4 { transition-delay: .28s; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto; }
  .js-rise .rise { opacity: 1; transform: none; }
}
