/* ============================================================================
   TerraMap Design Tokens
   Companion to docs/design-system.md. Linked directly by every public page.

   Prefixed --tm- throughout: MapLibre ships its own stylesheet and the map is
   a first-class element here, not an embed. Unprefixed tokens would collide.

   Governing rule (revised): the map is the strongest PRODUCT visual, but
   primary CTAs must retain clear visual prominence and accessibility. The
   palette is built so both can be true at once — see --tm-primary.

   Theming has three states, matching how the map itself behaves:
     - :root                          light
     - @media (prefers-color-scheme)  follows the OS
     - [data-theme="dark"|"light"]    an explicit user choice, wins both ways
   Every colour is defined on :root first, so no token exists only inside a
   media query.
   ========================================================================= */

/* ── Reference: the actual map colours these tokens are derived FROM ────────
   Not for direct use. Recorded so the derivation can be checked, and so a
   change to style.json can be traced through to the site palette.

   day    land #F8F7F7 · water #91D3E7→#9FD7EB · forest #AFE2C3→#D9F6E3
          park #CBEFD6 · roads #98ABC8→#8EA3BD · road casing #758EAD
   night  land #141617 · water #0F272E · park #1F3A27
          roads #5D6F8B · casing #2E3948 · labels #B9C0C8→#D7D4CF
   ------------------------------------------------------------------------- */

:root {
  /* ── Brand ────────────────────────────────────────────────────────────────
     Primary is a deep cartographic blue sitting BETWEEN the map's water hue
     (~194°) and its road hue (~214°), at a saturation and darkness neither
     surface ever reaches. That is deliberate: the CTA has to be unmistakably
     UI, never mistaken for geography, and it has to hold its own ON TOP of
     the map rather than yield to it.
     Verified against every surface it can land on (WCAG 1.4.11 wants 3:1 for
     a control silhouette): vs map water 5.18, vs forest 7.06, vs land 7.60.
     White label on primary: 8.13. */
  --tm-primary:            #0A5578;
  --tm-primary-hover:      #073F5B;
  --tm-primary-active:     #052F45;
  --tm-primary-contrast:   #FFFFFF;
  --tm-primary-subtle:     #E7F0F6;   /* tinted fills, selected nav, badges  */
  --tm-primary-ring:       rgba(10, 85, 120, 0.32);

  /* Accent — ochre. The map is almost entirely cool; the one warm note in
     cartography is the elevation/contour tint, so this reads as map-native
     rather than as decoration. Used sparingly: never a second CTA.
     Split into two values because the graphic tone fails text contrast.  */
  --tm-accent:             #B26A16;   /* graphics, rules, chart marks  4.23:1 */
  --tm-accent-text:        #8A5310;   /* the same idea, legible        6.31:1 */
  --tm-accent-subtle:      #FBF1E4;

  /* ── Surfaces ─────────────────────────────────────────────────────────────
     Planes are judged in CIE L*, not contrast ratio — adjacent surfaces are
     meant to be subtle and a legibility metric says nothing useful about
     them. 2-6 points of L* reads as a distinct plane. */
  --tm-bg:                 #F6F8FA;   /* page                                */
  --tm-surface:            #FFFFFF;   /* cards, navbar          ΔL* 2.5      */
  --tm-surface-elevated:   #FFFFFF;   /* menus, popovers — lifted by shadow  */
  --tm-surface-sunken:     #EEF1F5;   /* code blocks, wells                  */

  /* ── Text ─────────────────────────────────────────────────────────────── */
  --tm-text:               #101820;   /* 16.81:1 on bg                       */
  --tm-text-muted:         #59636E;   /*  5.74:1 on bg                       */
  --tm-text-subtle:        #7A838D;   /* graphical lines; not small text     */
  --tm-text-inverse:       #FFFFFF;

  /* ── Lines ────────────────────────────────────────────────────────────── */
  --tm-border:             #DFE4EA;
  --tm-border-strong:      #C6CED7;   /* inputs, map container               */
  --tm-divider:            #EAEEF2;

  /* ── Status. Green is the map's land colour family, so success is pushed
     deeper than the map ever goes — a green pill must not read as terrain. */
  --tm-success:            #2F7D4F;
  --tm-success-subtle:     #E6F3EB;
  --tm-warning:            #8A5308;
  --tm-warning-subtle:     #FBF1E0;
  --tm-error:              #B3261E;
  --tm-error-subtle:       #FBEAE8;
  --tm-info:               var(--tm-primary);
  --tm-info-subtle:        var(--tm-primary-subtle);

  /* ── Map chrome. The map paints its own world; these are only for the UI
     laid over it, which must stay legible above any tile underneath. */
  --tm-map-frame:          #C6CED7;
  --tm-map-control-bg:     rgba(255, 255, 255, 0.94);
  --tm-map-control-border: rgba(16, 24, 32, 0.10);
  --tm-map-scrim:          linear-gradient(to bottom,
                             rgba(246, 248, 250, 0.00) 0%,
                             rgba(246, 248, 250, 0.72) 62%,
                             rgba(246, 248, 250, 0.94) 100%);

  /* ── Shadows. Tinted with the ink blue, never neutral black: a black
     shadow on a cool palette reads as dirt. */
  --tm-shadow-xs:  0 1px 2px rgba(16, 24, 32, 0.05);
  --tm-shadow-sm:  0 1px 3px rgba(16, 24, 32, 0.07), 0 1px 2px rgba(16, 24, 32, 0.04);
  --tm-shadow-md:  0 4px 12px rgba(16, 24, 32, 0.08), 0 1px 3px rgba(16, 24, 32, 0.05);
  --tm-shadow-lg:  0 12px 28px rgba(16, 24, 32, 0.10), 0 2px 6px rgba(16, 24, 32, 0.05);
  --tm-shadow-map: 0 1px 2px rgba(16, 24, 32, 0.06), 0 16px 40px rgba(16, 24, 32, 0.10);
}

/* ── Dark, when the OS asks for it and the user has not overridden ───────── */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --tm-primary:            #3FA9D6;
    --tm-primary-hover:      #5CBBE2;
    --tm-primary-active:     #2E93BE;
    --tm-primary-contrast:   #06212D;   /* ink on bright blue — 6.22:1       */
    --tm-primary-subtle:     #102A38;
    --tm-primary-ring:       rgba(63, 169, 214, 0.40);

    --tm-accent:             #E0A45C;
    --tm-accent-text:        #E0A45C;   /* 8.18:1 on surface — one value here */
    --tm-accent-subtle:      #2A2015;

    /* Page sits BELOW the map's own darkest ground (#141617) so the map reads
       as an object on the page rather than bleeding into it. ΔL* 4.4. */
    --tm-bg:                 #070A0E;
    --tm-surface:            #111721;
    --tm-surface-elevated:   #18202B;
    --tm-surface-sunken:     #0C1119;

    --tm-text:               #E7ECF2;
    --tm-text-muted:         #93A0AE;
    --tm-text-subtle:        #6D7987;
    --tm-text-inverse:       #070A0E;

    --tm-border:             #232C38;
    --tm-border-strong:      #35404E;
    --tm-divider:            #1B2330;

    --tm-success:            #4FB07A;
    --tm-success-subtle:     #10261B;
    --tm-warning:            #D9A441;
    --tm-warning-subtle:     #2A2113;
    --tm-error:              #E5786F;
    --tm-error-subtle:       #2C1614;

    --tm-map-frame:          #2B3542;
    --tm-map-control-bg:     rgba(17, 23, 33, 0.92);
    --tm-map-control-border: rgba(231, 236, 242, 0.14);
    --tm-map-scrim:          linear-gradient(to bottom,
                               rgba(7, 10, 14, 0.00) 0%,
                               rgba(7, 10, 14, 0.72) 62%,
                               rgba(7, 10, 14, 0.94) 100%);

    /* Shadows barely register on dark. Elevation is carried by border and
       surface lightness instead; these stay only to seat large objects. */
    --tm-shadow-xs:  0 1px 2px rgba(0, 0, 0, 0.40);
    --tm-shadow-sm:  0 1px 3px rgba(0, 0, 0, 0.45);
    --tm-shadow-md:  0 4px 14px rgba(0, 0, 0, 0.50);
    --tm-shadow-lg:  0 14px 34px rgba(0, 0, 0, 0.55);
    --tm-shadow-map: 0 18px 44px rgba(0, 0, 0, 0.60);
  }
}

/* ── Dark, chosen explicitly. Same values; wins regardless of the OS. ────── */
[data-theme="dark"] {
  --tm-primary:            #3FA9D6;
  --tm-primary-hover:      #5CBBE2;
  --tm-primary-active:     #2E93BE;
  --tm-primary-contrast:   #06212D;
  --tm-primary-subtle:     #102A38;
  --tm-primary-ring:       rgba(63, 169, 214, 0.40);

  --tm-accent:             #E0A45C;
  --tm-accent-text:        #E0A45C;
  --tm-accent-subtle:      #2A2015;

  --tm-bg:                 #070A0E;
  --tm-surface:            #111721;
  --tm-surface-elevated:   #18202B;
  --tm-surface-sunken:     #0C1119;

  --tm-text:               #E7ECF2;
  --tm-text-muted:         #93A0AE;
  --tm-text-subtle:        #6D7987;
  --tm-text-inverse:       #070A0E;

  --tm-border:             #232C38;
  --tm-border-strong:      #35404E;
  --tm-divider:            #1B2330;

  --tm-success:            #4FB07A;
  --tm-success-subtle:     #10261B;
  --tm-warning:            #D9A441;
  --tm-warning-subtle:     #2A2113;
  --tm-error:              #E5786F;
  --tm-error-subtle:       #2C1614;

  --tm-map-frame:          #2B3542;
  --tm-map-control-bg:     rgba(17, 23, 33, 0.92);
  --tm-map-control-border: rgba(231, 236, 242, 0.14);
  --tm-map-scrim:          linear-gradient(to bottom,
                             rgba(7, 10, 14, 0.00) 0%,
                             rgba(7, 10, 14, 0.72) 62%,
                             rgba(7, 10, 14, 0.94) 100%);

  --tm-shadow-xs:  0 1px 2px rgba(0, 0, 0, 0.40);
  --tm-shadow-sm:  0 1px 3px rgba(0, 0, 0, 0.45);
  --tm-shadow-md:  0 4px 14px rgba(0, 0, 0, 0.50);
  --tm-shadow-lg:  0 14px 34px rgba(0, 0, 0, 0.55);
  --tm-shadow-map: 0 18px 44px rgba(0, 0, 0, 0.60);
}

/* ============================================================================
   Typography
   ========================================================================= */

:root {
  --tm-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
                  Roboto, "Helvetica Neue", Arial, sans-serif;
  --tm-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo,
                  Consolas, "Liberation Mono", monospace;

  /* Inter's defaults are set for maximum neutrality. These three features are
     what stop it reading as the stock SaaS default:
       cv05  single-storey l with a tail — disambiguates l/1/I
       ss03  a flat-topped, less geometric 'a'
       tnum  tabular figures, so credit counts and latencies do not jitter */
  --tm-font-features: "cv05" 1, "ss03" 1, "tnum" 1;
  --tm-font-features-display: "cv05" 1, "ss03" 1;

  /* Fluid, clamped between the mobile and desktop sizes in the spec.
     Hero drops hard on mobile: a 64px headline on a 390px screen wraps to
     four lines and destroys the five-second test. */
  /* 38 -> 52 base range. The homepage applies a 50px wide-desktop cap because
     the loaded Inter metrics need that final 2px reduction for both sentences
     to remain one physical line inside the 45% copy column. Measured by text
     ranges in dev/shoot-site.mjs rather than by the spans' block rectangles. */
  --tm-text-hero:      clamp(2.375rem, 1.62rem + 3.24vw, 3.25rem);  /* 38 → 52 */
  --tm-text-h1:        clamp(2.000rem, 1.34rem + 2.83vw, 3.00rem);  /* 32 → 48 */
  --tm-text-h2:        clamp(1.625rem, 1.29rem + 1.42vw, 2.125rem); /* 26 → 34 */
  --tm-text-h3:        clamp(1.1875rem, 1.06rem + 0.53vw, 1.375rem);/* 19 → 22 */
  --tm-text-body-lg:   clamp(1.0625rem, 1.03rem + 0.14vw, 1.125rem);/* 17 → 18 */
  --tm-text-body:      1rem;                                        /* 16      */
  --tm-text-sm:        0.875rem;                                    /* 14      */
  --tm-text-caption:   0.78125rem;                                  /* 12.5    */
  --tm-text-code:      0.875rem;
  --tm-text-code-sm:   0.8125rem;

  --tm-leading-hero:   1.04;
  --tm-leading-tight:  1.16;
  --tm-leading-snug:   1.32;
  --tm-leading-normal: 1.55;
  --tm-leading-relaxed:1.68;

  /* Large type needs negative tracking to stop looking loose; small type needs
     none. This is the single biggest lever on whether a headline reads as
     designed or as default. */
  --tm-tracking-hero:  -0.028em;
  --tm-tracking-h1:    -0.022em;
  --tm-tracking-h2:    -0.016em;
  --tm-tracking-h3:    -0.010em;
  --tm-tracking-body:   0;
  --tm-tracking-eyebrow: 0.09em;

  --tm-weight-regular: 400;
  --tm-weight-medium:  500;
  --tm-weight-semibold:600;
  --tm-weight-bold:    700;

  --tm-measure:        68ch;   /* body copy never runs wider than this */
  --tm-measure-narrow: 52ch;
}

/* ============================================================================
   Space, layout, radius
   ========================================================================= */

:root {
  /* 4px base. Steps get coarser as they grow — nobody needs 4px precision at
     the 96px end, and a purely linear scale invites arbitrary choices. */
  --tm-space-1:   0.25rem;   /*   4 */
  --tm-space-2:   0.5rem;    /*   8 */
  --tm-space-3:   0.75rem;   /*  12 */
  --tm-space-4:   1rem;      /*  16 */
  --tm-space-5:   1.5rem;    /*  24 */
  --tm-space-6:   2rem;      /*  32 */
  --tm-space-7:   3rem;      /*  48 */
  --tm-space-8:   4rem;      /*  64 */
  --tm-space-9:   6rem;      /*  96 */
  --tm-space-10:  8rem;      /* 128 */

  --tm-container:       1200px;  /* text and cards                */
  --tm-container-wide:  1440px;  /* map sections only             */
  --tm-container-prose:  720px;  /* docs and long-form            */
  --tm-gutter:          2rem;    /* desktop                       */
  --tm-gutter-mobile:   1.25rem; /* 20px — 16 is tight for cards  */

  /* Fixed chrome and named layout splits, so the hero ratio and the sticky
     offsets live in one place rather than being retyped per page. */
  --tm-navbar-height:   64px;
  --tm-sidebar-width:   260px;  /* developer navigation          */
  --tm-hero-copy:       45%;    /* desktop hero: copy column     */
  --tm-hero-map:        55%;    /* desktop hero: map column      */

  /* SECTION RHYTHM.
     Was 96/64. At 96 the rules between sections sat in so much air that each
     section read as a separate page rather than as part of one, which is the
     opposite of what a divider is for. 64 still breathes and lets a reader
     see that two sections belong together. */
  --tm-section-y:        var(--tm-space-8);   /* 64 desktop */
  --tm-section-y-tablet: 52px;                /* 52 tablet  */
  --tm-section-y-mobile: 44px;                /* 44 mobile  */
  --tm-section-y-tight:  var(--tm-space-6);

  /* Restrained by instruction. Nothing is a pill except badges — a pill-shaped
     button is the single loudest "generic SaaS" signal there is. */
  --tm-radius-xs:  2px;
  --tm-radius-sm:  4px;
  --tm-radius-md:  6px;    /* buttons, inputs        */
  --tm-radius-lg:  10px;   /* cards, code blocks     */
  --tm-radius-xl:  14px;   /* map container          */
  --tm-radius-pill: 999px; /* badges only            */

  --tm-border-width: 1px;
  --tm-focus-width:  2px;
  --tm-focus-offset: 2px;
}

/* One step down at tablet, another at phone, so the rhythm tightens with the
   viewport instead of jumping straight from desktop to mobile. */
@media (max-width: 1023px) {
  :root { --tm-section-y: var(--tm-section-y-tablet); }
}

@media (max-width: 767px) {
  :root {
    --tm-gutter:    var(--tm-gutter-mobile);
    --tm-section-y: var(--tm-section-y-mobile);
  }
}

/* ============================================================================
   Motion

   One easing curve, three durations. The curve is asymmetric — quick to leave,
   slow to settle — which is how a map behaves when you release a pan. Reusing
   the product's physics in the interface is most of what makes a site feel
   like an extension of the product rather than a wrapper around it.
   ========================================================================= */

:root {
  --tm-ease:          cubic-bezier(0.20, 0.00, 0.00, 1.00);
  --tm-ease-out:      cubic-bezier(0.16, 1.00, 0.30, 1.00);
  --tm-ease-in-out:   cubic-bezier(0.65, 0.00, 0.35, 1.00);

  --tm-duration-fast: 120ms;   /* hover, focus, colour            */
  --tm-duration-base: 180ms;   /* menus, disclosure               */
  --tm-duration-slow: 240ms;   /* theme switch, panel transitions */

  /* There is NO idle map animation. An earlier draft proposed a slow zoom
     drift in the hero; it was removed. The map loads naturally and stays
     interactive — a map that moves on its own is fighting the visitor for
     control of the one element that is meant to prove the product works. */

  --tm-transition-color:
    color var(--tm-duration-fast) var(--tm-ease),
    background-color var(--tm-duration-fast) var(--tm-ease),
    border-color var(--tm-duration-fast) var(--tm-ease);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --tm-duration-fast: 1ms;
    --tm-duration-base: 1ms;
    --tm-duration-slow: 1ms;
  }
}

/* ============================================================================
   Stacking. Named so nobody writes z-index: 9999 at 2am.
   ========================================================================= */

:root {
  --tm-z-base:     0;
  --tm-z-map-ui:  10;   /* controls sitting on the map   */
  --tm-z-sticky:  20;   /* sticky section headers        */
  --tm-z-navbar:  30;
  --tm-z-dropdown:40;
  --tm-z-overlay: 50;   /* mobile nav, dialogs           */
  --tm-z-toast:   60;
}
