/* ── Someone Song — Design Tokens ──
 *
 * Single source of truth for colour, space, type, radius, elevation and motion.
 * Nothing below this file should contain a raw hex, rgba(), or magic px value;
 * page stylesheets consume these tokens so a brand change happens here only.
 *
 * ── How to rebrand ──
 * Change --hue-brand (and optionally --hue-accent / --chroma-brand) in the
 * "Brand knobs" block. Every rose/mauve surface, border, tint, gradient, focus
 * ring and shadow across the site is derived from those, so the whole product
 * moves together. To rescale the layout, change --sp-unit.
 *
 * ── Naming ──
 *   --brand-*   the primary brand hue (currently rose)
 *   --accent-*  the secondary brand hue (currently mauve)
 *   --tint-*    white at increasing alpha — raised surfaces on a dark ground
 *   --scrim-*   black at increasing alpha — overlays, shadows, media scrims
 *   --sp-*      spacing scale        --fs-* type scale        --r-* radii
 *   --dur-* / --ease-*  motion
 *
 * Legacy names (--rose, --glass, --border, --t1, --max, --radius …) are kept as
 * aliases so the existing page stylesheets keep working. Prefer the new names
 * in anything you write from here on.
 */

:root {
  /* ─────────────────────────────────────────────
     Brand knobs — the whole palette derives from these five numbers
     ───────────────────────────────────────────── */
  /* Sampled from the logo mark (static/images/logo/logo-horizontal.svg), which
     is a violet-to-pink ramp: the pink end sits at hue 357, the violet end at
     hue 316, and the mark's true chroma is 0.207.

     Note on chroma: an earlier pass took the MEDIAN chroma of the logo's
     pixels, which came out at 0.19. That was wrong — the logo is auto-traced,
     so anti-aliased edge pixels are desaturated and drag the median down. The
     peak chroma (0.207) is the real brand colour; the median made every brand
     surface read slightly dull, which was especially visible once the page
     background went to near-black. */
  --hue-brand: 357;       /* pink end of the logo ramp   */
  --hue-accent: 316;      /* violet end of the logo ramp */
  --hue-surface: 292;     /* the violet cast in every dark surface */
  --hue-gold: 75;         /* gold  */
  --chroma-brand: 0.207;
  --chroma-accent: 0.19;

  /* ── Ground ──
     The page sits at near-black (L 0.045) with only a trace of the surface hue
     — enough that it reads as considered rather than clinically flat, and it
     goes fully black on OLED. Cards deliberately did NOT drop with it: the
     page-to-card step is now 0.115 rather than 0.057, so surfaces lift clearly
     off the background instead of blending into it. Dropping the whole ladder
     together was tried and pushed cards to #040309, which vanished. */
  --bg: oklch(0.045 0.012 var(--hue-surface));
  --bg-deep: oklch(0.025 0.008 var(--hue-surface));

  /* ── Brand (primary) ── */
  --brand: oklch(0.63 var(--chroma-brand) var(--hue-brand));
  --brand-bright: oklch(0.72 var(--chroma-brand) var(--hue-brand));
  --brand-deep: oklch(0.52 var(--chroma-brand) var(--hue-brand));
  --brand-mid: oklch(0.63 var(--chroma-brand) var(--hue-brand) / 0.40);
  --brand-dim: oklch(0.63 var(--chroma-brand) var(--hue-brand) / 0.16);
  --brand-faint: oklch(0.63 var(--chroma-brand) var(--hue-brand) / 0.06);

  /* ── Accent (secondary) ── */
  --accent: oklch(0.60 var(--chroma-accent) var(--hue-accent));
  --accent-deep: oklch(0.52 var(--chroma-accent) calc(var(--hue-accent) + 15));
  --accent-mid: oklch(0.60 var(--chroma-accent) var(--hue-accent) / 0.40);
  --accent-dim: oklch(0.60 var(--chroma-accent) var(--hue-accent) / 0.14);

  /* ── Gold ── */
  --gold: oklch(0.78 0.12 var(--hue-gold));
  --gold-mid: oklch(0.78 0.12 var(--hue-gold) / 0.28);
  --gold-dim: oklch(0.78 0.12 var(--hue-gold) / 0.22);

  /* ── Semantic status ──
     Each has a text-weight base, a 0.40 border (-mid) and a 0.14 fill (-dim),
     which is the shape every status pill and badge in the product uses. */
  --ok: oklch(0.70 0.13 155);
  --ok-mid: oklch(0.70 0.13 155 / 0.40);
  --ok-dim: oklch(0.70 0.13 155 / 0.14);

  --info: oklch(0.72 0.10 250);
  --info-mid: oklch(0.72 0.10 250 / 0.40);
  --info-dim: oklch(0.72 0.10 250 / 0.14);

  --warn: oklch(0.76 0.12 85);
  --warn-mid: oklch(0.76 0.12 85 / 0.40);
  --warn-dim: oklch(0.76 0.12 85 / 0.14);

  --danger: oklch(0.68 0.16 25);
  --danger-mid: oklch(0.68 0.16 25 / 0.42);
  --danger-dim: oklch(0.68 0.16 25 / 0.14);

  --muted-mid: oklch(0.65 0 0 / 0.32);
  --muted-dim: oklch(0.65 0 0 / 0.12);

  /* Background at partial alpha — sticky headers and veils over content */
  --bg-veil: oklch(0.045 0.012 var(--hue-surface) / 0.92);
  --bg-veil-soft: oklch(0.045 0.012 var(--hue-surface) / 0.78);

  /* Deep veils, for fading artwork and audio surfaces out to the page ground.
     Kept as a scale because gift/player use five stops of the same colour. */
  --veil-00: oklch(0.025 0.008 var(--hue-surface) / 0);
  --veil-25: oklch(0.025 0.008 var(--hue-surface) / 0.25);
  --veil-55: oklch(0.025 0.008 var(--hue-surface) / 0.55);
  --veil-72: oklch(0.025 0.008 var(--hue-surface) / 0.72);
  --veil-85: oklch(0.025 0.008 var(--hue-surface) / 0.85);
  --surface-veil: oklch(0.160 0.026 var(--hue-surface) / 0.94);

  /* ── Documented exceptions ──
     These are deliberately NOT derived from the brand knobs. Rebranding must
     not touch them: the first is a third-party brand mark, the rest are the
     neutral greys of the vinyl-record illustration in the player, which should
     stay grey whatever colour the product becomes. */
  --color-whatsapp: #25d366;
  --record-edge: #5b5768;
  --record-face: #2f2c3a;
  --record-groove: #777288;
  --record-label: #d5d1e6;
  --record-shadow: #393645;

  /* ─────────────────────────────────────────────
     Surfaces — opaque, so nothing shimmers as it scrolls
     ───────────────────────────────────────────── */
  --surface: oklch(0.160 0.026 var(--hue-surface));
  --surface-hi: oklch(0.195 0.034 var(--hue-surface));
  --surface-raised: oklch(0.225 0.040 var(--hue-surface));

  /* ── Borders ── */
  --border: oklch(0.215 0.038 var(--hue-surface));
  --border-hi: oklch(0.275 0.060 var(--hue-surface));
  --border-brand: oklch(0.63 var(--chroma-brand) var(--hue-brand) / 0.32);

  /* ─────────────────────────────────────────────
     Tint / scrim scales — replaces ~40 one-off rgba() values
     ───────────────────────────────────────────── */
  /* Steps chosen to match the alphas already in use, so migrating existing
     one-off rgba() values snaps to a step instead of shifting the design. */
  --tint-01: rgba(255, 255, 255, 0.02);
  --tint-02: rgba(255, 255, 255, 0.035);
  --tint-03: rgba(255, 255, 255, 0.05);
  --tint-04: rgba(255, 255, 255, 0.08);
  --tint-05: rgba(255, 255, 255, 0.12);
  --tint-06: rgba(255, 255, 255, 0.16);
  --tint-07: rgba(255, 255, 255, 0.25);
  --tint-08: rgba(255, 255, 255, 0.45);
  --tint-09: rgba(255, 255, 255, 0.75);

  --scrim-01: rgba(0, 0, 0, 0.20);
  --scrim-02: rgba(0, 0, 0, 0.30);
  --scrim-03: rgba(0, 0, 0, 0.40);
  --scrim-04: rgba(0, 0, 0, 0.55);
  --scrim-05: rgba(0, 0, 0, 0.70);
  --scrim-06: rgba(0, 0, 0, 0.85);

  /* ── Text ── */
  --t1: rgba(255, 255, 255, 0.96);
  --t2: rgba(255, 255, 255, 0.68);
  --t3: rgba(255, 255, 255, 0.42);

  /* Primary action — the logo mark's own pink, one notch down in lightness.
     The logo's exact pink (#d83582, L 0.600) carries white text at only
     4.41:1, just under the 4.5 AA floor for this button's 15px/600 label.
     L 0.59 gives #d4317f at 4.60:1 — indistinguishable from the mark to the
     eye, but accessible. */
  --action: oklch(0.59 var(--chroma-brand) var(--hue-brand));
  --action-hover: oklch(0.66 var(--chroma-brand) var(--hue-brand));
  --action-fg: #fff;

  /* ─────────────────────────────────────────────
     Gradients — the brand ramp was written 12 different ways; now it is one
     ───────────────────────────────────────────── */
  --grad-brand: linear-gradient(135deg, var(--brand), var(--accent-deep));
  --grad-brand-flat: linear-gradient(90deg, var(--brand), var(--accent));
  --grad-brand-wash: linear-gradient(145deg, var(--brand-dim), var(--accent-dim));
  --grad-surface: linear-gradient(145deg, var(--surface-hi), var(--surface));
  --grad-veil: linear-gradient(180deg, transparent, var(--bg));

  /* ─────────────────────────────────────────────
     Space
     ─────────────────────────────────────────────
     Tokens are named for the pixel value they produce at the default scale,
     so --sp-16 is 16px. The steps are 2px-granular because that is the system
     the product already used: 10, 14, 18 and 22 make up roughly 40% of all
     spacing in the codebase, and snapping those to a 4px grid would have been
     a silent redesign rather than a refactor.

     Change --sp-unit to rescale every spacing value in the product at once
     (e.g. 0.11rem for a denser UI, 0.14rem for a roomier one).

     The unit is in rem, so spacing grows with the reader's browser font-size
     setting. That is deliberate and pairs with the type scale below: if text
     grew but spacing did not, larger text would land in fixed-size boxes. */
  --sp-unit: 0.125rem;

  --sp-2:  calc(var(--sp-unit) *  1);
  --sp-4:  calc(var(--sp-unit) *  2);
  --sp-6:  calc(var(--sp-unit) *  3);
  --sp-8:  calc(var(--sp-unit) *  4);
  --sp-10: calc(var(--sp-unit) *  5);
  --sp-12: calc(var(--sp-unit) *  6);
  --sp-14: calc(var(--sp-unit) *  7);
  --sp-16: calc(var(--sp-unit) *  8);
  --sp-18: calc(var(--sp-unit) *  9);
  --sp-20: calc(var(--sp-unit) * 10);
  --sp-22: calc(var(--sp-unit) * 11);
  --sp-24: calc(var(--sp-unit) * 12);
  --sp-26: calc(var(--sp-unit) * 13);
  --sp-28: calc(var(--sp-unit) * 14);
  --sp-30: calc(var(--sp-unit) * 15);
  --sp-32: calc(var(--sp-unit) * 16);
  --sp-36: calc(var(--sp-unit) * 18);
  --sp-40: calc(var(--sp-unit) * 20);
  --sp-44: calc(var(--sp-unit) * 22);
  --sp-48: calc(var(--sp-unit) * 24);
  --sp-56: calc(var(--sp-unit) * 28);
  --sp-60: calc(var(--sp-unit) * 30);
  --sp-64: calc(var(--sp-unit) * 32);
  --sp-80: calc(var(--sp-unit) * 40);
  --sp-96: calc(var(--sp-unit) * 48);

  /* ─────────────────────────────────────────────
     Semantic spacing — the layer pages are meant to override
     ─────────────────────────────────────────────
     Reach for these rather than raw steps when the value means something
     structural. A page scope can then retune its own rhythm without forking
     the scale or touching any other page. See "Per-page overrides" at the
     bottom of this file. */
  --sp-section: clamp(var(--sp-64), 9vw, var(--sp-96)); /* between sections   */
  --sp-gutter: var(--sp-40);   /* page horizontal padding                     */
  --sp-card: var(--sp-24);     /* card interior padding                       */
  --sp-stack: var(--sp-16);    /* gap between stacked blocks                  */
  --sp-inline: var(--sp-8);    /* gap between inline items (icon + label)     */
  --sp-field: var(--sp-14);    /* gap between form fields                     */

  /* ─────────────────────────────────────────────
     Type
     ───────────────────────────────────────────── */
  --fd: 'Cormorant Garamond', Georgia, serif;
  --fb: 'DM Sans', system-ui, sans-serif;

  /* Named for the pixel value they produce, matching the spacing convention:
     --fs-16 is 16px. The steps below are the sizes the product actually uses,
     so migrating existing declarations was lossless rather than a resize.

     --fs-scale multiplies every step, so a page can run larger or smaller type
     the same way it can retune spacing (see "Per-page overrides" below).

     Sizes are in rem, so a reader who sets a larger default font size in their
     browser gets larger text here — px would ignore that setting entirely.
     1rem = 16px at the browser default, so every value below renders exactly
     as it did when these were px. Spacing is in rem for the same reason, so
     text and the space around it grow together. */
  --fs-scale: 1;
  --fs-10: calc(0.625rem * var(--fs-scale));
  --fs-11: calc(0.6875rem * var(--fs-scale));
  --fs-12: calc(0.75rem * var(--fs-scale));
  --fs-13: calc(0.8125rem * var(--fs-scale));
  --fs-14: calc(0.875rem * var(--fs-scale));
  --fs-15: calc(0.9375rem * var(--fs-scale));
  --fs-16: calc(1rem * var(--fs-scale));
  --fs-17: calc(1.0625rem * var(--fs-scale));
  --fs-18: calc(1.125rem * var(--fs-scale));
  --fs-20: calc(1.25rem * var(--fs-scale));
  --fs-22: calc(1.375rem * var(--fs-scale));
  --fs-24: calc(1.5rem * var(--fs-scale));
  --fs-26: calc(1.625rem * var(--fs-scale));
  --fs-28: calc(1.75rem * var(--fs-scale));
  --fs-30: calc(1.875rem * var(--fs-scale));
  --fs-32: calc(2rem * var(--fs-scale));
  --fs-36: calc(2.25rem * var(--fs-scale));
  --fs-40: calc(2.5rem * var(--fs-scale));
  --fs-48: calc(3rem * var(--fs-scale));

  /* Semantic aliases — prefer these for UI text so intent survives a resize. */
  --fs-xs: var(--fs-11);
  --fs-sm: var(--fs-13);
  --fs-base: var(--fs-15);
  --fs-md: var(--fs-17);
  --fs-lg: var(--fs-20);
  --fs-xl: var(--fs-26);
  --fs-2xl: clamp(var(--fs-28), 3.2vw, var(--fs-48));
  --fs-3xl: clamp(var(--fs-36), 5.2vw, calc(4.25rem * var(--fs-scale)));

  --lh-tight: 1.1;
  --lh-snug: 1.3;
  --lh-body: 1.6;

  --ls-tight: -0.025em;
  --ls-label: 0.13em;

  /* ─────────────────────────────────────────────
     Radius / layout
     ───────────────────────────────────────────── */
  /* px-named, same convention as spacing and type. */
  --r-2: 2px;
  --r-4: 4px;
  --r-6: 6px;
  --r-8: 8px;
  --r-10: 10px;
  --r-12: 12px;
  --r-14: 14px;
  --r-16: 16px;
  --r-18: 18px;
  --r-20: 20px;
  --r-24: 24px;
  --r-28: 28px;
  --r-32: 32px;
  --r-full: 999px;

  /* Semantic aliases */
  --r-sm: var(--r-8);
  --r-md: var(--r-12);
  --r-lg: var(--r-16);
  --r-xl: var(--r-24);

  --max: 1160px;
  --max-narrow: 780px;

  /* ─────────────────────────────────────────────
     Breakpoints — a convention, not tokens
     ─────────────────────────────────────────────
     CSS custom properties do NOT work inside @media queries: `@media
     (max-width: var(--bp-md))` is invalid and silently does nothing. So these
     cannot be real tokens; the values must be written literally. This block is
     the canonical set — write new media queries against these only:

       480px   small phone
       600px   phone            <- the main mobile breakpoint
       900px   tablet / small laptop
       1200px  desktop

     These were chosen by counting which widths actually carry the layout, not
     by which numbers look tidiest: 600px drives 73 rules and 900px drives 72,
     while 640px only ever had 10. An earlier revision of this comment named
     640px as canonical and told you to migrate 600px to it — that was
     backwards, and would have meant rewriting the site's main mobile layout to
     match a minor one. */

  /* ─────────────────────────────────────────────
     Elevation
     ───────────────────────────────────────────── */
  --shadow-sm: 0 1px 2px var(--scrim-02);
  --shadow-md: 0 8px 24px var(--scrim-03);
  --shadow-lg: 0 24px 64px var(--scrim-04);
  --shadow-brand: 0 12px 32px oklch(0.63 var(--chroma-brand) var(--hue-brand) / 0.22);

  /* ─────────────────────────────────────────────
     Motion
     ───────────────────────────────────────────── */
  /* Steps chosen from what the product already used: 0.2s is by far the most
     common transition, so it is the base rather than 0.25s. */
  --dur-instant: 0.08s;
  --dur-fast: 0.15s;
  --dur-base: 0.2s;
  --dur-slow: 0.3s;
  --dur-slower: 0.5s;
  --ease-out: cubic-bezier(0.2, 0.7, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* Focus ring — one definition, used by every interactive element.
     Applied globally in _focus.css, which loads last. */
  --focus-ring: 2px solid var(--brand-bright);
  --focus-offset: 3px;

  /* ─────────────────────────────────────────────
     Z-index — a named ladder, so stacking is decided here and not by
     escalating magic numbers in page files.
     ─────────────────────────────────────────────
     The previous values ran -1 … 300 and then jumped to 9998/9999, where the
     media lightbox and the toast container both sat at 9999 — a real collision
     that made toasts render unpredictably against the lightbox. Toast now
     outranks modal deliberately: a confirmation or error must stay readable
     while a dialog is open. */
  --z-below: -1;      /* decorative layers behind content      */
  --z-base: 1;        /* normal in-flow content                */
  --z-raised: 10;     /* cards and controls lifted on hover    */
  --z-sticky: 100;    /* sticky nav and section headers        */
  --z-overlay: 200;   /* backdrops and scrims                  */
  --z-effect: 250;    /* transient effects over the backdrop   */
  --z-modal: 300;     /* modals, lightboxes, pickers           */
  --z-toast: 400;     /* always above modals                   */
  --z-skip: 500;      /* skip link outranks everything         */

  /* ─────────────────────────────────────────────
     Legacy aliases — existing page stylesheets still reference these.
     Kept so a rebrand through the knobs above reaches old code too.
     ───────────────────────────────────────────── */
  --rose: var(--brand);
  --rose-mid: var(--brand-mid);
  --rose-dim: var(--brand-dim);
  --mauve: var(--accent);
  --mauve-mid: var(--accent-mid);
  --mauve-dim: var(--accent-dim);
  --glass: var(--surface);
  --glass-hi: var(--surface-hi);
  --radius: var(--r-lg);
  --radius-lg: var(--r-xl);
}

/* ═════════════════════════════════════════════════
   Per-page overrides
   ═════════════════════════════════════════════════
   Every page keeps its own autonomy here: override a semantic token on the
   page's body scope and only that page changes. Nothing is forked and no
   other page is affected, because the scale itself is untouched.

       .my-page {
         --sp-section: var(--sp-64);   ← tighter vertical rhythm
         --sp-card: var(--sp-32);      ← roomier cards
         --sp-gutter: var(--sp-24);    ← narrower page margins
       }

   To rescale one page wholesale, override --sp-unit on its scope instead;
   every step inherits from it, so the whole page breathes together:

       .dense-page { --sp-unit: 0.11rem; }

   Below are the deliberate per-page deviations that exist today. Add to this
   block rather than hardcoding px in a page stylesheet. */

/* Marketing pages run a wider, more generous rhythm than the app: long-scroll
   reading, no dense controls competing for the same vertical space. */
.landing-page {
  --sp-section: clamp(var(--sp-80), 9vw, var(--sp-96));
  --sp-card: var(--sp-28);
}

/* App surfaces are working screens. Tighter rhythm keeps controls reachable
   and puts more content above the fold. Scoped to the shell wrapper in
   templates/base_dashboard.html — custom properties inherit, so this reaches
   dashboard, settings and billing alike. */
.dash-wrap {
  --sp-section: var(--sp-48);
  --sp-card: var(--sp-24);
  --sp-gutter: var(--sp-24);
}

/* Single-purpose focused screens: one card, centred, no competing content.
   Scoped to the allauth shell wrapper (apps/accounts/templates/allauth/). */
.aa-wrap {
  --sp-card: var(--sp-32);
  --sp-field: var(--sp-16);
}

/* Honour the OS reduced-motion setting globally, so no page has to remember. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0.01ms;
    --dur-base: 0.01ms;
    --dur-slow: 0.01ms;
  }
}
