/* ==========================================================================
   Ayah Health — Unified Design System
   Apple HIG–inspired clarity + Material 3 tonal depth.

   This file is the single source of truth for the site's visual language.
   Pages should reach for the classes defined here (.card, .btn, .eyebrow,
   .tile, .icon-tile, .alert, .stat, .text-*, etc.) instead of repeating
   long strings of color/typography/shadow utility classes. Tailwind is
   still used on individual pages only for structural layout — grid/flex
   arrangement, gap, max-width, and responsive breakpoints — since that's
   inherently different per page and isn't part of the shared "look."

   Performance notes for future maintainers:
   - No `backdrop-filter`, transparency, or glassmorphism anywhere in this
     file, on purpose. Cards/panels are solid, opaque gray fills that sit
     visibly on top of the canvas color (Apple/Google grouped-surface
     pattern) rather than translucent panes trying to blend with whatever
     is behind them — that alone does most of the contrast work, cheaply.
   - Elevation shadows use two layers (a tight contact shadow + a soft wide
     ambient one) to read as a natural cast shadow rather than a flat blur.
     That's still just two box-shadow layers — no inset "sheen" highlight,
     no backdrop-filter — so it stays cheap to paint/repaint on scroll.
   - Color and text-tone classes below (.text-primary/.text-secondary/
     .text-muted, .card, .tile, etc.) read CSS custom properties that
     flip automatically when `html.dark` is toggled, so a single class
     works in both themes — no more pairing every element with a second
     `dark:` utility class just to restate the same color relationship.
   ========================================================================== */

/* Quicksand — same rounded, friendly typeface already used on the clinical/
   intake side (intake/clinical-ui.css). Copied verbatim from that file: the
   woff2 files already live in /vendor/fonts/ on the server (shared static
   asset folder, same relative path from either stylesheet), so nothing new
   needs to be uploaded — this just registers the same font family for the
   marketing pages too. A variable-weight font (300–700 in one file), which
   is why every rule below can just say a font-weight number rather than
   needing separate font files per weight. */
@font-face {
    font-family: "Quicksand";
    font-style: normal;
    font-display: swap;
    font-weight: 300 700;
    src: url("/vendor/fonts/quicksand-latin-ext-wght-normal.woff2") format("woff2-variations");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "Quicksand";
    font-style: normal;
    font-display: swap;
    font-weight: 300 700;
    src: url("/vendor/fonts/quicksand-latin-wght-normal.woff2") format("woff2-variations");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Design Tokens --- */
:root {
    /* Tells the browser which palette is active so native UI it renders
       itself — scrollbars, the default form-control chrome on inputs we
       don't otherwise skin, the OS-level autofill highlight — matches
       instead of defaulting to light and looking like a seam. */
    color-scheme: light;

    /* Canvas + surfaces — inverted from an earlier pass that made canvas
       the near-white tone and surface pure white: on a flat, borderless,
       shadowless card (see .card below) that left cards almost
       indistinguishable from the page itself, since #f9f8f6 vs #ffffff is
       only a ~3/255 difference — everything visually "stacked together"
       with no cue where one card ended and the next began. Page background
       is now true white, and cards are the visible light-gray step down
       from it — the color difference alone is what separates a flat card
       from the page, so it needs to be a real, noticeable step, not a
       rounding error. surface-2 (nested tiles inside a card) steps down
       again from surface for the same reason. Also neutral gray now, not
       the earlier warm stone tint — border-hairline/border-soft/elevation/
       neutral-tint below were all shifted the same way, so nothing built on
       this token set carries a leftover warm cast next to a neutral card. */
    --canvas: #ffffff;
    --surface: #f5f5f5;
    /* Neutral gray, not the earlier warm beige (#eae6df) — now that
       --surface itself is a true neutral gray rather than a warm off-
       white, a warm-toned surface-2 would read as mismatched next to it.
       Icon-tile backgrounds, nested tiles, alert boxes, and other
       components built on this token all inherit the neutral tone
       automatically. */
    --surface-2: #e5e5e5;
    --border-hairline: rgba(30, 30, 30, 0.08);
    --border-soft: rgba(30, 30, 30, 0.05);

    /* Elevation — same two-layer approach (tight contact shadow + soft
       ambient falloff) but each layer's opacity roughly halved from the
       previous scale, closer to clinical-ui's very quiet card shadow
       (0 1px 2px rgba(15,23,42,.025)) than to a typical SaaS-dashboard
       drop shadow. Neutral gray (not the earlier warm stone tint) to match
       the borders above and the neutral surface/surface-2 cards now sit on.
       Panels still read as lifted off the canvas — just quietly. */
    --elevation-1: 0 1px 2px rgba(30, 30, 30, 0.03), 0 3px 8px -3px rgba(30, 30, 30, 0.06);
    --elevation-2: 0 1px 3px rgba(30, 30, 30, 0.04), 0 10px 24px -10px rgba(30, 30, 30, 0.09);
    --elevation-3: 0 2px 5px rgba(30, 30, 30, 0.05), 0 20px 44px -18px rgba(30, 30, 30, 0.12);

    /* Brand accent (teal/emerald — matches the logo). Deepened one step
       from the brighter teal-600 this used to be, closer to clinical-ui's
       muted #0f5954 — a calmer, less "default SaaS" teal that still reads
       clearly as the same brand color. */
    --accent: 15, 118, 110;
    --accent-solid: #0f766e;
    --accent-solid-hover: #0b5b54;
    --accent-tint-bg: rgba(15, 118, 110, 0.08);
    --accent-tint-border: rgba(15, 118, 110, 0.20);

    /* Conversion CTA accent — reserved for external "book with the doctor"
       actions only, kept distinct from the teal brand/navigation accent so
       the highest-intent buttons always stand out the same way. Same values
       in both themes (defined once here, not repeated under html.dark)
       since a saturated rose reads fine on both a light and dark canvas —
       what actually matters is that the white button label stays readable
       against the fill. #be123c/#e11d48 give the label 6.3:1 / 4.7:1
       contrast; the lighter rose-400/500 shades this used to fade toward on
       hover(-reverse) dropped as low as 2.7:1 against white, which fails
       WCAG AA outright, so the ramp stays within this darker, safe range. */
    --cta-grad: linear-gradient(135deg, #be123c 0%, #e11d48 100%);
    --cta-grad-hover: linear-gradient(135deg, #9f1239 0%, #be123c 100%);
    --cta-shadow: 0 4px 12px -4px rgba(190, 18, 60, 0.30);

    /* Semantic tones — deepened one step each (rose-600→rose-700,
       amber-700→amber-800) to match the calmer accent above, EXCEPT the
       danger color keeps enough saturation to stay unambiguous: this is a
       medical site, and the emergency notice/out-of-scope callouts that
       lean on --danger-solid need to keep reading as urgent, not just
       "muted like everything else." Success stays at its existing depth
       for the same reason — it's already restrained. */
    --danger-solid: #be123c;
    --danger-tint-bg: rgba(190, 18, 60, 0.06);
    --danger-tint-border: rgba(190, 18, 60, 0.20);
    --warning-solid: #92400e;
    --warning-tint-bg: rgba(146, 64, 14, 0.08);
    --warning-tint-border: rgba(146, 64, 14, 0.22);
    /* Deliberately a true green, not the teal brand accent — this is the
       "yes/available" half of a yes/no pair (see .card--success), and needs
       to read as unambiguously distinct from --accent-solid at a glance. */
    --success-solid: #047857;
    --success-tint-bg: rgba(4, 120, 87, 0.06);
    --success-tint-border: rgba(4, 120, 87, 0.20);

    /* The 4 "How It Works" step-card hues — purely decorative, not a
       semantic success/danger/warning role, so they get their own
       dedicated tokens (kept separate from --success-solid/--warning-solid
       above even though green/orange are close in hue) rather than reusing
       those roles, since reusing them would also quietly change this
       card's shade to match whatever success/warning happen to be tuned
       to. Defined as tokens (not the literal hex these 4 classes used
       before) specifically so dark mode can redeclare them: the light
       pastel tints below read as a near-white smear with barely any hue
       left once they sit on a near-black canvas instead of white — that's
       what was "washed out" in dark mode. Solid values match what
       .step-number--* already used inline. */
    --step-green-solid: #047857;
    --step-green-tint-bg: #e5f3ea;
    --step-blue-solid: #2f5fa8;
    --step-blue-tint-bg: #e6eefb;
    --step-orange-solid: #92400e;
    --step-orange-tint-bg: #fbeee0;
    --step-purple-solid: #6d4a9c;
    --step-purple-tint-bg: #f0e9f9;

    --neutral-tint-bg: rgba(30, 30, 30, 0.04);
    --neutral-tint-border: rgba(30, 30, 30, 0.08);

    --active-pill-bg: linear-gradient(135deg, #0f766e 0%, #0d9488 100%);

    --easing: cubic-bezier(0.2, 0, 0, 1);

    /* Radius scale */
    /* --radius-xs added 2026-08-24 — the dashboard's Patient Details panel
       had several small elements (the Note/Data/Plan/Instructions text
       field wrap, the Plan accordion sections, the diagnosis input) all
       independently using a literal 10px rather than any token, purely by
       organic drift rather than deliberate choice. --radius-s (14px) reads
       noticeably too round on these smaller elements, so this fills the
       gap below it rather than forcing them onto the existing scale. */
    --radius-xs: 10px;
    --radius-s: 14px;
    --radius-m: 20px;
    --radius-l: 26px;
    --radius-xl: 32px;

    /* Text — every text color × every surface (canvas/surface/surface-2)
       combination now clears WCAG AAA (7:1), not just AA. text-muted was
       the tightest one to satisfy (weakest contrast by design, since
       it's meant to look de-emphasized) — 4.81:1 on canvas originally
       (barely legal AA), now 8.85:1 on canvas and 7.55:1 even against
       the tile surface, its hardest case. */
    --text-primary: #1a191a;
    --text-secondary: #383735;
    --text-muted: #4a4742;
    --text-on-accent: #ffffff;

    --font-serif: "New York", ui-serif, Charter, "Iowan Old Style", Georgia, Cambria, "Times New Roman", serif;

    /* Flat, solid canvas — no colored radial wash. Depth comes from panel
       elevation/borders, not a tinted glow behind the whole page. */
    --body-bg: var(--canvas);
}

html.dark {
    color-scheme: dark;

    /* Same gray-page/lighter-solid-card relationship as light mode, just
       inverted in direction: near-black canvas, distinctly lighter opaque
       gray cards (Apple's grouped systemBackground scale) — not a
       translucent pane picking up the black behind it. Reverted back to
       the original values — the warm nudge tried here didn't add
       anything dark mode needed (contrast was already 15-19:1), and the
       original cooler near-black read better. */
    --canvas: #060708;
    --surface: #1c1c1e;
    --surface-2: #2c2c2e;
    --border-hairline: rgba(255, 255, 255, 0.09);
    --border-soft: rgba(255, 255, 255, 0.055);

    /* Dark shadows need more opacity than light ones to read at all against
       a near-black canvas, and still benefit from a tight contact shadow +
       a wider soft falloff rather than one flat blur — that combination is
       what keeps a strong shadow looking like a cast shadow instead of a
       smudge. Depth is still carried mainly by the surface being genuinely
       lighter than the canvas; the shadow reinforces it. Nudged calmer
       (slightly lower opacity) alongside the light-mode softening above,
       though dark keeps its own separately-tuned scale since it needs more
       contrast than light mode to read at all. */
    --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.38), 0 6px 16px -6px rgba(0, 0, 0, 0.42);
    --elevation-2: 0 2px 4px rgba(0, 0, 0, 0.42), 0 20px 44px -16px rgba(0, 0, 0, 0.48);
    --elevation-3: 0 4px 8px rgba(0, 0, 0, 0.46), 0 36px 72px -24px rgba(0, 0, 0, 0.52);

    --accent: 45, 212, 191;
    --accent-solid: #2dd4bf;
    --accent-solid-hover: #5eead4;
    --accent-tint-bg: rgba(45, 212, 191, 0.12);
    --accent-tint-border: rgba(45, 212, 191, 0.28);

    /* --cta-grad / --cta-grad-hover / --cta-shadow intentionally not
       redefined here — see the :root definition, they're shared. */

    --danger-solid: #fb7185;
    --danger-tint-bg: rgba(244, 63, 94, 0.12);
    --danger-tint-border: rgba(244, 63, 94, 0.30);
    --warning-solid: #fbbf24;
    --warning-tint-bg: rgba(251, 191, 36, 0.12);
    --warning-tint-border: rgba(251, 191, 36, 0.28);
    --success-solid: #4ade80;
    --success-tint-bg: rgba(74, 222, 128, 0.12);
    --success-tint-border: rgba(74, 222, 128, 0.30);

    /* Brightened the same way success/warning/danger are above — the light
       mode solids (#047857, #2f5fa8, #92400e, #6d4a9c) read as muddy/low-
       contrast on a near-black canvas, and the pastel tints need to become
       an actual dark-mode tint (solid rgba over canvas) rather than
       staying a pale hex that only makes sense on white — that pale hex on
       near-black is exactly what read as "washed out." */
    --step-green-solid: #4ade80;
    --step-green-tint-bg: rgba(74, 222, 128, 0.16);
    --step-blue-solid: #60a5fa;
    --step-blue-tint-bg: rgba(96, 165, 250, 0.16);
    --step-orange-solid: #fbbf24;
    --step-orange-tint-bg: rgba(251, 191, 36, 0.16);
    --step-purple-solid: #a78bfa;
    --step-purple-tint-bg: rgba(167, 139, 250, 0.16);

    --neutral-tint-bg: rgba(255, 255, 255, 0.06);
    --neutral-tint-border: rgba(255, 255, 255, 0.12);

    --active-pill-bg: linear-gradient(135deg, #14b8a6 0%, #10b981 100%);

    --text-primary: #f7f7fa;
    --text-secondary: #dde1e7;
    /* Lightened just slightly from #aeb4bc — that original value cleared
       AAA fine against canvas/surface but only hit 6.67:1 against
       surface-2 (tiles), just short of 7:1. This is the only change in
       dark mode; canvas/surface/surface-2 are untouched. */
    --text-muted: #b8bec6;
    --text-on-accent: #04211d;

    --body-bg: var(--canvas);
}

/* --- Base & Rendering --- */
html {
    -webkit-tap-highlight-color: transparent;
}

body {
    background: var(--body-bg);
    color: var(--text-primary);
    /* Site-wide default is now Quicksand (same family as the intake/
       clinical side), applied here so every element inherits it unless a
       more specific rule below says otherwise. The .text-hero/.text-display/
       .text-title/.stat-value/blog-article-body rules further down each get
       their own explicit Quicksand declaration too (same stack, repeated
       per-rule rather than only relying on inheritance, matching how this
       file already treats typography everywhere else). */
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeSpeed;
    min-height: 100vh;
}

/* The AYAH HEALTH wordmark in the header/footer is deliberately excluded
   from the Quicksand switch above — it keeps the site's original system-
   font treatment so the brand mark itself doesn't change. */
.brand-wordmark {
    font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

h1, h2, h3, .font-display {
    letter-spacing: -0.018em;
    text-rendering: optimizeLegibility;
}

p {
    line-height: 1.65;
}

a {
    color: inherit;
}

*:focus {
    outline: none;
}

*:focus-visible {
    outline: 2px solid rgba(var(--accent), 0.65);
    outline-offset: 2px;
    border-radius: 6px;
}

@media (prefers-contrast: more) {
    :root { --border-hairline: rgba(30, 30, 30, 0.35); }
    html.dark { --border-hairline: rgba(255, 255, 255, 0.35); }
}

/* --- Text Tone Utilities --- */
/* Replace text-slate-900/dark:text-white style pairs with a single class
   that already knows how to flip for dark mode via the variables above. */
.text-primary  { color: var(--text-primary); }
.text-secondary { color: var(--text-secondary); }
.text-muted    { color: var(--text-muted); }
.text-accent   { color: var(--accent-solid); }
.text-danger   { color: var(--danger-solid); }
.text-warning  { color: var(--warning-solid); }
.text-success  { color: var(--success-solid); }

/* Tailwind can only generate a `hover:`/`group-hover:` variant for
   utilities IT knows about — since these are our own custom classes (not
   real Tailwind theme colors), hover:text-secondary / hover:text-danger /
   hover:text-accent / group-hover:text-accent all compile to nothing under
   Tailwind's JIT even though several pages use them (e.g. admin-editor.html's
   tab switcher label and remove-category button) — these were silently
   no-ops under the old CDN setup too. Defined by hand here so the intended
   hover effect actually works. (Previously duplicated as two separate rule
   blocks with identical selectors — consolidated into one.) */
.hover\:text-secondary:hover { color: var(--text-secondary); }
.hover\:text-danger:hover { color: var(--danger-solid); }
.hover\:text-accent:hover { color: var(--accent-solid); }
.group:hover .group-hover\:text-accent { color: var(--accent-solid); }

.text-on-accent { color: var(--text-on-accent); }

/* Same story — `scrollbar-none` isn't a built-in Tailwind utility (needs a
   plugin we don't have installed), so the horizontally-scrollable tab strip
   on admin-editor.html has always shown its scrollbar despite this class. */
.scrollbar-none {
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.scrollbar-none::-webkit-scrollbar { display: none; }

/* Legacy Tailwind slate utilities used only inside untouched generated
   content (older stored blog posts) — nudged for contrast, not removed. */
.text-slate-400,
.text-slate-500 {
    color: #52606d !important;
}

/* Safety net: #52606d is only ~3.1:1 against the dark-mode canvas, which
   fails WCAG AA. Old stored content is expected to always pair this class
   with a literal `dark:text-slate-300`/`dark:text-slate-400` class (below),
   but if any post is missing that pairing, this lower-specificity rule
   keeps dark-mode text readable instead of silently going low-contrast.
   Same specificity as the `.dark .dark\:text-slate-*` rule below, so
   source order decides — this comes first, so that rule still wins when
   both classes are present on an element. */
.dark .text-slate-400,
.dark .text-slate-500 {
    color: var(--text-muted) !important;
}

.dark .dark\:text-slate-300,
.dark .dark\:text-slate-400 {
    color: #b3c0d1 !important;
}

/* --- Typography Scale --- */
/* Fluid, single-class replacements for the old text-3xl sm:text-5xl
   md:text-6xl font-extrabold tracking-tight ...-style stacks repeated on
   every page. One class = the full responsive treatment. */
.text-hero {
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: clamp(2.25rem, 1.35rem + 3.6vw, 4rem);
    /* Was 800 (maximum weight at maximum size) — one of the more
       recognizable "generated landing page" signatures. Dropped to 600
       (semibold): still confident and legible as a hero headline at this
       size, without needing to be the boldest possible weight to read as
       important. Size/line-height/letter-spacing untouched. */
    font-weight: 600;
    line-height: 1.05;
    letter-spacing: -0.025em;
    color: var(--text-primary);
}

/* Homepage hero split into two visually distinct lines: a short, slightly
   heavier opening line ("Skip the Wait") and a smaller, lighter second
   line carrying the rest of the headline — rather than one uniform-weight
   block. Both inherit .text-hero's family/line-height/letter-spacing/color;
   only weight (line 1) and size (line 2) are overridden. */
.text-hero-line1 {
    display: block;
    /* Was 700 — a little lighter now (still heavier than line2's inherited
       600 base, just not as stark a jump) so the two lines read as a more
       uniform pair rather than one bold headline stacked over one much
       lighter/smaller subhead. */
    font-weight: 650;
}

.text-hero-line2 {
    display: block;
    /* Bumped up twice now: originally clamp(1.5rem, 0.9rem + 2.6vw, 2.5rem),
       then clamp(1.75rem, 1.1rem + 2.8vw, 2.75rem), now bigger again per
       explicit follow-up feedback that line2 ("Free Evaluation, Pay Only
       on Approval" / "Scope of Care" / "Better Healthcare Insights") still
       read too small next to line1. */
    font-size: clamp(2rem, 1.3rem + 3.2vw, 3.25rem);
    margin-top: 0.2em;
}

/* One-line hero variant — for a hero heading that must never wrap
   (e.g. Services' "Comprehensive Scope of Care"). The vw coefficient is
   tuned so the text fits one line down to ~320px viewports rather than
   using .text-hero's normal clamp, whose 2.25rem floor is too large for
   a ~28-character heading at phone widths. */
.text-hero--compact {
    font-size: clamp(1.125rem, 0.15rem + 4.5vw, 2.75rem);
    white-space: nowrap;
}

.text-display {
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: clamp(1.625rem, 1.35rem + 1.2vw, 2.375rem);
    font-weight: 700;
    line-height: 1.18;
    letter-spacing: -0.017em;
    color: var(--text-primary);
}

/* Same idea as .text-hero--compact above, sized for a longer ~34-character
   .text-display heading ("Making Everyday Healthcare Simple") instead of
   an h1. Declared after .text-display so the font-size override wins the
   same-specificity cascade tie; everything else (weight/color/spacing)
   still comes from .text-display. Floor is lower than .text-hero--compact's
   since this string is longer and needs a smaller minimum size to still
   fit one line at ~320px viewports. */
.text-display--compact {
    font-size: clamp(0.9375rem, 0.1rem + 3.6vw, 2.375rem);
    white-space: nowrap;
}

.text-title {
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: clamp(1.0625rem, 0.98rem + 0.35vw, 1.3125rem);
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.011em;
    color: var(--text-primary);
}

.text-subtitle {
    font-size: clamp(1rem, 0.94rem + 0.25vw, 1.1875rem);
    font-weight: 400;
    line-height: 1.6;
    color: var(--text-secondary);
}

.text-body {
    font-size: 1rem;
    line-height: 1.7;
    color: var(--text-secondary);
}

.text-small {
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--text-muted);
}

.text-caption {
    font-size: 0.6875rem;
    line-height: 1.5;
    letter-spacing: 0.02em;
    color: var(--text-muted);
}

.dot-accent { background-color: var(--accent-solid); }

/* Was a teal→emerald gradient text-fill. Gradient text reads as a stock
   "AI-generated landing page" flourish (color standing in for an actual
   design decision) and it was one of many places teal appeared on the
   hero alone. Plain, confident, solid-color text carries the same
   emphasis without needing a special effect to do it. Class kept (rather
   than removed + call sites edited) so nothing else has to change. */
.text-gradient-accent {
    color: var(--text-primary);
    font-weight: inherit;
}

/* Re-declared here (having already been set once, above the typography
   scale) so they win when combined with .text-hero/.text-display/
   .text-title on the same element — e.g. `<h2 class="text-display
   text-success">`. Both rules share the same single-class specificity, so
   without this, whichever one is later in the file wins the tie, and
   .text-display/.text-title being defined after the first declaration
   meant the heading's default text-primary color was silently winning
   over the intended success/danger/warning/accent tint. Confirmed live on
   Services' "What We Can/Cannot Treat" headings, which were rendering in
   the default heading color instead of green/red. */
.text-accent   { color: var(--accent-solid); }
.text-danger   { color: var(--danger-solid); }
.text-warning  { color: var(--warning-solid); }
.text-success  { color: var(--success-solid); }

/* --- Eyebrow / Label Pills --- */
/* Default eyebrow is a neutral pill, not brand-teal. There are ~30 of
   these across the marketing pages (one on nearly every card/section),
   so leaving the base variant teal meant the accent color was painting
   almost everything on the page rather than marking anything specific.
   Semantic variants (--danger/--warning/--success below) are untouched;
   reach for the new --accent variant below for the rare eyebrow that
   should actually draw the eye. */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.32rem 0.85rem;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    background-color: var(--surface-2);
    color: var(--text-secondary);
    border: 1px solid var(--border-hairline);
    white-space: nowrap;
}

/* Opt-in variant for the rare eyebrow that should still carry the brand
   accent (used sparingly, not as the default). */
.eyebrow--accent {
    background-color: var(--accent-tint-bg);
    color: var(--accent-solid);
    border-color: var(--accent-tint-border);
}

.eyebrow--danger {
    background-color: var(--danger-tint-bg);
    color: var(--danger-solid);
    border-color: var(--danger-tint-border);
}

.eyebrow--warning {
    background-color: var(--warning-tint-bg);
    color: var(--warning-solid);
    border-color: var(--warning-tint-border);
}

.eyebrow--success {
    background-color: var(--success-tint-bg);
    color: var(--success-solid);
    border-color: var(--success-tint-border);
}

/* Mixed-case variant for longer descriptive pill labels (page-top intro
   badges) rather than the short all-caps section eyebrows. */
.eyebrow--text {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
}

/* --- Surface Cards --- */
/* Shared by every card-style section, admin panels, and modals. Flat by
   default — no border, no shadow — the same "large flat cards" treatment
   as the Hormn-style reference this was reworked against: a card reads as
   distinct from the page purely through the --surface/--canvas color step
   (white on warm off-white) and its own generous padding, not an outline
   or a drop shadow. .card--emphasis below opts a specific card back into a
   very light lift for the handful of places that still want one (the hero
   panel, the pricing breakdown, the two promo cards) — everything else on
   the page stays fully flat. (The old `.liquid-glass` alias — kept around
   for a transition period after this class was renamed from an earlier
   glassmorphism look — has been removed: nothing on the site referenced it
   anymore.) */
.card {
    background-color: var(--surface);
    border-radius: var(--radius-l);
    box-shadow: none;
    transition: background-color 0.2s var(--easing), box-shadow 0.2s var(--easing);
}

/* A light lift, not the old two-tier shadow scale — enough to say "this
   one's a little more important" without reintroducing a heavy drop
   shadow anywhere on the page. */
.card--emphasis { box-shadow: var(--elevation-1); }

.card--danger { background-color: var(--danger-tint-bg); }
.card--warning { background-color: var(--warning-tint-bg); }
.card--success { background-color: var(--success-tint-bg); }
/* Teal accent tint — for a card that should read as a notable callout
   (e.g. a sub-brand/product announcement) without resorting to a colored
   border/outline, which the site deliberately avoids (see .card--accent-
   border above). */
.card--accent { background-color: var(--accent-tint-bg); }
/* Light blue tint — reuses the same --step-blue tokens already used on the
   "How It Works" step 2 card, so this isn't a new color introduced just
   for one section; it's already tuned for both themes there (a soft
   wash in light mode, a low-alpha tint in dark mode so it doesn't glow). */
.card--blue { background-color: var(--step-blue-tint-bg); }

/* Previously an accent border, then a stronger shadow. Now just a light
   lift like .card--emphasis — flat cards don't get an outline to signal
   "notice me," they get the same quiet shadow treatment instead. */
.card--accent-border {
    box-shadow: var(--elevation-1);
}

/* Nested tonal sub-cards inside a .card — replaces the old
   bg-white/50 dark:bg-slate-900/50 ad hoc pattern with one tonal surface.
   Border-free for the same reason as .card above — the surface-2/surface
   color step is enough to read as a distinct tile without an outline. */
.tile {
    background-color: var(--surface-2);
    border-radius: var(--radius-s);
}

.tile--danger { background-color: var(--danger-tint-bg); }
.tile--warning { background-color: var(--warning-tint-bg); }
.tile--success { background-color: var(--success-tint-bg); }

/* Square icon containers used ahead of headings across cards. Default is
   now a neutral tile rather than a teal-tinted one — this is the "one
   Font Awesome icon per benefit in a colored circle" pattern repeated
   ~16 times across the homepage and services page alone, so a teal
   default here meant the brand color was really just decorating every
   single benefit rather than highlighting anything. .icon-tile--accent
   below is there for the rare tile that should still stand out. */
.icon-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-s);
    background-color: var(--surface-2);
    color: var(--text-secondary);
    flex-shrink: 0;
}

.icon-tile--accent { background-color: var(--accent-tint-bg); color: var(--accent-solid); }
.icon-tile--danger { background-color: var(--danger-tint-bg); color: var(--danger-solid); }
.icon-tile--warning { background-color: var(--warning-tint-bg); color: var(--warning-solid); }
.icon-tile--success { background-color: var(--success-tint-bg); color: var(--success-solid); }
/* Pairs with .card--blue — a near-white/near-black tile (var(--surface),
   already theme-correct) so the icon shape still reads as distinct on
   top of the tinted card instead of blending flat into it, with the
   icon itself in the same blue as the card's tint for a cohesive look. */
.icon-tile--blue { background-color: var(--surface); color: var(--step-blue-solid); }

/* --- Homepage Hero Decoration ---
   Two independent pieces, both scoped to index.html's hero only:
   1. hero-btn-glow: a small, very subtle radial glow centered behind the
      "Start Free Assessment" button. Active on every screen size. Sized
      to bleed slightly into the paragraph above and the pricing row
      below rather than being confined to the button itself, per explicit
      design direction — this is deliberately restrained (low alpha,
      modest radius), not a decorative centerpiece.
   2. hero-chat-bg: an animated loop of the real intake chat, faded into
      the background. Desktop-only and gated at a wide breakpoint (not
      just "tablet-and-up") because the hero's text column is a fixed
      max-w-3xl (768px) that stays centered at any viewport width — this
      only has genuine empty space to run in once the window is wide
      enough that space actually exists outside that column. Anchored via
      `left: calc(50% + 408px)` relative to the wrapping .relative div
      around the whole hero (see index.html), which is 384px (half the
      768px hero width) plus a 24px gap — an algebraic offset from the
      hero's true edge, not a guessed pixel value, so it cannot overlap
      the hero copy at any width where it's shown at all. */
.hero-btn-glow-wrap {
    position: relative;
    display: inline-block;
}
.hero-btn-glow {
    /* Settled at 0.1 alpha — the 0.18 pass read as a bit too present, this
       is the subtler middle ground between that and the original 0.08. */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 500px;
    height: 290px;
    border-radius: 50%;
    background: radial-gradient(ellipse at center, rgba(15, 118, 110, 0.1), transparent 70%);
    pointer-events: none;
    z-index: 0;
}

.hero-chat-bg {
    display: none;
}
@media (min-width: 1280px) {
    .hero-chat-bg {
        display: flex;
        position: absolute;
        top: 0;
        left: calc(50% + 408px);
        width: 280px;
        flex-direction: column;
        gap: 12px;
        opacity: 0.55;
        pointer-events: none;
        user-select: none;
        z-index: 1;
    }
}
/* Bubble shape/border/shadow now mirror the real intake chat's own
   conventions (see intake/clinical-ui.css: --ui-border + --ui-radius +
   --ui-shadow-card, and the tail-corner treatment on
   .patient-chat-preview__bubble / .provider-message-bubble), just mapped
   onto this site's own tokens (--border-hairline / --radius-xs /
   --elevation-1) instead of duplicating raw values, so this reads as the
   same chat rather than an invented one. */
.hero-chat-bubble {
    max-width: 85%;
    padding: 10px 16px;
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-xs);
    box-shadow: var(--elevation-1);
    font-size: 0.875rem;
    line-height: 1.45;
    opacity: 0;
    transform: translateY(8px);
    animation: heroChatFade 18s ease-in-out infinite;
}
.hero-chat-bubble--left {
    align-self: flex-start;
    background-color: var(--surface);
    color: var(--text-secondary);
    border-bottom-left-radius: 3px;
}
.hero-chat-bubble--right {
    align-self: flex-end;
    background-color: var(--accent-tint-bg);
    border-color: var(--accent-tint-border);
    color: var(--accent-solid);
    border-bottom-right-radius: 3px;
}
.hero-chat-bubble--b1 { animation-delay: 0s; }
.hero-chat-bubble--b2 { animation-delay: 1.8s; }
.hero-chat-bubble--b3 { animation-delay: 3.6s; }
.hero-chat-bubble--b4 { animation-delay: 5.4s; }
.hero-chat-bubble--b5 { animation-delay: 7.2s; }
.hero-chat-bubble--b6 { animation-delay: 9.0s; }
@keyframes heroChatFade {
    0% { opacity: 0; transform: translateY(8px); }
    6% { opacity: 1; transform: translateY(0); }
    72% { opacity: 1; transform: translateY(0); }
    82% { opacity: 0; transform: translateY(-4px); }
    100% { opacity: 0; transform: translateY(-4px); }
}

/* Turn wrapper: stacks a typing indicator and the reply it precedes in
   the exact same grid cell (both children placed at grid-area 1/1), so
   the indicator vanishing and the message fading in read as one line
   changing state — like a real chat — instead of two separate flex
   items that each permanently reserve their own vertical slot (which
   used to leave a visible empty line behind after the indicator faded). */
.hero-chat-turn {
    display: grid;
    align-self: flex-start;
    justify-items: start;
}
.hero-chat-turn > * {
    grid-area: 1 / 1;
}

/* "Typing…" indicator — sits right before the reply it announces
   (hero-chat-bubble--b3 and --b5), sharing the same 18s loop as the
   message bubbles. Retimed so it fully fades out just before its paired
   bubble starts fading in (rather than overlapping mid-fade with it),
   since the two now occupy the same physical spot and would otherwise
   visibly cross over each other. */
.hero-chat-typing {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 12px 14px;
    animation-name: heroChatTypingFade;
}
.hero-chat-typing-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: currentColor;
    opacity: 0.45;
    animation: heroChatDotPulse 1.1s ease-in-out infinite;
}
.hero-chat-typing-dot:nth-child(2) { animation-delay: 0.18s; }
.hero-chat-typing-dot:nth-child(3) { animation-delay: 0.36s; }
.hero-chat-typing--t1 { animation-delay: 2.0s; }
.hero-chat-typing--t2 { animation-delay: 5.6s; }
@keyframes heroChatTypingFade {
    0% { opacity: 0; transform: translateY(6px); }
    2% { opacity: 1; transform: translateY(0); }
    5% { opacity: 1; transform: translateY(0); }
    8% { opacity: 0; transform: translateY(-4px); }
    100% { opacity: 0; transform: translateY(-4px); }
}
@keyframes heroChatDotPulse {
    0%, 100% { opacity: 0.35; transform: scale(0.85); }
    50% { opacity: 0.9; transform: scale(1); }
}

/* Respects reduced-motion preference — bubbles simply hold at full
   visibility (staggered by their own delay so they still "arrive" once,
   just without the recurring loop) instead of animating indefinitely.
   The typing indicator is hidden outright rather than held visible,
   since a permanently-visible "typing…" that never resolves into a
   message would be a confusing, misleading state to freeze on. */
@media (prefers-reduced-motion: reduce) {
    .hero-chat-bubble {
        animation: none;
        opacity: 1;
        transform: none;
    }
    .hero-chat-typing {
        display: none;
    }
    .hero-chat-typing-dot {
        animation: none;
    }
}

/* --- Homepage "How It Works" Step Cards --- */
/* Four purely decorative pastel tints — not semantic like danger/warning/
   success above, so they get their own dedicated tokens rather than
   repurposing those. Used only for the homepage's 4-card step sequence,
   one color per card, so the 4 steps read as a distinct ordered set at a
   glance. Kept muted/pastel to match the rest of the site's calmer
   palette rather than saturated "candy" SaaS colors. */
.step-card--green { background-color: var(--step-green-tint-bg); }
.step-card--blue { background-color: var(--step-blue-tint-bg); }
.step-card--orange { background-color: var(--step-orange-tint-bg); }
.step-card--purple { background-color: var(--step-purple-tint-bg); }

.step-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border-radius: 999px;
    font-weight: 800;
    font-size: 1.375rem;
    color: #ffffff;
    flex-shrink: 0;
}
/* Now pulling from the same --step-*-solid tokens as .step-card--* above
   (was var(--success-solid)/var(--warning-solid) for green/orange, and
   inline #2f5fa8/#6d4a9c for blue/purple) so all 4 badges brighten
   correctly in dark mode along with their cards instead of just 2 of them
   doing so by accident via a borrowed token. */
.step-number--green { background-color: var(--step-green-solid); }
.step-number--blue { background-color: var(--step-blue-solid); }
.step-number--orange { background-color: var(--step-orange-solid); }
.step-number--purple { background-color: var(--step-purple-solid); }

/* .step-number's own text color is a hardcoded white, correct in light
   mode where the 4 solids above are all dark. In dark mode those solids
   flip to brighter, lighter tones (#4ade80/#60a5fa/#fbbf24/#a78bfa) to stay
   visible against the near-black canvas — but white text on top of a
   light amber or light green badge is nearly unreadable. Flipping the
   number's own text to a dark near-black keeps every badge legible in
   dark mode without needing 4 separate "text-on-X" tokens for what's
   really one shared fix. */
html.dark .step-number { color: #1a1a1a; }

/* Neutral circular number badge — same idea as .icon-tile (a numbered/
   iconed square ahead of a heading) but round instead of rounded-square,
   for the several "step 1/2/3" card rows on the Services page. Kept
   separate from .icon-tile rather than changing its shape globally, since
   .icon-tile's rounded-square is still the right shape everywhere else it
   appears (feature grids, etc). */
.number-circle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background-color: var(--surface-2);
    color: var(--text-secondary);
    flex-shrink: 0;
}

/* Callout / notice boxes (emergency notices, policy call-outs) */
.alert {
    display: flex;
    gap: 0.85rem;
    align-items: flex-start;
    border-radius: var(--radius-m);
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--border-hairline);
    background-color: var(--surface-2);
    color: var(--text-secondary);
}

.alert--danger {
    background-color: var(--danger-tint-bg);
    border-color: var(--danger-tint-border);
    color: var(--text-primary);
}

.alert--warning {
    background-color: var(--warning-tint-bg);
    border-color: var(--warning-tint-border);
    color: var(--text-primary);
}

.alert--success {
    background-color: var(--success-tint-bg);
    border-color: var(--success-tint-border);
    color: var(--text-primary);
}

/* Small hover/focus info tooltip — a muted circle-info icon that reveals
   a floating help bubble above it. CSS-only (no JS), keyboard-accessible
   via tabindex + :focus-within. Used next to the admin editor's "Article
   Body Content" label to hold the HTML formatting guidance without
   permanently taking up page space. */
.info-tooltip {
    position: relative;
    display: inline-flex;
    align-items: center;
}
.info-tooltip-icon {
    color: var(--text-muted);
    cursor: help;
    transition: color 0.15s ease;
}
.info-tooltip:hover .info-tooltip-icon,
.info-tooltip:focus-within .info-tooltip-icon {
    color: var(--accent-solid);
}
.info-tooltip-bubble {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: 300px;
    max-width: 80vw;
    padding: 0.75rem 0.875rem;
    background-color: var(--surface-2);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-s);
    box-shadow: var(--elevation-2);
    color: var(--text-secondary);
    font-size: 0.75rem;
    line-height: 1.55;
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 30;
}
.info-tooltip-bubble code {
    background-color: var(--surface);
    border-radius: 4px;
    padding: 0.1em 0.35em;
    font-size: 0.95em;
}
.info-tooltip:hover .info-tooltip-bubble,
.info-tooltip:focus-within .info-tooltip-bubble {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}

/* Stat blocks (pricing highlights row) */
.stat-value {
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: clamp(1.375rem, 1.2rem + 0.7vw, 1.75rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--text-primary);
}

.stat-value--accent { color: var(--accent-solid); }

.stat-label {
    font-size: 0.8125rem;
    color: var(--text-muted);
    margin-top: 0.15rem;
}

/* --- Buttons --- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    border-radius: 999px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    transition: opacity 0.15s var(--easing), transform 0.15s var(--easing), background-color 0.15s var(--easing), box-shadow 0.15s var(--easing);
}

.btn:active { transform: scale(0.97); }

.btn-primary {
    background-color: var(--accent-solid);
    color: var(--text-on-accent);
    box-shadow: var(--elevation-1);
}
.btn-primary:hover { background-color: var(--accent-solid-hover); }

.btn-cta {
    background-image: var(--cta-grad);
    color: #ffffff;
    box-shadow: var(--cta-shadow);
}
.btn-cta:hover { background-image: var(--cta-grad-hover); }

.btn-secondary {
    background-color: var(--surface-2);
    color: var(--text-primary);
    border: 1px solid var(--border-hairline);
}
.btn-secondary:hover { background-color: var(--neutral-tint-bg); }

.btn-danger {
    background-color: var(--danger-tint-bg);
    color: var(--danger-solid);
}
.btn-danger:hover { background-color: var(--danger-tint-border); }

.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background-color: var(--surface);
    border: 1px solid var(--border-hairline);
    color: var(--text-secondary);
    box-shadow: var(--elevation-1);
    transition: color 0.15s var(--easing), transform 0.15s var(--easing), background-color 0.15s var(--easing);
}
.btn-icon:hover { color: var(--accent-solid); }
.btn-icon:active { transform: scale(0.95); }

/* The chat composer buttons are absolutely centered with translateY(-50%).
   The generic button :active transforms above replace (rather than add to)
   that positioning transform, which made iOS Safari appear to drag the
   Send/mic button down by half its height while a touch was held. Preserve
   the centering transform and compose the press feedback after it. The
   extra .chat-input-area scope keeps this exception local to the composer. */
.chat-input-area .composer-action:active {
    transform: translateY(-50%) scale(0.97);
}

.chat-input-area .chat-mic-btn.composer-action:active {
    transform: translateY(-50%) scale(0.95);
}

/* --- Navigation Pill (segmented control) --- */
/* Confirmed (via components.js) reused in at least two places that both
   need to keep working below the header's lg-only breakpoint: the footer's
   theme/admin utility pill (always visible, any width) and, per its own
   "Matching Blog Category Selector" comment, styled to match a blog
   category-filter tablist elsewhere (.cat-btn / [aria-selected] /
   .active-glass-pill below are that pattern). Only the header's instance
   gets hidden below lg — see the @media rules further down, which target
   the header nav specifically rather than this class in general. Hardened
   here so none of its uses can visually break at any width: no wrapping (a
   pill nav wrapping to a second row looks broken), and if its contents are
   ever wider than the viewport it scrolls horizontally within itself
   instead of overflowing the page. */
.pill-nav {
    position: relative;
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    background-color: var(--surface);
    border: 1px solid var(--border-hairline);
    border-radius: 999px;
    box-shadow: var(--elevation-1);
}
.pill-nav::-webkit-scrollbar { display: none; }

.active-glass-pill {
    background: var(--active-pill-bg);
    box-shadow: var(--elevation-1);
    will-change: transform, opacity;
    transition: transform 0.25s var(--easing), opacity 0.2s ease;
}

.cat-btn {
    color: var(--text-secondary);
    flex-shrink: 0;
    white-space: nowrap;
    transition: color 0.15s ease;
}

.cat-btn[aria-selected="true"] {
    color: #ffffff !important;
    font-weight: 600;
}

/* --- Mobile Navigation Popup ---
   A floating card anchored under the hamburger button that overlays page
   content (rather than pushing it down, like an earlier inline-grid version
   of this menu did) and closes on outside click. Deliberately
   position:absolute, not position:fixed — its containing block is the
   position:sticky <header> in components.js, since sticky (like relative/
   absolute/fixed) is a positioned value and establishes a containing block
   for absolutely-positioned descendants per spec. iOS 26 Safari has a
   confirmed, currently-unfixed WebKit engine bug (bugs.webkit.org #302272)
   where any position:fixed (or sticky) element with a background near the
   viewport edges gets sampled to re-tint the address bar/status bar —
   several targeted CSS workarounds (opacity, edge-masking, moving
   background-color onto a child layer) were tried on an earlier
   position:fixed version of this menu and none reliably avoided it, which
   lines up with other developers' reports that this is a rendering-engine
   bug, not something page-level CSS can fully route around. This popup uses
   position:absolute and only ever covers a small anchored card near the
   button — nowhere close to the viewport edges — so there's nothing here
   for that bug to trigger on. The background/border/shadow still live on an
   inner child (.mobile-nav-dropdown-inner) rather than the positioned
   element itself, as extra insurance. */
.mobile-nav-dropdown {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 1rem;
    width: min(340px, calc(100vw - 2rem));
    z-index: 45;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px) scale(0.98);
    transform-origin: top right;
    transition: opacity 0.18s var(--easing), transform 0.18s var(--easing), visibility 0s linear 0.18s;
}

.mobile-nav-dropdown.active {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
    transition: opacity 0.18s var(--easing), transform 0.18s var(--easing), visibility 0s linear 0s;
}

.mobile-nav-dropdown-inner {
    /* Matches --surface, the same token the chat window's card
       (.intake-card, in intake/chat.html) uses for its own background in
       both light (#ffffff) and dark (#1c1c1e) mode — rather than --canvas,
       the page's background tone, which read too close to the header
       behind it. */
    background-color: var(--surface);
    border: 1px solid var(--border-hairline);
    border-radius: var(--radius-m);
    box-shadow: var(--elevation-3);
    overflow: hidden;
}

.mobile-nav-link {
    display: block;
    padding: 1rem 1.1rem;
    border-radius: var(--radius-s);
    font-weight: 500;
    color: var(--text-primary);
    transition: background-color 0.15s var(--easing), color 0.15s var(--easing);
}
.mobile-nav-link:hover { background-color: var(--accent-tint-bg); color: var(--accent-solid); }
.mobile-nav-link.is-active {
    background-color: var(--accent-tint-bg);
    color: var(--accent-solid);
    font-weight: 600;
}

/* Tablet (roughly 768–1023px) now stays on the hamburger + dropdown instead
   of switching to a horizontal desktop nav at 768px — the header's toggle
   button/dropdown and its desktop nav/CTA counterparts use Tailwind's
   `lg:hidden` / `hidden lg:flex` (1024px) in components.js, so this matches
   that breakpoint exactly. Kept here as a defensive duplicate of the same
   cutoff (same reasoning as the original 768px version of this rule): if a
   future page ever renders this header markup without those exact Tailwind
   classes, the mobile chrome still gets force-hidden past 1024px rather
   than silently stacking on top of a desktop nav. */
@media (min-width: 1024px) {
    body #mobile-menu-toggle,
    body .mobile-nav-dropdown {
        display: none !important;
    }
}

/* Same redundancy, the other direction: the header's desktop nav
   (#nav-island-container, wrapped in <nav aria-label="Desktop Navigation">)
   and its adjacent "Start Consult" CTA force-hidden below 1024px so neither
   can double up with the hamburger menu on a tablet even if their
   `hidden lg:flex` classes are ever missing. The CTA has no id of its own,
   but `.btn-primary` linking to the intake chat is unique to it WITHIN THE
   HEADER — the same destination also appears in the mobile drawer (as
   `.btn-cta`), so this doesn't touch that one. Scoped to `header` (not just
   `body`) after this rule was found also hiding the unrelated "Consult with
   Dr. Akram" button on the About page, which happens to share the same
   `.btn-primary` class and `/intake/chat` href but lives in the page body,
   not the header — the un-scoped selector was matching both. Scoped to
   this specific nav instance, not `.pill-nav` generally, since the footer's
   theme/admin pill and any blog category tablist reusing `.pill-nav` are
   meant to stay visible at every width. */
@media (max-width: 1023.98px) {
    body nav[aria-label="Desktop Navigation"],
    body #nav-island-container,
    body header a.btn-primary[href="/intake/chat"] {
        display: none !important;
    }
}

/* --- Interactive Micro-Animations --- */
/* `will-change` is a hint to pre-promote an element to its own compositor
   layer — cheap for a handful of always-animating elements (the nav pill,
   the mobile drawer, below), but expensive if applied unconditionally to
   every button/card on the page: it was previously set here on the bare
   `button, .btn, .interactive-card` selector, which forces a persistent
   GPU layer for every single button on every page, whether or not it's
   ever animated. Scoped to the interaction states that actually trigger a
   transform instead, so the hint only exists right before it's needed. */
button:hover, button:focus-visible,
.btn:hover, .btn:focus-visible,
.interactive-card:hover, .interactive-card:focus-visible {
    will-change: transform;
}

/* Tailwind's Preflight reset (loaded via tailwind.css, before this file)
   sets every <button> to -webkit-appearance:button — not none — as its own
   deliberate normalize choice. On Safari that keeps the OS's native
   push-button chrome (a soft highlight/bevel) active underneath any button
   that doesn't paint its own opaque background over it, which showed up as
   a visible "circle in a circle" halo on intake/dashboard.html's circular,
   background-less search icon buttons — full root-cause writeup is in that
   page's own CSS history. Any button anywhere on the site can hit the same
   issue (a transparent icon-only button, or one using a fully-rounded
   border-radius like .btn-icon), so the reset belongs here once, site-wide,
   rather than patched into each page that happens to have one. */
button {
    -webkit-appearance: none;
    appearance: none;
}

/* --- Universal Form Controls ---
   Background is var(--canvas), not var(--surface): fields should read as
   white wells sitting on the page (light mode), not the same gray as a
   .card. This matters most on admin-editor.html, whose fields inherited
   --surface's gray tone once --surface stopped being white this round —
   canvas stays theme-aware (white in light mode, dark in dark mode) while
   staying visually distinct from the gray .card/.tile surfaces. */
input, textarea, select {
    color: var(--text-primary) !important;
    background-color: var(--canvas) !important;
    border: 1px solid var(--border-hairline) !important;
    border-radius: var(--radius-m);
    font-weight: 500;
    transition: border-color 0.15s var(--easing), box-shadow 0.15s var(--easing);
}

input:focus, textarea:focus, select:focus {
    border-color: rgba(var(--accent), 0.75) !important;
    box-shadow: 0 0 0 3px rgba(var(--accent), 0.15);
}

input::placeholder,
textarea::placeholder {
    color: var(--text-muted) !important;
    opacity: 0.92;
}

label {
    color: var(--text-secondary);
}

/* For an <input> that sits inside another element already styled as a
   .tile/.card (e.g. the URL-slug field with fixed prefix/suffix text) —
   strips the input's own background/border so it doesn't double up. */
.input-plain {
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
}
.input-plain:focus {
    box-shadow: none !important;
}

/* --- Blog Article Typography --- */
/* Serif for reading copy, sans-serif for headings — scoped to the article
   body only so UI chrome (nav, cards, buttons) stays on the system sans
   stack everywhere else. */
/* One font, one size, matching the rest of the site — same sans stack
   and same body-copy size as everywhere else, no serif, nothing blog-
   specific. Priority here is plain readability and consistency, not a
   distinct "article" typographic identity. */
.blog-article-body {
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 1.0625rem;
    line-height: 1.75;
    color: var(--text-secondary);
}

/* Tailwind's Preflight reset (loaded via tailwind.css) sets
   blockquote/dd/dl/figure/h1-h6/hr/p/pre margin to 0 site-wide — h1-h6,
   blockquote, figure, hr, and pre all already have their own margin
   rules below/above, but plain <p> never did. Without this, a classless
   paragraph (which is exactly what every post should be using now) has
   literally zero space before the next one and everything runs
   together. This was always missing; every earlier test article in
   this conversation happened to have mb-4/mb-6 utility classes on its
   paragraphs, which papered over the gap.

   Only top/bottom are set here (as separate longhand properties) —
   deliberately NOT touching margin-left/margin-right. A 3-value
   shorthand like `margin: 0 0 1.25em` would implicitly force both to 0,
   which (being a real selector, higher specificity than a single
   utility class) would silently cancel out `mx-auto` on any paragraph
   that uses it — e.g. the "Need a Virtual Consultation" CTA paragraph
   in manage-post.php, which needs mx-auto to center its max-w-lg box. */
.blog-article-body p {
    margin-top: 0;
    margin-bottom: 1.25em;
}

/* .tile keeps the exact same look it has everywhere else on the site
   (--surface-2 fill, --border-soft hairline, no color/font overrides
   here) — this only adds the card-style elevation shadow on top, since
   tiles standing alone in an article (rather than nested inside a
   .card) read better with a bit of lift. */
.blog-article-body .tile {
    box-shadow: var(--elevation-1);
}

/* Headings/paragraphs used inside an in-article .tile (e.g. a grid of
   topic cards) shouldn't carry the body-level heading top-margin or
   paragraph bottom-margin — those are sized for spacing between
   full-width blocks, and blow out the padding of a compact card.
   Higher specificity than the plain .blog-article-body h1-h6/p rules
   above, so it wins regardless of source order. */
.blog-article-body .tile h1,
.blog-article-body .tile h2,
.blog-article-body .tile h3,
.blog-article-body .tile h4,
.blog-article-body .tile h5,
.blog-article-body .tile h6 {
    margin: 0 0 0.35em;
}
.blog-article-body .tile p {
    margin: 0;
}

/* Long-form reading copy needs more contrast than ordinary secondary UI
   text (labels, captions, etc.), especially in dark mode where the base
   secondary tone can start to feel dim over a full article. */
html.dark .blog-article-body {
    color: #e6e9ee;
}

/* Tailwind's Preflight reset (loaded via tailwind.css) sets every
   heading's font-size and font-weight to `inherit` — so without setting
   both explicitly here, h2/h3/etc. silently collapse down to plain body
   text size and weight and barely read as headings at all. This was
   always missing from this rule; font-size/font-weight are the fix.
   Scale borrowed from .text-display/.text-title above so article
   headings read as the same typographic family as the rest of the
   site. */
.blog-article-body h1,
.blog-article-body h2,
.blog-article-body h3,
.blog-article-body h4,
.blog-article-body h5,
.blog-article-body h6 {
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    letter-spacing: -0.015em;
    line-height: 1.3;
    color: var(--text-primary);
    margin: 1.75em 0 0.6em;
}
.blog-article-body h1 { font-size: clamp(1.75rem, 1.5rem + 1vw, 2.25rem); font-weight: 800; }
.blog-article-body h2 { font-size: clamp(1.4375rem, 1.25rem + 0.75vw, 1.75rem); font-weight: 700; }
.blog-article-body h3 { font-size: clamp(1.1875rem, 1.1rem + 0.35vw, 1.3125rem); font-weight: 700; }
.blog-article-body h4 { font-size: 1.0625rem; font-weight: 600; }
.blog-article-body h5 { font-size: 1rem; font-weight: 600; }
.blog-article-body h6 { font-size: 0.9375rem; font-weight: 600; }
/* The previous version of this rule only zeroed the top margin for the
   article's very first element overall — so a heading landing as the
   first thing inside a NESTED container (a .tile card, the CTA .card,
   a blockquote) still carried its 1.75em top margin, showing up as an
   odd gap above the icon/heading line inside each card. *:first-child
   catches every such case, not just the outermost one. */
.blog-article-body *:first-child { margin-top: 0; }

/* Article bodies are raw HTML typed straight into the admin editor and
   saved as static files under blog-entries/ — that content never passes
   through the Tailwind build, so it can never rely on a Tailwind utility
   class (nothing outside of *.html/*.php/components.js gets scanned when
   the compiled stylesheet is built — see tailwind.config.js). Every tag
   an article is realistically going to use gets a sensible default here,
   so a plain, classless <ul>, <blockquote>, <img>, etc. always looks
   correct with zero dependency on a rebuild ever having "seen" it.

   Everything below is wrapped in :where(.blog-article-body ...) on
   purpose — :where() contributes ZERO specificity, so these are true
   fallback defaults: if an existing post already has its own Tailwind
   classes on a specific element (a fancier table, a custom-sized list,
   etc.), that class always wins outright instead of fighting a same-
   specificity rule here. Only .blog-article-body's own font-size/
   line-height/color and the p → serif rule above stay as plain
   (non-:where) selectors, since those are meant to hold regardless —
   the serif treatment on paragraphs in particular is intentional and
   should stay authoritative. */

:where(.blog-article-body) ul,
:where(.blog-article-body) ol {
    padding-left: 1.375em;
    margin: 1.25em 0;
    display: flex;
    flex-direction: column;
    gap: 0.5em;
}
:where(.blog-article-body) ul { list-style: disc; }
:where(.blog-article-body) ol { list-style: decimal; }
:where(.blog-article-body) li { padding-left: 0.25em; }
:where(.blog-article-body) li > ul,
:where(.blog-article-body) li > ol {
    margin: 0.5em 0 0;
}

:where(.blog-article-body) blockquote {
    margin: 1.5em 0;
    padding: 0.25em 0 0.25em 1.25em;
    border-left: 3px solid rgba(var(--accent), 0.55);
    color: var(--text-primary);
    font-style: italic;
}
:where(.blog-article-body) blockquote p { margin: 0; }

:where(.blog-article-body) img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 1.75em auto;
    border-radius: 14px;
}
:where(.blog-article-body) figure { margin: 1.75em 0; }
:where(.blog-article-body) figure img { margin: 0 auto; }
:where(.blog-article-body) figcaption {
    margin-top: 0.6em;
    text-align: center;
    font-size: 0.8125rem;
    color: var(--text-muted);
}

/* :not(.btn) so a button-styled link dropped into an article — like the
   "Start Your Free Intake" CTA in the card below — keeps its own button
   look instead of being pulled back into plain underlined prose-link
   styling here. */
:where(.blog-article-body) a:not(.btn) {
    color: var(--accent-solid);
    text-decoration: underline;
    text-decoration-color: rgba(var(--accent), 0.35);
    text-underline-offset: 2px;
}
:where(.blog-article-body) a:not(.btn):hover { text-decoration-color: currentColor; }

:where(.blog-article-body) strong,
:where(.blog-article-body) b {
    font-weight: 600;
    color: var(--text-primary);
}

:where(.blog-article-body) code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.875em;
    background-color: var(--surface-2);
    border: 1px solid var(--border-hairline);
    border-radius: 5px;
    padding: 0.15em 0.4em;
}
:where(.blog-article-body) pre {
    margin: 1.5em 0;
    padding: 1em 1.25em;
    background-color: var(--surface-2);
    border: 1px solid var(--border-hairline);
    border-radius: 12px;
    overflow-x: auto;
}
:where(.blog-article-body) pre code {
    background: none;
    border: none;
    padding: 0;
    font-size: 0.8125rem;
    line-height: 1.6;
}

/* Tables get the site's normal "tile" treatment — a solid opaque
   container with a hairline border and rounded corners, a shaded header
   row, and body text that matches surrounding paragraph copy size
   instead of shrinking it — so it reads as one of the site's existing
   card-like elements rather than a bare HTML table. border-collapse:
   separate + border-spacing: 0 is what lets border-radius/overflow work
   on a <table> at all (collapse breaks that). */
/* background-color was missing here, so the table body fell through to
   the page canvas — fine in light mode (canvas is a pale gray close to
   white), but in dark mode canvas (#060708) is much darker than every
   other card/tile on the page (--surface, #1c1c1e), so the table read
   as a jarring near-black hole against the rest of the article. Giving
   it --surface makes it a normal solid opaque panel like every other
   card on the site, per the design system's own "cards are solid,
   opaque fills, never transparent" rule at the top of this file. */
:where(.blog-article-body) table {
    width: 100%;
    margin: 1.75em 0;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid var(--border-hairline);
    border-radius: 14px;
    overflow: hidden;
    font-size: inherit;
    background-color: var(--surface);
}
:where(.blog-article-body) th,
:where(.blog-article-body) td {
    padding: 0.7em 1em;
    text-align: left;
    border-bottom: 1px solid var(--border-hairline);
}
:where(.blog-article-body) tr:last-child td { border-bottom: none; }
:where(.blog-article-body) thead th {
    background-color: var(--surface-2);
    font-family: 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-weight: 600;
    font-size: 0.9em;
    color: var(--text-primary);
}

/* Reusable 3-up card row for article bodies (e.g. "here's what's wrong
   with X" call-outs) — plain CSS Grid instead of Tailwind's grid-cols
   and md: utilities, since those specific classes aren't guaranteed to
   be in the compiled tailwind.css (see the big comment above). Pair
   each child with the site's existing .tile class. Matches Tailwind's
   default md: breakpoint (768px) so it behaves the same either way. */
.blog-article-body .article-grid-3 {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    margin: 1.75em 0;
}
@media (min-width: 768px) {
    .blog-article-body .article-grid-3 {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Same idea as .article-grid-3, 2-up instead of 3-up (e.g. a grid of
   feature/topic tiles). */
.blog-article-body .article-grid-2 {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    margin: 1.75em 0;
}
@media (min-width: 768px) {
    .blog-article-body .article-grid-2 {
        grid-template-columns: repeat(2, 1fr);
    }
}

:where(.blog-article-body) hr {
    margin: 2.5em 0;
    border: none;
    border-top: 1px solid var(--border-hairline);
}

/* Lets the site's existing .alert / .alert--danger / .alert--warning /
   .alert--success callout component be dropped straight into an article
   body (e.g. a "controlled substances excluded" notice) with the right
   spacing against surrounding paragraphs. */
.blog-article-body .alert {
    margin: 1.75em 0;
}
/* A short icon-prefixed list (e.g. "these medications aren't eligible")
   inside an alert reads better as a plain flex/grid list than with the
   article's normal disc/decimal bullets — .alert already provides its
   own padding and color, so strip the list-level styling entirely. */
.blog-article-body .alert ul,
.blog-article-body .alert ol {
    list-style: none;
    padding-left: 0;
    margin: 0;
}

/* --- Layout & Accessibility Performance --- */
.skip-link {
    position: fixed;
    top: 0.75rem;
    left: 0.75rem;
    z-index: 100;
    padding: 0.7rem 1rem;
    border-radius: var(--radius-s);
    background: var(--accent-solid);
    color: var(--text-on-accent);
    font-weight: 700;
    box-shadow: var(--elevation-2);
    transform: translateY(-160%);
    transition: transform 160ms var(--easing);
}

.skip-link:focus {
    transform: translateY(0);
    outline: 3px solid var(--surface);
    outline-offset: 2px;
}

.photo-banner {
    box-shadow: var(--elevation-3);
}

.photo-banner-overlay {
    background: linear-gradient(90deg, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.46) 32%, rgba(0, 0, 0, 0.06) 58%, transparent 68%);
}

.photo-banner-eyebrow {
    color: #fff;
    background-color: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.25);
}

.photo-banner-title {
    color: #fff;
    text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
}

.photo-banner-copy {
    color: rgba(255, 255, 255, 0.9);
}

/* Legal documents use one continuous reading surface with a persistent
   contents rail, rather than presenting every clause as a separate card. */
.legal-main {
    width: 100%;
}

.legal-hero {
    max-width: 52rem;
}

.legal-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    padding-top: 0.25rem;
    color: var(--text-muted);
    font-size: 0.78rem;
    font-weight: 600;
}

.legal-meta span {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.legal-layout {
    display: grid;
    grid-template-columns: minmax(12.5rem, 15rem) minmax(0, 1fr);
    gap: 2rem;
    align-items: start;
}

.legal-sidebar {
    position: sticky;
    top: 6.5rem;
}

.legal-toc {
    border-top: 3px solid var(--accent-solid);
    padding-top: 1rem;
}

.legal-toc-title {
    margin-bottom: 0.65rem;
    color: var(--text-primary);
    font-family: "Quicksand", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.legal-toc nav {
    display: grid;
    gap: 0.2rem;
}

.legal-toc a {
    display: block;
    padding: 0.48rem 0.65rem;
    border-radius: var(--radius-xs);
    color: var(--text-secondary);
    font-size: 0.8rem;
    font-weight: 550;
    line-height: 1.35;
    transition: color 150ms var(--easing), background-color 150ms var(--easing);
}

.legal-toc a:hover,
.legal-toc a:focus-visible {
    color: var(--accent-solid);
    background: var(--accent-tint-bg);
    outline: none;
}

.legal-related {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border-hairline);
}

/* .legal-document (the <article> wrapping every numbered clause) used to
   be a boxed card here — border/background/shadow/rounded corners. No
   longer: the legal body text now sits directly on the bare page
   background, same as every other page that's had its header/text pulled
   out of a wrapping card this round. The class name/element stays in the
   markup (still needed for the legal-layout grid), it just carries no
   visual styling of its own anymore. .legal-section's own padding and the
   section-to-section border-top divider below still do the work of
   visually separating each numbered clause, so nothing about the internal
   reading structure changes — only the outer box is gone. */

.legal-section {
    padding: 1.75rem 2rem;
    scroll-margin-top: 7rem;
}

.legal-section + .legal-section {
    border-top: 1px solid var(--border-hairline);
}

.legal-section > h2 {
    margin-bottom: 1rem;
}

.legal-section p,
.legal-section li {
    max-width: 74ch;
}

.legal-statement {
    padding: 1.15rem 1.35rem;
    border: 1px solid var(--accent-tint-border);
    border-left: 4px solid var(--accent-solid);
    border-radius: var(--radius-s);
    background: var(--accent-tint-bg);
}

.legal-acknowledgment {
    margin-top: 2rem;
}

@media (max-width: 899px) {
    .legal-layout {
        grid-template-columns: 1fr;
        gap: 1.25rem;
    }

    .legal-sidebar {
        position: static;
    }

    .legal-toc nav {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 639px) {
    .legal-main {
        padding-left: 1rem !important;
        padding-right: 1rem !important;
    }

    .legal-section {
        padding: 1.35rem 1.2rem;
    }

    .legal-section > h2 {
        align-items: flex-start;
        font-size: 1.25rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    button, a, .btn, .interactive-card, .active-glass-pill, .card, .mobile-nav-dropdown {
        transition: none !important;
        transform: none !important;
    }
}

.lazy-section {
    content-visibility: auto;
    contain-intrinsic-size: auto 500px;
}
