/* ============================================================
   01 — DESIGN TOKENS
   Single source of truth. Change a value here, the whole
   site follows. Nothing below this file hardcodes a color,
   size, radius or easing.
   ============================================================ */

:root {
  /* ---------- COLOR ----------

     CHANNELS FIRST, THEN EVERYTHING ELSE FROM THEM.

     The project had thirty-one hardcoded rgba() values spread over
     nine files, and almost all of them were one of two colours at
     some alpha: rgba(215, 226, 234, a) is the ink, rgba(12, 12, 12, a)
     is the surface. Written that way a theme swap means finding and
     rewriting every one of them.

     Holding the channels as bare triplets and composing with
     `rgb(... / a)` means the whole set re-bases from four numbers,
     and a value that was 15% ink stays 15% ink in either theme
     instead of being re-guessed by hand.
     ------------------------------------------------------------ */

  color-scheme: dark;

  --rgb-ink:     215 226 234;   /* foreground: text, borders, tints */
  --rgb-surface:  12  12  12;   /* the page itself                  */
  --rgb-raised:   20  20  22;   /* cards and panels above it        */
  --rgb-shadow:    0   0   0;
  --rgb-shine:   255 255 255;   /* highlight sweeps                 */

  /* surfaces */
  --c-bg:            rgb(var(--rgb-surface));
  --c-bg-elevated:   #141416;   /* cards on dark */
  --c-surface-light: #FFFFFF;   /* skip-link chip, ghost button */

  /* text */
  --c-text:          rgb(var(--rgb-ink));
  --c-text-dim:      rgb(var(--rgb-ink) / 0.60);
  --c-text-invert:   rgb(var(--rgb-surface));
  /* One step past --c-text, for the hover state of something that
     is already at full text colour. Brighter than the ink on dark,
     darker than it on light — so it has to be its own token rather
     than a hardcoded white. */
  --c-text-strong:   #FFFFFF;

  /* borders */
  --c-border:        rgb(var(--rgb-ink) / 0.15);
  --c-border-strong: rgb(var(--rgb-ink));

  /* ---- over footage -------------------------------------------
     The hero and the features panel sit on dark video. These do NOT
     follow the theme, because the thing behind them does not: a
     white scrim over that footage washes it out (measured: 6% of
     the original colour saturation retained, against 54% for the
     dark one) and light-mode ink on it would be unreadable.

     So those two sections are treated as media panels — dark in
     both themes, the way a photograph stays a photograph. Every
     other surface on the site flips.
     ------------------------------------------------------------ */
  --rgb-media:      12  12  12;    /* scrims laid over footage */
  --rgb-on-media:  215 226 234;    /* borders and tints on top of it */
  --c-on-media:      #D7E2EA;
  --c-on-media-dim:  rgba(215, 226, 234, 0.60);
  /* Solid, not translucent. Secondary copy over the features video
     cannot use alpha: blending against moving footage caps the
     contrast it can reach. The media-panel block below pins this
     value for the sections that actually sit on footage; elsewhere
     it follows the theme, because it is also the prose colour on
     about.html, which has no video behind it at all. */
  --c-on-media-soft: #A8B4BE;
  --c-text-soft:     #A8B4BE;

  /* heading gradient — the signature look */
  --grad-heading: linear-gradient(180deg, #646973 0%, #BBCCD7 100%);

  /* The hero h1 sits on the footage too, so this one never flips
     either — see --c-on-media above.

     Measured against #0C0C0C, the darkest stop (#8E9AA5) still
     lands at 6.8:1, so the sentence stays legible over the opening
     frames without leaning on the scrim. */
  --grad-slogan: linear-gradient(172deg,
                   #FFFFFF  0%,
                   #DCE6ED 30%,
                   #8E9AA5 52%,
                   #EDF3F7 74%,
                   #FFFFFF 100%);

  /* Travelling sheen and depth for the h1. Declared here rather
     than inline in hero.css so the light theme can flip them from
     one place — see the hero override block below. */

  --hero-shine: rgba(255, 255, 255, 0.92);
  --hero-slogan-filter:
    drop-shadow(0 0 30px rgba(190, 214, 230, 0.20))
    drop-shadow(0 6px 16px rgba(0, 0, 0, 0.55));

  /* CTA gradient. Reads on either theme, so it is shared. */
  --grad-cta: linear-gradient(123deg,
                #18011F  7%,
                #B600A8 37%,
                #7621B0 72%,
                #BE4C00 100%);
  --shadow-cta:
      0 4px 4px rgba(181, 1, 167, 0.25),
      4px 4px 12px #7721B1 inset;

  /* badges — carried over from the Fartak sample, dark variants */
  --c-badge-hot-bg:  #892828;   --c-badge-hot-fg:  #EF999F;
  --c-badge-free-bg: #2A6E39;   --c-badge-free-fg: #A7C8AE;

  /* The showcase card and the page were the same colour, which on
     dark is deliberate — the 2px bright border is what draws it. In
     the light theme that left a panel with no fill at all, so the
     surface is named here and re-pointed below. */
  --c-panel:        var(--c-bg);
  --c-panel-border: var(--c-border-strong);
  --bw-panel:       2px;

  --c-card-border:  var(--c-border);
  --bw-card:        1px;

  /* Two states, so the shadow can grow as the card lifts instead of
     appearing from nothing — see the note in grid.css. */
  --shadow-card-rest: 0 4px 14px rgb(var(--rgb-shadow) / 0.30);
  --shadow-card:      0 24px 60px rgb(var(--rgb-shadow) / 0.45);
  --shadow-panel:     0 10px 30px rgb(var(--rgb-shadow) / 0.35);

  /* The footer is the bottom-most layer, so its shadow is INSET
     along the top edge — the page casting down onto it, not the
     footer casting onto something below. There is nothing below.

     None on dark: an inset dark shadow against #0C0C0C has nothing
     to darken, and the existing hairline already does the work
     there. Set it here if it is ever wanted on dark too. */
  --shadow-footer: none;

  /* ---- hand loader (luxury obsidian & amethyst crystal glass) --- */
  --hand-palm-bg:          linear-gradient(155deg, rgba(215, 65, 235, 0.38) 0%, rgba(139, 47, 201, 0.48) 45%, rgba(24, 1, 31, 0.90) 100%);
  --hand-palm-rim:         rgba(215, 65, 235, 0.75);
  --hand-palm-side:        rgba(15, 6, 25, 0.35);
  --hand-finger-face:      linear-gradient(165deg, rgba(255, 255, 255, 0.45) 0%, rgba(215, 65, 235, 0.65) 28%, rgba(124, 58, 237, 0.55) 75%, rgba(24, 1, 31, 0.75) 100%);
  --hand-finger-side:      rgba(50, 15, 75, 0.30);
  --hand-outline:          rgba(255, 255, 255, 0.30);
  --hand-border-specular:  #ffffff;
  --hand-shadow:           rgba(0, 0, 0, 0.75);
  --hand-ambient-glow:     rgba(182, 0, 168, 0.35);
  --hand-text-dim:         rgba(225, 232, 240, 0.48);
  --hand-text-pop:         #ffffff;
  --hand-text-glow:        rgba(215, 65, 235, 0.85);

  /* The cinematic is INSET on a page-coloured ground, with real
     corners, instead of being faded into the page.

     The fade was tried first, tuned hard, and abandoned. Sampling
     the colours it actually produced showed why it could never
     work: blending the page colour over near-black footage passes
     through neutral grey, and the transition measured

         12%  rgb(190,192,193)   saturation 0.024
         16%  rgb(142,144,145)              0.013
         20%  rgb( 91, 93, 94)              0.016
         24%  rgb( 49, 51, 52)              0.030

     — a dead grey ramp across a third of the panel, which on a
     white page reads as a smudge rather than a dissolve. That is
     inherent to alpha compositing, not to the curve: two rounds of
     smoothing the ramp (linear -> smootherstep, 2 stops -> 48)
     improved its geometry and changed none of that, because the
     problem was never the shape.

     A crisp edge has no intermediate values at all, so there is no
     grey to be muddy. It also states the theme change more loudly
     than a fade did: the whole panel visibly detaches from the page.

     Zero on dark, so the hero stays full-bleed there and nothing
     about the dark theme moves. */
  --hero-inset:  0px;
  --hero-radius: 0px;

  /* ---- the hero panel ------------------------------------------
     The footage itself cannot follow the theme — measured, it is a
     near-black studio render with mean luminance 0.012-0.053 and no
     headroom to lift (see ROADMAP). So the theme change is carried
     by how the footage MEETS the page instead. */

  /* Was briefly its own token, when the cue sat inside a white
     fade. With the inset panel it is back on footage in both
     themes, so it takes the media ink like everything else there.
     Kept named because the cue is the one hero element whose
     background is set by the layout rather than by the video. */
  --c-hero-cue: var(--c-on-media-dim);

  /* ---------- TYPOGRAPHY ---------- */

  --font-main: 'Vazirmatn', system-ui, sans-serif;

  /* one family, weight carries the hierarchy (300 -> 900) */
  --fw-light:  300;
  --fw-normal: 400;
  --fw-medium: 500;
  --fw-bold:   700;
  --fw-black:  900;

  /* fluid scale — a measured modular scale
     ------------------------------------------------------------
     Audited at 1440px, the page was rendering ELEVEN distinct text
     sizes, and the trouble was the shape of the set rather than any
     one value:

         80 -> 66   ratio 1.21
         66 -> 32   ratio 2.06   a two-fold gap with nothing in it
         32 -> 30   ratio 1.07   near-identical, no hierarchy gained
         18 -> 17 -> 16          three sizes doing one job
         14 -> 13 -> 12          and again

     Sizes that close together read as inconsistency, not hierarchy;
     the gap in the middle meant anything between a section heading
     and an item title had nowhere to sit. So --fs-subhead fills the
     gap, the near-duplicates were merged, and the whole set was
     brought down again.

     Display sizes still sit above a conventional 40-48px heading
     because oversized display type is this design's character — but
     52px leads the page instead of shouting over it.

     Lower bounds are floors, not the small end of a ratio: 16px for
     anything read as prose, 12px for incidental labels. Only the
     upper end grows with the viewport. */
  /* One step above --fs-display and nothing else uses it: the hero
     slogan is the h1 and should lead the page, but the whole point
     of this scale was to stop headings shouting. 68px against the
     52px of a section title is a 1.31 ratio — the same order as the
     other steps here, and read as "the largest thing on the site"
     rather than as a different design. */
  /* Eased back from 4.25rem. At 68px the slogan was carrying the
     hero on size alone; the treatment on it (the metal ramp, the
     travelling shine, the glow added in hero.css) does that work
     better than scale does, and 60px leaves the sentence room to
     breathe on a laptop instead of filling the frame. Still the
     largest type on the site by a clear step. */
  /* Halved. It was the largest type on the site by a wide margin
     and it fought the footage for the frame; at this size the
     sentence reads as a caption over the shot rather than a poster
     laid on top of it. The logo above it now carries the weight
     the type used to. */
  --fs-slogan:  clamp(1.25rem,  4.8vw,  1.875rem);  /* hero h1, only  */
  --fs-display: clamp(1.75rem,  3.9vw,  3.25rem);  /* section headings */
  --fs-number:  clamp(1.5rem,   3vw,    2.5rem);   /* 01..05, 50+     */
  --fs-subhead: clamp(1.2rem,   1.9vw,  1.75rem);  /* footer, menu    */
  --fs-title:   clamp(1.05rem,  1.5vw,  1.375rem); /* item titles     */
  --fs-lead:    clamp(1rem,     1.2vw,  1.125rem); /* intro copy      */
  --fs-body:    clamp(1rem,     1.05vw, 1.0625rem);
  --fs-sm:      clamp(0.875rem, 0.95vw, 0.9375rem);
  --fs-xs:      0.75rem;

  /* Persian letterforms connect — tracking must stay at 0.
     Only Latin runs (.u-latin) may use this. */
  --track-latin: 0.08em;

  /* Persian has deep descenders (ج ح ع م ی). Measured in Vazirmatn
     900: actual ink height is ~1.27em, so the reference design's
     `leading-none` both clips the glyphs and collides consecutive
     lines. 1.35 is the tightest value that clears both. */
  --lh-display: 1.35;   /* Persian display headings — do not lower */
  --lh-tight:   1.20;   /* Latin-only runs: 500+, 01, 02 */
  --lh-snug:    1.35;
  --lh-body:    1.75;   /* Persian reads better with room */

  /* ---------- SPACE ---------- */

  /* The small steps are unchanged — they were never the problem.
     The three large ones drove section padding to 171px, which
     with the reduced headings left sections floating in empty
     space out of proportion to their content. */
  --sp-2xs: 0.25rem;
  --sp-xs:  0.5rem;
  --sp-sm:  0.75rem;
  --sp-md:  1rem;
  --sp-lg:  1.5rem;
  --sp-xl:  2rem;
  --sp-2xl: 2.5rem;
  --sp-3xl: clamp(2.5rem, 4.5vw, 3.75rem);
  --sp-4xl: clamp(3rem,  6vw,   5.5rem);

  /* Section rhythm. These existed as ad-hoc values per section —
     padding ran 86 / 107 / 160 and the gap between a heading and
     its content was 64 / 80 / 112 across three sections doing the
     same thing. Naming them makes the page breathe evenly and lets
     the rhythm be retuned in one place. */
  --sp-section:      clamp(3.5rem, 7vw, 6rem);   /* top & bottom of a section */
  --sp-heading-gap:  clamp(2rem, 4.5vw, 3.5rem); /* heading -> its content    */

  /* ---------- LAYOUT ---------- */

  --w-wide:   1800px;   /* demo grid */
  --w-main:   1440px;   /* default container */
  --w-narrow: 900px;    /* prose blocks */
  --gutter:   clamp(1.25rem, 4vw, 2.5rem);

  /* ---------- SHAPE ---------- */

  /* Eased back with the type. A 60px corner reads as playful at
     the reduced scale rather than architectural, and the panel
     corners were rounder than the cards sitting inside them. */
  --r-section: clamp(24px, 3vw,   40px);
  --r-card:    clamp(18px, 2.2vw, 28px);
  --r-tile:    clamp(10px, 1.2vw, 16px);
  --r-pill:    999px;

  /* ---------- MOTION ---------- */

  --ease:      cubic-bezier(0.25, 0.10, 0.25, 1.00);
  --ease-out:  cubic-bezier(0.16, 1.00, 0.30, 1.00);

  --dur-fast: 200ms;
  --dur-base: 400ms;
  --dur-slow: 700ms;

  /* ---------- DEPTH (3D) ---------- */

  --perspective: 1200px;

  /* ---------- Z-INDEX ---------- */

  --z-below:     -1;
  --z-base:       1;
  --z-raised:    10;
  --z-menu:     190;   /* full-screen nav panel   */
  --z-menu-btn: 200;   /* hamburger, above it     */
  --z-progress: 210;   /* scroll hairline, on top */
  --z-top:      999;   /* entry loader            */
  --z-cursor:  1000;   /* follower, above all     */
}

/* ============================================================
   LIGHT THEME

   Only the things that genuinely differ are listed. Everything
   else is already expressed as a share of --rgb-ink or
   --rgb-surface up in :root, so re-basing those four triplets
   carries the whole system across — a border that was 15% ink
   stays 15% ink, a scrim that was 72% surface stays 72% surface.

   Applied as an attribute on <html> rather than through
   `prefers-color-scheme`, because dark is this site's identity and
   is what a first-time visitor should get regardless of what their
   OS prefers. The attribute is set before first paint by the
   inline script in <head>.
   ============================================================ */

:root[data-theme='light'] {
  color-scheme: light;

  /* Ink is a deep cool near-black rather than pure black, and the
     page a barely-cool off-white rather than pure #FFF — the same
     blue-grey cast the dark theme has, so the two read as one
     design seen under different light.

     Measured: #10141A on #F7F9FA is 17.5:1, and --c-text-dim
     composites to 4.74:1, which clears AA for body text. */
  --rgb-ink:     16  20  26;
  --rgb-surface: 247 249 250;

  /* Cool, not neutral: a pure-black shadow on a cool white page
     reads as grey dirt. */
  --rgb-shadow:   16  24  40;

  /* Cards are a shade DARKER than the page here, not lighter.

     White-on-white was the first attempt and it did not read: the
     demo cards and the page were both effectively #FFF, so the only
     thing separating a card from its background was a 1px 15% line.
     A slightly sunken tint gives the grid actual structure, and it
     is what the raised channel now carries — the gradient that
     reads each screenshot down into its card uses the same channel,
     so the two stay matched automatically.

     Measured on this tint: body text 15.86:1, secondary 4.58:1. */
  --rgb-raised:      232 237 241;
  --c-bg-elevated:   rgb(var(--rgb-raised));
  --c-panel:         rgb(var(--rgb-raised));

  /* Heavier on light. A hairline at 15% ink reads as a crisp edge
     on a dark page and as almost nothing on a pale one. */
  /* 0.65, not the 0.60 the dark theme uses. Secondary copy sits on
     the tinted card rather than the page here, and against that
     slightly darker surface 0.60 measured 4.57:1 — over the line,
     but with almost nothing to spare. 0.65 puts it at 5.38:1. */
  --c-text-dim:      rgb(var(--rgb-ink) / 0.65);

  --c-card-border:   rgb(var(--rgb-ink) / 0.22);
  --bw-card:         2px;
  --bw-panel:        3px;

  /* The pair that makes a chip contrast with the page: light chip
     on dark, dark chip on light. --c-text-invert already flips on
     its own, so only this side needs stating. */
  --c-surface-light: rgb(var(--rgb-ink));

  --c-text-strong:   #000000;

  /* Mirrors the dark ramp: starts mid and resolves to the extreme,
     so a heading still arrives at maximum contrast at its baseline. */
  --grad-heading: linear-gradient(180deg, #7B8592 0%, #10141A 100%);

  /* Two layers, not one — a tight contact shadow plus a wide
     ambient one. A single blurred drop reads as a grey halo; the
     pair is what makes the card look like it is resting on
     something. Alphas are far below the dark theme's, because a
     dark shadow on a pale page is doing much more work per unit.

     The layers grow at different rates between rest and hover: the
     contact shadow spreads only a little while the ambient one
     roughly doubles, which is how a real object behaves as it
     lifts. */
  --shadow-card-rest: 0 2px 6px   rgb(var(--rgb-shadow) / 0.07),
                      0 8px 20px  rgb(var(--rgb-shadow) / 0.06);
  --shadow-card:      0 6px 14px  rgb(var(--rgb-shadow) / 0.10),
                      0 26px 52px rgb(var(--rgb-shadow) / 0.13);
  --shadow-panel:     0 4px 10px  rgb(var(--rgb-shadow) / 0.06),
                      0 18px 40px rgb(var(--rgb-shadow) / 0.09);

  /* Light theme only, and this is where it matters: the footer and
     the section above it are the same colour, so the join was a
     single 15%-opacity hairline and nothing else.

     Negative spread pulls the shadow back inside the top edge so it
     reads as a soft band that fades within ~20px, rather than a
     dark rim tracing all four sides of the footer. */
  --shadow-footer: inset 0 16px 22px -14px rgb(var(--rgb-shadow) / 0.16);

  /* Small enough that the two fixed corner buttons, which sit about
     20px in, still land on the panel rather than straddling its
     edge. */
  /* Zero, same as dark — the hero is full-bleed in both themes now.

     The inset was added in 7.16 to solve a problem that no longer
     exists: dark footage sitting on a white page needed an edge to
     detach from it. The sequence is shot twice now, so the light
     theme shows light footage on a light page and the border was
     just a visible frame around the video. */
  --hero-inset:  0px;
  --hero-radius: 0px;



  /* Left un-themed this was #A8B4BE on a near-white page — 2.00:1,
     which is not readable, and it is the body copy on about.html.
     #5A626B measures 5.86:1 there. */
  --c-text-soft: #5A626B;

  --c-badge-hot-bg:  #FBE3E5;   --c-badge-hot-fg:  #96262C;
  --c-badge-free-bg: #E1F3E6;   --c-badge-free-fg: #1F6733;

  /* ---- hand loader (light frosted glassmorphism) -------------- */
  --hand-palm-bg:      linear-gradient(145deg, rgba(255, 255, 255, 0.55) 0%, rgba(230, 210, 250, 0.40) 50%, rgba(180, 130, 220, 0.25) 100%);
  --hand-palm-rim:     rgba(118, 33, 176, 0.45);
  --hand-palm-side:    rgba(118, 33, 176, 0.12);
  --hand-finger-face:  linear-gradient(160deg, rgba(255, 255, 255, 0.65) 0%, rgba(215, 160, 245, 0.42) 45%, rgba(160, 80, 210, 0.28) 100%);
  --hand-finger-side:  rgba(118, 33, 176, 0.14);
  --hand-outline:      rgba(255, 255, 255, 0.55);
  --hand-shadow:       rgba(40, 15, 60, 0.15);
  --hand-ghost:        rgba(182, 0, 168, 0.22);
  --hand-ambient-glow: rgba(168, 50, 235, 0.16);
  --hand-text-dim:     rgba(30, 25, 40, 0.45);
  --hand-text-pop:     #7621b0;
  --hand-text-glow:    rgba(118, 33, 176, 0.35);
}

/* ============================================================
   MEDIA PANELS

   Two sections are laid over dark video — the hero's frame
   sequence and the features clip — and the footage does not change
   with the theme, so neither can they.

   Rather than rewriting every rule inside them to a second set of
   token names, the tokens themselves are REDECLARED here. Custom
   properties inherit, so every `var(--c-text)` below this point
   resolves to the media value without a single selector in
   hero.css or features.css changing.

   Caught by measurement, not by reading: in the light theme the
   hero's scroll cue computed to rgba(16, 20, 26, 0.6) — dark ink
   at 60% on top of near-black footage — and the whole features
   panel turned white behind a video lit for a dark background.
   ============================================================ */

/* .features used to be here too. It is not a media panel any more:
   its rendered still is gone and the section is now plain type on
   the page's own surface, so it takes the page's own tokens. The
   values it resolves to are identical either way — --rgb-media and
   --rgb-surface carry the same numbers in both themes — but naming
   it a media panel would now be a lie about why. */
.hero-scroll {
  --c-bg:       rgb(var(--rgb-media));
  --c-text:     var(--c-on-media);
  --c-text-dim: var(--c-on-media-dim);
  --c-border:   rgb(var(--rgb-on-media) / 0.15);
  --c-text-soft: var(--c-on-media-soft);
}

/* ------------------------------------------------------------
   BOTH PANELS NOW FOLLOW THE THEME

   The block above exists because footage did not follow the theme.
   That is no longer true of either section: the hero sequence was
   shot twice, and the features backdrop is now a pair of stills
   rather than the one clip that was lit for a dark page.

   So on light both panels show bright media, and every token the
   block above pinned to "light ink on dark footage" has to invert
   back. Only the SOURCE tokens are redeclared here — `--c-bg`,
   `--c-text`, `--c-text-dim`, `--c-border` and `--c-text-soft`
   above are `var()` references, and custom properties substitute
   at computed-value time, so they pick these up on the element
   without being restated. Redeclaring them would be duplication
   that could drift out of step.

   `.hero::before` and `--c-hero-cue` need no rule at all for the
   same reason: both are already written in terms of --rgb-media
   and --c-on-media-dim.
   ------------------------------------------------------------ */
:root[data-theme='light'] .hero-scroll {
  --rgb-media:     247 249 250;
  --rgb-on-media:   16  24  40;

  --c-on-media:      #10131A;
  --c-on-media-dim:  rgba(16, 19, 26, 0.62);
  --c-on-media-soft: #454C57;
}

/* Hero only — the h1 sits on the footage and nothing in the
   features panel uses these three. */
:root[data-theme='light'] .hero-scroll {
  /* Mirror of the dark ramp: the light footage measures 0.55-0.64
     mean sRGB, so the palest stop (#4A5460) still lands at 4.9:1
     against the brightest part of the frame. */
  --grad-slogan: linear-gradient(172deg,
                   #0B0E14  0%,
                   #232B36 30%,
                   #4A5460 52%,
                   #1A212B 74%,
                   #0B0E14 100%);

  /* The sheen that travels along the sentence. White on dark
     glyphs reads as a highlight; on light footage with dark glyphs
     the same white would punch holes in the letters, so it flips
     to a dark pass. */
  --hero-shine: rgba(10, 13, 20, 0.55);

  /* Halo first, then separation. Inverted from the dark theme,
     where it is a cool glow plus a black drop. */
  --hero-slogan-filter:
    drop-shadow(0 0 26px rgba(255, 255, 255, 0.55))
    drop-shadow(0 4px 12px rgba(16, 24, 40, 0.28));
}
