/* CDR Intelligence — Design System */


:root {
  --bg: #0a0a0a;
  --surface: #111111;
  --surface2: #1a1a1a;
  --border: #2a2a2a;
  --border2: #3a3a3a;
  --text: #f0f0f0;
  --text-primary: #f0f0f0;
  /* --muted raised #666→#808080 (2026-07-09): #666 on #0a0a0a is ~3.4:1 —
     below WCAG AA 4.5:1 for the small text it styles (ticker timestamps,
     feed meta). #808080 ≈ 5:1, still reads dim. */
  --muted: #808080;
  --muted2: #999999;
  --accent: #f0f0f0;
  --accent2: #888888;
  --accent3: #555555;
  --green: #3b82f6;
  --red: #f59e0b;
  --amber: #f5a623;
  --accent-rgb: 240, 240, 240;
  --accent2-rgb: 136, 136, 136;
  --green-rgb: 59, 130, 246;
  --red-rgb: 245, 158, 11;
  --amber-rgb: 245, 166, 35;
  --blue: #2563EB;
  --blue-rgb: 37, 99, 235;
  /* Selection tint — active pills, filters, tabs */
  --select-bg: rgba(var(--blue-rgb),0.12);
  --select-border: rgba(var(--blue-rgb),0.4);
  --select-text: var(--text);
  /* Matte surface system */
  --glass: #161b22;
  --glass2: #1c2129;
  --glass3: #192030;
  --glass-border: #30363d;
  --glass-highlight: inset 0 1px 0 rgba(255,255,255,0.04);
  --glass-shadow: 0 4px 12px rgba(0,0,0,0.3), 0 1px 4px rgba(0,0,0,0.2);
  --glass-blur: blur(0px);
  --nav-bg: #0d1117;
  --overlay-bg: rgba(1,4,9,0.75);
  --dropdown-bg: #161b22;
  /* Shared size tokens */
  --nav-link-padding: 8px 14px;
  --nav-link-font-size: var(--fs-xs);
  --nav-link-radius: 8px;
  --nav-link-color: #c9d1d9;
  --nav-hover-bg: rgba(255,255,255,0.06);
  --nav-active-bg: rgba(59,130,246,0.16);
  --btn-circle-size: var(--ctl-md);
  --btn-circle-size-sm: var(--ctl-sm);
  /* Control tokens (2026-09-18): four heights, two shapes, three type sizes,
     three icon sizes, one edge, one hit target. Every button, pill, chip and
     icon control reads these; nothing types its own numbers. */
  --ctl-xs: 26px; --ctl-sm: 31px; --ctl-md: 40px; --ctl-lg: 52px;
  --ctl-r: 999px; --ctl-r-sq: 10px;
  --ctl-fs-sm: var(--fs-xs); --ctl-fs-md: var(--fs-sm); --ctl-fs-lg: 0.88rem;
  --ctl-px-sm: 12px; --ctl-px-md: 18px; --ctl-px-lg: 24px;
  --ctl-icon-sm: 14px; --ctl-icon-md: 16px; --ctl-icon-lg: 26px;
  --ctl-edge: 1.5px; --ctl-hit: 44px;
  --pill-h: var(--ctl-sm); --pill-fs: var(--ctl-fs-sm); --pill-px: var(--ctl-px-sm);
  --checkbox-tick: #0a0a0a;
  /* Subtle tints for inline template styles */
  --purple: #a78bfa;
  --subtle: rgba(255,255,255,0.04);
  --subtle-hover: rgba(255,255,255,0.06);
  --subtle-border: rgba(255,255,255,0.08);
  --subtle-active: rgba(59,130,246,0.15);
  --subtle-active-text: #93c5fd;
  /* ── Chart palette (dark) ─── 8 tokens + grid/axis; each represents a
     categorical series in Chart.js / inline SVG. Tuned for discriminability
     on a dark surface and to match the two brand accents (blue, amber). */
  --chart-1: #3b82f6;  /* blue */
  --chart-2: #f5a623;  /* amber */
  --chart-3: #4ade80;  /* green */
  --chart-4: #a78bfa;  /* purple */
  --chart-5: #f87171;  /* coral */
  --chart-6: #22d3ee;  /* teal  */
  --chart-7: #fbbf24;  /* gold  */
  --chart-8: #e879f9;  /* magenta */
  --chart-grid: rgba(255,255,255,0.08);
  --chart-axis: #94a3b8;
  --chart-mute: #64748b;

  /* ── Elevation scale — consistent shadow depth across cards ─── */
  --elev-1: 0 1px 2px rgba(0,0,0,0.18), 0 2px 8px rgba(0,0,0,0.22);
  --elev-2: 0 2px 4px rgba(0,0,0,0.22), 0 8px 24px rgba(0,0,0,0.32);
  --elev-hover: 0 4px 8px rgba(0,0,0,0.28), 0 14px 36px rgba(0,0,0,0.42);
  /* ── Table zebra + hover (dark) — subtle but perceptible on surface ─── */
  --zebra-bg: rgba(255,255,255,0.035);
  --pin-shadow: rgba(0, 0, 0, 0.7);           /* pinned column edge (phone tables) */
  --pin-edge: rgba(255, 255, 255, 0.18);      /* the line itself: light on a dark ground, a black shadow shows nothing there */
  --zebra-hover: rgba(255,255,255,0.065);

  /* ── Type faces ─────────────────────────────────────────────────────
     Three webfonts are loaded in index.html: Inter (body/UI), Syne
     (numerals + UI display), Instrument Serif (titles). There is NO mono
     webfont - 'Space Mono' and 'JetBrains Mono' were referenced for months
     and never loaded, so half the numbers rendered in Courier and the other
     half in SF Mono. One stack, one token (2026-09-07). */
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;

  /* ── Typography scale ────────────────────────────────────────────────
     Eleven steps, and every font-size in the codebase is one of them. The
     old seven-step scale was used four times against 475 hand-written
     declarations in 51 distinct values, eleven of which sat between 0.55
     and 0.7rem - differences smaller than the gap between two weights of
     the same face, which no reader can see (2026-09-07).
     Steps sit ON the values the site already used most, so more than half
     the declarations did not move and nothing moved by more than 2px.
     Anything above --fs-4xl is a one-off display size, left alone. */
  --fs-3xs:  0.62rem;   /*  9.9px  micro caps, chip labels        */
  --fs-2xs:  0.7rem;    /* 11.2px  small labels - the big bucket  */
  --fs-xs:   0.78rem;   /* 12.5px  secondary UI, pills, tabs      */
  --fs-sm:   0.85rem;   /* 13.6px  dense body, table cells        */
  --fs-base: 0.92rem;   /* 14.7px  body                           */
  --fs-md:   1.05rem;   /* 16.8px  emphasis, lead-in              */
  --fs-lg:   1.25rem;   /* 20.0px  small headings                 */
  --fs-xl:   1.5rem;    /* 24.0px  section and page titles        */
  --fs-2xl:  1.8rem;    /* 28.8px  display                        */
  --fs-3xl:  2rem;      /* 32.0px  display                        */
  --fs-4xl:  2.25rem;   /* 36.0px  display                        */

  /* ── Spacing scale — 4px base; use instead of arbitrary px ─── */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;

  /* ── Variant C theme tokens — used by calculator pages (2026-05-11) ─── */
  /* Sage accent + warm neutral palette; works for light + dark via the
     light-mode overrides below. */
  --calc-bg: #0a0b0d;
  --calc-panel: #15171b;
  --calc-panel-2: #1d1f24;
  --calc-panel-hover: #21242a;
  --calc-border: rgba(255,255,255,0.06);
  --calc-border-strong: rgba(255,255,255,0.1);
  --calc-accent: #5fa97e;
  --calc-accent-soft: rgba(95,169,126,0.1);
  --calc-accent-glow: rgba(95,169,126,0.18);
  --calc-text: #f0f0ee;
  --calc-text-dim: #c8c8c4;
  --calc-muted: #88898a;
  --calc-muted-dim: #5b5c5e;
  --calc-success: #5fa97e;
  --calc-warning: #d4a056;
  --calc-danger: #c9686f;
}

/* ── Light mode: black and white, Bloomberg Businessweek ─── */
[data-theme="light"] {
  --bg: #ffffff;
  --surface: #fafafa;
  --surface2: #f2f2f2;
  --border: #e0e0e0;
  --border2: #cccccc;
  --text: #0a0a0a;
  --text-primary: #0a0a0a;
  /* --muted darkened #888→#6b6b6b (2026-07-09): #888 on #fff is ~3.5:1 —
     below AA 4.5:1 for small text. #6b6b6b ≈ 5.4:1. */
  --muted: #6b6b6b;
  --muted2: #555555;
  --accent: #0a0a0a;
  --accent2: #444444;
  --accent3: #888888;
  --green: #1d4ed8;
  --red: #d97706;
  --amber: #b45309;
  --accent-rgb: 10, 10, 10;
  --accent2-rgb: 68, 68, 68;
  --green-rgb: 29, 78, 216;
  --red-rgb: 217, 119, 6;
  --amber-rgb: 180, 83, 9;
  --blue: #2563EB;
  --blue-rgb: 37, 99, 235;
  /* Selection tint — active pills, filters, tabs */
  --select-bg: rgba(var(--blue-rgb),0.08);
  --select-border: rgba(var(--blue-rgb),0.35);
  --select-text: #1d4ed8;
  --glass: #f6f8fa;
  --glass2: #f0f2f5;
  --glass3: #f4f5f7;
  --glass-border: #d0d7de;
  --glass-highlight: inset 0 1px 0 rgba(255,255,255,0.7);
  --glass-shadow: 0 4px 12px rgba(0,0,0,0.06), 0 1px 4px rgba(0,0,0,0.03);
  --glass-blur: blur(0px);
  --nav-bg: #ffffff;
  --overlay-bg: rgba(255,255,255,0.7);
  --dropdown-bg: #ffffff;
  /* Shared size tokens */
  --nav-link-padding: 8px 14px;
  --nav-link-font-size: var(--fs-xs);
  --nav-link-radius: 8px;
  --nav-link-color: #4a5160;
  --nav-hover-bg: rgba(0,0,0,0.04);
  --nav-active-bg: rgba(37,99,235,0.10);
  --btn-circle-size: var(--ctl-md);
  --btn-circle-size-sm: var(--ctl-sm);
  --checkbox-tick: #ffffff;
  --purple: #7c3aed;
  --subtle: rgba(0,0,0,0.03);
  --subtle-hover: rgba(0,0,0,0.05);
  --subtle-border: rgba(0,0,0,0.08);
  --subtle-active: rgba(37,99,235,0.1);
  --subtle-active-text: #1d4ed8;
  /* Chart palette (light) — darker hues for contrast on pale surface */
  --chart-1: #1d4ed8;
  --chart-2: #b45309;
  --chart-3: #15803d;
  --chart-4: #7c3aed;
  --chart-5: #b91c1c;
  --chart-6: #0e7490;
  --chart-7: #a16207;
  --chart-8: #a21caf;
  --chart-grid: rgba(0,0,0,0.06);
  --chart-axis: #475569;
  --chart-mute: #64748b;
  /* ── Elevation scale (light) — softer, shorter shadows on pale surface ─── */
  --elev-1: 0 1px 2px rgba(0,0,0,0.04), 0 2px 6px rgba(0,0,0,0.06);
  --elev-2: 0 2px 4px rgba(0,0,0,0.05), 0 8px 20px rgba(0,0,0,0.08);
  --elev-hover: 0 4px 8px rgba(0,0,0,0.07), 0 12px 28px rgba(0,0,0,0.12);

  /* ── Variant C theme tokens — LIGHT variant (2026-05-11) ─── */
  --calc-bg: #fafaf9;
  --calc-panel: #ffffff;
  --calc-panel-2: #f5f5f4;
  --calc-panel-hover: #efefed;
  --calc-border: rgba(0,0,0,0.06);
  --calc-border-strong: rgba(0,0,0,0.1);
  --calc-accent: #2d6a4f;
  --calc-accent-soft: rgba(45,106,79,0.08);
  --calc-accent-glow: rgba(45,106,79,0.16);
  --calc-text: #1c1917;
  --calc-text-dim: #44403c;
  --calc-muted: #78716c;
  --calc-muted-dim: #a8a29e;
  --calc-success: #166534;
  --calc-warning: #b45309;
  --calc-danger: #b91c1c;
  --zebra-bg: rgba(0,0,0,0.025);
  /* The pinned-column edge on phone tables. On a dark ground a 2px light line
     over a heavy shadow reads as a frozen panel; on WHITE the same weights
     read as a hard black hairline running past the top and bottom of the
     table, which the operator saw as a crack down the APRA institution table
     (2026-09-18). Light mode gets a divider, not an edge. */
  --pin-shadow: rgba(24, 32, 48, 0.05);
  --pin-edge: rgba(24, 32, 48, 0.12);
  --zebra-hover: rgba(0,0,0,0.055);
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* One focus ring (2026-09-18). Every control and field shows the same 2px ring
   in the site blue when focused from the keyboard; fields hug it (offset 0).
   The per-field outline:none rules that removed focus entirely are gone. */
:where(a, button, [role="button"], input, select, textarea, summary, [tabindex]):focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
:where(input, select, textarea):focus-visible { outline-offset: 0; }
/* dialog containers take focus on open so the sheet is announced; they never draw the ring themselves */
[role="dialog"]:focus-visible { outline: none; }

/* External link — standard hyperlink blue so it's instantly recognisable */
.ext-link {
  color: #5b9cf5;
  text-decoration: none;
  transition: color 0.12s;
}
.ext-link:hover { color: #7cb8ff; text-decoration: underline; }

/* Product modal action row */
.prod-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}

.prod-action-pill {
  font-size: var(--ctl-fs-sm);
  font-weight: 600;
  height: var(--ctl-sm);
  padding: 0 var(--ctl-px-sm);
  border-radius: var(--ctl-r);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  line-height: 1.4;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  text-decoration: none;
}

.prod-action-internal {
  background: rgba(255,255,255,0.05);
  border: none;
  color: var(--text);
}
.prod-action-internal:hover {
  background: rgba(255,255,255,0.10);
  color: var(--text);
}

.prod-action-ext {
  background: none;
  border: 1px solid rgba(91,156,245,0.25);
  color: #5b9cf5;
}
.prod-action-ext:hover {
  background: rgba(91,156,245,0.08);
  border-color: rgba(91,156,245,0.5);
  color: #7cb8ff;
  text-decoration: none;
}

/* Product modal header — spacious two-column layout */
.prod-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 24px;
}

.prod-modal-identity {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 1;
  min-width: 0;
}

.prod-modal-info {
  flex: 1;
  min-width: 0;
  padding-top: 4px;
}

.prod-modal-name {
  /* the sheet title (2026-09-18): the serif title size, like page titles;
     phones keep --fs-md (the rules at the end of the file) */
  font-family: 'Instrument Serif', Georgia, serif;
  font-weight: 400;
  font-size: var(--fs-xl);
  line-height: 1.2;
  color: var(--text);
  margin-bottom: 4px;
}

.prod-modal-inst {
  font-size: var(--fs-2xs);
  color: var(--muted);
  margin-bottom: 4px;
}

.prod-modal-rate-block {
  text-align: right;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  padding-top: 4px;
}

.prod-modal-rate {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-2xl);
  font-weight: 800;
  color: var(--green);
  line-height: 1.1;
}

/* Card art strip (2026-07-10) — CDR cardArt images in the product modal */
.prod-card-art-strip {
  display: flex;
  gap: 12px;
  margin: 0 0 18px;
  flex-wrap: wrap;
}
.prod-card-art {
  height: 96px;
  max-width: 160px;
  object-fit: contain;
  border-radius: 8px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  padding: 6px;
}

/* Bank note (2026-07-10) — the bank's own updatedReason free-text */
.prod-bank-note {
  font-size: var(--fs-xs);
  color: var(--muted2);
  line-height: 1.6;
  background: rgba(var(--amber-rgb), 0.06);
  border-left: 2px solid var(--amber);
  border-radius: 0 6px 6px 0;
  padding: 8px 12px;
  margin: 0 0 18px;
}
.prod-bank-note-label {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--amber);
  margin-right: 6px;
}

.prod-modal-rate-label {
  font-size: var(--fs-2xs);
  color: var(--muted);
}

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-sm);
  line-height: 1.5;
  min-height: 100vh;
  overflow-x: clip; /* clip not hidden - hidden makes body the scroll container and breaks position:sticky */
  display: flex;
  flex-direction: column;
}

/* Form controls do NOT inherit the page font by default — the browser's own
   stylesheet gives them 13.333px Arial. Thirteen rules said `font-family:
   inherit` one control at a time; everything they missed rendered in Arial:
   the insights filter pills, the RBA event pills, the APRA $Bn/% Share
   toggle, both bank-filter inputs, every unstyled `select`, the theme
   toggle, and the compare basket's Ask AI button. One rule, first in the
   cascade, so any explicit family later still wins (2026-09-07). */
button, input, select, textarea, optgroup { font-family: inherit; }

/* Active page fills remaining space — pushes footer to bottom on short pages */
main { flex: 1 0 auto; }
footer { flex-shrink: 0; }

/* === ORB BACKGROUNDS === */
/* Ambient depth — static radial gradients, zero per-frame GPU cost */
/* The ground behind the top of every page (2026-09-24, after the energy
   site): midnight fading to the plain ground by ~900px, a blue glow low on
   the left where the title sits, a faint amber warmth top right. Absolute,
   not fixed, so it scrolls away with the hero. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background:
    radial-gradient(55% 60% at 22% 38%, rgba(37, 99, 235, 0.34) 0%, rgba(37, 99, 235, 0) 70%),
    radial-gradient(70% 70% at 96% 0%, rgba(245, 166, 35, 0.09) 0%, rgba(245, 166, 35, 0) 55%),
    linear-gradient(180deg, #04060c 0%, #0a1222 55%, #0a0d14 100%);
  pointer-events: none;
  /* BENEATH the page: at z-index 0 this layer painted over every unpositioned
     element (the calculator's input panel, the LVR grid's legend and rows, the
     APRA table), which the near-transparent grey haze it replaced never
     showed. body isolates so -1 stays above the html ground. */
  z-index: -1;
}
body { isolation: isolate; }
[data-theme="light"] body::before { display: none; }

/* === NAV === */
nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  min-height: 64px;
  background: var(--nav-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--glass-border);
  display: flex;
  align-items: center;
  /* flat bar, content on the page column (1400px, 32px inset), 2026-09-24 */
  padding: 0 max(20px, calc((100% - 1400px) / 2 + 32px));
  z-index: 100;
  gap: 12px;
}

.nav-logo {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Instrument Serif', serif;
  font-weight: 400;
  font-size: var(--fs-2xl);
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}

/* Google-style search bar — uniform across all pages */
.gsearch {
  position: relative; /* anchors .srch-suggest (2026-07-17) */
  display: flex;
  align-items: center;
  max-width: 592px;
  width: 100%;
  height: 44px;
  padding: 0 14px;
  margin: 8px 0 12px;
  background: var(--surface);
  border: none;
  border-radius: 24px;
  transition: background 0.2s, box-shadow 0.2s;
}

.gsearch:hover {
  box-shadow: 0 1px 6px rgba(0,0,0,0.2);
}

.gsearch:focus-within {
  box-shadow: 0 1px 6px rgba(0,0,0,0.25);
}

/* The control the reader sees is the 24px pill, not the bare <input> stretched
   across the middle of it. The house focus ring sits on every input, and here
   it drew a hard-edged blue rectangle from the magnifier to the clear button,
   inside a rounded control (operator, 2026-09-18). So the ring MOVES to the
   pill; it is not removed, and focus is still indicated on the keyboard and on
   click, which is why the input may drop its own. Scoped with :has to the
   input, or focusing the clear button would ring the pill and the button both.
   The calc strip next to it already does this, and additionally clips inner
   outlines with overflow:hidden, which is why only this control showed it. */
.gsearch:has(.gsearch-input:focus-visible) {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
.gsearch-input:focus-visible { outline: none; }

.gsearch-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  margin-right: 10px;
  color: var(--muted);
}

.gsearch-input {
  flex: 1;
  height: 100%;
  background: none;
  border: none;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-sm);
  color: var(--text);
}

.gsearch-input::placeholder { color: var(--muted); opacity: 0.55; }

.gsearch-clear {
  width: 24px; height: 24px;
  display: none;
  align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: var(--fs-md);
  border-radius: 50%;
  transition: background 0.15s;
}
.gsearch-clear:hover { background: rgba(255,255,255,0.08); }

/* Inline spinner for buttons */
.feed-sub-spinner {
  display: inline-block;
  width: 14px; height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--text);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Skeleton loading ────────────────────────────────────────────────────── */
@keyframes shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position:  400px 0; }
}
.skel {
  display: inline-block;
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--surface) 25%, color-mix(in srgb, var(--text) 8%, var(--surface)) 50%, var(--surface) 75%);
  background-size: 800px 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}
.skel-row td { padding-top: 14px; padding-bottom: 14px; }
.skel-row .bank-cell { gap: 10px; align-items: center; }
.skel-row .bank-cell .skel:first-child { height: 32px; width: 32px; border-radius: 50%; flex-shrink: 0; }

.gsearch:focus-within .gsearch-clear,
.gsearch .gsearch-clear.visible { display: flex; }

/* Section row — title + search + action on one line, sticky below nav */
.section-row {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 12px;
  position: sticky;
  top: 64px;
  z-index: 20;
  background: var(--bg);
  padding: 8px 0;
}

.section-row .gsearch {
  margin: 0;
  /* Let the search bar fill the row instead of capping at 592px — caller
     puts it in a flex:1 wrapper, so this just removes the cap. */
  max-width: none;
}
#heatmap-header .gsearch {
  max-width: none;
}

/* ── OMI animated grid mark (nav logo + loaders) ── */
.omi-mark {
  width: 22px; height: 22px; flex-shrink: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 3px;
}
.omi-mark span { border-radius: 1.5px; background: #1e40af; }

.omi-loader {
  display: inline-grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 2px;
  vertical-align: middle;
  width: 22px; height: 22px;
}
.omi-loader.lg { width: 30px; height: 30px; gap: 3px; }
.omi-loader span { border-radius: 1px; background: #1e40af; }
.omi-loader.lg span { border-radius: 1.5px; }

/* F2 flicker — cells 2, 4, 9 flare amber */
.omi-mark span:nth-child(1),
.omi-loader span:nth-child(1) { animation: omi-flicker 3.1s ease-in-out infinite 0.2s; }
.omi-mark span:nth-child(2),
.omi-loader span:nth-child(2) { animation: omi-flicker-amb 4.0s ease-in-out infinite 1.5s; }
.omi-mark span:nth-child(3),
.omi-loader span:nth-child(3) { animation: omi-flicker 3.5s ease-in-out infinite 0.5s; }
.omi-mark span:nth-child(4),
.omi-loader span:nth-child(4) { animation: omi-flicker-amb 3.6s ease-in-out infinite 0.3s; }
.omi-mark span:nth-child(5),
.omi-loader span:nth-child(5) { animation: omi-flicker-bright 1.9s ease-in-out infinite 0s; }
.omi-mark span:nth-child(6),
.omi-loader span:nth-child(6) { animation: omi-flicker 3.2s ease-in-out infinite 1.4s; }
.omi-mark span:nth-child(7),
.omi-loader span:nth-child(7) { animation: omi-flicker 2.5s ease-in-out infinite 0.3s; }
.omi-mark span:nth-child(8),
.omi-loader span:nth-child(8) { animation: omi-flicker 3.8s ease-in-out infinite 0.9s; }
.omi-mark span:nth-child(9),
.omi-loader span:nth-child(9) { animation: omi-flicker-amb 4.4s ease-in-out infinite 2.1s; }

@keyframes omi-flicker {
  0%, 100% { background: #1e40af; opacity: 0.5; }
  50% { background: #60a5fa; opacity: 1; }
}
@keyframes omi-flicker-bright {
  0%, 100% { background: #3b82f6; opacity: 0.9; }
  50% { background: #93c5fd; opacity: 1; }
}
@keyframes omi-flicker-amb {
  0%, 40%, 100% { background: #1e40af; opacity: 0.5; }
  60%, 80% { background: #d97706; opacity: 1; }
}

.logo-icon {
  width: 32px; height: 32px;
  background: linear-gradient(135deg, var(--accent2), var(--accent));
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-md);
}

.nav-links {
  display: flex;
  gap: 2px;
  flex: 1;
  min-width: 0;
  margin-left: 16px;
  /* was overflow-x:auto for the 17-item nav; the 3-item launch nav never
     scrolls, and overflow must be visible or the Analytics dropdown clips */
  overflow: visible;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.nav-links::-webkit-scrollbar { display: none; }

.nav-link {
  padding: var(--nav-link-padding);
  border-radius: var(--nav-link-radius);
  font-size: var(--nav-link-font-size);
  font-weight: 500;
  color: var(--nav-link-color);
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
  white-space: nowrap;
  border: none;
  background: none;
  font-family: inherit;
}

.nav-link:hover { color: var(--text); background: var(--nav-hover-bg); }
/* Nav items and footer links are real anchors since 2026-09-20 (crawlable, real paths); same box as the buttons they were. */
a.nav-link { display: inline-block; text-decoration: none; }
a.footer-link { text-decoration: none; }
.nav-link.active { color: var(--text); background: var(--nav-active-bg); }
/* Alerts beside the account controls: a quiet pill, not a page tab */
nav .nav-alerts { height: var(--ctl-sm); display: inline-flex; align-items: center; padding: 0 14px; border-radius: var(--ctl-r); font-weight: 600; }

.nav-status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-2xs);
  color: var(--green);
  white-space: nowrap;
}

.status-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--green);
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

.btn-login {
  height: var(--ctl-sm);
  padding: 0 16px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #2563EB;
  border: none;
  border-radius: var(--ctl-r);
  color: #ffffff;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--ctl-fs-sm);
  cursor: pointer;
  transition: background 0.2s;
  white-space: nowrap;
}

.btn-login:hover { background: #1d4ed8; }
.btn-login.signed-in { background: var(--glass2); border: none; color: var(--green); }

/* === THEME TOGGLE === */
.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--ctl-sm);
  height: var(--ctl-sm);
  border-radius: var(--ctl-r);
  background: none;
  border: none;
  color: var(--nav-link-color);
  cursor: pointer;
  line-height: 1;
  transition: background 0.2s, color 0.2s;
  flex-shrink: 0;
  padding: 0;
}
.theme-toggle svg { display: block; flex-shrink: 0; }
.theme-toggle:hover { color: var(--text); background: var(--nav-hover-bg); }

/* === BUTTONS === */
.btn-primary {
  /* the md control (2026-09-18): 40px, full radius; .btn-analyst lifts it to lg */
  height: var(--ctl-md);
  padding: 0 var(--ctl-px-md);
  background: #2563EB;
  border: none;
  border-radius: var(--ctl-r);
  color: #ffffff;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--ctl-fs-md);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  display: flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 20px rgba(37,99,235,0.3), inset 0 1px 0 rgba(255,255,255,0.15);
}

.btn-primary:hover { transform: translateY(-3px); box-shadow: 0 12px 36px rgba(37,99,235,0.45), inset 0 1px 0 rgba(255,255,255,0.2); }

/* Monthly Briefing CTA — sits next to .btn-primary on the APRA hero. Amber
   accent + pulsing glow signals "structured editorial report" rather than the
   chat-blue conversational CTA. */
.btn-briefing {
  padding: 14px 28px;
  background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  border: none;
  border-radius: 28px;
  color: #ffffff;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 20px rgba(245,158,11,0.35), inset 0 1px 0 rgba(255,255,255,0.18);
  animation: btn-briefing-pulse 3.2s ease-in-out infinite;
}
.btn-briefing:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 40px rgba(245,158,11,0.55), inset 0 1px 0 rgba(255,255,255,0.25);
  animation: none;
}
@keyframes btn-briefing-pulse {
  0%, 100% { box-shadow: 0 4px 20px rgba(245,158,11,0.30), 0 0 0 0 rgba(245,158,11,0.0), inset 0 1px 0 rgba(255,255,255,0.18); }
  50%      { box-shadow: 0 6px 28px rgba(245,158,11,0.55), 0 0 0 8px rgba(245,158,11,0.10), inset 0 1px 0 rgba(255,255,255,0.22); }
}

.btn-secondary {
  height: var(--ctl-md);
  padding: 0 var(--ctl-px-md);
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--glass2);
  border: none;
  border-radius: var(--ctl-r);
  color: var(--text);
  font-size: var(--ctl-fs-md);
  line-height: 1;
  white-space: nowrap;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
}
.btn-secondary:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(var(--accent-rgb),0.25); color: var(--accent); }

.btn-ghost {
  height: var(--ctl-md);
  padding: 0 var(--ctl-px-md);
  background: var(--glass);
  border: none;
  border-radius: var(--ctl-r);
  color: var(--muted2);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 600;
  font-size: var(--ctl-fs-md);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  display: flex;
  align-items: center;
  gap: 8px;
  box-shadow: var(--glass-highlight);
}

.btn-ghost:hover { color: var(--accent); background: rgba(var(--accent-rgb),0.06); transform: translateY(-2px); }

/* === HERO === */
/* === HERO + STATS SIDE-BY-SIDE LAYOUT === */
.hero-layout {
  display: flex;
  align-items: flex-start;
  gap: 40px;
  max-width: 1400px;
  margin: 6px auto 0;
  padding: 0 32px;
  position: relative;
  z-index: 1;
}

.hero-layout .hero {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  padding: 24px 0 20px;
}

/* Column wrapper: feed panel + subtle badge beneath */
.stats-column {
  flex: 0 0 690px;
  width: 690px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  overflow: visible;
  padding: 24px 0 20px; /* match .hero-layout .hero padding so feed aligns with text content */
}

.hero-layout .stats-bar {
  width: 100%;
  grid-template-columns: repeat(3, 1fr);
  margin: 0;
}

/* ── Feed Panel ─────────────────────────────────────────────────────────── */
.feed-panel {
  background: transparent;
  border: none;
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Height is SYNCED from JS to the left column's (hero + insights) bottom
     (2026-07-18) - pure flex stretch let the feed's own content drive the
     column and it over-extended to ~950px. 360px is the pre-JS base. */
  height: 360px;
  min-height: 0;
}

.feed-header {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 13px 18px 11px;
}
.feed-header-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.feed-header-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-left: 15px;  /* visually align with title (after pulse + 8px gap) */
  min-height: 14px;
}
.feed-header-meta:empty { display: none; }

.feed-pulse {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  flex-shrink: 0;
  animation: feed-pulse-ring 2s ease-in-out infinite;
}

@keyframes feed-pulse-ring {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--green-rgb), 0.5); }
  50%       { box-shadow: 0 0 0 5px rgba(var(--green-rgb), 0); }
}

.feed-title {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--muted2);
  flex: 1;
  white-space: nowrap;
  min-width: 0;
}

.feed-week-count {
  font-weight: 500;
  color: var(--muted2);
  letter-spacing: 0;
  text-transform: none;
  font-size: var(--fs-2xs);
  white-space: nowrap;
}
.feed-week-count:empty { display: none; }

.feed-week-num {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-sm);
  font-weight: 800;
  color: var(--accent);
}

.feed-cta {
  font-size: var(--fs-2xs);
  color: var(--amber);
  cursor: pointer;
  opacity: 0.85;
  text-decoration: none;
  transition: opacity 0.15s;
}
.feed-cta:hover { opacity: 1; }

/* Feed header "updated Xm ago" */
.feed-updated {
  font-size: var(--fs-3xs);
  color: var(--muted);
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.feed-updated:empty { display: none; }
/* Insert a thin · separator between week-count and updated when both exist */
.feed-week-count:not(:empty) + .feed-updated:not(:empty)::before {
  content: '· ';
  color: var(--muted);
  margin-right: 2px;
}

/* Feed header category dropdown (replaces pill row in subscribe panel) */
.feed-cat-select {
  /* the sm control height and radius (2026-09-18), beside the charts toggle */
  font-size: var(--ctl-fs-sm);
  line-height: 1;
  height: var(--ctl-sm);
  box-sizing: border-box;
  padding: 0 26px 0 12px;
  background: var(--surface2);
  color: var(--text);
  border: none;
  border-radius: var(--ctl-r);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 6px center;
  font-family: 'Inter', sans-serif;
  max-width: 140px;
}
.feed-cat-select:hover { background-color: var(--glass2); }

/* Charts toggle pill — sits in feed-header, expands the rate-movement charts fold below */
.charts-toggle-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--ctl-fs-sm);            /* the sm control (2026-09-18): was a 9.9px uppercase 26px box */
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  background: var(--surface2);
  border: none;
  border-radius: var(--ctl-r);
  height: var(--ctl-sm);
  box-sizing: border-box;
  padding: 0 12px;
  line-height: 1;
  cursor: pointer;
  background: rgba(var(--green-rgb), 0.08);
  box-shadow:
    inset 0 0 10px rgba(var(--green-rgb), 0.32),
    0 0 0 1px rgba(var(--green-rgb), 0.32),
    0 0 12px rgba(var(--green-rgb), 0.28);
  animation: charts-toggle-pulse 2.4s ease-in-out infinite;
  transition: color 0.15s ease, background 0.15s ease, box-shadow 0.2s ease;
}
.charts-toggle-pill:hover {
  color: var(--text);
  background: rgba(var(--green-rgb), 0.14);
  box-shadow:
    inset 0 0 14px rgba(var(--green-rgb), 0.45),
    0 0 0 1px rgba(var(--green-rgb), 0.60),
    0 0 18px rgba(var(--green-rgb), 0.50);
}
@keyframes charts-toggle-pulse {
  0%, 100% {
    box-shadow:
      inset 0 0 8px rgba(var(--green-rgb), 0.22),
      0 0 0 1px rgba(var(--green-rgb), 0.28),
      0 0 10px rgba(var(--green-rgb), 0.22);
  }
  50% {
    box-shadow:
      inset 0 0 14px rgba(var(--green-rgb), 0.48),
      0 0 0 1px rgba(var(--green-rgb), 0.50),
      0 0 18px rgba(var(--green-rgb), 0.45);
  }
}
.charts-toggle-chev { width: var(--ctl-icon-sm); height: var(--ctl-icon-sm); transition: transform 0.18s ease; }
.charts-toggle-pill[aria-expanded="true"] .charts-toggle-chev { transform: rotate(180deg); }

/* Collapsible fold containing the 4 mini charts */
.charts-fold {
  padding: 10px 14px 0;
}
.charts-fold[hidden] { display: none; }
.charts-fold .chart-mini-grid {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto auto;
  gap: 8px;
  min-height: 0;
}
.charts-fold .chart-mini {
  min-height: 0;       /* let flex parent control sizing so panel stays at fixed 360px */
  padding: 6px 10px 8px;
  cursor: pointer;
  transition: background 0.15s ease, box-shadow 0.15s ease;
}
.charts-fold .chart-mini:hover {
  background: var(--surface2);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.06);
}
/* In-place expansion: clicked cell fills the grid; siblings are hidden */
.chart-mini-grid--has-expanded .chart-mini:not(.chart-mini--expanded) { display: none; }
.chart-mini-grid--has-expanded .chart-mini--expanded {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}
.charts-fold .chart-mini--expanded { padding: 10px 14px 12px; }
.charts-fold .chart-mini--expanded .chart-mini-title { font-size: var(--fs-xs); }
.charts-fold .chart-mini--expanded .chart-mini-counts { font-size: var(--fs-2xs); }
.chart-mini--expanded .chart-mini-y-axis { display: flex; }
.chart-mini--expanded .chart-mini-gridlines { display: block; }
.chart-mini--expanded .chart-mini-x-ticks { display: flex; }
.chart-mini--expanded .chart-mini-x-labels { display: none; }
/* Tighter typography inside the narrow panel so titles + peak metrics fit on one line */
.charts-fold .chart-mini-title {
  font-size: var(--fs-3xs);
  letter-spacing: 0.03em;
}
.charts-fold .chart-mini-counts {
  font-size: var(--fs-3xs);
  gap: 6px;
}
.charts-fold .chart-mini-peak {
  font-size: var(--fs-3xs);
}
.charts-fold .chart-mini-x-labels { font-size: var(--fs-3xs); }

/* Charts-mode: panel shows charts + subscribe CTA (the hook for conversions); hide
   the activity items list since the charts cover the same 30-day signal visually.
   Also hide the cat-select dropdown - it only filters items, not the fixed 4 charts. */
.feed-panel.charts-open .feed-items,
.feed-panel.charts-open .feed-cat-select { display: none; }
/* charts-open keeps the same fixed 360px height — no max-height override.
   charts-fold flexes to fill remaining space below the header. */
.feed-panel.charts-open .charts-fold {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding-bottom: 12px;
}
.feed-panel.charts-open .charts-fold .chart-mini-grid {
  flex: 1;
  min-height: 0;
}

.feed-items {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  padding: 4px 0;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  /* Bottom fade (2026-07-09): the list clipped mid-item at the panel edge with
     no cue that it scrolls - fade the last ~28px so the cut reads intentional.
     mask (not an overlay) → scroll + clicks unaffected. */
  mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
}

/* Section dividers: TODAY / THIS WEEK / EARLIER */
.feed-section-divider {
  padding: 6px 16px 3px;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size:var(--fs-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  /* 0.5→0.8 (2026-07-09): stacked on --muted this sat near 2.5:1 — barely
     visible. 0.8 keeps the dimmed hierarchy while staying legible. */
  opacity: 0.8;
}

/* Slide-in animation */
@keyframes feedSlideIn {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: translateX(0); }
}

.feed-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 16px;
  transition: background 0.12s, transform 0.15s, box-shadow 0.15s;
  opacity: 0;
}
.feed-item.feed-entering {
  animation: feedSlideIn 0.22s ease both;
}
.feed-item:hover {
  background: rgba(255,255,255,0.03);
  transform: translateX(2px);
}

/* Big-move emphasis — keep the theme palette (in this theme --red is amber
 * and --green is blue per styles.css :root vars). Was overriding to literal
 * #f87171 / #4ade80 which read as "real red / real green" and didn't match
 * the rest of the page's amber-rises / blue-cuts convention. */
.feed-item--big .feed-item-name  { font-weight: 700; }
.feed-item--big .feed-delta.rise { color: var(--red);   font-weight: 700; }
.feed-item--big .feed-delta.cut  { color: var(--green); font-weight: 700; }

.feed-item-logo {
  width: 26px;
  height: 26px;
  border-radius: 5px;
  object-fit: contain;
  background: #fff;
  flex-shrink: 0;
}

.feed-item-logo-ph {
  width: 26px;
  height: 26px;
  border-radius: 5px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
}

.feed-item-body {
  flex: 1;
  min-width: 0;
}

.feed-item-name {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
}

.feed-item-sub {
  font-size:var(--fs-2xs);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.4;
}

.feed-item-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex-shrink: 0;
  gap: 1px;
}

.feed-rate {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--text);
  line-height: 1.2;
}

.feed-meta {
  display: flex;
  align-items: center;
  gap: 5px;
}

.feed-delta {
  font-family: 'Syne', sans-serif;
  font-size:var(--fs-2xs);
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}
.feed-delta.cut  { color: var(--green); }
.feed-delta.rise { color: var(--red); }
.feed-delta.new  { color: var(--muted2); }

.feed-time {
  font-size:var(--fs-2xs);
  color: var(--muted);
  flex-shrink: 0;
  min-width: 24px;
  text-align: right;
}

.feed-subscribe {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6px;
  padding: 8px 14px 10px;
}

.feed-sub-input {
  flex: 1;
  min-width: 110px;
  background: var(--surface);
  border: none;
  border-radius: 6px;
  color: var(--text);
  font-size: var(--fs-2xs);
  padding: 5px 9px;
}
.feed-sub-input::placeholder { color: var(--muted); }

.feed-sub-select { display: none; }

.feed-subscribe .feed-cat-pills { flex-wrap: nowrap; flex: 1; min-width: 0; overflow-x: auto; gap: 4px; }

.feed-sub-btn {
  margin-left: auto;
  /* Blue action system (2026-07-09): was hardcoded #22c55e — the only green
     CTA on the page while every other action is blue (.btn-primary #2563EB).
     Success STATE (✓ Subscribed) keeps var(--green). */
  background: var(--blue);
  color: #fff;
  border: none;
  border-radius: var(--ctl-r);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--ctl-fs-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  height: var(--ctl-sm);
  padding: 0 14px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 3px 10px rgba(var(--blue-rgb), 0.32), 0 1px 3px rgba(0,0,0,0.15);
  transform: translateY(0);
  transition: background 0.15s, box-shadow 0.15s, transform 0.15s;
}
.feed-sub-btn:hover {
  background: #1d4ed8;
  box-shadow: 0 6px 18px rgba(var(--blue-rgb), 0.42), 0 2px 5px rgba(0,0,0,0.2);
  transform: translateY(-2px);
}
/* Subscribed = quiet done-chip, legible in both themes (2026-09-02: the old
   inline var(--green) text was blue-on-blue in light mode). All JS writers
   toggle this class instead of setting inline colors. */
.feed-sub-btn.is-subscribed,
.feed-sub-btn.is-subscribed:hover {
  background: var(--subtle);
  color: var(--text);
  box-shadow: none;
  transform: none;
}
.feed-sub-btn.is-subscribed:disabled { cursor: default; }

.feed-footer {
  padding: 7px 18px;
  font-size:var(--fs-2xs);
  color: var(--muted);
  text-align: center;
}

.feed-empty {
  padding: 34px 18px;
  text-align: center;
  font-size: var(--fs-2xs);
  color: var(--muted);
}

/* Specialist tag pills — colour-coded by category */
.specialist-tag {
  display: inline-block;
  font-size:var(--fs-2xs);
  font-weight: 700;
  padding: 1px 5px;
  border-radius: 4px;
  margin-left: 5px;
  vertical-align: middle;
  letter-spacing: 0.03em;
  position: relative;
  top: -1px;
  text-transform: uppercase;
}
.specialist-tag--defence       { background: rgba(96,165,250,0.15); color: #60a5fa; border: 1px solid rgba(96,165,250,0.3); }
.specialist-tag--green         { background: rgba(34,197,94,0.12);  color: #22c55e; border: 1px solid rgba(34,197,94,0.25); }
.specialist-tag--smsf          { background: rgba(167,139,250,0.15);color: #a78bfa; border: 1px solid rgba(167,139,250,0.3); }
.specialist-tag--construction  { background: rgba(251,191,36,0.12); color: #fbbf24; border: 1px solid rgba(251,191,36,0.25); }
.specialist-tag--bridging      { background: rgba(251,191,36,0.12); color: #fbbf24; border: 1px solid rgba(251,191,36,0.25); }
.specialist-tag--shared-equity { background: rgba(52,211,153,0.12); color: #34d399; border: 1px solid rgba(52,211,153,0.25); }
.specialist-tag--indigenous    { background: rgba(252,165,165,0.12);color: #f87171; border: 1px solid rgba(252,165,165,0.25); }
.specialist-tag--hardship      { background: rgba(249,115,22,0.12); color: #f97316; border: 1px solid rgba(249,115,22,0.25); }
.specialist-tag--profession    { background: rgba(244,114,182,0.12);color: #f472b6; border: 1px solid rgba(244,114,182,0.25); }
.specialist-tag--essential-worker { background: rgba(244,114,182,0.12);color: #f472b6; border: 1px solid rgba(244,114,182,0.25); }
.specialist-tag--seniors       { background: rgba(148,163,184,0.12);color: #94a3b8; border: 1px solid rgba(148,163,184,0.25); }
.specialist-tag--student       { background: rgba(148,163,184,0.12);color: #94a3b8; border: 1px solid rgba(148,163,184,0.25); }
.specialist-tag--specialist    { background: rgba(148,163,184,0.08);color: var(--muted); border: 1px solid rgba(148,163,184,0.15); }

/* ── Page Stats Strip (Products page) ──────────────────────────────────── */
.page-stats-strip {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.page-stat-chip {
  background: transparent;
  border: none;
  border-radius: 8px;
  padding: 6px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.page-stat-chip-label {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size:var(--fs-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

.page-stat-chip-value {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--text);
  line-height: 1.2;
}

/* ── API Health Pill (Data Quality page) ───────────────────────────────── */
.api-health-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface2);
  border: none;
  border-radius: 20px;
  padding: 4px 10px;
  font-size: var(--fs-2xs);
  color: var(--muted2);
}

.api-health-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--muted);
}
.api-health-dot.healthy  { background: var(--green); }
.api-health-dot.degraded { background: var(--red); }

/* Badge repositioned below stats — right-aligned subtle caption */
.stats-column .hero-badge {
  align-self: flex-end;
  font-size:var(--fs-2xs);
  color: var(--muted);        /* subtle text; emoji renders at full native colour */
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  padding: 4px 6px;
  margin-bottom: 0;
  pointer-events: none;
  opacity: 1;                 /* let the flag emoji stay vivid */
}

.hero-layout .stat-cell {
  padding: 16px 18px;
  min-height: 88px;
}


.hero-layout .stat-value {
  font-size: var(--fs-3xl);
}

.hero-layout .stat-label {
  font-size:var(--fs-2xs);
  margin-bottom: 4px;
  letter-spacing: 0.06em;
}

.hero {
  padding: 80px 32px 48px;
  max-width: 1400px;
  margin: 64px auto 0;
  position: relative;
  z-index: 1;
}

.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  background: rgba(var(--accent-rgb),0.08);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(var(--accent-rgb),0.25);
  border-radius: 20px;
  font-size: var(--fs-2xs);
  color: var(--accent);
  margin-bottom: 24px;
  box-shadow: 0 0 20px rgba(var(--accent-rgb),0.1), inset 0 1px 0 rgba(255,255,255,0.08);
}

.hero-title {
  font-family: 'Instrument Serif', serif;
  font-size: clamp(2.4rem, 5vw, 4rem);
  line-height: 1.1;
  font-weight: 400;
  margin-bottom: 10px;  /* tight to the tagline - one thought (2026-07-18) */
  color: var(--text);
}

.hero-title .line2 { color: var(--accent); font-style: italic; }

.hero-sub {
  /* 2026-07-11: the tagline carries the whole research positioning now —
     one notch more present (size + brightness), still subordinate to the H1. */
  font-size: var(--fs-md);
  color: var(--muted);
  letter-spacing: 0.01em;
  max-width: 680px;
  line-height: 1.6;
  margin-bottom: 22px;  /* buttons are the action that follows the pitch */
}

.hero-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

/* === STATS BAR === */
.stats-bar {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  max-width: 1400px;
  width: 100%;
  padding: 0 32px;
  margin: 24px auto;
  position: relative;
  z-index: 1;
  box-sizing: border-box;
}

.stat-cell {
  padding: 20px 24px;
  position: relative;
}

/* Dot separator between cells */
.stat-cell + .stat-cell::before {
  content: '·';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  color: var(--border2);
  font-size: var(--fs-xl);
  line-height: 1;
  pointer-events: none;
}

.stat-label {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: 6px;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
}

.stat-value {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-4xl);
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--text);
  margin-bottom: 4px;
  line-height: 1;
}

.stat-value .unit { font-size: var(--fs-md); color: var(--muted2); font-weight: 400; letter-spacing: 0; }

.stat-change {
  font-size:var(--fs-2xs);
  display: flex;
  align-items: center;
  gap: 4px;
}

.stat-change.up { color: var(--green); }
.stat-change.down { color: var(--red); }

/* === SECTION === */
.section {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 32px 60px;
  position: relative;
  z-index: 1;
  overflow-anchor: none;
}
.section * {
  overflow-anchor: none;
}

.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  margin-top: 48px;
}

.section-header:first-child {
  margin-top: 0;
}

.section-title {
  font-family: 'Instrument Serif', serif;
  font-size: var(--fs-xl);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 0;
}

/* Default heading scale — uses Instrument Serif for elegant display.
   Specific page classes (.section-title, .hero-title) take precedence. */
h1, h2, h3 {
  font-family: 'Instrument Serif', serif;
  font-weight: 400;
  line-height: 1.15;
  color: var(--text);
}
h1 { font-size: var(--fs-3xl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
h4 {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
}

/* Muted uppercase label — canonical small-caps section header style */
.ui-label {
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* === AI CHAT === */
.ai-panel {
  background: transparent;
  border: none;
  border-radius: 8px;
  overflow: hidden;
  margin-top: 48px;
  margin-bottom: 0;
}

.ai-header {
  padding: 16px 20px;
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface);
}

.ai-icon {
  width: 32px; height: 32px;
  background: linear-gradient(135deg, var(--accent3), var(--accent2));
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
  flex-shrink: 0;
}

.ai-header-text h3 { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: var(--fs-sm); font-weight: 700; }
.ai-header-text p { font-size: var(--fs-2xs); color: var(--muted); }

.ai-body {
  padding: 20px;
  min-height: 220px;
  max-height: 380px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ai-msg {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  animation: fadeIn 0.4s ease;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

.ai-avatar {
  width: 28px; height: 28px;
  border-radius: 6px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-2xs);
  /* Align the avatar's centre with the bubble's FIRST text line (bubble:
     10px padding + ~20px line): dead-centred on one-liners, anchored to the
     opening line on long answers - both chats share these classes. */
  margin-top: 6px;
}

.ai-avatar.bot { background: linear-gradient(135deg, var(--accent3), var(--accent2)); box-shadow: 0 2px 8px rgba(var(--accent-rgb),0.3); }
.ai-avatar.user { background: var(--glass2); border: none; color: var(--muted2); }

.ai-bubble {
  padding: 10px 14px;
  border-radius: 10px;
  font-size: var(--fs-xs);
  line-height: 1.6;
  max-width: 85%;
}

.ai-bubble.bot { background: rgba(var(--accent2-rgb),0.1); border: none; color: var(--text); }
.ai-bubble.user { background: var(--glass2); border: none; color: var(--muted2); margin-left: auto; }
.ai-bubble .highlight { color: var(--accent); font-weight: 500; }

.ai-msg.user { flex-direction: row-reverse; }

.ai-suggestions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding: 0 20px 4px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.ai-suggestions::-webkit-scrollbar { display: none; }

.ai-chip {
  /* a <button> since 2026-09-18 (was a div: no keyboard focus, no role) */
  font-family: inherit;
  text-align: left;
  line-height: normal;
  height: var(--ctl-sm);
  padding: 0 var(--ctl-px-sm);
  display: inline-flex; align-items: center;
  background: rgba(var(--accent-rgb),0.06);
  border: none;
  border-radius: var(--ctl-r);
  font-size: var(--ctl-fs-sm);
  color: var(--accent);
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  white-space: nowrap;
  flex-shrink: 0;
}

.ai-chip:hover { background: rgba(var(--accent-rgb),0.14); transform: translateY(-1px); }

.ai-input-row {
  padding: 12px 16px;
  display: flex;
  gap: 10px;
  align-items: center;
}

.ai-input {
  flex: 1;
  background: var(--glass2);
  border: none;
  border-radius: 20px;
  padding: 10px 18px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text);
  resize: none;
  overflow-y: auto;
  min-height: 40px;
  transition: background 0.2s, box-shadow 0.2s;
}

.ai-input::placeholder { color: var(--muted); }
.ai-input:focus { box-shadow: 0 0 20px rgba(var(--accent-rgb),0.15); }

.ai-send {
  padding: 10px 18px;
  background: var(--accent);
  border: none;
  border-radius: 20px;
  color: var(--bg);
  font-size: var(--fs-xs);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  white-space: nowrap;
  box-shadow: 0 4px 16px rgba(var(--accent2-rgb),0.3), inset 0 1px 0 rgba(255,255,255,0.2);
}

.ai-send:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(var(--accent2-rgb),0.45), inset 0 1px 0 rgba(255,255,255,0.25); }

/* === APRA AI CHAT (floating panel) === */

/* Rich-markdown content inside chat bubbles (tables, headings, lists).
   Used by both Ask Obee and Ask APRA Analyst - both panels use .ai-dock. */
.ai-dock .ai-bubble table { width: 100%; border-collapse: collapse; margin: 8px 0; font-size: var(--fs-2xs); display: block; overflow-x: auto; }
.ai-dock .ai-bubble th { text-align: left; padding: 4px 6px; border-bottom: 1px solid var(--glass2); color: var(--muted); font-weight: 600; white-space: nowrap; }
.ai-dock .ai-bubble td { padding: 4px 6px; border-bottom: 1px solid var(--subtle-border); white-space: nowrap; }
/* Chat headings: force the body sans font (the global h1-h3 rule uses the
   'Instrument Serif' display font, which looks out of place + oversized in a
   chat bubble) and cover ALL levels h1-h6 (h4+ were previously unstyled →
   large serif browser defaults). Gentle hierarchy, all close to body size. */
.ai-dock .ai-bubble h1, .ai-dock .ai-bubble h2, .ai-dock .ai-bubble h3,
.ai-dock .ai-bubble h4, .ai-dock .ai-bubble h5, .ai-dock .ai-bubble h6 {
  font-family: inherit; font-weight: 700; margin: 12px 0 4px; line-height: 1.3; color: var(--text);
}
.ai-dock .ai-bubble h1 { font-size: var(--fs-base); }
.ai-dock .ai-bubble h2 { font-size: var(--fs-base); }
.ai-dock .ai-bubble h3, .ai-dock .ai-bubble h4,
.ai-dock .ai-bubble h5, .ai-dock .ai-bubble h6 { font-size: var(--fs-sm); }
.ai-dock .ai-bubble h1:first-child, .ai-dock .ai-bubble h2:first-child,
.ai-dock .ai-bubble h3:first-child, .ai-dock .ai-bubble h4:first-child { margin-top: 0; }
.ai-dock .ai-bubble ul, .ai-dock .ai-bubble ol { margin: 6px 0; padding-left: 18px; }
.ai-dock .ai-bubble li { margin-bottom: 4px; font-size: var(--fs-xs); line-height: 1.4; }
.ai-dock .ai-bubble p { margin: 6px 0; line-height: 1.5; }
.ai-dock .ai-bubble strong { color: var(--text); font-weight: 700; }
.ai-dock .ai-bubble blockquote { margin: 8px 0; padding: 6px 10px; border-left: 2px solid var(--accent); background: rgba(255,255,255,0.04); border-radius: 0 6px 6px 0; color: var(--muted2); font-size: var(--fs-2xs); }
.ai-dock .ai-bubble blockquote p { margin: 2px 0; }
.ai-dock .ai-bubble hr { border: none; border-top: 1px solid var(--subtle-border); margin: 12px 0; }
.ai-dock .ai-bubble code { background: var(--glass2); padding: 1px 4px; border-radius: 4px; font-size: var(--fs-2xs); }
.ai-dock .ai-bubble tr:last-child td { border-bottom: none; }

/* === PRODUCT TABLE === */
.table-wrap {
  background: transparent;
  border: none;
  border-radius: 8px;
  overflow: hidden;
}

.table-toolbar {
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 12px;
  background: transparent;
  flex-wrap: wrap;
}

.search-box {
  flex: 1;
  min-width: 260px;
  max-width: 560px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  background: var(--surface);
  border: none;
  border-radius: 24px;
  transition: box-shadow 0.2s;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}

.search-box:hover {
  box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}

.search-box:focus-within {
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}

.search-input {
  flex: 1;
  background: none;
  border: none;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-sm);
  color: var(--text);
  letter-spacing: 0.01em;
}

.search-input::placeholder { color: var(--muted); opacity: 0.7; }

.filter-pill {
  /* the sm control (2026-09-18): 31px, full radius, 12.5px, 14px icon. Every
     filter pill on every page reads these tokens; the page rules below only
     add colour and layout. */
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--ctl-sm);
  padding: 0 var(--ctl-px-sm);
  /* --surface2 (#1a1a1a) instead of --surface (#111) — bumped 2026-04-29
     because pills against --bg (#0a0a0a) had only ~7-point luminance
     difference and looked invisible in dark mode. --surface2 gives ~16. */
  background: var(--surface2);
  border: 1px solid transparent;
  border-radius: var(--ctl-r);
  font-size: var(--ctl-fs-sm);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  color: var(--muted2);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
  font-family: inherit;
}
.filter-pill > svg, .filter-pill .ico { width: var(--ctl-icon-sm); height: var(--ctl-icon-sm); flex-shrink: 0; }

.cat-icon {
  flex-shrink: 0;
  opacity: 0.7;
}

.filter-pill:hover {
  background: var(--select-bg);
  color: var(--select-text);
}

.filter-pill.active {
  background: var(--select-bg);
  color: var(--select-text);
  font-weight: 600;
}

/* Volatile toggle button — amber warning palette, distinct from regular pills */
.volatile-btn { color: var(--muted); font-size:var(--fs-2xs); }
.volatile-btn.active {
  background: rgba(217, 119, 6, 0.15);
  color: #d97706;
  font-weight: 600;
}

table { width: 100%; border-collapse: collapse; }

th {
  text-align: left;
  padding: 12px 16px 8px;
  font-size:var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  background: var(--bg);
  cursor: pointer;
  user-select: none;
  transition: color 0.15s;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
}
/* Data table headers align right to match numeric body cells; first column stays left */
.apra-inner-table th,
.data-table th { text-align: right; }
.apra-inner-table th:first-child,
.data-table th:first-child { text-align: left; }

th:hover { color: var(--text); }

td {
  padding: 12px 16px;
  font-size: var(--fs-xs);
  vertical-align: middle;
}
tr:nth-child(even) td { background: var(--zebra-bg); }
tr:hover td { background: var(--zebra-hover); }

.bank-cell { display: flex; align-items: center; gap: 10px; }

.bank-logo {
  width: 40px; height: 40px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
  font-weight: 700;
  flex-shrink: 0;
}

.bank-logo-img {
  width: 40px; height: 40px;
  border-radius: 8px;
  object-fit: contain;
  flex-shrink: 0;
  background: #fff;
}

.bank-logo-img.modal-logo, .bank-logo.modal-logo {
  width: 72px; height: 72px;
  border-radius: 14px;
  font-size: var(--fs-2xl);
}

.bank-name { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-weight: 600; font-size: var(--fs-xs); }
.bank-abn { font-size:var(--fs-2xs); color: var(--muted); }

.rate-value { font-family: 'Syne', sans-serif; font-weight: 700; font-size: var(--fs-md); letter-spacing: -0.01em; line-height: 1.1; }
.rate-change { font-size:var(--fs-2xs); margin-top: 2px; }

.badge {
  padding: 4px 10px;
  border-radius: 20px;
  font-size:var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
  display: inline-block;
}

/* ── Status badges ─────────────────────────────────────────────────── */
.badge-healthy { background: rgba(var(--green-rgb),0.1); color: var(--green); border: 1px solid rgba(var(--green-rgb),0.2); }
.badge-warn    { background: rgba(var(--red-rgb),0.08); color: var(--red); border: 1px solid rgba(var(--red-rgb),0.15); }
.badge-error   { background: rgba(var(--red-rgb),0.12); color: var(--red); border: 1px solid rgba(var(--red-rgb),0.25); }
.badge-new     { background: rgba(var(--accent-rgb),0.08); color: var(--accent); border: 1px solid rgba(var(--accent-rgb),0.18); }

/* ── Category badges (glassy, theme-adaptive) ──────────────────────── */
.badge-cat-home       { --_r: 59, 130, 246;  background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-savings    { --_r: 16, 185, 129;  background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-term       { --_r: 139, 92, 246;  background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-transaction{ --_r: 107, 114, 128; background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-personal   { --_r: 245, 158, 11;  background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-credit     { --_r: 239, 68, 68;   background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-business   { --_r: 20, 184, 166;  background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }
.badge-cat-default    { --_r: 107, 114, 128; background: rgba(var(--_r),0.16); color: rgb(var(--_r)); border: 1px solid rgba(var(--_r),0.28); }

/* Light mode: slightly stronger tint for legibility */
[data-theme="light"] .badge-cat-home       { --_r: 37, 99, 235; }
[data-theme="light"] .badge-cat-savings    { --_r: 5, 150, 105; }
[data-theme="light"] .badge-cat-term       { --_r: 109, 40, 217; }
[data-theme="light"] .badge-cat-transaction{ --_r: 75, 85, 99; }
[data-theme="light"] .badge-cat-personal   { --_r: 217, 119, 6; }
[data-theme="light"] .badge-cat-credit     { --_r: 220, 38, 38; }
[data-theme="light"] .badge-cat-business   { --_r: 13, 148, 136; }

.up { color: var(--red); }
.down { color: var(--green); }
.neutral { color: var(--muted2); }

/* === PAGINATION === */
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px;
}

.page-btn {
  height: var(--ctl-sm);
  padding: 0 12px;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--ctl-r);
  font-size: var(--ctl-fs-sm);
  color: var(--muted2);
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  font-family: inherit;
  box-shadow: var(--glass-highlight);
}

.page-btn:hover:not(:disabled) { border-color: rgba(var(--accent-rgb),0.45); color: var(--accent); transform: translateY(-1px); box-shadow: 0 4px 14px rgba(var(--accent-rgb),0.18), inset 0 1px 0 rgba(255,255,255,0.1); }
.page-btn.active { border-color: rgba(var(--accent-rgb),0.45); color: var(--accent); background: rgba(var(--accent-rgb),0.1); box-shadow: 0 0 16px rgba(var(--accent-rgb),0.18), inset 0 1px 0 rgba(255,255,255,0.1); }
.page-btn:disabled { opacity: 0.4; cursor: default; }

/* === ACTIVITY LOG === */
.log-panel {
  background: transparent;
  border: none;
  border-radius: 8px;
  overflow: hidden;
  margin-top: 48px;
}

.log-header {
  padding: 14px 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: transparent;
}

.log-list { max-height: 340px; overflow-y: auto; }
.log-list::-webkit-scrollbar { width: 4px; }
.log-list::-webkit-scrollbar-track { background: transparent; }
.log-list::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 2px; }

.log-item {
  padding: 14px 20px;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  transition: background 0.15s;
}

.log-item:hover { background: rgba(var(--accent-rgb),0.02); }

.log-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex-shrink: 0; }
.log-dot.info { background: var(--accent); }
.log-dot.warn { background: var(--amber); }
.log-dot.error { background: var(--red); }
.log-dot.success { background: var(--green); }

.log-content { flex: 1; }
.log-msg { font-size: var(--fs-xs); color: var(--text); line-height: 1.5; margin-bottom: 3px; }
.log-meta { font-size:var(--fs-2xs); color: var(--muted); }
.log-bank { color: var(--accent); }

/* === CHART === */
.chart-panel {
  background: transparent;
  border: none;
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 48px;
}

.chart-header {
  padding: 16px 20px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.chart-header--with-filters {
  flex-wrap: wrap;
  gap: 10px;
}

.chart-title { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: var(--fs-xs); font-weight: 700; }

.chart-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.chart-filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: var(--ctl-sm);
  padding: 0 var(--ctl-px-sm);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--ctl-r);
  color: var(--muted);
  font-size: var(--ctl-fs-sm);
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  white-space: nowrap;
}

.chart-filter-pill:hover {
  background: var(--select-bg);
  border-color: var(--select-border);
  color: var(--select-text);
}

.chart-filter-pill.active {
  background: var(--select-bg);
  border-color: var(--select-border);
  color: var(--select-text);
  font-weight: 600;
}

/* Larger scheme pills (All / Banking / Energy) on the health page */

.chart-body {
  padding: 16px 16px 32px 52px;
  height: 280px;
  display: flex;
  align-items: stretch;
  gap: 2px;
  position: relative;
}

.chart-y-grid {
  position: absolute;
  top: 16px; left: 52px; right: 16px; bottom: 32px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  pointer-events: none;
}

.chart-y-line { width: 100%; height: 1px; background: rgba(255,255,255,0.05); }

/* Zero axis line — sits at vertical midpoint of the bar area */
.chart-zero-line {
  position: absolute;
  left: 52px; right: 16px;
  top: 132px; /* padding-top(16) + inner-height/2(116) */
  height: 1px;
  background: rgba(255,255,255,0.22);
  pointer-events: none;
  z-index: 2;
}

/* Y-axis labels: top (max rises), zero, bottom (max cuts) */
.chart-y-labels {
  position: absolute;
  left: 0; width: 48px;
  top: 16px; bottom: 32px;
  font-size:var(--fs-2xs);
  color: var(--muted);
  pointer-events: none;
}

.chart-y-label-top    { position: absolute; top: 0;   right: 8px; transform: none; }
.chart-y-label-zero   { position: absolute; top: 50%; right: 8px; transform: translateY(-50%); }
.chart-y-label-bottom { position: absolute; bottom: 0; right: 8px; transform: none; }

/* Diverging bar structure */
.chart-bar-group {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  min-width: 0;
}

.chart-bar-upper {
  flex: 1;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.chart-bar-lower {
  flex: 1;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.chart-bar-rise {
  width: 6px;
  background: var(--red);
  border-radius: 3px 3px 0 0;
  opacity: 0.78;
  transition: height 0.25s ease, opacity 0.15s;
  cursor: pointer;
}

.chart-bar-cut {
  width: 6px;
  background: var(--green);
  border-radius: 0 0 3px 3px;
  opacity: 0.78;
  transition: height 0.25s ease, opacity 0.15s;
  cursor: pointer;
}

.chart-bar-rise:hover, .chart-bar-cut:hover { opacity: 1; filter: brightness(1.2); }

/* Anomalous day — shows a faint dashed line instead of bars */
.chart-bar-group--anomalous {
  flex: 1;
  position: relative;
  min-width: 0;
  cursor: default;
}
.chart-bar-group--anomalous::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 15%;
  bottom: 15%;
  width: 1px;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255,255,255,0.12) 0px,
    rgba(255,255,255,0.12) 3px,
    transparent 3px,
    transparent 6px
  );
  transform: translateX(-50%);
}

/* Quiet day — poll ran, no rate changes: tiny dot on the zero line */
.chart-bar-group--quiet {
  flex: 1;
  position: relative;
  min-width: 0;
  cursor: default;
}
.chart-bar-group--quiet::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4px;
  height: 4px;
  transform: translate(-50%, -50%);
  background: rgba(255,255,255,0.18);
  border-radius: 50%;
}

/* No-poll day — short hatched block centered on the zero line */
.chart-bar-group--no-poll {
  flex: 1;
  position: relative;
  min-width: 0;
  cursor: default;
}
.chart-bar-group--no-poll::after {
  content: '';
  position: absolute;
  left: 50%;
  top: calc(50% - 8px);
  width: 6px;
  height: 16px;
  transform: translateX(-50%);
  background: repeating-linear-gradient(
    45deg,
    rgba(255,255,255,0.10) 0px,
    rgba(255,255,255,0.10) 2px,
    transparent 2px,
    transparent 5px
  );
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 2px;
}

/* New product dot — sits on the zero line */
.chart-newp-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.85;
  cursor: pointer;
  z-index: 3;
}

/* ── Small-multiples chart grid (dashboard Market Movement) ─────────────── */
.chart-mini-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 10px;
  min-height: 240px;
}
.chart-mini {
  background: var(--surface);
  border-radius: 10px;
  padding: 8px 12px 10px;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.chart-mini-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
  flex-shrink: 0;
  gap: 8px;
}
.chart-mini-title {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-2xs);
  font-weight: 700;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chart-mini-counts {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-2xs);
  color: var(--muted);
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.chart-mini-counts .up   { color: var(--red); }
.chart-mini-counts .down { color: var(--green); }
.chart-mini-plot {
  flex: 1;
  display: flex;
  align-items: stretch;
  gap: 6px;
  min-height: 0;
}
.chart-mini-y-axis {
  display: none;                      /* shown only in expanded mode */
  flex-direction: column;
  justify-content: space-between;
  font-size: var(--fs-3xs);
  font-family: 'Syne', sans-serif;
  color: var(--muted);
  text-align: right;
  width: 28px;
  flex-shrink: 0;
}
.chart-mini-gridlines {
  display: none;                      /* shown only in expanded mode */
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}
.chart-mini-gridlines .gl {
  position: absolute;
  left: 0; right: 0;
  height: 1px;
  background: rgba(255,255,255,0.05);
}
.chart-mini-gridlines .gl-upper-50 { top: 25%; }
.chart-mini-gridlines .gl-lower-50 { top: 75%; }
.chart-mini-x-ticks {
  display: none;                      /* shown only in expanded mode */
  justify-content: space-between;
  font-size: var(--fs-3xs);
  font-family: 'Syne', sans-serif;
  color: var(--muted);
  margin-top: 6px;
  flex-shrink: 0;
}
.chart-mini-body {
  flex: 1;
  position: relative;
  display: flex;
  align-items: stretch;
  gap: 1px;
  min-height: 0;
}
.chart-mini-zero-line {
  position: absolute;
  top: 50%; left: 0; right: 0;
  height: 1px;
  background: rgba(255,255,255,0.08);
  pointer-events: none;
  z-index: 1;
}
.chart-mini-x-labels {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-3xs);
  color: var(--muted);
  margin-top: 4px;
  flex-shrink: 0;
}
.chart-mini-peak {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-right: 2px;
}

/* ── Systems Health page ────────────────────────────────────────────────── */

/* Fix top whitespace: push main below the fixed nav, remove redundant
   margin-top from .page-content for pages that have a sticky header.
   #page-analytics-movements added 2026-07-21: without the nav clearance its
   .section sat flush at viewport y=0, so the sticky .section-row header
   (top:64px) pinned DOWN immediately and its opaque z-20 background covered
   the category-filter pills + view toggle directly below it - that is why
   the Rate Movements filters were invisible despite rendering into the DOM. */
#page-health,
#page-analytics-movements {
  padding-top: 64px;
}
#page-health .page-content {
  margin-top: 0;
  padding-top: 20px;
}

/* Section wrapper */
.health-section { margin-bottom: 24px; }

/* Zone divider — Backend / Frontend / Pipeline Detail */
.health-zone-label {
  font-family: 'Instrument Serif', serif;
  font-size: var(--fs-xl); font-weight: 400; letter-spacing: 0;
  color: var(--text); margin: 32px 0 14px;
  display: flex; align-items: center; gap: 12px;
}
.health-zone-label:first-child { margin-top: 0; }
.health-zone-label::before { content: ''; flex-shrink: 0; width: 3px; height: 18px; background: var(--accent); border-radius: 2px; }
.health-zone-label::after  { content: ''; flex: 1; height: 1px; background: var(--border); }

/* Section label — small caps with extending line */
.health-section-label {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted); font-weight: 600; margin-bottom: 10px;
}
.health-section-label::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}

/* Generic card */
.health-card {
  background: transparent; border: none;
  border-radius: 10px; padding: 16px;
}
.health-card-title {
  font-size: var(--fs-2xs); font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 12px;
}

/* Table wrapper */
.health-table-wrap {
  background: transparent; border: none;
  border-radius: 10px; overflow-x: auto;
}

/* Layer cards — top colour strip */
.health-layers-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.health-layer-card {
  background: transparent;
  border-radius: 10px; padding: 14px 14px 12px;
  position: relative; overflow: hidden;
}
.health-layer-card::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
}
.health-layer-card.green::before  { background: var(--green); }
.health-layer-card.yellow::before { background: var(--amber); }
.health-layer-card.red::before    { background: var(--red); }
.health-layer-name {
  font-size:var(--fs-2xs); font-weight: 700; letter-spacing: 0.1em;
  color: var(--muted); text-transform: uppercase; margin-bottom: 8px;
}
.health-layer-dot {
  width: 7px; height: 7px; border-radius: 50%; margin-bottom: 8px;
}
.health-layer-detail { font-size: var(--fs-xs); color: var(--text); line-height: 1.45; }

/* Tables */
.health-poll-table, .health-pipeline-table {
  width: 100%; border-collapse: collapse; font-size: var(--fs-xs);
}
.health-poll-table th, .health-pipeline-table th {
  text-align: left; padding: 9px 12px; color: var(--muted);
  font-weight: 500; white-space: nowrap;
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.06em;
  position: sticky; top: 0; background: var(--bg); z-index: 1;
}
.health-poll-table td, .health-pipeline-table td {
  padding: 8px 12px; vertical-align: middle;
}
.health-pipeline-table tbody tr:hover td { background: rgba(255,255,255,0.018); }

/* Phase cells */
.phase-ok      { color: var(--green); font-size: var(--fs-xs); }
.phase-fail    { color: var(--red);   font-size: var(--fs-xs); }
.phase-skip    { color: var(--muted); font-size: var(--fs-xs); }
.phase-partial { color: var(--amber);  font-size: var(--fs-xs); }

/* Pipeline status badge */
.pipeline-badge {
  font-size:var(--fs-2xs); font-weight: 700; padding: 2px 7px;
  border-radius: 3px; letter-spacing: 0.07em; white-space: nowrap;
}
.pipeline-badge.fresh    { background: rgba(var(--green-rgb),0.13); color: var(--green); }
.pipeline-badge.carry    { background: rgba(var(--amber-rgb),0.13);  color: var(--amber); }
.pipeline-badge.fail     { background: rgba(var(--red-rgb),0.13);    color: var(--red); }
.pipeline-badge.degraded { background: rgba(var(--amber-rgb),0.08);  color: var(--amber); }

/* Action items panel */
.health-action-panel {
  background: rgba(224,82,82,0.05); border: 1px solid rgba(224,82,82,0.18);
  border-left: 3px solid var(--red); border-radius: 8px; padding: 14px 16px;
}
.health-action-title {
  font-size: var(--fs-2xs); font-weight: 700; color: var(--red);
  text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 10px;
}
.health-action-row {
  display: flex; gap: 8px; align-items: baseline;
  font-size: var(--fs-xs); color: var(--text); margin-bottom: 6px;
}
.health-action-row:last-child { margin-bottom: 0; }

/* Inline list rows used by cards */
.health-list-row {
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--fs-xs);
}

/* Large stat numbers */
.health-stat-num {
  font-size: var(--fs-xl); font-family: 'Syne', sans-serif; font-weight: 700;
  line-height: 1; margin-bottom: 2px;
}
.health-stat-label { font-size: var(--fs-2xs); color: var(--muted); }

/* Sticky header */
.health-sticky-header {
  position: sticky;
  top: 64px;
  z-index: 50;
  background: var(--nav-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--glass-border);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 32px;
  gap: 12px;
}

/* Countdown */
.health-countdown { font-size: var(--fs-2xs); color: var(--muted); }

/* Action buttons in health header */
.health-btn {
  font-size: var(--fs-xs);
  font-weight: 500;
  padding: 7px 14px;
  border-radius: 8px;
  border: none;
  background: var(--glass);
  color: var(--muted2);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
  white-space: nowrap;
}
.health-btn:hover { color: var(--text); background: rgba(var(--accent-rgb),0.06); }
.health-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* N/A layer cards (scheme filter) */
.health-layer-card.na { opacity: 0.38; }

/* Admin Runbook — panels grouped by domain */
.health-panels-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 14px;
}
.health-panel {
  background: rgba(255,255,255,0.015);
  border-radius: 10px;
  padding: 12px 14px 10px;
}
.health-panel-title {
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.1em;
  color: var(--accent); text-transform: uppercase; margin-bottom: 10px;
  display: flex; align-items: center; gap: 8px;
}
.health-panel-title::after {
  content: ''; flex: 1; height: 1px; background: var(--border); opacity: 0.45;
}
.health-metric {
  display: grid; grid-template-columns: 10px 1fr auto;
  gap: 8px; align-items: start;
  padding: 6px 0;
  font-size: var(--fs-xs);
  cursor: help;
  position: relative;
}
.health-metric + .health-metric { border-top: 1px dashed rgba(255,255,255,0.03); }
.health-metric-dot {
  width: 7px; height: 7px; border-radius: 50%;
  margin-top: 6px;
}
.health-metric-dot.green  { background: var(--green); }
.health-metric-dot.yellow { background: var(--amber); }
.health-metric-dot.red    { background: var(--red); }
.health-metric-dot.na     { background: var(--muted2); opacity: 0.4; }
.health-metric-name {
  color: var(--text); font-weight: 500;
}
.health-metric-detail {
  font-size: var(--fs-2xs); color: var(--muted); margin-top: 2px;
  line-height: 1.35;
}
.health-metric-value {
  font-size: var(--fs-2xs); color: var(--muted2); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* Tooltip surface */
.health-metric-tip {
  position: absolute; z-index: 10;
  left: 18px; top: calc(100% + 4px);
  max-width: 360px;
  background: var(--nav-bg);
  backdrop-filter: var(--glass-blur);
  box-shadow: 0 12px 40px rgba(0,0,0,0.55), 0 0 0 1px rgba(var(--accent-rgb),0.18);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: var(--fs-2xs); color: var(--text); line-height: 1.45;
  display: none;
  pointer-events: none;
}
.health-metric:hover .health-metric-tip { display: block; }
.health-metric-tip-label {
  font-size: var(--fs-3xs); font-weight: 700; letter-spacing: 0.1em;
  color: var(--muted); text-transform: uppercase; margin-top: 6px;
}
.health-metric-tip-label:first-child { margin-top: 0; }
.health-metric-tip-body { color: var(--text); margin-top: 2px; }
.health-metric-tip-body.action { color: var(--amber); }

.chart-x-labels {
  position: absolute;
  bottom: 8px;
  left: 52px; right: 16px;
  display: flex;
  justify-content: space-between;
  font-size:var(--fs-2xs);
  color: var(--muted);
}

/* === ALERT SUBSCRIPTION PANEL === */
.notif-panel {
  background: transparent;
  border: none;
  border-radius: 8px;
  overflow: hidden;
}

.notif-item {
  padding: 16px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
  transition: background 0.15s;
  cursor: pointer;
}

.notif-item:hover { background: rgba(var(--accent-rgb),0.02); }

.notif-icon {
  width: 36px; height: 36px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
  flex-shrink: 0;
}

.notif-body { flex: 1; }
.notif-title { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: var(--fs-xs); font-weight: 600; margin-bottom: 3px; }
.notif-sub { font-size: var(--fs-2xs); color: var(--muted2); }
.notif-time { font-size:var(--fs-2xs); color: var(--muted); }

/* === TOGGLE === */
.toggle {
  width: 36px; height: 20px;
  border-radius: 10px;
  background: var(--border2);
  position: relative;
  cursor: pointer;
  transition: background 0.2s;
  border: none;
  flex-shrink: 0;
}

.toggle.on { background: #2563EB; }  /* brand blue like .qc-switch; --accent2 is a theme neutral, so on read as off (2026-09-29) */

.toggle::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: white;
  transition: transform 0.2s;
}

.toggle.on::after { transform: translateX(16px); }

/* === TABS === */
.tabs {
  display: flex;
  gap: 2px;
  padding: 0 20px;
  background: var(--glass2);
}

.tab {
  padding: 12px 18px;
  font-size: var(--fs-xs);
  color: var(--muted2);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.2s;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 600;
  white-space: nowrap;
}

.tab:hover { color: var(--text); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }

/* === ARCHITECTURE CARDS === */
.arch-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}

.arch-card {
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: none;
  border-radius: 20px;
  padding: 20px;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  position: relative;
  overflow: hidden;
  box-shadow: var(--glass-shadow), var(--glass-highlight);
}

.arch-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent2), var(--accent), transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s;
}

.arch-card:hover::before { transform: scaleX(1); }
.arch-card:hover { transform: translateY(-4px); box-shadow: 0 16px 48px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.15); }

.arch-icon {
  width: 36px; height: 36px;
  border-radius: 10px;
  background: var(--glass2);
  backdrop-filter: var(--glass-blur);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-md);
  margin-bottom: 14px;
}

.arch-title { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: var(--fs-sm); font-weight: 700; margin-bottom: 8px; }
.arch-desc { font-size: var(--fs-2xs); color: var(--muted2); line-height: 1.6; }

.arch-stack { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 12px; }

.stack-tag {
  padding: 2px 8px;
  background: var(--glass);
  border: none;
  border-radius: 8px;
  font-size:var(--fs-2xs);
  color: var(--muted2);
  text-transform: uppercase;
}

/* === CODE BLOCK === */
.code-panel {
  background: rgba(4,8,15,0.4);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: none;
  border-radius: 16px;
  overflow: hidden;
  margin-top: 20px;
  box-shadow: var(--glass-shadow);
}

.code-header {
  padding: 10px 16px;
  background: var(--glass2);
  border-bottom: none;
  display: flex;
  align-items: center;
  gap: 8px;
}

.code-dot { width: 10px; height: 10px; border-radius: 50%; }
.code-dot.r { background: #ff5f57; }
.code-dot.y { background: #ffbd2e; }
.code-dot.g { background: #28ca41; }
.code-lang { margin-left: auto; font-size:var(--fs-2xs); color: var(--muted); text-transform: uppercase; letter-spacing: 0.1em; }

pre { padding: 20px; font-size: var(--fs-2xs); line-height: 1.7; color: var(--muted2); overflow-x: auto; }

.kw { color: #7c3aed; }
.fn { color: var(--accent); }
.str { color: var(--green); }
.cm { color: var(--muted); font-style: italic; }
.num { color: var(--amber); }

/* === ALERTS PAGE === */
.alert-form-panel {
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: none;
  border-radius: 22px;
  padding: 24px;
  margin-bottom: 24px;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-bottom: 16px;
}

.form-group { display: flex; flex-direction: column; gap: 6px; }

.form-label { font-size:var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted2); }

.form-input, .form-select {
  background: var(--glass2);
  /* a hairline edge (2026-09-29): on the Account cards the field fill equals
     the card fill, so the three password fields were invisible */
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 14px;
  /* the site's text face (2026-09-29): an alert name and "All institutions"
     are words, not figures; mono made the Alerts and Account forms read as
     a terminal */
  font-family: inherit;
  font-size: var(--fs-xs);
  color: var(--text);
  transition: all 0.2s;
  width: 100%;
}

.form-input::placeholder { color: var(--muted); }
.form-input:focus, .form-select:focus { box-shadow: 0 0 20px rgba(var(--accent-rgb),0.12); }
.form-select { cursor: pointer; }
.form-select option { background: var(--surface); }

.delivery-options {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.delivery-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: var(--glass);
  border: none;
  border-radius: 20px;
  cursor: pointer;
  font-size: var(--fs-xs);
  color: var(--muted2);
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.delivery-option.selected { color: var(--accent); background: rgba(var(--accent-rgb),0.08); }
.delivery-option input { display: none; }

/* === FOOTER === */
footer {
  padding: 10px 32px;
  border-top: 1px solid var(--glass-border);
  background: var(--glass);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  font-size: var(--fs-2xs);
  color: var(--muted);
  position: relative;
  z-index: 1;
}

.footer-links { display: flex; gap: 20px; }
.footer-link { color: var(--muted2); cursor: pointer; transition: color 0.2s; }
.footer-link:hover { color: var(--accent); }

/* Footer copyright (launch cleanup 2026-08-30; flat link row — the Product/
   Company columns duplicated the top nav and made the footer too tall) */
.footer-copyright { margin-top: 8px; color: var(--muted); font-size: var(--fs-2xs); }

/* Alerts page two-column top (2026-09-01): create-alert cards left,
   publications right; single column under 900px */
.alerts-top-grid { display: grid; grid-template-columns: 1fr 320px; gap: 24px; align-items: start; margin-bottom: 28px; }
@media (max-width: 900px) { .alerts-top-grid { grid-template-columns: 1fr; } }
.alert-card-step {
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 14px;
}

/* APRA insights scroll-dock rail (2026-09-01): fixed right slot the hero
   carousel re-parents into once scrolled past the hero; desktop only */
.apra-insights-rail { display: none; }
.apra-insights-rail.docked {
  display: block; position: fixed; top: 84px; right: 32px;
  width: 340px; z-index: 60;
}
.apra-insights-rail .hero-insights { margin-top: 0; max-width: 340px; }
@media (max-width: 1100px) { .apra-insights-rail.docked { display: none; } }

/* Analytics nav dropdown (launch nav 2026-08-30) */
.nav-dropdown { position: relative; display: inline-flex; }
.nav-dropdown-menu {
  display: none;
  position: absolute; top: calc(100% + 6px); left: 0;
  min-width: 190px;
  background: var(--nav-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 6px;
  z-index: 300;
  flex-direction: column;
  gap: 1px;
  box-shadow: 0 18px 50px rgba(0,0,0,0.45);
}
.nav-dropdown-menu.open { display: flex; }
.nav-dropdown-menu .nav-link {
  width: 100%; text-align: left; border-radius: 8px; padding: 9px 12px; font-size: 13px;
}
.nav-dd-cta { color: var(--blue) !important; font-weight: 600; }
.nav-dd-section {
  font-size: var(--fs-3xs); font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--muted);
  padding: 8px 12px 2px;
}
.nav-dd-divider { height: 1px; background: var(--glass-border); margin: 6px 4px; }

/* Legal & company pages (privacy / terms / disclaimer / about) */
.legal-page {
  /* margin-top 64px clears the fixed nav, same as .page-content */
  max-width: 760px; margin: 64px auto 0; padding: 48px 24px 80px;
  color: var(--text); line-height: 1.7; font-size: var(--fs-base);
}
.legal-page h1 {
  font-family: 'Instrument Serif', Georgia, serif; font-size: var(--fs-xl); font-weight: 400;
  margin-bottom: 6px;
}
.legal-page h2 {
  /* Titles are the serif everywhere, company and legal pages included
     (2026-09-07). Set larger than the old sans heading so 400-weight serif
     still carries on a dark ground - that legibility floor is real, it is
     the reason these pages had their own heading font for months. */
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--fs-lg); font-weight: 400; margin: 30px 0 10px;
  color: var(--text);
}
.legal-page p { margin: 0 0 12px; color: var(--muted2); }
.legal-page a { color: var(--blue); text-decoration: none; }
.legal-page a:hover { text-decoration: underline; }
.legal-updated { font-size: var(--fs-2xs); color: var(--muted); margin-bottom: 24px; }

/* === MODAL === */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--overlay-bg);
  backdrop-filter: blur(8px);
  z-index: 1100;
  align-items: center;
  justify-content: center;
}

.modal-overlay.open { display: flex; }

.modal {
  background: rgba(8,15,26,0.55);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: none;
  border-radius: 24px;
  width: 100%;
  max-width: 460px;
  padding: 36px;
  position: relative;
  animation: modalIn 0.3s ease;
  box-shadow: 0 32px 96px rgba(0,0,0,0.7), inset 0 1px 0 rgba(255,255,255,0.08);
}

@keyframes modalIn {
  from { opacity: 0; transform: scale(0.95) translateY(20px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

/* Detail modals (product & institution) — wider, scrollable body, sticky close bar */
.modal.detail-modal {
  max-width: min(960px, 94vw);
  max-height: 88vh;
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.detail-modal-topbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 20px 0;
  flex-shrink: 0;
}

.detail-modal-body {
  padding: 4px 36px 40px;
  overflow-y: auto;
  flex: 1;
  -webkit-overflow-scrolling: touch;
}

.modal-close {
  position: absolute;
  top: 16px; right: 16px;
  background: var(--glass2);
  border: none;
  border-radius: 10px;
  color: var(--muted2);
  width: 32px; height: 32px;
  padding: 0;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.modal-close .ico { width: var(--ctl-icon-md); height: var(--ctl-icon-md); }
.modal-close:hover { color: var(--text); transform: scale(1.1); }

.modal-title { font-family: 'Instrument Serif', Georgia, serif; font-size: var(--fs-xl); font-weight: 400; margin-bottom: 6px; }
.modal-sub { font-size: var(--fs-xs); color: var(--muted2); margin-bottom: 28px; }

.social-btns { display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px; }

.social-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: var(--glass2);
  border: none;
  border-radius: 14px;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
}

.social-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.3); }
.social-icon { font-size: var(--fs-md); }

.modal-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 16px 0;
  color: var(--muted);
  font-size: var(--fs-2xs);
}

.modal-divider::before, .modal-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

.modal-input {
  width: 100%;
  background: var(--glass2);
  border: none;
  border-radius: 12px;
  padding: 11px 14px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text);
  margin-bottom: 10px;
  transition: all 0.2s;
}

.modal-input::placeholder { color: var(--muted); }
.modal-input:focus { box-shadow: 0 0 20px rgba(var(--accent-rgb),0.12); }

.modal-submit {
  width: 100%;
  height: var(--ctl-md);
  padding: 0 var(--ctl-px-md);
  display: inline-flex; align-items: center; justify-content: center;
  background: #2563EB;
  border: none;
  border-radius: var(--ctl-r);
  color: #ffffff;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--ctl-fs-md);
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 4px 20px rgba(37,99,235,0.3), inset 0 1px 0 rgba(255,255,255,0.15);
}

.modal-submit:hover { transform: translateY(-2px); box-shadow: 0 10px 32px rgba(37,99,235,0.45), inset 0 1px 0 rgba(255,255,255,0.2); }
.modal-submit:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }

.modal-error {
  font-size: var(--fs-xs);
  color: var(--red);
  margin-bottom: 10px;
  display: none;
}
.modal-success {
  font-size: var(--fs-xs);
  color: var(--green);
  margin-bottom: 10px;
  display: none;
}

/* === MOBILE NAV DRAWER === */
.nav-hamburger {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  cursor: pointer;
  width: 32px; height: 32px; padding: 0;
  border-radius: var(--ctl-r-sq);
  background: var(--glass2);
  border: none;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.nav-hamburger:hover { transform: scale(1.05); }

.nav-hamburger span {
  display: block;
  width: 18px; height: 2px;
  background: var(--muted2);
  border-radius: 2px;
  transition: all 0.25s;
}

.nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger.open span:nth-child(2) { opacity: 0; }
.nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.nav-drawer {
  display: none;
  position: fixed;
  top: 64px; left: 0; right: 0;
  background: var(--dropdown-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: none;
  box-shadow: 0 8px 32px rgba(0,0,0,0.4);
  z-index: 99;
  padding: 12px 16px 20px;
  flex-direction: column;
  gap: 4px;
}

.nav-drawer.open { display: flex; }
.nav-drawer .nav-link { padding: 12px 16px; font-size: var(--fs-sm); border-radius: 8px; }

/* === TICKER === */
.ticker-wrap {
  overflow: hidden;
  border-top: none;
  border-bottom: none;
  background: var(--glass);
  padding: 8px 0;
  position: relative;
  z-index: 1;
  user-select: none;
}
/* Edge fade to hint at more content */
.ticker-wrap::before,
.ticker-wrap::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  width: 48px;
  z-index: 2;
  pointer-events: none;
}
.ticker-wrap::before { left: 0;  background: linear-gradient(to right, var(--bg), transparent); }
.ticker-wrap::after  { right: 0; background: linear-gradient(to left,  var(--bg), transparent); }

/* CSS-animation ticker — works on Safari (scrollLeft rAF is unreliable there) */
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.ticker {
  display: flex;
  gap: 64px;
  white-space: nowrap;
  width: max-content;
  padding: 0 48px;
  will-change: transform;
}

.ticker-item { display: flex; align-items: center; gap: 8px; font-size: var(--fs-2xs); cursor: pointer; border-radius: 4px; padding: 1px 6px; transition: background 0.15s; }
.ticker-item:hover { background: var(--glass2); }
.ticker-item:hover .ticker-bank { color: var(--text); }
.ticker-bank { color: var(--text); font-weight: 600; }
.ticker-cat   { color: var(--muted2); font-size: var(--fs-2xs); letter-spacing: 0.01em; }
.ticker-rate  { color: var(--text); font-family: 'Syne', sans-serif; font-weight: 700; font-size: var(--fs-xs); }
.ticker-delta { font-family: 'Syne', sans-serif; font-weight: 700; font-size: var(--fs-2xs); }
.ticker-delta--up   { color: var(--red, #f87171); }
.ticker-delta--down { color: var(--green); }
.ticker-time  { color: var(--muted); font-size: var(--fs-2xs); font-style: italic; }
.ticker-chg   { font-size: var(--fs-2xs); }
.ticker-sep   { color: var(--border2); }

/* === TOAST NOTIFICATION === */
.toast-container {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.toast {
  padding: 12px 18px;
  background: rgba(8,15,26,0.55);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: none;
  border-radius: 16px;
  font-size: var(--fs-xs);
  color: var(--text);
  animation: toastIn 0.3s ease;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 320px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.45);
}

.toast.success { box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(var(--green-rgb),0.3); }
.toast.error   { box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(var(--red-rgb),0.3); }
.toast.warn    { box-shadow: 0 8px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(var(--amber-rgb),0.3); }

@keyframes toastIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* cursor blink */
.cursor {
  display: inline-block;
  width: 2px;
  height: 1em;
  background: var(--accent);
  margin-left: 2px;
  animation: blink 1s step-end infinite;
  vertical-align: middle;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

/* === SCROLL ANIMATIONS === */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.reveal.visible { opacity: 1; transform: translateY(0); }

/* No-transform variant: position:sticky works inside this reveal (transform breaks sticky) */
.reveal.reveal--opacity-only { transform: none; transition: opacity 0.6s ease; }
.reveal.reveal--opacity-only.visible { transform: none; }

/* === EMPTY / LOADING STATES === */
.empty-state,
.loading-state {
  text-align: center;
  padding: 64px 24px;
  color: var(--muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.empty-state .icon,
.loading-state .icon {
  font-size: var(--fs-4xl);
  margin-bottom: 4px;
  opacity: 0.55;
}

.empty-state p,
.loading-state p {
  font-size: var(--fs-sm);
  line-height: 1.5;
  max-width: 380px;
}

.empty-state .hint,
.loading-state .hint {
  font-size: var(--fs-xs);
  color: var(--muted);
  opacity: 0.7;
  margin-top: 2px;
}

/* === USER AVATAR === */
.user-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--accent);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--bg);
  cursor: pointer;
  position: relative;
}

.user-menu {
  position: absolute;
  top: 44px; right: 0;
  /* SOLID bg (2026-07-18): backdrop-filter never renders here — the menu is
     nested inside the nav's own backdrop-filter, and nested backdrop roots
     fail in both WebKit and Chromium, leaving a 55% translucent panel with
     page content bleeding through it. */
  background: var(--dropdown-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 8px;
  min-width: 160px;
  display: none;
  z-index: 200;
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
}

.user-menu.open { display: block; }

.user-menu-item {
  padding: 8px 12px;
  font-size: var(--fs-xs);
  color: var(--muted2);
  cursor: pointer;
  border-radius: 8px;
  transition: all 0.15s;
}

.user-menu-item:hover { background: var(--glass2); color: var(--text); }
.user-menu-item.danger { color: var(--red); }

/* === PAGE LAYOUT WRAPPERS === */
.page-content {
  max-width: 1400px;
  margin: 64px auto 0;
  padding: 20px 32px 60px;
}

.page-content-narrow {
  max-width: 900px;
  margin: 64px auto 0;
  padding: 20px 32px 60px;
}

/* ── Account Settings ──────────────────────────────────────────────────── */
.settings-card {
  background: var(--glass2);
  border: none;
  border-radius: 16px;
  padding: 24px 28px;
  margin-bottom: 20px;
  box-shadow: var(--elev-1);
}
.settings-card-title {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted2);
  margin-bottom: 20px;
}
.session-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.session-row:last-child { border-bottom: none; }
.session-info { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.session-ua   { font-size: var(--fs-xs); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.session-meta { font-size: var(--fs-2xs); color: var(--muted); }

/* Arch data flow — responsive row */
.data-flow-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
}

.data-flow-arrow {
  color: var(--accent);
  font-size: var(--fs-lg);
  flex: 1;
  text-align: center;
}

/* === RESPONSIVE — TABLET (≤ 900px) === */
/* === HEATMAP === */
.heat-grid { width: 100%; }
.heat-header-row,
.heat-row { display: flex; align-items: center; gap: 4px; margin-bottom: 4px; }

.heat-row { border-radius: 4px; }

#heatmap-card {
  border-radius: 8px;
  max-height: 65vh;
  /* Vertical scroll ONLY. Columns fit the width (see .heat-cell min-width:0),
     so there is no horizontal overflow - a single-axis scroll keeps the sticky
     date header reliable across browsers (a dual-axis overflow:auto made the
     header leak rows above/behind it, esp. in Safari). 2026-07-22. */
  overflow-x: hidden;
  overflow-y: auto;
}
/* Dates header row — sticky within the card's scroll viewport.
   Fully OPAQUE (was a →transparent gradient that let cell numbers bleed
   through as they scrolled under it, so it never read as truly static). */
.heat-dates-sticky {
  position: sticky;
  top: 0;
  z-index: 4;
  background: var(--bg);
  padding-top: 12px;
  padding-bottom: 8px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--border);
  box-shadow: 0 4px 8px -4px rgba(0,0,0,0.35);
}

/* Sticky institution column — stays visible during horizontal scroll */
.heat-inst-col {
  min-width: 300px; width: 300px; flex-shrink: 0;
  padding-right: 28px; display: flex; align-items: center; gap: 10px;
  position: sticky; left: 0; z-index: 3;
  background: var(--bg);
}
/* Soft right-edge fade separates names from the scrolling cells */
.heat-inst-col::after {
  content: '';
  position: absolute; right: 0; top: 0; bottom: 0; width: 28px;
  background: linear-gradient(to right, var(--bg), transparent);
  pointer-events: none;
}
.heat-header-row .heat-inst-col {
  background: var(--bg);
  /* Top-left corner is sticky on BOTH axes (top from .heat-dates-sticky z4,
     left from .heat-inst-col z3). It must sit above both the date labels and
     the row name cells scrolling under it, or names bleed through - z6. */
  z-index: 6;
}
.heat-header-row .heat-inst-col::after {
  background: linear-gradient(to right, var(--bg), transparent);
}
.heat-inst-name {
  font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: var(--fs-xs); font-weight: 600;
  color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color 0.12s;
}
.heat-inst-col:hover .heat-inst-name {
  color: var(--accent);
}

/* Date labels and cells grow to fill available width. min-width:0 lets them
   shrink so a 90-day window fits without horizontal overflow (see #heatmap-card). */
.heat-date-label {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  text-align: center;
  /* Visible (not clipped): in dense mode only every Nth label has text, so a
     label's month can spill into its empty neighbours instead of being cut
     off ('24 APl'). white-space:nowrap keeps day/month on their own lines. */
  overflow: visible; white-space: nowrap;
}
.heat-date-day {
  font-size: var(--fs-2xs); font-weight: 700; color: var(--text); line-height: 1.25;
}
.heat-date-mon {
  font-size:var(--fs-2xs); font-weight: 500; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em; line-height: 1.2;
}
.heat-cell {
  flex: 1; min-width: 0; height: 34px;
  border-radius: 5px;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-2xs); font-weight: 700;
  font-family: 'Syne', sans-serif;
  transition: transform 0.14s ease, box-shadow 0.14s ease, opacity 0.14s;
  cursor: pointer;
  letter-spacing: 0.01em;
  position: relative; z-index: 1;
  overflow: hidden;
}
/* Dense (wide-window) mode: columns are too narrow for the tier-count number,
   so show pure colour - the hover tooltip still carries the full detail. */
.heat-grid--dense .heat-cell { color: transparent; font-size: 0; height: 30px; }
.heat-grid--dense .heat-row,
.heat-grid--dense .heat-header-row { gap: 2px; }
.heat-cell:hover {
  transform: scale(1.15);
  z-index: 10;
  box-shadow: 0 3px 12px rgba(0,0,0,0.45);
  opacity: 1 !important;
}
.heat-cell.empty { cursor: default; opacity: 0.35; }
.heat-cell.empty:hover { transform: none; box-shadow: none; }
.heat-cell.empty  { background: var(--border); }
.heat-cell.cut-1  { background: #0f2d5f; color: #93c5fd; }
.heat-cell.cut-2  { background: #1e40af; color: #dbeafe; }
.heat-cell.cut-3p { background: #2563eb; color: #fff; }
.heat-cell.rise-1  { background: #3d2005; color: #fbbf24; }
.heat-cell.rise-2  { background: #78350f; color: #fed7aa; }
.heat-cell.rise-3p { background: #d97706; color: #fff; }
.heat-cell.mixed   { color: #fff; overflow: hidden; }
.heat-cell.policy  { background: #1a2744; color: #79aaff; }
.heat-cell.feat    { background: #1e2433; color: var(--muted); }

/* Light mode */
[data-theme="light"] .heat-inst-col { background: var(--bg); }
[data-theme="light"] .heat-inst-col::after { background: linear-gradient(to right, var(--bg), transparent); }
[data-theme="light"] .heat-header-row .heat-inst-col { background: var(--bg); }
[data-theme="light"] .heat-cell.empty  { background: var(--border); }
[data-theme="light"] .heat-cell.cut-1  { background: #dbeafe; color: #1e40af; }
[data-theme="light"] .heat-cell.cut-2  { background: #93c5fd; color: #1e3a8a; }
[data-theme="light"] .heat-cell.cut-3p { background: #2563eb; color: #fff; }
[data-theme="light"] .heat-cell.rise-1  { background: #fef3c7; color: #92400e; }
[data-theme="light"] .heat-cell.rise-2  { background: #fcd34d; color: #78350f; }
[data-theme="light"] .heat-cell.rise-3p { background: #d97706; color: #fff; }
[data-theme="light"] .heat-cell.policy  { background: #dbe9ff; color: #1d4ed8; }
[data-theme="light"] .heat-cell.feat    { background: #e8eaed; color: #555; }
[data-theme="light"] .heat-cell:hover { box-shadow: 0 3px 12px rgba(0,0,0,0.12); }
.heat-dim-header {
  font-size:var(--fs-2xs); color: var(--muted); text-align: center;
  white-space: nowrap; flex-shrink: 0; padding-bottom: 2px;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.heat-dim-col {
  font-size:var(--fs-2xs); color: var(--muted2); text-align: center;
  flex-shrink: 0; font-weight: 600; letter-spacing: 0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  padding-right: 4px;
}
.heat-row-inst-start {
  margin-top: 5px;
  padding-top: 5px;
  /* Replaced hard border with subtle spacing — less box-like */
}
.heat-legend { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 16px; padding-top: 12px; }
.heat-legend-item { display: flex; align-items: center; gap: 5px; font-size: var(--fs-2xs); color: var(--muted2); font-weight: 500; }
.heat-legend-swatch { width: 13px; height: 13px; border-radius: 3px; flex-shrink: 0; }

/* === HEATMAP CELL DRILL-DOWN MODAL === */
.heatcell-section {
  display: flex; align-items: center; gap: 7px;
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 10px 0 6px; margin-top: 6px;
  color: var(--muted2);
}
.heatcell-section span {
  font-size:var(--fs-2xs); font-weight: 600; border-radius: 10px;
  padding: 1px 7px;
}
.heatcell-section.cut  { color: #10c060; }
.heatcell-section.cut  span { background: rgba(16,192,96,0.12); color: #10c060; }
.heatcell-section.rise { color: #ef3030; }
.heatcell-section.rise span { background: rgba(239,48,48,0.12); color: #ef3030; }
.heatcell-section.other { color: var(--muted2); }
.heatcell-section.other span { background: var(--surface2); }

.heatcell-row {
  display: flex; flex-direction: column; gap: 3px;
  padding: 9px 0;
}
.heatcell-row-name {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--text);
  word-break: break-word;
}
.heatcell-row-bottom {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.heatcell-row-dims {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap; flex: 1;
}
.heatcell-dim-tag {
  font-size:var(--fs-2xs); font-weight: 600; color: var(--muted2);
  background: var(--glass2); border: 1px solid var(--glass-border);
  border-radius: 4px; padding: 1px 6px; white-space: nowrap;
}
.heatcell-count-badge {
  display: inline-block; margin-left: 7px;
  font-size:var(--fs-2xs); font-weight: 700; color: var(--muted2);
  background: var(--glass2); border: 1px solid var(--glass-border);
  border-radius: 10px; padding: 1px 7px; vertical-align: middle;
}
.heatcell-link {
  display: inline-block; margin-left: 7px; vertical-align: middle;
  font-size: var(--fs-2xs); color: #5b9cf5; text-decoration: none;
  opacity: 0.75; transition: opacity 0.15s, color 0.12s;
}
.heatcell-link:hover { opacity: 1; color: #7cb8ff; text-decoration: underline; }
.heatcell-row-rates {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-sm); font-family: monospace; flex-shrink: 0;
}
.heatcell-old  { color: var(--muted); text-decoration: line-through; }
.heatcell-new  { color: var(--text); font-weight: 700; }
.heatcell-arrow { color: var(--muted2); }
.heatcell-delta { font-weight: 700; font-size: var(--fs-sm); }

/* ── Market Pulse panel (hero sidebar) ─────────────────────────────────── */
/* The card chrome lives on the wrapper so the subscribe pill renders INSIDE
   the panel bottom, mirroring Product Research's .feed-panel/.feed-subscribe. */
.apra-pulse-panel {
  background: var(--subtle);
  border-radius: 12px;
}
#apra-pulse-inner {
  padding: 12px 14px;
  border-radius: 12px;
}

/* Reserved right gutter below the APRA hero so the docked insights carousel
   never overlaps the tables (matches the rail width + edge gap). */
@media (min-width: 1101px) {
  .apra-below-hero { padding-right: 376px; }
}
.pulse-freshness {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size:var(--fs-2xs);
  color: var(--muted);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 500;
}
.pulse-kpi {
  padding: 6px 8px;
  border-radius: 8px;
  background: var(--subtle);
}
.pulse-kpi-label {
  font-size:var(--fs-2xs);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 2px;
  font-weight: 500;
}
.pulse-kpi-value {
  font-size: var(--fs-base);
  font-weight: 700;
}
.pulse-bar-track {
  height: 8px;
  border-radius: 4px;
  background: var(--subtle-hover);
  overflow: hidden;
}
.pulse-bar-fill {
  height: 100%;
  border-radius: 4px;
  background: #3b82f6;
  transition: width 0.4s ease;
}
.pulse-mover {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border-radius: 8px;
  background: rgba(255,255,255,0.03);
}

/* === HERO STACKS BELOW 1200px (2026-09-19) ===
   The feed column is a fixed 690px and the hero takes what is left: 406px at
   1200, 306 at 1100, 230 at 1024, 166 at 960 - the title wrapped to two lines,
   the Product Analyst button ran off the column and the insight card clipped
   its own headline ("Fixed Rate Ho..."). The row only stacked below 900px.
   From 1200px down the hero sits above the feed at full width, the same shape
   phones already get; the ≤900px block below keeps its tighter paddings. */
@media (max-width: 1200px) {
  .hero-layout { flex-direction: column; gap: 0; }
  .hero-layout .hero { padding: 20px 0 12px; }
  .stats-column { flex: none; width: 100%; margin: 0 0 8px; }
}

/* === RESPONSIVE — MEDIUM (≤ 1100px) === */
@media (max-width: 1100px) {
  .nav-status { display: none; }
}

@media (max-width: 900px) {
  .hero-layout { flex-direction: column; padding: 0 24px; gap: 0; margin-top: 12px; }
  .hero-layout .hero { padding: 20px 0 12px; }
  .stats-column { flex: none; width: 100%; margin: 0 0 8px; }
  .hero-layout .stat-cell { padding: 14px 16px; }
  .hero-layout .stat-label { font-size:var(--fs-2xs); }
  .stats-bar { grid-template-columns: repeat(2, 1fr); }
  .arch-grid { grid-template-columns: repeat(2, 1fr); }
  .form-grid { grid-template-columns: 1fr; }

  .page-content, .page-content-narrow { padding: 24px 24px 48px; }

  /* Section headers allow wrapping at tablet */
  .section-header { flex-wrap: wrap; gap: 12px; }

  /* Toolbar stacks vertically — search full width, pills scrollable */
  .table-toolbar { flex-direction: column; align-items: stretch; gap: 10px; }
  .search-box { min-width: unset; width: 100%; }

  /* Filter pills — horizontal scroll, no wrap */
  #dash-category-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  #dash-category-pills::-webkit-scrollbar { display: none; }
  #dash-category-pills .filter-pill { flex-shrink: 0; }
}

/* === RESPONSIVE — MOBILE (≤ 640px) === */
/* ── Mobile: Product Research page (2026-07-19) ─────────────────────────── */
@media (max-width: 640px) {
  /* Mobile WebKit lets a nested overflow-hidden marquee (the ticker) extend
     the BODY's horizontal scroll anyway - clip at the root. Nothing
     meaningful lives off-canvas at this width. */
  html, body { overflow-x: clip; }

  /* Rate Activity header: controls were overlaying the title — title row
     grows, the category select + charts pill wrap to their own row. */
  .feed-header-row { flex-wrap: wrap; row-gap: 8px; }
  .feed-header-row .feed-title { flex: 1 0 auto; }
  .feed-cat-select { margin-left: 0; }

  /* Repayment-calc strip: the single pill clipped at the right edge (the
     "over N years" field was off-screen). Wrap into rows, drop the pill
     radius, hide the vertical dividers. */
  .calc-inputs-strip {
    display: flex; flex-wrap: wrap; width: 100%;
    border-radius: 16px; row-gap: 2px;
  }
  .calc-inputs-strip .calc-strip-context { flex: 1 1 100%; }
  .calc-inputs-strip .calc-field-divider { display: none; }
  .calc-inputs-strip .calc-field { flex: 1 1 45%; }

  .hero-insights { max-width: 100%; }

  /* ── Category sidebar → horizontal chip bar (2026-07-20) ──────────────
     The desktop left rail (vertical, grouped, two screens tall on a phone)
     becomes the standard mobile pattern: one horizontally-scrollable row
     of chips. Group labels turn into small inline separators. */
  .tracker-filter-bar-body .tracker-filter-pills {
    flex-direction: row; align-items: center; gap: 6px;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; padding: 4px 2px 10px;
  }
  .tracker-filter-bar-body .tracker-filter-pills::-webkit-scrollbar { display: none; }
  /* one extra class of specificity: the base .tracker-filter-pills
     .filter-pill rules sit LATER in this file and would win a tie */
  .tracker-filter-bar-body .tracker-filter-pills .filter-pill {
    flex: 0 0 auto; width: auto; height: var(--ctl-sm);
    padding: 0 var(--ctl-px-sm); border-radius: var(--ctl-r);
    background: var(--glass2);
  }

  /* inline group separators WITHIN the main category row (Lending/Deposits…) */
  #dash-category-pills .tracker-filter-group-label {
    flex: 0 0 auto; white-space: nowrap;
    padding: 0 2px 0 12px; margin-left: 4px;
    font-size: var(--fs-3xs);
    border-left: 1px solid var(--glass-border);
  }
  /* standalone groups (Specialist / Other): label stays above its own
     horizontally-scrollable chip row */
  .tracker-filter-group > .tracker-filter-group-label { padding: 10px 6px 2px; }
  #dash-category-pills .subfilter-inline {
    display: inline-flex; flex: 0 0 auto; flex-wrap: nowrap;
  }

  /* 30-day mini charts: 2x2 grid is unreadable at 390px — one tall column */
  .chart-mini-grid { grid-template-columns: 1fr; grid-template-rows: none; }
  .chart-mini { min-height: 130px; }

  /* Compare basket (full-width static block at this width): breathing room,
     and the CTA/Ask-AI buttons get thumb-sized targets */
  .compare-basket { padding: 14px; }
  .compare-basket-cta, .compare-basket-askai { min-height: 44px; }

  /* Touch targets: ticker rows and circle buttons */
  .ticker-wrap { padding: 10px 0; }
  .btn-circle { width: 40px; height: 40px; }

  /* Feed rows: slightly roomier line height for fat fingers */
  .feed-item { padding-top: 10px; padding-bottom: 10px; }
}

@media (max-width: 640px) {
  /* Nav */
  nav { padding: 0 16px; }
  .nav-links { display: none; }
  .nav-status { display: none; }
  .nav-hamburger { display: flex; }
  .btn-login { display: none; }

  /* Page layout */
  .page-content, .page-content-narrow { padding: 16px 16px 40px; margin-top: 64px; }
  .hero { padding: 48px 16px 36px; }
  .hero-layout { padding: 0 16px; }
  .hero-layout .hero { padding: 12px 0 8px; }
  .stats-column { width: 100%; }
  .hero-layout .stat-value { font-size: var(--fs-xl); }
  .section { padding: 0 16px 40px; }
  .stats-bar { grid-template-columns: repeat(2, 1fr); width: calc(100% - 32px); margin: 16px auto; }
  .arch-grid { grid-template-columns: 1fr; }

  /* Hero */
  .hero-title { font-size: clamp(1.9rem, 8vw, 2.8rem); }
  .hero-sub { font-size: var(--fs-base); }
  .hero-actions { flex-direction: column; gap: 10px; }
  .hero-actions .btn-primary, .hero-actions .btn-ghost, .hero-actions .btn-secondary { width: 100%; justify-content: center; }

  /* Page tables → card layout (modals excluded — they use their own scroll) */
  main table thead { display: none; }
  main table, main table tbody, main table tr, main table td { display: block; width: 100%; }
  main table tr { border: 1px solid var(--glass-border); border-radius: 14px; margin: 0 0 10px; background: var(--glass); overflow: hidden; backdrop-filter: var(--glass-blur); }
  main table tr:last-child { margin-bottom: 0; }
  main table td { padding: 10px 16px; border-bottom: 1px solid rgba(255,255,255,0.05); display: flex; align-items: flex-start; justify-content: space-between; font-size: var(--fs-xs); gap: 8px; }
  main table td:last-child { border-bottom: none; }
  main table td::before { content: attr(data-label); font-size:var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); font-weight: 500; flex-shrink: 0; margin-top: 1px; }
  main table td:first-child { background: var(--glass2); justify-content: flex-start; padding: 12px 16px; }
  main table td:first-child::before { display: none; }

  /* APRA analytics tables — preserve table layout, use horizontal scroll instead of card stacking */
  #apra-table, .apra-inner-table { display: table !important; width: 100% !important; }
  #apra-table thead, .apra-inner-table thead { display: table-header-group !important; }
  #apra-table tbody, .apra-inner-table tbody { display: table-row-group !important; }
  #apra-table tr, .apra-inner-table tr { display: table-row !important; border: none !important; border-radius: 0 !important; margin: 0 !important; background: none !important; }
  #apra-table td, .apra-inner-table td, #apra-table th, .apra-inner-table th { display: table-cell !important; width: auto !important; border-bottom: none !important; padding: revert !important; }
  #apra-table td::before, .apra-inner-table td::before { display: none !important; }

  /* Modal tables → horizontal scroll instead of cards */
  .modal-overlay .modal table { font-size:var(--fs-2xs); }
  #prod-detail-content, #inst-detail-content { overflow-x: hidden; }

  /* Toolbar */
  .table-toolbar { flex-direction: column; align-items: stretch; gap: 8px; }
  .search-box { min-width: unset; width: 100%; }

  /* Filter pill rows stay sideways scrollers on the dashboard, Changes and
     Institutions: that is how those pages are meant to read. */
  #dash-category-pills,
  #inst-filter-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  #dash-category-pills::-webkit-scrollbar,
  #inst-filter-pills::-webkit-scrollbar { display: none; }

  #dash-category-pills .filter-pill,
  #inst-filter-pills .filter-pill { flex-shrink: 0; }

  /* Log + alerts: single column */
  .log-notif-grid { grid-template-columns: 1fr !important; }

  /* Footer */
  footer { flex-direction: column; text-align: center; padding: 28px 20px; gap: 20px; }
  .footer-links { flex-wrap: wrap; justify-content: center; gap: 12px; }

  /* Modals → full-width bottom sheet with scroll */
  .modal-overlay { align-items: flex-end; }
  .modal {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    margin: 0;
    width: 100%;
    max-width: 100%;
    padding: 28px 20px;
    max-height: 92vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .modal.detail-modal {
    padding: 0;
    max-height: 92vh;
    overflow: hidden;
  }
  .detail-modal-body {
    padding: 4px 20px 36px;
  }

  /* Collapse 2-col grids inside product/institution modals */
  #prod-detail-content [style*="grid-template-columns:1fr 1fr"],
  #inst-detail-content [style*="grid-template-columns:1fr 1fr"] {
    grid-template-columns: 1fr !important;
  }

  /* Rate tables inside modal: horizontal scroll */
  #prod-detail-content [style*="overflow-x:auto"],
  #inst-detail-content [style*="overflow-x:auto"] {
    -webkit-overflow-scrolling: touch;
  }

  /* Stats */
  .stat-cell { padding: 18px 16px; }
  .stat-value { font-size: var(--fs-xl); }

  /* Toast */
  .toast-container { right: 12px; bottom: 16px; }

  /* Arch data flow: vertical stack, hide horizontal arrows */
  .data-flow-row { flex-direction: column; align-items: center; gap: 12px; }
  .data-flow-arrow { flex: none; transform: rotate(90deg); }
}

@media (max-width: 380px) {
  .stats-bar { grid-template-columns: 1fr; }
  .hero-title { font-size: var(--fs-2xl); }
}

/* ── Institutions grid ─────────────────────────────────────────────────── */

.inst-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

.inst-card {
  background: var(--surface2);
  border: none;
  border-radius: 10px;
  padding: 16px 14px 12px;
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  box-shadow: var(--elev-1);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.inst-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--elev-hover);
}

.inst-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}

.inst-logo-wrap {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
}

.inst-logo-img {
  width: 40px;
  height: 40px;
  object-fit: contain;
  border-radius: 8px;
  background: #fff;
}

.inst-logo-fallback {
  width: 40px;
  height: 40px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-md);
  font-weight: 700;
}

.inst-card-name {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--fs-sm);
  line-height: 1.2;
  color: var(--text);
}

.inst-card-abn {
  font-size:var(--fs-2xs);
  color: var(--muted);
  letter-spacing: 0.02em;
}

.inst-card-stats {
  display: flex;
  gap: 16px;
  margin-top: 6px;
  padding-top: 10px;
}

.inst-stat {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.inst-stat-value {
  font-family: 'Syne', sans-serif;
  font-weight: 800;
  font-size: var(--fs-md);
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1;
}

.inst-stat-label {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
}

.inst-loading {
  grid-column: 1 / -1;
  text-align: center;
  padding: 60px 20px;
  color: var(--muted);
  font-size: var(--fs-sm);
}

@media (max-width: 640px) {
  .inst-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
  .inst-card { padding: 14px 12px 10px; }
}

/* ── Sector Switcher ─────────────────────────────────────────────────────── */
.sector-switcher {
  display: flex;
  gap: 4px;
  align-items: center;
  background: var(--glass2);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: 20px;
  padding: 3px;
  flex-shrink: 0;
  box-shadow: var(--glass-highlight);
}

.sector-pill {
  display: flex;
  align-items: center;
  gap: 5px;
  height: var(--ctl-sm);
  padding: 0 var(--ctl-px-sm);
  border-radius: var(--ctl-r);
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: var(--ctl-fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  white-space: nowrap;
}

.sector-pill:hover {
  color: var(--text);
  background: var(--glass2);
}

.sector-pill.active {
  background: var(--accent);
  color: var(--bg);
  box-shadow: 0 2px 10px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.1);
}

/* ── Sector Coming-Soon Banner ───────────────────────────────────────────── */
.sector-coming-soon-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px 20px;
  background: linear-gradient(90deg, rgba(var(--accent-rgb),0.06), rgba(var(--accent-rgb),0.03));
  font-size: var(--fs-xs);
  color: var(--text);
}

.sector-coming-soon-banner strong {
  color: #ff6d00;
}

@media (max-width: 640px) {
  .sector-switcher { display: none; }
}

/* ── Light mode: surface overrides for hardcoded dark rgba values ────────── */
[data-theme="light"] .modal {
  background: rgba(248,250,255,0.78);
  box-shadow: 0 24px 80px rgba(0,0,0,0.08), 0 0 0 1px rgba(255,255,255,0.7), inset 0 1px 0 rgba(255,255,255,0.95);
}
[data-theme="light"] .toast {
  background: rgba(248,250,255,0.92);
  box-shadow: 0 8px 32px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.9);
}
[data-theme="light"] .user-menu {
  box-shadow: 0 8px 32px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,255,255,0.9);
}
[data-theme="light"] .nav-drawer {
  /* opaque: at 0.92 the page read through the open drawer on phones (operator, 2026-09-06) */
  background: #f3f5f9;
  box-shadow: 0 8px 32px rgba(0,0,0,0.08);
}
[data-theme="light"] .code-panel {
  background: rgba(230,234,244,0.6);
}

/* ── Bank Comparison ───────────────────────────────────────────────────── */
/* ── Live Product Tracker ────────────────────────────────────────────────── */

/* Outer wrapper: filter-bar + table on the left, compare basket sticky on the right */
.tracker-layout {
  display: grid;
  grid-template-columns: 176px 1fr 240px;
  gap: 16px;
  align-items: stretch;
  overflow-anchor: none; /* prevent browser scroll-anchoring on layout changes */
}

/* The third 240px track is the Explorer's compare basket. The Product
   Browser has no basket, so on that page the grid is two columns and the
   list takes the width back (2026-09-09). */

/* Centre column — flows with the page; search+calc pin via .tracker-sticky-header */
.tracker-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* Sticky header inside .tracker-main — pins flush with the nav, then internal padding-top
   reserves a 16px visible strip below the nav. The sticky box extends up to cover the strip
   with --bg so table rows can't scroll through it. */
.tracker-sticky-header {
  position: sticky;
  top: 64px;
  z-index: 5;
  background: var(--bg);
  padding-top: 16px;
  padding-bottom: 8px;
}

/* Search bar — sits at top of tracker-main, not separately sticky */
.tracker-search-bar {
  height: 46px;
  flex-shrink: 0;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  padding: 0 14px;
  background: var(--surface2);
  border: none;
  border-radius: 8px 8px 0 0;
}
.tracker-search-bar .search-box {
  flex: 1;
  min-width: 0;
  background: var(--surface);
  border: none;
  border-radius: 5px;
  padding: 5px 12px;
  box-shadow: none;
}
.tracker-search-bar .search-input {
  width: 100%;
}

/* Left sidebar: filter panel — sticky to viewport, grows naturally (no scrollbar) */
/* Slot: outer wrapper that occupies the grid column. Height flexes with the grid row, but
   the slot's own content (filter-bar) contributes to the row's intrinsic size so that when
   the table column is short (e.g. 2 products filtered), the row stretches to let the full
   categories/specialist list remain reachable. */
.tracker-filter-slot {
  width: 176px;
  align-self: stretch;
  position: relative;
}

.tracker-filter-bar {
  width: 100%;
  /* Sticky within the slot. max-height keeps it viewport-bounded when the slot is tall. */
  position: sticky;
  top: 64px;
  max-height: calc(100vh - 64px);
  background: transparent;
  border: none;
  border-radius: 8px;
  padding: 0 10px;
  display: flex;
  flex-direction: column;
}

/* Head sits at the top of the sidebar as a fixed (non-scrolling) flex item.
   No sticky needed - the body is the scroll container below, so pills can never
   physically reach this area. */
.tracker-filter-bar-head {
  flex: 0 0 auto;
  background: var(--bg);
  padding: 16px 0 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Body is the actual scroll container — flexes to fill remaining sidebar height.
   min-height:0 is critical for flex-child overflow to work. */
.tracker-filter-bar-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  scrollbar-width: none;
}
.tracker-filter-bar-body::-webkit-scrollbar { display: none; }

/* Sidebar title block — sits above Categories so the title row aligns
   horizontally with the centre column's search bar and right column's Compare. */
.tracker-pretitle {
  padding: 0 4px 14px;
}
.tracker-pretitle .section-title {
  font-size: var(--fs-xl);
  line-height: 1.05;
  margin: 0;
  display: block; /* allow wrap onto two lines in narrow sidebar */
}
.tracker-pretitle-sub {
  font-size: var(--fs-2xs);
  color: var(--muted);
  margin-top: 4px;
}

/* Sidebar header — sits at top of sticky sidebar; visible whenever the sidebar is in view */
.tracker-filter-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text);
  padding-bottom: 8px;
  margin-bottom: 4px;
}

/* Group label inside vertical nav — clear section heading */
.tracker-filter-group-label {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted2);
  padding: 12px 6px 4px;
}
.tracker-filter-group-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
  border-radius: 4px;
  transition: color 0.15s ease;
}
.tracker-filter-group-toggle:hover { color: var(--text); }
.tracker-filter-chevron {
  opacity: 0.55;
  transform: rotate(90deg);
  transition: transform 0.18s ease;
  flex-shrink: 0;
  margin-right: 4px;
}
.tracker-filter-group.collapsed .tracker-filter-chevron { transform: rotate(0deg); }
.tracker-filter-group.collapsed .tracker-filter-group-body { display: none; }

/* Vertical nav pills */
.tracker-filter-pills {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.tracker-filter-pills .filter-pill {
  /* the desktop rail is a list: sm height, square corners, full width */
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  width: 100%;
  height: var(--ctl-sm);
  padding: 0 8px;
  border-radius: var(--ctl-r-sq);
  background: transparent;
  border: none;
  color: var(--muted2);
  font-size: var(--ctl-fs-sm);
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background 0.13s, color 0.13s;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tracker-filter-pills .filter-pill:hover {
  background: rgba(255,255,255,0.05);
  color: var(--text);
}
.tracker-filter-pills .filter-pill.active {
  background: var(--select-bg);
  color: var(--select-text);
  font-weight: 600;
}
.tracker-filter-pills .filter-pill.active:hover {
  background: var(--select-bg);
  opacity: 1;
}

/* Specialist pills — coloured dot variant in sidebar */
.tracker-specialist-pills { gap: 4px; }
.tracker-specialist-pills .filter-pill { justify-content: flex-start; }

/* Active specialist pill — colour-tinted background only */
.specialist-pill--green.active        { background: rgba(34,197,94,0.15);  border: none; color: #22c55e; }
.specialist-pill--defence.active      { background: rgba(96,165,250,0.15); border: none; color: #60a5fa; }
.specialist-pill--smsf.active         { background: rgba(167,139,250,0.15);border: none; color: #a78bfa; }
.specialist-pill--construction.active { background: rgba(251,191,36,0.15); border: none; color: #fbbf24; }
.specialist-pill--bridging.active     { background: rgba(251,191,36,0.15); border: none; color: #fbbf24; }
.specialist-pill--shared-equity.active{ background: rgba(52,211,153,0.15); border: none; color: #34d399; }
.specialist-pill--profession.active   { background: rgba(244,114,182,0.15);border: none; color: #f472b6; }
.specialist-pill--seniors.active      { background: rgba(148,163,184,0.15);border: none; color: #94a3b8; }

/* Inline subfilter block — appears directly below the active category pill */
.subfilter-inline {
  margin: 2px 0 4px 6px;
  padding-left: 10px;
  border-left: 2px solid var(--blue);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Legacy subfilter row (hidden in sidebar mode, kept for products page) */
.tracker-subfilter-row {
  padding-top: 10px;
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.subfilter-group {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.subfilter-group-label {
  font-size:var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted2);
  padding: 4px 6px 4px;
  margin-top: 2px;
}
.subfilter-group-pills {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.subfilter-pill {
  display: flex !important;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  height: var(--ctl-sm);
  padding: 0 8px !important;
  border-radius: var(--ctl-r-sq) !important;
  background: transparent !important;
  border: none !important;
  color: var(--muted2) !important;
  font-size: var(--fs-xs) !important;
  font-weight: 500 !important;
  text-align: left !important;
  cursor: pointer;
  transition: background 0.13s, color 0.13s;
}
.subfilter-pill:hover { color: var(--text) !important; background: rgba(255,255,255,0.05) !important; }
.subfilter-pill.active { background: var(--select-bg) !important; color: var(--select-text) !important; font-weight: 600 !important; }

/* Legacy filter-row (heatmap etc.) stays horizontal */
.filter-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Table card: flex-1 scroll container — fills remaining height of tracker-main.
   min-height stabilises the tracker section across filter changes - without it, a filter
   that drops row count (e.g. 30 → 3 rows) collapses tracker-layout dramatically, pulling
   the Rate Movement Heatmap section below up into the viewport.
   Sized so total tracker-layout height (sticky header ~80px + this wrap + pagination) ≥ 100vh,
   guaranteeing the next section stays below the fold when anchored to tracker top. */
.tracker-table-wrap {
  border-radius: 0 0 8px 8px;
  /* Table column sized to content — no artificial min-height. This way the tracker-layout
     row ends where the products end, and the sticky sidebar exits cleanly as the user
     scrolls into the next section (Rate Movement Heatmap). */
}
.tracker-table-wrap::-webkit-scrollbar { width: 4px; }
.tracker-table-wrap::-webkit-scrollbar-track { background: transparent; }
.tracker-table-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

/* Single fixed-layout table inside the scroll container */
.tracker-col-table {
  table-layout: fixed;
  width: 100%;
  border-collapse: collapse;
}
/* Default (no calc mode) — 6 visible cols, sums to 100% */
.col-inst { width: 18%; }
.col-prod { width: 28%; }
.col-cat  { width: 16%; }
.col-rate { width: 11%; }
.col-tier { width: 17%; }
.col-cmp  { width: 10%; }

/* Calc mode overrides the table grid with card rendering — see .quote-card rules below */

/* Thead sticks below the sticky search+calc header (which pins at top: 80px).
   196px = 80 sticky offset + ~46 search row + ~52 calc strip + ~18 padding.
   When calc strip is hidden the thead sits ~52px below the header - minor cosmetic gap. */
#product-table thead {
  position: sticky;
  top: 196px;
  z-index: 4;
  background: var(--bg);
}
#product-table thead th {
  padding: 10px 14px;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size:var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* Pagination locked below the scroll area — never scrolls with the table */
.tracker-pagination {
  flex-shrink: 0;
  margin: 0;
  border-radius: 0 0 8px 8px;
  background: transparent;
}

/* CDR source disclaimer — single muted line above product lists.
   Visually attached to the table-wrap below it (matching surface +
   rounded top corners) so it reads as a single block with the table
   header instead of a floating disconnected line. Originally sat as
   a free-floating italic line which felt disjointed (caught 2026-04-29). */
.cdr-source-note {
  flex-shrink: 0;
  font-size: var(--fs-2xs);
  font-style: italic;
  color: var(--muted2, var(--muted));
  /* Compact 2026-04-29 — was 8px vertical, now 4px to recover ~10px of
     vertical space. Disclaimer is informational, not a primary control. */
  padding: 4px 14px;
  line-height: 1.3;
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border-radius: 8px 8px 0 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
}
.cdr-source-note::before {
  content: "ⓘ";
  font-style: normal;
  opacity: 0.7;
  flex-shrink: 0;
}
/* Disclaimer + table-wrap form one continuous block: table-wrap loses
   its top corners since they're now owned by the disclaimer above it. */
.cdr-source-note + .tracker-table-wrap {
  border-radius: 0 0 8px 8px;
}

/* ── Products page: full-page layout matching dashboard ─────────────────── */
/* tracker-main already gives sticky viewport-height flex column;
   prod-tracker-main overrides height to account for the taller filter bar */
/* The Product Browser used to be a 100vh panel with the table scrolling
   inside it, which showed three or four products and gave the reader a second
   scroll surface. It now grows to its content and the PAGE scrolls, the way
   the Product Explorer list does (2026-09-09). */

/* Products filter bar: search + horizontal category pills + subfilters stacked */

/* The Freshness/Sort row now sits at the top of the list column, not in the
   filter panel, so it needs its own breathing room (2026-09-09). */
/* the group blocks stack down the bar; only the pill rows run across */

/* Sub-filter toggle pills (products page dimension filters) */
.subfilter-toggle {
  font-size:var(--fs-2xs) !important;
  padding: 2px 10px !important;
  border-radius: 16px !important;
  background: transparent !important;
  color: var(--muted) !important;
  border: 1px solid var(--glass-border) !important;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s;
  line-height: 1.6;
}
.subfilter-toggle:hover {
  color: var(--text) !important;
  border-color: var(--border) !important;
}
.subfilter-toggle.active {
  background: var(--accent) !important;
  color: #fff !important;
  border-color: var(--accent) !important;
}
/* "Clear ×" button next to the subfilter toggles — hover colour moved here
   from inline onmouseover/onmouseout handlers (CSP step 2a). */
.subfilter-clear {
  color: var(--muted2);
  transition: color 0.15s;
}
.subfilter-clear:hover { color: var(--text); }

/* Products table thead removed 2026-04-29 — card-style rows make
   columnar headers redundant. Sort UI now lives in the filter bar
   below as a dropdown (.prod-sort-wrap). */

/* Sort dropdown — sits on the right side of the dim-filter row, paired
   with the filter pills on the left. Styled to match the existing dark
   surface aesthetic; the select itself uses appearance:none so we own
   the chevron rendering and avoid the OS-default heavy native styling. */
.prod-dim-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  width: 100%;
}
.prod-sort-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.prod-sort-wrap label {
  font-size: var(--fs-2xs);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}
/* Match .filter-pill aesthetic exactly: 20px pill radius, no border,
   --surface bg, --muted2 text, 0.7rem. Padding allows for the chevron
   icon on the right (28px right-pad vs the standard 12px). */
.prod-sort-wrap select {
  appearance: none;
  -webkit-appearance: none;
  /* --surface2 to match .filter-pill — same dark-mode contrast bump */
  background-color: var(--surface2);
  color: var(--muted2);
  border: none;
  border-radius: 20px;
  padding: 5px 30px 5px 12px;
  font-size: var(--fs-2xs);
  cursor: pointer;
  font-family: inherit;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
  transition: color 0.15s, background-color 0.15s;
}
.prod-sort-wrap select:hover,
.prod-sort-wrap select:focus {
  background-color: var(--select-bg);
  color: var(--select-text);
}


/* ── Sticky compare basket ───────────────────────────────────────────────── */
.compare-basket {
  width: 240px;
  flex-shrink: 0;
  align-self: flex-start;
  position: sticky;
  top: 64px;            /* sit directly under nav; padding-top creates breathing strip */
  max-height: calc(100vh - 64px);  /* cap at viewport; avoids overlapping sections below when content is short */
  background: transparent;  /* no filled box - keeps visual top aligned with title + search pill */
  border: none;
  border-radius: 8px;
  padding: 16px 14px 14px 14px;  /* 16px top → COMPARE label at y=80, matching pill + title */
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.compare-basket-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: 'Instrument Serif', serif;
  font-weight: 400;
  font-size: var(--fs-xl);
  letter-spacing: 0;
  color: var(--text);
  line-height: 1.15;
}
.compare-basket-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
/* The panel header shows the SAME switch as the rows (2026-09-23, operator):
   off while nothing is selected, on (blue, knob across) once anything is. The
   two-circle glyph it replaced looked switched on at "0 / 5", the opposite of
   the row switches beside it. product-table.js toggles .is-active. */
.compare-basket-icon { flex-shrink: 0; }
.compare-basket-icon.is-active { background: var(--blue); box-shadow: none; }
.compare-basket-icon.is-active .qc-switch-knob { transform: translateX(14px); background: var(--bg); }
.compare-basket-count {
  font-size:var(--fs-2xs);
  font-family: var(--font-mono);
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0;
}
.compare-basket-slots {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.compare-basket-slots::-webkit-scrollbar { width: 3px; }
.compare-basket-slots::-webkit-scrollbar-track { background: transparent; }
.compare-basket-slots::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.compare-basket-slot {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: none;
  border-radius: 8px;
  padding: 7px 8px;
  min-height: 52px;
}
.compare-basket-slot.empty {
  background: rgba(255,255,255,0.03);
  justify-content: center;
  color: var(--muted);
  font-size:var(--fs-2xs);
  letter-spacing: 0.04em;
  opacity: 0.55;
  cursor: default;
}
.compare-basket-slot-logo {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  object-fit: contain;
  background: var(--glass2);
  flex-shrink: 0;
}
.compare-basket-slot-logo-fallback {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size:var(--fs-2xs);
  font-weight: 700;
}
.compare-basket-slot-info {
  flex: 1;
  min-width: 0;
}
.compare-basket-slot-name {
  font-size:var(--fs-2xs);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 600;
}
.compare-basket-slot-sub {
  font-size:var(--fs-2xs);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 2px;
}
.compare-basket-slot-tier {
  font-size:var(--fs-2xs);
  font-family: var(--font-mono);
  text-transform: uppercase;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--glass);
  border: none;
  color: var(--muted2);
  white-space: nowrap;
  margin-top: 3px;
  display: inline-block;
}
.compare-basket-slot-remove {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: var(--fs-2xs);
  padding: 2px;
  line-height: 1;
  flex-shrink: 0;
  transition: color 0.2s;
}
.compare-basket-slot-remove:hover { color: var(--red, #f87171); }
.compare-basket-cta {
  /* the md control (2026-09-18): 40px, full radius */
  width: 100%;
  height: var(--ctl-md);
  padding: 0 var(--ctl-px-md);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: var(--ctl-r);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 700;
  font-size: var(--ctl-fs-md);
  cursor: pointer;
  transition: opacity 0.2s, transform 0.2s;
  letter-spacing: 0.03em;
}
.compare-basket-cta:hover:not(:disabled) { opacity: 0.88; transform: translateY(-1px); }
.compare-basket-cta:disabled { opacity: 0.3; cursor: not-allowed; }

/* Tablet (iPad portrait): the 3-col Rate Browser grid (sidebar | table | compare)
   cramps the table. Keep the filter sidebar NEXT TO the table (2 cols) and drop
   only the compare basket to a full-width row below. Placed AFTER the base
   .tracker-layout (line ~3926) and .compare-basket (line ~4424) definitions so
   source-order cascade wins - a media query does not raise specificity. */
@media (max-width: 900px) {
  .tracker-layout { grid-template-columns: 176px 1fr; }
  .compare-basket {
    grid-column: 1 / -1;
    width: 100%;
    position: static;
    max-height: none;
  }
}

/* Phone: no room for a side filter column — stack everything to one column.
   Filter pills already scroll horizontally at this width. */
@media (max-width: 640px) {
  .tracker-layout { grid-template-columns: 1fr; }
}

/* ── Compare basket mini-card slot (Option B) ──────────────────────────── */
.cb-slot {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--surface);
  border-radius: 8px;
  padding: 8px 9px 9px 9px;
  min-height: 64px;
}
.cb-slot--empty {
  background: rgba(255,255,255,0.03);
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  opacity: 0.55;
  cursor: default;
  min-height: 28px;
  padding: 6px;
  flex-direction: row;
}
.cb-slot-row1 {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.cb-slot-logo {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  object-fit: contain;
  background: var(--glass2);
  flex-shrink: 0;
}
.cb-slot-logo-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-3xs);
  color: var(--muted);
  background: var(--surface2);
}
.cb-slot-bank {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--muted2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}
.cb-slot-rate {
  font-family: 'Syne', sans-serif;
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--text);
  line-height: 1;
  letter-spacing: -0.01em;
  flex-shrink: 0;
}
.cb-slot-pct {
  font-size: var(--fs-3xs);
  color: var(--muted);
  margin-left: 1px;
  font-weight: 600;
}
.cb-slot-rate-empty {
  color: var(--muted);
  font-weight: 500;
}
.cb-slot-remove {
  /* the close square at the slot's scale: 24px, 8px corners, 12px cross */
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  width: 24px; height: 24px; padding: 0; border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
  flex-shrink: 0;
  transition: color 0.2s, background 0.2s;
}
.cb-slot-remove .ico { width: 12px; height: 12px; }
.cb-slot-remove:hover { color: var(--red, #f87171); }
.cb-slot-name {
  font-size: var(--fs-2xs);
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
}
.cb-slot-row3 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-height: 16px;
}
.cb-slot-chips {
  display: flex;
  gap: 3px;
  flex-wrap: wrap;
  min-width: 0;
}
.cb-slot-chip {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--glass);
  color: var(--muted2);
  white-space: nowrap;
  letter-spacing: 0.02em;
}
.cb-slot-metric {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  color: var(--muted);
  white-space: nowrap;
  flex-shrink: 0;
  letter-spacing: 0.01em;
}
.cb-slot-metric--note {
  color: rgba(var(--green-rgb), 0.85);
}

.compare-action-bar {
  padding: 8px 20px;
  border-top: none;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  background: var(--glass);
}
.compare-action-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.compare-action-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--surface2);
  border: none;
  border-radius: var(--ctl-r);
  height: var(--ctl-xs);
  padding: 0 8px 0 4px;
  font-size: var(--ctl-fs-sm);
  color: var(--text);
}
.compare-action-chip img {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  object-fit: contain;
  background: var(--glass2);
}
.compare-action-chip .remove {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: var(--fs-2xs);
  padding: 0 2px;
  line-height: 1;
}
.compare-action-chip .remove:hover { color: var(--red, #f87171); }
/* ── Live status pill — nav-link sizing on top of btn-ghost base ──────────── */
.live-status-pill {
  padding: var(--nav-link-padding);
  font-size: var(--nav-link-font-size);
  border-radius: var(--nav-link-radius);
}

/* ── Circle refresh button — btn-ghost style, circular ─────────────────── */
.btn-circle {
  width: var(--btn-circle-size);
  height: var(--btn-circle-size);
  border-radius: 50%;
  padding: 0;
  background: var(--glass);
  border: none;
  color: var(--muted2);
  font-size: var(--fs-md);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 600;
  box-shadow:
    0 0 6px rgba(96, 165, 250, 0.45),
    0 0 14px rgba(96, 165, 250, 0.22),
    inset 0 0 6px rgba(96, 165, 250, 0.18);
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.btn-circle:hover {
  color: var(--accent);
  background: rgba(var(--accent-rgb),0.06);
  transform: rotate(180deg);
  box-shadow:
    0 0 10px rgba(96, 165, 250, 0.7),
    0 0 22px rgba(96, 165, 250, 0.35),
    inset 0 0 8px rgba(96, 165, 250, 0.28);
}
.btn-circle--sm {
  width: var(--btn-circle-size-sm);
  height: var(--btn-circle-size-sm);
  font-size: var(--fs-xs);
  transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), transform 0.3s ease;
}


/* ── Compare column header + modern checkbox ────────────────────────────── */
.compare-th {
  width: 68px;
  text-align: center;
}
.compare-checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  border: 1.5px solid var(--border);
  border-radius: 5px;
  background: transparent;
  cursor: pointer;
  position: relative;
  transition: border-color 0.15s, background 0.15s;
  vertical-align: middle;
}
.compare-checkbox:hover { border-color: var(--accent); }
.compare-checkbox:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.compare-checkbox:checked::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 5px;
  height: 9px;
  border: 2px solid var(--checkbox-tick);
  border-top: none;
  border-left: none;
  transform: rotate(45deg);
}

/* ─── Compare modal · per-category glass cards ─────────────────────────── */

/* Card row layout — auto-fit so 2-3 cards sit side-by-side, wrap at narrow widths */
.cs-card-row-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 18px;
  margin: 4px 0 12px;
}
.cs-card-row-grid.single {
  /* One category: the card spans the modal like the summary under it
     (2026-09-29; a centred 720px card sat off-axis from a full-width summary). */
  grid-template-columns: minmax(0, 1fr);
}

/* Glass surface — shared with .compare-summary-inner so the summary panel
   and the cards read as the same material. Backdrop-filter creates the
   frosted-glass refraction; the rest is shadow + ring + inset highlight. */
.cs-card.glass,
.compare-summary-inner.glass {
  background: linear-gradient(180deg, rgba(28,28,30,0.62), rgba(20,20,22,0.52));
  -webkit-backdrop-filter: blur(28px) saturate(140%);
  backdrop-filter: blur(28px) saturate(140%);
  border-radius: 14px;
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.05),
    inset 0 1px 0 rgba(255,255,255,0.06),
    0 1px 2px rgba(0,0,0,0.10),
    0 18px 48px rgba(0,0,0,0.32);
  position: relative;
  overflow: hidden;
}
/* Faint diagonal gloss for the lit-from-above feel */
.cs-card.glass::before,
.compare-summary-inner.glass::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(125deg,
    rgba(255,255,255,0.04) 0%, rgba(255,255,255,0) 28%,
    rgba(255,255,255,0) 72%, rgba(255,255,255,0.025) 100%);
  pointer-events: none;
  border-radius: inherit;
}

/* Card: header + columns row + body + note */
.cs-card { padding: 18px 22px 16px; }
.cs-card:nth-child(odd)  { transform: translateY(-1px); }
.cs-card:nth-child(even) { transform: translateY(1px); }

.cs-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255,255,255,0.07);
}
.cs-card-title {
  font-family: 'Instrument Serif', serif;
  font-size: var(--fs-md);
  font-weight: 400;
  color: var(--text);
}
.cs-card-count {
  font-size: var(--fs-3xs);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-weight: 600;
  background: rgba(255,255,255,0.04);
  padding: 3px 8px;
  border-radius: 999px;
}

/* Product column headers (logo + brand + name) */
.cs-card-cols {
  display: grid;
  gap: 10px;
  margin-bottom: 12px;
}
.cs-card-col-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  text-align: center;
  /* A real <button> since 2026-09-18, so the footnote's "click a product name
     for full details" is true. Reset the UA button box; the focus ring comes
     from the one :where() rule. */
  width: 100%;
  background: none;
  border-top: 0; border-left: 0; border-right: 0;
  padding-left: 0; padding-right: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-radius: var(--ctl-r-sq) var(--ctl-r-sq) 0 0;
  transition: background 0.13s;
}
.cs-card-col-head:hover .cs-card-name { text-decoration: underline; }
.cs-card-col-head:hover { background: rgba(127,127,127,0.07); }
.cs-card-logo {
  width: 56px;
  height: 56px;
  border-radius: 10px;
  background: #fff;
  padding: 6px;
  object-fit: contain;
  box-shadow: 0 1px 3px rgba(0,0,0,0.20), 0 0 0 1px rgba(255,255,255,0.10);
  flex-shrink: 0;
}
/* Initials fallback for institutions where the logo URL is missing OR the
   bank's CDN blocks hotlinks (Judo, BNK at time of writing). */
.cs-card-logo--initials {
  background: rgba(255,255,255,0.04);  /* overridden inline with brand colour */
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-md);
  font-weight: 700;
  letter-spacing: -0.02em;
  padding: 0;
}
.cs-card-brand {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text);
}
.cs-card-name {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--muted);
  line-height: 1.3;
  max-width: 180px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Spec body — grid mirroring the column header grid */
.cs-card-body { display: flex; flex-direction: column; }

/* Section headers must clearly read as a different "level" than row labels.
   Different font (Instrument Serif italic - matches site theme), full-strength
   text color, larger size, mixed case, and extra breathing room above so the
   eye knows it's a section break, not another data row. */
.cs-card-section-head {
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-size: var(--fs-base);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--text);
  margin: 18px 0 6px;
  padding-top: 14px;
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
}
.cs-card-section-head::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(255,255,255,0.12) 0%,
    rgba(255,255,255,0.04) 50%,
    rgba(255,255,255,0) 100%);
}
.cs-card-section-head::after {
  content: '';
  flex: 1;
  height: 1px;
  background: rgba(255,255,255,0.05);
  margin-left: 4px;
}
.cs-card-row {
  display: grid;
  grid-template-columns: var(--cs-grid, 132px 1fr 1fr);
  column-gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  font-size: var(--fs-xs);
  line-height: 1.4;
}
.cs-card-row:last-child { border-bottom: none; }
.cs-card-rowlabel {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  font-weight: 600;
  padding-top: 3px;
}
.cs-card-cell {
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.cs-card-note {
  font-size: var(--fs-2xs);
  color: var(--muted);
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid rgba(255,255,255,0.05);
  font-style: italic;
}

/* ─── Light-mode overrides ─── */
[data-theme="light"] .cs-card.glass,
[data-theme="light"] .compare-summary-inner.glass {
  background: linear-gradient(180deg, rgba(255,255,255,0.82), rgba(250,250,252,0.66));
  box-shadow:
    0 0 0 1px rgba(0,0,0,0.06),
    inset 0 1px 0 rgba(255,255,255,0.7),
    0 1px 2px rgba(0,0,0,0.04),
    0 18px 48px rgba(0,0,0,0.10);
}
[data-theme="light"] .cs-card.glass::before,
[data-theme="light"] .compare-summary-inner.glass::before {
  background: linear-gradient(125deg,
    rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 28%,
    rgba(255,255,255,0) 72%, rgba(0,0,0,0.015) 100%);
}
[data-theme="light"] .cs-card-head { border-bottom-color: rgba(0,0,0,0.08); }
[data-theme="light"] .cs-card-count { background: rgba(0,0,0,0.04); }
[data-theme="light"] .cs-card-section-head { color: var(--text); }
[data-theme="light"] .cs-card-section-head::before {
  background: linear-gradient(90deg,
    rgba(0,0,0,0.10) 0%,
    rgba(0,0,0,0.04) 50%,
    rgba(0,0,0,0) 100%);
}
[data-theme="light"] .cs-card-section-head::after {
  background: rgba(0,0,0,0.04);
}
[data-theme="light"] .cs-card-row { border-bottom-color: rgba(0,0,0,0.05); }
[data-theme="light"] .cs-card-note { border-top-color: rgba(0,0,0,0.05); }
[data-theme="light"] .cs-card-logo {
  box-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.06);
}

/* ─── Market Insights page (analytics-insights) ────────────────────────── */
.ai-page { max-width: 1280px; margin: 0 auto; padding: 24px 28px 80px; }
.ai-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 24px; gap: 20px; flex-wrap: wrap;
  position: sticky;
  top: 64px;
  z-index: 30;
  padding: 14px 0 12px;
  background: var(--bg);
  border-bottom: 1px solid rgba(127,127,127,0.10);
}
[data-theme="light"] .ai-head { border-bottom-color: rgba(0,0,0,0.08); }
.ai-section-title { scroll-margin-top: 140px; }

/* Mark certain charts as full-width so they take the whole card-row. */
.ai-card[data-chart="td-curve"],
.ai-card[data-chart="lvr-step"] {
  grid-column: 1 / -1;
}
.ai-card[data-chart="td-curve"] .ai-chart-wrap,
.ai-card[data-chart="lvr-step"] .ai-chart-wrap {
  height: 420px;
}

/* Wide-curve charts pair the canvas with a scrollable HTML legend on the
   right. Grid splits the wrap into [chart] [legend]. */
.ai-chart-wrap.with-legend {
  display: grid;
  grid-template-columns: 1fr 220px;
  gap: 14px;
}
.ai-chart-wrap.with-legend > canvas { width: 100% !important; }
.ai-html-legend {
  display: flex;
  flex-direction: column;
  gap: 1px;
  height: 100%;
  overflow-y: auto;
  padding: 4px 6px 4px 0;
  border-left: 1px solid rgba(127,127,127,0.10);
  padding-left: 12px;
}
.ai-html-legend::-webkit-scrollbar { width: 6px; }
.ai-html-legend::-webkit-scrollbar-thumb { background: rgba(127,127,127,0.25); border-radius: 3px; }
.ai-legend-row {
  display: flex; align-items: center; gap: 8px;
  background: transparent;
  border: none;
  padding: 5px 6px;
  border-radius: 5px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  font-size: var(--fs-2xs);
  color: var(--muted);
  transition: background 0.12s, color 0.12s;
  width: 100%;
}
.ai-legend-row:hover { background: rgba(127,127,127,0.10); color: var(--text); }
.ai-legend-row.on    { color: var(--text); font-weight: 500; }
.ai-legend-row.off   { opacity: 0.6; }
.ai-legend-swatch {
  width: 12px; height: 12px;
  border-radius: 3px;
  flex-shrink: 0;
}
.ai-legend-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ai-title { font-family: 'Instrument Serif', serif; font-size: var(--fs-2xl); font-weight: 400; margin: 0 0 4px; }
.ai-sub { font-size: var(--fs-xs); color: var(--muted); max-width: 720px; }
.ai-meta { font-size: var(--fs-3xs); color: var(--muted); letter-spacing: 0.04em; font-variant-numeric: tabular-nums; }

.ai-controls { display: flex; align-items: center; gap: 18px; }
.ai-filter {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-2xs);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 600;
}
.ai-filter select {
  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  color: var(--text);
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(127,127,127,0.18);
  border-radius: 8px;
  padding: 6px 10px;
  min-width: 200px;
  cursor: pointer;
}
.ai-filter select:focus { outline: 2px solid var(--accent); outline-offset: 2px; }
[data-theme="light"] .ai-filter select {
  background: rgba(0,0,0,0.03);
  border-color: rgba(0,0,0,0.12);
}

.ai-section { margin-bottom: 28px; }
.ai-section-title {
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-size: var(--fs-md); font-weight: 400;
  color: var(--text);
  margin: 6px 0 14px;
  display: flex; align-items: center; gap: 12px;
}
.ai-section-title::after {
  content: '';
  flex: 1;
  height: 1px;
  background: rgba(127,127,127,0.10);
}

.ai-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 18px;
}
.ai-card { padding: 18px 22px 16px; min-height: 180px; }
.ai-card.glass { /* inherits from .glass - same material as compare cards */ }
.ai-card.soon  { opacity: 0.66; }

.ai-card-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 12px; padding-bottom: 8px;
  border-bottom: 1px solid rgba(255,255,255,0.07);
}
.ai-card-title { font-family: 'Instrument Serif', serif; font-size: var(--fs-md); font-weight: 400; color: var(--text); }
.ai-card-tag {
  font-size: var(--fs-3xs); color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.16em; font-weight: 600;
  background: rgba(255,255,255,0.04); padding: 3px 8px; border-radius: 999px;
}

.ai-chart-wrap { height: 320px; position: relative; }
/* Niche heatmap is grid-based and grows with rows; let its wrap auto-size
   instead of clipping at 320px (which made the card foot overlap the grid). */
.ai-card[data-chart="niche"] .ai-chart-wrap { height: auto; min-height: 320px; }

.ai-card-foot {
  font-size: var(--fs-2xs); color: var(--muted);
  margin-top: 12px; padding-top: 8px;
  border-top: 1px solid rgba(255,255,255,0.05);
  font-style: italic;
  line-height: 1.5;
}
.ai-card-foot:empty { display: none; }

.ai-coming-soon {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 280px;
  color: var(--muted); text-align: center; gap: 6px;
  font-size: var(--fs-sm);
}
.ai-coming-icon { font-size: var(--fs-xl); color: rgba(127,127,127,0.5); }
.ai-coming-sub { font-size: var(--fs-2xs); opacity: 0.7; max-width: 280px; }

.ai-empty {
  height: 280px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); font-size: var(--fs-sm); font-style: italic;
}

/* Niche eligibility heatmap (chart #7) */
.ai-niche-grid {
  display: grid;
  gap: 4px;
  margin: 6px 0;
  font-size: var(--fs-2xs);
}
.ai-niche-grid .h {
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  font-weight: 600;
  padding: 6px 4px;
  text-align: center;
}
.ai-niche-grid .h.row {
  text-align: left;
  padding-left: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.ai-niche-grid .h.row .cnt {
  font-weight: 700;
  color: var(--text);
  font-size: var(--fs-2xs);
  letter-spacing: 0;
  text-transform: none;
}
.ai-niche-grid .cell {
  padding: 8px 4px;
  text-align: center;
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--text);
}
.ai-niche-grid .cell.zero      { background: rgba(127,127,127,0.05); color: var(--muted); }
.ai-niche-grid .cell.low       { background: rgba(74,144,255,0.15); }
.ai-niche-grid .cell.med       { background: rgba(74,144,255,0.35); }
.ai-niche-grid .cell.high      { background: rgba(74,144,255,0.55); }
.ai-niche-grid .cell.very-high { background: rgba(74,144,255,0.78); color: #fff; }

/* Light-mode overrides */
[data-theme="light"] .ai-section-title::after { background: rgba(0,0,0,0.10); }
[data-theme="light"] .ai-card-head { border-bottom-color: rgba(0,0,0,0.08); }
[data-theme="light"] .ai-card-foot { border-top-color: rgba(0,0,0,0.06); }
[data-theme="light"] .ai-card-tag { background: rgba(0,0,0,0.04); }

/* Compare modal */
.compare-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}
.compare-table th {
  text-align: center;
  padding: 12px 8px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  vertical-align: bottom;
}
.compare-table th:first-child {
  text-align: left;
  width: 140px;
}
.compare-table td {
  padding: 10px 8px;
  text-align: center;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.compare-table td:first-child {
  text-align: left;
  font-weight: 600;
  color: var(--muted2);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.compare-table tr:last-child td {
  border-bottom: none;
}
.compare-rate-best {
  color: var(--green);
  font-weight: 700;
}
.compare-col-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  min-height: 132px;
}
.compare-col-logo {
  width: 72px;
  height: 72px;
  border-radius: 10px;
  object-fit: contain;
  background: #fff;
  flex-shrink: 0;
  padding: 6px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.06);
}
/* ─── Compare summary panel (Box 1: hairline, dot bullets, em-dash prose) ─── */
.compare-summary { margin: 0 0 18px; }
.compare-summary:empty { display: none; }

.compare-summary-inner {
  background: var(--surface);
  border-radius: 12px;
  padding: 10px 16px 12px;
  box-shadow:
    0 0 0 1px rgba(127, 127, 127, 0.08),
    0 1px 2px rgba(0, 0, 0, 0.10),
    0 10px 28px rgba(0, 0, 0, 0.22);
}

.compare-summary-skel {
  font-size: var(--fs-2xs);
  color: var(--muted);
  font-style: italic;
  padding: 10px 16px;
}

/* Header bar: title left, data-as-of right */
.cs-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: 6px;
  margin-bottom: 4px;
  border-bottom: 1px solid rgba(127, 127, 127, 0.08);
}
.cs-head-title {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-3xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted2);
}
.cs-head-meta {
  font-size: var(--fs-3xs);
  color: var(--muted);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

/* Bullet list with custom dot marker — compressed line-height & no dividers */
.cs-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.cs-list > li {
  position: relative;
  padding: 2px 0 2px 14px;
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--text);
}
.cs-list > li + li { margin-top: 2px; }
.cs-list > li::before {
  content: '';
  position: absolute;
  left: 3px;
  top: 9px;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(127, 127, 127, 0.55);
}
.cs-list strong {
  font-weight: 700;
  color: var(--text);
}

/* Section header for multi-category baskets */
.cs-section-head {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-3xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted2);
  margin: 8px 0 3px;
  padding-top: 5px;
  border-top: 1px solid rgba(127, 127, 127, 0.08);
}
.cs-section-head:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.compare-col-name {
  font-size: var(--fs-2xs);
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.3;
  max-width: 200px;
  margin: 0 auto;
  white-space: normal;
  word-break: break-word;
  overflow: hidden;
}
.compare-cashback-note {
  display: block;
  font-size: var(--fs-3xs);
  color: var(--muted);
  font-weight: 500;
  margin-top: 3px;
  line-height: 1.3;
}
.compare-toggle {
  display: inline-flex;
  gap: 0;
  border: none;
  background: var(--surface2);
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 16px;
}
.compare-toggle-btn {
  background: none;
  border: none;
  padding: 6px 14px;
  font-size: var(--fs-2xs);
  color: var(--muted2);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.compare-toggle-btn.active {
  background: var(--surface2);
  color: var(--text);
  font-weight: 600;
}
.compare-note {
  font-size:var(--fs-2xs);
  color: var(--muted);
  padding: 6px 0;
}

/* ── Calculator ─────────────────────────────────────────────────────────── */
.calc-layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 24px;
  align-items: start;
}
.calc-inputs {
  background: var(--surface);
  border: none;
  border-radius: 14px;
  padding: 22px 20px;
  position: sticky;
  top: 80px;
}
.calc-results { display: flex; flex-direction: column; gap: 16px; }
.calc-input-group { margin-bottom: 20px; }
.calc-input-group:last-child { margin-bottom: 0; }
.calc-label {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: 5px;
}
.calc-value-display {
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--text);
  margin-bottom: 6px;
  min-height: 1.2em;
}
.calc-range { width: 100%; accent-color: var(--blue); cursor: pointer; }
.calc-num-row {
  display: flex;
  align-items: baseline;
  gap: 3px;
  margin-bottom: 8px;
}
.calc-num-prefix, .calc-num-suffix {
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--muted2);
}
.calc-num-input {
  font-weight: 700;
  font-size: var(--fs-base);
  color: var(--text);
  background: transparent;
  border: none;
  border-bottom: 1.5px solid var(--border2);
  padding: 1px 4px 2px;
  width: 120px;
  -moz-appearance: textfield;
}
.calc-num-input::-webkit-outer-spin-button,
.calc-num-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.calc-num-input:focus { border-bottom-color: var(--blue); color: var(--text); }
.calc-num-hint {
  font-size: var(--fs-2xs);
  color: var(--muted);
  margin-left: 6px;
}
.calc-result-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.calc-result-card {
  background: var(--surface);
  border: none;
  border-radius: 12px;
  padding: 14px 16px;
  box-shadow: var(--elev-1);
}
.calc-result-card.primary {
  background: rgba(var(--blue-rgb), 0.06);
}
.calc-result-label {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  margin-bottom: 4px;
}
.calc-result-value {
  font-family: 'Syne', sans-serif;
  font-weight: 800;
  font-size: var(--fs-xl);
  color: var(--text);
  line-height: 1.1;
}
.calc-result-card.primary .calc-result-value { color: var(--blue); }
.calc-cdr-panel {
  background: var(--surface);
  border: none;
  border-radius: 12px;
  padding: 14px 16px;
}
.calc-cdr-panel.calc-cdr-good {
  background: rgba(var(--green-rgb), 0.06);
}
.calc-cdr-saving {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  background: rgba(var(--blue-rgb), 0.06);
  border: none;
  border-radius: 8px;
}
.calc-panel {
  background: var(--surface);
  border: none;
  border-radius: 12px;
  padding: 16px 20px;
}
.calc-panel-title {
  font-size:var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted2);
  margin-bottom: 12px;
}
.calc-legend-item { font-size:var(--fs-2xs); display: flex; align-items: center; gap: 4px; }
.calc-term-group, .calc-type-group { display: flex; gap: 6px; margin-top: 4px; }
.calc-term-btn, .calc-type-btn { font-family: inherit; cursor: pointer; transition: all 0.12s; white-space: nowrap; }  /* size and shape: the .seg track */
.calc-term-btn.active, .calc-type-btn.active {
  background: var(--select-bg);
  color: var(--select-text);
  font-weight: 600;
}
@media (max-width: 480px) {
  .calc-result-grid { grid-template-columns: 1fr; }
}

/* ── CDR Data Quality / Compliance Scores ──────────────────────────────── */

.score-a { color: var(--green); }
.score-b { color: var(--green); }
.score-c { color: var(--amber); }
.score-f { color: var(--red); }

.dim-bar-track {
  height: 3px;
  background: var(--glass-border);
  border-radius: 2px;
  margin: 2px 0 6px;
  overflow: hidden;
}

.dim-bar-fill {
  height: 3px;
  border-radius: 2px;
  transition: width 0.4s ease;
}

.grade-badge {
  font-family: 'Syne', sans-serif;
  font-weight: 700;
  font-size: var(--fs-2xl);
  line-height: 1;
}

.compliance-issues {
  list-style: none;
  padding: 0;
  margin: 8px 0;
}

.compliance-issues li {
  font-size: var(--fs-xs);
  color: var(--muted);
  padding: 4px 0 4px 16px;
  position: relative;
}

.compliance-issues li::before {
  content: '⚠';
  color: var(--red);
  position: absolute;
  left: 0;
  font-size:var(--fs-2xs);
}

.compliance-disclaimer {
  font-size:var(--fs-2xs);
  color: var(--muted);
  font-style: italic;
  padding-top: 8px;
  margin-top: 12px;
}

/* Dimension collapsible section */
.compliance-dim-section {
  margin-bottom: 16px;
  border-radius: 6px;
  overflow: hidden;
}
.compliance-dim-section > summary { list-style: none; }
.compliance-dim-section > summary::-webkit-details-marker { display: none; }
.compliance-dim-section > summary::marker { display: none; }

.compliance-dim-summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 12px;
  cursor: pointer;
  user-select: none;
  background: var(--glass);
}
.compliance-dim-summary:hover { background: var(--glass-border); }

.compliance-dim-body {
  padding: 10px 12px 12px;
}

.compliance-dim-subtitle {
  font-size:var(--fs-2xs);
  color: var(--muted);
  font-style: italic;
  margin: 0 0 8px;
  line-height: 1.4;
}

/* Issue items — collapsible with <details> */
.compliance-issue-item {
}
.compliance-issue-item > summary { list-style: none; }
.compliance-issue-item > summary::-webkit-details-marker { display: none; }
.compliance-issue-item > summary::marker { display: none; }

.compliance-issue-summary {
  display: block;
  font-size: var(--fs-2xs);
  color: var(--text);
  font-weight: 500;
  padding: 7px 0;
  cursor: pointer;
  user-select: none;
}
.compliance-issue-summary:hover { color: var(--amber); }

.compliance-issue-detail {
  font-size:var(--fs-2xs);
  color: var(--muted);
  line-height: 1.55;
  padding: 0 0 8px;
}

/* Failing product chips */
.failing-product-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 2px 0 6px;
}

.failing-chip {
  font-size:var(--fs-2xs);
  padding: 2px 7px;
  border-radius: 3px;
  background: rgba(239,68,68,0.10);
  border: none;
  color: var(--red);
  cursor: default;
  white-space: nowrap;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--font-mono);
}

/* ── Reports page ───────────────────────────────────────────────── */
.reports-sticky-header {
  position: sticky;
  top: 64px;
  z-index: 50;
  background: var(--nav-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: none;
  box-shadow: 0 4px 20px rgba(0,0,0,0.2);
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 32px;
  gap: 12px;
  flex-wrap: wrap;
}

.reports-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(480px, 1fr));
  gap: 20px;
  margin-bottom: 8px;
}

.report-card {
  background: var(--surface);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--elev-1);
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}
.report-card:hover {
  box-shadow: var(--elev-2);
}

.report-card--wide { grid-column: 1 / -1; }

.report-card-header {
  padding: 16px 18px 12px;
}

.report-card-title {
  font-size: var(--fs-xs);
  font-weight: 600;
  margin-bottom: 3px;
}

.report-card-sub {
  font-size:var(--fs-2xs);
  color: var(--muted);
}

.report-chart-wrap {
  padding: 16px 18px 0;
  /* height and overflow set dynamically by JS based on data count */
  max-height: 420px;
  overflow: auto;
  /* smooth scrolling inside chart area */
  scroll-behavior: smooth;
  /* thin scrollbar */
  scrollbar-width: thin;
  scrollbar-color: #333 transparent;
}
.report-chart-wrap::-webkit-scrollbar { width: 4px; height: 4px; }
.report-chart-wrap::-webkit-scrollbar-track { background: transparent; }
.report-chart-wrap::-webkit-scrollbar-thumb { background: #333; border-radius: 4px; }

/* ── Chart-R7 filter sidebar ─────────────────────────────────────────────── */
.r7-body {
  display: flex;
  gap: 0;
  align-items: flex-start;
}
.r7-filters {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px 0 0 18px;
  min-width: 108px;
  flex-shrink: 0;
}
.r7-filter-group-label {
  font-size:var(--fs-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted2);
  margin-bottom: 5px;
}
.r7-filter-pills {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.r7-pill {
  display: block;
  width: 100%;
  padding: 3px 8px;
  font-size:var(--fs-2xs);
  font-weight: 500;
  background: transparent;
  border: none;
  border-radius: 4px;
  color: var(--muted2);
  cursor: pointer;
  text-align: left;
  transition: background 0.12s, color 0.12s;
  white-space: nowrap;
}
.r7-pill:hover {
  background: rgba(255,255,255,0.05);
  color: var(--text);
}
.r7-pill.active {
  background: rgba(var(--accent-rgb), 0.12);
  color: var(--text);
  font-weight: 600;
}

.report-table-wrap {
  overflow-x: auto;
  max-height: 220px;
  overflow-y: auto;
}

.report-table {
  width: 100%;
  border-collapse: collapse;
  font-size:var(--fs-2xs);
}

.report-table th {
  padding: 7px 12px;
  text-align: left;
  color: var(--muted);
  font-weight: 500;
  position: sticky;
  top: 0;
  background: var(--bg);
  white-space: nowrap;
}

.report-table td {
  padding: 6px 12px;
}
.report-table tr:hover td { background: rgba(255,255,255,0.02); }

.report-empty {
  padding: 32px;
  text-align: center;
  color: var(--muted);
  font-size: var(--fs-2xs);
}

@media (max-width: 900px) {
  .reports-grid { grid-template-columns: 1fr; }
  .reports-sticky-header { padding: 10px 16px; }
}

/* ── APRA analytics — chart pills & overlay (always-dark chart section) ─── */
/* ── APRA Lens Bar ────────────────────────────── */
.apra-lens-bar {
  padding: 8px 0;
  margin-bottom: 16px;
}
.apra-lens-l1 {
  display: flex;
  gap: 4px;
  margin-bottom: 6px;
}
.apra-lens-l2 {
  display: flex;
  gap: 3px;
  flex-wrap: wrap;
}
.apra-lens-pill {
  font-size: var(--fs-2xs);
  padding: 4px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
  background: transparent;
  color: #64748b;
  transition: background 0.15s, color 0.15s;
}
.apra-lens-pill:hover { background: rgba(255,255,255,0.06); }
.apra-lens-pill.active {
  background: rgba(59,130,246,0.18);
  color: #60a5fa;
  font-weight: 600;
}
.apra-lens-l1 .apra-lens-pill {
  font-size: var(--fs-xs);
  padding: 5px 16px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ── APRA Context Bar ─────────────────────────── */
.apra-context-bar {
  font-size: var(--fs-2xs);
  color: var(--muted);
  padding: 8px 0;
  margin-bottom: 12px;
  letter-spacing: 0.02em;
}

.apra-chart-cat-tab {
  color: #475569;
  background: transparent;
  border-bottom: 2px solid transparent;
}
.apra-chart-cat-tab.active {
  color: #60a5fa;
  background: rgba(59,130,246,0.15);
  border-bottom-color: #3b82f6;
}
.apra-chart-group-label { color: #334155; }
.apra-share-inst-input {
  background: var(--subtle);
  border-bottom: 1px solid var(--subtle-border);
  color: var(--text);
}
.apra-share-inst-input::placeholder { color: var(--muted); opacity: 1; }
.apra-share-inst-dropdown {
  background: var(--glass);
  border: 1px solid var(--glass-border);
}

/* ── Repayment Calculator inputs strip ──────────────────────────────────────
   Single seamless pill with a vertical divider between fields. No nested
   chips - keeps the strip cohesive instead of looking like "two pills in a
   frame". Hugs content width via inline-flex + width: fit-content. */
.tracker-search-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 12px;
}
.tracker-search-row .gsearch {
  max-width: none;
  margin: 0;
}
.calc-strip-context {
  display: inline-flex;
  align-items: center;
  padding: 0 14px 0 18px;
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-2xs);
  font-weight: 700;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}
.calc-inputs-strip {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  margin-bottom: 12px;
  background: var(--surface);
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--border);
  width: fit-content;
  max-width: 100%;
  overflow: hidden;
  transition: box-shadow 0.18s ease;
}
.calc-inputs-strip:focus-within {
  box-shadow: inset 0 0 0 1px var(--border2),
              0 0 0 3px rgba(var(--green-rgb), 0.18);
}
.calc-field {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 18px;
  font-size: var(--fs-sm);
  color: var(--text);
  cursor: text;
  white-space: nowrap;
}
.calc-field-label {
  color: var(--muted);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  margin-right: 2px;
}
.calc-field-prefix, .calc-field-suffix {
  color: var(--muted);
  font-size: var(--fs-sm);
  font-weight: 500;
}
.calc-field-divider {
  width: 1px;
  align-self: stretch;
  background: var(--border);
  margin: 6px 0;
  flex: 0 0 1px;
}
.calc-input {
  background: transparent;
  color: var(--text);
  border: none;
  padding: 0;
  font-size: var(--fs-base);
  font-weight: 700;
  width: 80px;
  font-variant-numeric: tabular-nums;
  text-align: left;
  -moz-appearance: textfield;
  font-family: inherit;
}
.calc-input::-webkit-outer-spin-button,
.calc-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.calc-input--short { width: 32px; text-align: center; }

/* Calc-mode column widths no longer needed — card rows bypass the column grid */

/* Small utility classes used by non-card (table) calc rendering fallback */
.calc-cell-monthly { font-weight: 600; color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.calc-cell-fees { font-size: var(--fs-2xs); color: var(--muted); line-height: 1.35; white-space: nowrap; font-variant-numeric: tabular-nums; }
.calc-cell-fees strong { color: var(--text); font-weight: 600; }

/* ═══════════════════════════════════════════════════════════════════════════════
   UNIVERSAL QUOTE CARDS - every row in the Live Product Tracker renders as a card.
   3 zones: LOGO · INFO (bank + product + metadata + chips) · HERO (rate or repayment).
   Works in dark + light via CSS variables.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* Kill the table grid entirely — cards provide their own structure */
#product-table > thead,
#product-table > colgroup { display: none; }
/* The Product Browser table was `border-collapse: collapse`, so its cards
   butted straight up against each other while the Explorer's had a 10px
   gap between them. Same rhythm on both lists (2026-09-09). */
#product-table {
  border-spacing: 0 10px;
  border-collapse: separate;
  width: 100%;
}

tr.quote-card { cursor: pointer; }
.quote-card-cell {
  padding: 0 !important;
  border: none !important;
  background: transparent;
}
.quote-card-cell > .qc-grid {
  position: relative;
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) minmax(180px, auto);
  grid-template-areas: "logo info hero";
  gap: 18px;
  align-items: center;
  padding: 10px 18px;
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--elev-1), inset 0 0 0 1px var(--border);
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}
tr.quote-card:hover .quote-card-cell > .qc-grid {
  box-shadow: var(--elev-hover), inset 0 0 0 1px var(--border2);
  transform: translateY(-1px);
}

/* ── Zone 1: LOGO (prominent, its own column) ──────────────────────────── */
.qc-logo {
  grid-area: logo;
  width: 72px;
  height: 72px;
  border-radius: 14px;
  overflow: hidden;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.qc-logo .bank-logo-img,
.qc-logo .bank-logo {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 14px;
}
.qc-logo .bank-logo {
  font-size: var(--fs-xl);
  font-weight: 700;
}

/* ── Zone 2: INFO (bank name, product, metadata, chips) ────────────────── */
.qc-info {
  grid-area: info;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.qc-bank-name {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-weight: 600;
  font-size: var(--fs-xs);
  color: var(--muted2);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.qc-product-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  min-width: 0;
}
.qc-product-name {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  line-height: 1.25;
  letter-spacing: -0.005em;
}
.qc-rate-type {
  font-size: var(--fs-sm);
  color: var(--muted2);
  font-weight: 500;
}
.qc-cat-pill {
  font-size: var(--fs-3xs);
  padding: 2px 8px;
  border-radius: 10px;
  letter-spacing: 0.06em;
  line-height: 1.5;
  flex-shrink: 0;
}
.qc-tier-line {
  font-size: var(--fs-2xs);
  color: var(--muted2);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  margin-top: 2px;
}
.qc-pricing {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  align-items: center;
  margin-top: 4px;
}
.qc-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 8px;
  background: var(--surface2);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.qc-chip em {
  font-style: normal;
  color: var(--muted);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 500;
}
.qc-chip strong { color: var(--text); font-weight: 600; }
.qc-chip--muted strong { color: var(--muted); font-weight: 500; font-style: italic; }
/* Label-less note chip (positive single-fact pill: "No annual fee", "No monthly fee"). */
.qc-chip--note strong {
  color: rgba(var(--green-rgb), 0.95);
  font-weight: 600;
  font-size: var(--fs-2xs);
}

/* ── Zone 3: HERO (rate or repayment) ──────────────────────────────────── */
.qc-hero {
  grid-area: hero;
  text-align: right;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  min-width: 0;
  padding-right: 46px;
}
/* Compare switch (2026-09-23, operator): an on/off switch, not an icon. Off is a
   grey track with a light knob on the left; on is the brand blue with a dark
   knob on the right (a light one in the light theme). The two overlapping
   circles it replaced changed only their shading when selected, so a selected
   row looked like an unselected one. */
.qc-switch {
  position: relative;
  display: block;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 18%, var(--surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 10%, transparent);
  transition: background 0.18s ease, box-shadow 0.18s ease;
}
.qc-switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #f5f5f5;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  transition: transform 0.18s ease, background 0.18s ease;
}
.qc-compare-wrap:hover .qc-switch { background: color-mix(in srgb, var(--text) 26%, var(--surface)); }
.qc-compare-wrap:has(input:checked) .qc-switch { background: var(--blue); box-shadow: none; }
.qc-compare-wrap:has(input:checked) .qc-switch-knob { transform: translateX(14px); background: var(--bg); }
.qc-compare-wrap:has(input:focus-visible) .qc-switch { outline: 2px solid var(--blue); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .qc-switch, .qc-switch-knob { transition: none; }
}
.qc-hero-label {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.qc-hero-badge {
  display: inline-block;
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(var(--green-rgb), 0.95);
  background: rgba(var(--green-rgb), 0.12);
  padding: 1px 6px;
  border-radius: 4px;
  line-height: 1.4;
}
/* Clickable disclosure variant — replaces the static `est.` badge with a pill
   that opens the repayment-info popover. */
.qc-hero-info {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(var(--green-rgb), 0.95);
  background: rgba(var(--green-rgb), 0.12);
  padding: 1px 6px;
  border-radius: 4px;
  line-height: 1.4;
  border: none;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, transform 0.15s;
}
.qc-hero-info:hover {
  background: rgba(var(--green-rgb), 0.22);
  color: rgba(var(--green-rgb), 1);
}
.qc-hero-info-icon {
  font-size: var(--fs-3xs);
  line-height: 1;
  font-weight: 400;
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: italic;
}
.qc-hero-value {
  font-family: 'Syne', sans-serif;
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.qc-hero-unit {
  font-size: var(--fs-2xs);
  color: var(--muted2);
  margin-bottom: 6px;
}
/* Dual hero (rate + comp stacked over repayment). Sized so the overall .qc-hero
   vertical envelope matches the single-hero layout - right rail height unchanged. */
.qc-hero-row {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  justify-content: flex-end;
}
.qc-hero-row--sub { margin-top: 1px; }
.qc-hero-dual-value {
  font-family: 'Syne', sans-serif;
  font-weight: 700;
  font-size: var(--fs-lg);
  letter-spacing: -0.015em;
  color: var(--text);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.qc-hero-dual-value--sub {
  font-size: var(--fs-base);
  color: var(--muted);
  font-weight: 600;
}
.qc-hero-dual-label {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  font-weight: 600;
  min-width: 34px;
  text-align: left;
}
.qc-hero-divider {
  width: 64%;
  height: 1px;
  background: var(--border);
  margin: 2px 0;
  align-self: flex-end;
}
.qc-hero-badge-row { margin-top: 2px; }

.qc-compare-wrap {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 4px;
  background: transparent;
  transition: transform 0.15s ease;
}
.qc-compare-wrap input { position: absolute; opacity: 0; pointer-events: none; }
.qc-compare-wrap input { margin: 0; }

/* ── Responsive: stack zones below 900px ───────────────────────────────── */
@media (max-width: 900px) {
  .quote-card-cell > .qc-grid {
    grid-template-columns: 60px 1fr;
    grid-template-areas:
      "logo info"
      "hero hero";
    gap: 12px;
    padding: 14px;
  }
  .qc-logo { width: 60px; height: 60px; border-radius: 12px; }
  .qc-hero {
    text-align: left;
    align-items: flex-start;
    border-top: 1px solid var(--border);
    padding-top: 10px;
    margin-top: 4px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════════
   AI CHAT - floating launcher (FAB) + dock panel.
   Lives at body level so it's available on every page (dashboard, products,
   analytics, etc.). Always starts collapsed; user toggles via FAB or hero CTA.
   ═════════════════════════════════════════════════════════════════════════════ */

.ai-fab {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 56px;
  height: 56px;
  border: 1.5px solid rgba(96, 165, 250, 0.85);
  border-radius: 50%;
  cursor: pointer;
  z-index: 90;
  /* Stays transparent (the glowing-ring look), but FROSTS whatever surface it
     floats over - over the dark page it's invisible, over the footer/content
     panels it blurs the backdrop instead of letting text bleed through the orb,
     so the glyph keeps its clarity on any surface. Degrades to plain
     transparent on browsers without backdrop-filter. */
  background: transparent;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #1e293b;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.18s ease;
}
.ai-fab:hover { transform: translateY(-2px); }
.ai-fab:active { transform: translateY(0); }
.ai-fab {
  box-shadow:
    0 0 8px rgba(96, 165, 250, 0.6),
    0 0 18px rgba(96, 165, 250, 0.35),
    inset 0 0 8px rgba(96, 165, 250, 0.25);
}
.ai-fab svg .dots circle {
  transform-box: fill-box;
  transform-origin: center;
  animation: fab-dot-typing 2.4s ease-in-out infinite;
}
.ai-fab svg .dots .d1 { animation-delay: 0s; }
.ai-fab svg .dots .d2 { animation-delay: 0.35s; }
.ai-fab svg .dots .d3 { animation-delay: 0.7s; }
@keyframes fab-dot-typing {
  0%, 50%, 100% { transform: scale(1);    opacity: 0.5; }
  20%           { transform: scale(1.3);  opacity: 1; }
}
.ai-fab-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 0;
}
/* Unread-pulse: appears when a bot reply lands while the dock is closed. */
.ai-fab-pulse {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 2px var(--bg);
}
.ai-fab-pulse::before {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: var(--red);
  opacity: 0.4;
  animation: ai-fab-ping 1.6s ease-out infinite;
}
@keyframes ai-fab-ping {
  0%   { transform: scale(0.6); opacity: 0.5; }
  100% { transform: scale(2.2); opacity: 0; }
}
/* When the dock is open, hide the FAB (the dock has its own close button). */
body.ai-dock-open .ai-fab { transform: scale(0.85); opacity: 0; pointer-events: none; }

.ai-dock {
  --dock-bg: rgba(8, 10, 14, 0.78);
  --dock-shadow: 0 24px 64px rgba(0, 0, 0, 0.55), 0 4px 12px rgba(0, 0, 0, 0.35);
  --dock-input-bg: rgba(255, 255, 255, 0.04);
  --dock-input-bg-focus: rgba(255, 255, 255, 0.07);
  --dock-chip-bg: rgba(255, 255, 255, 0.05);
  --dock-chip-bg-hover: rgba(255, 255, 255, 0.1);
  --dock-close-hover: rgba(255, 255, 255, 0.06);
}
[data-theme="light"] .ai-dock {
  --dock-bg: rgba(255, 255, 255, 0.78);
  --dock-shadow: 0 12px 40px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);
  --dock-input-bg: rgba(0, 0, 0, 0.04);
  --dock-input-bg-focus: rgba(0, 0, 0, 0.07);
  --dock-chip-bg: rgba(0, 0, 0, 0.05);
  --dock-chip-bg-hover: rgba(0, 0, 0, 0.09);
  --dock-close-hover: rgba(0, 0, 0, 0.06);
}

.ai-dock {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 520px;
  height: 620px;
  max-width: calc(100vw - 48px);
  max-height: calc(100vh - 48px);
  z-index: 95;
  background: var(--dock-bg);
  backdrop-filter: blur(22px) saturate(1.4);
  -webkit-backdrop-filter: blur(22px) saturate(1.4);
  border: none;
  border-radius: 16px;
  box-shadow: var(--dock-shadow);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform-origin: bottom right;
  animation: ai-dock-pop 0.22s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
@keyframes ai-dock-pop {
  from { transform: scale(0.85) translateY(12px); opacity: 0; }
  to   { transform: scale(1)    translateY(0);    opacity: 1; }
}
.ai-dock[hidden] { display: none; }
.ai-dock-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px 10px;
  background: transparent;
  border: none;
  flex-shrink: 0;
}
.ai-dock-header h3 {
  margin: 0;
  flex: 1;
  min-width: 0;
  font-family: 'Instrument Serif', serif;
  font-size: var(--fs-lg);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text);
  line-height: 1.1;
}
.ai-dock-status { font-size: var(--fs-3xs); padding: 2px 8px; }
.ai-dock-close {
  /* the same 32px square as .modal-close (2026-09-18): one close button */
  background: var(--glass2);
  border: none;
  color: var(--muted2);
  cursor: pointer;
  width: 32px;
  height: 32px;
  padding: 0;
  flex-shrink: 0;
  border-radius: var(--ctl-r-sq);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s ease, color 0.15s ease;
}
.ai-dock-close .ico { width: var(--ctl-icon-md); height: var(--ctl-icon-md); }
.ai-dock-close:hover { background: var(--dock-close-hover); color: var(--text); }
.ai-dock-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.ai-dock .ai-suggestions {
  flex-shrink: 0;
  padding: 0 16px 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.ai-dock .ai-avatar.bot { display: none; }
.ai-dock .ai-chip {
  font-size: var(--ctl-fs-sm);
  height: var(--ctl-sm);
  padding: 0 12px;
  border-radius: var(--ctl-r);
  background: var(--dock-chip-bg);
  border: none;
  cursor: pointer;
  color: var(--muted);
  transition: background 0.15s ease, color 0.15s ease;
}
.ai-dock .ai-chip:hover { background: var(--dock-chip-bg-hover); color: var(--text); }
.ai-dock-input-row {
  flex-shrink: 0;
  padding: 10px 14px 14px;
  background: transparent;
  border: none;
  display: flex;
  gap: 8px;
  align-items: flex-end;
}
.ai-dock-input-row .ai-input {
  flex: 1;
  min-width: 0;
  background: var(--dock-input-bg);
  border: none;
  border-radius: 10px;
  padding: 11px 14px;
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: 1.4;
  min-height: 44px;
  resize: none;
  box-shadow: none;
  transition: background 0.18s ease;
}
.ai-dock-input-row .ai-input::placeholder { color: var(--muted2); }
.ai-dock-input-row .ai-input:focus { background: var(--dock-input-bg-focus); box-shadow: none; }
.ai-dock-input-row .ai-send {
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: 10px;
  padding: 0 14px;
  font-size: var(--fs-xs);
  cursor: pointer;
  font-weight: 600;
}

/* Mobile: dock takes full viewport so the keyboard doesn't fight a tiny panel. */
@media (max-width: 600px) {
  .ai-dock {
    inset: 0;
    width: 100%;
    height: 100%;
    max-height: 100%;
    border-radius: 0;
  }
  .ai-fab { right: 16px; bottom: 16px; }
}

/* ── Research Assistant full-screen mode (2026-07-11, de-persona'd 07-12) ──
   ChatGPT-style takeover: centered ~760px conversation column, sticky bottom
   composer, typographic empty state. Scoped to .ai-dock--full ONLY - the
   APRA chat panel reuses the base .ai-dock classes and must keep its compact
   bottom-right footprint. */
.ai-dock--full {
  /* Capped, centered modal (2026-07-12): a dialog over the page, not a
     near-fullscreen takeover - the dimmed rim around it signals "this is
     an overlay you can click out of". */
  inset: 0;
  margin: auto;
  width: min(1060px, calc(100vw - 48px));
  height: min(760px, calc(100vh - 48px));
  max-width: none;
  max-height: none;
  border-radius: 18px;
  border: 1px solid var(--border2);
  transform-origin: center;
  /* Above the site nav (z-index 100) — the overlay owns the whole viewport;
     below modal overlays (1100) so sign-in still stacks on top. */
  z-index: 1000;
}
/* Dimmed backdrop behind the inset panel — also the click-out hit area
   (ui.js closes on clicks that land on <body>, which only the fixed
   pseudo-element produces while the overlay is open). */
body.ai-dock-open::after {
  content: '';
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 999;
}
.ai-dock--full .ai-dock-header {
  padding: 14px 24px;
}
/* Conversation column: constrain each message to the centered column.
   (max-width + margin:auto rather than max(…, calc(…)) padding - the calc
   form silently failed to apply in Safari, leaving bubbles pinned to the
   panel edges.) 760px, NOT the row's 792px: the input row carries 16px side
   padding, so the visible pill is 760 wide - bubbles must align with the
   PILL edges or the user bubble overhangs it 16px (2026-07-13). */
.ai-dock--full .ai-dock-body {
  padding: 24px 16px;
  gap: 16px;
}
.ai-dock--full .ai-dock-body > .ai-msg {
  width: 100%;
  max-width: 760px;
  margin-left: auto;
  margin-right: auto;
}
/* Empty state (2026-07-12): centered typographic block, not a chat bubble.
   NB: named ai-dock-empty - .ai-empty is already taken by the insights
   empty-chart placeholder (flex/italic) and collides. */
.ai-dock--full .ai-dock-body:has(> .ai-dock-empty) {
  justify-content: center;
}
.ai-dock-empty {
  text-align: center;
  max-width: 560px;
  margin: 0 auto;
  padding: 24px 8px;
}
.ai-dock-empty-title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-weight: 400;
  /* the opening line of an empty chat is the only thing on the panel; at
     --fs-xl it read as a caption rather than an invitation (2026-09-08) */
  font-size: var(--fs-2xl);
  line-height: 1.15;
  color: var(--text);
  margin-bottom: 10px;
}
.ai-dock-empty-sub {
  color: var(--muted);
  font-size: var(--fs-base);
  line-height: 1.6;
}
/* Header: site mark + quiet label; "New chat" appears mid-conversation only */
.ai-dock-mark { display: flex; align-items: center; }
/* Full mode: title hugs its text so the provenance note sits beside it;
   the note then pushes the buttons to the right edge. */
.ai-dock--full .ai-dock-header h3 { flex: 0 0 auto; }
.ai-powered-by {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-right: auto;
  padding-left: 12px;
  border-left: 1px solid var(--border2);
  color: var(--muted);
  font-size: var(--fs-2xs);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.ai-powered-by svg { flex-shrink: 0; }
.ai-new-chat {
  background: none;
  border: 1px solid var(--border2);
  border-radius: 999px;
  color: var(--muted);
  font-size: var(--ctl-fs-sm);
  height: var(--ctl-sm);
  padding: 0 12px;
  display: inline-flex; align-items: center;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.ai-new-chat:hover { color: var(--text); border-color: var(--muted2); }
/* Sign-in pill (signed-out only): filled like the send button so the one
   action that unlocks answers reads as primary */
.ai-signin {
  background: var(--accent);
  color: var(--bg);
  border-color: transparent;
  font-weight: 600;
}
.ai-signin:hover { color: var(--bg); border-color: transparent; opacity: 0.9; }
/* Signed-in user chip: Google avatar or initials, 28px circle */
.ai-user-chip {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--dock-chip-bg);
  border: 1px solid var(--border2);
  font-size: var(--fs-3xs);
  font-weight: 700;
  color: var(--muted);
  letter-spacing: 0.03em;
}
.ai-user-chip img { width: 100%; height: 100%; object-fit: cover; }
/* Ephemerality note under the composer */
.ai-privacy-note {
  flex-shrink: 0;
  text-align: center;
  font-size: var(--fs-2xs);
  color: var(--muted2);
  padding: 0 16px 10px;
  order: 7;  /* stays at the very bottom in the empty-state reordering too */
}
.ai-dock--full .ai-suggestions {
  width: 100%;
  max-width: 792px;
  margin: 0 auto;
  padding: 8px 16px;
  justify-content: center;
}
.ai-dock--full .ai-dock-input-row {
  width: 100%;
  max-width: 792px;
  margin: 0 auto;
  padding: 12px 16px 22px;
}
/* Empty state (2026-07-12): ChatGPT-style home — headline above a centered
   composer in the middle of the panel, chips beneath it. Once the first
   message removes .ai-dock-empty, everything reverts to the docked
   bottom-composer conversation layout automatically. */
.ai-dock--full:has(.ai-dock-empty) .ai-dock-body {
  flex: 0 1 auto;
  margin-top: auto;
}
.ai-dock--full:has(.ai-dock-empty) .ai-suggestions {
  order: 5;             /* below the composer */
  margin-bottom: auto;  /* with body's margin-top:auto, centers the group */
  padding-top: 2px;
}
/* Fixed spacer below the chips biases the centered group upward by half its
   height, so the COMPOSER (not the group's midpoint) sits at the panel's
   vertical center - the headline above roughly cancels it out. */
.ai-dock--full:has(.ai-dock-empty)::after {
  content: '';
  order: 6;
  flex: 0 1 180px;
}
/* Send: round icon button tucked inside the field, pinned to its bottom
   corner (the textarea autogrows upward). Scoped to --full - the APRA
   panel keeps its labelled pill. */
.ai-dock--full .ai-dock-input-row { position: relative; }
/* Full pill field (radius = half its 44px min-height) to match the round
   send button; right padding clears the button */
.ai-dock--full .ai-dock-input-row .ai-input {
  border-radius: 22px;
  padding: 12px 58px 12px 20px;
}
.ai-dock--full .ai-dock-input-row .ai-send {
  position: absolute;
  right: 19px;
  bottom: 25px;
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: var(--bg);
  box-shadow: none;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.ai-dock--full .ai-dock-input-row .ai-send:hover {
  transform: scale(1.06);
  box-shadow: none;
}
/* Bot avatar returns in full mode (hidden in the compact dock).
   Avatars are circles here: bot wears the OMI grid mark on quiet glass
   (the amber gradient chip clashed with the mark), user a stroked
   silhouette. */
.ai-dock--full .ai-avatar { border-radius: 50%; }
.ai-dock--full .ai-avatar.bot {
  display: flex;
  background: var(--dock-chip-bg);
  border: 1px solid var(--border2);
  box-shadow: none;
}
.ai-dock--full .ai-avatar.user { border: 1px solid var(--border2); }
.ai-dock--full .ai-bubble { max-width: 90%; }
/* Block-reveal animation for answer paragraphs (progressive reveal) */
.ai-dock--full .ai-bubble-md > * {
  transition: opacity 0.22s ease, transform 0.22s ease;
}
.ai-reveal-pending { opacity: 0; transform: translateY(4px); }
/* Premium markdown rendering in the full-screen overlay (2026-07-12) — the
   compact-dock md styles above stay for the APRA-size panel; full mode gets
   document-like type scale and card-style tables. */
.ai-dock--full .ai-bubble.bot.ai-bubble-md {
  padding: 16px 20px 12px;
  border-radius: 14px;
}
.ai-dock--full .ai-bubble-md p  { font-size: var(--fs-sm); line-height: 1.65; margin: 8px 0; }
.ai-dock--full .ai-bubble-md li { font-size: var(--fs-sm); line-height: 1.6; margin-bottom: 6px; }
.ai-dock--full .ai-bubble-md h1 { font-size: var(--fs-md); margin: 18px 0 8px; letter-spacing: 0.01em; }
.ai-dock--full .ai-bubble-md h2 { font-size: var(--fs-base); margin: 18px 0 8px; letter-spacing: 0.01em; }
.ai-dock--full .ai-bubble-md h3, .ai-dock--full .ai-bubble-md h4,
.ai-dock--full .ai-bubble-md h5, .ai-dock--full .ai-bubble-md h6 { font-size: var(--fs-base); margin: 14px 0 6px; }
.ai-dock--full .ai-bubble-md table {
  font-size: var(--fs-sm);
  margin: 10px 0 14px;
  border: 1px solid var(--border2);
  border-radius: 10px;
  border-collapse: separate;   /* collapse defeats the rounded corners */
  border-spacing: 0;
}
.ai-dock--full .ai-bubble-md th {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  background: var(--dock-chip-bg);
  padding: 8px 12px;
  border-bottom: 1px solid var(--border2);
}
.ai-dock--full .ai-bubble-md th:first-child { border-top-left-radius: 9px; }
.ai-dock--full .ai-bubble-md th:last-child  { border-top-right-radius: 9px; }
.ai-dock--full .ai-bubble-md td { padding: 8px 12px; }
.ai-dock--full .ai-bubble-md tbody tr:nth-child(even) td { background: var(--dock-input-bg); }
.ai-dock--full .ai-bubble-md blockquote {
  font-size: var(--fs-sm);
  padding: 10px 14px;
  margin: 10px 0;
  line-height: 1.55;
}
/* Working-status shimmer (2026-07-12): a light sweep across the status text
   replaces the terminal-style block cursor while the answer builds. */
.ai-status-shimmer {
  background: linear-gradient(90deg,
    var(--muted) 0%, var(--muted) 38%,
    var(--text) 50%,
    var(--muted) 62%, var(--muted) 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: ai-status-shimmer 1.7s linear infinite;
}
@keyframes ai-status-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* ── Repayment estimate disclaimer popover ──────────────────────────────── */
.repayment-info-popover {
  position: fixed;
  width: 300px;
  max-width: calc(100vw - 24px);
  background: var(--surface2);
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px var(--border);
  z-index: 92;
  animation: repayment-info-pop 0.16s cubic-bezier(0.2, 0.9, 0.3, 1.15);
}
@keyframes repayment-info-pop {
  from { opacity: 0; transform: translateY(-4px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.repayment-info-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px 6px;
}
.repayment-info-title {
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--text);
}
.repayment-info-close {
  background: var(--glass2);
  border: none;
  color: var(--muted);
  cursor: pointer;
  width: 32px; height: 32px; padding: 0; border-radius: var(--ctl-r-sq);
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
  flex-shrink: 0;
  transition: color 0.15s;
}
.repayment-info-close .ico { width: var(--ctl-icon-md); height: var(--ctl-icon-md); }
.repayment-info-close:hover { color: var(--text); }
.repayment-info-body {
  padding: 4px 12px 12px;
}
.repayment-info-body p {
  margin: 0 0 8px 0;
  font-size: var(--fs-2xs);
  line-height: 1.45;
  color: var(--muted2);
}
.repayment-info-body p:last-child { margin-bottom: 0; }
.repayment-info-body strong { color: var(--text); font-weight: 600; }
.repayment-info-footnote {
  font-style: italic;
  color: var(--muted) !important;
  padding-top: 2px;
}

/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 * Variant C theme — calculator pages  (2026-05-11)
 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 * Sage accent (--calc-accent) + warm neutral palette via --calc-* tokens.
 * Tokens are defined in :root (dark) and [data-theme="light"] above; flips
 * automatically with the rest of the site. Spacing tightened ~20% from
 * the previous .calc-* defaults.
 *
 * Note: rules in this section override the legacy .calc-* rules above,
 * which are kept for backward compat with non-calculator pages that may
 * reuse these class names.
 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */

.calc-layout {
  grid-template-columns: 280px 1fr;
  gap: 16px;
}
/* One column on phones and narrow tablets. This MUST follow the theme rule
   above: the same declaration used to sit 1,400 lines earlier, lost on source
   order, and eight tabs rendered their results column off the right edge of a
   phone (2026-09-13). */
@media (max-width: 820px) {
  /* minmax(0, 1fr), not 1fr: a bare 1fr track has an auto minimum, so one
     wide child (a nowrap hint, a 120px input beside its unit) widened the
     whole column to 436-546px on Repayments, Investment and Fixed Expiry. */
  .calc-layout { grid-template-columns: minmax(0, 1fr); }
  .calc-inputs, .calc-results { min-width: 0; }
  .calc-inputs  { position: static; }
}
.calc-inputs {
  background: var(--calc-panel);
  border: 1px solid var(--calc-border);
  border-radius: 12px;
  padding: 18px 16px;
  transition: border-color 200ms;
}
.calc-inputs:hover { border-color: var(--calc-border-strong); }
.calc-results { gap: 12px; }
.calc-input-group { margin-bottom: 14px; }
.calc-label {
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  color: var(--calc-muted);
  margin-bottom: 4px;
}
.calc-value-display {
  color: var(--calc-text);
  font-family: var(--font-mono);
  font-feature-settings: 'tnum';
}
.calc-num-prefix, .calc-num-suffix {
  color: var(--calc-muted-dim);
  font-family: var(--font-mono);
}
.calc-num-input {
  color: var(--calc-text);
  font-family: var(--font-mono);
  font-feature-settings: 'tnum';
  border-bottom-color: var(--calc-border);
}
.calc-num-input:focus { border-bottom-color: var(--calc-accent); color: var(--calc-text); }
.calc-num-hint { color: var(--calc-muted); }
.calc-range { accent-color: var(--calc-accent); }
.calc-result-grid { gap: 8px; }
.calc-result-card {
  background: var(--calc-panel-2);
  border: 1px solid var(--calc-border);
  border-radius: 10px;
  padding: 14px 16px;
  transition: border-color 200ms;
}
.calc-result-card:hover { border-color: var(--calc-border-strong); }
.calc-result-card.primary {
  background:
    radial-gradient(circle at top right, var(--calc-accent-soft) 0%, transparent 60%),
    var(--calc-panel);
  border-color: var(--calc-accent);
}
.calc-result-label {
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--calc-muted);
}
.calc-result-value {
  font: 400 var(--fs-xl) 'Instrument Serif', serif;
  color: var(--calc-text);
  font-feature-settings: 'tnum';
  margin-top: 4px;
}

/* Calculator sub-tab nav (Borrowing Power | Buying Budget | …) */
.calc-tabs, [class*="calc-tab"] {
  gap: 6px;
}
.calc-tab-btn, [class*="calc-tab-btn"] {
  background: transparent;
  color: var(--calc-text);
  border: 1px solid var(--calc-border);
  border-radius: var(--ctl-r);
  height: var(--ctl-sm);
  padding: 0 12px;
  font-size: var(--ctl-fs-sm);
  cursor: pointer;
  transition: all 180ms ease;
}
.calc-tab-btn:hover, [class*="calc-tab-btn"]:hover {
  background: var(--calc-panel-hover);
  border-color: var(--calc-accent);
}
.calc-tab-btn.active, [class*="calc-tab-btn"].active {
  background: var(--calc-accent-soft);
  border-color: var(--calc-accent);
  color: var(--calc-accent);
  font-weight: 600;
}

/* ── Cross-tab calculator theme shim (Variant C cascade, 2026-05-11) ───
   Maps the legacy design tokens (--bg, --surface, --text, --muted, etc.)
   to the new --calc-* tokens, scoped to any calculator tab. This lets
   the 13 legacy tabs (buying-budget, equity, refinance, repayments, etc.)
   inherit the same sage-green/warm-neutral palette as borrowing-power
   without rewriting their per-tab <style> blocks.

   To opt a new tab in: just use class="X-tab" on the outer wrapper
   (or one of the legacy roots: .calc-layout / .calc-panel / .sm-tab).
*/
.bp-tab,
.bb-tab,
.sm-tab,
.calc-layout,
.calc-panel {
  --bg:       var(--calc-bg);
  --surface:  var(--calc-panel);
  --surface-2: var(--calc-panel-2);
  --text:     var(--calc-text);
  --muted:    var(--calc-muted);
  --border:   var(--calc-border);
  --glass:    var(--calc-panel-2);
  --glass2:   var(--calc-panel);
  --blue:     var(--calc-accent);
  --accent:   var(--calc-accent);
}

/* Calculator page: trim the empty space above the title (was ~160px from
   nav + ticker + .page-content margin). Scoped override keeps other
   pages' spacing unchanged. */
#page-calc .page-content {
  margin-top: 24px;
  padding-top: 16px;
}
/* Breathing room between title row and section/tab nav */
#page-calc .page-content > .section-row {
  margin-bottom: 36px !important;
}

/* Ticker safety net — only visible on the dashboard page. The JS at
   app.js:showPage() also toggles `display`, but this CSS rule guarantees
   it can't accidentally render on any non-dashboard page even if a future
   navigation path skips that JS branch. */
body:not([data-active-page="dashboard"]) #ticker-wrap {
  display: none !important;
}

/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 *  Market Pulse modal — public 30-day rate-change report (landing page).
 *  Opened from the hero "Market Pulse · 30 days" button.
 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */

/* Hero secondary CTA — pairs with .btn-primary */
.btn-pulse {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 24px;
  font-size: var(--fs-base);
  font-weight: 600;
  font-family: inherit;
  background: var(--glass2);
  color: var(--text);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: background 160ms ease, transform 160ms ease, box-shadow 160ms ease;
  margin-left: 12px;
  letter-spacing: 0.005em;
}
.btn-pulse:hover {
  background: var(--surface);
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(0,0,0,0.18);
}
.btn-pulse svg { color: var(--amber, #f5a623); }

@media (max-width: 720px) {
  .btn-pulse { margin-left: 0; margin-top: 10px; width: 100%; justify-content: center; }
}

/* Modal container — re-uses .modal.detail-modal sizing */
.modal.pulse-modal {
  max-width: 1080px;
  width: min(96vw, 1080px);
  max-height: 92vh;
}
.pulse-topbar-text {
  display: flex; flex-direction: column; gap: 10px;
  flex: 1; min-width: 0;
  padding: 6px 0 4px;
}
.pulse-eyebrow {
  font: 600 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--amber, #f5a623);
  margin-bottom: 2px;
}
.pulse-title {
  font: 400 var(--fs-xl) 'Instrument Serif', serif;
  color: var(--text);
  line-height: 1.1;
}
.pulse-sub {
  font: 500 var(--fs-xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  margin-top: 4px;
}

/* Loading state */
.pulse-loading {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 80px 20px; gap: 18px;
}
.pulse-loading-text {
  font: 500 var(--fs-sm) 'Inter', system-ui, sans-serif;
  color: var(--muted);
}
.pulse-error {
  padding: 60px 20px; text-align: center;
  color: var(--red, #ef4444);
  font: 500 var(--fs-base) 'Inter', system-ui, sans-serif;
}

/* Headline numbers row */
.pulse-headline {
  margin-bottom: 22px;
}
.pulse-headline-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}
@media (max-width: 720px) { .pulse-headline-grid { grid-template-columns: 1fr 1fr; } }
.pulse-headline-card {
  padding: 16px 18px;
  background: var(--glass2);
  border-radius: 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.pulse-headline-card--primary {
  background: linear-gradient(135deg, color-mix(in srgb, var(--amber, #f5a623) 16%, transparent), var(--glass2));
}
.pulse-headline-num {
  font: 400 var(--fs-4xl) 'Instrument Serif', serif;
  color: var(--text);
  line-height: 1;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.pulse-headline-card--primary .pulse-headline-num { font-weight: 500; }
.pulse-headline-lbl {
  font: 500 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  letter-spacing: 0.03em;
}

/* Methodology footnote */
.pulse-method {
  font: 400 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  line-height: 1.55;
  padding: 12px 14px;
  background: rgba(255,255,255,0.025);
  border-radius: 8px;
  margin-bottom: 22px;
}
.pulse-method strong { color: var(--text); font-weight: 600; }

/* Section groups */
.pulse-group { margin-bottom: 22px; }
.pulse-group-title {
  font: 600 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  margin: 0 0 10px;
}
.pulse-group--appendix { opacity: 0.7; }
.pulse-group-body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 10px;
}
@media (max-width: 720px) {
  /* minmax(0,1fr), not 1fr: a bare 1fr track is minmax(auto,1fr) and grows
     to the card's min-content (310px at a 320px viewport), pushing the
     briefing 6px past the screen edge (phone pass 18, 2026-09-05). */
  .pulse-group-body { grid-template-columns: minmax(0, 1fr); }
  .pulse-section { min-width: 0; }
}

/* Section cards */
.pulse-section {
  background: var(--glass2);
  border-radius: 12px;
  padding: 16px 18px;
  display: flex; flex-direction: column; gap: 14px;
}
.pulse-section--empty {
  opacity: 0.55;
  padding: 12px 18px;
  gap: 4px;
}

.pulse-section-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  flex-wrap: wrap;
}
.pulse-section-label {
  font: 600 var(--fs-base) 'Inter', system-ui, sans-serif;
  color: var(--text);
}
.pulse-section-count {
  font: 500 var(--fs-2xs) var(--font-mono);
  color: var(--muted);
  font-feature-settings: 'tnum';
}
.pulse-section-empty-tag {
  font: 500 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.pulse-section-empty-body {
  font: 500 var(--fs-xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
}

.pulse-section-headline {
  display: flex; align-items: center; gap: 14px;
  padding: 8px 0 2px;
}
.pulse-section-headline-text {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; gap: 3px;
  font: 500 var(--fs-sm) 'Inter', system-ui, sans-serif;
  font-feature-settings: 'tnum';
}
.pulse-section-headline-avg {
  text-align: right;
  display: flex; flex-direction: column; gap: 2px;
}
.pulse-avg-label {
  font: 500 var(--fs-3xs) 'Inter', system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.pulse-avg-value {
  font: 600 var(--fs-sm) var(--font-mono);
  font-feature-settings: 'tnum';
}

.pulse-up   { color: var(--green, #22c55e); font-weight: 600;
              font-family: 'Inter', system-ui, -apple-system, sans-serif; }
.pulse-down { color: var(--red, #ef4444); font-weight: 600;
              font-family: 'Inter', system-ui, -apple-system, sans-serif; }
.pulse-muted { color: var(--muted); }

/* Bucket bars */
.pulse-block {
  display: flex; flex-direction: column; gap: 6px;
}
.pulse-block-title {
  font: 500 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 2px;
}
.pulse-bar-row {
  display: grid;
  grid-template-columns: 90px 1fr 110px;
  gap: 10px;
  align-items: center;
}
.pulse-bar-label {
  font: 500 var(--fs-2xs) var(--font-mono);
  font-feature-settings: 'tnum';
  color: var(--text);
}
.pulse-bar-track {
  position: relative;
  height: 8px;
  background: rgba(255,255,255,0.05);
  border-radius: 4px;
  overflow: hidden;
}
.pulse-bar-fill {
  display: block; height: 100%;
  border-radius: 4px;
  transition: width 480ms cubic-bezier(0.2, 0.9, 0.3, 1.15);
}
.pulse-bar-meta {
  font: 500 var(--fs-2xs) var(--font-mono);
  color: var(--text);
  font-feature-settings: 'tnum';
  text-align: right;
  white-space: nowrap;
}
.pulse-bar-pct {
  color: var(--muted);
  font-weight: 400;
  margin-left: 8px;
}

/* Fixed-vs-variable stacked bar */
.pulse-fv-row { display: flex; flex-direction: column; gap: 6px; }
.pulse-fv-bar {
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  display: flex;
  background: rgba(255,255,255,0.05);
}
.pulse-fv-fixed    { background: color-mix(in srgb, var(--blue, #3b82f6) 70%, transparent); }
.pulse-fv-variable { background: color-mix(in srgb, var(--amber, #f5a623) 70%, transparent); }
.pulse-fv-legend {
  font: 500 var(--fs-2xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  display: flex; align-items: center; gap: 6px;
  flex-wrap: wrap;
}
.pulse-fv-legend strong { color: var(--text); font-weight: 600; }
.pulse-fv-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
}
.pulse-fv-dot--fixed    { background: color-mix(in srgb, var(--blue, #3b82f6) 70%, transparent); }
.pulse-fv-dot--variable { background: color-mix(in srgb, var(--amber, #f5a623) 70%, transparent); }
.pulse-fv-sep { color: var(--muted); opacity: 0.5; margin: 0 2px; }

/* Section footer — current market state */
.pulse-section-foot {
  font: 500 var(--fs-xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  padding-top: 6px;
  border-top: 1px solid rgba(255,255,255,0.05);
  font-feature-settings: 'tnum';
}
.pulse-section-foot strong { color: var(--text); font-weight: 600; }

/* CTA back into early-access funnel */
.pulse-cta {
  margin-top: 22px;
  padding: 22px 24px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--amber, #f5a623) 14%, transparent), rgba(255,255,255,0.03));
  border-radius: 14px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.pulse-cta-text {
  font: 500 var(--fs-base) 'Inter', system-ui, sans-serif;
  color: var(--text);
}

/* Market Pulse v2 additions — Step 0+1+4 */

/* Plain-English bullet between section header and donut */
.pulse-bullet {
  font: 500 var(--fs-sm) 'Inter', system-ui, sans-serif;
  color: var(--text);
  line-height: 1.5;
  padding: 4px 0 2px;
  letter-spacing: 0.005em;
}
.pulse-bullet strong { color: var(--text); font-weight: 700; }

/* Expandable methodology note */
details.pulse-method {
  margin-bottom: 22px;
  background: rgba(255,255,255,0.025);
  border-radius: 8px;
  padding: 0;
}
details.pulse-method[open] { padding-bottom: 12px; }
.pulse-method-summary {
  cursor: pointer;
  padding: 12px 14px;
  font: 600 var(--fs-xs) 'Inter', system-ui, sans-serif;
  color: var(--text);
  letter-spacing: 0.01em;
  user-select: none;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
.pulse-method-summary::before {
  content: '▸';
  font-size: var(--fs-2xs);
  color: var(--muted);
  transition: transform 160ms ease;
}
details.pulse-method[open] .pulse-method-summary::before { transform: rotate(90deg); }
.pulse-method-summary::-webkit-details-marker { display: none; }
.pulse-method-body {
  padding: 0 14px;
  font: 400 var(--fs-xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  line-height: 1.6;
}
.pulse-method-body p { margin: 0 0 10px; }
.pulse-method-body p:last-child { margin-bottom: 0; }
.pulse-method-body strong { color: var(--text); font-weight: 600; }
.pulse-method-body em { color: var(--text); font-style: italic; }

/* ── Two-table layout for sticky row labels ───────────────────────────
   Rewritten 2026-05-19 after `position: sticky` on <td> proved fragile.
   The label column is a SEPARATE table on the left; the data columns
   live in a horizontally scrollable second table on the right. Because
   the tables are physically separate elements, scrolled-under content
   cannot overlap the labels - no z-index gymnastics needed.

   Pattern: shell (flex) → labels-table | scroll-wrapper → data-table. */
/* Two-column grid: first track = labels-table natural width,
   second track = remaining space (scrolling data table). Grid is more
   deterministic than flex when one of the children is a <table>,
   which has weird intrinsic-width semantics. */
.pulse-tt-shell {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: stretch;
  font: 500 var(--fs-xs) var(--font-mono);
  font-feature-settings: 'tnum';
}
.pulse-tt-wrap { /* legacy alias; kept so unrelated code paths don't break */
  overflow-x: auto;
}
.pulse-tt-scroll {
  overflow-x: auto;
  min-width: 0;
}
.pulse-tt-labels {
  border-collapse: collapse;
  background: #1b1d22;
  border-right: 1px solid rgba(255,255,255,0.06);
  box-shadow: 4px 0 8px rgba(0,0,0,0.35);
}
.pulse-tt-data {
  width: 100%;
  border-collapse: collapse;
  min-width: 360px;
}
.pulse-tt-labels th,
.pulse-tt-labels td,
.pulse-tt-data th,
.pulse-tt-data td {
  padding: 6px 8px;
  text-align: right;
  white-space: nowrap;
  height: 32px; /* explicit height keeps both tables' rows aligned */
  box-sizing: border-box;
}
.pulse-tt-labels thead th,
.pulse-tt-data thead th {
  font: 600 var(--fs-3xs) 'Inter', system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid rgba(255,255,255,0.06);
  padding-bottom: 6px;
}
.pulse-tt-labels tbody td {
  text-align: left !important;
  /* 0.8rem Inter ≈ 0.75rem JetBrains Mono visually — monospace renders
     larger at the same point size. Sync so labels don't look smaller
     than the data values they describe. */
  font: 500 var(--fs-xs) 'Inter', system-ui, sans-serif;
  color: var(--muted);
  padding-right: 16px;
  min-width: 180px;
}
.pulse-tt-data tbody td {
  color: var(--text);
}
.pulse-tt-labels tbody tr:not(:last-child) td,
.pulse-tt-data tbody tr:not(:last-child) td {
  border-bottom: 1px solid rgba(255,255,255,0.03);
}
/* Light-theme variant */
[data-theme="light"] .pulse-tt-labels {
  background: #f5f5f4;
  border-right-color: rgba(0,0,0,0.06);
  box-shadow: 4px 0 8px rgba(0,0,0,0.08);
}

/* Variable product-type table — block-title note styling */
.pulse-block-note {
  color: var(--muted);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0.005em;
  font-style: italic;
}

/* Rate distribution: "median" tag on the bucket containing the section median */
.pulse-bar-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: var(--fs-3xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 3px;
  background: rgba(59, 130, 246, 0.15);
  color: rgb(var(--blue-rgb, 59 130 246));
  vertical-align: middle;
}

/* Rate distribution: median row tint + leading accent (replaces the
   wrapping MEDIAN tag - visual lands on the row at a glance). */
.pulse-bar-row--median {
  background: rgba(59, 130, 246, 0.06);
  border-left: 3px solid rgb(var(--blue-rgb, 59 130 246));
  padding-left: 6px;
  margin-left: -9px;  /* re-align with non-median rows */
  border-radius: 2px;
}
.pulse-bar-row--median .pulse-bar-label {
  font-weight: 600;
  color: var(--text);
}

/* Hidden-buckets footnote — small italic line below the bar list */
.pulse-bar-hidden {
  margin-top: 4px;
  padding-left: 2px;
  font-size: var(--fs-2xs);
  font-style: italic;
  color: var(--muted2, #8b8f99);
}

/* Clickable bucket rows — subtle hover indicates drill-down is available */
.pulse-bar-row--clickable {
  cursor: pointer;
  transition: background 0.12s, transform 0.12s;
  border-radius: 4px;
  padding: 3px 6px;
  margin-left: -6px;
}
.pulse-bar-row--clickable:hover {
  background: rgba(59, 130, 246, 0.07);
}
.pulse-bar-row--clickable.pulse-bar-row--median {
  /* Hover on the median row should still feel different — bump tint */
  cursor: pointer;
}
.pulse-bar-row--clickable.pulse-bar-row--median:hover {
  background: rgba(59, 130, 246, 0.12);
}

/* Bucket drill-down modal: scrollable two-line card list (Rate Browser
   visual language). Monochrome - hierarchy via size/weight, not colour. */
.pulse-bucket-modal {
  max-width: 880px;
  width: 96vw;
}
.pulse-bucket-list {
  max-height: calc(85vh - 140px);
  overflow-y: auto;
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
/* Compact list row — 3 lines, 32×32 logo (Rate Browser scale, slightly
   tighter for modal density). Hierarchy via size only - no colour. */
.pulse-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  transition: background 0.12s;
}
.pulse-row:hover { background: rgba(150, 150, 150, 0.04); }
.pulse-row:last-child { border-bottom: none; }
.pulse-row-logo {
  flex-shrink: 0;
  display: flex;
}
.pulse-row-logo .bank-logo-img,
.pulse-row-logo .bank-logo {
  width: 44px; height: 44px;
  border-radius: 8px;
}
.pulse-logo-fallback {
  background: var(--surface2);
  color: var(--muted);
  font-size: var(--fs-xs);
  font-weight: 600;
  border: 1px solid var(--border);
}
.pulse-row-body { flex: 1; min-width: 0; }
.pulse-row-top,
.pulse-row-mid {
  display: flex;
  align-items: baseline;
  gap: 14px;
  justify-content: space-between;
}
.pulse-row-bank {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--text);
  line-height: 1.2;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pulse-row-rate {
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  flex-shrink: 0;
}
.pulse-row-prod {
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: 1.3;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pulse-row-comp {
  font-size: var(--fs-2xs);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.pulse-row-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 4px;
  font-size: var(--fs-2xs);
  color: var(--muted2, #8b8f99);
  gap: 12px;
}
.pulse-row-dims {
  letter-spacing: 0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
.pulse-row-link {
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px dotted var(--muted2, #8b8f99);
  transition: border-color 0.12s, color 0.12s;
  flex-shrink: 0;
}
.pulse-row-link:hover {
  border-bottom-color: var(--text);
}
.pulse-empty {
  padding: 32px;
  text-align: center;
  color: var(--muted);
  font-style: italic;
}

/* Clickable bucket rows: the LABEL gets the link affordance (dotted
   underline, same pattern as "View at lender" link). On hover the
   underline solidifies + label brightens + row background lifts so
   users can click anywhere in the row. No icons, no colour. */
.pulse-bar-row--clickable {
  transition: background 0.12s;
}
.pulse-bar-row--clickable .pulse-bar-label {
  border-bottom: 1px dotted var(--muted2, #8b8f99);
  padding-bottom: 1px;
  transition: border-bottom-color 0.12s, color 0.12s;
}
.pulse-bar-row--clickable:hover {
  background: rgba(150, 150, 150, 0.06);
}
.pulse-bar-row--clickable:hover .pulse-bar-label {
  border-bottom-color: var(--text);
  color: var(--text);
}

/* ── CSP step 2b utilities (2026-07-05): inline onmouseover/onmouseout style
   handlers converted to classes during the template-handler sweep. */
.hov-bg:hover { background: var(--subtle-hover, rgba(255,255,255,0.06)) !important; }
.hov-op { opacity: 0.7; }
.hov-op:hover { opacity: 1; }
/* text-button hover (was inline onmouseover color swap) — muted → full text */
.hov-text:hover { color: var(--text) !important; }
/* modal back-button hover (was inline onmouseover border+color swap) */
.hov-navback:hover { border-color: var(--glass-border) !important; color: var(--text) !important; }


/* ── Search typeahead (2026-07-17) ─────────────────────────────────────── */
.srch-suggest {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 60;
  background: var(--glass, rgba(20,22,28,0.98)); border: 1px solid var(--glass2, #2a2d36);
  border-radius: 14px; padding: 6px; backdrop-filter: blur(14px);
  box-shadow: 0 12px 32px rgba(0,0,0,0.45); max-height: 340px; overflow-y: auto;
}
.srch-suggest-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border-radius: 9px; cursor: pointer; font-size: var(--fs-sm); color: var(--text);
}
.srch-suggest-row:hover, .srch-suggest-row.is-active { background: rgba(255,255,255,0.06); }
.srch-suggest-logo { width: 22px; height: 22px; border-radius: 6px; object-fit: contain; background: #fff; flex: 0 0 22px; }
.srch-suggest-logo--dot { background: var(--glass2, #2a2d36); }
.srch-suggest-logo--cat { display:flex; align-items:center; justify-content:center; background: transparent; color: var(--accent, #3b82f6); font-size: var(--fs-base); }
.srch-suggest-name { flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.srch-suggest-name, .srch-suggest-name * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.srch-suggest-sub { color: var(--muted, #8a8f9c); font-size: var(--fs-2xs); }
.srch-suggest-kind { color: var(--muted, #8a8f9c); font-size: var(--fs-3xs); text-transform: uppercase; letter-spacing: 0.06em; }
.srch-suggest-rate { color: var(--text); font-weight: 700; font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }


/* ── Hero insights carousel (2026-07-17) ───────────────────────────────── */
/* Insights zone carries the column's ONE big break; 680px card width keeps
   body lines inside the readable 45-75 char band and matches .hero-sub. */
/* width:100% + flex-basis:100% pin the carousel to a full row of the wrapping
   .hero-actions flex parent - without it the card is a content-sized flex item,
   so each slide's different text length changed the width (2026-07-24).
   #hero-insights-home needs the SAME pin: the IntersectionObserver re-parents
   the carousel INTO it at rest, and a bare flex item shrink-wraps its content,
   which re-introduced the per-slide width jitter one level up. */
.hero-insights { margin-top: 42px; width: 100%; flex-basis: 100%; max-width: 680px; }
#hero-insights-home { width: 100%; flex-basis: 100%; }
.hero-insights-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 10px;
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--muted, #8a8f9c); font-weight: 600;
}
.hero-insights-date { font-weight: 400; letter-spacing: 0.04em; }
.hero-insights-head .hero-insights-dots { margin-left: auto; margin-top: 0; }
.hero-live-dot { width: 7px; height: 7px; border-radius: 50%; background: #34d399; flex: 0 0 7px;
  animation: hero-pulse 2.2s ease-in-out infinite; }
@keyframes hero-pulse { 0%,100% { opacity: 1; box-shadow: 0 0 0 0 rgba(52,211,153,.5); } 50% { opacity: .55; box-shadow: 0 0 0 5px rgba(52,211,153,0); } }
.hero-insight-card {
  display: flex; gap: 14px; align-items: flex-start;
  background: var(--glass, rgba(20,22,28,0.7)); border: 1px solid var(--glass2, #2a2d36);
  border-radius: 14px; padding: 13px 16px;
  /* Full wording, no clamps (2026-07-18): the card hugs each insight's
     measured height (JS animates height per slide); the tallest height is
     reserved on the #hero-insights container, so layout stays stable while
     short insights never sit in a half-empty panel. */
  min-height: 92px; overflow: hidden;
  transition: opacity .35s ease, height .3s ease;
  cursor: grab; user-select: none; touch-action: pan-y;
}
.hero-insight-card:active { cursor: grabbing; }
.hero-insight-card.is-fading { opacity: 0; }
.hero-insight-rank {
  font-family: 'Syne', sans-serif; font-size: var(--fs-2xl); font-weight: 700;
  color: var(--accent, #3b82f6); line-height: 1; min-width: 34px; text-align: center;
}
/* The text column is a flex item beside the rank, and a flex item's default
   min-width is its min-content width. The fact line below is nowrap, so a
   line wider than the column (larger phone text sizes, a band on a deposit
   line) used to WIDEN the column past the card and the card clipped the
   headline and the fact line together (operator, 2026-09-19, card 4 on an
   iPhone; not reproducible at rest in Chromium or WebKit at 360/390, which
   points at device text size). min-width:0 caps the column at the card, so
   the headline wraps inside it and the fact line ellipsises instead. */
.hero-insight-text { min-width: 0; flex: 1 1 auto; }
.hero-insight-headline {
  font-weight: 700; color: var(--text); font-size: var(--fs-base); line-height: 1.3;
  overflow-wrap: anywhere;
}
.hero-insight-body {
  color: var(--muted2, #a7adba); font-size: var(--fs-xs); line-height: 1.45; margin-top: 4px;
}
.hero-insight-meta {
  color: var(--muted, #8a8f9c); font-size: var(--fs-2xs); line-height: 1.4; margin-top: 6px;
  font-variant-numeric: tabular-nums; letter-spacing: 0.01em;
  /* ONE LINE, always (2026-09-18, operator). The sentence is composed short by
     construction in daily_insights.fact_line (about 39 characters at worst,
     because the only variables are a fixed label and two rates), and nowrap
     stops a wrap the composer did not anticipate. Measured on prod: the
     longest realistic string is 284px against 367px of desktop card. The
     ellipsis can only fire on a string the composer says cannot exist, and a
     clipped tail still reads better than a card that outgrows the feed's
     sign-up button. */
  /* Wraps to as many lines as it needs (operator, 2026-09-19: "elongate the
     box if needed"). Between about 900 and 1100px the hero puts the carousel
     in a side column where this line's box is 124px wide, so nowrap printed
     "Owner-occupier from 6.4..." and a two-line clamp still clipped the
     rates. The card's height is measured by JS per slide, so a taller line
     grows the card rather than overflowing it. At 1180px and above the
     sentence is one line (304px of 304); on phones the box is 276px and it
     is one line too. */
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 0;
}
/* The card sits beside the rate feed and its bottom is what the feed's height
   is aligned to, so an over-long insight pushed the panel past the feed's
   sign-up button (2026-09-18, operator). Generated prose is short by
   construction now; these clamps mean no future insight can break the column
   either. Headline two lines, body three, then ellipsis. */
.hero-insight-headline { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.hero-insight-body { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* Stacked (≤1200px, see the hero block): the card no longer shares a row with
   the feed, so nothing needs the clamps and a 246px-wide phone column cut the
   Westpac body at four lines ("...the same group, made..." - operator,
   2026-09-19, twice). Headline, body and fact line all wrap to what they
   need; the JS-measured card height grows with them. */
@media (max-width: 1200px) {
  .hero-insight-headline, .hero-insight-body { display: block; -webkit-line-clamp: unset; overflow: visible; }
}
/* The carousel is 276px wide on a 390px phone and 246px on a 360px one, so
   11.2px cannot hold the sentence on either. Measured against the real font:
   the longest string the composer can emit is 284px at 11.2px, so 9.4px lands
   it at 238px and clears even a 360px screen with a two-digit rate. This is a
   tertiary fact line under a headline and a body; one legible line says more
   than two lines that push the card past the sign-up button. */
@media (max-width: 640px) { .hero-insight-meta { font-size: 9.4px; letter-spacing: 0; } }
/* ── AI answer product-reference chips (2026-07-18) ─────────────────────── */
.ai-refs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.ai-ref-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; font-size: var(--fs-2xs); line-height: 1.4;
  color: var(--text); background: var(--glass2);
  border: 1px solid var(--glass-border); border-radius: 999px;
  cursor: pointer; transition: border-color .15s, background .15s;
  max-width: 100%; text-align: left;
}
.ai-ref-chip:hover { border-color: var(--accent, #3b82f6); }
.ai-ref-rate { color: var(--accent, #3b82f6); font-weight: 700; }
.ai-ref-explore { color: var(--accent, #3b82f6); background: transparent; }

/* "Ask AI" pill in the product modal + compare basket (2026-07-18) */
/* Shared "Ask AI" treatment: dark pill with a rotating light border + AI glow.
   Uses the padding-box/border-box double-background trick driven by an
   animated @property angle - a perfectly even ring with no corner glitch
   (the earlier rotating-pseudo-element version showed a seam, 2026-07-20). */
@property --ai-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }

.prod-action-ai,
.compare-basket-askai {
  color: #fff;
  /* ONE ring, not two. This rule used to paint a permanent conic gradient in
     the border box while the travelling-light ::after painted another over
     it at a hard-coded 999px radius, which on a 10px-radius button read as a
     second border offset behind the first (2026-09-08). The border is a
     hairline now; the light that travels around it is the ::after. */
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--ai-center, #0d1526);
  box-shadow: 0 0 14px rgba(124, 58, 237, 0.28);
  transition: box-shadow .2s ease, transform .15s ease;
}
.prod-action-ai:hover,
.compare-basket-askai:hover {
  box-shadow: 0 0 20px rgba(124, 58, 237, 0.5);
}
[data-theme="light"] .prod-action-ai,
[data-theme="light"] .compare-basket-askai {
  /* a near-black slab beside a light grey button read as broken rather than
     as the special one; the pill goes light and keeps its travelling ring */
  --ai-center: #eef1ff;
  color: #1e293b;
  border-color: rgba(29, 78, 216, 0.22);
  box-shadow: 0 0 14px rgba(59, 130, 246, 0.28);
}
[data-theme="light"] .prod-action-ai:hover,
[data-theme="light"] .compare-basket-askai:hover {
  box-shadow: 0 0 20px rgba(59, 130, 246, 0.45);
}
@keyframes ai-border-spin { to { --ai-angle: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  .prod-action-ai, .compare-basket-askai { animation: none; }
}
/* Layout only — colour/glow/border come from the shared .prod-action-ai,
   .compare-basket-askai rule above (2026-07-20: matched to the modal pill). */
.compare-basket-askai {
  width: 100%; margin-top: 8px; height: var(--ctl-md); padding: 0 var(--ctl-px-md);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-size: var(--ctl-fs-md); letter-spacing: 0.01em;
  border-radius: var(--ctl-r); cursor: pointer;
}
.compare-basket-askai:hover { transform: translateY(-1px); }
.compare-basket-askai:active { transform: translateY(0); }
/* Empty basket: the pill mutes — no rainbow ring, no glow, no spin. It stays
   clickable on purpose: the click shows a "tick Compare first" toast hint.
   Class toggled by _renderCompareBasket() in components/product-table.js. */
.compare-basket-askai.is-empty {
  animation: none;
  background: var(--ai-center, #0d1526);
  border-color: var(--border);
  box-shadow: none;
  color: var(--muted);
}
.compare-basket-askai.is-empty:hover {
  box-shadow: none;
  transform: none;
}

/* ONE carousel dot everywhere (2026-09-18). A 7px dot on a 14px pitch: the
   home page had 6px dots on a 24px pitch (a 24px tap box with 18px of air
   between them, which read as scattered) and the APRA page had 7px spans
   touching at a 7px pitch with no keyboard access at all. The button is 14px
   wide and 22px tall, so the row stays compact while the tap target keeps
   its height; phones widen it. Every carousel renders <button> children. */
.hero-insights-dots { display: flex; gap: 0; margin-top: 1px; justify-content: center; align-items: center; }
.hero-insights-dots button {
  width: 14px; height: 22px; border-radius: 50%; border: none; padding: 0; margin: 0; cursor: pointer;
  background: transparent; position: relative; flex: 0 0 auto;
}
.hero-insights-dots button::before {
  content: ''; position: absolute; left: 50%; top: 50%; width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
  border-radius: 50%; background: var(--glass2, #2a2d36); transition: background .2s, transform .2s;
}
.hero-insights-dots button.is-active::before { background: var(--accent, #3b82f6); transform: scale(1.3); }
@media (max-width: 640px) { .hero-insights-dots button { width: 18px; } }


/* ── Insights docked into the compare rail on scroll (2026-07-18) ──────── */
.compare-basket .hero-insights { margin-top: 14px; max-width: none; }
.compare-basket .hero-insight-card { height: auto; min-height: 0; padding: 10px 12px; gap: 10px; }
.compare-basket .hero-insight-rank { font-size: var(--fs-lg); min-width: 22px; }
.compare-basket .hero-insight-headline {
  /* fit the 240px rail: smaller type, room for 4 lines, card grows with it
     (2026-07-18 - headlines were truncating mid-word at 3 lines) */
  font-size: var(--fs-2xs); line-height: 1.35; -webkit-line-clamp: 4;
}
.compare-basket .hero-insight-body { display: none; }
.compare-basket .hero-insights-head { font-size: var(--fs-3xs); }
.compare-basket .hero-insights-dots { margin-top: 0; }
.compare-basket .hero-insights-date { display: none; }

/* ── Phone pass (2026-09-05, first day live) ─────────────────────────────
   Reviewed on a 390px iPhone viewport against production. Every rule here
   is confined to ≤640px so desktop/tablet are untouched. What looked
   clunky and why:
   1. Product Explorer kept its 176px sticky side column even after the
      640px rule made the grid one column - a squeezed "Categories" card
      with clipped pills. → full width, static.
   2. The sticky search + repayment strip ate a third of the screen while
      scrolling the table. → static on phones.
   3. The AI dock was a translucent centred dialog: page text bled through,
      the "powered by" tag pushed the close button off-screen, the greeting
      clipped under the header. → opaque full-screen sheet, tag hidden.
   4. The 56px FAB sat on top of the footer links / last form field. →
      smaller, tighter to the corner, footer gets clearance.
   5. Drawer items centred under left-aligned section labels. → left. */
@media (max-width: 640px) {
  .tracker-filter-slot { width: 100%; }
  .tracker-filter-bar { position: static; max-height: none; }
  .tracker-sticky-header { position: static; padding-top: 8px; }

  /* Galaxy S21 (360x800, ~640px visible under Android chrome): the drawer
     ran past the bottom with overflow visible, so APRA Publication and
     Alerts were unreachable. Scroll inside the drawer and tighten rows. */
  .nav-drawer {
    max-height: calc(100vh - 64px);
    max-height: calc(100dvh - 64px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: max(16px, env(safe-area-inset-bottom));
  }
  .nav-drawer .nav-link { text-align: left; justify-content: flex-start; padding: 9px 16px; font-size: var(--fs-base); }
  .nav-drawer .nav-dd-section { padding: 6px 16px 2px; }
  .nav-drawer .btn-login { height: var(--ctl-md) !important; flex-shrink: 0; padding: 0 !important; font-size: var(--ctl-fs-md) !important; }  /* the drawer is a column that can overflow: without flex-shrink:0 the button squashed to 16px */

  .ai-fab { width: 48px; height: 48px; right: 14px; bottom: 14px; }
  .ai-fab-glyph svg { width: 30px; height: 30px; }
  .footer-links { padding-bottom: 64px; }

  .ai-dock--full {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    border-radius: 0;
    border: none;
    --dock-bg: rgb(8, 10, 14);   /* fully opaque: a sheet, not a glass panel */
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  [data-theme="light"] .ai-dock--full { --dock-bg: rgb(255, 255, 255); }
  .ai-dock-header { padding: 12px 12px 8px; }
  .ai-dock-header h3 { font-size: var(--fs-md); }
  .ai-powered-by { display: none; }
  .ai-dock-empty-title { font-size: var(--fs-xl); }
}

/* ── Phone pass 2 (2026-09-05 evening, Galaxy S21 screenshots from the operator) ──
   1. Market Rates Pulse "rates by term" / "by product type": the global
      ≤640px responsive-table rule (main table … { display:block }) stacked
      the two-table matrix into one column of tall empty cells. Restore real
      table display for the pulse matrix (same opt-out the APRA tables have)
      and let the data half scroll sideways under a narrower label column.
   2. Dashboard: search bar, repayment strip and product cards ran off the
      right edge (then clipped by overflow-x: clip). The calc strip is an
      inline-flex that never wraps, and the tracker grid track is `1fr`,
      which lets min-content widen the whole column. Bound the track, wrap
      the strip.
   3. Compare basket rendered as two empty bars under the cards - comparing
      side by side needs width; hide the basket and the per-card toggle.
   4. AI dock header: "Sign in" pill wrapped to two lines; a hidden
      New-chat button rendered as an empty circle because .ai-new-chat's
      display beats the UA's [hidden]. */
@media (max-width: 640px) {
  .pulse-tt-labels thead, .pulse-tt-data thead { display: table-header-group !important; }
  .pulse-tt-labels tbody, .pulse-tt-data tbody { display: table-row-group !important; }
  .pulse-tt-labels, .pulse-tt-data { display: table !important; width: auto !important; }
  .pulse-tt-data { width: 100% !important; }
  .pulse-tt-labels tr, .pulse-tt-data tr { display: table-row !important; border: none !important; border-radius: 0 !important; margin: 0 !important; background: none !important; backdrop-filter: none !important; }
  .pulse-tt-labels th, .pulse-tt-labels td, .pulse-tt-data th, .pulse-tt-data td {
    display: table-cell !important; width: auto !important; padding: 6px 6px !important;
    border-bottom: 1px solid rgba(255,255,255,0.03) !important; background: none !important;
  }
  .pulse-tt-labels td::before, .pulse-tt-data td::before { content: none !important; }
  .pulse-tt-labels tbody td { min-width: 0 !important; font-size: var(--fs-2xs) !important; padding-right: 8px !important; }
  .pulse-tt-labels td:first-child { background: none !important; justify-content: flex-start; }

  .tracker-layout { grid-template-columns: minmax(0, 1fr); }
  .calc-inputs-strip { display: flex !important; flex-wrap: wrap; width: 100% !important; max-width: 100%; row-gap: 6px; }
  .calc-strip-context { white-space: normal; }

  #compare-basket { display: none !important; }

  .ai-signin { white-space: nowrap; }
}
/* Every control in the chat headers sets its own display (flex pills, the
   round user chip, the quota badge), which beats the browser's [hidden]; on
   a desktop a signed-out dock painted an empty avatar circle and an empty or
   stale quota pill beside "Sign in" (2026-09-29). This used to live only in
   the phone block above. */
.ai-dock-header [hidden], #apra-chat-panel [hidden] { display: none !important; }

/* ── Phone pass 3 (2026-09-05, element-by-element audit at 360px) ─────────── */
@media (max-width: 640px) {
  /* Product detail modal header: logo | title | rate block squeezed the title to
     one word per line. Stack: identity row, then rate row. */
  .prod-modal-header { flex-wrap: wrap; gap: 12px; }
  .prod-modal-identity { flex: 1 1 100%; }
  .prod-modal-name { font-size: var(--fs-md); }
  .prod-modal-rate-block { flex: 1 1 100%; flex-direction: row; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 6px 12px; }
  .prod-modal-rate { font-size: var(--fs-xl); }

  /* 30-day chart tiles: 2x2 grid truncated titles to "HO…". One per row. */
  .chart-mini-grid { grid-template-columns: 1fr; grid-template-rows: auto; }
  .chart-mini-title { white-space: normal; }

  /* Feed sign-up CTA floated right with dead space beside it. */
  .feed-subscribe { justify-content: center; }
  .feed-subscribe .feed-sub-btn { width: 100%; }

  /* Card rows carried a backdrop blur each — a scroll-performance tax on
     phones (and a headless-capture hazard). Solid surface instead. */
  main table tr { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }

  /* Market Rates Pulse: subtitle touched the stat tiles; donut + legend +
     median-move squeezed into three narrow columns. */
  .pulse-sub { margin-bottom: 14px; }
  .pulse-section-headline { flex-wrap: wrap; }
  .pulse-section-headline-avg { flex: 1 1 100%; flex-direction: row; justify-content: space-between; align-items: baseline; text-align: left; }

  /* LVR Grid: the control toolbar was sticky and taller than the screen, so
     the chart underneath could never be seen. */
  .lvr-toolbar { position: static !important; }
  /* LVR segments on phones (2026-09-20). The 09-18 control system made
     .lvr-seg a 31px track with hidden overflow, so the pass-3 wrap hid the
     shelves' second row (≤100, Flat, All) below the track's edge; the phone
     hit-layer list named the TRACK (a div around the buttons, not a button),
     whose invisible ::after sat over every segment and ate every tap for
     three days; and the grid cell stretched each track across the whole row,
     thirteen empty boxes down the screen. The track now scrolls sideways
     like every other seg, fits its segments, and each segment's tap box is
     the full track height (the track clips anything taller). */
  .lvr-seg, #lvr-shelf-multi { flex-wrap: nowrap; width: fit-content; max-width: 100%; justify-self: start; }
  .lvr-seg > button { position: relative; }
  .lvr-seg > button::after { content: ''; position: absolute; left: 0; right: 0; top: -3px; bottom: -3px; }

  /* APRA Publication: hero KPI cards sat in a non-wrapping flex row; the
     market-share tables were card-stacked without labels (the global rule)
     - restore real tables inside a sideways-scrolling wrapper, like #apra-table. */
  div:has(> .pulse-kpi) { flex-wrap: wrap; }
  .pulse-kpi { flex: 1 1 calc(50% - 4px); min-width: 0; }
  main .data-table { display: table !important; width: 100% !important; }
  main .data-table thead { display: table-header-group !important; }
  main .data-table tbody { display: table-row-group !important; }
  main .data-table tr { display: table-row !important; border: none !important; border-radius: 0 !important; margin: 0 !important; background: none !important; }
  main .data-table td, main .data-table th { display: table-cell !important; width: auto !important; padding: 8px 10px !important; border-bottom: 1px solid var(--border) !important; background: none !important; white-space: nowrap; }
  main .data-table td::before { display: none !important; }
  div:has(> .data-table) { overflow-x: auto !important; -webkit-overflow-scrolling: touch; }

  /* Chat launcher: a touch smaller so it hides less of the last row. */
  .ai-fab { width: 44px; height: 44px; }
  .ai-fab-glyph svg { width: 28px; height: 28px; }
}

/* ── Phone pass 4 (2026-09-05, verification of pass 3) ─────────────────────── */
@media (max-width: 640px) {
  /* Detail modals were translucent glass over the page: the product cards
     behind ghosted through the sheet. Solid surface on phones. */
  .modal-overlay .modal { background: var(--bg) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
  /* Tables inside modals (lending rates, fees) clipped at the right edge. */
  .modal-overlay .modal table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap; }
  #prod-detail-content, #inst-detail-content { overflow-x: visible; }
  .prod-actions .prod-action-pill { gap: 5px; }

  /* LVR Grid heatmap: card-stacked by the global rule into value-only rows
     (no lender, no shelf). Real table, sideways scroll, lender column pinned. */
  .lvr-heatmap { display: table !important; width: auto !important; min-width: 100%; }
  .lvr-heatmap thead { display: table-header-group !important; }
  .lvr-heatmap tbody { display: table-row-group !important; }
  .lvr-heatmap tr { display: table-row !important; border: none !important; border-radius: 0 !important; margin: 0 !important; background: none !important; }
  .lvr-heatmap td, .lvr-heatmap th { display: table-cell !important; width: auto !important; padding: 6px 8px !important; white-space: nowrap; border-bottom: 1px solid var(--border) !important; }
  .lvr-heatmap td::before { display: none !important; }
  .lvr-heatmap td:first-child, .lvr-heatmap th:first-child { position: sticky; left: 0; background: var(--bg) !important; z-index: 1; }
  div:has(> .lvr-heatmap) { overflow-x: auto !important; -webkit-overflow-scrolling: touch; }
  /* LVR strip chart + 200px legend sat side by side; legend hung off-screen. */
  div:has(> #lvr-legend) { flex-wrap: wrap; }
  div:has(> #lvr-legend) > div:first-child { flex: 1 1 100% !important; height: 420px !important; }
  /* A 220px box holding 295px of legend drew a scrollbar down its right and
     read as a second panel floating inside the page. The scanner lost the
     same inner vertical box in pass 30; the legend loses it here. The list
     is short, so let it be as tall as it is and give the page the scrolling
     (2026-09-08). */
  #lvr-legend { width: 100% !important; max-height: none !important; overflow: visible !important; }
}

/* ── Phone pass 5 (2026-09-05, DOM-probe driven) ───────────────────────────── */
@media (max-width: 640px) {
  /* Chart tiles: a more specific rule kept two columns; the title was starved
     to 5px by its flex siblings. One tile per row, title on its own line. */
  .chart-mini-grid, .charts-fold .chart-mini-grid { grid-template-columns: 1fr !important; grid-template-rows: auto !important; }
  .chart-mini-header { flex-wrap: wrap; row-gap: 4px; }
  .chart-mini-title { flex: 1 1 100%; white-space: normal; overflow: visible; }

  /* APRA Publication hero: every row inside is an inline display:flex that
     never wraps, so the KPI cards and the lender mini-cards pushed the whole
     panel to 420px. Wrap them, two cards per row. */
  #apra-pulse-inner [style*="display:flex"] { flex-wrap: wrap; }
  #apra-pulse-inner .pulse-kpi { flex: 1 1 calc(50% - 6px); min-width: 140px; }
  #apra-pulse-inner, .apra-pulse-panel, #apra-hero-layout .stats-column { max-width: 100%; width: 100% !important; }

  /* LVR shelves multi-select: scrolls sideways inside its track since 2026-09-20
     (a wrapped second row was clipped by the 31px track). */
}

/* ── Phone pass 6 (2026-09-05): the repayment strip ────────────────────────
   A desktop single-line pill (999px radius, dividers, nowrap fields) forced
   to wrap read as a broken pill: label clipped by the round corner, fields
   floating. On phones it becomes a small card: caption on top, the two
   fields side by side as proper input chips. */
@media (max-width: 640px) {
  .calc-inputs-strip {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 8px 10px;
    width: 100% !important;
    border-radius: 12px;
    padding: 10px 12px 12px;
    overflow: visible;
    align-items: stretch;
  }
  .calc-inputs-strip .calc-strip-context { grid-column: 1 / -1; padding: 0; font-size: var(--fs-3xs); color: var(--muted); flex: none; }
  .calc-inputs-strip .calc-field-divider { display: none; }
  .calc-inputs-strip .calc-field {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px;
    padding: 8px 10px; border-radius: 8px; white-space: normal; flex: none;
    background: rgba(127, 140, 170, 0.08); box-shadow: inset 0 0 0 1px var(--border);
  }
  .calc-inputs-strip .calc-field:focus-within { box-shadow: inset 0 0 0 1px var(--accent); }
  .calc-inputs-strip .calc-field-label { flex: 1 1 100%; margin: 0; }
  .calc-inputs-strip .calc-input { width: 7ch; font-size: var(--fs-md); }
  .calc-inputs-strip .calc-input--short { width: 3ch; text-align: left; }
}

/* Phone: the ↺ reset/refresh circles carried the desktop glow and read like a
   second chat launcher next to the search bar. Flat, smaller, quiet. */
@media (max-width: 640px) {
  .btn-circle { --btn-circle-size: var(--ctl-sm); box-shadow: inset 0 0 0 1px var(--border) !important; background: transparent; font-size: var(--fs-base); }
  .btn-circle--sm { --btn-circle-size: 26px; }
}

/* ── Phone pass 7 (2026-09-05): product rows + pagination + page bulk ───────
   24 cards × 308px made the dashboard a 10,000px wall. Each card becomes a
   row: logo, name and tier on the left, rate / comp / monthly beside it on
   the right. The pricing chips (borrowing, term, fees) repeat the calculator
   settings and are dropped on phones; fees live in the detail sheet. */
@media (max-width: 640px) {
  .quote-card-cell > .qc-grid {
    grid-template-columns: 40px minmax(0, 1fr) auto;
    grid-template-areas: "logo info hero";
    gap: 10px;
    padding: 10px 12px;
    align-items: center;
  }
  .qc-logo { width: 40px; height: 40px; border-radius: 9px; }
  .qc-bank-name { font-size: var(--fs-3xs); }
  .qc-product-name { font-size: var(--fs-sm); line-height: 1.2; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .qc-product-row { gap: 4px 6px; }
  .qc-rate-type, .qc-tier-line { font-size: var(--fs-3xs); }
  .qc-cat-pill, .qc-info .badge { font-size: var(--fs-3xs); padding: 1px 6px; }
  .qc-pricing { display: none; }
  .qc-hero { padding-right: 0; gap: 0; border: none; margin: 0; padding-top: 0; text-align: right; align-items: flex-end; }
  .qc-hero-row { gap: 4px; }
  .qc-hero-dual-value { font-size: var(--fs-md); line-height: 1.15; }
  .qc-hero-dual-value--sub { font-size: var(--fs-2xs); }
  .qc-hero-dual-label { font-size: var(--fs-3xs); }
  .qc-hero-divider { display: none; }
  .qc-hero-badge-row, .qc-hero-info { transform: scale(0.85); transform-origin: right center; }
  .qc-hero-value { font-size: var(--fs-md); }
  .qc-hero-label, .qc-hero-unit { font-size: var(--fs-3xs); margin: 0; }
  main table tr { margin-bottom: 8px !important; }

  /* Pagination ran off both edges: "Prev" clipped left, the "Page 1 of 166"
     note squeezed vertically on the right. Prev / current / Next on one row,
     the note underneath. */
  .pagination { flex-wrap: wrap; justify-content: center; gap: 6px; padding: 12px 0 4px; }
  .pagination .page-btn { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .pagination .page-btn:not(.active):not(:first-child):not(:last-child) { display: none; }
  .pagination > :not(.page-btn) { flex: 1 1 100%; text-align: center; font-size: var(--fs-2xs); color: var(--muted); }
  .tracker-layout, .tracker-main { padding-bottom: 0; margin-bottom: 0; }
}
@media (max-width: 640px) {
  /* The trailing "Page x of y" note is the last child, so the Next button is
     second-last; the "…" spacer span is noise on a phone. */
  .pagination .page-btn:nth-last-child(2) { display: inline-flex; }
  .pagination > span:not(:last-child) { display: none; }
}

/* ── Phone pass 8 (2026-09-05): footer bulk ────────────────────────────────
   Two thirds of the footer was air: the "Data updated" line was pushed right
   with 64px padding, the links row carried the chat-launcher clearance, and
   the disclaimer band sat under it all. Tight stack; clearance moves to the
   very end where the launcher actually overlaps. */
@media (max-width: 640px) {
  footer { padding: 22px 20px 6px !important; }
  footer .footer-brand { gap: 4px 10px !important; }
  footer .footer-links { flex-wrap: wrap; gap: 6px 16px; padding-bottom: 0 !important; margin-top: 12px; }
  footer > div[style*="text-align:right"] { text-align: left !important; padding-right: 0 !important; margin-top: 10px; font-size: var(--fs-2xs); color: var(--muted); }
  footer + div { padding: 8px 20px 84px !important; }
}
@media (max-width: 640px) {
  /* Next button lost to a higher-specificity hide rule; dead space between
     the pagination and the footer. */
  .pagination .page-btn:nth-last-child(2) { display: inline-flex !important; }
  .tracker-pagination { margin-bottom: 0; padding-bottom: 0; }
  main .section:last-of-type, main .section:last-child { padding-bottom: 12px !important; }
  main { padding-bottom: 0 !important; margin-bottom: 0 !important; }
}

/* ── Phone pass 9 (2026-09-05): APRA hero two-up ─────────────────────────────
   Inline flex:1 on the KPI cards beat the earlier basis, and the panel is
   only 268px inside its padding, so 140px minimums forced one card per row. */
@media (max-width: 640px) {
  #apra-pulse-inner .pulse-kpi { flex: 1 1 calc(50% - 4px) !important; min-width: 0 !important; }
  #apra-pulse-inner [style*="flex:1;padding:4px 6px"] { flex: 1 1 calc(50% - 4px) !important; min-width: 0 !important; }
  #apra-pulse-inner .pulse-kpi-label { font-size: var(--fs-3xs); }
}

/* ── Phone pass 10 (2026-09-05): APRA institution detail table ──────────────
   Its wrapper is inline overflow-x:hidden and the opt-out's `padding: revert`
   left cells with no padding and the name column at 0px wide. */
@media (max-width: 640px) {
  div:has(> .apra-inner-table) { overflow-x: auto !important; -webkit-overflow-scrolling: touch; }
  .apra-inner-table td, .apra-inner-table th { padding: 6px 8px !important; white-space: nowrap; }
  .apra-inner-table td:first-child, .apra-inner-table th:first-child { min-width: 150px; max-width: 190px; white-space: normal; position: sticky; left: 0; background: var(--bg) !important; z-index: 1; }
}
@media (max-width: 640px) {
  /* table-layout:fixed + a colgroup with no width for the name column = 0px
     name column on phones. Let content size it. */
  .apra-inner-table { table-layout: auto !important; }
  .apra-inner-table td:first-child > span { display: inline-flex; max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
}

/* ── Phone pass 11 (2026-09-05): sideways-scroll affordance ────────────────
   ui.js marks horizontal scrollers .hscroll-fade and toggles .at-end. The
   fade is a mask on the scroller itself, so it stays put while the content
   moves underneath it. */
@media (max-width: 640px) {
  .hscroll-fade:not(.at-end) {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
  }
  /* Table scrollers (2026-09-06): WebKit tints a masked scroll layer, so on
     an iPhone in light mode the fade over the banded rows rendered as a dark
     band down the right of the screen (Chromium fades to white). The tables
     use a mask-free fade instead: the scroller becomes a one-cell grid, the
     table and a sticky gradient share the cell, and the gradient paints the
     page background at the right edge until the row reaches its end. */
  /* `1fr` sized the single track to the scroller's CONTENT BOX, not to its
     scrollable width, and the fade below is a sticky grid item: a sticky box
     can never leave its containing block, so past scrollLeft 0 the fade
     stopped following the right edge and PARKED IN THE MIDDLE OF THE TABLE,
     painting a var(--bg) band straight through the rate columns. That band
     is the "break" readers saw in the LVR grid, and it was latent in every
     phone table scroller (2026-09-08). The track has to span the full scroll
     width, because that is the containing block the sticky fade needs, and
     only `max-content` does it: a `minmax(100%, max-content)` floor keeps the
     track from growing past the container. Content NARROWER than the
     scroller no longer stretches, which costs nothing - ui.js marks that case
     `.at-end`, and an `.at-end` fade is already invisible. */
  .hscroll-wrap.hscroll-fade { -webkit-mask-image: none !important; mask-image: none !important; display: grid !important; grid-template-columns: max-content !important; }
  .hscroll-wrap.hscroll-fade > * { grid-area: 1 / 1; }
  .hscroll-wrap.hscroll-fade::after {
    content: ''; grid-area: 1 / 1; justify-self: end; align-self: stretch; position: sticky; right: 0; z-index: 6;
    width: 36px; pointer-events: none; background: linear-gradient(to right, transparent, var(--bg));
  }
  .hscroll-wrap.hscroll-fade.at-end::after { opacity: 0; }
  /* WebKit tints ANY masked scroll layer, so a table scroller must never
     carry the mask: `.pulse-tt-scroll` was still getting it, which is the
     dark band down the right of Market Pulse in light mode coming back
     (2026-09-08). Same mask-free treatment as `.hscroll-wrap`. */
  .pulse-tt-scroll.hscroll-fade { -webkit-mask-image: none !important; mask-image: none !important; }

  /* LVR heatmap: the frozen lender column, and its collapse on scroll. */
  .lvr-heatmap td:first-child, .lvr-heatmap th:first-child { z-index: 3; }
  .lvr-heatmap .hm-bank-cell, .lvr-heatmap .hm-grouphdr-bank,
  .lvr-heatmap thead th:first-child {
    min-width: 148px !important; max-width: 148px !important;
    transition: min-width 0.18s ease, max-width 0.18s ease;
  }
  .hscroll-moved .lvr-heatmap .hm-bank-cell,
  .hscroll-moved .lvr-heatmap .hm-grouphdr-bank,
  .hscroll-moved .lvr-heatmap thead th:first-child {
    /* 52px held a 10px peer dot AND a 26px logo, so on a 360px Galaxy the
       logo was clipped in half by the frozen edge and read as a second table
       starting underneath (2026-09-08). The dot goes, the logo grows, and
       there is room to breathe on both sides. */
    min-width: 96px !important; max-width: 96px !important;
    padding-left: 6px !important; padding-right: 10px !important;
    /* the word LENDER is wider than the collapsed column and would print
       over the first rate column */
    overflow: hidden !important; text-indent: -999px;
  }
  .hscroll-moved .lvr-heatmap .hm-bank-cell,
  .hscroll-moved .lvr-heatmap .hm-grouphdr-bank { text-indent: 0; }
  /* The heatmap sits in a box with `overflow:auto; max-height:560px`, so on a
     phone it scrolled BOTH ways inside a page that also scrolls. Expand a peer
     group and the table passes 560px: the box starts scrolling vertically, its
     header pins to the box rather than the page, and what you get is a second
     table sliding under a half-sliced header strip - which is exactly what it
     looked like (2026-09-08). A horizontal scroller cannot have visible
     vertical overflow (CSS forces the other axis to auto), so the only fix is
     to let the table be as tall as it wants and give the page the scrolling. */
  #lvr-heatmap-table { max-height: none !important; }
  .hscroll-wrap:has(> .lvr-heatmap), div:has(> .lvr-heatmap) {
    max-height: none !important; overflow-y: visible !important;
  }
  /* A header inside the scroller can never pin to the page: a wrapper with
     overflow-x is a vertical scrollport too, so its sticky thead pins to the
     WRAPPER, which never scrolls. The LVR shelves matter too much to lose on
     the way down, so the page carries a MIRROR of the header row outside the
     scroller (#lvr-sticky-head), pinned to the page and kept in step with
     the table's sideways offset by the page script (2026-09-09). */
  .lvr-heatmap thead th { z-index: 4 !important; }
  .lvr-heatmap thead th:first-child { z-index: 5 !important; }

  /* Column snapping is GONE (2026-09-08). It was added to stop the scroll
     resting on a heat-tinted sliver hard against the frozen panel, but that
     sliver was never the snap position: it was the right-edge fade painting
     a var(--bg) wash mid-table, fixed at its source in the .hscroll-fade
     grid track. With the wash gone the snap bought nothing and cost the one
     thing a wide table needs, which is a scroll that runs smoothly under
     the finger instead of catching at every column. */
  /* 88px columns centred a five-character rate ~20px inside the cell, which
     held the first number well clear of the frozen edge. 76px closes that
     and fits one more column on screen. */
  .lvr-heatmap thead th:not(:first-child), .lvr-heatmap tbody td:not(:first-child) {
    min-width: 76px !important;
  }
  /* a sideways swipe must never hand its momentum on to the page */
  .hscroll-wrap:has(> .lvr-heatmap), div:has(> .lvr-heatmap) { overscroll-behavior-x: none; }

  /* Expanded bank rows carry the logo with the FULL name centred underneath,
     the way the APRA tables print an identity column. Before this the name
     was a single nowrap line that ellipsised on a 148px column and vanished
     altogether on a 96px one, so a reader who opened a peer group got a
     column of logos and "Commonwealth Bank of A..." (2026-09-09). */
  .lvr-heatmap .hm-row .hm-peer-dot { display: none !important; }
  .lvr-heatmap .hm-bank-inner {
    flex-direction: column !important; align-items: center !important; gap: 3px !important;
  }
  .lvr-heatmap .hm-bank-logo-img,
  .lvr-heatmap .hm-bank-logo {
    width: 26px !important; height: 26px !important; margin: 0 auto !important; display: block;
  }
  .lvr-heatmap .hm-bank-inner > div { min-width: 0; max-width: 100%; }
  .lvr-heatmap .hm-bank-name {
    display: block; text-align: center; font-size: var(--fs-3xs) !important; line-height: 1.1;
    white-space: normal !important; overflow: visible !important; text-overflow: clip !important;
    /* never break inside a word: the APRA column learned this the hard way
       with "Commonwealt/h" */
    overflow-wrap: normal; word-break: keep-all; hyphens: manual;
    max-width: 100%; margin: 0 auto;
  }
  /* the peer-group label repeats the group row the reader just expanded */
  .lvr-heatmap .hm-bank-meta { display: none !important; }
  /* The lender count is the number readers look for beside a peer group, and
     hiding it on scroll took it away exactly when the shelves it belongs to
     came into view. It keeps its own second line in the collapsed cell, one
     step smaller so both lines fit the 96px column (2026-09-08). */
  .hscroll-moved .lvr-heatmap .hm-grouphdr-bank > div { flex-wrap: wrap; row-gap: 1px; }
  /* "4 lenders" under a 96px column is mostly the word. The column is headed
     Lender and the row is a peer group, so the number says it (2026-09-09). */
  .lvr-heatmap .hm-grp-count-word { display: none; }
  .hscroll-moved .lvr-heatmap .hm-grp-count {
    /* its own full-width line under the name: sharing the flex row with the
       chevron, the dot and a name like "Macquarie" left ~10px and ellipsised
       the number away, which is no better than hiding it */
    display: block !important;
    flex: 1 0 100%;
    font-size: var(--fs-3xs) !important;
    line-height: 1.15;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .hscroll-moved .lvr-heatmap .hm-grp-label {
    font-size: var(--fs-3xs) !important; line-height: 1.05;
    max-width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .hscroll-moved .lvr-heatmap .hm-grouphdr-bank .hm-chev { margin-right: 2px; }
  .hscroll-moved .lvr-heatmap .hm-grouphdr-bank > div { gap: 2px !important; }
  .hscroll-moved .lvr-heatmap .hm-bank-inner { justify-content: center; gap: 0; }
  /* the frozen edge, the same one every other phone table uses */
  .lvr-heatmap td:first-child::after, .lvr-heatmap th:first-child::after {
    content: ''; position: absolute; top: 0; bottom: 0; right: -10px; width: 12px;
    pointer-events: none;
    background: linear-gradient(to right, var(--pin-edge) 0 2px, var(--pin-shadow) 2px, transparent 100%);
  }

  /* The growth table's first cell is a peer-group NAME with a disclosure
     chevron, not a bank identity with a logo above it, so the phone rule that
     stacks logo-over-name must not apply: it was turning the chevron into a
     centred block on its own line above the group (2026-09-09). */
  /* A GROUP row is a name with a disclosure chevron, so it reads across. */
  #apra-growth-tbody tr[data-action] td:first-child { text-align: left !important; }
  #apra-growth-tbody tr[data-action] td:first-child > span:first-child {
    display: inline !important; text-align: left !important;
    margin: 0 3px 0 0 !important; max-width: none !important; max-height: none !important;
    font-size: inherit !important; line-height: inherit !important;
  }
  /* ...and its ADI count is the number readers look for beside the group. The
     generic rule hides every span after the first, which took it away on
     phones only (2026-09-09). */
  #apra-growth-tbody tr[data-action] td:first-child > span:not(:first-child) {
    display: inline !important; font-size: var(--fs-3xs) !important; color: var(--muted) !important;
  }
  /* A BANK row is an identity, so it keeps the logo-over-name stack the other
     APRA tables use, centred in the pinned column rather than hugging its
     left edge. */
  #apra-growth-tbody tr:not([data-action]) td:first-child { text-align: center !important; }
  #apra-growth-tbody tr:not([data-action]) td:first-child > span:first-child {
    display: block !important; text-align: center !important; margin: 0 auto !important;
  }
  #apra-growth-tbody tr:not([data-action]) td:first-child img {
    display: block !important; margin: 0 auto 3px !important;
  }

  /* a full-width divider row (one td with colspan, 2px tall) is not a bank
     cell: it must not be frozen, widened to 74px or given the edge line */
  main .data-table td[colspan]:first-child, .apra-inner-table td[colspan]:first-child {
    position: static !important; width: auto !important; min-width: 0 !important; max-width: none !important;
    padding: 0 !important; height: 2px !important; box-shadow: none !important;
  }
  main .data-table td[colspan]:first-child::after, .apra-inner-table td[colspan]:first-child::after { content: none !important; }
}

/* ── Phone pass 12 (2026-09-05): launcher out of the way, Pulse rhythm ──── */
@media (max-width: 640px) {
  .ai-fab { transition: transform 0.22s ease, opacity 0.22s ease; }
  .ai-fab.fab-hidden { transform: translateY(140%); opacity: 0; pointer-events: none; }
  .pulse-section { padding: 14px 16px 16px; }
  .pulse-group-title { margin-top: 18px; margin-bottom: 8px; }
}
@media (prefers-reduced-motion: reduce) { .ai-fab { transition: none; } }

/* ── Phone pass 13 (2026-09-05): pinned bank identity on APRA tables ───────
   Scrolling the share and institution tables sideways lost the row's bank.
   The first column now stays put: logo above a two-line short name, opaque
   ground, a soft edge where the numbers slide under it. Scroll wrappers are
   marked by ui.js (.hscroll-wrap) so this does not depend on :has(). */
@media (max-width: 640px) {
  .hscroll-wrap { overflow-x: auto !important; -webkit-overflow-scrolling: touch; }
  main .data-table td:first-child, main .data-table th:first-child,
  .apra-inner-table td:first-child, .apra-inner-table th:first-child {
    position: sticky; left: 0; z-index: 2;
    background: var(--bg) !important;
    width: 68px !important; min-width: 68px !important; max-width: 68px !important;
    padding: 6px 4px !important; white-space: normal !important;
    vertical-align: middle;
  }
  /* The frozen column's edge (2026-09-06). A box-shadow on a collapsed-border
     table cell is never painted (measured: even 6px solid red did not show),
     and a background-image is reset by the stripe rule on even rows. A
     positioned pseudo-element inside the sticky cell paints with the cell,
     above the numbers sliding under it: a 2px line plus a soft shadow, so the
     column reads as a frozen panel rather than logos the data vanishes behind. */
  main .data-table td:first-child::after, main .data-table th:first-child::after,
  .apra-inner-table td:first-child::after, .apra-inner-table th:first-child::after {
    content: ''; position: absolute; top: 0; bottom: 0; right: -10px; width: 12px; pointer-events: none;
    background: linear-gradient(to right, var(--pin-edge) 0 2px, var(--pin-shadow) 2px, transparent 100%);
  }
  main .data-table thead th:first-child, .apra-inner-table thead th:first-child { font-size: var(--fs-3xs) !important; text-align: center !important; }
  main .data-table td:first-child > span:first-child, .apra-inner-table td:first-child > span:first-child {
    display: block !important; text-align: center; font-size: var(--fs-3xs); line-height: 1.1; color: var(--text);
    max-height: 54px; overflow: hidden; max-width: 60px; margin: 0 auto; word-break: break-word;
  }
  main .data-table td:first-child > span:first-child img, .apra-inner-table td:first-child > span:first-child img {
    display: block; width: 26px !important; height: 26px !important; margin: 0 auto 3px; border-radius: 5px;
  }
  /* the count badge / secondary chip after the name is noise at this width */
  main .data-table td:first-child > span:not(:first-child), .apra-inner-table td:first-child > span:not(:first-child) { display: none !important; }
  main .data-table tbody td, .apra-inner-table tbody td { height: 58px; }
}
@media (max-width: 640px) {
  /* pinned identity column, refinement: the peer badge is nested INSIDE the
     name span; legal names need three short lines. */
  main .data-table td:first-child > span:first-child > span, .apra-inner-table td:first-child > span:first-child > span { display: none !important; }
  main .data-table td:first-child > span:first-child, .apra-inner-table td:first-child > span:first-child { font-size: var(--fs-3xs); max-width: 64px; max-height: 62px; overflow-wrap: anywhere; hyphens: auto; }
  main .data-table tbody td, .apra-inner-table tbody td { height: 66px; }
}
@media (max-width: 640px) {
  /* "Commonwealt/h": never break inside a word; give the column the 72px it needs. */
  main .data-table td:first-child, main .data-table th:first-child,
  .apra-inner-table td:first-child, .apra-inner-table th:first-child { width: 74px !important; min-width: 74px !important; max-width: 74px !important; }
  main .data-table td:first-child > span:first-child, .apra-inner-table td:first-child > span:first-child { max-width: 70px; overflow-wrap: normal; word-break: keep-all; hyphens: manual; }
}

/* ── Phone pass 14 (2026-09-05): product sheet header ─────────────────────
   A 140px logo beside a 200px column stacked four action pills one per
   line. Grid: small logo, name and bank beside it, actions in a full-width
   wrapping row underneath. `display: contents` lifts the info wrapper's
   children into the grid without touching the markup. */
@media (max-width: 640px) {
  .prod-modal-identity { display: grid !important; grid-template-columns: 52px minmax(0, 1fr); column-gap: 12px; row-gap: 4px; align-items: start; }
  .prod-modal-identity > .modal-logo, .prod-modal-identity > .bank-logo { grid-column: 1; grid-row: 1 / span 2; width: 52px !important; height: 52px !important; border-radius: 10px; }
  .prod-modal-info { display: contents; }
  .prod-modal-name { grid-column: 2; font-size: var(--fs-md); line-height: 1.2; }
  .prod-modal-inst { grid-column: 2; }
  .prod-actions { grid-column: 1 / -1; margin-top: 6px; gap: 6px; }
  .prod-actions .prod-action-pill { gap: 5px; }
}
@media (max-width: 640px) {
  /* Coverage matrix cards: the segment label (from data-label) sits on its
     own line above the cell's figures. */
  .lvr-cov-matrix td.lvr-cov-cell { flex-wrap: wrap; }
  .lvr-cov-matrix td.lvr-cov-cell::before { flex: 1 1 100%; color: var(--accent) !important; font-weight: 600 !important; }
}
@media (max-width: 640px) {
  /* Fees (name / type / amount) as a wrapping table so the amount is visible
     without scrolling; wider sheet tables keep the sideways scroller. */
  .modal-overlay .modal table.tbl-narrow { display: table !important; width: 100% !important; white-space: normal !important; table-layout: auto; }
  .modal-overlay .modal table.tbl-narrow th, .modal-overlay .modal table.tbl-narrow td { padding: 7px 6px !important; vertical-align: top; white-space: normal !important; }
  .modal-overlay .modal table.tbl-narrow th:nth-child(2), .modal-overlay .modal table.tbl-narrow td:nth-child(2) { font-size: var(--fs-2xs); color: var(--muted); }
  .modal-overlay .modal table.tbl-narrow th:last-child, .modal-overlay .modal table.tbl-narrow td:last-child { text-align: right; white-space: nowrap !important; }
}
@media (max-width: 640px) {
  /* ::before on these cells is the heat stripe (content:""), so the segment
     label rides on ::after, ordered first in the flex row. */
  .lvr-cov-matrix td.lvr-cov-cell::after { content: attr(data-label); order: -1; flex: 1 1 100%; color: var(--accent); font-weight: 600; font-size: var(--fs-2xs); letter-spacing: 0.04em; }
}

/* ── Phone pass 16 (2026-09-05): Product Browser page (reached from a sheet) ── */
@media (max-width: 640px) {
  /* flex-basis was losing to a later `flex` shorthand, so the search sat on
     the same line as the reset button and the row read as three cramped
     things side by side. It gets its own line (2026-09-08). */
  /* the legend (source note + freshness chips) was six flex items squeezed
     into word-per-line columns */
  .cdr-source-note { flex-wrap: wrap; row-gap: 6px; column-gap: 8px; align-items: center; }
}

/* ── Phone pass 17 (2026-09-05): briefing rows; tablet range ───────────────── */
@media (max-width: 640px) {
  /* APRA briefing "the numbers" rows: five inline grid columns (520px) on a
     328px row. Name / value / change on the first line, sparkline and
     year-on-year on a second line. */
  #page-apra-briefing a[style*="grid-template-columns:minmax(130px,1fr)"] {
    grid-template-columns: minmax(0, 1fr) auto auto !important; column-gap: 10px !important; row-gap: 2px !important;
  }
  #page-apra-briefing a[style*="grid-template-columns:minmax(130px,1fr)"] > span:nth-child(4) { grid-column: 1; justify-self: start !important; }
  #page-apra-briefing a[style*="grid-template-columns:minmax(130px,1fr)"] > span:nth-child(5) { grid-column: 2 / -1; justify-self: end; }
}
@media (max-width: 900px) {
  /* Tablets: the repayment strip and the LVR heatmap still overflowed at 768px. */
  .calc-inputs-strip { display: flex; flex-wrap: wrap; width: 100%; max-width: 100%; row-gap: 6px; }
  .calc-strip-context { white-space: normal; }
  .hscroll-wrap { overflow-x: auto !important; -webkit-overflow-scrolling: touch; }
}

/* ── Phone pass 19 (2026-09-06): pinned column keeps the row's band ────────
   The global zebra rule tints even rows; the pinned identity cell painted
   the page ground over it, so in light mode every other row read as a grey
   slab with a white column cut out (operator: "dark shadow on the right").
   The sticky cell must stay opaque, so it layers the same tint over the
   ground instead of replacing it. Same for the header cell. */
@media (max-width: 640px) {
  main .data-table tr:nth-child(even) td:first-child,
  .apra-inner-table tr:nth-child(even) td:first-child {
    background: linear-gradient(var(--zebra-bg), var(--zebra-bg)), var(--bg) !important;
  }
  main .data-table thead th:first-child, .apra-inner-table thead th:first-child {
    background: linear-gradient(var(--thead-bg, transparent), var(--thead-bg, transparent)), var(--bg) !important;
  }
  main .data-table tr:hover td:first-child, .apra-inner-table tr:hover td:first-child {
    background: linear-gradient(var(--zebra-hover), var(--zebra-hover)), var(--bg) !important;
  }
}

/* ── Phone pass 19 (2026-09-06): every clickable state ─────────────────────
   Operator review after pass 18 opened the states the captures had skipped:
   a category filter, Ask AI from the sheet, the APRA Scanner and Quarterly
   tabs, light mode. Fixes below, one block per state. */

/* Short names on the pinned identity column. Tables render both spans;
   desktop shows the legal name, phones the brand/short form. */
.apra-nm-short { display: none; }
@media (max-width: 640px) {
  main .data-table td:first-child > span:first-child > span.apra-nm-short,
  .apra-inner-table td:first-child > span:first-child > span.apra-nm-short {
    display: block !important; font-size: var(--fs-2xs); line-height: 1.15; max-height: 46px; overflow: hidden; font-weight: 500;
  }
  main .data-table td:first-child > span:first-child, .apra-inner-table td:first-child > span:first-child { max-height: none; }
  main .data-table tbody td, .apra-inner-table tbody td { height: 60px; }
}

/* APRA Publication tab pills: three-line wrapped labels become one word each. */
.apra-nav-short { display: none; }
@media (max-width: 640px) {
  .apra-nav-long { display: none; }
  .apra-nav-short { display: inline; }
  #apra-nav-explore, #apra-nav-scan, #apra-nav-qadips { padding: 7px 16px !important; font-size: var(--fs-sm) !important; }
}

/* Quarterly tab: the 2x2 / 3-up chart grids were two columns on a 360px
   screen (right column cut off); one column, and selects never exceed the
   screen. */
@media (max-width: 640px) {
  .apra-chart-grid { grid-template-columns: minmax(0, 1fr) !important; gap: 18px !important; }
  #page-analytics-apra select, #page-apra-briefing select { max-width: 100%; }
}

/* Chat dock header on a phone: title truncates, "New chat" is a round
   icon button, Sign in stays a pill, the close button is never clipped. */
@media (max-width: 640px) {
  .ai-dock--full .ai-dock-header { gap: 8px; padding: 12px 12px 8px 14px; }
  .ai-dock--full .ai-dock-header h3 { font-size: var(--fs-md); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ai-dock--full #ai-new-chat { width: 34px; height: 34px; padding: 0; font-size: 0; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
  .ai-dock--full #ai-new-chat::before { content: '\FF0B'; font-size: var(--fs-md); line-height: 1; color: var(--muted); }
  .ai-dock--full .ai-signin { padding: 5px 11px; font-size: var(--fs-xs); white-space: nowrap; flex-shrink: 0; }
  .ai-dock--full .ai-dock-close { flex-shrink: 0; }
  .ai-dock--full .ai-input { font-size: var(--fs-base); }
}

/* Category sub-filters (Type / Repayment / Purpose / LVR) parked under the
   rail: a card of labelled pill rows instead of the sidebar's 800px list. */
@media (max-width: 640px) {
  .subfilter-inline.subfilter-parked {
    display: flex !important; flex-direction: column; gap: 6px; width: 100%; box-sizing: border-box;
    margin: 8px 0 2px; padding: 8px 0 8px 10px; border: 1px solid var(--border); border-left: 3px solid var(--blue);
    border-radius: 12px; background: var(--glass2); overflow: hidden;
  }
  /* each group is ONE row: label, then its pills scrolling sideways (operator,
     pass 26: the wrapped rows made the card tall; scroll, do not wrap) */
  .subfilter-parked .subfilter-group { flex-direction: row; align-items: center; flex-wrap: nowrap; gap: 8px; min-width: 0; }
  .subfilter-parked .subfilter-group-label { flex: 0 0 auto; min-width: 64px; padding: 0; margin: 0; font-size: var(--fs-3xs); letter-spacing: 0.08em; }
  .subfilter-parked .subfilter-group-pills {
    flex: 1 1 auto; min-width: 0; flex-direction: row; flex-wrap: nowrap; gap: 5px; padding: 1px 12px 1px 0;
    overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
  .subfilter-parked .subfilter-group-pills::-webkit-scrollbar { display: none; }
  .subfilter-parked .subfilter-pill { flex: 0 0 auto; white-space: nowrap; }
  .subfilter-parked .subfilter-pill {
    display: inline-flex !important; align-items: center; width: auto !important; padding: 0 10px !important; height: var(--pill-h) !important;
    border: 1px solid var(--border) !important; border-radius: 999px !important; background: transparent !important;
    color: var(--muted) !important; font-size: var(--pill-fs) !important; line-height: 1;
  }
  /* a parked block that has been emptied (category back to All) must not
     linger as a bare bordered box: the JS drops the class, this is the guard */
  .subfilter-inline.subfilter-parked:empty { display: none !important; }
  .subfilter-parked .subfilter-pill.active { background: var(--blue) !important; color: #fff !important; border-color: var(--blue) !important; }
}

/* LVR Grid side panels on a phone: full-width sheets. The bank drill's offer
   table becomes one card per offer (name line, then shelf / rate / comp as a
   labelled 3-up); the compare grid's stacked cells carry the bank name, which
   the hidden header row used to supply. */
@media (max-width: 640px) {
  #lvr-bank-drill-panel, #lvr-compare-panel { width: 100vw !important; max-width: 100vw !important; padding: 16px 14px 28px !important; box-sizing: border-box; }
  .lvr-drill-table tr { display: grid !important; grid-template-columns: 1fr 1fr 1.6fr; column-gap: 6px; padding: 2px 0 6px; }
  .lvr-drill-table td { display: block !important; border-bottom: none !important; padding: 8px 12px 4px !important; text-align: left !important; }
  .lvr-drill-table td:first-child { grid-column: 1 / -1; padding-bottom: 0 !important; }
  .lvr-drill-table td[data-label]::before { content: attr(data-label); display: block; font-size: var(--fs-3xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 3px; }
  .lvr-drill-table td:nth-child(3) { font-size: var(--fs-base); }
  .lvr-drill-table td:nth-child(2) { color: var(--text) !important; font-size: var(--fs-xs) !important; }
  #lvr-compare-grid td.lvr-cmp-shelf { font-weight: 600; background: var(--glass2); }
  #lvr-compare-grid td[data-label] { justify-content: space-between; align-items: center; }
  #lvr-compare-grid td[data-label]::before { content: attr(data-label); font-size: var(--fs-2xs); color: var(--muted); text-align: left; flex: 1 1 auto; text-transform: none; letter-spacing: 0; font-weight: 500; }
  #lvr-compare-grid .lvr-cmp-val { text-align: right; flex: 0 0 auto; }
}

/* Scanner table on a phone: the two-row header (LENDING / DEPOSITS group
   captions over the column names) left a stray band beside the pinned
   INSTITUTION cell; one header row is enough at this width. */
@media (max-width: 640px) {
  .apra-inner-table thead tr:not(:last-child) { display: none !important; }
}

/* Quote card dimension line (VAR · P&I · OO · 60-80%) on one line; the
   trailing band wrapped onto its own line beside the hero figures. */
@media (max-width: 640px) {
  .quote-card-cell .qc-tier-line { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; letter-spacing: 0; font-size: var(--fs-3xs); word-spacing: -1px; }
}

/* Scanner table: no nested vertical scroller on a phone (a 600px box inside
   the page scroll traps the thumb); the page itself scrolls. */
@media (max-width: 640px) {
  .apra-scan-scroll { max-height: none !important; overflow-y: visible !important; }
}

@media (max-width: 640px) {
  /* drill cards: the zebra tint on individual grid cells read as three
     separate blocks; the card itself is the surface */
  .lvr-drill-table tr:nth-child(even) td, .lvr-drill-table tr:hover td { background: transparent !important; }
}

/* Scanner: the second sticky column (left:240px, a desktop convenience) has
   no place on a 360px screen; it sat mid-screen as a slab. */
@media (max-width: 640px) {
  .apra-inner-table td[style*="left:240px"], .apra-inner-table th[style*="left:240px"] { position: static !important; box-shadow: none !important; }
}

/* The phone layout rule for the calculator strip (display:grid !important)
   was beating the component's own inline display:none, so "Home loan
   repayment" showed under Savings, Term Deposits and FX. Inline none wins. */
@media (max-width: 640px) {
  .calc-inputs-strip[style*="display: none"], .calc-inputs-strip[style*="display:none"] { display: none !important; }
}

/* ── Phone pass 20 (2026-09-06): scanner rows read as one table ───────────
   Group rows were shouting (uppercase bold, count on its own line, their own
   band fighting the zebra), and the GROUP column repeated "Big 4" down the
   screen next to rows already grouped under a Big 4 heading. On phones the
   peer-group column is dropped, group rows use sentence case with the count
   inline, and every cell in a group row shares one band. */
@media (max-width: 640px) {
  .apra-scan-scroll [data-col="peer_group"] { display: none !important; }
  .apra-scan-scroll .apra-scan-group td { background: transparent !important; border-top: none !important; border-bottom: none !important; }
  .apra-scan-scroll tr.apra-scan-group { background: var(--subtle) !important; }
  /* the group stripe is a background, not a border: a border-left on a
     sticky cell of a collapsed-border table shifts the cell's paint and let
     the neighbouring bold number leak into the page gutter (2026-09-06) */
  .apra-scan-scroll .apra-scan-group td:first-child {
    border-left: 0 !important;
    background: linear-gradient(to right, rgb(128, 128, 128) 0 3px, transparent 3px), linear-gradient(var(--subtle), var(--subtle)), var(--bg) !important;
  }
  .apra-scan-scroll .apra-scan-group-name {
    text-transform: none !important; letter-spacing: 0 !important; font-size: var(--fs-2xs) !important; font-weight: 600 !important;
    white-space: normal !important; line-height: 1.2; text-align: left !important;
  }
  .apra-scan-scroll .apra-scan-group-name { font-size: var(--fs-2xs) !important; }
  .apra-scan-scroll .apra-scan-group-count { display: block !important; margin: 2px 0 0 !important; font-size: var(--fs-3xs) !important; font-weight: 400 !important; }
  .apra-scan-scroll .apra-scan-group-count::after { content: ' ADIs'; }
  .apra-scan-scroll .apra-scan-group-count[data-n="1"]::after { content: ' ADI'; }
  .apra-scan-scroll .apra-inner-table tbody td { height: 56px; }
}

/* Footer disclaimer wording follows the page (2026-09-06): APRA pages show
   statistics, not CDR product data. app.js stamps body[data-page]. */
.disc-apra { display: none; }
body[data-page="analytics-apra"] .disc-cdr, body[data-page="apra-briefing"] .disc-cdr { display: none; }
body[data-page="analytics-apra"] .disc-apra, body[data-page="apra-briefing"] .disc-apra { display: inline; }

/* Table header band on phones (2026-09-06): the institution detail header
   cells carry an inline var(--surface2) band while the pinned first cell was
   painted with the page ground, so the band read as a strip floating over
   the rows. One band for every header cell, pinned or not. */
@media (max-width: 640px) {
  main .data-table thead th, .apra-inner-table thead th { background: var(--surface2) !important; }
  main .data-table thead th:first-child, .apra-inner-table thead th:first-child { background: var(--surface2) !important; }
}

/* ── Phone pass 21 (2026-09-06): LVR Grid toolbar as a labelled form ──────
   Fifteen controls in a wrapping flex row landed as a ragged two-column
   jumble. On phones each control is one row: a fixed 74px label column and
   the control filling the rest, in a deliberate order (segment first, then
   view, then advanced), with the compare CTA and reset last. */
@media (max-width: 640px) {
  .lvr-toolbar .lvr-toolbar-controls { display: flex !important; flex-direction: column; align-items: stretch !important; gap: 8px !important; }
  .lvr-toolbar .lvr-ctrl { display: grid !important; grid-template-columns: 74px minmax(0, 1fr); align-items: center; column-gap: 8px; width: 100%; }
  .lvr-toolbar .lvr-ctrl .lvr-ctrl-label { font-size: var(--fs-3xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
  .lvr-toolbar .lvr-ctrl select, .lvr-toolbar .lvr-ctrl input[type="search"] { width: 100% !important; min-width: 0 !important; max-width: none !important; box-sizing: border-box; }
  .lvr-toolbar .lvr-ctrl-comp { grid-template-columns: auto minmax(0, 1fr); font-size: var(--fs-xs); padding-top: 2px; }
  .lvr-toolbar .lvr-ctrl-spacer { display: none; }
  .lvr-toolbar .lvr-ctrl-compare { width: 100%; justify-content: flex-start; padding-top: 4px; }
  .lvr-toolbar .lvr-ctrl-compare > * { max-width: 100%; }
  .lvr-toolbar .lvr-ctrl-reset { align-self: flex-end; }
  .lvr-toolbar .lvr-ctrl-purpose { order: 1; } .lvr-toolbar .lvr-ctrl-repay { order: 2; } .lvr-toolbar .lvr-ctrl-rate { order: 3; }
  .lvr-toolbar .lvr-ctrl-loan { order: 4; } .lvr-toolbar .lvr-ctrl-topn { order: 5; }
  .lvr-toolbar .lvr-ctrl-display { order: 6; } .lvr-toolbar .lvr-ctrl-group { order: 7; } .lvr-toolbar .lvr-ctrl-focus { order: 8; } .lvr-toolbar .lvr-ctrl-search { order: 9; }
  .lvr-toolbar .lvr-ctrl-frontier { order: 10; } .lvr-toolbar .lvr-ctrl-xrange { order: 11; } .lvr-toolbar .lvr-ctrl-niche { order: 12; } .lvr-toolbar .lvr-ctrl-shelves { order: 13; } .lvr-toolbar .lvr-ctrl-comp { order: 14; }
  .lvr-toolbar .lvr-ctrl-compare { order: 15; } .lvr-toolbar .lvr-ctrl-reset { order: 16; }
}

/* Pinned identity column edge (phones): with the header band now shared by
   the pinned cell, its right edge had vanished, so a header cell sliding
   underneath read as running into the INSTITUTION label. A hairline plus a
   left-aligned label restore the boundary. */
@media (max-width: 640px) {
  main .data-table td:first-child, main .data-table th:first-child,
  .apra-inner-table td:first-child, .apra-inner-table th:first-child { border-right: 1px solid var(--border) !important; }
  main .data-table thead th:first-child, .apra-inner-table thead th:first-child { text-align: left !important; letter-spacing: 0.04em !important; padding-left: 6px !important; }
}

/* Sign in lives in the top bar on phones too (operator, 2026-09-06): a
   compact pill between the theme toggle and the menu; the drawer keeps its
   own. The avatar takes the same slot once signed in. */
@media (max-width: 640px) {
  /* display without !important: the sign-in code hides this pill inline once signed in, and inline must win */
  nav #nav-login-btn.btn-login { display: inline-flex; align-items: center; height: var(--ctl-sm); padding: 0 12px !important; font-size: var(--ctl-fs-sm) !important; line-height: 1; white-space: nowrap; box-shadow: none !important; transform: none !important; }
  nav #nav-user-area { margin-left: 0; }
}

/* Phone top bar: Sign In needs the theme toggle's slot (menu button was
   12px off-screen at 360px). The toggle moves into the drawer. */
@media (max-width: 640px) {
  nav #theme-toggle { display: none !important; }
  nav > div { gap: 8px !important; }
}
.nav-link-theme { display: none; }
@media (max-width: 640px) { .nav-drawer .nav-link-theme { display: block; } }

/* Phone top bar: the right cluster (Sign In, menu) hugs the right edge; on
   desktop the nav links between logo and cluster do that job. */
@media (max-width: 640px) {
  nav > div:last-child { margin-left: auto; }
  nav .nav-logo { min-width: 0; flex-shrink: 1; }
}

/* "View desktop site" / "Back to mobile view" in the footer. Shown by
   viewport.js on phone-sized screens only; a quiet underlined line. */
.desktop-switch { background: none; border: 0; padding: 0; margin: 0; color: var(--muted); font: inherit; font-size: var(--fs-2xs); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.desktop-switch:hover { color: var(--text); }
@media (max-width: 640px) { footer .desktop-switch { display: block; margin-top: 6px; } footer .desktop-switch[hidden] { display: none; } }

/* ── Phone pass 22 (2026-09-06) ────────────────────────────────────────────
   1. Pinned identity column must win the stacking order. The institution
      detail header cells carry inline position:sticky;top:0;z-index:1 for
      the desktop scroll box; the pinned first cell got the same z-index
      from that inline style, so a header cell sliding beneath it painted
      on top ("LENDING goes over INSTITUTION" on a real phone). !important
      beats inline here; the body cells get the same treatment. */
@media (max-width: 640px) {
  main .data-table td:first-child, main .data-table th:first-child,
  .apra-inner-table td:first-child, .apra-inner-table th:first-child { position: sticky !important; left: 0 !important; z-index: 4 !important; }
  main .data-table thead th:first-child, .apra-inner-table thead th:first-child { z-index: 5 !important; }
  main .data-table thead th:not(:first-child), .apra-inner-table thead th:not(:first-child) { z-index: 1 !important; }
}
/* 2. LVR toolbar: no grey segmented-control troughs on phones; the pills
      are plain chips like the explorer's sub-filters, active one blue. */
@media (max-width: 640px) {
  .lvr-toolbar .lvr-ctrl select, .lvr-toolbar .lvr-ctrl input[type="search"] { border: 1px solid var(--border) !important; background: transparent !important; border-radius: 999px !important; padding: 0 14px !important; height: var(--pill-h) !important; font-size: var(--pill-fs) !important; line-height: 1; }
}

/* ── Phone pass 23 (2026-09-06): one control language on phones ──────────
   Option sets are chips (active = blue fill); long lists stay selects but
   drawn as hairline pills; text inputs match; secondary actions are
   outlined pills. Desktop untouched. Selectors key on the ids, classes and
   inline tokens the controls already carry (active states are expressed
   inline as var(--blue) / var(--subtle-active), or by .active). */
@media (max-width: 640px) {
  /* ONE pill size on phones (2026-09-06): the LVR toolbar's chips are the
     reference. Every chip, select, input and secondary action below reads
     these tokens, so a change here moves the whole app together. */
  :root { --pill-h: 31px; --pill-fs: var(--fs-xs); --pill-px: 12px; --sticky-bar-h: 38px; }
  /* selects and text inputs on the data pages */
  #page-dashboard select, #page-analytics-apra select, #page-apra-briefing select, #page-market-pulse select,
  #page-analytics-apra input[type="text"], #page-analytics-apra input[type="search"], #apra-share-inst-input, #apra-scan-search {
    background: transparent !important; color: var(--text) !important; border: 1px solid var(--border) !important;
    border-radius: 999px !important; padding: 0 14px !important; height: var(--pill-h) !important; font-size: var(--pill-fs) !important; line-height: 1; box-sizing: border-box; max-width: 100%;
  }
  #page-analytics-apra select { padding-right: 30px !important; }



  /* secondary action on the home page */
  #page-dashboard .charts-toggle-pill { border-radius: 999px !important; text-transform: none !important; letter-spacing: 0 !important; }

  /* LVR compare panel segment tabs */
  #lvr-compare-tabs .lvr-cmp-tab { border: 1px solid var(--border) !important; border-radius: 999px !important; padding: 0 var(--pill-px) !important; height: var(--pill-h) !important; display: inline-flex !important; align-items: center; font-size: var(--pill-fs) !important; line-height: 1; background: transparent !important; color: var(--muted) !important; }
  #lvr-compare-tabs .lvr-cmp-tab[style*="var(--blue)"] { background: var(--blue) !important; color: #fff !important; border-color: var(--blue) !important; }
}

/* pass 23, second sweep: pill groups that use classes instead of the inline
   radius (category tabs, lens pills, timeframe pills, wholesale pills,
   growth sections), and the home page select whose fixed 26px height
   clipped the text and hid its chevron. */
@media (max-width: 640px) {
  /* selects: consistent height and a chevron even where appearance was reset */
  #page-dashboard select, #page-analytics-apra select, #page-apra-briefing select, #page-market-pulse select {
    height: var(--pill-h) !important; line-height: 1.25 !important; -webkit-appearance: none; appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b94a7' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") !important;
    background-repeat: no-repeat !important; background-position: right 12px center !important; background-size: 12px !important; padding-right: 32px !important;
  }
}


/* ── Phone pass 24 (2026-09-06): drawer hierarchy, category chips ─────────
   Headings (AI Chat, Analytics) and items looked alike; items now carry a
   chevron and more weight, headings are small caps with breathing room.
   Signed-in visitors see Account settings and Sign out instead of Sign in. */
@media (max-width: 640px) {
  .nav-drawer .nav-dd-section { font-size: var(--fs-3xs) !important; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); padding: 14px 16px 4px !important; opacity: 0.9; }
  .nav-drawer .nav-link { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px !important; font-size: var(--fs-base) !important; color: var(--text); }
  .nav-drawer .nav-link::after { content: '\203A'; color: var(--muted); font-size: var(--fs-lg); line-height: 1; margin-left: 12px; }
  .nav-drawer .nav-link.nav-dd-cta::after { color: var(--blue); }
  .nav-drawer .nav-link[hidden] { display: none !important; }
  .nav-drawer .nav-link { border-radius: 10px; }
  .nav-drawer .nav-link.active { background: var(--nav-active-bg); }
  nav .nav-alerts { display: none; }
  /* the Product Explorer category rail and specialist pills join the chip language */
  #page-dashboard .tracker-filter-pills .filter-pill, #page-dashboard .tracker-filter-bar .filter-pill:not(.subfilter-pill) {
    background: transparent !important; border: 1px solid var(--border) !important; color: var(--muted) !important; border-radius: 999px !important;
    padding: 0 var(--pill-px) !important; height: var(--pill-h) !important; min-height: 0 !important; display: inline-flex !important; align-items: center;
    font-size: var(--pill-fs) !important; font-weight: 500 !important; line-height: 1; box-shadow: none !important;
  }
  #page-dashboard .tracker-filter-pills .filter-pill.active, #page-dashboard .tracker-filter-bar .filter-pill.active:not(.subfilter-pill) {
    background: var(--blue) !important; color: #fff !important; border-color: var(--blue) !important;
  }
  #page-dashboard .tracker-filter-bar .filter-pill.active:not(.subfilter-pill) svg { color: #fff; stroke: #fff; }
}

/* Monthly Briefing modal on phones: a full-screen sheet, not a 40px-inset
   card; the number rows use the briefing page's phone layout (value and
   change on the first line, sparkline and marker beneath); any table inside
   scrolls sideways within the sheet instead of pushing past it. */
@media (max-width: 640px) {
  #apra-briefing-modal { padding: 0 !important; align-items: stretch !important; backdrop-filter: none !important; }
  #apra-briefing-card { width: 100vw !important; max-width: 100vw !important; min-height: 100dvh; max-height: none !important; border-radius: 0 !important; margin: 0 !important; padding: 0 0 40px !important; box-sizing: border-box; overflow-x: hidden; }
  #apra-briefing-card a[style*="grid-template-columns:minmax(130px,1fr)"] {
    grid-template-columns: minmax(0, 1fr) auto auto !important; column-gap: 10px !important; row-gap: 2px !important;
  }
  #apra-briefing-card a[style*="grid-template-columns:minmax(130px,1fr)"] > span:nth-child(4) { grid-column: 1; justify-self: start !important; }
  #apra-briefing-card a[style*="grid-template-columns:minmax(130px,1fr)"] > span:nth-child(5) { grid-column: 2 / -1; justify-self: end; }
  #apra-briefing-card table { display: block; max-width: 100%; overflow-x: auto; white-space: nowrap; }
  #apra-briefing-card select { border: 1px solid var(--border) !important; border-radius: 999px !important; background: transparent !important; padding: 7px 30px 7px 14px !important; }
  #apra-briefing-card svg { max-width: 100%; height: auto; }
}

/* Briefing sheet: the close control sat on top of the month picker at 360px.
   It becomes a round button in its own row above the header. */
@media (max-width: 640px) {
  #apra-briefing-card { padding-top: 62px !important; }
  #apra-briefing-close { top: 12px !important; right: 12px !important; width: 38px; height: 38px; border: 1px solid var(--border) !important; border-radius: 50% !important; display: flex; align-items: center; justify-content: center; font-size: var(--fs-lg) !important; background: var(--glass2) !important; }
}

/* Phone, Rate Activity header (2026-09-06, operator, two rounds): the
   "Show 30-day charts" pill first wrapped onto its own line as a glowing
   primary-looking action; the first fix docked it absolutely and it then ran
   under the longer "no new changes today · checked 6h ago" meta text and sat
   18px right of, and 2px shorter than, the category select. Now the header
   is a two-row grid on phones: row 1 = pulse · title · select, row 2 = meta
   text (left, wraps inside its own column) · the charts chip (right). The
   select and the chip share column 3 and one size, so their right edges and
   heights line up; nothing can overlap. Chevron carries open/closed state;
   the visible label is "30-day charts", the full label stays for screen
   readers; the "· " separator is dropped because the meta stacks. */
@media (max-width: 640px) {
  #page-dashboard .feed-header { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; column-gap: 8px; row-gap: 8px; align-items: center; }
  #page-dashboard .feed-header-row, #page-dashboard .feed-header-meta { display: contents; }
  #page-dashboard .feed-pulse { grid-column: 1; grid-row: 1; }
  #page-dashboard .feed-title { grid-column: 2; grid-row: 1; }
  #page-dashboard .feed-cat-select { grid-column: 3; grid-row: 1; justify-self: end; }
  /* row 2 = the week count across the full width (it needs ~150px and would wrap beside the chip);
     row 3 = the shorter freshness line on the left with the chip beside it */
  #page-dashboard .feed-week-count { grid-column: 1 / 4; grid-row: 2; align-self: end; }
  #page-dashboard .feed-updated { grid-column: 1 / 3; grid-row: 3; align-self: center; }
  /* the meta line is nowrap on desktop; in its own grid column it must wrap or it runs under the chip */
  #page-dashboard .feed-week-count, #page-dashboard .feed-updated { white-space: normal; min-width: 0; overflow-wrap: anywhere; }
  #page-dashboard .feed-week-count:not(:empty) + .feed-updated:not(:empty)::before { content: none; }
  #page-dashboard .charts-toggle-pill {
    grid-column: 3; grid-row: 3; justify-self: end; align-self: center;
    height: var(--pill-h) !important; padding: 0 12px 0 14px !important; gap: 6px !important;
    border-radius: 999px !important; background: transparent !important;
    color: var(--text) !important; animation: none !important;
    /* soft, static version of the desktop glow (operator: it should still slightly glow) */
    box-shadow: inset 0 0 8px rgba(var(--green-rgb), 0.16), 0 0 0 1px rgba(var(--green-rgb), 0.55) !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
    font-size: var(--pill-fs) !important; font-weight: 400 !important; letter-spacing: 0 !important; text-transform: none !important;
  }
  #page-dashboard .charts-toggle-pill[aria-expanded="true"] { box-shadow: inset 0 0 10px rgba(var(--green-rgb), 0.24), 0 0 0 1px rgba(var(--green-rgb), 0.7) !important; }
  #page-dashboard .charts-toggle-pill::before { content: "30-day charts"; }
  #page-dashboard #charts-toggle-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* ── Phone selection: compare on a 360px screen (2026-09-07) ───────────────
   The compare rail does not fit, so it stays hidden; hiding the per-row
   toggle with it left cards that could be selected but did nothing. The
   toggle is a labelled chip on the card, and a dock appears once something
   is selected. Long-press a card does the same thing for readers who expect
   it; the chip is the affordance, the long-press is the shortcut. */
@media (max-width: 640px) {
  /* No per-card chip: it cost a row of card height (operator, 2026-09-07).
     Long-press selects, the card outline says which are selected, and the
     dock says what you can do with them. */
  .qc-compare-wrap { display: none !important; }
  .quote-card-cell > .qc-grid:has(.compare-checkbox:checked) {
    box-shadow: inset 0 0 0 2px var(--blue), var(--elev-1);
    background: color-mix(in srgb, var(--blue) 8%, var(--surface));
  }
  /* one sticky bar carries the section name and the gesture, so the reader
     always knows where they are and what a swipe does (2026-09-07) */
  /* the section name pins first; the swipe note keeps its own place above
     the list and pins directly beneath it (2026-09-07) */
  /* The bar's height and the note's offset were set independently, so the
     note pinned 8px below the bar and a strip of the list scrolled through
     the gap. One variable now drives both (2026-09-07). */
  .cmp-sticky-m {
    position: sticky; top: 64px; z-index: 20;
    display: flex; align-items: center;
    height: var(--sticky-bar-h);
    background: var(--bg); padding: 0 2px; box-shadow: 0 1px 0 var(--border);
  }
  .cmp-sticky-title {
    font-family: 'Instrument Serif', Georgia, serif; font-size: var(--fs-xl);
    color: var(--text); line-height: 1.1;
  }
  .cmp-hint-m {
    position: sticky; top: calc(64px + var(--sticky-bar-h)); z-index: 19;
    display: block; font-size: var(--fs-2xs); font-weight: 600; color: var(--muted);
    background: var(--bg); padding: 6px 2px; letter-spacing: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    box-shadow: 0 1px 0 var(--border);
  }
  /* the heading inside the filter bar would repeat the sticky one */
  #page-dashboard .tracker-pretitle .section-title { display: none; }
  /* section-heading pinning now lives at the end of this file: it applies
     at every width, not only on phones (2026-09-07). */

  .compare-dock-m {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    display: flex; align-items: center; gap: 8px;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--bg); border-top: 1px solid var(--border);
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.28);
  }
  .compare-dock-m[hidden] { display: none !important; }
  .cdm-count { font-size: var(--fs-xs); color: var(--text); font-weight: 600; margin-right: auto; white-space: nowrap; }
  .cdm-btn {
    height: var(--pill-h); padding: 0 var(--pill-px); border-radius: 999px; border: 1px solid var(--blue);
    background: var(--blue); color: #fff; font-size: var(--pill-fs); font-weight: 500; line-height: 1; white-space: nowrap;
  }
  .cdm-btn[disabled] { opacity: 0.45; }
  .cdm-btn.cdm-ai { background: transparent; color: var(--text); border-color: var(--border); }
  .cdm-clear {
    height: var(--pill-h); width: var(--pill-h); border-radius: 999px; border: 1px solid var(--border);
    background: transparent; color: var(--muted); font-size: var(--fs-xs); line-height: 1;
  }
  /* the dock must not sit on top of the last card */
  body.has-compare-dock #page-dashboard { padding-bottom: 64px; }
}
/* Desktop keeps the rail; the dock and the hint are phone-only. */
@media (min-width: 641px) { .compare-dock-m, .cmp-sticky-m, .cmp-hint-m { display: none !important; } }

/* ── Scanner bank detail on a phone (2026-09-07) ───────────────────────────
   Opening a bank put two tables side by side in 360px, so both were clipped
   and every label wrapped; the chart's legend took three full-width rows.
   The tables stack, the panel keeps less of its desktop indent, and the
   chart gets the height the legend was using. */
@media (max-width: 640px) {
  .apra-scan-detail-cols { grid-template-columns: 1fr !important; gap: 14px !important; }
  .apra-scan-detail-body { padding-left: 12px !important; padding-top: 14px !important; padding-bottom: 14px !important; }
  .apra-scan-detail-body table { width: 100%; }
  /* each table scrolls in its own lane: squeezing six columns into the
     column width broke numbers across lines ("939." / "7") */
  .apra-scan-detail-cols > div { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .apra-scan-detail-cols > div::-webkit-scrollbar { height: 0; }
  .apra-scan-detail-body table { table-layout: auto; width: max-content; min-width: 100%; }
  .apra-scan-detail-body table td, .apra-scan-detail-body table th { white-space: nowrap !important; font-size: var(--fs-2xs); padding: 5px 7px !important; }
  .apra-scan-detail-chart-wrap { height: 260px !important; }
}

/* ── Compare on a phone: five products must all be reachable (2026-09-07) ──
   The comparison card is a grid of a 132px label column plus one column per
   product. At 360px five products needed 479px inside a 262px box, and the
   card clipped the overflow with no scroll, so products three to five simply
   could not be reached. The card scrolls sideways, the label column stays
   put, and each product column gets a readable fixed width. */
@media (max-width: 640px) {
  .cs-card { overflow-x: auto !important; -webkit-overflow-scrolling: touch; padding: 14px 12px 12px !important; }
  /* the decorative 1px offset makes .cs-card a containing block, which stops
     the label column sticking while the products scroll under it */
  .cs-card:nth-child(odd), .cs-card:nth-child(even) { transform: none !important; }
  .cs-card::-webkit-scrollbar { height: 0; }
  /* header row and every spec row share one column ruler so they scroll as
     one; .cs-card is the single scroller, so the rows stay in step */
  .cs-card-cols, .cs-card-row {
    grid-template-columns: 96px !important;
    grid-auto-flow: column !important;
    grid-auto-columns: 108px !important;
    gap: 8px !important;
    /* the row must be as wide as its content: a row stretched to the visible
       width becomes the sticky label's containing block and the label stops
       part-way (measured: it stuck 196px of a 382px scroll) */
    width: max-content; min-width: 100%;
  }
  .cs-card-cols > :first-child, .cs-card-rowlabel {
    position: sticky; left: 0; z-index: 6;
    /* .cs-card is glass, so var(--surface) let the numbers show through the
       pinned label; the page ground is the only reliably opaque token here */
    /* the card's left padding scrolls with the content, so the first product
       column showed in the 12px strip beside the label: extend the label's
       ground into it with a solid shadow rather than moving the box */
    background: var(--bg); box-shadow: -14px 0 0 var(--bg), 6px 0 8px -6px var(--pin-shadow);
    padding-right: 6px;
  }
  .cs-card-section-head { position: sticky; left: 0; }
  .cs-card-head { position: sticky; left: 0; width: max-content; }
  .cs-card-col-head { font-size: var(--fs-2xs); }
}

/* ── Compare modal on a phone: the site's responsive type step ─────────────
   The modal used one fixed scale at every width while the rest of the site
   steps down on phones (2026-09-07). */
@media (max-width: 640px) {
  .cs-card-title { font-size: var(--fs-md); }
  .cs-card-rowlabel { font-size: var(--fs-3xs); letter-spacing: 0.06em; }
  .cs-card-brand { font-size: var(--fs-2xs); }
  .cs-card-name { font-size: var(--fs-2xs); }
  .cs-card-cell { font-size: var(--fs-xs); }
  .cs-card-note, .compare-note { font-size: var(--fs-2xs); }
  /* the LVR pills join the one phone pill size */
  .cmp-lvr-pill { height: var(--pill-h); padding: 0 var(--pill-px) !important; font-size: var(--pill-fs) !important; line-height: 1; }
}

/* ── Long-press must not select text (2026-09-07) ─────────────────────────
   Holding a product to compare put the phone into text-selection mode and
   raised the copy bar. Selection is off on the product rows only; the rest
   of the page still copies normally. */
@media (max-width: 640px) {
  #page-dashboard tr.quote-card, #page-calc tr.quote-card,
  #page-dashboard .quote-card-cell, #page-calc .quote-card-cell {
    -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  }
}

/* ── The compare hint reads as an invitation (2026-09-07) ─────────────────
   First version animated a gradient through background-clip:text with a
   transparent fill. WebKit painted nothing, so the note was invisible on the
   phones it was written for. The text is a solid colour now and a soft
   highlight travels beneath it left to right: the words can never disappear,
   whatever the paint does. */
@media (max-width: 640px) {
  .cmp-hint-m { color: var(--muted); overflow: hidden; }
  .cmp-hint-m::after {
    content: ''; position: absolute; left: 0; bottom: 3px; width: 52px; height: 2px; border-radius: 2px;
    background: linear-gradient(90deg, transparent, var(--blue), transparent);
    opacity: 0.85; animation: cmp-hint-sweep 3.4s ease-in-out infinite;
  }
}
@keyframes cmp-hint-sweep { from { transform: translateX(-60px); } to { transform: translateX(340px); } }
@media (prefers-reduced-motion: reduce) { .cmp-hint-m::after { animation: none; opacity: 0; } }

/* Minimising the chat on phones used a 34px circle with a drawn chevron;
   since 2026-09-18 it is the same 32px square as every other close. */

/* ── Swipe to compare: the card follows the finger (2026-09-07) ────────────
   pan-y keeps vertical scrolling native while the horizontal gesture reaches
   the handler. The tint tells you which way the swipe is going before you
   let go: blue to add, muted to remove. */
@media (max-width: 640px) {
  #page-dashboard tr.quote-card { touch-action: pan-y; }
  .quote-card-cell > .qc-grid.sw-add {
    box-shadow: inset 0 0 0 2px var(--blue), var(--elev-1);
    background: color-mix(in srgb, var(--blue) 10%, var(--surface));
  }
  .quote-card-cell > .qc-grid.sw-del {
    box-shadow: inset 0 0 0 2px var(--border), var(--elev-1);
    background: color-mix(in srgb, var(--muted) 10%, var(--surface));
  }
}

/* ── A light travels around the Ask AI pill's border (2026-09-07) ─────────
   Two earlier attempts were wrong: a filled cone swept like a lighthouse
   beam, and masking it to a ring but ROTATING the element drew a diagonal
   line, because rotating a wide pill's box swings its corners outside the
   mask. The angle of the gradient is animated instead, so the box never
   moves and only a bright arc travels around the border. */
@property --omi-ring {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}
.cdm-ai, .compare-basket-askai { position: relative; isolation: isolate; }
.cdm-ai::after, .compare-basket-askai::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 2px; pointer-events: none;
  background: conic-gradient(from var(--omi-ring),
    transparent 0deg, transparent 244deg,
    rgba(var(--green-rgb), 0.3) 280deg, var(--blue) 318deg, #a5c8ff 340deg, var(--blue) 352deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  animation: omi-ring-travel 2.8s linear infinite;
}
@keyframes omi-ring-travel { to { --omi-ring: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  .cdm-ai::after, .compare-basket-askai::after { animation: none; }
}

/* APRA section headings, formerly inline-styled with no hook (2026-09-07) */
.apra-sec-head {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--fs-xl); font-weight: 400; color: var(--text);
  padding: 18px 0 10px; margin: 8px 0 14px;
}
@media (max-width: 640px) {
  .apra-sec-head {
    font-size: var(--fs-md); padding: 10px 0 8px; margin: 4px 0 8px;
    /* the tab row above says which part of the publication you are in, so a
       section heading pins beneath it rather than over it (2026-09-07) */
    position: sticky; top: 110px; z-index: 17; background: var(--bg);
  }
  main .apra-nav-row { padding: 6px 0 !important; margin-bottom: 8px !important; }
}

/* ── The Market Pulse table treatment, applied elsewhere (2026-09-07) ──────
   The Pulse tables read cleanly because of four things, not their markup:
   small uppercase Inter headers, monospace tabular numerals right-aligned,
   labels in Inter at a size that matches the numerals optically, and one
   fixed row height so every row lines up. Those four are applied here to the
   compare modal and the APRA tables, which keep their own pinned-column
   structure (splitting them into two tables would risk rows drifting apart
   wherever a value wraps). */

/* Compare modal */
.cs-card-rowlabel {
  /* Pulse puts its row labels in sentence case at a readable size and saves
     uppercase for the column headers; the first attempt had that backwards */
  font: 500 var(--fs-xs) 'Inter', system-ui, sans-serif !important;
  letter-spacing: 0 !important; text-transform: none !important;
  color: var(--muted); text-align: left;
}
.cs-card-cell {
  /* these cells mix figures and words ("Principal And Interest"), so the text
     face stays and only the digits are made to line up column to column */
  font: 500 var(--fs-xs) 'Inter', system-ui, sans-serif;
  font-variant-numeric: tabular-nums; font-feature-settings: 'tnum';
  color: var(--text);
}

/* APRA tables: figures line up column to column */
main .apra-inner-table tbody td:not(:first-child),
main .data-table tbody td:not(:first-child) {
  font-family: var(--font-mono);
  font-feature-settings: 'tnum';
  font-variant-numeric: tabular-nums;
}
/* The LVR grid's tables are the same kind of object as Market Pulse's, so
   they take the same label weight: Pulse sets 500 on the row labels, which
   is what makes a name read as a label rather than as body text (2026-09-08). */
main .lvr-heatmap tbody td:first-child,
main .lvr-drill-table tbody td:first-child,
main .lvr-cov-matrix tbody td:first-child { font-weight: 500; }

main .apra-inner-table thead th, main .data-table thead th {
  font: 600 var(--fs-3xs) 'Inter', system-ui, sans-serif;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}

/* ── Compare rows read as one panel, the way Pulse does (2026-09-07) ───────
   Pulse has no gaps: rows butt together, separated by a hairline that runs
   the full width, with a vertical rule between the label column and the
   figures. The compare grid had 8px gaps, which broke it into floating
   tiles. */
@media (max-width: 640px) {
  .cs-card-cols, .cs-card-row { gap: 0 !important; }
  .cs-card-row > * {
    border-bottom: 1px solid var(--border);
    padding: 8px 8px; min-height: 38px; display: flex; align-items: center;
  }
  .cs-card-row > :first-child { justify-content: flex-start; }
  .cs-card-row > :not(:first-child) { justify-content: center; text-align: center; }
  /* the vertical rule between labels and figures, as in Pulse */
  /* Pulse's label column is a panel one step LIGHTER than the page, with a
     right edge and a shadow. Ours was var(--bg), which on a glass card read
     as a black slab beside the figures (2026-09-07). */
  .cs-card-cols > :first-child, .cs-card-rowlabel, .cs-card-row > :first-child {
    background: #1b1d22 !important;
    border-right: 1px solid rgba(255, 255, 255, 0.06);
    /* TWO shadows, and the first one is not decoration: the card's left
       padding scrolls with the content, so without a ground extended into it
       the product columns slide out past the pinned label and show in the
       gutter. Recolouring this panel replaced the earlier -14px ground and
       reopened exactly that (2026-09-08). */
    box-shadow: -14px 0 0 #1b1d22, 4px 0 8px rgba(0, 0, 0, 0.35);
  }
  /* The section head is a child of .cs-card-body, which had sized itself to
     the label column while the rows inside it run to the full scroll width.
     Sticky is bounded by the parent, so the head could not travel: it simply
     scrolled away and left an empty band that the product columns showed
     through. The body now spans the content, and the head paints a solid
     divider across it (2026-09-08). */
  .cs-card-body { width: max-content; min-width: 100%; }
  /* A heading that spans the table is a BAND, and the thing that pins is the
     text inside it, not the box. Pinning the box means shrinking it to its
     own words, which then reads as a stray dark tile sitting on the table;
     leaving it full width means it cannot shift at all and the label scrolls
     away. Both were tried and both were wrong (2026-09-08). */
  .cs-card-section-head, .cs-card-head {
    position: static;
    /* the card is a block inside a horizontal scroller, so a plain child only
       stretches to the visible width and the rest of the row stays bare */
    width: max-content; min-width: 100%;
    background: var(--glass); box-shadow: -14px 0 0 var(--glass);
  }
  .cs-card-section-head {
    padding: 12px 8px 6px; border-bottom: 1px solid var(--border);
  }
  .cs-card-section-head > span, .cs-card-head-in {
    position: sticky; left: 0; display: inline-flex; align-items: center; gap: 8px;
  }
}

/* ── Pinned headings must stack, not collide (2026-09-07) ──────────────────
   On Market Rates Pulse the page title and the group heading both pinned at
   64 with the same z-index, so "Home loans" sat on top of the page title
   instead of beneath it. A group heading pins below whatever page title is
   already pinned above it, and paints under it. */
/* Market Pulse stacks two pinned headings: the page title, then the category
   group title beneath it. Both defaulted to top:64px and the group title
   painted THROUGH the page title. Now that headings pin at every width, this
   has to apply at every width too, not only on phones (2026-09-07). */
#page-market-pulse .pulse-group-title { top: 105px; z-index: 17; }
#page-market-pulse .pulse-title { z-index: 19; }
@media (max-width: 640px) {
  /* the compare rows butt together: the base row padding left a gap that
     broke the label column into floating tiles */
  .cs-card-row { padding: 0 !important; }
  .cs-card-cols { margin-bottom: 0 !important; }
}

/* ── The briefing's section headings speak in the site's voice (2026-09-07) ─
   On Market Rates Pulse a group title is a small label sitting under a serif
   page heading, which is right. On the APRA Monthly Briefing the same class
   is the only heading level, so it was doing a heading's job in a caption's
   clothes: Inter, uppercase, 0.74rem, unlike anything else on the site. */
#page-apra-briefing .pulse-group-title {
  font: 400 var(--fs-xl) 'Instrument Serif', Georgia, serif;
  text-transform: none; letter-spacing: 0; color: var(--text);
  margin: 18px 0 10px;
}
@media (max-width: 640px) {
  #page-apra-briefing .pulse-group-title { font-size: var(--fs-md); margin: 10px 0 8px; padding: 6px 0; }
}

/* the same panel, the other way round, in light mode */
@media (max-width: 640px) {
  [data-theme="light"] .cs-card-cols > :first-child,
  [data-theme="light"] .cs-card-rowlabel,
  [data-theme="light"] .cs-card-row > :first-child {
    background: #f5f5f4 !important;
    border-right-color: rgba(0, 0, 0, 0.06);
    box-shadow: -14px 0 0 #f5f5f4, 4px 0 8px rgba(0, 0, 0, 0.08);
  }
}


/* A slide-over panel parked off-screen right still PAINTS ITS SHADOW into the
   viewport: `-12px 0 48px rgba(0,0,0,0.55)` on the two LVR panels drew a grey
   band down the whole right edge of that page, invisible on a dark ground and
   obvious on a white one. Closed panels cast nothing (2026-09-08). */
#lvr-compare-panel[aria-hidden="true"],
#lvr-bank-drill-panel[aria-hidden="true"] { box-shadow: none !important; }

/* ── No scrollbar chrome on touch scrollers (2026-09-08) ──────────────────
   The sideways scrollers are 338-358px wide inside a 390px screen, so their
   scrollbar draws a bar along nearly the full width at the bottom of the
   table and reads as a scrollbar on the PAGE. There is already a fade at the
   right edge saying there is more, so the bar is only noise. The content
   still scrolls; the chrome stops drawing.
   The cutoff is 900px, NOT 640px: ui.js marks these scrollers `.hscroll-wrap`
   at `(max-width: 900px)`, so a 641-900px window got the sideways scrolling
   with the bar still painted under it, on both axes (2026-09-08). */
@media (max-width: 900px) {
  .hscroll-wrap, .pulse-tt-scroll, .tracker-filter-pills, .subfilter-group-pills, .apra-scan-scroll, .table-wrap, .cs-card,
  .tracker-table-wrap, div:has(> .lvr-heatmap), div:has(> .data-table),
  div:has(> .apra-inner-table) {
    scrollbar-width: none; -ms-overflow-style: none;
  }
  .hscroll-wrap::-webkit-scrollbar, .pulse-tt-scroll::-webkit-scrollbar,
  .tracker-filter-pills::-webkit-scrollbar, .subfilter-group-pills::-webkit-scrollbar, .apra-scan-scroll::-webkit-scrollbar,
  .table-wrap::-webkit-scrollbar, .cs-card::-webkit-scrollbar,
  .tracker-table-wrap::-webkit-scrollbar,
  div:has(> .lvr-heatmap)::-webkit-scrollbar, div:has(> .data-table)::-webkit-scrollbar,
  div:has(> .apra-inner-table)::-webkit-scrollbar { width: 0; height: 0; display: none; }

}

@media (max-width: 900px) {
  /* An inner vertical scroll box inside a page that already scrolls gives the
     reader two bars and two gestures. The page does the vertical scrolling. */
  .apra-scan-scroll { max-height: none !important; overflow-y: visible !important; }
  /* Same for the Product Browser. On a desktop it is deliberately an app
     panel: 100vh tall with the table scrolling inside it. On a phone or a
     tablet that is a second scroll surface inside a page that already
     scrolls, which is the up-and-down scrollbar readers were fighting. The
     panel grows to its content and the PAGE scrolls (2026-09-08). */
}

/* ── Overscroll stays inside the thing being scrolled (2026-09-08) ────────
   A sideways scroller that reaches its end passes the rest of the gesture to
   the page, and the page rubber-bands: on a phone that reads as the whole
   screen shifting and springing back at the right edge and the bottom. The
   page has no horizontal scroll to give (body is overflow-x: clip, and
   scrollWidth equals clientWidth on every page, measured), so the movement is
   pure overscroll chaining. Contain it at the scroller. */
.hscroll-wrap, .pulse-tt-scroll, .tracker-filter-pills, .subfilter-group-pills,
.apra-scan-scroll, .table-wrap, .cs-card, .modal-overlay .modal {
  overscroll-behavior-x: contain;
}
body { overscroll-behavior-x: none; }

/* ── One content width on phones (2026-09-08) ─────────────────────────────
   Three different gutters were in play: 16px on most pages, 24px on the seven
   company and legal pages, 32px inline on the APRA Publication page. On a
   390px screen that is 358, 342 and 326px of usable width, and moving between
   them reads as the pages being different sizes, which is what it is. */
@media (max-width: 640px) {
  .legal-page { padding-left: 16px !important; padding-right: 16px !important; }
  #page-analytics-apra > .page-content { padding-left: 16px !important; padding-right: 16px !important; }
}

/* ── Sticky section headings ──────────────────────────────────────────────
   A heading pins under the top bar while its own section is on screen, so
   the reader always knows which part of the page they are in, and hands over
   when the next one arrives. This used to be phone-only, which left five
   desktop pages with nothing pinned at all: Market Pulse, the APRA briefing,
   League Table, RBA Pass-Through and APRA Publication (2026-09-07).

   Sticky is bounded by the PARENT. A heading can only travel as far as its
   parent's box, so a title inside a 67px wrapper pins for 19px and then
   leaves. That is the whole reason this selector list targets the roles it
   does, and why a few of them are forced static below. */
main .section-title, main .pulse-title, main .hero-title,
main > h1, main > .page-content > h1, main .section-header,
main .pulse-group-title, main .apra-nav-row,
main > .page-content > .section-row, main header > h1 {
  position: sticky; top: 64px; z-index: 18;
  background: var(--bg); padding: 6px 0; margin-bottom: 0;
}
/* when a heading sits inside a sticky header, the header does the work: a
   title pinned inside a 40px parent can only travel a few pixels, and the two
   boxes then pin independently and slide over each other */
main .section-header .section-title,
main > .page-content > .section-row .section-title { position: static; padding: 0; }
/* ui.js measures each pinned block on phones and marks anything taller than a
   band. On the LVR grid .section-header wraps the title, a three-line lede and
   a counts row: 133px frozen under a 64px bar, a quarter of the screen, with
   the table sliding under it and its top row always sliced. That is worse than
   no pinning at all (2026-09-08). */
main .sticky-too-tall { position: static !important; }
/* pinning a heading inside a card, table or side panel is wrong */
main .modal .section-title, main .card .section-title,
main table .section-title, main .lvr-panel .section-title,
main .cs-card .section-title, main .apra-inner-table .section-title,
main .compare-summary .section-title { position: static; padding: 0; }
/* Phone-only pinned page title, for pages whose title sits inside a wrapper
   too short to give sticky any travel. Hidden at every other width, where the
   real .section-row pins instead. */
.psticky-m { display: none; }
@media (max-width: 640px) {
  .psticky-m {
    display: flex; align-items: center;
    position: sticky; top: 64px; z-index: 20;
    height: var(--sticky-bar-h);
    background: var(--bg); padding: 0 2px; box-shadow: 0 1px 0 var(--border);
  }
  .psticky-title {
    font-family: 'Instrument Serif', Georgia, serif; font-size: var(--fs-xl);
    color: var(--text); line-height: 1.1;
  }
  /* the in-row title would repeat the pinned one */
}

/* The feed is its own section between the hero and Product Explorer, and it
   had no heading to pin: 454px of the dashboard scrolled with the header band
   empty. Its own header takes over, which also keeps the category filter and
   the charts toggle reachable while the list scrolls. `overflow: hidden` on
   the panel had to go first - it makes the panel a scrollport that cannot
   scroll, so a sticky child inside it never moves (2026-09-07). */
#page-dashboard .feed-panel { overflow: visible; }
#page-dashboard .feed-header {
  position: sticky; top: 64px; z-index: 18;
  background: var(--bg); box-shadow: 0 1px 0 var(--border);
}

/* the dashboard hero title holds while the hero is on screen, then hands over */
#page-dashboard .hero-title { position: sticky; top: 64px; z-index: 19; background: var(--bg); padding: 4px 0; }

/* ── Phone: peer-group labels in the frozen APRA column (2026-09-10) ───────
   The pinned identity column shrinks a BANK to 9.9px, but every rule that
   does it selects `td:first-child > span…` - a bank name is wrapped in a
   span beside its logo. A PEER GROUP is not: the label is a bare text node
   sitting directly in the cell, between a chevron span and an ADI-count
   span. So it kept the table's own 12.5-13.6px inside a 74px cell, and
   because the cell must keep `overflow: visible` for its frozen-edge
   ::after (parked at right:-10px, so hiding overflow erases the edge), a
   nine-letter group like "Macquarie" or "Neobanks" painted straight across
   the divider and into the numbers.
   Sizing the CELL reaches the text node; the spans inside already carry
   their own size, so bank rows are untouched. Four tables, one rule: the
   Insights growth table, the Scanner group rows, the Quarterly capital
   peer groups, and the growth table's System Total. */
@media (max-width: 640px) {
  #apra-growth-tbody td:first-child,
  #apra-capital-tbody td:first-child,
  #apra-scan-tbody td.apra-scan-group-name {
    font-size: var(--fs-3xs) !important;
    line-height: 1.15 !important;
    letter-spacing: 0 !important;
  }
  /* the chevron inherits the cell, so it shrinks with the label and stops
     being wide enough to orphan itself on a line of its own */
  #apra-growth-tbody tr[data-action] td:first-child > span:first-child {
    width: auto !important; margin-right: 2px !important;
  }
}

/* ── Gated pages (2026-09-11): Rate Movements and Data Quality ─────────────
   One prompt for every page that needs a verified account, rendered by
   _gatePromptHtml in place of the page's data until the auth event fires. */
.gate-prompt { padding: 48px 20px; text-align: center; }
.gate-prompt .gate-title { font-size: var(--fs-lg); font-weight: 600; color: var(--text); margin: 0 0 6px; }
.gate-prompt .gate-line { font-size: var(--fs-sm); color: var(--muted); margin: 0 0 18px; max-width: 46ch; margin-left: auto; margin-right: auto; }
.gate-prompt .gate-btn { min-width: 120px; display: inline-flex; justify-content: center; align-items: center; text-align: center; }

/* ── Phone: the typeahead must outrank the swipe band (2026-09-12) ─────────
   .tracker-sticky-header is a flex item of .tracker-main with z-index 5, and
   a flex item with a z-index is its own stacking context. The typeahead
   (.srch-suggest, z 60) lives inside that context, while the sticky
   "Swipe right to compare" band (.cmp-hint-m, z 19) is a SIBLING flex item,
   so the band painted straight through the suggestion list whenever the
   filtered list was short enough for the two to overlap (search a bank on
   the home page: the band sat mid-screen across the dropdown). Lift the
   header only while a dropdown is open; nothing else changes. */
@media (max-width: 640px) {
  .tracker-sticky-header:has(.srch-suggest:not([hidden])) { z-index: 20; }
}

/* ── Phone: the chat headers never overflow the screen (2026-09-12) ───────
   The desktop rule pins the dock title (flex: 0 0 auto) so the header row
   could not shrink. Signed in, once a conversation had started, the quota
   badge + user chip + New chat pushed the minimise button to 386px: 4px
   from the edge of a 390px phone and off the edge of a 375px one. The APRA
   panel had it worse because its New chat was still the full-width text
   button. The title yields first (it already ellipsises); New chat is the
   same round icon on both panels; the buttons never shrink. */
@media (max-width: 640px) {
  .ai-dock--full .ai-dock-header, #apra-chat-panel .ai-dock-header { flex-wrap: nowrap; gap: 8px; padding: 12px 12px 8px 14px; }
  .ai-dock--full .ai-dock-header h3, #apra-chat-panel .ai-dock-header h3 {
    flex: 1 1 auto; min-width: 0; font-size: var(--fs-md);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #apra-chat-panel #apra-new-chat { width: 34px; height: 34px; padding: 0; font-size: 0; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
  #apra-chat-panel #apra-new-chat::before { content: '\FF0B'; font-size: var(--fs-md); line-height: 1; color: var(--muted); }
  #apra-chat-panel .ai-signin { padding: 5px 11px; font-size: var(--fs-xs); white-space: nowrap; flex-shrink: 0; }
  .ai-dock--full .ai-dock-header .ai-dock-status, #apra-chat-panel .ai-dock-header .ai-dock-status,
  .ai-dock--full .ai-user-chip, #apra-chat-panel .ai-user-chip { flex-shrink: 0; }
}

/* ── Calculator on phones (2026-09-13) ─────────────────────────────────────
   Eleven tools share one page. Three things broke at 390px:
   1. The results column sat off the right edge on eight tabs (fixed at the
      source: the ≤820px collapse now follows the theme rule it lost to).
   2. The global ≤640px "tables become cards" rule stacked every calculator
      table into unlabelled value rows; the twenty-lender table alone ran to
      ~7,900px. Label/value and top-5 tables fit a phone as real tables, so
      they get the same opt-out the APRA tables have. The eight-column lender
      table becomes a labelled card per lender instead.
   3. The title row never wrapped: the lede clipped mid-word and the tab Reset
      sat off screen. The title block may now shrink and wrap. */
@media (max-width: 640px) {
  #page-calc .page-content > .section-row > div:first-child { flex: 1 1 auto !important; min-width: 0; }
  /* The title row pins under the nav on phones (main .section-row is sticky).
     With the lede it is a 100px band, over the 84px limit ui.js allows, so the
     lede goes and the band is the title plus the tab Reset. */
  #page-calc .page-content > .section-row > div:first-child > div:last-child { display: none; }

  /* Tables that fit stay tables. */
  #page-calc table:not(.bp-banks-table) { display: table; width: 100%; }
  #page-calc table:not(.bp-banks-table) thead { display: table-header-group; }
  #page-calc table:not(.bp-banks-table) tbody { display: table-row-group; }
  #page-calc table:not(.bp-banks-table) tr {
    display: table-row; border: none; border-radius: 0; margin: 0; background: none;
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  #page-calc table:not(.bp-banks-table) td, #page-calc table:not(.bp-banks-table) th { display: table-cell; width: auto; }
  #page-calc table:not(.bp-banks-table) td::before { content: none; }
  #page-calc table:not(.bp-banks-table) td:first-child { background: transparent; }

  /* The lender table: one card per lender, three labelled figures under the
     product name. Labels come from data-label on the cells. */
  #page-calc .bp-banks-table, #page-calc .bp-banks-table tbody { display: block; width: 100%; }
  #page-calc .bp-banks-table thead { display: none; }
  #page-calc .bp-banks-table tr {
    /* three equal, bounded tracks after the logo: auto tracks grew to a long
       bank name's full width and pushed the monthly figure under it. */
    display: grid; grid-template-columns: 34px minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 10px; row-gap: 2px; align-items: center;
    padding: 10px 12px; margin: 0 0 8px; border: 1px solid var(--calc-border); border-radius: 12px;
    background: var(--calc-panel-2); backdrop-filter: none; -webkit-backdrop-filter: none; overflow: hidden;
  }
  #page-calc .bp-banks-table tr.is-pinned { border-color: var(--calc-accent); background: var(--calc-accent-soft); }
  #page-calc .bp-banks-table td { display: block; width: auto; min-width: 0; padding: 0; border: 0; background: none; font-size: var(--fs-xs); }
  #page-calc .bp-banks-table td::before { content: none; }
  #page-calc .bp-banks-table td.bp-rank { display: none; }
  #page-calc .bp-banks-table td.bp-bank-logo-cell { grid-column: 1; grid-row: 1 / 3; }
  #page-calc .bp-banks-table td.bp-bank-name { grid-column: 2 / 4; grid-row: 1; font-weight: 600; font-size: var(--fs-sm); color: var(--calc-text); white-space: normal; overflow-wrap: anywhere; line-height: 1.25; }
  #page-calc .bp-banks-table td.bp-monthly { grid-column: 4; grid-row: 1; justify-self: end; text-align: right; font-weight: 700; font-size: var(--fs-sm); color: var(--calc-text); white-space: nowrap; }
  #page-calc .bp-banks-table td.bp-product-name { grid-column: 2 / 5; grid-row: 2; color: var(--calc-muted); line-height: 1.3; max-width: none; white-space: normal; overflow: visible; text-overflow: clip; }
  #page-calc .bp-banks-table td.bp-lvr { grid-column: 2; grid-row: 3; }
  #page-calc .bp-banks-table td.bp-rate { grid-column: 3; grid-row: 3; }
  #page-calc .bp-banks-table td.bp-comp { grid-column: 4; grid-row: 3; }
  #page-calc .bp-banks-table td.bp-extra { grid-column: 2 / 5; grid-row: 4; margin-top: 6px; text-align: left; }
  /* Max loan sits under the monthly figure on the right (2026-09-29). */
  #page-calc .bp-banks-table td.bp-maxloan { grid-column: 4; grid-row: 2; justify-self: end; text-align: right; white-space: nowrap; color: var(--calc-muted); font-size: var(--fs-2xs); }
  #page-calc .bp-banks-table td.bp-maxloan::before { content: attr(data-label) ' '; font-size: var(--fs-3xs); letter-spacing: .08em; text-transform: uppercase; }
  #page-calc .bp-banks-table td.bp-product-name { grid-column: 2 / 4; }
  #page-calc .bp-banks-table td.bp-lvr, #page-calc .bp-banks-table td.bp-rate, #page-calc .bp-banks-table td.bp-comp {
    margin-top: 6px; text-align: left; white-space: nowrap;
  }
  #page-calc .bp-banks-table td.bp-extra::before,
  #page-calc .bp-banks-table td.bp-lvr::before, #page-calc .bp-banks-table td.bp-rate::before, #page-calc .bp-banks-table td.bp-comp::before {
    content: attr(data-label); display: block; font-family: 'Inter', system-ui, sans-serif; font-weight: 500;
    font-size: var(--fs-3xs); letter-spacing: .08em; text-transform: uppercase; color: var(--calc-muted); margin-bottom: 1px;
  }

  /* Touch: underline inputs at a size iOS does not zoom on focus, with room
     for a thumb; term and type chips at the house pill height; labels one
     step up from the 11px desktop caption size. */
  #page-calc .calc-num-input { font-size: var(--fs-md); padding: 6px 4px 7px; min-height: 36px; box-sizing: border-box; }
  #page-calc .calc-label, #page-calc .calc-num-hint, #page-calc .calc-result-label { font-size: var(--fs-xs); }
  /* Equity's LVR tracker: the goal box beside the table has no room on a phone. */
  #page-calc .eq-tracker-grid { grid-template-columns: 1fr !important; }
  /* Three- and four-up stat rows (Fixed Expiry's three paths and loyalty tax,
     Investment's ten-year figures) stack two-up; the live market table's
     segment labels may wrap instead of pushing the range column off screen. */
  #page-calc .calc-stat-row { grid-template-columns: 1fr 1fr !important; }
  #page-calc .rep-market-table td { white-space: normal !important; }
}

/* ── Rate Movements on phones (2026-09-13) ─────────────────────────────────
   Signed-in probe at 390px: the 300px institution column left the flex cells
   zero width (24 names, no data), the search box, window select and refresh
   sat at x=450-719 because the title row never wrapped, and ten 24px pills
   wrapped into four rows. Phone treatment follows the LVR grid: a narrow
   pinned institution column, date columns at a fixed width that scroll
   sideways inside the card (the page scrolls vertically), pills in one
   sideways row at the house pill size. */
@media (max-width: 640px) {
  /* static, not sticky: with the legend hidden the row is under ui.js's 84px
     limit, pinned at the same 64px as the title band and painted over it. */
  #heatmap-header { flex-wrap: wrap; row-gap: 8px; position: static; }
  #heatmap-header > div:first-child { flex: 1 1 100%; }
  #heatmap-header .heat-legend { flex-wrap: wrap; row-gap: 2px; column-gap: 10px; }
  #heatmap-header .gsearch { flex: 1 1 200px; min-width: 0; }
  #heatmap-days { height: var(--pill-h); font-size: var(--pill-fs); }

  /* both containers carry an inline flex-wrap:wrap, hence the !important */
  #heatmap-toolbar { flex-wrap: nowrap !important; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-bottom: 8px; }
  #heatmap-toolbar::-webkit-scrollbar { display: none; }
  #heatmap-category-pills { flex-wrap: nowrap !important; width: max-content; }

  /* The card scrolls sideways only; vertical scrolling is the page's. */
  #heatmap-card { max-height: none; overflow-x: auto; overflow-y: visible; }
  /* Only a grid widens the wrap; the sign-in prompt stays put and is sized
     for a phone (it scrolled sideways with the empty card, 2026-09-13). */
  #heatmap-wrap { padding: 4px 10px 14px; width: 100%; }
  #heatmap-wrap:has(.heat-grid) { width: max-content; min-width: 100%; }
  #heatmap-wrap .gate-prompt { padding: 22px 12px; }
  #heatmap-wrap .gate-prompt .gate-title { font-size: var(--fs-md); }
  #heatmap-wrap .gate-prompt .gate-line { font-size: var(--fs-xs); }
  /* Rows stretch so the pinned column is as tall as the cells and hides them
     completely as they pass under the names: an opaque column with a hard
     edge, no gradient (cells were visible sliding under the brand name). */
  .heat-row, .heat-header-row { align-items: stretch; }
  .heat-inst-col { align-items: center; border-right: 1px solid var(--border); }
  .heat-inst-col::after { display: none; }
  .heat-dates-sticky { padding-top: 8px; }
  .heat-inst-col { min-width: 104px; width: 104px; padding-right: 8px; gap: 5px; }
  .heat-inst-col .bank-logo-img, .heat-inst-col .bank-logo { width: 20px; height: 20px; flex: 0 0 20px; }
  .heat-inst-name { font-size: var(--fs-3xs); white-space: normal; line-height: 1.15; max-height: 2.3em; overflow: hidden; text-overflow: clip; }
  /* Compact density (operator picked B from the density study, 2026-09-13):
     24px cells at the smallest house size, 2px gaps, a 104px name column.
     One screen holds ~9 days x 22 banks instead of 5 x 18. */
  .heat-date-label, .heat-cell { flex: 1 0 24px; min-width: 24px; }
  .heat-cell { height: 24px; font-size: var(--fs-3xs); border-radius: 3px; }
  .heat-row, .heat-header-row { gap: 2px; margin-bottom: 2px; }
  .heat-date-day, .heat-date-mon { font-size: var(--fs-3xs); }
  .heat-grid--dense .heat-date-label, .heat-grid--dense .heat-cell { flex-basis: 18px; min-width: 18px; }
  #heatmap-header .heat-legend { display: none; }   /* the legend under the grid remains */
  #heatmap-toolbar { padding-bottom: 4px; }
  /* the pinned .psticky-m band carries the title on phones */
  #page-analytics-movements .section-row .section-title { display: none; }
}

/* ── Rate Movements feed-first phone view (2026-09-14) ──────────────────────
   On phones the page opens on a feed of moves (newest first) with a per-bank
   strip view and the compact grid behind a toggle. The band pins under the
   title band. Desktop never renders any of this. */
@media (max-width: 640px) {
  .hm-band { position: sticky; top: calc(64px + var(--sticky-bar-h)); z-index: 19; background: var(--bg); padding: 6px 0 6px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
  .hm-band[hidden] { display: none; }
  .hm-sum { display: flex; align-items: baseline; gap: 6px 10px; font-variant-numeric: tabular-nums; font-size: var(--fs-xs); color: var(--muted); }
  .hm-sum b { font: 700 var(--fs-lg) 'Syne', sans-serif; }
  .hm-sum .hm-cut { color: #3b82f6; } .hm-sum .hm-rise { color: #f59e0b; }
  .hm-sum .hm-meta { margin-left: auto; }
  .hm-seg { margin-top: 6px; }  /* the shared .seg track (below) draws it */
  .hm-day { padding: 12px 0 4px; font-size: var(--fs-3xs); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
  .hm-move { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
  .hm-logo { width: 34px; height: 34px; border-radius: 9px; background: #fff; object-fit: contain; padding: 3px; box-sizing: border-box; }
  .hm-logo-fb { display: inline-flex; align-items: center; justify-content: center; background: var(--glass2); color: var(--muted); font: 700 var(--fs-2xs) 'Inter', system-ui, sans-serif; }
  .hm-who { min-width: 0; } .hm-who b { display: block; font-size: var(--fs-sm); font-weight: 600; line-height: 1.2; color: var(--text); }
  .hm-who span { display: block; font-size: var(--fs-2xs); color: var(--muted); line-height: 1.3; }
  .hm-cat { color: var(--text); font-weight: 600; }
  /* words in Inter (Syne is for figures in the type contract), tap-sized */
  .hm-pill { font: 600 var(--ctl-fs-sm) 'Inter', system-ui, sans-serif; height: var(--ctl-xs); padding: 0 10px; display: inline-flex; align-items: center; border-radius: var(--ctl-r); white-space: nowrap; }
  .hm-pill.cut { background: #14243f; color: #93c5fd; } .hm-pill.rise { background: #3a2408; color: #fbbf24; } .hm-pill.mixed { background: linear-gradient(135deg, #3a2408 50%, #14243f 50%); color: #fff; }
  [data-theme="light"] .hm-pill.cut { background: #dbeafe; color: #1e40af; } [data-theme="light"] .hm-pill.rise { background: #fde7d6; color: #9a3412; }
  .hm-card { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 8px 10px; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
  .hm-card-txt { min-width: 0; } .hm-nm { font-size: var(--fs-sm); font-weight: 600; line-height: 1.2; color: var(--text); }
  .hm-last { font-size: var(--fs-2xs); color: var(--muted); line-height: 1.3; }
  .hm-strip { grid-column: 2; display: grid; gap: 2px; height: 12px; }
  .hm-strip i { display: block; border-radius: 2px; background: var(--glass2); }
  .hm-strip i.cut { background: #2563eb; } .hm-strip i.rise { background: #d97706; } .hm-strip i.mixed { background: linear-gradient(135deg, #78350f 50%, #1e40af 50%); }
  /* Grid view: the legend sits ABOVE the card, outside the sideways scroller,
     so it stays in view while the columns scroll; the copy under the grid
     (which scrolled away with it) is hidden. Month labels show only where the
     month changes. */
  .hm-legend-m[hidden] { display: none; }
  .hm-legend-m .heat-legend { margin: 0 0 6px; padding: 0; border-top: none; flex-wrap: wrap; gap: 4px 12px; }
  #heatmap-wrap .heat-legend { display: none; }
  .heat-date-mon { letter-spacing: 0; }
  /* the feed and bank views are not wider than the phone; only the grid is */
  #heatmap-wrap:has(.hm-feed), #heatmap-wrap:has(.hm-banks) { width: 100%; }
}

/* ── Product modal rate rows on phones (2026-09-16) ─────────────────────────
   The sideways table hid the rate off the right edge (Type, Term, Payment,
   Repayment, Purpose came first). Phones get one card per tier from the same
   row model: dimensions on the left, the figure on the right. */
.rate-cards { display: none; }
@media (max-width: 640px) {
  #prod-rate-section .rate-table-wrap { display: none; }
  #prod-rate-section .rate-cards { display: block; }
  .rate-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); }
  .rate-card:last-child { border-bottom: none; }
  .rate-card-type { font-size: var(--fs-xs); color: var(--text); display: flex; flex-wrap: wrap; align-items: center; gap: 2px 0; }
  .rate-card-dims { font-size: var(--fs-2xs); color: var(--muted2); line-height: 1.5; margin-top: 2px; overflow-wrap: anywhere; }
  .rate-card-figure { text-align: right; white-space: nowrap; }
  .rate-card-comp { font-size: var(--fs-3xs); color: var(--muted); margin-top: 2px; }
}

/* ── Hero pills (2026-09-18, operator's pick 3b) ─────────────────────────────
   "Product Analyst" / "Market Pulse" and "APRA ADI Analyst" / "Monthly
   Briefing" are one object in two colours: the lg control size (52px, 24px
   sides, 0.88rem), the full radius and a 1.5px edge on both. The analyst's
   edge is the launcher's blue at half strength with one soft halo, and it
   carries the launcher's three typing dots (flat fills at its dot size); the
   pulse and briefing pills take the neutral edge and a stroked glyph drawn in
   the same 26px box. Desktop: two equal columns sized to the wider label
   (.hero-pills). Phones: each pill takes half the row at 50px, 22px icon. */
.hero-pills { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; width: max-content; max-width: 100%; }
.hero-pills .btn-analyst, .hero-pills .btn-pulse {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; height: var(--ctl-lg); padding: 0 var(--ctl-px-lg); margin: 0; box-sizing: border-box;
  border-radius: var(--ctl-r); font-size: var(--ctl-fs-lg); line-height: 1; white-space: nowrap;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease, background 0.18s ease;
}
.btn-primary.btn-analyst { font-weight: 700; background: transparent; color: var(--text); border: var(--ctl-edge) solid rgba(96, 165, 250, 0.5); box-shadow: 0 0 10px rgba(96, 165, 250, 0.25); }
.btn-primary.btn-analyst:hover { transform: translateY(-2px); border-color: rgba(96, 165, 250, 0.85); box-shadow: 0 0 14px rgba(96, 165, 250, 0.4); }
.hero-pills .btn-pulse { font-weight: 600; background: var(--glass); color: var(--text); border: var(--ctl-edge) solid var(--border); box-shadow: none; }
.hero-pills .btn-pulse:hover { transform: translateY(-1px); background: var(--glass2); }
.btn-analyst .cta-dots { display: inline-flex; align-items: center; line-height: 0; }
.btn-analyst .cta-dots svg { display: block; width: var(--ctl-icon-lg); height: var(--ctl-icon-lg); }
.btn-analyst .cta-dots circle { transform-box: fill-box; transform-origin: center; animation: fab-dot-typing 2.4s ease-in-out infinite; }
.btn-analyst .cta-dots .d1 { fill: #1e40af; animation-delay: 0s; }
.btn-analyst .cta-dots .d2 { fill: #60a5fa; animation-delay: 0.35s; }
.btn-analyst .cta-dots .d3 { fill: #d97706; animation-delay: 0.7s; }
@media (prefers-reduced-motion: reduce) { .btn-analyst .cta-dots circle { animation: none; opacity: 0.9; } }
.btn-pulse .cta-glyph { width: var(--ctl-icon-lg); height: var(--ctl-icon-lg); flex-shrink: 0; color: var(--amber, #f5a623); }
.lbl-short { display: none; }
@media (max-width: 640px) {
  .hero-pills { display: flex; width: 100%; gap: 8px; }
  .hero-pills .btn-analyst, .hero-pills .btn-pulse { flex: 1 1 0; min-width: 0; height: 50px; padding: 0 10px; gap: 6px; font-size: var(--fs-sm); }
  .btn-analyst .cta-dots svg, .btn-pulse .cta-glyph { width: 22px; height: 22px; }
  .hero-actions .lbl-long { display: none; }
  .hero-actions .lbl-short { display: inline; }
}

/* ── Sign-in sheet (2026-09-17): two doors, then the form ────────────────────
   Google and email are the two ways in, each with its logo, at one size. The
   email form stays folded until "Continue with email", so the sheet opens
   short on a phone. Scoped to #modal-overlay: .modal is shared with the
   product and institution sheets. */
#modal-overlay .modal { max-width: 400px; padding: 28px 28px 24px; }
#modal-overlay .modal-title { margin-bottom: 4px; }
#modal-overlay .modal-sub { margin-bottom: 18px; line-height: 1.5; }
.auth-providers { display: flex; flex-direction: column; }
/* Two discs, the G on white and the envelope on the accent blue, a word under
   each (operator's pick, 2026-09-17). The disc is the whole button; the label
   is part of it so the tap target is disc plus word. */
.auth-circles { display: flex; justify-content: center; gap: 32px; padding: 2px 0 0; }
.auth-circles .social-btn {
  flex-direction: column; align-items: center; gap: 8px; padding: 0; background: none; border: none;
  font-size: var(--fs-2xs); font-weight: 600; color: var(--text); text-decoration: none; cursor: pointer;
}
.auth-circles .social-btn:hover { transform: none; box-shadow: none; }
.auth-circles .social-logo {
  width: 64px; height: 64px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; line-height: 0;
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
}
.auth-circles .social-btn:hover .social-logo { transform: translateY(-2px); }
.social-btn--google .social-logo { background: #ffffff; border: 1px solid rgba(0,0,0,0.10); box-shadow: 0 6px 18px rgba(0,0,0,0.18); }
/* --accent is the theme's neutral (#f0f0f0 dark / #0a0a0a light); the site's blue is #2563EB */
.social-btn--email .social-logo { background: #2563EB; color: #ffffff; box-shadow: 0 6px 18px rgba(37,99,235,0.35); }
.social-btn--email[aria-expanded="true"] .social-logo { box-shadow: 0 0 0 3px rgba(37,99,235,0.35), 0 6px 18px rgba(37,99,235,0.35); }
.auth-circles .social-label { letter-spacing: 0.02em; }
.auth-email-form { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.auth-email-form:not(.is-open) { display: none; }
#modal-overlay .modal-input { padding: 10px 12px; margin-bottom: 8px; }
.auth-row { text-align: right; margin: -2px 0 12px; }
.auth-link { font-size: var(--fs-2xs); color: var(--muted); cursor: pointer; background: none; border: none; padding: 0; font-family: inherit; }
.auth-link:hover { color: var(--text); }
#modal-overlay .modal-submit { padding: 0 var(--ctl-px-md); }
.auth-hint { text-align: center; margin-top: 12px; font-size: var(--fs-2xs); color: var(--muted); line-height: 1.5; }
/* Phones: the sign-in card sits in the middle of the screen (2026-09-17). The
   generic phone rule turns every modal into a bottom sheet, which is right for
   the long product and institution sheets but left this short card at the
   foot of an empty overlay, reading as "dropped down". Centred, with the
   drag handle gone and the header spacing pulled together. */
@media (max-width: 640px) {
  #modal-overlay { align-items: center; padding: 0 16px; }
  #modal-overlay .modal {
    width: 100%; max-width: 400px; margin: 0 auto; border-radius: 24px;
    padding: 20px 20px 22px; max-height: calc(100dvh - 32px); overflow-y: auto;
  }
  #modal-overlay #modal-handle { display: none !important; }
  #modal-overlay .modal-title { margin-bottom: 2px; }
  #modal-overlay .modal-sub { margin-bottom: 12px; }
}

/* ── Phone gaps (2026-09-17 audit): the Alerts sign-in wall was centred in a
   60vh box, 200px of nothing above the bell and 180px below the button. */
@media (max-width: 640px) {
  #alerts-auth-wall { min-height: auto !important; padding: 12px 0 28px !important; }
}

/* ── Phone gaps (2026-09-17 audit, row coverage on every page) ─────────────
   The same three spaces on every page: 32px tracker margin + 40px content
   padding + footer padding between the last content and the footer (95px on
   the Product Browser), the borrowing-power result card's 26px padding on top
   of the grid gap (88px), and the APRA stats column's 24px top padding under
   the insight (58px). */
@media (max-width: 640px) {
  .page-content, .page-content-narrow { padding-bottom: 20px; }
  .tracker-layout { margin-bottom: 0 !important; }
  #page-calc .bp-tab .bp-headline { padding: 18px 18px 16px !important; }
  #page-calc .bp-3col-grid { gap: 10px !important; }
  #apra-hero-layout .stats-column { padding-top: 12px; }
  /* FAB clearance under the disclaimer: 48px FAB + 16px edge + 8px, was 84px */
  footer + div { padding-bottom: 72px !important; }
}

/* ── Phone hit areas (2026-09-18) ─────────────────────────────────────────────
   Pills stay 31px tall, but every control gets a 44px tap box through an
   invisible ::after that extends above and below (never sideways, so
   neighbours in a row never overlap). .charts-toggle-pill draws its label in
   ::before, so ::after is the hit layer everywhere. Inline controls in dense
   rows (the est. badge, the compare-slot remove, the compare chips) take the
   24px floor instead. .modal-close is positioned already (absolute in the
   sign-in sheet, relative inline elsewhere). */
@media (max-width: 640px) {
  .filter-pill, .chart-filter-pill, .page-btn, .hm-seg-btn, .apra-chart-l1-pill, .apra-chart-l2-pill, .apra-trend-tf-pill,
  .calc-tab-btn, .calc-persona-btn, .calc-reset-btn, .calc-type-btn, .charts-toggle-pill, .feed-sub-btn,
  .ai-chip, .ai-new-chat, .prod-action-pill, .btn-login, .btn-circle, .theme-toggle, .nav-hamburger, .ai-dock-close,
  .cb-slot-remove, .bp-link-btn, .bp-purpose-chip, .qc-hero-info, .auth-link, .desktop-switch, .sector-pill,
  .subfilter-pill, .hm-pill, .compare-action-chip, .sm-pill, .lvr-cmp-pulse, .btn-ghost, .repayment-info-close { position: relative; }
  .filter-pill::after, .chart-filter-pill::after, .page-btn::after, .hm-seg-btn::after, .apra-chart-l1-pill::after, .apra-chart-l2-pill::after, .apra-trend-tf-pill::after,
  .calc-tab-btn::after, .calc-persona-btn::after, .calc-reset-btn::after, .calc-type-btn::after, .charts-toggle-pill::after, .feed-sub-btn::after,
  .ai-chip::after, .ai-new-chat::after, .prod-action-pill::after, .btn-login::after, .btn-circle::after, .theme-toggle::after, .nav-hamburger::after, .ai-dock-close::after,
  .cb-slot-remove::after, .bp-link-btn::after, .bp-purpose-chip::after, .qc-hero-info::after, .auth-link::after, .desktop-switch::after, .sector-pill::after,
  .subfilter-pill::after, .hm-pill::after, .compare-action-chip::after, .sm-pill::after, .lvr-cmp-pulse::after, .btn-ghost::after, .repayment-info-close::after, .modal-close::after {
    content: ''; position: absolute; left: 0; right: 0; top: 50%; height: var(--ctl-hit); transform: translateY(-50%);
  }
  .qc-hero-info::after, .cb-slot-remove::after, .compare-action-chip::after { height: 24px; }
  /* sideways pill rails: room for the hit layer inside the scroll box (no
     phantom vertical scroll), and the rail pills stop clipping their own
     ::after (their overflow:hidden served the desktop rail's ellipsis) */
  .tracker-filter-bar-body .tracker-filter-pills { padding-top: 7px; }  /* the body is a scroller too, so no negative margin here */
  .btn-circle { overflow: visible; }
  .tracker-filter-bar-body .tracker-filter-pills .filter-pill { overflow: visible; }
  #dash-category-pills, #inst-filter-pills { padding-top: 7px; padding-bottom: 7px; margin-top: -7px; margin-bottom: -5px; }
  #heatmap-toolbar { padding-top: 7px; margin-top: -7px; }
  /* text links that acted as buttons: the box grows, the layout does not */
  .auth-link { display: inline-flex; align-items: center; padding: 12px 6px; margin: -12px -6px; }
  footer .desktop-switch { display: inline-flex; align-items: center; padding: 14px 0; margin: -8px 0 -14px; }
}
/* the calculator's text buttons ("+ Add bonus or rental income") sit on the sm control height */
#page-calc .bp-link-btn { min-height: var(--ctl-sm); display: inline-flex; align-items: center; }

/* ── Segmented control (2026-09-18) ──────────────────────────────────────────
   "Pick one of N" is one object everywhere: a 31px track on the surface tint
   with a 1px edge and a 3px inset, each segment a 25px pill, the chosen
   segment filled with the text colour (the Rate Movements switch was the
   model). The track scrolls sideways where it cannot fit (phones). Rows too
   long for one line anywhere (the calculator tabs) use .seg-wrap: the same
   segments as free pills that wrap. The calculator keeps its own accent for
   the chosen segment; the wholesale section keeps its amber. Multi-select
   groups (LVR shelves) use the same track with several segments filled.
   Selector list: the class-based groups on the APRA, LVR, Rate Movements,
   Insights and calculator pages, and any container given class="seg". */
.seg, .hm-seg, .lvr-seg, #lvr-shelf-multi, .calc-type-group, .calc-term-group, .calc-tabs, .calc-section-seg, #ins-cat-pills, #ins-sev-pills, #health-scheme-filters, #apra-view-toggle {
  display: inline-flex; align-items: center; gap: 2px; height: var(--ctl-sm); padding: 2px; box-sizing: border-box;  /* 2px inset: segments are 25px, over the 24px floor */
  background: var(--surface2); border: 1px solid var(--border); border-radius: var(--ctl-r);
  max-width: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -webkit-overflow-scrolling: touch; white-space: nowrap;
}
.seg::-webkit-scrollbar, .hm-seg::-webkit-scrollbar, .lvr-seg::-webkit-scrollbar, #lvr-shelf-multi::-webkit-scrollbar, .calc-type-group::-webkit-scrollbar, .calc-term-group::-webkit-scrollbar, #ins-cat-pills::-webkit-scrollbar, #ins-sev-pills::-webkit-scrollbar, #apra-view-toggle::-webkit-scrollbar { display: none; }
.seg > button, .hm-seg > button, .lvr-seg > button, #lvr-shelf-multi > button, .calc-type-group > button, .calc-term-group > button, .calc-tabs > button, .calc-section-seg > button, #ins-cat-pills > button, #ins-sev-pills > button, #health-scheme-filters > button, #apra-view-toggle > button {
  flex: 0 0 auto; height: calc(var(--ctl-sm) - 6px); padding: 0 12px; margin: 0; border: 0; border-radius: var(--ctl-r);
  background: transparent; color: var(--muted); font-family: inherit; font-size: var(--ctl-fs-sm); font-weight: 500; line-height: 1;
  white-space: nowrap; cursor: pointer; transition: background .15s, color .15s; box-shadow: none;
}
.seg > button:hover, .hm-seg > button:hover, .lvr-seg > button:hover, #lvr-shelf-multi > button:hover, .calc-type-group > button:hover, .calc-term-group > button:hover, #ins-cat-pills > button:hover, #ins-sev-pills > button:hover, #health-scheme-filters > button:hover, #apra-view-toggle > button:hover { color: var(--text); background: transparent; }
.seg > button.active, .seg > button.on, .seg > button[aria-pressed="true"], .hm-seg > button.on, .lvr-seg > button.lvr-seg-active, #lvr-shelf-multi > button.lvr-multiseg-active,
.calc-type-group > button.active, .calc-term-group > button.active, #ins-cat-pills > button.active, #ins-sev-pills > button.active, #health-scheme-filters > button.active, #apra-view-toggle > button.active {
  background: var(--text); color: var(--bg); font-weight: 600;
}
/* the calculator keeps its accent for the chosen segment */
#page-calc .calc-type-group > button.active, #page-calc .calc-term-group > button.active, #page-calc .calc-tabs > button.active, #page-calc .calc-section-seg > button.active {
  background: var(--calc-accent-soft); color: var(--calc-accent); font-weight: 600;
}
/* the wholesale section keeps its amber */
.seg-amber > button.active { background: #b45309; color: #fff; }
/* groups that fill their column (the calculator's type and term toggles) */
.calc-type-group > button, .calc-term-group > button { flex: 1 1 0; min-width: 0; padding: 0 6px; }
.calc-type-group, .calc-term-group { width: 100%; }
/* rows too long for one line: the same segments as free pills that wrap */
.seg-wrap, .calc-tabs { display: flex; flex-wrap: wrap; gap: 6px; height: auto; padding: 0; background: transparent; border: 0; overflow: visible; white-space: normal; }
.seg-wrap > button, .calc-tabs > button { height: var(--ctl-sm); border: 1px solid var(--border); background: transparent; flex: 0 0 auto; min-width: auto; padding: 0 12px; }
.seg-wrap > button.active, .calc-tabs > button.active { border-color: transparent; }
/* a lone on/off pill beside a track (Big 4 split) */
.seg-toggle { height: var(--ctl-sm); padding: 0 12px; border: 1px solid var(--border); border-radius: var(--ctl-r); background: transparent; color: var(--muted); font-family: inherit; font-size: var(--ctl-fs-sm); font-weight: 500; line-height: 1; white-space: nowrap; cursor: pointer; display: inline-flex; align-items: center; }
.seg-toggle:hover { color: var(--text); }
.seg-toggle.active { background: var(--text); color: var(--bg); border-color: var(--text); font-weight: 600; }

/* ── One icon set (2026-09-18) ────────────────────────────────────────────────
   Inline SVG on a 24 box, stroke 2 (config.js omiIcon). Sized by the control
   it sits in: 14px in sm pills, 16px in md buttons and icon squares, 12px as
   a nav chevron. Colour follows the text (currentColor); the status dots in
   the institution filter carry their own. The typed glyphs they replace
   (→ ← ↗ ↺ ✕ × ✦ ⚡ ● ◐ ○ ▾) came from whatever font the platform
   substituted and never shared a size or baseline with the SVG icons. */
.ico { width: var(--ctl-icon-sm); height: var(--ctl-icon-sm); flex-shrink: 0; vertical-align: -0.15em; }
.ico-xs { width: 12px; height: 12px; opacity: 0.75; }
.btn-primary .ico, .btn-ghost .ico, .btn-secondary .ico, .modal-submit .ico, .compare-basket-cta .ico, .compare-basket-askai .ico, .bp-btn-primary .ico, .bp-btn-secondary .ico, .bp-persona-browse-all .ico, .btn-circle .ico, .gsearch-clear .ico, .cdm-clear .ico { width: var(--ctl-icon-md); height: var(--ctl-icon-md); }
.btn-circle .ico { width: 18px; height: 18px; }
.btn-circle--sm .ico { width: var(--ctl-icon-sm); height: var(--ctl-icon-sm); }
.nav-link .ico { margin-left: 2px; }
.ico-ok { color: var(--green); } .ico-warn { color: var(--amber, #f5a623); } .ico-bad { color: var(--red, #f87171); }
.compare-action-chip .remove .ico { width: 12px; height: 12px; }
.compare-action-chip .remove { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; cursor: pointer; }

/* ── Sheet titles (2026-09-18) ────────────────────────────────────────────────
   The product, institution and data-quality sheets name their subject in the
   serif title face at the page-title size on the desktop; phones drop one
   step so a long bank name does not run to three lines. */
.sheet-title { font-family: 'Instrument Serif', Georgia, serif; font-weight: 400; font-size: var(--fs-xl); line-height: 1.2; color: var(--text); }
@media (max-width: 640px) { .sheet-title { font-size: var(--fs-lg); } }


/* ── Admin pages on phones (2026-09-19) ─────────────────────────────────────
   The console was built for a desk. On a 390px screen the Health header's
   pills and five buttons ran off the right edge, the Users table was a
   sideways 8-column grid whose pinned emails overlapped the next column, and
   the X posts toolbar overflowed both edges. */
@media (max-width: 640px) {
  /* Health: the sticky header wraps; pills scroll in their own row; the five
     actions become a two-column grid of full-width buttons. */
  .health-sticky-header { flex-wrap: wrap; padding: 8px 16px; gap: 8px; }
  .health-sticky-header > div:first-child { flex: 1 1 100%; flex-wrap: wrap; gap: 8px; }
  #health-scheme-filters { flex: 1 1 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 2px; }
  .health-sticky-header > div:last-child { flex: 1 1 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
  .health-btn { padding: 8px 6px; font-size: var(--fs-2xs); text-align: center; white-space: normal; }
  .health-countdown { flex: 1 1 100%; }
  /* Health ops tables keep their columns and scroll sideways inside their
     wrapper (the generic card-stack would stack them without labels). */
  main .health-poll-table, main .health-pipeline-table { display: table !important; width: 100% !important; }
  main .health-poll-table thead, main .health-pipeline-table thead { display: table-header-group !important; }
  main .health-poll-table tbody, main .health-pipeline-table tbody { display: table-row-group !important; }
  main .health-poll-table tr, main .health-pipeline-table tr { display: table-row !important; border: none !important; border-radius: 0 !important; margin: 0 !important; background: transparent !important; }
  main .health-poll-table td, main .health-poll-table th, main .health-pipeline-table td, main .health-pipeline-table th { display: table-cell !important; width: auto !important; white-space: nowrap; }
  main .health-poll-table td::before, main .health-pipeline-table td::before { display: none !important; }
  .health-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .health-panels-grid { grid-template-columns: 1fr; }
  /* Users: one labelled card per user (the site's own card-stack; the
     generic .data-table rule forces a sideways table, so this opts back in). */
  main #admin-users-table { display: block !important; }
  main #admin-users-table thead { display: none !important; }
  main #admin-users-table tbody { display: block !important; }
  main #admin-users-table tr { display: block !important; width: 100% !important; border: 1px solid var(--glass-border) !important; border-radius: 14px !important; margin: 0 0 10px !important; background: var(--glass) !important; overflow: hidden; }
  main #admin-users-table td { display: flex !important; width: 100% !important; padding: 10px 16px !important; justify-content: space-between; align-items: center; gap: 10px; border-bottom: 1px solid rgba(255,255,255,0.05) !important; }
  main #admin-users-table td::before { display: inline !important; content: attr(data-label); font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); font-weight: 600; }
  main #admin-users-table td:first-child { display: block !important; background: var(--glass2); padding: 12px 16px !important; overflow-wrap: anywhere; }
  main #admin-users-table td:first-child::before { display: none !important; }
  main #admin-users-table td.admin-users-actions { white-space: normal !important; flex-wrap: wrap; }
  main #admin-users-table td.admin-users-actions > div { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
  div:has(> #admin-users-table) { overflow-x: visible !important; display: block !important; }  /* the shell is a grid built for labels-table | scroll-wrapper; a card list wants the full column */
  /* The sideways-table rules pin a 68px sticky first cell and hide its extra
     spans; a card wants none of that. */
  main #admin-users-table { width: 100% !important; min-width: 0 !important; }
  main #admin-users-table td:first-child { position: static !important; width: 100% !important; min-width: 0 !important; max-width: none !important; white-space: normal !important; z-index: auto; }
  main #admin-users-table td:first-child::after { content: none !important; }
  main #admin-users-table td:first-child > span { display: inline-block !important; }
  main #admin-users-table td:first-child > div { display: block !important; }
  /* Health: the poll calendar's month controls wrap; a card holding an ops
     table scrolls it sideways instead of clipping it. */
  .health-section-label > div { flex-wrap: wrap; row-gap: 6px; }
  .health-card:has(> table) { overflow-x: auto !important; -webkit-overflow-scrolling: touch; }
  /* X posts: the toolbar is a full-width two-column grid of buttons. */
  #admin-social-toolbar { margin-left: 0 !important; width: 100%; display: grid !important; grid-template-columns: 1fr 1fr; gap: 8px !important; }
  #admin-social-toolbar .btn-ghost { width: 100%; justify-content: center; }
  #admin-social-toolbar .btn-circle { justify-self: end; }
}

/* ── Nav at tablet widths (2026-09-24 restyle) ─────────────────────────────
   The full bar needs about 1,050px. Down to 981px it tightens (smaller link
   padding and gaps); below that and above phone width the page links and
   Alerts go into the drawer, as on phones, instead of running into the
   account controls (they overlapped at 900px before the restyle too). */
@media (min-width: 641px) and (max-width: 1100px) {
  nav { gap: 8px; }
  .nav-links { margin-left: 4px; }
  .nav-links .nav-link, .nav-links .nav-dropdown > .nav-link { padding: 8px 9px; }
  nav .nav-alerts { padding: 0 9px; }
}
@media (min-width: 641px) and (max-width: 980px) {
  .nav-links, nav .nav-alerts { display: none; }
  .nav-hamburger { display: flex; }
  nav > div:last-child { margin-left: auto; }
  /* the drawer's phone rows, which only phones had until now */
  .nav-drawer .nav-dd-section { font-size: var(--fs-3xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); padding: 14px 16px 4px; }
  .nav-drawer .nav-link { display: flex; align-items: center; justify-content: space-between; text-align: left; padding: 12px 16px; font-size: var(--fs-base); color: var(--text); border-radius: 10px; }
  .nav-drawer .nav-link::after { content: '\203A'; color: var(--muted); font-size: var(--fs-lg); line-height: 1; margin-left: 12px; }
  .nav-drawer .nav-link.nav-dd-cta::after { color: var(--blue); }
  .nav-drawer .nav-link[hidden], .nav-drawer .nav-link-theme { display: none !important; }
}

/* MOCKUP (2026-09-24 glow trial, dark theme only). The glow is fixed behind
   the page, so anything painted in the ground colour reads as a black box.
   A sticky band is frosted glass ONLY while it is stuck (app.js marks it
   .is-stuck when it has pinned to its top offset); at rest it is clear. */
html:not([data-theme="light"]) .ticker-wrap { background: rgba(22, 27, 34, 0.55); }
html:not([data-theme="light"]) :is(.section-title, .qc-logo, .tracker-filter-bar-head,
  h1.hero-title, .feed-header, .tracker-sticky-header, .section-row, .apra-nav-row, .pulse-title,
  .section-header, .lvr-toolbar, #page-apra-briefing h1, .pulse-group-title, .cmp-sticky-m, .cmp-hint-m) { background: transparent !important; }
html:not([data-theme="light"]) :is(h1.hero-title, .feed-header, .tracker-sticky-header, .section-row, .apra-nav-row, .pulse-title,
  .section-header, .lvr-toolbar, #page-apra-briefing h1, .pulse-group-title, .cmp-sticky-m, .cmp-hint-m).is-stuck {
  background: rgba(10, 14, 22, 0.62) !important; backdrop-filter: blur(22px) saturate(1.25); -webkit-backdrop-filter: blur(22px) saturate(1.25);
  box-shadow: none; }
/* The stuck band's lower edge is a short fade drawn BELOW the band, not a
   hard line; the band itself stays solid so nothing shows through its
   controls (a mask on the band let the cards through the search bar). */
html:not([data-theme="light"]) :is(h1.hero-title, .feed-header, .tracker-sticky-header, .section-row, .apra-nav-row, .pulse-title,
  .section-header, .lvr-toolbar, #page-apra-briefing h1, .pulse-group-title, .cmp-sticky-m, .apra-sec-head).is-stuck::after {
  content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 22px; pointer-events: none;
  background: linear-gradient(to bottom, rgba(10, 14, 22, 0.62), rgba(10, 14, 22, 0)); }

/* The LVR grid's pinned-header mirror (#lvr-sticky-head) exists for phones,
   where the table cannot pin its own header; every rule that hides it until
   it is pinned lives in the <=640px block, so on a desktop it was always
   visible as a second LENDER row (on prod since 2026-09-09; found 2026-09-28).
   The desktop table pins its own thead inside its scroller. */
/* Since 2026-09-28 the mirror pins on EVERY width (the operator asked for the
   shelves and the legend to stay in view on a desktop too): the scroller has
   no max-height any more, the page scrolls the table, and the page script
   copies the real header's column widths into the mirror. The legend row is
   a copy of #lvr-heatmap-legend. */
.lvr-sticky-head {
  display: none !important;
  position: sticky;
  top: 64px;
  z-index: 20;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  box-shadow: 0 6px 12px -8px rgba(0, 0, 0, 0.9);
}
.lvr-sticky-head.is-pinned { display: block !important; }
.lvr-sticky-legend { display: flex; align-items: center; gap: 10px; font-size: var(--fs-2xs); color: var(--muted); padding: 6px 0 6px 14px; }
.lvr-sticky-scroller { overflow-x: hidden; }
.lvr-sticky-head table { width: auto; }
.lvr-sticky-head thead th { position: static !important; }
.lvr-sticky-head thead th:first-child { position: sticky !important; left: 0; z-index: 2; background: var(--bg) !important; }
/* Near-opaque: the table's frozen lender cells sit at z-index 5 and painted
   through a 0.72 frost as ghost logos under LENDER. */
html:not([data-theme="light"]) .lvr-sticky-head.is-pinned { background: #0a0e16; }
html:not([data-theme="light"]) .lvr-sticky-head thead th:first-child { background: #0a0e16 !important; }
.lvr-sticky-head.is-pinned { z-index: 40; }
/* Product Comparison (2026-09-29): the LVR row, restriction tags, neutral initials. */
.cmp-lvr-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 0 0 16px; }
.cmp-lvr-label { font: 600 var(--fs-3xs) 'Inter', system-ui, sans-serif; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-right: 6px; }
.cs-card-tags { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; margin-top: 6px; }
.cs-card-tag { font: 600 var(--fs-3xs) 'Inter', system-ui, sans-serif; letter-spacing: 0.04em; padding: 2px 8px; border-radius: 999px; color: var(--amber, #f5a623); background: rgba(245, 166, 35, 0.12); white-space: nowrap; }
.cs-card-logo--initials { background: var(--surface2) !important; color: var(--muted) !important; }
#compare-overlay .compare-summary { margin: 4px 0 12px; }
.cs-cell-note { font-size: var(--fs-3xs); color: var(--muted); line-height: 1.3; }
/* Phone title band and compare hint: clear at rest, glass only while pinned
   (2026-09-29); their resting hairline read as the lower edge of a black box. */
html:not([data-theme="light"]) .cmp-sticky-m:not(.is-stuck), html:not([data-theme="light"]) .cmp-hint-m:not(.is-stuck) { box-shadow: none !important; border-bottom-color: transparent !important; }
/* The briefing's month picker is a house pill (2026-09-29). */
.pulse-month-select { height: var(--ctl-sm); border: 1px solid var(--border); border-radius: 999px; background: transparent; color: var(--text); padding: 0 30px 0 14px; font: 500 var(--fs-2xs) 'Inter', system-ui, sans-serif; cursor: pointer; appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; background-size: 14px; }
/* The briefing sheet on phones (2026-09-29, corrected 2026-09-30): it is
   full-bleed, so it must HIDE the page, not frost it. A 72% fill with
   --glass-blur (which is blur(0px)) let the APRA page's text read through
   every line of the briefing; even 96% left a ghost of it. Opaque. */
@media (max-width: 640px) {
  html:not([data-theme="light"]) #apra-briefing-card { background: #080f1a !important; backdrop-filter: none; -webkit-backdrop-filter: none; }
  /* room for the close square beside a two-line title */
  #apra-briefing-card .pulse-topbar-text { padding-right: 48px; }
}
/* Calculator lender cards (2026-09-29): the Product Browser's quote card,
   reused as-is; only the spacing and the pinned ring are added here. */
.lender-cards { width: 100%; border-collapse: separate; border-spacing: 0; margin-top: 8px; }
.lender-cards tr.quote-card { cursor: pointer; }
.lender-cards tr.quote-card > td.quote-card-cell { padding: 0 0 8px !important; }
.lender-cards tr.quote-card.is-pinned .quote-card-cell > .qc-grid { box-shadow: inset 0 0 0 2px var(--calc-accent, var(--blue)); }
.lender-cards tr.quote-card:focus-visible { outline: none; }
.lender-cards tr.quote-card:focus-visible .quote-card-cell > .qc-grid { box-shadow: inset 0 0 0 2px var(--blue); }
.qc-hero-badge--pinned { background: var(--calc-accent, var(--blue)); color: #fff; }
.bp-banks-foot-note { font-size: var(--fs-2xs); color: var(--muted); margin: 2px 0 8px; }
/* The MADIS scanner freezes Institution + Group (left) and its whole header
   (top). A transparent frozen cell shows the columns scrolling under it, so
   the frozen header cells and the header band stay opaque (2026-09-29). */
/* APRA table headers let the glow through, EXCEPT the scanner (its own
   table) and any frozen cell. This lives OUTSIDE the :is() list above on
   purpose: :is() takes the specificity of its most specific member, and this
   selector (an id + a chain) once sat in that list and silently out-ranked
   the opaque rule on every stuck band (2026-09-29). */
html:not([data-theme="light"]) #page-analytics-apra table:not(.apra-inner-table) th:not([style*="sticky"]) { background: transparent !important; }
html:not([data-theme="light"]) #apra-scan-thead { background: #0a0e16 !important; }
html:not([data-theme="light"]) .apra-scan-scroll { background: #0a0e16; }
html:not([data-theme="light"]) .apra-inner-table tbody tr:hover td[style*="sticky"] { background: #131820 !important; }
html:not([data-theme="light"]) #apra-scan-thead th[style*="sticky"] { background: #0a0e16 !important; }
/* The LVR filter toolbar is a dense control band over a dense table: frosted
   it showed the page title and rate rows through itself, so it is opaque. */
/* The pinned LVR toolbar is the same glass as every other stuck band; its
   compact title shows only while pinned. */
.lvr-toolbar-title { display: none; font-family: 'Instrument Serif', Georgia, serif; font-size: var(--fs-lg); line-height: 1.1; padding: 8px 0 0; color: var(--text); }
.lvr-toolbar.is-stuck .lvr-toolbar-title { display: block; }
@media (max-width: 640px) { .lvr-sticky-legend { padding-left: 8px; flex-wrap: wrap; row-gap: 2px; } }
/* MOCKUP, continued (2026-09-28): the feed's source note and the product
   cards let the glow through; a hairline keeps each card's edge readable. */
html:not([data-theme="light"]) .cdr-source-note { background: transparent; border-bottom-color: rgba(255, 255, 255, 0.08); }
/* No blur on the cards: twenty blur passes per scroll frame at Retina size
   stalled an integrated GPU (2026-09-28); the translucent fill alone lets the
   glow through. Blur is reserved for the one or two stuck bands. */
html:not([data-theme="light"]) .quote-card-cell > .qc-grid { background: transparent; border-color: rgba(255, 255, 255, 0.10); }
/* The hero sits on the brightest part of the glow: the insight card and the
   Market Pulse button were opaque slabs there (2026-09-28). A thin fill and
   a hairline, matching the product cards. */
html:not([data-theme="light"]) .hero-insight-card { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.12); }
html:not([data-theme="light"]) .btn-pulse { background: rgba(255, 255, 255, 0.06); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14); }
html:not([data-theme="light"]) .btn-pulse:hover { background: rgba(255, 255, 255, 0.11); }
/* The Market Pulse heartbeat draws itself on every six seconds (2026-09-29,
   operator): the line is 50 units long; it clears and redraws left to
   right in about a second, then rests. Reduced motion: still. */
.btn-pulse .cta-glyph path { stroke-dasharray: 52; stroke-dashoffset: 0; animation: pulse-trace 6s ease-in-out infinite; }
@keyframes pulse-trace {
  0%, 78% { stroke-dashoffset: 0; opacity: 1; }
  80% { stroke-dashoffset: 52; opacity: 0.35; }
  81% { opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .btn-pulse .cta-glyph path { animation: none; } }
html:not([data-theme="light"]) .qc-chip { background: rgba(255, 255, 255, 0.05); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10); }
/* Audit 2026-09-28: every surface that sat on the glow as an opaque slab. */
html:not([data-theme="light"]) .gsearch { background: rgba(255, 255, 255, 0.05); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10); }
html:not([data-theme="light"]) .inst-card { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.10); }
html:not([data-theme="light"]) .pulse-section { background: rgba(255, 255, 255, 0.035); border-color: rgba(255, 255, 255, 0.09); }
html:not([data-theme="light"]) .calc-inputs-strip { background: rgba(255, 255, 255, 0.05); }
html:not([data-theme="light"]) #bespoke-brief { background: rgba(255, 255, 255, 0.05); }
html:not([data-theme="light"]) .pulse-headline-card { background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.10); }
html:not([data-theme="light"]) .psticky-m, html:not([data-theme="light"]) #heatmap-band { background: rgba(10, 14, 22, 0.62); backdrop-filter: blur(22px) saturate(1.25); -webkit-backdrop-filter: blur(22px) saturate(1.25); }
/* Calculator panels follow the same translucent family as the product cards
   (2026-09-29): the calc theme tokens were solid #15171b / #1d1f24 slabs. */
/* Pop-overs sit on top of other content and must be solid: the profession
   search results and the "Pick a profession" sheet inherited the translucent
   panel token and the fields beneath read through them (2026-09-29). */
html:not([data-theme="light"]) #page-calc .bp-occ-results,
html:not([data-theme="light"]) .bp-persona-modal {
  background: #10151e !important;
  border: 1px solid rgba(255, 255, 255, 0.12) !important;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55) !important;
}
html:not([data-theme="light"]) #page-calc {
  --calc-bg: transparent;
  --calc-panel: rgba(255, 255, 255, 0.035);
  --calc-panel-2: rgba(255, 255, 255, 0.055);
  --calc-panel-hover: rgba(255, 255, 255, 0.08);
  --calc-border: rgba(255, 255, 255, 0.09);
  --calc-border-strong: rgba(255, 255, 255, 0.14);
}
/* No rectangular cell behind the rounded card, on any width: the row and
   cell backgrounds showed at the card's corners (2026-09-29). */
html:not([data-theme="light"]) tr.quote-card, html:not([data-theme="light"]) tr.quote-card > td.quote-card-cell,
html:not([data-theme="light"]) tr.quote-card:hover, html:not([data-theme="light"]) tr.quote-card:hover > td.quote-card-cell { background: transparent !important; }

/* LVR Grid: advanced controls fold behind "More filters" (2026-09-29).
   The segment, loan size and search stay on the main row; the fold opens as
   its own full-width row under it, and the toggle carries a count of folded
   settings that differ from the defaults. */
.lvr-more { display: none; flex-basis: 100%; flex-wrap: wrap; gap: 10px 18px; align-items: center; order: 99; padding-top: 10px; border-top: 1px solid var(--border); }
.lvr-toolbar.more-open .lvr-more { display: flex; }
.lvr-more-toggle { gap: 6px; }
.lvr-more-chev { display: inline-flex; transition: transform .15s; }
.lvr-more-chev .ico { width: 14px; height: 14px; }
.lvr-toolbar.more-open .lvr-more-chev { transform: rotate(180deg); }
.lvr-toolbar.more-open .lvr-more-toggle { color: var(--text); border-color: var(--muted); }
.lvr-more-count { display: inline-flex; align-items: center; justify-content: center; min-width: 17px; height: 17px; padding: 0 5px; border-radius: 999px; background: #2563EB; color: #fff; font-size: var(--fs-3xs); font-weight: 600; line-height: 1; }
.lvr-more-count[hidden] { display: none; }
@media (max-width: 640px) {
  .lvr-toolbar .lvr-ctrl-search { order: 5; }
  .lvr-toolbar .lvr-more-toggle { order: 6; align-self: flex-start; }
  .lvr-toolbar .lvr-more { order: 7; flex-direction: column; align-items: stretch; gap: 8px; padding-top: 8px; }
}

/* Product sheet header follows the Market Pulse family (2026-09-29): amber
   eyebrow (the market), serif title (the product), a plain subtitle (the
   lender). The category badge beside the lender became the eyebrow. */
.prod-modal-eyebrow { margin-bottom: 6px; }
.prod-modal-info .prod-modal-name { margin-bottom: 2px; }
.prod-modal-info .prod-modal-inst { font-size: var(--fs-xs); margin: 0 0 12px; }
@media (max-width: 640px) {
  .prod-modal-identity > .modal-logo, .prod-modal-identity > .bank-logo { grid-row: 1 / span 3; }
  .prod-modal-eyebrow { grid-column: 2; margin: 2px 0 0; padding-right: 48px; }
  .prod-modal-name { padding-right: 40px; }
  .prod-modal-info .prod-modal-inst { margin: 0; }
}

/* APRA Quarterly (2026-09-29): KPI strip, chart titles and the "this series
   is a quarter behind" note as classes instead of per-element inline styles. */
.apra-kpi { padding: 10px 16px; min-width: 110px; flex: 1; }
.apra-kpi-label { font-size: var(--fs-2xs); color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; }
.apra-kpi-value { font-size: var(--fs-md); font-weight: 600; font-feature-settings: 'tnum'; color: var(--text); }
.apra-chart-title { font-size: var(--fs-xs); font-weight: 600; margin-bottom: 8px; color: var(--muted); }
.apra-lag-note { font-size: var(--fs-xs); color: var(--muted); margin-bottom: 14px; padding: 8px 12px; border-left: 2px solid var(--amber); background: var(--subtle); border-radius: 0 6px 6px 0; }

/* Data Quality (2026-09-29 signed-in sweep): the grade pills sat 18px in from
   the content edge (the generic .table-toolbar padding, meant for toolbars
   inside a table card); on phones the title, search and refresh shared one
   row and pushed refresh off the screen, and two card columns at 390px wrapped
   every badge onto three lines. */
#page-compliance .table-toolbar { padding-left: 0; padding-right: 0; }
@media (max-width: 640px) {
  #page-compliance .section-row { flex-wrap: wrap; row-gap: 12px; }
  #page-compliance .section-row > :first-child { flex: 1 1 100%; }
  #page-compliance .section-row > .gsearch { flex: 1 1 0; min-width: 0; }
  #page-compliance #compliance-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ── APRA tables, one system (2026-09-30) ──────────────────────────────────
   The operator: "the experience in mobile when it comes to tables is not up
   to spec and seems to be stitched up together". It was: fifteen phone
   passes had layered rules on `main .data-table` and `.apra-inner-table`
   (a 68 then 74px column, the logo stacked over the name, rows of 56, 58, 60
   and 66px, counts hidden in one table and shown in the next), so Total
   Lending rows ran to 120px and three Foreign Banks names were cut at the
   word "Bank". This block states the whole layout once, for every table on
   the APRA page, measured against the LVR grid (the site's reference grid:
   one-line identity column, 12.5px monospace figures, 10px uppercase
   headers). It is scoped by id so it outranks the old rules without
   touching the other pages that still read them.

   Headers pin through apra-pinned-heads.ts (a fixed mirror of each <thead>,
   because a sideways scroller is a scroll container on both axes and a
   sticky header inside it can never pin to the page). */

/* The initials tile shows only when there is no logo before it, or the
   logo failed and imgHide hid it. */
.apra-logo-ini { display: inline-flex; }
img.apra-logo:not([style*="display: none"]) + .apra-logo-ini { display: none; }

.apra-pinhead { position: fixed; z-index: 16; display: none; }
.apra-pinhead.on { display: block; }
.apra-pinhead-in {
  overflow: hidden; background: var(--bg);
  border-bottom: 1px solid var(--border);
  box-shadow: 0 8px 14px -10px rgba(0, 0, 0, 0.45);
}
.apra-pinhead-table { border-collapse: separate !important; border-spacing: 0 !important; }
.apra-pinhead-table thead th { background: var(--bg) !important; }
html:not([data-theme="light"]) .apra-pinhead-in,
html:not([data-theme="light"]) .apra-pinhead-table thead th { background: #0a0e16 !important; }
/* the stuck band's soft fade would sit over the pinned header's labels */
body.apra-head-pinned #page-analytics-apra .is-stuck::after { display: none; }

/* A wrapped segmented row is a set of chips, not a track: the inline
   border-bottom on #apra-growth-section-nav, bent by the family's 999px
   radius, drew an arc under the sixteen Credit & Funding chips. */
#page-analytics-apra .seg-wrap { border: 0 !important; border-radius: 0 !important; }

/* Quarterly section headings pin under the tab row as glass, like every
   other band (they were an opaque black slab, 3px below the row). */
@media (max-width: 640px) {
  .apra-sec-head { top: 107px; }
}
html:not([data-theme="light"]) .apra-sec-head { background: transparent !important; }
html:not([data-theme="light"]) .apra-sec-head.is-stuck {
  background: rgba(10, 14, 22, 0.62) !important;
  backdrop-filter: blur(22px) saturate(1.25); -webkit-backdrop-filter: blur(22px) saturate(1.25);
}

@media (max-width: 640px) {
  #page-analytics-apra .hscroll-wrap { overscroll-behavior-x: contain; }
  #page-analytics-apra .hscroll-wrap > table {
    table-layout: auto !important; width: max-content !important; min-width: 100% !important;
  }
  #page-analytics-apra .hscroll-wrap > table :is(th, td):not([colspan]) {
    padding: 0 10px !important; white-space: nowrap !important; vertical-align: middle !important;
  }
  #page-analytics-apra .hscroll-wrap > table > thead th {
    height: 34px !important; font-size: var(--fs-3xs) !important; letter-spacing: 0.05em !important;
  }
  #page-analytics-apra .hscroll-wrap > table > tbody td:not([colspan]) { height: 42px !important; }

  /* The identity column: logo (or initials) beside a short name, never
     above it; two lines at most; frozen and opaque. */
  #page-analytics-apra .hscroll-wrap > table :is(td, th):first-child:not([colspan]) {
    position: sticky !important; left: 0 !important; z-index: 4 !important;
    width: 140px !important; min-width: 140px !important; max-width: 140px !important;
    padding: 0 8px 0 10px !important; white-space: normal !important; text-align: left !important;
    box-shadow: none !important;
  }
  #page-analytics-apra .hscroll-wrap > table > thead th:first-child { z-index: 5 !important; }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child > span:first-child {
    display: inline-flex !important; flex-direction: row !important; align-items: center !important; gap: 8px !important;
    text-align: left !important; margin: 0 !important; max-width: 100% !important; max-height: none !important;
    font-size: var(--fs-xs) !important; line-height: 1.2 !important; overflow: visible !important;
    word-break: normal !important; overflow-wrap: normal !important; hyphens: manual !important; vertical-align: middle;
  }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child .apra-logo {
    width: 20px !important; height: 20px !important; margin: 0 !important; border-radius: 5px !important;
    font-size: 8px !important;
  }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child img.apra-logo { display: block !important; }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child .apra-logo-ini { display: inline-flex !important; }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child img.apra-logo:not([style*="display: none"]) + .apra-logo-ini { display: none !important; }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child .apra-nm-full { display: none !important; }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child .apra-nm-short {
    display: -webkit-box !important; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; white-space: normal; max-height: none !important; min-width: 0;
    font-size: var(--fs-xs) !important; font-weight: 500; line-height: 1.2 !important;
  }
  /* counts beside a group name are the number readers look for; any other
     chip after the name (the Quarterly peer badge) is noise at this width */
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child > span:not(:first-child) { display: none !important; }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child .apra-count {
    display: inline !important; background: none !important; padding: 0 !important; margin-left: 5px !important;
    font-size: var(--fs-3xs) !important; color: var(--muted) !important;
  }
  /* Scanner group rows: "Big 4 subtotal 4 ADIs" reads across, like a group
     row everywhere else. */
  #page-analytics-apra .apra-scan-scroll .apra-scan-group-count {
    display: inline !important; margin: 0 0 0 5px !important;
  }
}
/* the mirror is outside the scroller, so it restates the header cell rules */
.apra-pinhead-table :is(th, td) { white-space: nowrap !important; overflow: hidden; text-overflow: clip; }
@media (max-width: 640px) {
  .apra-pinhead-table :is(th, td) {
    padding: 0 10px !important; vertical-align: middle !important;
    height: 34px !important; font-size: var(--fs-3xs) !important; letter-spacing: 0.05em !important;
  }
  .apra-pinhead-table th:first-child {
    position: sticky !important; left: 0 !important; z-index: 2 !important;
    padding: 0 8px 0 10px !important; text-align: left !important; box-shadow: none !important;
    border-right: 1px solid var(--border) !important;
  }
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child span.apra-count {
    display: inline !important; background: none !important; padding: 0 !important; margin-left: 5px !important;
    font-size: var(--fs-3xs) !important; color: var(--muted) !important;
  }
  #page-analytics-apra #apra-growth-tbody tr[data-action] td:first-child > span:first-child { margin-right: 5px !important; }
  #page-analytics-apra .apra-scan-scroll td.apra-scan-group-name { font-size: var(--fs-2xs) !important; line-height: 1.2 !important; }
  #page-analytics-apra .apra-scan-scroll .apra-scan-group-count { font-size: var(--fs-3xs) !important; }
}
@media (max-width: 640px) {
  /* the Scanner's count is the first span in its cell, so it must opt out of
     the name-span rule above by name */
  #page-analytics-apra .hscroll-wrap > table > tbody td:first-child > span.apra-scan-group-count:first-child {
    display: inline !important; font-size: var(--fs-3xs) !important; font-weight: 400 !important; margin: 0 0 0 5px !important;
  }
}
@media (max-width: 640px) {
  /* No box inside the page scroll on a phone (the Quarterly capital list was
     600px, the Explore institution list 500px): a nested vertical scroller
     traps the thumb, and the page is what pins the header. The Scanner has
     done this since pass 19. */
  #page-analytics-apra .hscroll-wrap { max-height: none !important; }
}

/* Segment tracks are glass on the glow, SITE-WIDE (2026-09-30, operator):
   they were solid --surface2 slabs. The track carries the fill and hairline;
   the segments inside it carry none (the APRA tabs are .filter-pill buttons
   inside a .seg, and each drew its own glass box inside the track's). The
   chosen segment keeps its fill. Light theme untouched. */
html:not([data-theme="light"]) :is(.seg, .hm-seg, .lvr-seg, #lvr-shelf-multi, .calc-type-group, .calc-term-group,
  .calc-section-seg, #ins-cat-pills, #ins-sev-pills, #health-scheme-filters, #apra-view-toggle):not(.seg-wrap) {
  background: rgba(255, 255, 255, 0.04); border-color: rgba(255, 255, 255, 0.10);
}
html:not([data-theme="light"]) :is(.seg, .hm-seg, .lvr-seg, #lvr-shelf-multi, .calc-type-group, .calc-term-group,
  .calc-section-seg, #ins-cat-pills, #ins-sev-pills, #health-scheme-filters, #apra-view-toggle):not(.seg-wrap)
  > button:not(.active):not(.on):not([aria-pressed="true"]):not(.lvr-seg-active):not(.lvr-multiseg-active) {
  background: transparent; border-color: transparent; box-shadow: none;
}
/* Loose filter pills on the APRA page (Institution Detail) take the same glass */
html:not([data-theme="light"]) #page-analytics-apra .filter-pill:not(.active):not(.seg > .filter-pill) {
  background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.10);
}
html:not([data-theme="light"]) #page-analytics-apra .filter-pill:not(.active):not(.seg > .filter-pill):hover {
  background: rgba(255, 255, 255, 0.08); color: var(--text);
}

/* Selected text in the dark theme (2026-09-30): no ::selection rule existed,
   and the browser default painted a grey box over light-grey text, so a
   highlighted word vanished. Light theme keeps the browser default. */
html:not([data-theme="light"]) ::selection { background: rgba(59, 130, 246, 0.55); color: #fff; }
