/* Median — the app's material, for the web.
 *
 * Every value here is read from the iOS app, not invented for the site:
 * docs/design/MEDIAN_DESIGN_SYSTEM.md §1 and MedianMaterial.swift / MedianGround.
 * If the app's material changes, this file follows it. */

@font-face {
  font-family: "Geist";
  src: url("fonts/Geist-Regular.otf") format("opentype");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Geist";
  src: url("fonts/Geist-Medium.otf") format("opentype");
  font-weight: 500; font-style: normal; font-display: swap;
}

:root {
  /* §1.1 ground: greyscale 5/255, never pure black (OLED smear). */
  --ground: #050505;
  /* §1.2 the one container. */
  --surface: #161616;
  --edge: rgba(255, 255, 255, 0.14);
  /* §1.4 colour, contrast verified against #050505. */
  --primary: #F2F2F2;    /* ~19:1, off-white to avoid halation */
  --secondary: #8A8A8A;  /* 5.9:1 */
  --tertiary: #767676;   /* 4.8:1; never the old #5E5E5E */
  /* The resting key light, rgb(0.84, 0.89, 1.0). */
  --cool: 214, 227, 255;

  --margin: 32px;
  --measure: 34rem;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }
html { background: var(--ground); color-scheme: dark; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--ground);
  color: var(--primary);
  font-family: "Geist", ui-sans-serif, -apple-system, "Helvetica Neue", Arial, sans-serif;
  font-weight: 400;
  font-size: 17px;          /* §1.3 Body */
  line-height: 24px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  position: relative;
  overflow-x: hidden;
}
/* NOTHING SWIPES SIDEWAYS. iOS Safari ignores overflow-x: hidden on body for
 * touch scrolling, so anything that bleeds past the screen edge (a tilted phone,
 * a glow) let the whole page pan. clip stops it without creating a scroll
 * container, so the sticky nav keeps working. */
html, body, .page { overflow-x: clip; }

/* §1.1 THE RESTING GROUND, layer for layer as MedianGround draws it: a key light
 * upper right, a softer second source left, a wash along the top, and a
 * vignette. Fixed to the viewport so it reads as the light in a room, not a
 * picture that scrolls away. */
.ground {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(900px circle at 63% 19%,
      rgba(var(--cool), 0.125) 0%, rgba(var(--cool), 0.036) 45%, transparent 100%),
    radial-gradient(730px circle at 16% 40%,
      rgba(var(--cool), 0.050) 0%, transparent 100%),
    linear-gradient(to bottom, rgba(var(--cool), 0.020) 0%, transparent 58%),
    var(--ground);
}
.ground::after {
  /* The vignette: clear in the middle, 30% then 62% black at the edges. */
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(1400px circle at 50% 42%,
    transparent 33%, rgba(0, 0, 0, 0.30) 66%, rgba(0, 0, 0, 0.62) 100%);
}

/* §1.1 GRAIN OVER EVERYTHING, ~3%. Non-negotiable in the app, and for the same
 * reason here: it is the surface, and it breaks the banding a shallow
 * near-black gradient always produces on a screen. Fine 1px noise, added. */
/* A PRE-RENDERED TILE, NOT A FILTER. The grain was an SVG feTurbulence filter,
 * and on a long page at phone size the browser painted the whole page black once
 * scrolled; replacing the filter with a flat fill made it render, so the filter
 * was the fault. assets/img/grain.png is the same material MedianGrain draws:
 * about 1 pixel in 13 lit, white at 35-100% alpha, seeded so it never shimmers.
 * At 3.5% layer opacity each lit pixel lands at 1-3.5% white, as in the app. */
.grain {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  opacity: 0.035;
  background-image: url("img/grain.png");
  background-size: 256px 256px;
  image-rendering: pixelated;
}

.page { position: relative; z-index: 2; }

/* §1.5 Four columns, 32pt margins. Nothing is centred: left-anchored,
 * deliberately imbalanced. */
.frame {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--margin);
}

/* §1.3 TYPE. Two weights only; weight and case carry the hierarchy. */
.kicker {
  font-size: 11px; line-height: 16px; font-weight: 500;
  letter-spacing: 1.3px; text-transform: uppercase;
  color: var(--tertiary);
}
.caption { font-size: 13px; line-height: 20px; color: var(--tertiary); }
.value   { font-size: 22px; line-height: 28px; font-weight: 500; letter-spacing: -0.3px; }
.display { font-size: 34px; line-height: 40px; font-weight: 500; letter-spacing: -0.6px; margin-left: -1.3px; }
.hero    { font-size: 42px; line-height: 48px; font-weight: 500; letter-spacing: -0.9px; margin-left: -1.6px; }
.statement {
  font-size: clamp(48px, 9vw, 92px);
  line-height: 1.02; font-weight: 500;
  letter-spacing: -0.028em;
  margin-left: -0.03em;     /* optical margin: the capital's edge on the margin */
}
.secondary { color: var(--secondary); }
.tertiary  { color: var(--tertiary); }
.regular   { font-weight: 400; }

a { color: inherit; text-decoration: none; }
a.link {
  color: var(--primary);
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size 200ms var(--ease-out), color 200ms var(--ease-out);
}
a.link:hover { color: #fff; }

/* §1.2 THE ONE CONTAINER: a real step above the ground, a light-catch on the
 * TOP EDGE ONLY fading to nothing at both ends, and a shadow that pools the
 * ground around it. Never a border. */
.surface {
  position: relative;
  background: var(--surface);
  border-radius: 22px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.60);
}
.surface::before {
  content: ""; position: absolute; left: 22px; right: 22px; top: 0; height: 1px;
  background: linear-gradient(to right, transparent, var(--edge) 30%, var(--edge) 70%, transparent);
}

/* §1.6 MOTION: enter ease-out, groups staggered, never in unison. */
@media (prefers-reduced-motion: no-preference) {
  .arrive { opacity: 0; transform: translateY(11px); animation: arrive 700ms var(--ease-out) forwards; }
  .arrive:nth-child(2) { animation-delay: 70ms; }
  .arrive:nth-child(3) { animation-delay: 140ms; }
  .arrive:nth-child(4) { animation-delay: 210ms; }
  .arrive:nth-child(5) { animation-delay: 280ms; }
  @keyframes arrive { to { opacity: 1; transform: none; } }
}

::selection { background: rgba(var(--cool), 0.28); color: #fff; }
:focus-visible { outline: 2px solid rgba(var(--cool), 0.7); outline-offset: 3px; border-radius: 4px; }
