/*  Leaf & Bloom - Design tokens
 *  ---------------------------------------------------------------------------
 *  THE single source of colour, type, space, radius and shadow for the whole
 *  site. Nothing downstream may hard-code a value. This file ships into the
 *  theme verbatim as assets/css/tokens.css.
 *
 *  Palette derived from the Leaf & Bloom logo (deep olive-forest tree, antique
 *  gold script). Every pair verified against WCAG 2.1 AA - see
 *  CONTRAST-REPORT.md and `node tools/contrast-check.js`.
 *
 *  Structure:
 *    1. Brand palette   - the raw named colours (spec 3.1)
 *    2. Semantic layer  - what the UI actually consumes; this is what flips
 *                         between modes, so component CSS never knows the mode
 *    3. Type / space / radius / shadow / motion
 *    4. Dark mode       - redefines the palette + semantic layer
 *  ------------------------------------------------------------------------- */

:root {
  color-scheme: light dark;

  /* == 1. Brand palette (light) ========================================== */
  --c-forest:       #395211;   /* sampled from the logo: wordmark, trunk and canopy all agree */
  --c-forest-deep:  #26370B;   /* same hue, darker - footer, button hover */
  --c-leaf:         #7C9159;   /* the logo canopy midtone */
  --c-leaf-light:   #E4E9D6;
  --c-cream:        #FAF7EE;   /* page ground - never pure white */
  --c-ivory:        #FFFDF7;
  --c-sand:         #EEE4CC;
  --c-gold:         #AA7918;   /* antique gold. Was #8E8E30, a khaki at hue 60 — the
                                  only accent token on the site, in 40+ rules, and the
                                  literal answer to "pheeka". Measured on cream it is
                                  3.59:1, BETTER than the olive it replaces (3.23:1). */
  --c-gold-ink:     #845E13;   /* the same gold, deep enough to be READ. --c-gold is
                                  3.04:1 on sand and 3.10 on the tint, fine for a rule
                                  or a star, a fail for 12px eyebrow caps, which are
                                  text. This clears 4.5 on every light ground: cream
                                  5.46, ivory 5.75, tint 4.71, sand 4.62. */
  --c-ink:          #232B1A;
  --c-ink-soft:     #5A644C;
  --c-success:      #3E7A4E;
  --c-error:        #B4453A;
  --c-sale:         #A93B28;   /* ALL sale UI - badges AND prices */

  /* == 2. Semantic layer ================================================= */
  /* Surfaces */
  --c-bg:            var(--c-cream);
  --c-surface:       var(--c-ivory);        /* cards */
  --c-surface-2:     var(--c-sand);         /* alternating warm bands, quotes */
  --c-tint:          var(--c-leaf-light);   /* green section tints */
  --c-well:          var(--c-ivory);        /* photo wells - light in BOTH modes */
  --c-line:          var(--c-leaf-light);   /* hairlines */
  --c-line-strong:   #D6DDC4;               /* input borders, table rules */
  --c-scrim:         rgba(22, 28, 16, .46); /* over hero imagery */

  /*  Grounds that do NOT invert.
   *
   *  --c-forest and --c-forest-deep flip in dark mode, because there they are
   *  heading and link colours and have to become light to stay legible. But
   *  the hero, the Grove and the footer use those same names as BACKGROUNDS,
   *  where the flip is exactly wrong: the hero gradient turned cream-to-sage
   *  and washed the whole band out.
   *
   *  These three are the deep greens, in both modes, for any surface that
   *  cream text sits on. They are the only colours in the file that are
   *  deliberately identical in light and dark. */
  --c-ground:    #26370B;
  --c-ground-2:  #395211;
  --c-ground-3:  #7C9159;
  /*  Bright gold for decoration on those three grounds ONLY. On cream it is
   *  2.0:1 and unusable; on --c-ground it measures 6.21:1, which is the one
   *  place on a cream site where gold can actually look like gold. Never let
   *  it touch --c-ground-3, where it is 1.68:1. */
  --c-gold-bright: #D4AF6A;
  /*  And the gold the hero light is made of. The dapple lands on --c-ground,
   *  which is deliberately the same colour in both modes — so the light on it
   *  has to be too. Using the inverting --c-gold meant the dark theme lit the
   *  hero with a paler gold and test:dapple measured the headline at 2.98:1
   *  against it. Fixed, both modes behave like the light one, which measures
   *  6.49:1 under the copy at the light's brightest. */
  --c-gold-lit: #AA7918;
  /*  The lightest ground any footer or newsletter text may sit on: halfway
   *  between --c-ground and --c-ground-2. Halfway is a measurement, not a
   *  taste. --c-gold-bright on --c-ground-2 itself is 4.24:1, which fails
   *  for the 12px gold column headings; on this mix it is 5.11:1, and cream
   *  is 9.88:1 (9.02:1 with the dark theme's cream). Like the two grounds
   *  it is made of, it does not invert. */
  --c-ground-mid: color-mix(in srgb, var(--c-ground-2) 50%, var(--c-ground));

  /* Text */
  --c-text:          var(--c-ink);
  --c-text-soft:     var(--c-ink-soft);
  --c-heading:       var(--c-forest);
  --c-heading-deep:  var(--c-forest-deep);
  --c-accent:        var(--c-forest);       /* links, active states */
  --c-accent-soft:   var(--c-leaf);         /* icon strokes, quiet UI */
  --c-on-dark:       var(--c-cream);        /* text on forest bands + footer */

  /* Controls */
  --c-brand-fill:        var(--c-forest);
  --c-brand-fill-hover:  var(--c-forest-deep);
  --c-on-brand:          var(--c-cream);
  --c-focus:             var(--c-forest);

  /* Accents + status */
  --c-gold-line:     var(--c-gold);
  --c-on-gold:       #161C10;   /* 4.52:1 on gold light, 8.80 dark (contrast-check) */
  --c-sale-fill:     var(--c-sale);
  --c-on-sale:       #FFFFFF;
  --c-sale-text:     var(--c-sale);
  --c-new-fill:      var(--c-forest);
  --c-on-new:        var(--c-cream);
  --c-ok:            var(--c-success);
  --c-bad:           var(--c-error);

  /* == 3a. Typography ==================================================== */
  --ff-display: 'Cormorant Garamond', 'Cormorant Fallback', Georgia, 'Times New Roman', serif;
  --ff-sans:    'Jost', 'Jost Fallback', system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;

  /*  Cormorant Garamond is a display face - extreme stroke modulation, hairline
   *  thins - and it does not start being beautiful until it is large. Capped at
   *  67px the site was paying 37KB of woff2 to render something that looked
   *  like Georgia. The hero and the one lead heading now go big enough for the
   *  face to actually show, and there is a deliberate empty middle between the
   *  display sizes and the body sizes. */
  /*  Was 5.4rem (86px) at the top, which put the hero headline on two very
   *  tall lines and was the single biggest reason the owner read the first
   *  screen as "bohut bara". 4.5rem (72px) is still far past the ~48px
   *  where Cormorant starts being worth its 37KB, and it takes roughly
   *  50px off the fold. */
  --fs-hero:    clamp(2.4rem, 6vw, 4.5rem);
  --fs-h2-lead: clamp(2.1rem, 5.4vw, 3.9rem);   /* the one chapter heading per page */
  --fs-h2:      clamp(1.8rem, 4vw, 2.75rem);
  /*  The step below --fs-h2, added after a measurement of the whole preview
   *  found SIX different clamps living in this one band: the pull quote at
   *  1.5-2.1, the large price at 1.6-2.1, the category label at 1.5-2.0, the
   *  Grove line at 1.6-2.8 and the buy-box title at 1.9-2.6. Five sizes doing
   *  one job is what makes a page look as though nobody decided anything.
   *  One name, one range, and any heading that is big but is not a chapter
   *  heading uses it. */
  --fs-h2-sm:   clamp(1.5rem, 3vw, 2.1rem);
  --fs-h3:    1.375rem;
  --fs-h4:    1.125rem;
  /*  The hero's tagline is the one lead that is allowed to be bigger than a
   *  lead, because it is read from across the room rather than at arm's
   *  length. It is named so it cannot be quietly retyped at a third size. */
  --fs-lead-lg: clamp(1.15rem, 2.2vw, 1.6rem);
  --fs-lead:  clamp(1.0625rem, 1.6vw, 1.25rem);
  --fs-body:  1rem;        /* 16px floor - never smaller, especially on inputs */
  --fs-small: 0.875rem;
  --fs-micro: 0.75rem;     /* uppercase eyebrows + badges, with --ls-micro */
  /*  The smallest type on the site, and there is exactly one of it. Before
   *  this token there were three: 10px on the cart count, the Sample flag and
   *  the filter count, 11px on the verify marker and the assistant note, and
   *  12.5px on the brand tagline - all of them doing the same job at sizes a
   *  reader can tell apart but nobody chose. Nothing may be smaller. */
  --fs-nano:  0.6875rem;

  /*  The line-height ladder. A measurement of the rendered pages found
   *  THIRTEEN distinct ratios in use and only four of them named — six of
   *  them (1.35 / 1.4 / 1.42 / 1.45 / 1.5 / 1.55) crammed into a 0.2 band,
   *  all doing the same job. A reader cannot name that, but they feel it:
   *  text that never settles onto a grid is a large part of what makes a
   *  page read as flat and unfinished. Six named steps now cover all
   *  thirteen, and nothing may type a bare number again. */
  --lh-flat:  1;        /* single-line UI: numerals, icon buttons, badges */
  --lh-tight: 1.12;     /* display headings */
  --lh-snug:  1.3;      /* small headings, labels, two-line UI text */
  --lh-copy:  1.45;     /* dense secondary copy inside cards */
  --lh-body:  1.65;     /* body copy */
  /*  Letter-spacing, same story as line-height: nine values in use, four of
   *  them named, and .04em typed out by hand in four places that could have
   *  said --ls-btn. Five steps, and -0.005/-0.012, .02, .06/.08 and .1 all
   *  resolve onto them. */
  --ls-display: -0.012em;  /* display headings */
  --ls-micro: 0.12em;      /* eyebrows and badges */
  --ls-wide:  0.07em;      /* wordmarks and small uppercase labels */
  --ls-btn:   0.04em;      /* buttons and small caps */
  --measure:         70ch;   /* body copy never runs wider */
  --measure-article: 68ch;

  /* == 3b. Space ========================================================= */
  --sp-1:  4px;   --sp-2:  8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px;   --sp-6: 32px;   --sp-7: 40px;  --sp-8: 48px;
  --sp-9: 56px;   --sp-10:64px;   --sp-11:80px;  --sp-12:96px;

  /*  Section rhythm.
   *
   *  This was a flat 96px top AND bottom on desktop. Across eleven homepage
   *  sections that is 2,112px of a 8,200px page - a quarter of the scroll was
   *  padding, and because every section carried the SAME padding, nothing on
   *  the page was weighted more than anything else. A page where everything is
   *  equally important reads as a template.
   *
   *  So: one fluid default, and two variants that let a section be deliberately
   *  loud or deliberately quiet. Weight is now a design decision per section
   *  rather than a constant.  */
  /*  Tightened by about a fifth on 22 Sep after the owner looked at the
   *  rendered pages and said the same thing three times: too much space.
   *  He is right — at 104px top and bottom, a section that carried four
   *  cards was spending a sixth of its own height on nothing, and a page
   *  that is mostly air reads as a page with nothing on it. The ratios
   *  between the three are unchanged; the whole ladder just steps down. */
  --section-y:    clamp(2rem, 4.2vw, 3.5rem);     /* 32px  -> 56px */
  --section-y-lg: clamp(2.75rem, 6vw, 5rem);      /* 44px  -> 80px  — the moments that carry the page */
  --section-y-sm: clamp(1.25rem, 2.4vw, 2rem);    /* 20px  -> 32px  — strips and rails */

  --gutter:      var(--sp-5);
  --wrap:        1240px;
  --wrap-narrow: 860px;
  --header-h:    68px;          /* reserved, so nothing shifts on load */

  /*  == The statement ==
   *
   *  One enormous typographic line per page, and at most one. Cormorant only
   *  starts being beautiful when it is large — below about 48px its hairlines
   *  and its stroke modulation are simply not visible, and the page is paying
   *  37KB of woff2 to render something that looks like Georgia. Every heading
   *  on this site used to top out at --fs-h2-lead, so the face never got to
   *  do the one thing it is for.
   *
   *  The gap between --fs-h2-lead (max 62px) and this is deliberate: there is
   *  nothing in between, so a statement can never be mistaken for a heading. */
  /*  Was 7.5rem — 120px — which is how "One formula. Three scents." came to
   *  fill a whole screen on every product page, and the owner pointed at it
   *  on all of them. 4.75rem (76px) is still unmistakably a statement and
   *  still bigger than anything else on the page. It must not go much lower:
   *  the gold second line passes contrast-check only as LARGE text (24px+),
   *  at 3.59:1 against the 3:1 that large text needs. */
  --fs-mega:  clamp(2.6rem, 6vw, 4.75rem);
  --lh-mega:  0.92;
  --ls-mega:  -0.02em;

  /* == 3c. Radius, shadow, motion ======================================== */
  --r-sm:   6px;    /* inputs */
  --r-md:  12px;    /* cards */
  /*  --r-lg was being READ by four rules in home.css and shop.css and had
   *  never been defined, so those cards fell back to square corners while
   *  every other card on the site was rounded. A missing custom property does
   *  not warn — it just quietly resolves to nothing. */
  --r-lg:  18px;    /* generous cards: ritual, expect, chooser, spotlight */
  --r-pill: 999px;  /* buttons, badges */

  --shadow-card:   0 2px 16px rgba(47, 74, 60, .07);
  --shadow-lift:   0 8px 28px rgba(47, 74, 60, .12);
  --shadow-drawer: 0 0 60px rgba(47, 74, 60, .22);
  /*  Wide, low and warm rather than tight and grey: this is the shadow that
   *  makes a card read as resting on the page rather than stuck to it. It is
   *  the one borrowed idea from the reference the owner liked, and it works
   *  here only because the shadow colour is the brand's own deep green rather
   *  than black. On dark it becomes none — see §4. */
  --shadow-soft:   0 18px 50px -18px rgba(38, 55, 11, .22);

  /*  == The card ==
   *
   *  One card, everywhere. Measured across the preview, the card-like boxes
   *  wore two radii, three edges (a transparent one, a leaf hairline, none)
   *  and three resting shadows (the tight one, the soft one, none), and which
   *  combination a box got was decided by the file it happened to live in, not
   *  by what it was. These lines are the whole contract now; a new card reads
   *  them rather than choosing its own.
   *
   *  The edge is a real hairline in BOTH themes. On light a card's ivory sits
   *  on a cream only a shade away, so with a transparent edge the shadow was
   *  the only thing saying where a card ends, and the top of it simply was not
   *  there. --c-line inverts, so this needs no twin in the dark blocks. The
   *  hover edge is the antique gold at 45%, the same mix as the arch round the
   *  story photograph. --shadow-soft is none on dark, where the hairline does
   *  the work, as the note on --card-border below has always said it should. */
  --card-radius:     var(--r-lg);
  --card-edge:       1px solid var(--c-line);
  --card-edge-hover: color-mix(in srgb, var(--c-gold) 45%, transparent);
  --card-shadow:     var(--shadow-soft);

  /*  == Gradients ==
   *
   *  Named, because an unnamed gradient gets retyped slightly differently the
   *  third time it is needed and the page stops looking like one system. All
   *  are built from tokens, so they invert with the theme — except
   *  --g-ground, --g-ending and --g-gold-bright, which are built from the
   *  colours that deliberately do not invert. */
  --g-warm:   linear-gradient(160deg, var(--c-surface) 0%, var(--c-surface-2) 100%);
  --g-well:   radial-gradient(120% 90% at 50% 18%,
                var(--c-well) 0%,
                color-mix(in srgb, var(--c-well) 84%, var(--c-sand)) 100%);
  --g-ground: linear-gradient(168deg, var(--c-ground), var(--c-ground-2) 46%, var(--c-ground-3) 100%);
  /*  A gold hairline that fades out at both ends. A rule that stops dead at
   *  the column edge reads as a border; one that fades reads as light. */
  --g-gold:   linear-gradient(90deg,
                transparent,
                color-mix(in srgb, var(--c-gold) 70%, transparent) 28%,
                color-mix(in srgb, var(--c-gold) 70%, transparent) 72%,
                transparent);
  /*  The ending: newsletter band and footer. --g-ground cannot do this job,
   *  because it runs on to --c-ground-3, where cream text is 3.24:1 and the
   *  bright gold 1.68:1, and the copyright line and the payment chips at
   *  the foot of the footer would sit on exactly that. This one only ever
   *  darkens: it starts at --c-ground-mid, where the band above ends, and
   *  settles to --c-ground, so every word on it is at least as legible as
   *  it is at the top edge. */
  --g-ending: linear-gradient(180deg, var(--c-ground-mid) 0%, var(--c-ground) 72%);
  /*  --g-gold in the bright gold, for hairlines on the deep grounds only.
   *  --g-gold is built from the inverting --c-gold, which on --c-ground is
   *  a muddy 3.34:1 in light mode and a different colour in dark. */
  --g-gold-bright: linear-gradient(90deg,
                transparent,
                color-mix(in srgb, var(--c-gold-bright) 70%, transparent) 28%,
                color-mix(in srgb, var(--c-gold-bright) 70%, transparent) 72%,
                transparent);
  /* On dark, shadows are invisible - a hairline border does the work instead. */
  --card-border: 1px solid transparent;

  /*  == Motion ==
   *
   *  Two families, and the difference is whether a person is waiting.
   *
   *  RESPONSE is anything the user triggered and is now watching for - hover,
   *  press, focus, a panel opening. Capped at 280ms, because past that a
   *  control feels slow rather than smooth.
   *
   *  AMBIENT is the page acting on its own while nothing is blocked - a block
   *  arriving on scroll, a meter filling. These may run longer, because nobody
   *  is waiting on them.
   *
   *  No easing curve here leaves 0-1 on y. That is what guarantees nothing on
   *  this site bounces or overshoots - it is a mechanical rule, not a taste. */
  --dur-1: 120ms;   /* colour, tint, underline */
  --dur-2: 200ms;   /* hover, press, focus, crossfade */
  --dur-3: 280ms;   /* drawer, panel, swatch, marker */
  --dur-4: 420ms;   /* rules drawing, meters filling */
  --dur-5: 640ms;   /* a block arriving */
  --dur-6: 900ms;   /* the arch draw. One use on the page. */

  --dur:   var(--dur-2);   /* kept: older rules still read this */

  --ease:        cubic-bezier(.22, .61, .36, 1);   /* general ease-out */
  --ease-settle: cubic-bezier(.16, 1, .30, 1);     /* everything that arrives */
  --ease-move:   cubic-bezier(.65, 0, .35, 1);     /* A to B, and stays */
  --ease-exit:   cubic-bezier(.55, 0, 1, .45);     /* leaving only */

  /*  Stagger is capped at five steps and ~300ms total. Past that the last item
   *  in a row is visibly waiting its turn, which reads as slow, not crafted. */
  --stag-1: 60ms;
  --stag-2: 90ms;

  --rise-sm: 10px;
  --rise:    18px;
  --rise-lg: 28px;
  --slide:   14px;
  --lift:    -8px;

  --z-header: 100;
  --z-buybar: 150;
  --z-fab:    160;   /* the floating chat + WhatsApp stack */
  --z-chat:   180;   /* the assistant panel, above the stack it grew from */
  --z-drawer: 200;   /* menu + filters stay on top of everything */
  --z-cursor: 9999;  /* the leaf cursor rides above every layer */
}

@media (min-width: 768px) {
  /* section-y is fluid now and needs no step here - only the gutter grows. */
  :root { --gutter: var(--sp-6); }
}
@media (min-width: 1024px) {
  :root { --header-h: 84px; }
}

/*  == 4. DARK MODE ========================================================
 *  Two blocks with identical bodies:
 *    a) :root[data-theme="dark"]                        - explicit user choice
 *    b) prefers-color-scheme + :not([data-theme=light]) - follows the device,
 *                                                         unless the user has
 *                                                         explicitly chosen light
 *  So "Auto" tracks the device and an explicit choice always wins.
 *  KEEP THE TWO BODIES IN SYNC.
 *  ---------------------------------------------------------------------- */

:root[data-theme="dark"] {
  --c-forest:      #93A873;   /* the green must invert to stay legible */
  --c-forest-deep: #F1EDDD;
  --c-leaf:        #93A873;
  --c-leaf-light:  #2A3320;
  --c-cream:       #161C10;   /* green-tinted near-black - never pure black */
  --c-ivory:       #202817;
  --c-sand:        #2A3320;
  --c-gold:        #D9B45C;   /* the warm gold at the same hue, lifted for dark */
  --c-gold-ink:    #D9B45C;   /* dark grounds need no deeper gold: 6.7:1 or better */
  --c-ink:         #F1EDDD;
  --c-ink-soft:    #AEB49A;
  --c-success:     #8FC08F;
  --c-error:       #E89A90;
  --c-sale:        #A93B28;   /* badge FILL stays - white on it is 6.28:1 */

  --c-well:        #FFFDF7;   /* product photos are never dark-filtered */
  --c-line:        #39422C;
  --c-line-strong: #4A553B;
  --c-scrim:       rgba(10, 14, 7, .58);

  --c-brand-fill:       #4B671E;
  --c-brand-fill-hover: #587529;   /* AA-safe lighten - see CONTRAST-REPORT.md */
  --c-on-brand:         #F5F2E3;
  --c-on-dark:          #F1EDDD;

  --c-sale-text: #E08066;
  --c-new-fill:  #93A873;
  --c-on-new:    #161C10;

  --shadow-card:   none;
  --shadow-lift:   none;
  /*  On dark a shadow is invisible: there is nothing lighter behind it to cast
   *  onto. A hairline border does the work instead, which is why --card-border
   *  exists. --shadow-soft has to go the same way, or a generous card on dark
   *  carries a faint grey bruise underneath it. */
  --shadow-soft:   none;
  --shadow-drawer: 0 0 60px rgba(0, 0, 0, .55);
  --card-border:   1px solid var(--c-line);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --c-forest:      #93A873;
    --c-forest-deep: #F1EDDD;
    --c-leaf:        #93A873;
    --c-leaf-light:  #2A3320;
    --c-cream:       #161C10;
    --c-ivory:       #202817;
    --c-sand:        #2A3320;
    --c-gold:        #D9B45C;   /* the warm gold at the same hue, lifted for dark */
    --c-gold-ink:    #D9B45C;   /* dark grounds need no deeper gold: 6.7:1 or better */
    --c-ink:         #F1EDDD;
    --c-ink-soft:    #AEB49A;
    --c-success:     #8FC08F;
    --c-error:       #E89A90;
    --c-sale:        #A93B28;

    --c-well:        #FFFDF7;
    --c-line:        #39422C;
    --c-line-strong: #4A553B;
    --c-scrim:       rgba(10, 14, 7, .58);

    --c-brand-fill:       #4B671E;
    --c-brand-fill-hover: #587529;
    --c-on-brand:         #F5F2E3;
    --c-on-dark:          #F1EDDD;

    --c-sale-text: #E08066;
    --c-new-fill:  #93A873;
    --c-on-new:    #161C10;

    --shadow-card:   none;
    --shadow-lift:   none;
    /*  On dark a shadow is invisible: there is nothing lighter behind it to cast
     *  onto. A hairline border does the work instead, which is why --card-border
     *  exists. --shadow-soft has to go the same way, or a generous card on dark
     *  carries a faint grey bruise underneath it. */
    --shadow-soft:   none;
    --shadow-drawer: 0 0 60px rgba(0, 0, 0, .55);
    --card-border:   1px solid var(--c-line);
  }
}
