/* ============================================================================
   frz.codes — design tokens
   ----------------------------------------------------------------------------
   This file is the design system. Everything else in the CSS consumes these
   custom properties and defines no raw colour, size or duration of its own.
   If a value is worth reusing, it belongs here; if it appears as a literal in
   site.css, that is a bug.

   Direction: "Halo" — the cluster is the light source. A near-black ground lit
   by a slow drifting mesh that runs warm (amber) where the hero ring sits and
   cools to violet and cyan away from it.

   Colour semantics are load-bearing, not decorative:
     --accent   amber   leader state · every link, focus ring and primary action
     --accent-2 cyan    follower state · secondary counts and markers
     --weather  violet  atmosphere only — never applied to text

   Theme resolves in three states, in this order:
     1. :root                                  dark (the default)
     2. prefers-color-scheme: light            light, unless the reader forced dark
     3. [data-theme] on <html>                 the reader's explicit choice wins
   ============================================================================ */

/* ---------------------------------------------------------------- typefaces */

@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 300 800;          /* variable: one file covers the range */
  font-display: swap;
  src: url("../fonts/unbounded-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: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/instrument-sans-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: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/instrument-sans-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;
}
@font-face {
  font-family: "Instrument Sans";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/instrument-sans-italic-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: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-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;
}

/* -------------------------------------------------- animatable custom props */
/* Registered so they can be interpolated; a plain custom property cannot be. */
@property --sweep-x { syntax: "<percentage>"; initial-value: 120%; inherits: false; }

/* ================================================================== tokens */

:root {
  /* ---- colour: dark, the default -------------------------------------- */
  --bg:          #0a0a12;
  --bg-deep:     #06060c;   /* code blocks, wells — recedes below the ground */
  --glass:       rgba(255, 255, 255, .045);
  --glass-strong:rgba(255, 255, 255, .08);
  --glass-edge:  rgba(237, 238, 245, .11);
  --img-edge:    rgba(255, 255, 255, .10);   /* neutral by design: never tint an image edge */
  --line:        #262636;
  --line-soft:   #181824;
  --text:        #edeef5;
  --muted:       #9a9db3;

  --accent:      #ffc24d;   /* leader   · 12.3:1 on --bg */
  --accent-ink:  #0a0a12;   /* text placed on top of a filled accent surface */
  --accent-2:    #5fd4f2;   /* follower · 11.4:1 on --bg */
  --weather:     #a99bff;   /* atmosphere only */

  /* code, mapped onto the palette rather than a chroma preset, so highlighting
     follows the theme instead of baking one in */
  --code-keyword: #ff9ec7;
  --code-string:  #9ee6a4;
  --code-comment: #7c8195;
  --code-number:  #ffc24d;
  --code-func:    #7fd4ff;
  --code-type:    #c4b5ff;

  --halo-opacity: .42;
  --halo-blend:   plus-lighter;
  --grid-opacity: .5;

  /* ---- type ------------------------------------------------------------ */
  --font-display: "Unbounded", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-body:    "Instrument Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Fluid from 320px to ~1400px. No breakpoint stepping anywhere. */
  --t-mono:  0.75rem;
  --t-small: 0.875rem;
  --t-body:  clamp(1rem,     0.96rem + 0.20vw, 1.0625rem);
  --t-lead:  clamp(1.125rem, 1.03rem + 0.47vw, 1.375rem);
  --t-title: 1.1rem;   /* a record's company or talk name: between body and h3 */
  --t-h3:    clamp(1.15rem,  1.05rem + 0.50vw, 1.4rem);
  --t-h2:    clamp(1.6rem,   1.30rem + 1.40vw, 2.5rem);
  --t-h1:    clamp(2.25rem,  1.25rem + 4.40vw, 5rem);

  --lh-tight: 1;
  --lh-head:  1.08;
  --lh-body:  1.65;
  --lh-lead:  1.5;

  --ls-display: -.05em;
  --ls-head:    -.035em;
  --ls-label:   .15em;    /* uppercase mono labels need the air */

  --t-code-inline: .9em;  /* em-relative on purpose: inline code tracks its sentence */

  --measure: 68ch;        /* reading width — prose never exceeds this */

  /* ---- space: a 4px base, named by multiple ---------------------------- */
  --sp-1:  0.25rem;  --sp-2:  0.5rem;   --sp-3:  0.75rem;
  --sp-4:  1rem;     --sp-5:  1.25rem;  --sp-6:  1.5rem;
  --sp-8:  2rem;     --sp-10: 2.5rem;   --sp-12: 3rem;
  --sp-16: 4rem;     --sp-20: 5rem;

  --shell:      1140px;                 /* max content width */
  --gutter:     1.25rem;                /* page edge padding */
  --section-y:  clamp(2.5rem, 5.5vw, 4.5rem);

  /* ---- shape ----------------------------------------------------------- */
  --radius:      10px;
  --radius-sm:   8px;
  --radius-pill: 999px;
  --hairline:    1px;

  /* ---- motion ---------------------------------------------------------- */
  --ease:      cubic-bezier(.2, .7, .2, 1);
  --dur-fast:  .2s;
  --dur:       .25s;
  --dur-slow:  .4s;

  /* Ambient loops. Long and prime-ish so they never visibly sync up. */
  --dur-halo-a:   38s;
  --dur-halo-b:   47s;
  --dur-halo-c:   53s;
  --dur-sweep:    11s;

  --z-nav: 60;

  /* lets height transitions run to and from `auto`, which is what makes the
     expanding résumé and talk entries animate rather than snap */
  interpolate-size: allow-keywords;

  color-scheme: dark;
}

/* ---- colour: light ---------------------------------------------------- */
/* Defined once as a token block and applied twice — once for readers whose OS
   says light and who have not overridden it, once for an explicit choice — so
   the toggle wins in both directions and no component ever styles itself
   inside a media query. */

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:          #f6f5fa;
    --bg-deep:     #eceaf4;
    --glass:       rgba(255, 255, 255, .66);
    --glass-strong:rgba(255, 255, 255, .88);
    --glass-edge:  rgba(18, 19, 28, .11);
    --img-edge:    rgba(0, 0, 0, .10);
    --line:        #d8d6e4;
    --line-soft:   #e7e5ef;
    --text:        #12131c;
    --muted:       #535468;

    --accent:      #c2410c;   /* burnt orange: 4.8:1 on paper, holds white text */
    --accent-ink:  #ffffff;
    --accent-2:    #0d6b88;
    --weather:     #5334cc;

    --code-keyword: #a1246b;
    --code-string:  #16643a;
    --code-comment: #5c6172;
    --code-number:  #8a5c00;
    --code-func:    #0b5f87;
    --code-type:    #5334cc;

    --halo-opacity: .34;
    --halo-blend:   multiply;
    --grid-opacity: .7;

    color-scheme: light;
  }
}

:root[data-theme="light"] {
  --bg:          #f6f5fa;
  --bg-deep:     #eceaf4;
  --glass:       rgba(255, 255, 255, .66);
  --glass-strong:rgba(255, 255, 255, .88);
  --glass-edge:  rgba(18, 19, 28, .11);
  --img-edge:    rgba(0, 0, 0, .10);
  --line:        #d8d6e4;
  --line-soft:   #e7e5ef;
  --text:        #12131c;
  --muted:       #535468;

  --accent:      #c2410c;
  --accent-ink:  #ffffff;
  --accent-2:    #0d6b88;
  --weather:     #5334cc;

  --code-keyword: #a1246b;
  --code-string:  #16643a;
  --code-comment: #5c6172;
  --code-number:  #8a5c00;
  --code-func:    #0b5f87;
  --code-type:    #5334cc;

  --halo-opacity: .34;
  --halo-blend:   multiply;
  --grid-opacity: .7;

  color-scheme: light;
}

/* ---- motion preference ------------------------------------------------- */
/* Ambient loops are driven by tokens, so honouring the preference is a matter
   of zeroing them here rather than hunting animations across the stylesheet.
   site.css still disables the keyframes themselves; this is the belt. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: .001ms;
    --dur:      .001ms;
    --dur-slow: .001ms;
  }
}
