/* =========================================
   ENSTACKED DESIGN TOKENS v2
   Single Source of Truth for ALL design variables.
   Loaded first — before any other stylesheet.
   ========================================= */

:root {

  /* ── Brand Colors ──────────────────────── */
  --brand-50:  #FFF3EE;
  --brand-100: #FFE4D6;
  --brand-200: #FFC4A3;
  --brand-300: #FF9D6B;
  --brand-400: #F47340;
  --brand-500: #E85D20;   /* primary accent  */
  --brand-600: #C94B14;   /* hover state     */
  --brand-700: #A33A0D;
  --brand-800: #7A2B09;
  --brand-900: #4F1C05;

  --accent-color: var(--brand-500);
  --accent-hover: var(--brand-600);
  --accent-subtle: var(--brand-50);

  /* ── Eyebrow chip ──────────────────────
     The chip is defined once as `.es-eyebrow` in utilities.css, and these
     three tokens are what it paints itself with. They exist so that a panel
     with its own ground repaints the chip by re-pointing three variables,
     instead of every partial that renders one restating the pairing. The
     values are the pairing the chip already used: brand-50 ground, brand-700
     ink, brand-100 hairline, 6.09:1.

     They are also what the blog's author disc and confirmation mark read, so
     those marks stay the same brand pairing as the chip beside them. */
  --eyebrow-bg:     var(--accent-subtle);
  --eyebrow-ink:    var(--brand-700);
  --eyebrow-border: var(--brand-100);

  /* ── Backward-Compat Aliases ───────────── */
  --primary-color: var(--brand-500);
  --light-bg-primary-color: var(--brand-50);

  /* ── Neutrals ─────────────────────────── */
  --gray-0:   #FFFFFF;
  --gray-50:  #FAFAF8;
  --gray-100: #F4F2EE;
  --gray-200: #E9E5DE;
  --gray-300: #D5CFC5;
  --gray-400: #B0A898;
  --gray-500: #8A8177;
  --gray-600: #635D55;
  --gray-700: #433F39;
  --gray-800: #2A2723;
  --gray-900: #161410;

  /* ── Semantic Text ────────────────────── */
  --text-color: #121212;
  --text-heading:  var(--gray-900);
  --text-body:     var(--gray-700);
  --text-muted:    var(--gray-500);
  --text-disabled: var(--gray-400);
  --text-inverse:  var(--gray-0);
  --description-text-color: #595959;

  /* ── Semantic Surface ─────────────────── */
  --bg-page:       var(--gray-50);
  --bg-surface:    var(--gray-0);
  --bg-raised:     var(--gray-0);
  --bg-sunken:     var(--gray-100);

  /* ── Borders ──────────────────────────── */
  --border-subtle:  var(--gray-200);
  --border-default: var(--gray-300);
  --border-strong:  var(--gray-400);

  /* ── Chips ────────────────────────────── */
  /* Neutral dark disc that sits behind a brand logo mark. Set by the header's
     tech strip (.hire-skils-list-main in header.css) and shared from here so
     the About page tile wall renders the identical chip. Deliberately neutral
     rather than a warm --gray token: it has to stay the same disc the navbar
     shows, and it is already a dark chip on a dark panel in both themes. */
  --chip-surface: #313131;

  /* ── Rating ───────────────────────────── */
  /* Star gold for review scores. Its own token rather than a brand or status
     colour: it has to stay recognisably "review star" on light and dark
     surfaces, so it must not drift with the palette. */
  --star-color: #F5A623;

  /* ── Status ───────────────────────────── */
  --success-bg:   #ECFDF3;
  --success-text: #166534;

  /* The same pair for a component sitting on a DARK ground.

     --success-bg is a near-white surface and --success-text is a dark green
     that needs it. Dropped onto a dark panel that pairing inverts into the
     brightest object in the composition, which is the opposite of what a
     quiet status pill should be. The dark pairing is a translucent wash of
     the same hue with a light ink, which is the treatment the eyebrow chip
     and the hero's surface chips already take on a dark ground.

     Its own token pair rather than a dark-mode override of the two above:
     these are for a component that is dark in BOTH themes (the CTA band, the
     hero's dark variant), not for the page flipping to dark. Overriding the
     originals in a dark block would leave those components with the light
     pairing in light mode, which is the case this exists to fix. */
  --success-bg-on-dark:   rgba(34, 197, 94, 0.16);
  --success-text-on-dark: #86EFAC;
  --warning-bg:   #FFFBEB;
  --warning-text: #92400E;
  --error-bg:     #FEF2F2;
  --error-text:   #991B1B;

  /* ── Offer card accents ──────────────────
     Two accent families used by the blog's offer cards, and nowhere else
     yet. They exist because the layout the owner supplied on 7 Sep 2026
     gives those two cards grounds of their own, one cool and one green,
     and every colour on the site has to be a token: writing the six
     values into es-blog.css would have been six raw hexes.

     They are NOT a second brand. Nothing here replaces --brand-500 or
     changes any control outside those cards; the site's accent is still
     the orange above. What these do is let a panel repaint its own ground
     and its own eyebrow chip, which is exactly the case the eyebrow rule
     in the uniformity contract already allows for.

     The -700 step is the chip's ink and the -100 step is the chip's
     ground. That pairing is the reason the ramp stops where it does: the
     two measure 8.7:1 (blue) and 6.5:1 (green), against the 6.09:1 the
     site-wide brand chip sets as the floor. Do not lighten a -700 or
     darken a -100 without re-measuring the pair. */
  --offer-blue-50:   #F1F6FD;   /* panel ground        */
  --offer-blue-100:  #DEE9FB;   /* chip ground         */
  --offer-blue-200:  #C9DAF6;   /* hairline, watermark */
  --offer-blue-700:  #1D3C7A;   /* chip ink            */

  --offer-green-50:  #F2F8F3;
  --offer-green-100: #DCEDE0;
  --offer-green-200: #C4E0CB;
  --offer-green-700: #1F5C33;

  /* The far end of the wash under the bloom. Not white and not the
     -50 step: a hair of colour, so the card is never flat even where
     the bloom does not reach. */
  --offer-blue-wash:  #FBFCFF;
  --offer-green-wash: #FBFEFC;

  /* ── Offer card ground ───────────────────
     The whole background of an offer card as one value: a soft bloom
     in the card's accent, over a near-white wash on the diagonal.
     From the layout supplied 7 Sep 2026.

     ── WHY THIS IS TWO TOKENS AND NOT ONE RECIPE ──────────────
     The obvious version of this is ONE token holding the shape, with
     `var(--bloom)` and `var(--wash)` inside it for each card to fill
     in. That does not work, and it fails silently, which is worse
     than failing loudly: a custom property resolves the `var()`s in
     its own value at the element where it is DECLARED, not where it
     is used. Declared here on `:root`, the inner lookups resolve
     against `:root`, find nothing, and both cards get the fallback.
     Built that way first, and the bloom came out `rgba(0,0,0,0)` on
     both cards while every rule involved looked correct.

     So each card's ground is stated in full. The cost is that the
     shape is written twice and a change to one has to be made to the
     other; the two are kept adjacent so that is visible. */
  --offer-card-bg-blue:
    radial-gradient(circle at 88% 17%,
      color-mix(in srgb, var(--offer-blue-100) 70%, transparent), transparent 27%),
    linear-gradient(135deg, var(--bg-surface) 0%, var(--offer-blue-wash) 100%);

  --offer-card-bg-green:
    radial-gradient(circle at 89% 55%,
      color-mix(in srgb, var(--offer-green-100) 65%, transparent), transparent 29%),
    linear-gradient(135deg, var(--bg-surface) 0%, var(--offer-green-wash) 100%);

  /* ── Typography ───────────────────────── */
  /* One family, site-wide. All three tokens resolve to it: the names describe
     the ROLE the type plays, not a different typeface, so a section can keep
     saying "this is a label" without that meaning "this is a second font". */
  --font-display: "Instrument Sans", "Instrument Sans Fallback", sans-serif;
  --font-body:    "Instrument Sans", "Instrument Sans Fallback", sans-serif;

  /* Eyebrows, section indices and tabular figures. Was "JetBrains Mono",
     monospace, which had no @font-face and no font file anywhere in the theme,
     so all 38 usages of it were rendering in whatever monospace the visitor's
     OS defaults to: Consolas on Windows, Menlo on macOS, something else again
     on Android. That was a second, uncontrolled typeface on every migrated
     page and is the reason eyebrows looked different across machines. */
  --font-label:   "Instrument Sans", "Instrument Sans Fallback", sans-serif;

  /* Deprecated alias, kept so any reference missed by the rename still lands
     on Instrument Sans rather than falling back to the OS monospace. Do not
     use it in new code: the name says monospace and the value is not. */
  --font-mono:    var(--font-label);

  --text-xs:   0.75rem;    /* 12px */
  --text-sm:   0.875rem;   /* 14px */
  --text-base: 1rem;       /* 16px */
  --text-md:   1.125rem;   /* 18px */
  --text-lg:   1.25rem;    /* 20px */
  --text-xl:   1.5rem;     /* 24px */
  --text-2xl:  1.875rem;   /* 30px */
  --text-3xl:  clamp(1.875rem, 3vw, 2.25rem);   /* 30-36px */
  --text-4xl:  clamp(2.25rem,  4vw, 3rem);       /* 36-48px */
  --text-5xl:  clamp(2.75rem,  5vw, 4rem);       /* 44-64px */
  --text-hero: clamp(3.25rem,  6.5vw, 5rem);     /* 52-80px */

  /* ── Border Radius ────────────────────── */
  --radius-xs:   4px;
  --radius-sm:   8px;
  --radius-md:  12px;
  --radius-lg:  16px;
  --radius-xl:  24px;
  --radius-2xl: 32px;
  --radius-full: 9999px;

  /* ── Spacing ───────────────────────────── */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  24px;
  --space-6:  32px;
  --space-7:  48px;
  --space-8:  64px;

  /* ── Shadows ───────────────────────────── */
  --shadow-xs:
    0 1px 2px rgba(0,0,0,0.04);
  --shadow-sm:
    0 1px 2px rgba(0,0,0,0.04),
    0 4px 12px rgba(0,0,0,0.05);
  --shadow-md:
    0 1px 3px rgba(0,0,0,0.04),
    0 8px 24px rgba(0,0,0,0.07);
  --shadow-lg:
    0 2px 4px rgba(0,0,0,0.04),
    0 16px 40px rgba(0,0,0,0.10);
  --shadow-brand:
    0 8px 32px rgba(232, 93, 32, 0.22);

  /* ── Transitions ───────────────────────── */
  --ease-out:   cubic-bezier(0.0, 0.0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --duration-fast:   150ms;
  --duration-normal: 250ms;
  --duration-slow:   400ms;

  /* ── Fluid Section Rhythm ──────────────────
     Vertical padding for page sections. Scales
     smoothly from mobile → desktop, no media
     queries needed. Use via .es-section classes.

     ── Retuned for narrow screens ────────────
     The floors used to be 60 / 44 / 72 and the
     slopes were shallow enough that a phone got
     the floor and nothing else: 4vw + 40 is only
     55px at 375, so every screen under about
     500px sat on the same 60. Two sections then
     joined at 60 + 60 = 120px, which is a third
     of a phone screen of nothing between one
     section and the next, and the seam clearances
     that are built as calc(token + space) carried
     it further still.

     The floors come down and the slopes come up
     to meet the same caps, so the change is a
     narrow-screen one: 41px at 375 and 60px at
     768 against 60 and 71 before, while 1440 is
     94 against 98 and everything from about
     1560 up is the 100 / 72 / 128 it always was.

     The three move together. They are one family
     and sm < pad < lg has to hold at every width:
     dropping only the default would have left the
     COMPACT section padded more than the standard
     one on a phone. */
  --section-pad:      clamp(40px, 5vw + 22px, 100px);   /* default section */
  --section-pad-sm:   clamp(28px, 3.6vw + 15px, 72px);  /* compact section  */
  --section-pad-lg:   clamp(52px, 6.4vw + 28px, 128px); /* hero-adjacent    */
  --section-head-gap: clamp(36px, 2.5vw + 20px, 56px);  /* head → content   */
  --hero-pad-top:     clamp(110px, 14vh, 170px);        /* under fixed nav  */

  /* ── Fluid Gaps (spacing inside sections) ── */
  --gap-fluid-xs: clamp(12px, 1.5vw, 16px);
  --gap-fluid-sm: clamp(16px, 2vw,   24px);
  --gap-fluid-md: clamp(24px, 2.5vw, 36px);
  --gap-fluid-lg: clamp(32px, 3.5vw, 48px);
  --gap-fluid-xl: clamp(40px, 4vw,   56px);

  /* ── Semantic Fluid Type Scale ─────────────
     One source of truth for responsive font
     sizes across all templates.

     Every size in this block and the two below was raised on the owner's
     instruction, because the old scale did not read comfortably. The step is
     by size rather than by percentage: +3px on display type from 24px up,
     +2px in the 15 to 20px band, +1px at 14px and below. A flat percentage
     would have moved a 64px heading by 6px and a 13px caption by barely one,
     which is the wrong way round when the complaint is about reading.

     The step is added to the PREFERRED term as well as to the floor and the
     ceiling. Raising only the two ends is the obvious way to write this and
     is wrong: between them the value is the bare `vw` term, so every viewport
     in the middle of a clamp's range would have kept the size it already had.
     `clamp(41px, 5.2vw + 3px, 67px)` moves the whole curve up by 3px; the
     `vw + px` form is what --fs-lede already used. */
  --fs-hero:          clamp(41px, 5.2vw + 3px, 67px);   /* page hero h1     */
  --fs-section-title: clamp(31px, 3.6vw + 3px, 47px);   /* section h2       */
  --fs-title-md:      clamp(29px, 3.2vw + 3px, 43px);   /* h2 in cards/CTAs */
  --fs-title-sm:      clamp(23px, 2.6vw + 3px, 31px);   /* pull-quotes, h3  */
  --fs-card-title:    clamp(20px, 1.5vw + 2px, 22px);   /* card headings    */
  --fs-lede-lg:       clamp(18px, 1.6vw + 2px, 21px);   /* hero subcopy     */
  /* Was a flat 17px, which was the only entry in the scale that did not
     respond to viewport at all: a lede set at the desktop size ran the full
     width of a phone under an already-large heading. */
  --fs-lede:          clamp(18px, 0.6vw + 16px, 19px);  /* section subcopy */

  /* ── Figures ───────────────────────────────
     Big numerals: proof bands, hero stats and
     rating scores. These were three raw clamps
     repeated inline across four partials, and
     two of them were byte-identical, so a change
     to "the stat size" meant editing every copy
     and hoping none was missed. */
  --fs-stat:          clamp(33px, 3.4vw + 3px, 45px);   /* stat band + hero stat */
  --fs-stat-lg:       clamp(37px, 3.6vw + 3px, 49px);   /* proof card figure     */
  --fs-rating:        clamp(27px, 2.4vw + 3px, 33px);   /* review score          */

  /* Body sizes stay fixed on purpose. Shrinking running copy on a phone is
     the opposite of responsive: the small screen is where it is hardest to
     read, and 16px is the floor browsers assume for comfortable reading.
     Only display type above scales. */
  --fs-body:          18px;
  --fs-body-sm:       17px;
  --fs-small:         15px;
  --fs-caption:       14px;
  --fs-eyebrow:       13px;   /* also the floor: nothing on the site is smaller */

  /* ── Line Heights ─────────────────────────── */
  --lh-display: 1.1;    /* hero headings   */
  --lh-heading: 1.15;   /* section headings */
  --lh-subhead: 1.35;   /* card headings   */
  --lh-body:    1.7;    /* paragraphs      */

  /* ═══════════════════════════════════════════
     v3 ADDITIONS
     Tokens documented in enstacked-design-system.md
     that were missing from this file. Purely
     additive: nothing above is overridden.
     ═══════════════════════════════════════════ */

  /* ── Layout Widths ────────────────────────── */
  --container-sm:   640px;
  --container-md:   768px;
  --container-lg:  1024px;
  --container-xl:  1280px;
  --container-2xl: 1440px;
  --reading-width:  720px;

  /* The gutter `.es-container` actually applies, in one place so a full-bleed
     section can cancel it exactly. Anything that pulls itself out to the
     screen edge must negate THIS value, never --container-pad below.

     A rail using --container-pad bled 16px against a 12px gutter and hung 4px
     past the viewport on both edges, which is a horizontal scrollbar on every
     page that ran it. Keep this and .es-container's padding-inline in step. */
  --container-gutter: 12px;

  /* NOT the container gutter. A larger inner inset used by components that pad
     their own content away from a panel edge (see section-team). Named before
     .es-container settled on 12px, kept because renaming it would churn the
     files that legitimately use it. Do not reach for it to cancel a gutter. */
  --container-pad: clamp(16px, 3vw, 32px);

  /* ── Spacing (extended scale) ─────────────── */
  --space-0:    0px;
  --space-9:   80px;
  --space-10:  96px;
  --space-11: 128px;
  --space-12: 160px;

  /* ── Surface / Status (missing entries) ───── */
  --bg-overlay: rgba(22, 20, 16, 0.48);
  --info-bg:   #EFF6FF;
  --info-text: #1E40AF;

  /* ── Typography axes ──────────────────────── */
  --tracking-tight:  -0.03em;
  --tracking-normal: -0.015em;
  --tracking-wide:    0.04em;
  --tracking-wider:   0.08em;

  --font-regular:  400;
  --font-medium:   500;
  --font-semibold: 600;
  --font-bold:     700;
  --font-extrabold: 800;

  --leading-tight:   1.15;
  --leading-snug:    1.35;
  --leading-normal:  1.6;
  --leading-relaxed: 1.8;

  /* ── Elevation (missing entry) ────────────── */
  --shadow-xl:
    0 4px 8px rgba(0,0,0,0.04),
    0 24px 64px rgba(0,0,0,0.14);

  /* ── Z-Index Scale ────────────────────────── */
  --z-base:       0;
  --z-raised:    10;
  --z-dropdown: 200;
  --z-sticky:   300;
  --z-overlay:  400;
  --z-modal:    500;
  --z-toast:    600;

  /* ── Easing (missing entries) ─────────────── */
  --ease-in:    cubic-bezier(0.4, 0.0, 1.0, 1);
  --ease-inout: cubic-bezier(0.4, 0.0, 0.2, 1);

  /* ── Focus ring ───────────────────────────── */
  --focus-ring: 0 0 0 3px rgba(232, 93, 32, 0.12);

  /* ── Sticky offset ─────────────────────────
     Clearance for the fixed floating nav (~105px:
     20px margin-top plus the nav bar itself), used
     as `top` by any position:sticky element so the
     value lives in one place. */
  --sticky-offset: clamp(96px, 9vh, 124px);
}
