/* ─────────────────────────────────────────────────────────────────────────────
   sandbeach — design tokens (single source of truth)
   Engine: Ollef's fluid root — body font-size scales with the viewport and the
   ENTIRE design is em-based, so one dial scales type, spacing and layout
   together. Tokens below are the only place values live; components never
   hardcode sizes or colors.
   Recolor path: swap the raw palette or the semantic aliases; context blocks
   (.theme-dark / .theme-light) feed every component via --_bg/--_text/…
   ──────────────────────────────────────────────────────────────────────────── */

@layer tokens {

:root {
  /* ── raw palette (Ollef exact) + brand accent ─────────────────────────── */
  --color-white:    #ffffff;
  --color-grey-200: #e5e5e5;
  --color-grey-500: #8a8a8a;   /* muted ON DARK — 5.6:1 on grey-950 (AA body) */
  --color-grey-600: #6e6e6e;   /* muted ON LIGHT — 5.1:1 on white; fails on dark */
  --color-grey-900: #252525;
  --color-grey-950: #0d0d0d;
  --color-sand:     #d8b888;   /* mockup's warm sand; the "beach colors" dial */

  /* ── semantic colors (dark-first) ─────────────────────────────────────── */
  --bg-page:    var(--color-grey-950);  /* dark slabs + page ground          */
  --bg-under:   var(--color-grey-200);  /* body behind slabs (footer reveal) */
  --bg-inverse: var(--color-white);     /* the light slab                    */
  --accent:     var(--color-sand);      /* links/buttons; monochrome = grey-200 */

  /* ── typography ───────────────────────────────────────────────────────── */
  --font-brand: "BDO Grotesk", Arial, sans-serif;

  --text-m:    1.125em;   /* body base            */
  --h6:        1.375em;
  --h5:        1.625em;   /* "heading-s" role     */
  --h4:        1.875em;   /* "heading-m" role     */
  --h3:        2.125em;
  --h2:        2.25em;
  --h1:        2.5em;     /* "heading-l" role     */
  --display-2: 3.875em;   /* "heading-xl" role    */
  --display:   6.75em;    /* service-row size     */

  --lh-tight:   104%;     /* display + xl headings */
  --lh-heading: 116%;     /* m/l headings          */
  --lh-body:    1.24;

  --ls-1: -0.02em;        /* body + s/m headings  */
  --ls-2: -0.035em;       /* h1 / heading-l       */
  --ls-3: -0.045em;       /* display-2            */
  --ls-4: -0.048em;       /* display              */

  /* ── spacing scale (Ollef steps, ACSS ladder) ─────────────────────────── */
  --space-3xs: 0.25em;
  --space-2xs: 0.5em;
  --space-xs:  0.75em;
  --space-s:   1em;
  --space-m:   1.5em;
  --space-l:   2em;
  --space-xl:  3em;
  --space-2xl: 4em;
  --space-3xl: 6em;

  /* section rhythm (between/inside big slabs) */
  --section-space-s:  6em;
  --section-space-m:  8.5em;
  --section-space-l:  13.75em;

  /* ── layout ───────────────────────────────────────────────────────────── */
  --brand-mark-size:   8.6vw;   /* giant logotype, fills the row width       */
  --gutter:            1.25em;  /* grid gap everywhere                       */
  --container-padding: 2em;     /* page edge; 1.75em under 991               */
  --radius-field:      0.6em;   /* form inputs                               */
  --radius-pill:       10em;    /* buttons                                   */
  --hairline:          1px;     /* the only px in the system (borders)       */

  /* ── atmosphere (dark slabs only) ─────────────────────────────────────── */
  /* Two dials for the sand haze + film grain that keep the black from reading
     flat. Grain is a texture, not layout: it must stay one physical size at
     every breakpoint, so the tile is the second and last px in the system
     (--hairline is the first). Scaling it with the em engine would blow it up
     into visible dots on mobile. */
  --grain-tile:     10rem;   /* 160px, viewport-independent by design */
  --grain-strength: 1;    /* opacity of the overlay-blended noise    */
  --haze-strength:  10.35%;  /* sand mixed into the ground at blob core */

  /* ── motion ───────────────────────────────────────────────────────────── */
  /* One deceleration for the whole site. This curve is the CSS twin of GSAP's
     expo.out, which app.js uses by name — CSS states and JS sequences must not
     land on two different curves. */
  --ease-out:   cubic-bezier(.16, 1, .3, 1);
  --dur-tap:    0.15s;   /* immediate feedback   */
  --dur-fast:   0.4s;    /* routine state change */
  --dur-med:    0.7s;    /* overlay / view       */
  --dur-slow:   1.1s;    /* authored entrance    */

  /* tap-target padding for inline text links (WCAG 2.5.8 needs ≥24px) */
  --link-pad:   0.4em;
}

/* ── context system: every component reads these, never raw colors ──────── */
.theme-dark {
  --_bg:    var(--bg-page);
  --_text:  var(--color-grey-200);
  --_muted: var(--color-grey-500);   /* grey-600 measures 3.81:1 here — too low */
  --_line:  var(--color-grey-900);
  --_focus: var(--accent);
  background-color: var(--_bg);
  color: var(--_text);
}
.theme-light {
  --_bg:    var(--bg-inverse);
  --_text:  var(--color-grey-950);
  --_muted: var(--color-grey-600);
  --_line:  var(--color-grey-200);
  --_focus: var(--color-grey-950);
  background-color: var(--_bg);
  color: var(--_text);
}

/* ── fluid root (Ollef engine, px-free) ─────────────────────────────────── */
body {
  font-size: 1.25vw;
}
@media screen and (min-width: 120em) {          /* 1920px */
  body { font-size: clamp(1.125rem, 1.042vw, 1.25rem); }
}
@media screen and (max-width: 61.94em) {        /* 991px  */
  :root { --container-padding: 1.75em; --display: 6em; }
}
@media screen and (max-width: 47.94em) {        /* 767px  */
  body { font-size: 2.347vw; }
  :root { --display: 12vw; }
}
@media screen and (max-width: 29.94em) {        /* 479px  */
  body { font-size: 3.226vw; }
  :root { --display-2: 10.5vw; }
}

} /* @layer tokens */
