/**
 * tokens.css -- The entire design system's raw values, in one place.
 *
 * RULE: nothing outside this file is a color, size, radius, shadow, or
 * duration literal. Every screen and component consumes a var(--token).
 * If you're tempted to write a hex code or a px value in styles.css, the
 * token you need either exists here or belongs here.
 *
 * ----------------------------------------------------------------------------
 * WHY THESE EXACT NUMBERS
 * ----------------------------------------------------------------------------
 * The base accent hexes (rose/lavender/plum/sage/coral/peach) are soft and
 * desaturated by design -- but soft colors fail contrast as TEXT or as a
 * white-on-solid button fill. Every accent below ships in two forms:
 *   --{name}       : the soft tint. Background only, paired with --ink text.
 *   --{name}-strong: darkened (light mode) / occasionally lightened (dark
 *                    mode) until it clears 4.5:1 both as text-on-bg and as
 *                    white-on-solid. Verified computationally, not eyeballed
 *                    -- see the contrast numbers in each block below.
 * Never use a soft tint as a text color, and never use a -strong variant as
 * a large filled background (it will look saturated/harsh, which is exactly
 * what "muted, never saturated" rules out) -- soft-tint-with-ink-text and
 * strong-color-as-text-or-small-accent are the two intended uses.
 */

:root {
  /* ============================================================
     LIGHT THEME (default)
     ============================================================ */
  --bg: #FBF9F7;
  --surface: #F5F1EC;
  --surface-sunken: #EFEBE7;
  --surface-raised: #FFFFFF;

  --ink: #2A2622;                /* 14.3:1 on bg */
  --ink-secondary: #6B635C;      /* 5.6:1 on bg -- body-safe */
  --ink-tertiary: #958E87;       /* 3.1:1 on bg -- LARGE/decorative text only, never body copy */

  /* Soft tints -- backgrounds only, pair with --ink */
  --rose: #C58B8B;
  --lavender: #B4A6CC;
  --plum: #7E6B82;
  --sage: #9EB09A;
  --coral: #D69B86;
  --peach: #F1E0D4;

  /* Text/icon/button-safe strong variants (>=4.5:1 both as text-on-bg and white-on-solid) */
  --rose-strong: #926767;
  --lavender-strong: #776E87;
  --plum-strong: #7E6B82;        /* already strong at base -- no separate variant needed */
  --sage-strong: #687466;
  --coral-strong: #92695B;
  --peach-strong: #78706A;

  --success: #7FA07A;
  --success-strong: #5E765A;
  --warning: #CB9E4E;
  --warning-strong: #8A6B35;
  --error: #C57A6E;
  --error-strong: #9E6258;

  /* Cycle phases -- 4 distinct hues from the accent set above. Never the
     only signal: every phase also carries an icon (see --phase-*-icon
     usage in ui.js) so colour is reinforcement, not the sole channel. */
  --phase-menstrual: var(--rose);
  --phase-menstrual-strong: var(--rose-strong);
  --phase-follicular: var(--sage);
  --phase-follicular-strong: var(--sage-strong);
  --phase-fertile: var(--coral);
  --phase-fertile-strong: var(--coral-strong);
  --phase-luteal: var(--lavender);
  --phase-luteal-strong: var(--lavender-strong);

  /* Primary action color -- the one place a "call to action" saturation is
     appropriate. Reuses rose-strong so buttons feel continuous with the
     menstrual/brand hue rather than introducing a 7th color. */
  --action: var(--rose-strong);
  --action-hover: #7A5555;

  --focus-ring: #2A2622;

  /* ============================================================
     TYPOGRAPHY
     ------------------------------------------------------------
     Display face: Merriweather (already self-hosted for the app's original
     bug-fix pass -- see css/fonts.css). Deliberately NOT adding Fraunces or
     Newsreader as a third font family: this app's whole privacy posture is
     "zero third-party requests," and every additional font is more bytes to
     self-host for a look Merriweather already delivers (an elegant serif
     for headers). Body/UI face: Inter, likewise already self-hosted.
     ============================================================ */
  --font-display: 'Merriweather', Georgia, serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --text-display: 2.75rem;   --lh-display: 1.15; --ls-display: -0.01em; --w-display: 700;
  --text-h1:      2.1rem;    --lh-h1: 1.2;        --ls-h1: -0.01em;      --w-h1: 700;
  --text-h2:      1.5rem;    --lh-h2: 1.3;        --ls-h2: 0;            --w-h2: 600;
  --text-title:   1.125rem;  --lh-title: 1.4;      --ls-title: 0;         --w-title: 600;
  --text-body:    1rem;      --lh-body: 1.55;      --ls-body: 0;          --w-body: 400;
  --text-body-sm: 0.875rem;  --lh-body-sm: 1.5;    --ls-body-sm: 0;       --w-body-sm: 400;
  --text-caption: 0.75rem;   --lh-caption: 1.45;   --ls-caption: 0.01em;  --w-caption: 500;

  /* ============================================================
     SPACING -- 4px base, 8px grid
     ============================================================ */
  --sp-1: 0.25rem;   /* 4px */
  --sp-2: 0.5rem;    /* 8px */
  --sp-3: 0.75rem;   /* 12px */
  --sp-4: 1rem;      /* 16px */
  --sp-5: 1.25rem;   /* 20px */
  --sp-6: 1.5rem;    /* 24px */
  --sp-8: 2rem;      /* 32px */
  --sp-10: 2.5rem;   /* 40px */
  --sp-12: 3rem;     /* 48px */
  --sp-16: 4rem;     /* 64px */

  /* ============================================================
     RADIUS
     ============================================================ */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-2xl: 28px;
  --r-full: 9999px;

  /* ============================================================
     ELEVATION -- soft, warm-tinted, never harsh black
     ============================================================ */
  --e1: 0 1px 3px rgba(42, 38, 34, 0.06), 0 1px 2px rgba(42, 38, 34, 0.08);
  --e2: 0 4px 10px rgba(42, 38, 34, 0.08), 0 2px 4px rgba(42, 38, 34, 0.06);
  --e3: 0 12px 28px rgba(42, 38, 34, 0.14), 0 4px 8px rgba(42, 38, 34, 0.08);

  /* ============================================================
     MOTION -- duration scale, shared easings, spring physics
     ------------------------------------------------------------
     --dur-fast/base/slow and --ease-standard predate this system and
     stay as-is (every existing transition already keys off them); the
     tokens below round the scale out to the full Instant..Slow range
     the motion system calls for, and add named eases/springs on top.
     Every duration/easing used anywhere in the app must come from this
     list -- never a hardcoded ms value or ad hoc cubic-bezier.
     ============================================================ */
  --dur-instant: 50ms;    /* Instant   */
  --dur-xfast: 100ms;     /* Very Fast */
  --dur-fast: 150ms;      /* Fast      */
  --dur-base: 250ms;      /* Normal    */
  --dur-medium: 320ms;    /* Medium    */
  --dur-slow: 400ms;      /* Slow      */
  --ease-standard: cubic-bezier(0.22, 1, 0.36, 1);   /* Ease Out (existing, unchanged) */
  --ease-out: var(--ease-standard);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-decelerate: cubic-bezier(0, 0, 0.2, 1);      /* fast start, slow finish -- entering elements */
  --ease-accelerate: cubic-bezier(0.4, 0, 1, 1);       /* slow start, fast finish -- exiting elements */

  /* Spring presets -- real damped-harmonic-oscillator curves (mass/
     stiffness/damping), sampled and encoded as CSS linear() easings.
     Computed, not eyeballed -- see scripts/gen-springs.js for the model
     and the exact per-preset parameters. Each spring is only correct
     paired with ITS OWN --spring-*-dur; using a different duration
     clips or stretches the curve. */
  --spring-soft: linear(0, 0.0225, 0.0777, 0.1513, 0.2334, 0.3176, 0.3994, 0.4765, 0.5472, 0.6109, 0.6676, 0.7175, 0.7609, 0.7984, 0.8306, 0.8581, 0.8814, 0.9012, 0.9179, 0.9319, 0.9436, 0.9534, 0.9615, 0.9683, 0.9739, 0.9786, 0.9824, 0.9856, 0.9882, 0.9904, 0.9921, 0.9936, 0.9948, 0.9957, 0.9965, 0.9972, 0.9977, 0.9981, 0.9985, 0.9988, 0.999);
  --spring-soft-dur: 702ms;
  --spring-gentle: linear(0, 0.0298, 0.106, 0.2113, 0.3316, 0.4558, 0.5758, 0.6861, 0.7831, 0.865, 0.9316, 0.9833, 1.0214, 1.0476, 1.0638, 1.0718, 1.0735, 1.0705, 1.0644, 1.0564, 1.0475, 1.0384, 1.0296, 1.0217, 1.0148, 1.0089, 1.0042, 1.0006, 0.998, 0.9962, 0.9952, 0.9947, 0.9946, 0.9949, 0.9954, 0.996, 0.9966, 0.9973, 0.9979, 0.9985, 0.999);
  --spring-gentle-dur: 943ms;
  --spring-responsive: linear(0, 0.0296, 0.1047, 0.2073, 0.3235, 0.4426, 0.5572, 0.6621, 0.7545, 0.8328, 0.897, 0.9477, 0.9861, 1.0137, 1.0323, 1.0435, 1.0489, 1.0499, 1.0479, 1.0437, 1.0384, 1.0325, 1.0266, 1.021, 1.0158, 1.0114, 1.0076, 1.0045, 1.0021, 1.0003, 0.9991, 0.9982, 0.9977, 0.9975, 0.9975, 0.9976, 0.9979, 0.9981, 0.9984, 0.9987, 0.999);
  --spring-responsive-dur: 714ms;
  --spring-snappy: linear(0, 0.0298, 0.106, 0.2115, 0.3319, 0.4565, 0.5769, 0.6876, 0.785, 0.8673, 0.9341, 0.9859, 1.0241, 1.0502, 1.0662, 1.074, 1.0754, 1.0722, 1.0658, 1.0575, 1.0482, 1.0388, 1.0299, 1.0217, 1.0146, 1.0087, 1.0039, 1.0003, 0.9976, 0.9959, 0.9948, 0.9943, 0.9943, 0.9946, 0.9952, 0.9958, 0.9965, 0.9972, 0.9979, 0.9985, 0.999);
  --spring-snappy-dur: 596ms;
  --spring-heavy: linear(0, 0.0451, 0.1598, 0.3151, 0.4866, 0.6551, 0.8071, 0.9341, 1.0319, 1.1002, 1.1413, 1.159, 1.1582, 1.1441, 1.1215, 1.0946, 1.067, 1.0412, 1.019, 1.0012, 0.9881, 0.9797, 0.9753, 0.9742, 0.9757, 0.9788, 0.9829, 0.9873, 0.9916, 0.9955, 0.9987, 1.0011, 1.0028, 1.0037, 1.0041, 1.0041, 1.0037, 1.0031, 1.0024, 1.0016, 1.001);
  --spring-heavy-dur: 1137ms;

  /* Deliberately NOT collapsed by the reduced-motion block below. Everywhere
     else, reduced motion means "instant" -- but the intro splash's own spec
     calls for replacing MOVEMENT with a gentle fade under reduced motion,
     not removing the fade too ("preserve branding and timing without
     unnecessary animation"). This token exists so that one component can
     keep a real, perceptible opacity transition while every transform it
     would otherwise animate collapses to instant via the normal tokens. */
  --dur-reduced-fade: 300ms;

  /* ============================================================
     LAYOUT
     ============================================================ */
  --nav-height: 4.5rem;
  --touch-min: 44px;             /* minimum tap target, Phase 7 accessibility floor */
  --container-max: 30rem;        /* mobile-first single-column width even on desktop */
}

/* ================================================================
   DARK THEME -- same warmth, not a cold gray inversion.
   Verified: most accents pass 4.5:1+ on the warm dark bg UNCHANGED
   (light colors read fine on dark backgrounds); only --plum needed a
   10% lift to clear the threshold. See tokens.css header for method.
   Triggered by OS preference by default, overridable via data-theme.
   ================================================================ */
@media (prefers-color-scheme: dark) {
  :root { color-scheme: dark; }
}

/* Two separate rules, deliberately: an explicit data-theme="dark" (the
   in-app toggle) always wins, and prefers-color-scheme applies only when
   the user hasn't explicitly overridden it either way. */
:root[data-theme="dark"] {
  --bg: #1A1613; --surface: #241F1B; --surface-sunken: #14110F; --surface-raised: #2C2621;
  --ink: #F2EDE7; --ink-secondary: #C9BFB5; --ink-tertiary: #8F857A;
  --rose: #C58B8B; --lavender: #B4A6CC; --plum: #8B7A8F; --sage: #9EB09A; --coral: #D69B86; --peach: #F1E0D4;
  --rose-strong: #D9ACAC; --lavender-strong: #C7BBDA; --plum-strong: #A594A9;
  --sage-strong: #B7C6AF; --coral-strong: #E3B6A2; --peach-strong: #F1E0D4;
  --success: #93B98E; --success-strong: #A8CCA3; --warning: #D9B269; --warning-strong: #E2C48A;
  --error: #D4938A; --error-strong: #DFA89F;
  --action: var(--rose-strong); --action-hover: #E6BEBE; --focus-ring: #F2EDE7;
  --e1: 0 1px 3px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.3);
  --e2: 0 4px 10px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.3);
  --e3: 0 12px 28px rgba(0, 0, 0, 0.5), 0 4px 8px rgba(0, 0, 0, 0.35);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1A1613; --surface: #241F1B; --surface-sunken: #14110F; --surface-raised: #2C2621;
    --ink: #F2EDE7; --ink-secondary: #C9BFB5; --ink-tertiary: #8F857A;
    --rose: #C58B8B; --lavender: #B4A6CC; --plum: #8B7A8F; --sage: #9EB09A; --coral: #D69B86; --peach: #F1E0D4;
    --rose-strong: #D9ACAC; --lavender-strong: #C7BBDA; --plum-strong: #A594A9;
    --sage-strong: #B7C6AF; --coral-strong: #E3B6A2; --peach-strong: #F1E0D4;
    --success: #93B98E; --success-strong: #A8CCA3; --warning: #D9B269; --warning-strong: #E2C48A;
    --error: #D4938A; --error-strong: #DFA89F;
    --action: var(--rose-strong); --action-hover: #E6BEBE; --focus-ring: #F2EDE7;
    --e1: 0 1px 3px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.3);
    --e2: 0 4px 10px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.3);
    --e3: 0 12px 28px rgba(0, 0, 0, 0.5), 0 4px 8px rgba(0, 0, 0, 0.35);
  }
}

/* ================================================================
   COLORBLIND-SAFE PHASE MAPPING
   ------------------------------------------------------------------
   Rose/coral/sage sit close together for deuteranopia/protanopia (red-green
   deficiency, the most common form). This alternate set swaps the 4 phase
   hues for a blue/orange/gold/violet family -- reliably distinguishable
   across deuteranopia, protanopia AND tritanopia -- muted to match the same
   soft aesthetic. Toggled via Profile > Accessibility, applied as
   [data-colorblind="true"] on <html>. Phase colour is ALWAYS paired with an
   icon and a text label regardless of this setting; this exists as a second
   line of defence, not the only one.
   ================================================================ */
:root[data-colorblind="true"] {
  --phase-menstrual: #C77F3E;         --phase-menstrual-strong: #8C5A2B;
  --phase-follicular: #5B85AA;        --phase-follicular-strong: #3E5C77;
  --phase-fertile: #D4A72C;           --phase-fertile-strong: #8C6F1D;
  --phase-luteal: #5C4D7D;            --phase-luteal-strong: #453A5F;
}
:root[data-theme="dark"][data-colorblind="true"] {
  --phase-menstrual: #E0A066;         --phase-menstrual-strong: #EDBB8C;
  --phase-follicular: #7FA6C9;        --phase-follicular-strong: #A3C2DC;
  --phase-fertile: #E2C158;          --phase-fertile-strong: #EDD387;
  --phase-luteal: #8A7BAD;            --phase-luteal-strong: #AB9FC7;
}

/* ================================================================
   HIGH CONTRAST override -- Profile > Accessibility. Widens every text
   pairing well past AA, for users who asked for it explicitly rather than
   relying only on the ordinary tokens' already-verified AA contrast.
   ================================================================ */
:root[data-contrast="high"] {
  --ink-secondary: var(--ink);
  --ink-tertiary: var(--ink);
  --focus-ring: var(--ink);
}
:root[data-theme="dark"][data-contrast="high"] {
  --ink-secondary: var(--ink);
  --ink-tertiary: var(--ink);
}

/* Respect a stated OS preference immediately, before any JS runs. Collapsing
   every duration (including spring settle times) to ~0 means any transition
   or animation driven by these tokens becomes instant regardless of its
   easing curve -- so this one block is sufficient for the whole motion
   system, springs included, with no per-component reduced-motion CSS needed
   purely for timing. Components that also translate meaningful DISTANCE
   (the calendar month-slide, screen transitions) still separately swap
   translation for a plain fade under this same media query -- see each
   component's own reduced-motion rule for that. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 0.001ms; --dur-xfast: 0.001ms; --dur-fast: 0.001ms;
    --dur-base: 0.001ms; --dur-medium: 0.001ms; --dur-slow: 0.001ms;
    --spring-soft-dur: 0.001ms; --spring-gentle-dur: 0.001ms;
    --spring-responsive-dur: 0.001ms; --spring-snappy-dur: 0.001ms; --spring-heavy-dur: 0.001ms;
  }
}
