/* =============================================================================
   GEEKLY DESIGN TOKENS — single source of truth
   CoveredGeekly Limited

   This is the ONLY place in the theme where brand values, colour roles, type
   scale, spacing, radii, motion and layout constants are declared.

   Before this file existed the same 38-token block was duplicated verbatim in
   geekly.css and forge/forge.css, and app-topbar.css re-declared
   --topbar-height. Every consumer now reads from here, so a brand change is a
   one-file change and the public site and Forge can no longer drift apart.

   Load order: tokens.css is enqueued FIRST and every other stylesheet depends
   on it (directly or transitively).

   ---------------------------------------------------------------------------
   THEMING
   ---------------------------------------------------------------------------
   Tokens are declared in two tiers:

     1. Palette    — raw, theme-independent values (--clr-*).
     2. Semantic   — roles that describe intent (--text-*, --radius-*, ...).

   Components should consume semantic tokens. A future light theme is then a
   single override block re-pointing the palette and the semantic roles:

       [data-theme="light"] { --clr-bg-base: #FFFFFF; ... }

   `color-scheme` is declared once here so native controls, scrollbars and
   autofill render for the dark surface instead of falling back to light.
   ============================================================================= */

:root {
  color-scheme: dark;

  /* ── Brand ────────────────────────────────────────────────────────────── */
  /* Two distinct hover roles, because they need opposite directions:

       --clr-brand-hover  LIGHTENS. For brand-coloured *text* on a dark
                          surface, hover must gain prominence, not lose it.
                          #F14A5A reads 5.30:1 on --clr-bg-deep, up from
                          4.55:1 at rest. The darker value previously used
                          here dropped the same link to 3.58:1 on hover.

       --clr-brand-dark   DARKENS. For *fills* that carry white text, a
                          darker fill raises the label contrast: white on
                          #C9303C is 5.29:1 against 3.58:1 on #F14A5A.

     Using one token for both is what caused the drift this file exists to
     prevent. See docs/ui-css-architecture-audit.md.

     WHERE --clr-brand MAY CARRY TEXT. Measured across the seven surfaces:

       --clr-bg-base     4.68:1   AA  normal text
       --clr-bg-deep     4.55:1   AA  normal text
       --clr-bg-elevated 4.47:1   AA-large only
       --clr-bg-raised   4.19:1   AA-large only
       --clr-bg-surface  4.11:1   AA-large only
       --clr-bg-hover    4.01:1   AA-large only
       --clr-bg-active   3.63:1   AA-large only

     So brand-coloured normal-size text is only AA on the page backgrounds.
     On raised surfaces it is AA-large only, and it cannot be fixed by
     lightening: a saturated red at this hue tops out at 4.33:1 on
     --clr-bg-active, so passing 4.5:1 there would require desaturating the
     brand away from its identity. The rule is therefore:

       - brand TEXT at normal size, on a raised surface -> use
         --clr-brand-hover, which reaches 4.67:1 on --clr-bg-hover and 4.88:1
         on --clr-bg-raised;
       - brand FILLS carrying white text need only 3:1 as a component and are
         fine as they are;
       - brand text at 24px+, or 18.66px+ bold, is fine at rest on any surface.

     See docs/ui-css-architecture-audit.md, Phase 7. */
  --clr-brand:          #E63946;
  --clr-brand-hover:    #F14A5A;
  --clr-brand-dark:     #C9303C;

  /* ── Text ─────────────────────────────────────────────────────────────── */
  /* --clr-text-dim (#484F58) is a DECORATION token, not a text colour. It
     measures 1.83:1 on --clr-bg-active and 2.35:1 on --clr-bg-base, so no
     surface in this theme lets it satisfy SC 1.4.3 (4.5:1). Phase 7 moved all
     283 of its text uses onto --clr-text-muted; what remains is borders,
     fills and dividers, which is what a 2:1 value is good for.

     Contract C6 enforces this: `color: var(--clr-text-dim)` fails the build. */
  --clr-text-primary:   #E6EDF3;
  --clr-text-secondary: #C9D1D9;
  --clr-text-muted:     #8B949E;
  --clr-text-dim:       #484F58;

  /* ── Backgrounds (darkest to lightest) ────────────────────────────────── */
  --clr-bg-base:        #0D0C10;
  --clr-bg-deep:        #111014;
  --clr-bg-elevated:    #131217;
  --clr-bg-raised:      #1A191F;
  --clr-bg-surface:     #1C1B20;
  --clr-bg-hover:       #1E1D24;
  --clr-bg-active:      #27252C;

  /* ── Borders ──────────────────────────────────────────────────────────── */
  --clr-border:         #2E2C35;
  /* Control boundaries. --clr-border measures 1.10-1.42:1 on the theme's
     surfaces - correct for a decorative divider, but it fails SC 1.4.11 (3:1)
     wherever the border is the only thing identifying a control, which is the
     case for every input, select and textarea whose background matches the
     page. This value measures 3.30:1 on the lightest surface (--clr-bg-active)
     and 4.42:1 on --clr-bg-deep. Use it for any border that IS the control. */
  --clr-border-control: #6E7681;
  /* Structural aliases. These were previously referenced but never declared,
     so every consumer silently fell back to its inline default. Declaring them
     here resolves the reference without changing the rendered value. */
  --clr-border-subtle:  var(--clr-border);
  --clr-border-strong:  rgba(255, 255, 255, 0.14);
  --clr-border-hover:   rgba(255, 255, 255, 0.15);

  /* ── Status ───────────────────────────────────────────────────────────── */
  --clr-success:        #10B981;
  --clr-warning:        #F59E0B;
  --clr-purple:         #8B5CF6;
  --clr-green:          #4CAF50;

  /* ── Typography ───────────────────────────────────────────────────────── */
  --font-display:       'Barlow Condensed', sans-serif;
  --font-body:          'Inter', system-ui, -apple-system, sans-serif;
  --font-mono:          ui-monospace, SFMono-Regular, 'SF Mono', Menlo,
                        Consolas, 'Liberation Mono', monospace;

  /* Type scale (rem, base 16px) */
  --text-2xs:   0.5625rem;  /*  9px — micro labels, tiny badges */
  --text-xs:    0.6875rem;  /* 11px — timestamps, secondary meta */
  --text-sm:    0.8125rem;  /* 13px — UI labels, nav items, card meta */
  --text-base:  1.0625rem;  /* 17px — body text, descriptions */
  --text-md:    1.125rem;   /* 18px — slightly larger body, lead text */
  --text-lg:    1.375rem;   /* 22px — card titles, subheadings */
  --text-xl:    1.75rem;    /* 28px — section headings */
  --text-2xl:   2.5rem;     /* 40px — page headings */
  --text-3xl:   3.5rem;     /* 56px — hero titles */

  /* Line heights */
  --lh-tight:   1.1;   /* display/condensed headings */
  --lh-ui:      1.5;   /* UI elements, labels, buttons */
  --lh-reading: 1.65;  /* body text, descriptions, articles */

  /* ── Spacing ──────────────────────────────────────────────────────────── */
  /* A 4px-based scale. The theme previously had no spacing tokens at all,
     which is why 84 distinct media-query widths and hundreds of one-off
     paddings accumulated. New work should compose from these. */
  --space-0:  0;
  --space-1:  0.25rem;   /*  4px */
  --space-2:  0.5rem;    /*  8px */
  --space-3:  0.75rem;   /* 12px */
  --space-4:  1rem;      /* 16px */
  --space-5:  1.25rem;   /* 20px */
  --space-6:  1.5rem;    /* 24px */
  --space-8:  2rem;      /* 32px */
  --space-10: 2.5rem;    /* 40px */
  --space-12: 3rem;      /* 48px */
  --space-16: 4rem;      /* 64px */
  --space-20: 5rem;      /* 80px */

  /* ── Radii ────────────────────────────────────────────────────────────── */
  --radius-sm:          4px;
  --radius-md:          8px;
  --radius-lg:          12px;

  /* ── Motion ───────────────────────────────────────────────────────────── */
  --transition-fast:    0.15s ease;
  --transition-med:     0.25s ease;
  /* Standard deceleration curve for elements arriving on screen. Declared
     here because ~18 declarations already referenced it with an inline
     `ease` fallback that was masking the missing token. */
  --ease-out:           cubic-bezier(0.22, 1, 0.36, 1);

  /* ── Focus ────────────────────────────────────────────────────────────── */
  /* One accessible focus ring for the whole network. --topbar-focus-color
     already used this value, so the shared ring is a lightened brand tint
     that stays legible on every dark surface in the palette. */
  --focus-ring-color:   #FFB4BA;
  --focus-ring-width:   2px;
  --focus-ring-offset:  2px;

  /* ── Layout ───────────────────────────────────────────────────────────── */
  --layout-max:         1400px;  /* outer container max-width */
  --article-max:        780px;   /* article body max-width (optimal reading width) */
  --nav-sidebar-width:  260px;   /* left navigation sidebar */
  --main-padding-lg:    32px;    /* geekly-main horizontal padding at 1280px+ */

  /* ── Chrome heights (used for sticky offsets, margin-top, scroll-margin-top) ── */
  --topbar-height:      56px;    /* fixed top navigation bar */
  --mobile-bar-h:       48px;    /* secondary mobile topbar (logged-in only) */

  /* ── Z-index scale ────────────────────────────────────────────────────── */
  /* The theme currently ships 63 distinct z-index values, several of which
     exceed the CSS maximum and are therefore clamped by the browser. New work
     must use this ladder; existing values are being migrated in phases. */
  --z-base:        0;
  --z-raised:      1;
  --z-dropdown:    100;
  --z-sticky:      200;
  --z-sidebar:     300;
  --z-overlay:     400;
  --z-modal:       500;
  --z-popover:     600;
  --z-toast:       700;
  --z-top:         1000;

  /* -------------------------------------------------------------------------
     CANONICAL BREAKPOINT SCALE
     -------------------------------------------------------------------------
     CSS custom properties cannot be used inside media-query preludes, so the
     scale is documented here and enforced by validate-css-architecture.py
     (contract C3), which runs in CI.

     A boundary N is written `max-width: N-1` for the last pixel below it and
     `min-width: N` for the first pixel at it, so the two never overlap.

        boundary   max-width   min-width   covers
        --------   ---------   ---------   ---------------------------------
            375        374         375     small phones (iPhone SE/8)
            430        429         430     large phones (Pro Max)
            480        479         480     phone landscape
            560        559         560     large phone landscape
            600        599         600     small tablets
            640        639         640     tablet portrait
            700        699         700     large tablet portrait
            768        767         768     tablets (iPad)
            820        819         820     iPad Air
            900        899         900     tablet landscape / small laptop
            980        979         980     narrow laptop
           1024       1023        1024     iPad landscape / laptop
           1100       1099        1100     small desktop
           1200       1199        1200     desktop
           1280       1279        1280     wide desktop
           1440       1439        1440     large desktop
           1600       1599        1600     extra large desktop

     Usage:  @media (max-width: 767px) { ... }

     HOW THIS SCALE WAS CHOSEN. It was not picked by eye. Phase 4 originally
     assumed the theme's 84 distinct widths were mostly drift; measuring them
     showed 46% sat more than 20px from any of the six steps then in use, and
     that they were spread across the device range rather than clustered. So the
     scale was derived instead: a weighted k-median over every media query in
     the theme, constrained to widths that correspond to real device viewports
     (tools/css-audit/bp_derive_scale2.py). This set minimises total pixel
     displacement - mean 6.4px across 1,015 queries - and 52% of all queries
     were already exactly on it before migration.

     All new work must use one of these. The C3 contract is axis-aware: a
     max-width query must use the max-width column and a min-width query the
     min-width column.

     See docs/ui-css-architecture-audit.md, Phase 4, for the full derivation
     and the impact report for the 95 rules whose coverage moved more than 20px.
     ------------------------------------------------------------------------- */
}
