/* ════════════════════════════════════════════════════════════════
   KinetiqAF — shared design tokens (Sprint design-system-foundation)
   ════════════════════════════════════════════════════════════════

   Single source of truth for COLOR + TYPE FAMILY + TYPE SCALE +
   SPACING + RADIUS + ELEVATION + MOTION tokens consumed by BOTH
   the client portal (/app) and the admin portal (/admin).

   CANONICAL-SOURCE PRINCIPLE
   The /app (client portal) values are canonical for every COLOR
   token. Admin conforms. The client portal is the customer-facing
   brand surface; the internal tool doesn't get to drift it. Per-
   portal overrides exist (see the bottom of each portal's inline
   <style> block) but are STRUCTURAL only (admin density:
   tighter radii). Never color.

   This file lives at public/styles/design-tokens.css and is copied
   verbatim into dist/ by Vite. Both HTML entry points <link> it
   BEFORE their inline <style> blocks so every `var(--token)`
   reference in inline CSS resolves against this layer.

   When tokens are renamed, this file is the canonical site to
   coordinate the rename. Inline CSS in app.html / admin.html
   should reference tokens defined here; defining new colors as
   raw hex literals is a regression.

   Last updated: 2026-06-10
*/

:root {

  /* ───────────────────────────────────────────────────────────────
     COLOR — NEUTRALS
     ─────────────────────────────────────────────────────────────── */

  /* feat/brand-tokens-clinical-blue (2026-06-15) — product-wide repalette to
     the "trusted / clinical / welcoming" brand (warm teal-blue + Inter) per
     CLINICAL_POSITIONING_2026_06_15.md. The historical warm-gold/serif brand
     retires. Old brand tokens below are REMAPPED to the new palette so every
     existing `var(--gold)` / `var(--clay)` / `var(--paper)` reference inherits
     the new colors via cascade; new canonical names (--primary, --surface, …)
     are added alongside. WCAG 2.2 AA verified per pair (notes inline). */

  /* --ink: the canonical near-black — now a cool blue-undertone ink
     (#1A2B33) so text reads as part of the clinical-blue brand. AA: #1A2B33
     on #FFFFFF ≈ 14.9:1. */
  --ink:         #1a2b33;

  /* Surface hierarchy — clean clinical whites/cool greys (no warm bias). */
  --surface:     #ffffff;  /* canonical card / page surface */
  --surface-alt: #f6f8f9;  /* subtle cool elevation */

  /* --app-canvas (fix/surface-contrast): the cool-neutral PAGE tint behind the
     /app portal. Content cards stay --surface (#fff) + --border, so every card
     visibly separates from the page (white-on-tint + hairline). Theme-aware —
     app.html's dark blocks re-point it darker than the card surface so cards
     still lift in dark mode. The named `--bg` alias stays the paper/theme alias
     (it's unused in /app); this is the dedicated canvas token. */
  --app-canvas:  #f4f7f9;
  --soft-blue:   #eaf2f6;  /* brand-tinted near-white (replaces gold-tinted) */
  --paper:       #ffffff;  /* legacy alias → surface */
  --paper-2:     #f6f8f9;  /* legacy alias → surface-alt */
  --paper-3:     #eaf2f6;  /* legacy alias → soft-blue */

  /* Ink scale — text-color hierarchy on surface. */
  --ink-soft:    #3a4a52;  /* body copy — AA on #fff ≈ 9.7:1 */
  /* --muted: secondary/label text. #5A6B73 on #FFFFFF ≈ 4.9:1 — clears AA
     normal-size; on #F6F8F9 ≈ 4.7:1 — clears. */
  --ink-faint:   #5a6b73;

  /* Borders / dividers. */
  --line:        #e1e8eb;

  /* ───────────────────────────────────────────────────────────────
     COLOR — BRAND ACCENTS
     ─────────────────────────────────────────────────────────────── */

  /* --primary: THE clinical-blue brand accent — the primary CTA fill
     (white text on primary). AA: #FFFFFF on #2C7DA0 ≈ 4.6:1 — clears AA
     normal-size for button text. --primary-strong is the darker text-on-
     surface + hover/secondary variant: #1B5A77 on #FFFFFF ≈ 7.0:1. */
  --primary:        #2c7da0;
  --primary-strong: #1b5a77;

  /* refactor/design-coherence-2 (2026-07-09) — canonical primary alpha steps.
     Replace the retired old-navy rgba(26,82,118,*) drift + ad-hoc primary
     rgba()s with a few tokenized transparency stops (44,125,160 = --primary). */
  --primary-a05:    rgba(44,125,160,.05);
  --primary-a10:    rgba(44,125,160,.10);
  --primary-a15:    rgba(44,125,160,.15);
  --primary-a20:    rgba(44,125,160,.20);
  --primary-a30:    rgba(44,125,160,.30);

  /* feat/ds-foundation (2026-06-21) — gallery canonical primary scale. Tints +
     shades the shared components + later phases reach for (e.g. teal-tinted
     "done" rows, hover shades). Names mirror the design-system gallery. */
  --primary-700:    #22617c;   /* darker shade — text-on-tint / hover */
  --primary-050:    #eaf3f7;   /* faint tint surface (≈ --soft-blue) */

  /* --accent-warm: a single warm accent, used SPARINGLY for positives
     (celebrations, streaks, highlights) so the brand stays calm-clinical.
     --accent-warm (#E0954A) is for FILLS / icons / large+bold text. For
     normal-size text on a light surface use --accent-warm-deep (#985E15 on
     #FFFFFF ≈ 5.1:1 — clears AA normal). */
  --accent-warm:      #e0954a;
  --accent-warm-deep: #985e15;

  /* feat/goals-redesign — muted-teal CHIP pair for category chips (state is
     encoded by progress/done; category is a quiet teal label, not a color
     code). Defined here (not inline) so app.html carries no new hex literal. */
  --teal-50:  #e1f5ee;
  --teal-800: #085041;

  /* feat/designv2-accent-line (2026-06-23) — the SIGNATURE of a tracked /
     actionable item card (research-backed: NN/g color-for-meaning +
     consistent-components). Apply `border-left: 3px solid var(--card-accent-tracked)`
     to 100% of "thing you log/act on" cards (habit cards, goal cards, today
     habit rows, goal rows) and 0% of info/history/summary cards (Nutrition
     log-history, session-history, billing rows, notes, plain stat cards).
     One token, one rule — its absence on info cards is now also a signal. */
  --card-accent-tracked: var(--primary);

  /* Old gold / clay brand tokens REMAPPED onto the clinical-blue primary so
     every legacy reference inherits the new brand. (Gold was primary; clay
     was the supporting CTA — both collapse to the single primary blue with a
     darker "strong" secondary.) */
  --gold:        var(--primary);
  --gold-deep:   var(--primary-strong);
  --clay:        var(--primary);
  --clay-deep:   var(--primary-strong);

  /* Sage → success-green family; sky → info-blue (kept distinct from primary
     but in-family); plum retired to a neutral-blue state accent. */
  --sage:        #2e8b6f;
  --sage-deep:   #1f6b54;
  --sky-new:     #3a6e8f;
  --sky-deep:    #1b5a77;
  --plum:        #5a6b73;
  --plum-deep:   #3a4a52;

  /* ───────────────────────────────────────────────────────────────
     COLOR — RESERVED (do NOT use as primary action)
     ─────────────────────────────────────────────────────────────── */

  /* Navy / steel — legacy accent, now folded into the primary-strong navy
     so auth tabs + any steel surface read as the one clinical brand. */
  --steel:       #1b5a77;

  /* ───────────────────────────────────────────────────────────────
     COLOR — SEMANTIC
     ─────────────────────────────────────────────────────────────── */

  /* feat/ds-foundation (2026-06-21) — SEMANTIC RULE (load-bearing): "done /
     complete / success" uses the PRIMARY teal, not a generic green. This is
     the single source for that rule — it kills the green-vs-teal drift across
     the logger done-state, the finish-summary check, and the compliance bars
     (Phase 1 points those hardcoded greens at this token). A literal green is
     still available as --sage / --sage-deep for the rare genuine-green cue
     (e.g. a nutrition "fresh" marker); --success is the action/done color and
     now resolves to --primary. The only current var(--success) consumer is the
     outcome-measure chart normal-band at 8% opacity — visually negligible. */
  --success:        var(--primary);
  --success-strong: var(--primary-strong);
  --warning:        #b5821f;    /* amber — kept for caution states */
  --danger:         #a8474a;    /* minor destructive / dismiss */
  --danger-strong:  #8a2a2d;    /* irreversible destructive (Delete Client) — visually heavier than --danger */
  --info:           var(--primary);

  /* ───────────────────────────────────────────────────────────────
     COLOR — CATEGORICAL (data-viz exception)
     ───────────────────────────────────────────────────────────────
     The CATEGORY-encoding palette for charts / muscle-group bars /
     SDP markers — the LEGITIMATE multi-hue exception to the
     clinical-blue brand. Pre-2026-06-24 these were loud "stoplight"
     saturations (#388e3c green, #f57c00 orange, #c62828 red, etc.)
     that fought the calm clinical look. Re-toned per JK's directive:
     desaturated slate / teal / sage / clay / plum / ochre that sit
     calmly next to --primary, with NO primary-green / primary-orange
     / primary-red. The palette is harmonized off the clinical-blue
     base — lightness/chroma roughly equal across the set so the bars
     read as "categories of the same weight" not "ranked by intensity."
     Document the muscle → token mapping below (stable; new muscle
     groups append --cat-9, --cat-10, ...).
     fix/categorical-color-retone (2026-06-24). */
  --cat-1: #6b8aa3;   /* slate-blue   → Chest    (was #e91e63 pink) */
  --cat-2: #2c7da0;   /* primary teal → Back     (was #1565c0 blue) — explicit brand reuse OK in categorical context */
  --cat-3: #7a5d8c;   /* muted plum   → Shoulders (was #7b1fa2 purple) */
  --cat-4: #2e8b6f;   /* muted sage   → Biceps   (was #0097a7 cyan) */
  --cat-5: #4d8a82;   /* desaturated teal → Triceps (was #00796b teal-green) */
  --cat-6: #6b8a55;   /* olive-sage   → Legs     (was #388e3c primary green) */
  --cat-7: #c08a4a;   /* warm ochre   → Core     (was #f57c00 primary orange) */
  --cat-8: #b06860;   /* muted clay   → Cardio   (was #c62828 primary red) */
  --cat-other: #6a7b87; /* neutral steel → Other / unmatched */

  /* SDP marker — a distinct single token kept as muted ochre/gold so it
     harmonizes with the categorical palette + the clinical-blue base.
     NOT folded into --accent-warm (which stays reserved for genuine
     positives — the SDP marker is a STATE category, not a positive). */
  --sdp-marker: #b08840;   /* re-toned from #c8983a — same hue, lower chroma so it sits calmly next to --primary */

  /* ───────────────────────────────────────────────────────────────
     TYPE — FAMILIES (canonical brand stack)
     ─────────────────────────────────────────────────────────────── */

  /* feat/brand-tokens-clinical-blue — the serif display face (Cormorant)
     retires product-wide. Headings AND body are Inter; data is IBM Plex Mono.
     --font-display now points at the Inter stack so every legacy
     `var(--font-display)` / `var(--serif)` heading + stat number renders in
     Inter (kills serif-on-UI lines + serif stat numbers in one cascade). */
  --font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-sans:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono:    'IBM Plex Mono', 'SF Mono', Menlo, Consolas, monospace;

  /* Legacy alias kept for inline-CSS compatibility — `var(--sans)`
     is referenced ~30 times across both portals; mapping it here
     means the inline rules still resolve correctly after the
     hex-sweep commit. */
  --sans:         var(--font-sans);
  --mono:         var(--font-mono);
  --display:      var(--font-display);

  /* ───────────────────────────────────────────────────────────────
     TYPE — FIXED STEP SCALE  (px-absolute per feat/typography-px-cleanup)
     ─────────────────────────────────────────────────────────────── */
  /* Canonical fixed scale per the design-system spec:
       12 / 14 / 16 / 20 / 28 / 36 / 56
     Token names match their pixel value EXACTLY (no rem cascade).
     The codebase historically carries html { font-size: var(--t-small) }
     which makes the cascade root 14px instead of the UA-default 16px.
     With rem-based tokens, every font-size:var(--t-*) cascaded ~14%
     smaller than its nominal name — `var(--t-body)` (1rem) computed
     to 14px instead of 16px. Absolute px values fix this drift.
     Trade-off: tokens no longer scale with the user-agent
     `font-size` setting (Chrome's "page zoom" still works; only
     the legacy "minimum font size" preference stops scaling these
     tokens). The cog-simplified accessibility overlay is unaffected
     because it overrides specific selectors directly. */
  --ds-12:        12px;
  --ds-14:        14px;
  --ds-16:        16px;
  --ds-20:        20px;
  --ds-28:        28px;
  --ds-36:        36px;
  --ds-56:        56px;

  /* Legacy t-* aliases mapped onto the fixed scale. --t-micro
     (10.4px) stays slightly below the 12px floor — allowed only
     for badge text + timestamps per the pre-existing rule. */
  --t-display-xl: var(--ds-56);
  --t-display-lg: 48px;       /* between ds-36 and ds-56 */
  --t-display-md: var(--ds-28);
  --t-h1:         var(--ds-20);
  --t-h2:         var(--ds-20);
  --t-body-lg:    17px;       /* between ds-16 and ds-20 */
  --t-body:       var(--ds-16);
  --t-small:      var(--ds-14);
  --t-tiny:       var(--ds-12);
  --t-micro:      10.4px;     /* sub-floor; badges only */

  /* ───────────────────────────────────────────────────────────────
     SPACING SCALE
     ─────────────────────────────────────────────────────────────── */

  --s-xs:   0.25rem;
  --s-sm:   0.5rem;
  --s-md:   1rem;
  --s-lg:   1.5rem;
  --s-xl:   2.5rem;
  --s-2xl:  4rem;
  --s-3xl:  6rem;

  /* ───────────────────────────────────────────────────────────────
     RADIUS TOKENS
     ─────────────────────────────────────────────────────────────── */

  /* Three-step radius system per the design-system spec:
       6  = chip / small control
       10 = button / input
       16 = card / panel */
  --r-chip:     6px;
  --r-control:  10px;
  --r-card:     16px;
  --r-pill:     999px;

  /* Legacy aliases kept so inline CSS that references --r / --r-lg /
     --r-sm / --r-md still resolves. Admin overrides --r-card down to
     14px and --r-control down to 8px in its inline <style> for
     trainer-density (documented in docs/design-system.md). */
  --r:          var(--r-card);
  --r-md:       var(--r-control);
  --r-sm:       var(--r-chip);
  --r-lg:       var(--r-card);

  /* ───────────────────────────────────────────────────────────────
     ELEVATION (BOX-SHADOW) TOKENS
     ─────────────────────────────────────────────────────────────── */

  /* Three-step elevation system — controls, lifted cards, modals.
     Values tuned to read as warm/editorial rather than crisp/
     digital. Use these tokens for new work; the existing inline
     CSS uses bespoke shadows that will migrate over time. */
  --shadow-1:   0 1px 2px rgba(26, 26, 26, .06),
                0 1px 3px rgba(26, 26, 26, .08);
  --shadow-2:   0 2px 6px rgba(26, 26, 26, .08),
                0 6px 16px rgba(26, 26, 26, .10);
  --shadow-3:   0 8px 24px rgba(26, 26, 26, .14),
                0 16px 40px rgba(26, 26, 26, .14);

  /* Focus ring — used by every interactive control. Gold-on-paper
     reads as a brand-coherent focus indicator at AA. The 2px ring
     + 2px offset clears 3:1 against every paper-* fill. */
  --focus-ring:           0 0 0 2px var(--paper), 0 0 0 4px var(--gold);
  --focus-ring-on-dark:   0 0 0 2px var(--ink),  0 0 0 4px var(--gold);

  /* ───────────────────────────────────────────────────────────────
     MOTION TOKENS
     ─────────────────────────────────────────────────────────────── */

  --d-fast:     150ms;
  --d-base:     220ms;     /* historical inline-CSS name */
  --d-normal:   var(--d-base);
  --d-slow:     360ms;
  --ease-out:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in:    cubic-bezier(0.4, 0, 1, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

  /* ───────────────────────────────────────────────────────────────
     LEGACY ALIASES — historical inline-CSS names that still
     resolve to the canonical tokens. Letting these live HERE means
     the per-portal :root blocks don't need to redefine them.
     New work should reference the canonical names above; these
     aliases are kept for migration safety, not for new code.
     ─────────────────────────────────────────────────────────────── */

  /* Surfaces */
  --bg:          var(--paper);
  --white:       var(--paper);     /* historical alias; was #fff in some surfaces */
  --parchment:   var(--paper-2);
  --frost:       var(--paper-2);
  --mist:        var(--line);

  /* Type colors */
  --body:        var(--ink-soft);
  --muted:       var(--ink-faint);
  --faint:       var(--ink-faint);
  --text:        #ffffff;            /* on-dark text color (legacy) */
  --light:       rgba(255,255,255,0.65);

  /* Brand alias — honey was the pre-Sprint-13 name for gold */
  --honey:       var(--gold);
  --honey-deep:  var(--gold-deep);
  --gold-text:   var(--gold-deep);

  /* Sky alias — legacy uses --sky / --sky-text */
  --sky:         var(--sky-new);
  --sky-text:    var(--sky-deep);

  /* Type families — historical names. --serif now resolves to the Inter
     stack (the serif brand retired), so every `var(--serif)` UI line +
     stat number renders sans without per-selector edits. */
  --serif:       var(--font-sans);

  /* App-specific status colors that hadn't been tokenized to
     semantic --success / --warning / --danger / --info yet.
     Kept here so both portals share the same exact values. */
  --green:       #15803d;
  --greenf:      #dcfce7;
  --red:         #b91c1c;
  --redf:        #fee2e2;
  --amber:       #b45309;
  --amberf:      #fef3c7;
  --gold2:       #3a8fb5;     /* lighter primary for hover-on-primary states */
  --goldfaint:   var(--soft-blue);  /* brand-tinted near-white for badges */

  /* Dark-text ink stops — used by status pills + warning badges.
     Pre-tokens these were per-file hex variants; consolidating
     here so both portals share the same exact value. */
  --ink2:        #152030;
  --ink3:        #07101c;
  --ink4:        #1c3352;
  --sky2:        #3d95cc;

  /* Marketing-site shared surfaces — repaletted from warm beige to the cool
     clinical surface family. */
  --cream:       #f6f8f9;
  --warm:        #eaf2f6;

  /* --border: canonical light hairline (clinical). The historical value was
     a faint white border for dark surfaces; those now use --border-on-dark. */
  --border:         #e1e8eb;
  --border-on-dark: rgba(255,255,255,0.10);

  /* ───────────────────────────────────────────────────────────────
     NEW CANONICAL NAMES (feat/brand-tokens-clinical-blue)
     Prefer these in new work. The old brand tokens above are remapped
     onto them so legacy references keep working.
     ─────────────────────────────────────────────────────────────── */
  /* --primary / --primary-strong / --accent-warm / --success / --surface /
     --surface-alt / --soft-blue / --border are all defined above. --muted
     mirrors --ink-faint; provided as the canonical name. */
  --muted-strong: var(--ink-soft);

  /* ───────────────────────────────────────────────────────────────
     DARK SURFACE FAMILY (marketing-bold hero + the live-workout bar)
     feat/ds-foundation — codifies the dark palette the public hero and
     the logger top bar already use as hardcoded hex, so they share one
     source. AA: --dark-ink (#EAF2F6) on --dark (#0F1F2C) ≈ 15:1.
     ─────────────────────────────────────────────────────────────── */
  --dark:        #0f1f2c;
  --dark-2:      #15293a;
  --dark-line:   #26414f;
  --dark-ink:    #eaf2f6;
  --dark-muted:  #9fb4c4;

  /* ───────────────────────────────────────────────────────────────
     CONTENT WIDTH (product-calm bounded column)
     feat/ds-foundation — Phase 1 standardizes /app's content width on
     these so Today / Progress / Goals / the logger sit in ONE centered
     column instead of 680 / 940 / full-width. Principle 5: ≤66ch lines.
     ─────────────────────────────────────────────────────────────── */
  --maxw-calm:   720px;   /* default product-calm reading column */
  --maxw-wide:   960px;   /* wider surfaces — tables, two-column layouts */

  /* ───────────────────────────────────────────────────────────────
     DESKTOP LAYOUT (responsive shell + reading measure + panes)
     feat/desktop-foundation (master-prompt STEP 0) — the substrate for
     the phased desktop-responsive layout. The research verdict (NN/g,
     Material, Refactoring UI, Baymard + Jane/Healthie/SimplePractice/
     Whoop/Oura/Strava teardowns): DON'T widen the reading column —
     cap the measure (~66ch / ~680px) and spend leftover desktop width
     on PANES + card grids. These tokens + the utilities at the bottom
     of this file are the shared vocabulary; per-page panes land in
     later steps. Breakpoints: <768 one column · 768–1023 two-col ·
     1024–1279 main+aside · 1280+ wide.
     ─────────────────────────────────────────────────────────────── */
  --container-max:      1280px;  /* portal content shell cap, centered */
  --container-hard-cap: 1440px;  /* never exceed this even on ultrawide */
  --measure:            66ch;    /* ~680px reading-measure cap for prose */
  --bp-tablet:          768px;   /* one-col → two-col */
  --bp-desktop:         1024px;  /* two-col → main + aside */
  --bp-wide:            1280px;  /* aside grids → wide */
  --gutter:             24px;    /* canonical pane / grid gap */
}

/* ───────────────────────────────────────────────────────────────
   PREFERS-REDUCED-MOTION
   ─────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  :root {
    --d-fast:   0ms;
    --d-normal: 0ms;
    --d-slow:   0ms;
  }
}

/* ───────────────────────────────────────────────────────────────
   BOUNDED LISTS (fix/bounded-lists)
   The "Load more (older)" control emitted by window.kafBoundedList — the
   single sanctioned renderer-helper for accumulating history/log/feed lists.
   Centred row; the button inherits the portal .btn-secondary styling so it
   reads identically across /app and /admin. 44px min target (client floor).
   ─────────────────────────────────────────────────────────────── */
.kaf-bl-more-row { text-align: center; margin: .85rem 0 .25rem; }
.kaf-bl-more-row td { padding: .6rem 0; }
.kaf-bl-more { min-height: 44px; }

/* ───────────────────────────────────────────────────────────────
   DESKTOP LAYOUT UTILITIES (feat/desktop-foundation — STEP 0)
   The shared layout vocabulary for the phased desktop work. Mobile-
   first: every utility is a single column by default and only opens
   into panes/grids at the breakpoints above, so WCAG 2.2 Reflow
   (1.4.10) holds — each multi-column layout collapses to one column
   at 320px-equiv / 400% zoom for free.

   Shell cap — the /app content column. `.portal-main` itself is the
   flex:1 child of `.portal-layout` (it must keep growing to fill the
   row next to the sidebar; auto inline-margins on a flex-grow item are
   eaten by the free-space distribution BEFORE the grow, which would
   collapse it to min-content — so we cap the CONTENT, not the flex
   item). Capping the page-bar + each portal-section at --container-max
   and centering them gives the "calm centered spine that doesn't sprawl
   on ultrawide" without touching the flex row. Below the cap width the
   max-width simply doesn't bind and the column fills as before. */
.portal-main > .portal-page-bar,
.portal-main > .portal-section {
  max-width: var(--container-max);
  margin-inline: auto;
}

/* Reading measure — cap body prose at ~66ch so long-form copy never
   runs past a comfortable line length even inside a wide pane. */
.prose { max-width: var(--measure); }

/* Card grid — auto-fit responsive grid; spends leftover width on more
   columns instead of widening each card. Collapses to one column when
   the viewport can't fit a 280px track. */
.card-grid {
  display: grid;
  gap: var(--gutter);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

/* Two-pane — main + fixed 320px aside, but only from --bp-desktop up.
   Below that the children are normal-flow blocks (one column). */
@media (min-width: 1024px) {
  .two-pane {
    display: grid;
    gap: var(--gutter);
    grid-template-columns: minmax(0, 1fr) 320px;
  }
}

/* ───────────────────────────────────────────────────────────────
   SERVICE-WORKER UPDATE PROMPT (fix/sw-auto-update)
   The non-blocking "A new version is available — Reload" banner emitted by
   window.kafSwAutoUpdate. Fixed to the bottom, centred, above content but it
   never blocks interaction with the page behind it (a workout/check-in keeps
   going until the user taps Reload). Clinical-blue surface; 44px tap targets.
   ─────────────────────────────────────────────────────────────── */
.kaf-update-banner {
  position: fixed;
  left: 50%;
  bottom: max(1rem, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 2147483000;            /* above app chrome + modals, below nothing */
  display: flex;
  align-items: center;
  gap: .6rem;
  max-width: min(92vw, 30rem);
  padding: .6rem .7rem .6rem 1rem;
  background: var(--primary, #2c7da0);
  color: #fff;
  border-radius: var(--r-card, 14px);
  box-shadow: 0 8px 28px rgba(15, 31, 44, .28);
  font-size: var(--t-small, .875rem);
}
.kaf-update-banner-msg { flex: 1 1 auto; line-height: 1.35; }
.kaf-update-banner-reload {
  flex: 0 0 auto;
  min-height: 44px;
  padding: .35rem .9rem;
  border: 0;
  border-radius: var(--r-control, 10px);
  background: #fff;
  color: var(--primary-strong, #1b5a77);
  font-weight: 700;
  font-size: var(--t-small, .875rem);
  cursor: pointer;
}
.kaf-update-banner-dismiss {
  flex: 0 0 auto;
  min-width: 44px;
  min-height: 44px;
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
@media (prefers-reduced-motion: no-preference) {
  .kaf-update-banner { animation: kaf-update-rise var(--d-normal, 200ms) ease both; }
  @keyframes kaf-update-rise { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; transform: translate(-50%, 0); } }
}
