/* The whole design language. Nothing in the markup or the JS sets a value that
   is not here. Everything on the page derives from this file. */
/* Tells the browser this page themes itself. Without it Chrome's forced dark
   mode, and some extensions, re-colour surfaces on top of ours, which is how
   you get dark cards sitting on a light page. */
/* ONE TYPEFACE, THE SAME ONE EVERYWHERE. [@maaz · 2026-08-23] The primary face
   was a system stack, which is not a typeface but an instruction to use
   whatever the machine has: San Francisco on a Mac, Segoe UI on Windows,
   Roboto on Android. Three visitors, three different pages, and the one
   element on a portfolio about product judgment that nobody had chosen.

   It is Inter because Inter was drawn to the same brief as the face he was
   already looking at, so the page he approved is the page that ships; what
   changes is that everyone else now sees it too. **Apple's own face could not
   be used**: SF Pro is licensed for Apple platforms and may not be served to
   anything else, which is the only reason this was not a five minute fix.

   Self-hosted, two files, 133 KB for the whole weight axis from 100 to 900, so
   the site still has no build step and no request to anyone else's server. The
   old stack is kept behind it as the fallback, which means a failed font
   request degrades to exactly what the site looked like yesterday rather than
   to a serif. `swap` for the same reason: text is readable from the first
   paint and reflows once, rather than being invisible while a font loads. */
@font-face{
  font-family:'Inter';
  font-style:normal;
  font-weight:100 900;
  font-display:swap;
  src:url('../assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Inter';
  font-style:normal;
  font-weight:100 900;
  font-display:swap;
  src:url('../assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root{
  color-scheme:light;
  /* surfaces */
  --bg:#E9ECEE; --bg-lift:#F3F5F6;
  --panel:#FCFDFD; --panel-2:#F6F8F9; --stage:#DEE3E6;
  /* Three inks, and all three have to be READABLE. --ink-3 was #98A1A8, which
     measures 2.21:1 on --bg where AA needs 4.5 — it carried the scroll
     instruction, the percentage counter, the subtitle under his name and the
     chat card header, so the least visible text on the page was the sentence
     the whole interaction depends on. Darkening it alone lands it at 5.01
     against --ink-2's 5.09, which is the same grey twice and no ramp at all,
     so --ink-2 moves with it. Measured against every ground a quiet label
     actually sits on, --stage included, not just against --bg.
     On --bg: 15.05 · 7.74 · 5.01. Worst ground: 13.8 · 7.10 · 4.60.
     The palette's own cast is kept exactly — red nine below the middle
     channel, blue seven above it — so these are the same greys, lower. */
  --ink:#14181B; --ink-2:#404950; --ink-3:#5C656C; --hair:#D6DBDF;
  --scene-ink:20,24,27;          /* the canvas draws with this */
  --scene-lift:120,150,175;

  /* one type scale, used everywhere. no size exists outside it. */
  --t1:12px;   /* labels, captions */
  --t2:14px;   /* small copy, chips */
  --t3:16px;   /* body */
  --t4:19px;   /* card titles */
  --t5:26px;   /* sub headings */
  --t6:38px;   /* section headings */
  --t7:56px;   /* display */
  --lh-tight:1.06; --lh-mid:1.3; --lh-body:1.55;

  /* one spacing scale */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --s7:48px; --s8:64px; --s9:96px; --s10:128px;

  /* one control system */
  --ctl-h:44px; --ctl-pad:20px;
  --r-panel:18px; --r-ctl:12px; --r-pill:999px;
  --lift:0 1px 1px rgba(20,24,27,.03), 0 6px 20px rgba(20,24,27,.06);
  --lift-2:0 1px 1px rgba(20,24,27,.04), 0 16px 48px rgba(20,24,27,.10);

  --f:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Helvetica Neue',Arial,sans-serif;
  --m:ui-monospace,'SF Mono','JetBrains Mono',Menlo,monospace;
  --ease:cubic-bezier(.22,1,.36,1);
  --ease-ui:cubic-bezier(.2,0,0,1);
  --max:1560px;
  /* set from script per element; declared so the lint can tell a runtime
     slot from a typo */
  --nudge:0px;                /* label pushed clear of another label */
  --len:0;                    /* a leader line's length, for drawing it in */
  --drop:120%;                /* which side of its dot a label sits on */
  --rail-w:min(360px,26vw);   /* the chat rail, needed by the station too */
  --dock:min(190px,22vw);    /* the parked core. The chat rail sits under it */
  --bar-h:64px;               /* the top bar. Stations clear it by this plus --s7 */
  --icon:18px;                /* one icon size, everywhere */
}

/* Dark is the same system with the surfaces inverted. No new values, no new
   rules, only these tokens change. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#0F1417; --bg-lift:#151B1F;
  --panel:#181F23; --panel-2:#141A1E; --stage:#101619;
  /* --ink-3 was #6C767B: 3.99 on --bg and 3.59 on --panel, so dark failed AA
     as well — the audit only measured light. --ink-2 already clears at 8.10
     and does not move. On --bg: 15.9 · 8.10 · 5.05. */
  --ink:#EDF1F2; --ink-2:#A3ADB2; --ink-3:#7D878C; --hair:#283035;
  --scene-ink:237,241,242;
  --scene-lift:150,185,210;
  --lift:0 1px 1px rgba(0,0,0,.30), 0 6px 20px rgba(0,0,0,.34);
  --lift-2:0 1px 1px rgba(0,0,0,.34), 0 16px 48px rgba(0,0,0,.46);
}
