/* Brand tokens — v2 transformation (2026-09-22), retuned for the wellness
   pivot (no alerts, no diagnosis; two calm profiles sharing one data
   stream). Builds on the "Serene Pastel Premium" Stitch triad rather than
   replacing it — that palette already sat in the right family per 2026
   color-psychology research (muted blue = trust/calm, muted green =
   growth/health, both under 35% saturation, which is exactly what
   meditation-app research recommends over anything punchier). What changed:
   the family is now split into two INTENTIONAL registers instead of one —
   --sky-blue/--sage-green stay cooler and carry the baby's factual data
   (trust, calm, "nothing wrong here"), while --blush-pink is warmed and
   pushed toward comfort/care to carry the parent-wellness surfaces (check-
   ins, journal, mood) — so a caregiver can feel which "mode" they're in
   before reading a single word. Variable NAMES are kept as-is to avoid a
   risky app-wide rename — they describe a semantic ROLE, not the literal
   hue. Component rules in app.css consume these vars so a reskin never
   requires touching per-screen JS. */
:root {
  --sky-blue: #56697A;       /* baby-data trust anchor — muted blue, ~15% cooler/deeper than v1 for more "clinical calm, not clinical cold" */
  --sky-blue-rgb: 86,105,122;
  --sky-blue-tint: #DCE7EE;

  --blush-pink: #8A6367;     /* parent-wellness warmth anchor — warmed ~6% toward red/away from mauve-grey so check-ins/journal read as "comfort," not "formal." Still primary/CTA color everywhere, per v1. */
  --blush-pink-rgb: 138,99,103;
  --blush-pink-tint: #F8DEE1;

  --sage-green: #4B8064;     /* baby-data growth/health anchor — temperature, "good" pattern moments. Slightly greener than v1 (less muddy-olive) per "calming greens, not muted-to-grey" guidance. */
  --sage-green-rgb: 75,128,100;
  --sage-green-tint: #DBEFE3;

  /* Emerald — a cleaner, livelier green than --sage-green (~21% saturation,
     read as muddy) but pulled back from a first pass that went too far the
     other way (~79% saturation, a genuinely neon-adjacent green that clashed
     with the muted "quiet luxury" family every other subscore color belongs
     to — blush-pink/sky-blue/warning all sit around 12-20% saturation).
     Landed at ~35%: distinctly greener/brighter than the original, but still
     recognizably part of the same dusty family, not a jarring outlier.
     Scoped to the subscore cards only — the rest of the app's palette isn't
     being re-litigated (see theme history note further down). */
  --emerald: #4B9B73;
  --emerald-rgb: 75,155,115;
  --emerald-tint: #DEF1E7;

  --cream: #FBF9F8;          /* Stitch "background"/"surface" */
  --cream-dark: #EFEDED;     /* Stitch "surface-container" */
  --brown: #1B1C1C;          /* Stitch "on-surface" — cooler deep charcoal, not warm brown-black like the old system */
  --brown-mid: #4F4445;      /* Stitch "on-surface-variant" */
  --text-medium: #4F4445;
  --text-muted: #6B6061;
  --text-light: #857A7B;
  --white: #ffffff;
  /* Base ink color as an rgb triplet so `rgba(var(--ink-rgb), X)` overlays
     (borders, dividers, scrims) can be re-pointed per-theme — see dark mode
     below. Must always match --brown. */
  --ink-rgb: 27,28,28;

  /* Semantic surface aliases — same values as --white/--cream today, but
     named by role so dark mode can re-point them independently of the
     literal color tokens above. */
  --surface: var(--white);
  --surface-sunken: var(--cream);
  --surface-sunken-alt: var(--cream-dark);

  /* Toggle switch knob — deliberately NOT --white/--surface. Those are
     semantic surface tokens that get re-pointed to near-black in dark mode
     (see [data-theme="dark"] below), which is correct for cards/pages but
     wrong for a toggle's physical "thumb": every native iOS/Android toggle
     keeps a solid white knob in dark mode too. Using --white here made the
     knob nearly invisible against a dark track and made the track's pastel-
     blue "on" color read far more vivid/jarring by contrast than intended —
     the actual bug behind a dark-mode "neon blue, scary" report. Same value
     in both themes, no dark-mode override needed. */
  --toggle-knob: #FFFFFF;

  /* One-off structural colors that aren't part of the accent/status system:
     splash screen background (the one deliberate exception to the
     strict-Stitch-palette rule below — pastel yellow lives only here,
     nowhere else in the app), and the desktop "phone frame" chrome (never
     seen on an actual phone — only wraps the preview on wide/desktop
     viewports, see the min-width:431px media query in app.css). */
  --splash-bg: #FCEFC6;
  --frame-bg: #ECE2CE;
  --frame-border: #2a2a2a;
  --critical-strong: #FFDAD6; /* Stitch's literal "error-container" — hero-status--alert gradient start */

  /* Badge text colors — Stitch's "on-*-fixed-variant" tokens, deliberately
     darker/higher-contrast than the badge's own accent so text stays
     readable on the badge's pale tint background; must be re-pointed (not
     just inverted) per theme. --badge-green-ink is derived alongside the
     invented mint accent above. --warning gets its own distinct tertiary
     (khaki-yellow) hue again now that Stitch's own token set actually
     provides one — no longer needs to alias pink. */
  --badge-blue-ink: #374954;
  --badge-pink-ink: #574144;
  --badge-green-ink: #2F4A3C;
  --badge-critical-ink: #93000A;
  --badge-warning-ink: #4C472D;

  /* v2 pair, replacing Playfair Display + Plus Jakarta Sans. Playfair is a
     high-contrast editorial serif — great for a magazine, wrong register for
     a wellness app a sleep-deprived parent opens at 3am (2026 wellness-app
     research repeatedly calls out soft, rounded, low-contrast type as the
     calming choice: Nunito Sans is named directly as "a rounded, friendly
     sans that softens interfaces for consumer, wellness and kids' apps").
     Spectral replaces Playfair: still a serif (keeps the brand's one
     signature editorial move) but a warm, humanist, low-contrast old-style
     serif — softer and rounder-feeling than Playfair's sharp high-contrast
     strokes, without reaching for Fraunces, which a design-quality pass
     flagged as having become its own AI-default tell (as common now as
     Inter or Geist). Nunito Sans replaces Plus Jakarta Sans as body: rounder
     terminals read as approachable rather than corporate, at no legibility
     cost at small UI sizes. --font-data unchanged (Space Mono/tabular
     figures for vital readouts — that convention was already correct, not
     part of this change). */
  --font-heading: 'Spectral', Georgia, serif;
  --font-body: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: ui-monospace, 'SF Mono', 'Menlo', 'Cascadia Mono', monospace;
  --font-data: 'Space Mono', var(--font-mono);

  /* Bumped up from the original 8/14/20/28 scale — softer, more generous
     rounding across the board is one of the clearest visual signals that
     distinguishes this from the previous pass (Airbnb/Oura-style rounding,
     not the tighter iOS-utility rounding this started as). Card radius
     nudged again per the Stitch design system spec (24-32px). */
  --radius-sm: 12px;
  --radius-md: 18px;
  --radius-lg: 28px;
  --radius-xl: 34px;
  --radius-full: 999px;

  --shadow-sm: 0 2px 8px rgba(var(--ink-rgb),0.08);
  --shadow-md: 0 10px 28px rgba(var(--ink-rgb),0.1);
  --shadow-lg: 0 20px 44px rgba(var(--ink-rgb),0.14);

  /* Glass tokens — a sparing "expensive" chrome accent (topbar, bottom nav,
     modal/sheet backdrops only, never regular content cards). Frosted
     translucent fill + backdrop-blur over whatever scrolls beneath it. */
  --glass-surface: rgba(255,255,255,0.62);
  --glass-border: rgba(255,255,255,0.5);
  --glass-blur: 18px;

  /* Wellness ring's drop-shadow needs its own theme-aware token — filter:
     drop-shadow() can't consume the box-shadow shorthand vars above, and an
     ink-tinted (light) shadow color would read as a glow, not a shadow,
     against a dark background (same reasoning as --shadow-* below). */
  --ring-shadow: rgba(var(--ink-rgb),0.14);

  /* Spacing scale (4px base) — for new component work (card/row/empty/error
     builders and anything added in later redesign phases). Existing
     hand-tuned per-rule spacing in app.css is left as-is; retrofitting every
     existing value onto this scale is unnecessary churn with no visual
     benefit and real regression risk. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* Type scale — same rationale as spacing: available for new component
     work, not a forced retrofit of existing per-screen font-sizes. */
  --text-xs: 0.66rem;
  --text-sm: 0.78rem;
  --text-base: 0.88rem;
  --text-md: 0.95rem;
  --text-lg: 1.15rem;
  --text-xl: 1.3rem;
  --text-2xl: 1.7rem;
  --text-3xl: 2.2rem;
  --leading-tight: 1.15;
  --leading-normal: 1.4;
  --leading-relaxed: 1.6;

  /* Status colors. "Critical" is Stitch's literal "error"/"error-container"
     pair — identical hex in both Stitch design systems this app has used,
     kept deliberately separate from the brand triad since a red danger
     signal is a near-universal safety convention. "Warning" is Stitch's
     literal "tertiary" (khaki/pale-yellow) token — a real, given hue this
     time, not an invented gold or an alias of pink. The splash screen's
     pastel yellow remains the one deliberate exception living only in
     --splash-bg below. "Good" reads as the Stitch secondary blue-grey. */
  --critical: #BA1A1A;
  --critical-rgb: 186,26,26;
  --critical-tint: #FFDAD6;
  --warning: #645F43;
  --warning-rgb: 100,95,67;
  --warning-tint: #EBE2BF;
  --good: #4E616D;
  --good-rgb: 78,97,109;
  --good-tint: #D1E5F3;
}

/* Dark mode — intentionally re-composed per token, not a blanket filter
   invert. Darker/duskier accents (not the same hue at lower lightness
   alone) so the palette still reads calm rather than neon-on-black.
   Activated by `data-theme="dark"` on <html>, set synchronously by an
   inline script in index.html before first paint (see there for why no
   separate `prefers-color-scheme` media block is needed here: the script
   always resolves OS preference down to a concrete "light"/"dark" value
   before CSS is even parsed, so there's no un-themed frame to catch). */
[data-theme="dark"] {
  /* Stitch's own "fixed-dim" brightened variants of primary/secondary/
     tertiary — the token set's designated pairing for dark surfaces, not an
     independent guess. Mint (--sage-green) is brightened proportionally
     since it was derived, not given, in light mode too.
     TODO(v2 follow-up): these three hexes predate the v2 light-mode retune
     above and haven't been re-derived from it yet — close enough not to
     clash (same hue families, similar lightness) but not yet a precise
     proportional match. Recompute alongside the next dark-mode pass. */
  --sky-blue: #B6C9D7;
  --sky-blue-rgb: 182,201,215;
  --sky-blue-tint: rgba(182,201,215,0.18);

  --blush-pink: #DEBFC2;
  --blush-pink-rgb: 222,191,194;
  --blush-pink-tint: rgba(222,191,194,0.18);

  --sage-green: #A9C7B7;
  --sage-green-rgb: 169,199,183;
  --sage-green-tint: rgba(169,199,183,0.18);

  /* Same moderated-saturation logic as light mode above — brightened for
     dark-surface legibility like every other token here, landing close to
     --sage-green's own dark value since pastel-on-dark convergence is
     expected at this lightness, not a sign the tokens should just be merged. */
  --emerald: #A2CDB8;
  --emerald-rgb: 162,205,184;
  --emerald-tint: rgba(162,205,184,0.18);

  /* Stitch's own inverse-surface/inverse-on-surface tokens — purpose-built
     for exactly this light-to-dark surface flip, not an independent guess
     the way the previous palette's dark neutrals had to be. */
  --cream: #303030;
  --cream-dark: #3A3A3A;
  --brown: #F2F0F0;
  --brown-mid: #C7BEBE;
  --text-medium: #C7BEBE;
  --text-muted: #ABA1A1;
  --text-light: #B8AFAF;
  --white: #262525;
  --ink-rgb: 242,240,240;

  --surface: var(--white);
  --surface-sunken: var(--cream);
  --surface-sunken-alt: var(--cream-dark);

  --frame-bg: #0D0B09;
  --frame-border: #000000;
  --critical-strong: #C96B6B;

  --badge-blue-ink: #D1E5F3;
  --badge-pink-ink: #FADADD;
  --badge-green-ink: #DCEEE3;
  --badge-critical-ink: #FFDAD6;
  --badge-warning-ink: #EBE2BF;

  --critical: #DE8177;
  --critical-rgb: 222,129,119;
  --critical-tint: rgba(222,129,119,0.18);
  --warning: #CFC7A5;
  --warning-rgb: 207,199,165;
  --warning-tint: rgba(207,199,165,0.18);
  --good: #B6C9D7;
  --good-rgb: 182,201,215;
  --good-tint: rgba(182,201,215,0.18);

  /* Shadows must be black-based in dark mode — an ink-tinted shadow at
     light-mode opacities disappears against a dark background. */
  --shadow-sm: 0 2px 8px rgba(0,0,0,0.32);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.4);
  --shadow-lg: 0 20px 44px rgba(0,0,0,0.5);

  --glass-surface: rgba(43,37,33,0.62);
  --glass-border: rgba(255,255,255,0.08);
  --ring-shadow: rgba(0,0,0,0.45);

  /* Deep warm brown-gold rather than the light-mode pastel yellow — the
     splash logo is drawn in brown ink for a light background, so it also
     needs the invert treatment below to stay legible here. */
  --splash-bg: #241B10;
}

/* Visually-hidden but screen-reader-readable — used by the accessible chart
   markup wrappers (sparklineMarkup/barChartMarkup/donutMarkup) and anywhere
   else a text alternative sits next to a purely visual element. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

* { box-sizing: border-box; }

/* Every `.card`/`.vital-tile`/`.subscore-card`/etc. reset resets border,
   background, and appearance on the native <button>s they're built from,
   but none of them reset `color` — so a button's text falls back to the
   browser's own default control-text color. Chrome/Firefox happen to
   inherit the surrounding text color anyway, masking this; Safari/WebKit
   uses its native system accent color (blue) for buttons instead, which is
   why every number/title living inside a button (vital tile values, Sleep
   Report/Health Report card titles) rendered blue on an actual iPhone even
   though nothing in this codebase ever sets color:blue. One reset here
   fixes the whole class of button, not just the ones already touched. */
button { color: inherit; font: inherit; }

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--font-body);
  background: var(--cream);
  color: var(--brown);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, .brand-font {
  font-family: var(--font-heading);
  color: var(--brown);
  margin: 0;
}

/* Accessibility: visible focus ring for keyboard navigation (Apple HIG /
   Material Design both require a visible focus indicator distinct from hover). */
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, [tabindex]:focus-visible {
  outline: 2.5px solid var(--sky-blue);
  outline-offset: 2px;
}

/* Respect the OS-level reduced-motion preference — disables the pulsing,
   shimmering, breathing, and page-transition animations used elsewhere in the app. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
