/* =============================================================================
   Capibrain · Shared styles
   =============================================================================

   This file is the foundation that every Capibrain page links to. It declares
   the design tokens (colours, type, spacing, radii, motion) and a small set
   of universal component base classes (cards, buttons, pills, tooltips).

   ── Authority ──────────────────────────────────────────────────────────────
   Source of truth: /DESIGN_SYSTEM.md at the project root. If anything in this
   file contradicts that document, the document wins and this file is wrong.

   ── What's in here ─────────────────────────────────────────────────────────
   1.  Geist font import (Google Fonts)
   2.  CSS custom properties — tokens at :root
   3.  Reset and base elements (html, body, *, ::selection, scrollbars)
   4.  Numbers (.num)
   5.  Labels (.label)
   6.  Cards (.card)
   7.  Buttons (.btn)
   8.  Status pills (.pill)
   9.  Tooltips (.tooltip)
   10. Focus rings
   11. Reduced motion
   12. Platform shell layout (.shell, .topbar, .rail, .bottom-nav, footer)  [added in v2]
   13. Print styles  /  notifications dropdown  /  print fallback
   14. Video embed (.video-embed) — privacy-safe click-to-load facade  [added in v3]

   ── What's deliberately NOT in here ────────────────────────────────────────
   - Page-specific layout (header, sidebar, grid templates)
   - Tool-specific styling (mortgage optimiser, glossary popups)
   - Article/prose/dashboard styles used only by /learn (.article-*, .prose,
     .dash-block, .aside-*, etc.) — still inline per page; future extraction

   Pages that need page-level layout add it on top of this in their own
   <style> block or page-specific CSS file.

   ── How to use ─────────────────────────────────────────────────────────────
   <link rel="stylesheet" href="/shared/styles.css" />

   That's it. Everything inside this file is automatic from there. Geist loads
   from Google Fonts, tokens are available as CSS variables, and the base
   classes can be used directly.

   Pages that depend on v2 (platform shell) styles can append a cache-busting
   query string to ensure fresh load on first visit after deploy:
     <link rel="stylesheet" href="/shared/styles.css?v=2" />

   ── Versioning ─────────────────────────────────────────────────────────────
   v1 · 2026-05-05 · Initial extraction from the design system doc.
   v2 · 2026-05-22 · Added platform shell layout (sec. 12). Previously
                      duplicated across 7+ pages as inline <style> blocks.
                      shell.js depends on these classes being globally
                      available.
   v3 · 2026-05 ·    Added video-embed facade (sec. 14). Pairs with
                      /shared/video-embed.js. Previously inline on the
                      inflation + offset /learn pages; promoted here so the
                      pattern is single-source. Bump consuming pages'
                      styles.css cache-buster (?v=4 → ?v=5) in the same commit.

   ============================================================================= */


/* ----------------------------------------------------------------------------
   1. Fonts
   ----------------------------------------------------------------------------
   Geist Sans for all UI text. Geist Mono for numbers and code.

   Loaded with display=swap so text renders immediately in the system fallback
   while Geist downloads. Avoids invisible text during font load (FOIT).

   Specific weights: 400 (body), 500 (medium emphasis), 600 (subtle headings),
   700 (titles), 800 (display). We import only what we use to keep the font
   payload small.
   ---------------------------------------------------------------------------- */

@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700;800&family=Geist+Mono:wght@400;500;700&display=swap');


/* ----------------------------------------------------------------------------
   2. Tokens — design system variables
   ----------------------------------------------------------------------------
   These are the only values allowed in production code. Pages MUST reference
   tokens, not raw hex/px values. If you find yourself wanting `#4ade9a`
   inline, use `var(--accent)` instead.

   See DESIGN_SYSTEM.md §3, §4, §5, §6 for rationale.
   ---------------------------------------------------------------------------- */

:root {
  /* === Surfaces === */
  --bg:           #0f1117;  /* page background */
  --surface:      #181c27;  /* top bar, rail, footer — chrome surfaces */
  --card:         #1e2235;  /* cards, raised surfaces */
  --card-raised:  #252a3f;  /* hover/active state on cards */

  /* === Borders === */
  --border:        #2a2f45; /* default borders, dividers */
  --border-strong: #3a4060; /* focus rings, active states */

  /* === Text === */
  --text:     #e6e9f0;  /* primary text (headings, body) */
  --text-dim: #b8bdcc;  /* secondary text, descriptions */
  --muted:    #8a92a3;  /* captions, labels, placeholders */

  /* === Accents ===
     Each accent has a "dimmed" variant for subtle backgrounds (e.g. a mint
     panel behind a positive metric). Dimmed variants are dark tints, not
     transparency — they composite cleanly over --bg. */
  --accent:     #4ade9a;  /* mint — primary actions, positive, "live" */
  --accent-hover: #5fe4a4; /* mint slightly lighter — primary button hover */
  --accent-dim: #1a3a2a;  /* mint dimmed */
  --warn:       #fbbf24;  /* amber — caution */
  --warn-dim:   #2d2310;  /* amber dimmed */
  --danger:     #f87171;  /* red — errors, blocked */
  --danger-dim: #3a1a1a;  /* red dimmed */
  --blue:       #60a5fa;  /* blue — informational */
  --blue-dim:   #0c2a3a;  /* blue dimmed */
  --highlight:  #c084fc;  /* magenta — special emphasis (max 1-2 per screen) */

  /* === Effects === */
  --accent-glow: rgba(74, 222, 154, 0.15);  /* logo glow, button focus aura */

  /* === Typography === */
  --font-sans: 'Geist', system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Type scale. clamp() values let display + headline scale with viewport;
     the smaller sizes are fixed because they shouldn't scale (a 14px body
     on a 320px phone reads identically to a 14px body on a 4K monitor). */
  --fs-display:  clamp(36px, 6vw, 64px);   /* marketing hero only */
  --fs-headline: clamp(22px, 3vw, 32px);   /* section/page titles */
  --fs-title:    17px;                     /* card/panel titles */
  --fs-body:     14px;                     /* body copy */
  --fs-caption:  12px;                     /* help text, meta */
  --fs-micro:    10px;                     /* labels, eyebrows, tags */

  /* === Spacing — dense scale === */
  /* The default scale. Used by the platform shell and all tools. Base unit
     is --space-4 (16px). Card padding, card gaps, and section spacing are
     all multiples of this base. */
  --space-0:  0;
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;   /* base */
  --space-5:  20px;
  --space-6:  24px;
  --space-8:  32px;
  --space-10: 40px;
  --space-12: 48px;

  /* === Spacing — comfortable scale === */
  /* Used only on the marketing landing and (future) /learn content. These
     are dedicated tokens (not multiples of --space-4) because the rhythm of
     editorial copy is intentionally different from dashboard density. */
  --space-comfortable-section:    80px;  /* between landing sections */
  --space-comfortable-paragraph:  24px;  /* between paragraphs */
  --space-comfortable-card-pad:   28px;  /* card padding on landing */
  --space-comfortable-grid-gap:   20px;  /* between cards on landing */

  /* === Corner radii === */
  --radius-sharp: 0;       /* chrome (top bar, rail, bottom nav) */
  --radius-sm:    6px;     /* buttons, badges, small inputs */
  --radius-md:    10px;    /* default for cards */
  --radius-lg:    14px;    /* large cards */
  --radius-pill:  9999px;  /* pill buttons, status pills */

  /* === Motion === */
  /* Default easing is Material's "fast out, slow in" — feels snappy without
     being jarring. The bounce easing has a slight overshoot for entrance
     animations (the hero blocks). Linear is reserved for the ticker scroll
     and indeterminate progress only. */
  --easing-default: cubic-bezier(0.4, 0, 0.2, 1);
  --easing-bounce:  cubic-bezier(0.34, 1.3, 0.64, 1);
  --duration-fast:  150ms;  /* default for hovers, state changes */
  --duration-slow:  700ms;  /* entrance/build animations */
  --duration-ambient: 4000ms; /* breathing, ambient motion */
}


/* ----------------------------------------------------------------------------
   3. Reset and base elements
   ----------------------------------------------------------------------------
   Lightweight reset — just the essentials. Box sizing inherited everywhere.
   System defaults for forms (so they feel native on each platform).
   ---------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  /* Use both vh and dvh — dvh respects mobile browsers' dynamic chrome
     (URL bar collapse on iOS Safari). vh fallback for older browsers. */
  min-height: 100vh;
  min-height: 100dvh;
  /* Smoother font rendering on macOS and iOS. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Default body type is body size with comfortable line-height. */
  font-size: var(--fs-body);
  line-height: 1.55;
}

/* Selection colour — mint background, dark text. A small but consistent
   moment of brand presence whenever the user highlights something. */
::selection {
  background: var(--accent);
  color: var(--bg);
}

/* Default headings. Pages override per their own type scale, but a sensible
   base prevents browser defaults (which are usually too big and bold). */
h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
}

/* Default link styling — used in body copy. Pages with custom navigation
   override per-element. */
a {
  color: var(--accent);
  text-decoration: none;
  transition: opacity var(--duration-fast) var(--easing-default);
}
a:hover { opacity: 0.85; }

/* Buttons inherit font from the page (browsers don't by default). Reset is
   minimal — actual button styling comes from .btn classes below. */
button {
  font-family: inherit;
  font-size: inherit;
  cursor: pointer;
}

/* Form inputs inherit too, for the same reason. */
input, select, textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

/* Custom scrollbar — subtle but on-brand. Webkit only (Firefox uses native
   styling). The thumb is dim by default and brightens on hover. */
::-webkit-scrollbar      { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }


/* ----------------------------------------------------------------------------
   4. Numbers — always monospace
   ----------------------------------------------------------------------------
   Per DESIGN_SYSTEM.md §4.3, numerical values always use the mono font.
   This class is the convenience wrapper for inline use.

   Usage:
     <span class="num">$3,200</span>
     "your monthly bill is <span class="num">$3,200</span>"
   ---------------------------------------------------------------------------- */

.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;  /* equal-width digits for alignment */
}


/* ----------------------------------------------------------------------------
   5. Labels and eyebrows
   ----------------------------------------------------------------------------
   Tiny uppercase text used for section labels, eyebrow text above titles,
   metric labels above numbers. The letter-spacing gives them visual rhythm.
   ---------------------------------------------------------------------------- */

.label {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.4;
}


/* ----------------------------------------------------------------------------
   6. Cards
   ----------------------------------------------------------------------------
   The most-used component. Three sizes:

   .card     — default; --space-4 padding, --radius-md radius
   .card-lg  — feature cards on the landing; --space-5 padding, --radius-lg
   .card-sm  — tight cards inside panels; --space-3 padding

   Add .card.interactive for cards that should respond to hover. Most cards
   on the platform are NOT interactive (they're just containers); save the
   hover state for cards that actually navigate or expand on click.
   ---------------------------------------------------------------------------- */

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}
.card-lg { padding: var(--space-5); border-radius: var(--radius-lg); }
.card-sm { padding: var(--space-3); }

.card.interactive {
  cursor: pointer;
  transition: transform var(--duration-fast) var(--easing-default),
              border-color var(--duration-fast) var(--easing-default),
              background var(--duration-fast) var(--easing-default);
}
.card.interactive:hover {
  border-color: var(--accent);
  background: var(--card-raised);
  transform: translateY(-1px);
}


/* ----------------------------------------------------------------------------
   7. Buttons
   ----------------------------------------------------------------------------
   Three variants:

   .btn-primary   — mint, dark text. The main "do this thing" CTA.
   .btn-secondary — card-coloured with border. Less prominent action.
   .btn-ghost     — transparent. For tertiary actions (cancel, close).

   Sizes:
   .btn-sm — smaller padding, micro font
   .btn (default) — body font, comfortable padding
   .btn-lg — bigger, used for hero CTAs

   Don't combine .btn-primary with .btn-secondary etc. Pick one variant per
   button.
   ---------------------------------------------------------------------------- */

.btn {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 600;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background var(--duration-fast) var(--easing-default),
              border-color var(--duration-fast) var(--easing-default),
              color var(--duration-fast) var(--easing-default);
  white-space: nowrap;
  /* Prevent iOS Safari's tap highlight grey-out, which clashes with our
     own hover/active states. */
  -webkit-tap-highlight-color: transparent;
}

.btn-primary {
  background: var(--accent);
  color: var(--bg);
}
.btn-primary:hover {
  /* Slightly lighter mint on hover — perceptible without being garish. */
  background: var(--accent-hover);
}

.btn-secondary {
  background: var(--card);
  color: var(--text);
  border-color: var(--border);
}
.btn-secondary:hover {
  background: var(--card-raised);
  border-color: var(--border-strong);
}

.btn-ghost {
  background: transparent;
  color: var(--text-dim);
}
.btn-ghost:hover {
  background: var(--card);
  color: var(--text);
}

.btn-sm {
  font-size: var(--fs-caption);
  padding: 6px 10px;
}
.btn-lg {
  font-size: var(--fs-title);  /* 17px — matches card titles, feels CTA-prominent */
  padding: 12px 22px;
  border-radius: var(--radius-md);
}

/* Disabled state — applies to any button variant. */
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}


/* ----------------------------------------------------------------------------
   8. Status pills
   ----------------------------------------------------------------------------
   Small uppercase pills for status indicators ("Live", "Soon", "Beta", "New").
   Always border + transparent background — never filled. The variant classes
   set the colour.

   Usage:
     <span class="pill pill-live">Live</span>
     <span class="pill pill-soon">Soon</span>
   ---------------------------------------------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-micro);
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: var(--radius-pill);
  border: 1px solid;
  line-height: 1;
  background: transparent;
}
.pill-live { color: var(--accent); border-color: var(--accent); }
.pill-soon { color: var(--muted); border-color: var(--border); }
.pill-beta { color: var(--accent); border-color: var(--accent); }
.pill-new  { color: var(--highlight); border-color: var(--highlight); }


/* ----------------------------------------------------------------------------
   9. Tooltips
   ----------------------------------------------------------------------------
   Pure CSS tooltips — no JS dependency. Works for the rail icon labels and
   anywhere else we want hover hints.

   Usage (on a parent that has a child .tooltip):
     <button class="has-tooltip">
       <span class="icon">...</span>
       <span class="tooltip">App name</span>
     </button>

   The 600ms delay before fade-in prevents the tooltip from flashing during
   quick mouse-throughs. Once visible, fade-out is instant.
   ---------------------------------------------------------------------------- */

.tooltip {
  position: absolute;
  background: var(--card-raised);
  color: var(--text);
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-caption);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  z-index: 100;
  /* Fade out instantly on mouseleave. The hover state below adds the
     600ms delay before fade-in to suppress noise from quick mouse-throughs. */
  transition: opacity var(--duration-fast) var(--easing-default);
}
.has-tooltip {
  position: relative;
}
.has-tooltip:hover .tooltip,
.has-tooltip:focus-visible .tooltip {
  opacity: 1;
  /* On hover, wait 600ms before fading the tooltip in. This filters out
     incidental mouseovers (e.g. mouse-throughs across the rail) so the
     tooltip only appears when the user has actually paused on a control. */
  transition: opacity var(--duration-fast) 600ms var(--easing-default);
}


/* ----------------------------------------------------------------------------
   10. Focus rings
   ----------------------------------------------------------------------------
   Every interactive element gets a visible focus ring on keyboard focus.
   Uses :focus-visible so it only appears for keyboard users — mouse clicks
   don't trigger it (which would be visual noise).

   The ring is offset slightly so it doesn't sit on the element's border.
   ---------------------------------------------------------------------------- */

button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--border-strong);
  outline-offset: 2px;
}


/* ----------------------------------------------------------------------------
   11. Reduced motion
   ----------------------------------------------------------------------------
   Users with motion sensitivity (vestibular disorders, focus difficulties)
   get instantaneous transitions instead of animations. Doesn't disable
   transforms — state still changes — just makes them happen instantly.

   This is a hard accessibility requirement and applies globally.
   ---------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ============================================================================
   12. Platform shell layout  (NEW in v2 — Session 16)
   ============================================================================
   The shared chrome that appears on every page with a platform shell:
   topbar, left rail, mobile bottom nav, and platform footer.

   Pages opt into the shell by including these placeholder elements:

     <header class="topbar"     id="topbar-root"></header>
     <nav    class="rail"       id="rail-root" aria-label="Apps"></nav>
     <nav    class="bottom-nav" id="bottom-nav-root" aria-label="Apps"></nav>
     <footer class="platform-footer no-print" id="footer-root"></footer>

   ...wrapping the page content in <div class="shell"> with <main class="main">
   inside. The shell.js module fills the placeholders with the actual markup
   (brand mark, nav icons, etc).

   The CSS below was previously duplicated across 7+ pages as inline <style>
   blocks. Promoted here in Session 16 so a single edit propagates everywhere.

   ── Authority ──
   DESIGN_SYSTEM.md §2.2 (platform shell skeleton) is the source of truth
   for the dimensions, sticky behaviour, and breakpoints below.
   ============================================================================ */

/* Outer flex container. Stretches to viewport so footer sticks to bottom on
   short pages. */
.shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* === Topbar === */
/* Sticky at the top, sharp corners (chrome stays substantial per §6).
   The double height calc accounts for iOS Safari's safe-area inset on
   notched devices so content isn't hidden under the notch. */
.topbar {
  height: 60px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  padding: 0 var(--space-4);
  padding-top: env(safe-area-inset-top, 0px);
  height: calc(60px + env(safe-area-inset-top, 0px));
}

.topbar-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
  color: var(--text);
  transition: color var(--duration-fast) var(--easing-default);
}
.topbar-brand:hover .topbar-brand-name { color: var(--accent); }

.topbar-brand-logo {
  display: inline-flex;
  align-items: center;
  color: var(--accent);
}
.topbar-brand-logo svg {
  display: block;
  height: 28px;
  width: auto;
}

.topbar-brand-text {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.topbar-brand-name {
  font-weight: 800;
  font-size: var(--fs-title);
  letter-spacing: -0.025em;
  color: var(--text);
  margin: 0;
  transition: color var(--duration-fast) var(--easing-default);
}

.topbar-right {
  margin-left: auto;
  display: flex;
  gap: var(--space-2);
}

.topbar-btn {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-dim);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  transition: background var(--duration-fast) var(--easing-default),
              border-color var(--duration-fast) var(--easing-default),
              color var(--duration-fast) var(--easing-default);
}
.topbar-btn:hover {
  background: var(--card);
  color: var(--text);
  border-color: var(--border);
}

/* Size SVG icons inside topbar buttons. Without this, SVGs that lack
   explicit width/height attributes default to 300x150 (the SVG spec
   default) and get clipped to near-invisibility inside the 36px button
   on iOS Safari. The bell SVG rendered by shell.js has explicit
   attributes, but page-passed extras (e.g. /app/'s Info and Refresh
   icons) typically only set viewBox — they need this rule. */
.topbar-btn svg {
  width: 18px;
  height: 18px;
}

/* Refresh spin animation. Applied via `.is-refreshing` class on the
   refresh button (toggled by the page's refresh handler). Defined here
   so any tool using a refresh button via shell.js's rightExtraButtons
   gets the animation for free. */
.topbar-btn.is-refreshing svg {
  animation: refresh-spin 600ms var(--easing-default);
}
@keyframes refresh-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* === Topbar Inputs button (tool-specific) ===
   The Inputs hamburger sits next to the brand on tools that have an
   inputs panel (currently /mortgage/). It's distinct from .topbar-btn
   because it has a text label, a background fill, and an active state
   when the inputs are open. Passes via shell.js's leftExtraButtons so
   it sits BETWEEN the brand and .topbar-right. */
.topbar-inputs-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--text);
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--duration-fast) var(--easing-default),
              border-color var(--duration-fast) var(--easing-default);
  -webkit-tap-highlight-color: transparent;
  /* Push slightly right of the brand block. */
  margin-left: var(--space-2);
}
.topbar-inputs-btn:hover {
  background: var(--card-raised);
  border-color: var(--border-strong);
}
.topbar-inputs-btn svg {
  width: 16px;
  height: 16px;
  color: var(--text-dim);
}
/* When inputs are open (sidebar visible / drawer open), give the button a
   subtle accent treatment so users know it's the "active" toggle state. */
.topbar-inputs-btn.is-open {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
.topbar-inputs-btn.is-open svg { color: var(--accent); }

/* On mobile (<700px), hide the "Inputs" text label — the hamburger icon
   alone is the affordance, saving header space. Also tighten padding. */
@media (max-width: 700px) {
  .topbar-inputs-btn { padding: 0 var(--space-2); }
  .topbar-inputs-btn-label { display: none; }
}

/* === Shell body wrapper === */
/* Holds the rail and main content side-by-side. flex: 1 makes it expand to
   fill the remaining viewport height between topbar and footer. */
.shell-body {
  display: flex;
  flex: 1;
  min-height: 0;
}

/* === Left rail (desktop) === */
/* Sticky beneath the topbar; sized 64px wide per DESIGN_SYSTEM.md §2.2.
   Top offset accounts for the topbar plus safe-area inset. */
.rail {
  width: 64px;
  background: var(--surface);
  border-right: 1px solid var(--border);
  position: sticky;
  top: calc(60px + env(safe-area-inset-top, 0px));
  height: calc(100vh - 60px - env(safe-area-inset-top, 0px));
  flex-shrink: 0;
  padding: var(--space-3) 0;
}
.rail ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  align-items: center;
}

.rail-item {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  text-decoration: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  position: relative;
  transition: background var(--duration-fast) var(--easing-default),
              color var(--duration-fast) var(--easing-default);
}
.rail-item svg {
  width: 24px;
  height: 24px;
}
.rail-item:hover {
  background: var(--card-raised);
  color: var(--text);
}
.rail-item.disabled {
  opacity: 0.35;
  pointer-events: none;
}

/* Active-app highlighting — driven by the body[data-app="..."] attribute
   set by shell.js mountShell. The mint colour on the active icon plus the
   3px left indicator are the visual cues per DESIGN_SYSTEM.md §2.2. */
body[data-app="home"]     .rail-home,
body[data-app="mortgage"] .rail-mortgage,
body[data-app="learn"]    .rail-learn,
body[data-app="salary"]   .rail-salary,
body[data-app="savings"]  .rail-savings,
body[data-app="explore"]  .rail-explore,
body[data-app="kidsfund"] .rail-kidsfund {
  color: var(--accent);
}
body[data-app="home"]     .rail-home::before,
body[data-app="mortgage"] .rail-mortgage::before,
body[data-app="learn"]    .rail-learn::before,
body[data-app="salary"]   .rail-salary::before,
body[data-app="savings"]  .rail-savings::before,
body[data-app="explore"]  .rail-explore::before,
body[data-app="kidsfund"] .rail-kidsfund::before {
  content: '';
  position: absolute;
  left: -8px;
  top: 12px;
  bottom: 12px;
  width: 3px;
  background: var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* === Main content area === */
/* Flex-grows to fill remaining horizontal space after the rail. Scrolls
   independently on desktop, page-level on mobile (because the rail hides
   on mobile and the bottom nav takes over). */
.main {
  flex: 1;
  padding: var(--space-8) var(--space-6);
  overflow-y: auto;
  background: var(--bg);
}

/* Inner wrapper to constrain content width. 1280px per DESIGN_SYSTEM.md
   §2.2 — wider than typical dashboards, accommodates dense layouts. */
.main-inner {
  max-width: 1280px;
  margin: 0 auto;
}

/* Escape hatch for content that should span the full main area width,
   used for sections like wide charts or the affordability dashboard. */
.full-bleed {
  max-width: 100%;
}

/* === Platform footer === */
/* Sits at the bottom of the shell, always visible (not sticky). Contains
   the privacy promise. The mint padlock emoji is one of the few places
   emoji are permitted in chrome. */
.platform-footer {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: var(--space-5) var(--space-6);
  text-align: center;
  color: var(--muted);
  font-size: var(--fs-caption);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: center;
}
.platform-footer .privacy {
  color: var(--text-dim);
  max-width: 70ch;
  line-height: 1.6;
}
.platform-footer .privacy strong { color: var(--text); }
.platform-footer .copyright {
  color: var(--muted);
  font-size: 11px;
}

/* ─────────────────────────────────────────────────────────────
   Footer meta row — Contact link + social glyphs
   Added v1.15. Renders inside .platform-footer (#footer-root),
   centred below the .privacy paragraph and above .copyright.

   Social glyphs are the §7.5 brand-glyph exception: filled,
   token-coloured (muted → accent on hover), footer-only. They
   are NOT counted against the §13 12-Lucide ceiling.

   Vertical spacing is handled by .platform-footer's own
   `gap: var(--space-2)` (it is a centred column flexbox), so this
   row carries no margin of its own — adding one would double up
   with the gap and space the row unevenly.
   ───────────────────────────────────────────────────────────── */

.footer-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
}

.footer-link {
  font-size: var(--fs-caption);
  color: var(--text-dim);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  transition: color var(--duration-fast) var(--easing-default),
              border-color var(--duration-fast) var(--easing-default);
}

.footer-link:hover,
.footer-link:focus-visible {
  color: var(--text);
  border-bottom-color: var(--border-strong);
}

.footer-social {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}

.footer-social-link {
  display: inline-flex;
  align-items: center;
  color: var(--muted);
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--easing-default);
}

.footer-social-link:hover,
.footer-social-link:focus-visible {
  color: var(--accent);
}

.footer-social-link svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* === Mobile bottom-nav === */
/* Hidden by default; only appears on mobile breakpoint (below 700px).
   The CSS in the @media block below handles the actual display. */
.bottom-nav {
  display: none;
}

/* === Mobile layout adjustments === */
/* Below 700px:
   - Hide the rail
   - Reduce main padding
   - Add bottom padding to clear the bottom-nav
   - Show and style the bottom-nav
   - Shrink the brand mark
   Per DESIGN_SYSTEM.md §2.2 mobile shell. */
@media (max-width: 700px) {
  .topbar-brand-logo svg { height: 24px; }
  .topbar-brand-name { font-size: 16px; }

  .rail { display: none; }

  .main {
    padding: var(--space-6) var(--space-4);
    padding-bottom: calc(56px + var(--space-4) + env(safe-area-inset-bottom, 0px));
  }

  /* The footer sits at the end of the shell, but the bottom-nav is
     position:fixed over the bottom 56px of the viewport — so without
     clearance the footer's last lines hide behind the nav on iOS. Give
     the footer its own bottom clearance: nav height (56px, kept in sync
     with .bottom-nav) + the safe-area inset, plus its normal --space-5
     breathing room. Its --surface background extends behind the nav, so
     the join stays seamless. */
  .platform-footer {
    padding-bottom: calc(var(--space-5) + 56px + env(safe-area-inset-bottom, 0px));
  }

  .bottom-nav {
    display: flex;
    justify-content: space-around;
    align-items: stretch;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 50;
    background: var(--surface);
    border-top: 1px solid var(--border);
    height: 56px;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .bottom-nav-item {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    color: var(--text-dim);
    text-decoration: none;
    position: relative;
    transition: color var(--duration-fast) var(--easing-default);
  }
  .bottom-nav-item svg {
    width: 22px;
    height: 22px;
  }
  .bottom-nav-item.disabled {
    opacity: 0.4;
    pointer-events: none;
  }

  /* Active bottom-nav highlighting — mirrors the rail highlighting above
     but with the indicator on the top edge instead of the left. */
  body[data-app="home"]     .nav-home,
  body[data-app="mortgage"] .nav-mortgage,
  body[data-app="learn"]    .nav-learn,
  body[data-app="salary"]   .nav-salary,
  body[data-app="savings"]  .nav-savings,
  body[data-app="explore"]  .nav-explore,
  body[data-app="kidsfund"] .nav-kidsfund {
    color: var(--accent);
  }
  body[data-app="home"]     .nav-home::before,
  body[data-app="mortgage"] .nav-mortgage::before,
  body[data-app="learn"]    .nav-learn::before,
  body[data-app="salary"]   .nav-salary::before,
  body[data-app="savings"]  .nav-savings::before,
  body[data-app="explore"]  .nav-explore::before,
  body[data-app="kidsfund"] .nav-kidsfund::before {
    content: '';
    position: absolute;
    top: 0;
    left: 25%;
    right: 25%;
    height: 3px;
    background: var(--accent);
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  }
}


/* ============================================================================
   14. Video embed  —  privacy-safe click-to-load facade  (NEW)
   ============================================================================
   The on-page YouTube embed used by /learn explainer-video pages. Pairs with
   the behaviour module /shared/video-embed.js, which auto-wires every
   .video-embed element on the page (parity with notifications.js).

   Why a facade rather than a plain <iframe>: a standard YouTube iframe
   contacts Google and can set cookies the instant the page loads, which would
   break the privacy promise (DESIGN_SYSTEM §12: "no cookies, no analytics, no
   tracking") on the very page that states it. With the facade, the page loads
   only a self-hosted poster image and makes ZERO requests to Google; the real
   player (via youtube-nocookie.com) is injected by video-embed.js only after
   the visitor clicks play — their choice, disclosed inline.

   The ▶ play affordance is a text glyph, NOT a Lucide icon, so the 12-icon
   ceiling (DESIGN_SYSTEM §7.2 / §13) is untouched — same typography-over-
   iconography reasoning as the ↓/↑ and → glyphs elsewhere.

   Markup contract (see DESIGN_SYSTEM §18 for the full pattern):

     <section class="video-section">
       <div class="video-eyebrow">Watch</div>
       <p class="video-intro">…one inviting line…</p>
       <div class="video-embed" data-yt-id="VIDEO_ID" data-yt-title="Human title">
         <button type="button" class="video-embed__play" aria-label="Play video: …">
           <img src="/learn/<topic>/poster.png" alt="" loading="lazy" />
           <span class="video-embed__icon" aria-hidden="true">▶</span>
         </button>
       </div>
       <p class="video-embed__note">Playing the video loads it from YouTube.</p>
     </section>

   ── Authority ──
   DESIGN_SYSTEM.md §18 (Motion & video) is the source of truth for this block.
   ============================================================================ */

.video-section {
  margin: var(--space-8) 0 var(--space-10);
}

.video-eyebrow {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--space-3);
}

.video-intro {
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--text-dim);
  margin: 0 0 var(--space-4);
  max-width: 65ch;
}

.video-embed {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--card);
}

.video-embed__play {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: block;
}

.video-embed__play img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.video-embed__icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--bg);
  font-size: 24px;
  padding-left: 4px; /* optically centre the triangle */
  transition: transform var(--duration-fast) var(--easing-default);
}

.video-embed__play:hover .video-embed__icon {
  transform: translate(-50%, -50%) scale(1.08);
}

/* Focus ring inset (-2px) because .video-embed clips overflow — a standard
   outline-offset would be hidden by the overflow:hidden on the parent. */
.video-embed__play:focus-visible {
  outline: 2px solid var(--border-strong);
  outline-offset: -2px;
}

.video-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-embed__note {
  font-size: var(--fs-caption);
  color: var(--muted);
  margin: var(--space-3) 0 0;
}


/* ----------------------------------------------------------------------------
   13. Print styles
   ----------------------------------------------------------------------------
   Minimum viable print: black text on white. Pages with print-specific
   layouts (the mortgage tool's PDF export) override per-page.

   This is the safety net — if a page doesn't define print rules, at least
   the output is legible on paper.
   ---------------------------------------------------------------------------- */

/* ----------------------------------------------------------------------------
   NOTIFICATIONS
   ----------------------------------------------------------------------------
   The notifications system is a bell icon in the top bar that opens a small
   dropdown panel listing recent platform updates (new /learn topics, data
   refreshes, feature shipments, etc.). Data is loaded from /notifications.json
   on click — items older than 7 days are filtered out client-side.

   Design principles (per DESIGN_SYSTEM.md):
   - Brand-pure: no persistence, no localStorage, no "unread" state. The
     badge count is purely "items in last 7 days".
   - Uses one of the 12 icon slots (bell). After this we are at the ceiling.
   - Anchored dropdown, not a modal — feels lightweight, not interruptive.
   - Closes on outside click and ESC, per a11y conventions.

   How to use on a page:
   1. Include /shared/notifications.js as a deferred script
   2. Add the bell markup inside your top bar (see notifications.js header
      comment for the exact markup template)
   3. The script auto-initialises any element with [data-notif-root]
   ---------------------------------------------------------------------------- */

.notif-wrap {
  position: relative;
  display: inline-flex;
}

.notif-btn {
  position: relative;
  /* Inherit your existing topbar-btn / icon-button base styling.
     The .notif-btn class is just a hook for the bell-specific dot and dropdown. */
}

.notif-badge {
  position: absolute;
  top: 4px;
  right: 4px;
  min-width: 14px;
  height: 14px;
  padding: 0 4px;
  border-radius: 7px;
  background: var(--accent);
  color: var(--bg);
  font-size: 9px;
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  letter-spacing: 0;
  pointer-events: none;
  font-family: var(--font-mono);
  border: 1.5px solid var(--surface);
  /* Inherit surface bg of the topbar so the badge looks "punched out" */
}

.notif-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 360px;
  max-width: calc(100vw - 32px);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  z-index: 100;
  overflow: hidden;
  /* Default state: hidden via the [hidden] attribute */
}

.notif-dropdown-header {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--surface);
}

.notif-dropdown-title {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.notif-dropdown-count {
  font-size: 11px;
  color: var(--text-dim);
  font-family: var(--font-mono);
}

.notif-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 420px;
  overflow-y: auto;
}

.notif-item {
  display: block;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: var(--text);
  transition: background 150ms cubic-bezier(0.4, 0, 0.2, 1);
}

.notif-item:last-child {
  border-bottom: none;
}

.notif-item:hover,
.notif-item:focus-visible {
  background: var(--card-raised);
  outline: none;
}

.notif-item-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.notif-item-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.4;
}

.notif-item-time {
  font-size: 10px;
  color: var(--muted);
  font-family: var(--font-mono);
  white-space: nowrap;
  flex-shrink: 0;
}

.notif-item-body {
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 0;
}

.notif-item-kind {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: 1px;
}
.notif-item-kind.kind-feature { background: var(--accent); }
.notif-item-kind.kind-data    { background: var(--blue); }
.notif-item-kind.kind-news    { background: var(--highlight); }

.notif-empty {
  padding: 28px 20px;
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.55;
}

/* ----------------------------------------------------------------------------
   Mobile breakpoint — full-width dropdown
   ----------------------------------------------------------------------------

   On narrow viewports (≤700px), the desktop pattern of anchoring the dropdown
   to the bell button (position: absolute; right: 0) puts the dropdown wherever
   the bell happens to sit in the topbar, often off-screen when the bell isn't
   right-aligned. We switch to position: fixed, anchored to the viewport with
   small margins, matching the Twitter/Slack mobile pattern. The dropdown then
   feels like a panel below the topbar rather than a popover from the bell.
   ---------------------------------------------------------------------------- */

@media (max-width: 700px) {
  .notif-dropdown {
    /* Switch to fixed positioning relative to the viewport. */
    position: fixed;
    /* Sit just below the mobile topbar (52px per design system §2.2) plus
       safe-area inset for notched devices. */
    top: calc(52px + env(safe-area-inset-top, 0px) + 4px);
    /* Span the viewport with small margins on both sides. */
    left: 16px;
    right: 16px;
    /* Override the desktop fixed width — let left/right pin both edges. */
    width: auto;
    max-width: none;
  }
}

/* ----------------------------------------------------------------------------
   PRINT — universal fallback
   ----------------------------------------------------------------------------

   This is the safety net — if a page doesn't define print rules, at least
   the output is legible on paper.
   ---------------------------------------------------------------------------- */

@media print {
  html, body {
    background: white !important;
    color: black !important;
  }
  /* Hide chrome by default — most pages have a sticky header that
     shouldn't appear in printed output. Pages that want to print the
     header can override .header { display: block !important }. */
  .no-print { display: none !important; }
}
