.section-loading > * {
  display: none !important;
}
.section-loading {
  display: block !important;
  height: auto !important;
  min-height: 120px !important;
  margin: 16px 0 !important;
  padding: 24px !important;
  border: 0 !important;
  border-radius: var(--radius-lg) !important;
  background: var(--surface) !important;
}
.portfolio-loading {
  position: relative;
  min-height: 120px;
  margin: 16px 0;
  padding: 24px;
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.section-loading::before,
.section-loading::after,
.portfolio-loading::before,
.section-loading::after,
.portfolio-loading::after {
  content: "";
  display: block;
  height: 12px;
  width: 24%;
  border-radius: var(--radius-sm);
  background: var(--surface-soft);
}
.portfolio-loading::after {
  width: 55%;
  height: 28px;
  margin-top: 18px;
}
.portfolio-loading > span {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* InteractiveFIRE stylesheet -- the only one; templates/hosted/base.html links it.
 *
 * DO NOT READ THIS FILE END TO END. Find your section:
 *   grep -n '^/\* -\+' static/style.css
 * then read that band alone. The app pages come first (base, header,
 * navigation, layout, forms, tables, alerts, cards, charts, activity,
 * dashboard, FIRE, analysis, look-through, settings, help), then the public
 * and account pages (landing, legal, sign-in, passkeys, Pro, operator status,
 * the Flex setup guide, the demo ribbon).
 *
 * Conventions (tests/hosted/test_stylesheet_drift.py enforces the first four):
 *   - Layout switches only at 980, 760, 640, 480 and 380px.
 *   - Small labels use --text-2xs or --text-xs; the inset colour is --well-rgb.
 *   - Every colour, radius and shadow comes from a token in :root, so the
 *     chart palette read by IF.colors (static/format.js) and the CSS agree.
 *   - No rule for a class nothing renders.
 *   - One block per selector, per at-rule context.
 *   - Component first, then that component's responsive rules, so a
 *     component is fully described in one place.
 *   - Three responsive table treatments, chosen by table shape:
 *       .card-rows    stack each row into a card (summary/settings tables)
 *       column hiding dense logs where a picker or the charts above cover it
 *       .corr-matrix  matrices, which cannot reflow, get tighter cells
 */

:root {
  --canvas: #0c1017;
  --surface: #171d28;
  --surface-raised: #1c2432;
  --surface-soft: #202a39;
  --well-rgb: 9 16 23;
  --surface-well: rgb(var(--well-rgb) / .34);
  --line: #2b3749;
  --line-strong: #3a4c65;
  --line-hover: #55708e;
  --text: #edf3f8;
  --text-soft: #c3ccd8;
  --text-muted: #8e9bad;
  --text-faint: #6b7789;
  --text-on-accent: #071318;
  /* The two small sizes for labels, captions and sub-lines. */
  --text-2xs: 0.64rem;
  --text-xs: 0.68rem;

  --cyan: #49bfc1;
  --cyan-rgb: 73 191 193;
  --cyan-bright: #6bd0ce;
  --cyan-deep: #398aa5;
  --blue: #6a9ed0;
  --blue-rgb: 106 158 208;
  --blue-bright: #8db9e4;
  --blue-deep: #337f9c;
  --green: #52c88e;
  --green-rgb: 82 200 142;
  --green-bright: #87ddb2;
  --red: #e47b7d;
  --red-rgb: 228 123 125;
  --red-bright: #ef9a9c;
  --amber: #e5b66d;
  --amber-rgb: 229 182 109;
  /* Reserved for a series that must not read as a verdict: green and red mean
     ahead and behind wherever they appear. */
  --pink: #cd8ac4;
  --slate: #60758f;
  --chart-grid: rgb(255 255 255 / .05);

  --radius-sm: 7px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 16px;
  --radius-pill: 999px;
  --radius: var(--radius-md);

  --shadow: 0 12px 32px rgb(0 0 0 / .2);
  --shadow-pop: 0 8px 24px rgb(0 0 0 / .4);
  --shadow-nav: 0 -10px 30px rgb(0 0 0 / .24);
  --focus: 0 0 0 3px rgb(var(--cyan-rgb) / .26);

  --accent-soft: rgb(var(--cyan-rgb) / .14);
  --accent-line: rgb(var(--cyan-rgb) / .4);
}

/* ---------- base ---------- */

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  min-height: 100vh;
  background: var(--canvas);
  color: var(--text);
  /* System stack only: no webfont is shipped with the app, so naming one
     here would just be a font that never loads. IF.applyChartDefaults()
     reads this same stack back out for Chart.js. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  line-height: 1.5;
}

h1, h2, h3 { color: var(--text); }
h1 { font-size: clamp(1.35rem, 2vw, 1.8rem); letter-spacing: -0.025em; }
h2 { font-size: 1.05rem; letter-spacing: -0.01em; }
h3 { font-size: 0.95rem; }

[hidden] { display: none !important; }

.hint { color: var(--text-muted); font-size: 0.9em; line-height: 1.65; margin-bottom: 20px; }
/* Body-copy links have no styling of their own anywhere else, so they fall
   back to the browser blue underline, which is unreadable on the dark
   canvas. Colour carries the link; the underline arrives on hover. */
.hint a { color: var(--text-soft); text-decoration: none; }
.hint a:hover,
.hint a:focus-visible { color: var(--cyan); text-decoration: underline; text-underline-offset: 3px; }
.pos { color: var(--green); }
.neg { color: var(--red); }
.ok { color: var(--green); font-weight: 700; }
.warn { color: var(--amber); }
.empty-cell { color: var(--text-muted); text-align: center; }

/* ---------- labels ----------
   The two small uppercase looks, each written once. A label names the figure
   under it; an eyebrow sits over a heading or a group, tracked wider. Any
   other uppercase text is a heading or a table head, with its own rule. */
.mobile-menu-group > span,
.card-rows tr > *:not(:first-child)::before,
.fire-timeline-label span,
.period-equation-end > span,
.period-equation-key > span,
.scenario-row-label,
.scenario-row-facts span,
.heatmap-half-label,
.drawdown-summary span,
.faq-search,
.holding-hero-return em,
.holding-hero-weight span,
.holding-account-map > span,
.holding-position-strip > span,
.holding-position-strip small,
.settings-subhead {
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: 0.035em;
  text-transform: uppercase;
}
.eyebrow,
.landing-eyebrow,
.landing-feature-kicker,
.landing-data-facts dt,
.ibkr-connection-page .ibkr-map-header span,
.auth-divider {
  font-size: var(--text-xs);
  font-weight: 750;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* ---------- header, navigation ---------- */

.app-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgb(12 16 23 / .94);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(16px);
}
.navbar {
  display: flex;
  align-items: center;
  gap: 18px;
  max-width: 1180px;
  min-height: 64px;
  margin: 0 auto;
  padding: 0 24px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--text);
  font-size: 0.98rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
}
.brand-mark {
  display: block;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  overflow: hidden;
}
.brand-mark img { display: block; width: 50px; height: 50px; margin: -10px; }
.brand-fire { color: var(--green-bright); }
/* The landing page's only header control. Not .desktop-nav, which is display:none
   below 760px because the app replaces it with the bottom tab bar -- the landing
   page has no tab bar, so borrowing that class would hide the one way in on a
   phone. Stays visible at every width; the label is short enough to.

   Size comes from the shared .btn-primary rule, which is further down the file
   and so wins on equal specificity -- only what it does not set belongs here. */
.header-signin {
  margin-left: auto;
  font-size: 0.84rem;
  text-decoration: none;
}
.desktop-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  margin-left: auto;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
}
.nav-links > a {
  position: relative;
  padding: 9px 11px;
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  font-size: 0.82rem;
  text-decoration: none;
  transition: color 150ms ease, background 150ms ease;
}
.nav-links > a:hover,
.nav-links > a.active {
  color: var(--text);
  background: var(--surface-raised);
}
.nav-links > a.active::after {
  position: absolute;
  right: 11px;
  bottom: -17px;
  left: 11px;
  height: 2px;
  background: var(--cyan);
  border-radius: 2px;
  content: "";
}
.nav-more { position: relative; }
.nav-more-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 8px 10px;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  font-size: 0.82rem;
  font-weight: 400;
}
.nav-more-toggle:hover,
.nav-more-toggle.active,
.nav-more-toggle[aria-expanded="true"] { color: var(--text); background: var(--surface-raised); border-color: transparent; }
.nav-more-toggle.active::after {
  position: absolute;
  right: 10px;
  bottom: -14px;
  left: 10px;
  height: 2px;
  background: var(--cyan);
  border-radius: 2px;
  content: "";
}
.nav-chevron {
  width: 7px;
  height: 7px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 150ms ease;
}
.nav-more-toggle[aria-expanded="true"] .nav-chevron { margin-top: 3px; transform: rotate(225deg); }
.nav-more-menu {
  position: absolute;
  top: calc(100% + 13px);
  right: 0;
  display: grid;
  width: 238px;
  padding: 7px;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-pop);
}
.nav-more-menu a {
  display: grid;
  gap: 1px;
  padding: 9px 11px;
  color: var(--text-soft);
  border-radius: var(--radius-sm);
  text-decoration: none;
}
.nav-more-menu a:hover,
.nav-more-menu a[aria-current="page"] { color: var(--text); background: var(--surface-soft); }
.nav-more-menu a span { font-size: 0.84rem; font-weight: 650; }
.nav-more-menu a small { color: var(--text-muted); font-size: var(--text-xs); }
.portfolio-scope {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 0 0 auto;
  padding-left: 15px;
  border-left: 1px solid var(--line);
}
.portfolio-scope select {
  width: 156px;
  min-width: 0;
  min-height: 38px;
  padding: 7px 30px 7px 11px;
  background-color: var(--surface-raised);
  border-color: var(--line-strong);
  font-size: 0.82rem;
  font-weight: 650;
}
/* FIRE pins the selector to Combined: the household aggregate is the only
   scope it can honour, so the control keeps its size but reads as context. */
.portfolio-scope select:disabled {
  color: var(--text-muted);
  opacity: 1;
  cursor: default;
}
/* No accounts imported yet: no divider without a control beside it. */
.portfolio-scope:empty { border-left-color: transparent; }

/* The bottom tab bar is the only mobile navigation; there is no hamburger
   duplicate of .nav-links to keep in sync. */
.mobile-tabs { display: none; }

@media (max-width: 980px) {
  .brand-name { display: none; }
  .navbar { padding: 0 18px; }
  .nav-links { gap: 0; }
  .nav-links > a { padding-right: 7px; padding-left: 7px; font-size: 0.76rem; }
  .nav-links > a.active::after { right: 7px; bottom: -17px; left: 7px; }
  .nav-more-toggle { padding-right: 7px; padding-left: 7px; font-size: 0.76rem; }
  .nav-more-toggle.active::after { right: 7px; left: 7px; }
  .portfolio-scope { padding-left: 11px; }
  .portfolio-scope select { width: 142px; }
}

@media (max-width: 760px) {
  body { padding-bottom: calc(78px + env(safe-area-inset-bottom)); }
  .navbar { min-height: 58px; padding: 0 14px; }
  .brand-name { display: inline; }
  .desktop-nav { display: none; }
  .portfolio-scope { margin-left: auto; padding-left: 12px; }
  .portfolio-scope select { width: min(39vw, 148px); min-height: 40px; }
  .mobile-tabs {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 60;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    min-height: 64px;
    padding: 7px 8px calc(7px + env(safe-area-inset-bottom));
    background: rgb(18 24 34 / .97);
    border-top: 1px solid var(--line);
    box-shadow: var(--shadow-nav);
    backdrop-filter: blur(16px);
  }
  .mobile-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 50px;
    padding: 5px 3px;
    color: var(--text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm);
    font-size: var(--text-2xs);
    font-weight: 600;
    text-decoration: none;
  }
  .mobile-tab svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.8; }
  .mobile-tab.active { color: var(--cyan); background: rgb(var(--cyan-rgb) / .1); }
  .mobile-more {
    position: absolute;
    right: 9px;
    bottom: calc(72px + env(safe-area-inset-bottom));
    display: grid;
    min-width: 220px;
    max-height: min(70vh, 480px);
    padding: 6px;
    overflow-y: auto;
    background: var(--surface-raised);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow);
  }
  .mobile-menu-group { display: grid; padding: 4px 0; }
  .mobile-menu-group + .mobile-menu-group { border-top: 1px solid var(--line); }
  .mobile-menu-group > span { padding: 6px 12px 3px; }
  .mobile-more a { padding: 9px 12px; color: var(--text-soft); border-radius: 6px; font-size: 0.84rem; text-decoration: none; }
  .mobile-more a:hover,
  .mobile-more a[aria-current="page"] { color: var(--text); background: var(--surface-soft); }
}

@media (max-width: 380px) {
  .brand-name { display: none; }
  .portfolio-scope select { width: 148px; }
}

/* ---------- page layout ---------- */

.container {
  max-width: 1160px;
  margin: 30px auto;
  padding: 0 28px;
}
.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-bottom: 26px;
}
.page-head > h1 { margin: 0; font-weight: 720; }
.page-head > p,
.page-head .hint { max-width: 680px; margin: 5px 0 0; }
.page-header-block { margin-bottom: 8px; }

/* Section headers: one treatment everywhere, so a section label cannot end
   up three different sizes on three pages. .analysis-section-head only
   adjusts spacing inside an .analysis-panel. The header's own padding is the
   whole gap to its content, as on the Dashboard, so the block after it brings
   no top margin of its own. */
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-top: 30px;
  padding-bottom: 10px;
}
.section-head > h2 {
  margin: 0;
  color: var(--text);
  font-size: 0.82rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.analysis-section-head { margin-top: 0; }
.section-head.analysis-section-head + * { margin-top: 0; }
/* A panel's header is one compact control tall whether or not a control
   shares the title's line, so the title sits at the same place in every
   panel. Controls in it shrink to that height. */
.panel > .section-head { min-height: 42px; }
/* The title keeps its one line and its centre even where a narrow layout
   stretches the header's items or widens its control. */
.panel > .section-head > h2 { display: flex; flex-shrink: 0; align-items: center; }
.panel > .section-head .segmented-control button { min-height: 24px; padding-top: 2px; padding-bottom: 2px; }
.panel > .section-head input:not([type="checkbox"]):not([type="radio"]) { height: 32px; min-height: 32px; padding-top: 0; padding-bottom: 0; }
.section-context { color: var(--text-muted); font-size: 0.78rem; white-space: nowrap; }
.section-context[title] { cursor: help; }
/* One fact belonging to the whole panel -- a plan name, the signed-in address --
   sat beside the heading instead of spending a line under it.

   Two variants, because the heading beside them is uppercased by CSS: a label we
   author reads as one of ours in the same case, while a value somebody typed is
   shown as they typed it. Upper-casing an email address would be a lie about
   what it is. */
.section-tag { color: var(--text-soft); font-size: 0.78rem; letter-spacing: 0.03em; }
.section-tag-label {
  color: var(--cyan);
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.dashboard-section > .section-head:first-child { margin-top: 0; }

@media (max-width: 760px) {
  .container { margin-top: 16px; margin-bottom: 20px; padding: 0 16px; }
  /* The gap under a page title is whatever the first block below it brings
     with it, not the title's own margin -- these are the two that set it. */
  .page-header-block { margin-bottom: 0; }
  /* Several pages put a hidden status alert directly under the title, so the
     block that actually shows up first is one or two siblings along. */
  .page-header-block + *,
  .page-header-block + [hidden] + *,
  .page-header-block + [hidden] + [hidden] + * { margin-top: 12px; }
  .page-head { flex-wrap: nowrap; gap: 12px; margin-bottom: 14px; }
  .page-head > h1 { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* The active tab already names these pages; the title stays for screen
     readers only. Same breakpoint as the tab bar. */
  .page-head-tabbed {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .page-head-tabbed + *,
  .page-head-tabbed + [hidden] + *,
  .page-head-tabbed + [hidden] + [hidden] + * { margin-top: 0; }
  .section-head { gap: 10px; margin-top: 20px; }
  .section-head.analysis-section-head { margin-top: 0; }

}

@media (max-width: 480px) {
  .container { margin-top: 12px; margin-bottom: 16px; padding: 0 10px; }
  .navbar { padding: 0 14px; }
  .brand { font-size: 0.9rem; }
  .page-head { margin-bottom: 10px; }
  .section-head { flex-direction: column; align-items: flex-start; }
  /* Stacked under the title, header controls no longer set its line height:
     give them back their full touch size. */
  .panel > .section-head { min-height: 0; }
  .panel > .section-head .segmented-control button { min-height: 32px; padding-top: 5px; padding-bottom: 5px; }
  .panel > .section-head input:not([type="checkbox"]):not([type="radio"]) { height: auto; min-height: 38px; padding-top: 8px; padding-bottom: 8px; }
  .panel > .section-head .contribution-scenario-form input:not([type="checkbox"]):not([type="radio"]) { min-height: 34px; padding-top: 5px; padding-bottom: 5px; }
  /* The contribution total is a short amount that belongs beside its heading;
     stacking it costs a line for nothing. */
  .dashboard-contribution .section-head { flex-direction: row; align-items: baseline; justify-content: space-between; }
}

/* ---------- form controls ---------- */

select,
input,
button,
textarea { font: inherit; }

/* Single source of truth for every text-like field's look, so no input
   anywhere in the app can be left unstyled (falling back to a native white
   box) just because it wasn't inside a .form-card/.config-grid container.
   Deliberately excludes hidden/checkbox/radio/file, which need their own
   (or no) presentation rather than a text-box style. Sits slightly darker
   than its surrounding card (--canvas vs --surface) so fields read as a
   recessed well rather than blending flat into the card. */
input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select,
textarea {
  padding: 8px 12px;
  background: var(--canvas);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
}
/* A long option (fund names especially) otherwise runs under the browser's
   own dropdown arrow instead of stopping short of it -- the 12px above only
   clears a short value. */
select {
  padding-right: 32px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
input[type="checkbox"],
input[type="radio"] { accent-color: var(--cyan); }

input:focus-visible,
select:focus-visible,
button:focus-visible,
a:focus-visible,
summary:focus-visible,
tr:focus-visible,
.data-table th.th-sortable:focus-visible {
  outline: 0;
  box-shadow: var(--focus);
}

/* Buttons come in one accent variant for the single main action of a view
   (.btn-primary), the neutral default for everything else, and .btn-danger
   for destructive ones. .btn-secondary is the neutral look as a class, so an
   <a> can adopt it; on a real <button> it is already the default. */
button,
.btn-primary,
.btn-secondary,
.btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, transform 150ms ease;
}
button,
.btn-secondary {
  color: var(--text-soft);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
}
button:hover,
.btn-secondary:hover { background: var(--surface-soft); border-color: var(--line-hover); }
.btn-primary {
  color: var(--text-on-accent);
  background: var(--cyan);
  border: 1px solid var(--cyan);
}
.btn-primary:hover { background: var(--cyan-bright); border-color: var(--cyan-bright); }
.btn-danger {
  color: var(--red);
  background: rgb(var(--red-rgb) / .1);
  border: 1px solid rgb(var(--red-rgb) / .34);
}
.btn-danger:hover { color: var(--red-bright); background: rgb(var(--red-rgb) / .2); }
button:active,
.btn-primary:active,
.btn-secondary:active,
.btn-danger:active { transform: translateY(1px); }
button:disabled,
button[aria-disabled="true"] { cursor: not-allowed; opacity: 0.48; }

.form-card {
  padding: 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
}
.form-card label { display: block; margin-bottom: 16px; color: var(--text-soft); font-size: 0.9em; }
.form-card small { color: var(--text-muted); }
.form-card small.field-note { display: block; margin: -4px 0 16px; padding-left: 4px; font-size: 0.8em; }
.field-error,
.form-card label small.field-error,
.field-form label small.field-error { display: block; margin-top: 5px; color: var(--red-bright); font-size: 0.78rem; line-height: 1.4; }
/* Excludes checkbox/radio for the same reason the base input rule above does:
   stretching one to the full width of a card turns a tick box into a large empty
   square that reads as a broken text field. They keep their intrinsic size and
   sit beside their label in a .field-row. */
.form-card input:not([type="checkbox"]):not([type="radio"]),
.form-card select,
.form-card textarea { display: block; width: 100%; margin-top: 4px; min-height: 38px; }
.form-card .field-row input[type="checkbox"] { width: auto; min-height: 0; margin: 0; }
.settings-form-grid {
  display: grid;
  /* auto-fit rather than a fixed pair with a max-width: two columns capped at
     720px left a third of a wide settings panel empty. */
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}
.settings-form-grid label { margin: 0; }
.settings-form-grid > button,
.settings-form-grid > .btn-primary { grid-column: 1 / -1; justify-self: start; }
.month-selects { display: flex; gap: 8px; }
.month-selects select { flex: 1; }
.field-row { display: flex; align-items: center; gap: 9px; margin-bottom: 20px; }
/* margin: 0 undoes .form-card label's bottom margin, which the centring
   would otherwise count, leaving the text above its checkbox. */
.field-row label { margin: 0; color: var(--text-muted); font-size: 0.9em; }
.field-row input[type="checkbox"] { flex-shrink: 0; }
.action-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 0;
}
/* A panel's action sits at its bottom right, where the eye leaves the thing it
   just filled in. Applied per toolbar rather than to .action-toolbar itself:
   onboarding's footer splits Back and Continue to opposite ends, and the
   older pages render this class too. */
.actions-end { justify-content: flex-end; }
/* A sentence and the button it describes on one line: the explanation sits at
   the left, the action at the right edge it would have had on its own. */
.actions-split { align-items: center; justify-content: flex-end; }
/* The auto right margin rather than space-between: the sentence is sometimes
   hidden (the passkey note waits for JavaScript to confirm support), and
   space-between would slide the button to the left when it is. */
.actions-split .hint { max-width: 62ch; margin: 0 auto 0 0; }
.allocation-target-column { width: 190px; min-width: 190px; }
.allocation-target-input { display: flex; align-items: center; gap: 8px; }
.allocation-target-input .compact-number { width: 150px; min-width: 150px; padding: 6px 10px; }
.compact-group { width: 140px; padding: 6px 8px; }
.holdings-filter { width: 100%; max-width: 260px; min-height: 38px; }

@media (max-width: 760px) {
  .settings-form-grid { grid-template-columns: 1fr; }
  .action-toolbar { display: grid; grid-template-columns: 1fr; }
  .action-toolbar button,
  .action-toolbar .btn-primary { width: 100%; }
  .allocation-target-column { width: auto; min-width: 0; }
  .allocation-target-input .compact-number { width: 100%; min-width: 0; }
  .compact-group { width: 130px; }
  .holdings-filter { max-width: none; }
}

@media (max-width: 480px) {
  .form-card { padding: 16px; }
}

/* ---------- tables ---------- */

.data-table {
  width: 100%;
  margin-top: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-collapse: collapse;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.data-table th,
.data-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 0.9em;
  text-align: left;
}
.data-table th {
  background: var(--surface-raised);
  color: var(--text-muted);
  font-size: 0.8em;
  letter-spacing: 0.025em;
  text-transform: uppercase;
}
.data-table td { color: var(--text-soft); }
.data-table tbody tr:hover { background: rgb(var(--cyan-rgb) / .045); }
.data-table .hint { margin: 0; }
.data-table input,
.data-table select { min-height: 34px; padding: 6px 8px; }
.data-table button { min-height: 34px; padding: 6px 12px; }
.table-scroll { overflow-x: auto; border-radius: var(--radius-md); -webkit-overflow-scrolling: touch; }

/* Sortable headers are focusable (see IF.sortableHeadCell), so the focus
   ring below is reachable rather than decorative. */
.data-table th.th-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.data-table th.th-sortable:hover { color: var(--text); }
.data-table th .th-caret { margin-left: 2px; color: var(--cyan); font-size: 0.75em; }
.data-table th:not(.th-asc):not(.th-desc) .th-caret { visibility: hidden; }

.data-table tr.group-row { cursor: pointer; font-weight: 600; }
.data-table tr.group-row:hover { background: rgb(var(--cyan-rgb) / .08); }
.data-table tr.group-row .group-caret { display: inline-block; width: 1em; color: var(--cyan); }
.data-table tr.group-detail td { color: var(--text-muted); font-weight: 400; }

/* Percentage and bar share one line: stacked, they made every holdings row
   two lines tall for a 4px graphic. */
.allocation-value { display: inline-block; line-height: 1.2; }
.allocation-bar {
  display: inline-block;
  width: 54px;
  height: 4px;
  margin-left: 8px;
  vertical-align: middle;
  overflow: hidden;
  background: var(--surface-soft);
  border-radius: var(--radius-pill);
}
.allocation-bar > span {
  display: block;
  height: 100%;
  min-width: 2px;
  background: linear-gradient(90deg, var(--cyan-deep), var(--cyan));
  border-radius: inherit;
}
.member-chip {
  display: inline-block;
  margin: 2px 3px 2px 0;
  padding: 3px 7px;
  color: var(--text-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.member-chip.legacy { color: var(--amber); border-color: rgb(var(--amber-rgb) / .45); }

.corr-matrix th,
.corr-matrix td { text-align: center; }
.corr-matrix th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface-raised);
  text-align: left;
}
.corr-cell { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }

.holdings-toolbar { position: relative; display: flex; justify-content: flex-end; gap: 8px; }
.holdings-toolbar button { min-height: 34px; padding: 6px 12px; font-size: 0.85em; }
.holdings-toolbar button[aria-pressed="true"] {
  color: var(--cyan);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.cols-menu {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 20;
  min-width: 240px;
  margin-top: 6px;
  padding: 12px;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-pop);
}
.cols-menu-hint { margin: 0 0 8px; color: var(--text-muted); font-size: 0.78em; }
.cols-list { margin: 0; padding: 0; list-style: none; }
.cols-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  border-radius: 4px;
  font-size: 0.88em;
  cursor: grab;
}
.cols-item:hover { background: var(--surface-raised); }
.cols-item.dragging { opacity: 0.5; }
.cols-item label { display: flex; flex: 1; align-items: center; gap: 6px; cursor: pointer; }
.cols-grip { color: var(--text-faint); cursor: grab; user-select: none; }

.fire-breakdown-table td { font-variant-numeric: tabular-nums; }
.bucket-table th:first-child { white-space: nowrap; }
.bucket-table .benchmark-badge { margin-left: 4px; color: var(--cyan); font-size: 0.85em; cursor: help; }
.holdings-table { margin-top: 0; }
/* One line per ticker. The description trails the symbol and is clipped to
   fit rather than claiming a second line of its own on every row. */
.holdings-table td { padding: 7px 12px; }
.holdings-table td:first-child { min-width: 220px; white-space: nowrap; }
.holdings-table td:first-child small {
  display: inline-block;
  max-width: 170px;
  margin-left: 8px;
  overflow: hidden;
  color: var(--text-muted);
  font-size: var(--text-xs);
  text-overflow: ellipsis;
  vertical-align: bottom;
}
.holdings-table td:not(:first-child) { font-variant-numeric: tabular-nums; white-space: nowrap; }
.holdings-sort { max-width: calc(100% - 110px); overflow-x: auto; }
.holdings-sort button { flex: 0 0 auto; white-space: nowrap; }
.holdings-pagination { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.holdings-more { margin: 0; }
.holdings-less { margin-left: auto; }
@media (min-width: 641px) {
  .dashboard-holdings .table-scroll { overflow: visible; }
  .holdings-table { display: block; width: 100%; background: transparent; border: 0; box-shadow: none; }
  .holdings-table thead { display: none; }
  .holdings-table tbody { display: block; width: 100%; }
  .holdings-table thead tr { display: inline-flex; max-width: 100%; padding: 3px; align-items: stretch; overflow-x: auto; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md); }
  .holdings-table thead th { display: inline-flex; width: auto; min-height: 32px; padding: 5px 12px; flex: 0 0 auto; align-items: center; justify-content: center; color: var(--text-muted); background: transparent; border: 0; border-radius: var(--radius-sm); font-size: .78rem; font-weight: 400; letter-spacing: 0; text-transform: none; }
  .holdings-table thead th:hover { color: var(--text); background: var(--surface-soft); }
  .holdings-table thead th.th-asc,
  .holdings-table thead th.th-desc { color: var(--cyan); background: var(--accent-soft); box-shadow: none; }
  .holdings-table tbody tr { display: grid; grid-template-columns: minmax(200px, 1fr) minmax(95px, 120px) minmax(74px, 90px) minmax(74px, 90px) minmax(105px, 125px); align-items: baseline; gap: 4px 12px; padding: 14px 4px 10px; border-bottom: 1px solid var(--line); }
  .holdings-table tbody tr:hover { background: rgb(var(--cyan-rgb) / .025); }
  .holdings-table td { padding: 0; border: 0; }
  .holdings-table td[data-col="symbol"] { grid-column: 1; grid-row: 1; min-width: 0; }
  .holdings-table td[data-col="value_eur"] { grid-column: 2; grid-row: 1; color: var(--text); font-size: .88rem; font-weight: 700; text-align: right; }
  .holdings-table td[data-col="twr_1y_pct"] { grid-column: 3; grid-row: 1; text-align: right; }
  .holdings-table td[data-col="twr_annualized_pct"] { grid-column: 4; grid-row: 1; text-align: right; }
  .holdings-table td[data-col="unrealized_eur"] { grid-column: 5; grid-row: 1; text-align: right; }
  .holdings-table td[data-col="twr_1y_pct"]::before { content: "1Y "; }
  .holdings-table td[data-col="twr_annualized_pct"]::before { content: "/yr "; }
  .holdings-table td[data-col="unrealized_eur"]::before { content: "P/L "; }
  .holdings-table td[data-col="twr_1y_pct"]::before,
  .holdings-table td[data-col="twr_annualized_pct"]::before,
  .holdings-table td[data-col="unrealized_eur"]::before { color: var(--text-muted); font-size: var(--text-xs); font-weight: 500; }
  .holdings-table td[data-col="pct_of_portfolio"] { display: flex; grid-column: 1 / -1; grid-row: 2; align-items: center; gap: 9px; }
  .holdings-table td[data-col="pct_of_portfolio"] .allocation-value { order: 2; color: var(--text-muted); font-size: var(--text-2xs); }
  .holdings-table td[data-col="pct_of_portfolio"] .allocation-bar { width: auto; height: 3px; margin: 0; flex: 1 1 auto; }
  .holdings-table td.empty-cell { grid-column: 1 / -1; }
}
@media (min-width: 641px) and (max-width: 760px) {
  .holdings-sort button[data-key="twr_annualized_pct"] { display: none; }
  .holdings-table tbody tr { grid-template-columns: minmax(180px, 1fr) 105px 78px 112px; }
  .holdings-table td[data-col="twr_annualized_pct"] { display: none; }
  .holdings-table td[data-col="unrealized_eur"] { grid-column: 4; }
}
@media (max-width: 760px) {
  .holdings-pagination { align-items: stretch; flex-direction: column; }
  .holdings-more,
  .holdings-less { width: 100%; justify-content: center; }
  .holdings-less { margin-left: 0; }
}

@media (max-width: 760px) {
  /* Matrix-shaped tables (correlation grids, the contribution-pace heatmap)
     can't reflow into a narrower column count. Every other .data-table sizes
     to its own content instead of being forced wide — most fit the viewport
     outright; genuinely dense ones still fall back to .table-scroll's
     horizontal scroll, just without an arbitrary 680px minimum tacked on
     regardless of column count. Matrices get tighter padding/font instead of
     a floor, so small ones fit outright and large ones scroll less. */
  .data-table.corr-matrix { min-width: 0; }
  .data-table.corr-matrix th,
  .data-table.corr-matrix td { padding: 6px 7px; font-size: 0.74em; }
  .data-table.corr-matrix th { font-size: 0.68em; }
  .data-table.corr-matrix th:not(:first-child),
  .data-table.corr-matrix .corr-cell { min-width: 34px; }
  .table-scroll { max-width: 100%; overflow-x: auto; }
  /* No column-picker exists on this page (unlike Activity) — drop everything
     except the company name and one number; the aggregated charts above
     already cover country/sector, and rank adds little a mobile glance
     actually needs. Which number that is comes from data-mobile-col, which
     lookthrough.js cycles when the header is tapped, so a phone can read the
     same rows as a percentage or as euros. Selection is by position and CSS
     cannot interpolate nth-child, so each possible column gets its own rule
     (3-5 covers both views' numeric columns). */
  .lookthrough-holdings-table[data-mobile-col="3"] th:not(:nth-child(2)):not(:nth-child(3)),
  .lookthrough-holdings-table[data-mobile-col="3"] td:not(:nth-child(2)):not(:nth-child(3)),
  .lookthrough-holdings-table[data-mobile-col="4"] th:not(:nth-child(2)):not(:nth-child(4)),
  .lookthrough-holdings-table[data-mobile-col="4"] td:not(:nth-child(2)):not(:nth-child(4)),
  .lookthrough-holdings-table[data-mobile-col="5"] th:not(:nth-child(2)):not(:nth-child(5)),
  .lookthrough-holdings-table[data-mobile-col="5"] td:not(:nth-child(2)):not(:nth-child(5)) { display: none; }
  /* The tap target that cycles it, marked so it does not read as a plain
     sortable header. The caret keeps its sort meaning on wider screens. */
  .lookthrough-holdings-table th.metric-toggle .th-caret { display: none; }
  .lookthrough-holdings-table th.metric-toggle::after { content: " ⇄"; opacity: .6; }
  /* The whole column is the tap target, and its width is fixed at the widest
     of the three numbers it can show, so cycling does not shift the layout. */
  .lookthrough-holdings-table[data-mobile-col="3"] th:nth-child(3),
  .lookthrough-holdings-table[data-mobile-col="3"] td:nth-child(3),
  .lookthrough-holdings-table[data-mobile-col="4"] th:nth-child(4),
  .lookthrough-holdings-table[data-mobile-col="4"] td:nth-child(4),
  .lookthrough-holdings-table[data-mobile-col="5"] th:nth-child(5),
  .lookthrough-holdings-table[data-mobile-col="5"] td:nth-child(5) {
    width: 7rem;
    min-width: 7rem;
    max-width: 7rem;
    text-align: right;
    cursor: pointer;
  }
}

@media (max-width: 640px) {
  .dashboard-holdings .section-head { align-items: stretch; }
  .holdings-sort { width: 100%; max-width: none; }
  /* Shared "stacked card per row" treatment for dense tables where the row
     identity is sometimes a <th> (Contribution scenarios) and sometimes a
     plain <td> (Settings tables) — used by Contribution scenarios,
     Investments, Instrument data, Look-through data sources, Sync history.
     Each field renders as a small stat tile (muted uppercase label above,
     value below) in a 2-column grid, the same label-over-value language
     already used by .contribution-summary-grid/.pulse-card elsewhere in
     the app, rather than a flat label:value list that read as one
     undifferentiated block. Fields with a real input/select span both
     columns, since their fixed widths (92-260px) don't fit a half-width tile. */
  .card-rows { min-width: 0; margin: 0; background: transparent; border: 0; box-shadow: none; }
  .card-rows thead { display: none; }
  .card-rows, .card-rows tbody { display: block; width: 100%; }
  .card-rows tr {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px 14px;
    margin-bottom: 10px;
    padding: 14px;
    background: var(--surface-raised);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
  }
  .card-rows tr:last-child { margin-bottom: 0; }
  .card-rows tr > *:first-child {
    grid-column: 1 / -1;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
    color: var(--text);
    white-space: normal;
    font-weight: 600;
  }
  .card-rows tr > *:not(:first-child) { display: flex; flex-direction: column; gap: 3px; padding: 0; border: 0; white-space: normal; }
  .card-rows tr > *:not(:first-child)::before {
  content: attr(data-label);
}
  .card-rows tr > *:not(:first-child):has(input:not([type=hidden]):not([type=checkbox]):not([type=radio]), select) { grid-column: 1 / -1; }
  .card-rows tr > *:not(:first-child):has(input:not([type=hidden]):not([type=checkbox]):not([type=radio]), select) input,
  .card-rows tr > *:not(:first-child):has(input:not([type=hidden]):not([type=checkbox]):not([type=radio]), select) select { width: 100%; }
  /* Holdings are the one table here that does not take the card treatment:
     one labelled tile per number ran to eight lines a ticker. */
  .holdings-table {
    display: block;
    margin: 0;
    background: transparent;
    border: 0;
    box-shadow: none;
  }
  .holdings-table tbody { display: block; }
  .holdings-table thead { display: none; }
  .holdings-table tr {
    display: grid;
    /* The unrealised-gain track carries a euro amount, and sits under the
       value, so it takes what it needs and the two percentages split the
       rest. */
    grid-template-columns: 1fr 1fr auto;
    align-items: baseline;
    column-gap: 10px;
    row-gap: 2px;
    padding: 10px 2px 0;
  }
  .holdings-table td { padding: 0; border: 0; }
  .holdings-table td[data-col="symbol"] {
    grid-column: 1 / 3;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .holdings-table td[data-col="value_eur"] {
    grid-column: 3;
    justify-self: end;
    color: var(--text);
    font-weight: 700;
    text-align: right;
  }
  /* Fixed columns rather than auto-placement: a portfolio too young for a
     rate or a one-year figure drops those cells, and the rest must not slide
     across into their tracks. */
  .holdings-table td[data-col="twr_annualized_pct"],
  .holdings-table td[data-col="twr_1y_pct"],
  .holdings-table td[data-col="unrealized_eur"] { grid-row: 2; font-size: 0.78rem; }
  .holdings-table td[data-col="twr_annualized_pct"] { grid-column: 1; }
  .holdings-table td[data-col="twr_1y_pct"] { grid-column: 2; }
  .holdings-table td[data-col="unrealized_eur"] { grid-column: 3; justify-self: end; }
  /* The header is hidden here, so each number says what it is. */
  .holdings-table td[data-col="twr_annualized_pct"]::before { content: "/yr "; }
  .holdings-table td[data-col="twr_1y_pct"]::before { content: "1Y "; }
  .holdings-table td[data-col="unrealized_eur"]::before { content: "P/L "; }
  .holdings-table td[data-col="twr_annualized_pct"]::before,
  .holdings-table td[data-col="twr_1y_pct"]::before,
  .holdings-table td[data-col="unrealized_eur"]::before { color: var(--text-muted); font-weight: 500; }
  /* Second-line space goes to the compounding rate, not the short term. The
     allocation is already the bar below the row, the unrealised percentage
     already its own euro amount, and the daily move is absent entirely
     whenever the latest two valuation dates do not both carry the position. */
  .holdings-table td[data-col="daily_gain_pct"],
  .holdings-table td[data-col="twr_ytd_pct"],
  .holdings-table td[data-col="unrealized_pct"],
  .holdings-table .allocation-value { display: none; }
  /* The allocation cell holds two things that belong in different places:
     the percentage, dropped above, and the bar as the rule between
     holdings. Dropping the cell's own box lets the grid place the bar, so
     the separator carries the allocation instead of being a plain
     hairline -- the same reading the bar gave on desktop. */
  .holdings-table td[data-col="pct_of_portfolio"] { display: contents; }
  .holdings-table .allocation-bar {
    display: block;
    grid-row: 3;
    grid-column: 1 / -1;
    align-self: center;
    width: 100%;
    height: 2px;
    margin: 8px 0 0;
    background: var(--line);
  }
  .holdings-table td.empty-cell { grid-column: 1 / -1; padding: 12px 0; }
}

/* ---------- alerts, badges, chips ---------- */

.alert {
  margin-bottom: 16px;
  padding: 12px 16px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
}
.alert.success { color: var(--green); background: rgb(var(--green-rgb) / .11); border-color: rgb(var(--green-rgb) / .36); }
.alert.warn { color: var(--amber); background: rgb(var(--amber-rgb) / .11); border-color: rgb(var(--amber-rgb) / .36); }
.alert.error { color: var(--red); background: rgb(var(--red-rgb) / .11); border-color: rgb(var(--red-rgb) / .36); }
.alert.info { color: var(--blue-bright); background: rgb(var(--blue-rgb) / .11); border-color: rgb(var(--blue-rgb) / .36); }

.badge { padding: 2px 8px; border-radius: var(--radius-pill); font-size: 0.8em; font-weight: 600; }
.badge.status-success { color: var(--green); background: rgb(var(--green-rgb) / .14); }
.badge.status-error { color: var(--red); background: rgb(var(--red-rgb) / .14); }
.badge.status-partial,
.badge.status-skipped { color: var(--amber); background: rgb(var(--amber-rgb) / .14); }

/* ---------- cards, charts, toggles ---------- */

.charts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: 18px;
  margin: 24px 0;
}
.chart-card {
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
}
.chart-title { margin-bottom: 8px; color: var(--text-muted); font-size: 0.85em; letter-spacing: 0.03em; text-transform: uppercase; }
/* A rolling estimate has to state its window, or it cannot be compared with
   itself over time. Not uppercased with the title: it is a value, not a label. */
.chart-title-note { margin-left: 6px; text-transform: none; letter-spacing: 0; opacity: 0.8; }
.chart-wrap { position: relative; width: 100%; height: 280px; }
.chart-wrap canvas,
.hero-chart-wrap canvas { position: absolute; top: 0; left: 0; width: 100% !important; height: 100% !important; }
.chart-wrap-large { height: 330px; }
.chart-hint { margin: -8px 0 16px; color: var(--text-muted); font-size: 0.8em; }
.chart-with-empty { position: relative; }
.chart-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-muted);
  text-align: center;
}
.chart-empty strong { color: var(--text-soft); font-size: 0.95rem; }
.chart-empty span { font-size: 0.82rem; }
.chart-empty .chart-empty-note { max-width: min(420px, 90%); font-size: 0.75rem; line-height: 1.45; opacity: 0.8; }
.chart-empty .chart-empty-note:empty { display: none; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.chart-key { display: flex; gap: 13px; color: var(--text-muted); font-size: var(--text-xs); }
.chart-key span::before { display: inline-block; width: 7px; height: 7px; margin-right: 5px; border-radius: 2px; content: ""; }
.chart-key .key-principal::before { background: var(--blue-deep); }
.chart-key .key-contrib::before { background: var(--blue); }
.chart-key .key-growth::before { background: var(--green); }
.chart-key .key-target::before { background: var(--amber); }
.coverage-progress {
  width: min(240px, 70%);
  height: 4px;
  overflow: hidden;
  background: var(--surface-soft);
  border-radius: var(--radius-pill);
}
.coverage-progress span { display: block; height: 100%; background: linear-gradient(90deg, var(--cyan-deep), var(--cyan)); border-radius: inherit; }

/* Every segmented toggle in the app — chart mode, correlation view,
   geography view, fund overlap — is this one control. IF.initToggleGroup
   keeps .active and aria-pressed in step. */
.segmented-control {
  display: inline-flex;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.segmented-control button {
  min-height: 32px;
  padding: 5px 12px;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  font-size: 0.78rem;
}
.segmented-control button:hover { color: var(--text); background: var(--surface-soft); }
.segmented-control button.active { color: var(--cyan); background: var(--accent-soft); }

.period-strip {
  display: grid;
  grid-auto-columns: minmax(0, 1fr);
  grid-auto-flow: column;
  gap: 5px;
  padding: 5px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.history-controls { margin-bottom: 10px; }
.period-strip .calendar-year-tile { display: flex; min-width: 0; flex-direction: column; gap: 2px; align-items: stretch; }
.period-strip .calendar-year-control {
  width: 100%;
  min-height: 32px;
  padding: 7px 30px 7px 10px;
  color: var(--text-muted);
  background-color: transparent;
  border-color: transparent;
  font-size: .72rem;
  font-weight: 650;
}
.period-strip .calendar-year-control:hover,
.period-strip .calendar-year-control:focus { color: var(--text); background-color: var(--surface-soft); border-color: var(--line-strong); }
.period-strip .calendar-year-tile strong { color: var(--text-soft); font-size: .75rem; font-variant-numeric: tabular-nums; text-align: center; }
.period-strip .calendar-year-tile strong.pos { color: var(--green); }
.period-strip .calendar-year-tile strong.neg { color: var(--red); }
.period-strip button {
  flex-direction: column;
  gap: 2px;
  min-height: 32px;
  padding: 7px;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  border-radius: 6px;
}
.period-strip button > span { color: var(--text-muted); font-size: var(--text-2xs); font-weight: 650; }
.period-strip button strong { color: var(--text-soft); font-size: 0.75rem; font-variant-numeric: tabular-nums; }
.period-strip button strong.pos { color: var(--green); }
.period-strip button strong.neg { color: var(--red); }
.period-strip button strong .pos { color: var(--green); }
.period-strip button strong .neg { color: var(--red); }
.period-strip button.active { background: var(--surface-soft); box-shadow: inset 0 0 0 1px var(--line-strong); }
.period-strip button.active span,
.period-strip button.active strong { color: var(--text); }
.period-strip button.active strong.pos { color: var(--green); }
.period-strip button.active strong.neg { color: var(--red); }

@media (max-width: 760px) {
  .chart-card { padding: 13px; }
  .chart-wrap { height: 240px; }
  .segmented-control { width: 100%; }
  .segmented-control button { flex: 1; }
}

@media (max-width: 640px) {
  .chart-wrap-large { height: 255px; }
  /* One row that scrolls, instead of equal columns that wrap. Eight-plus tiles
     cannot each take a fair share of a 390px screen without either squeezing
     to unreadable or wrapping to three rows -- and the rows eat the height the
     chart below needs. Sizing each tile to its own label costs nothing
     vertically and keeps the per-period return figures, which the alternatives
     lose. IF.initHistoryPeriodControl scrolls the active tile back into view. */
  .period-strip {
    /* minmax, not plain max-content: a short strip (Market comparison has five
       tiles) then spreads to fill the width instead of leaving dead space, while
       a long one still keeps each tile at its label width and scrolls. */
    grid-auto-columns: minmax(max-content, 1fr);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .period-strip::-webkit-scrollbar { display: none; }
  .period-strip > * { scroll-snap-align: center; }
  .period-strip button { padding: 7px 12px; }
  /* Say it is a slider. The tile at the edge is half-cut by the scroll box
     already, and these fades make that read as "more this way" rather than as
     a clipping bug. They live on the wrapper, not the strip: an overlay inside
     a scroll container scrolls away with the content, and masking the strip
     itself would fade its own border out at both ends. Inset by the border so
     it stays crisp, and painted only while there is a strip to fade. */
  .history-controls:has(.period-strip:not([hidden])) { position: relative; }
  .history-controls:has(.period-strip:not([hidden]))::before,
  .history-controls:has(.period-strip:not([hidden]))::after {
    content: "";
    position: absolute;
    top: 1px;
    bottom: 1px;
    width: 28px;
    pointer-events: none;
    border-radius: var(--radius-md);
  }
  .history-controls:has(.period-strip:not([hidden]))::before {
    left: 1px;
    background: linear-gradient(to right, var(--surface), transparent);
  }
  .history-controls:has(.period-strip:not([hidden]))::after {
    right: 1px;
    background: linear-gradient(to left, var(--surface), transparent);
  }
  /* The year tile holds a select, which does not size to content the way the
     buttons do; without this it collapses to its padding. */
  .period-strip .calendar-year-tile { min-width: 122px; }
}

@media (max-width: 480px) {
  .chart-wrap { height: 220px; }
}

/* ---------- page heroes ----------
   Every in-app page opens on the same frame: the raised gradient, one cyan
   glow from the top-left corner, the strong line and the large radius. A
   page's own hero class adds only its layout (grid, padding, margins). */
.hero {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(circle at 12% 6%, rgb(var(--cyan-rgb) / .1), transparent 45%),
    linear-gradient(145deg, var(--surface-raised), var(--surface));
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow);
}
@media (max-width: 640px) {
  .hero { border-radius: var(--radius-lg); }
}

/* ---------- panels ----------
   The page sections under a hero: one frame, one cyan top edge, one gap
   above. Only the Settings danger zone changes the edge, because there the
   colour means something. A page's own panel class adds only its content
   layout. */
.panel {
  margin-top: 22px;
  padding: 12px 20px 20px;
  background: linear-gradient(145deg, var(--surface), var(--surface-well));
  border: 1px solid var(--line);
  border-top: 3px solid var(--cyan);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.panel-danger { border-top-color: var(--red); }
@media (max-width: 640px) {
  .panel { padding: 12px 8px; }
}

/* ---------- Activity ---------- */

.activity-view-switcher { width: fit-content; max-width: 100%; margin: 12px 0 0; }
.activity-hero { margin: 0 0 16px; padding: 20px; }
.activity-hero-head { display: flex; align-items: end; justify-content: space-between; gap: 18px; }
.activity-hero-head .section-head { margin: 0; padding: 0; border: 0; }
.activity-hero-head h2 { font-size: 1.3rem; letter-spacing: -.025em; }
.activity-period-switcher { flex-wrap: wrap; justify-content: flex-end; }
.activity-period-switcher button { min-width: 44px; }
.activity-summary-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin-top: 18px; overflow: hidden; background: transparent; border: 1px solid var(--line); border-radius: var(--radius-md); }
.activity-summary-grid article { display: flex; min-width: 0; padding: 13px 14px; flex-direction: column; background: transparent; border: 0; border-radius: 0; }
.activity-summary-grid article:not(:first-child) { border-left: 1px solid var(--line); }
.activity-summary-grid span { color: var(--text-muted); font-size: var(--text-2xs); font-weight: 700; letter-spacing: .045em; text-transform: uppercase; }
.activity-summary-grid strong { margin-top: 8px; overflow: hidden; font-size: 1.12rem; font-variant-numeric: tabular-nums; letter-spacing: -.025em; text-overflow: ellipsis; white-space: nowrap; }
.activity-summary-grid small { margin-top: 4px; color: var(--text-muted); font-size: var(--text-2xs); }
.activity-view-switcher button { gap: 7px; }
.activity-view-switcher span {
  display: inline-grid;
  min-width: 22px;
  min-height: 20px;
  padding: 1px 6px;
  place-items: center;
  color: var(--text-muted);
  background: var(--surface-well);
  border-radius: var(--radius-pill);
  font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
}

.activity-panel .section-head { margin: 0 0 14px; }
.activity-panel .panel-table-wrap { margin: 0; }
.activity-panel .holdings-toolbar { position: relative; }

@media (max-width: 760px) {
  .activity-summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .activity-summary-grid article:nth-child(odd) { border-left: 0; }
  .activity-summary-grid article:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .activity-hero { padding: 15px; }
  .activity-hero-head { align-items: start; flex-direction: column; gap: 5px; }
  .activity-period-switcher { display: grid; width: 100%; grid-template-columns: repeat(3, 1fr); }
  .activity-view-switcher { display: grid; width: 100%; grid-template-columns: 1fr; }
  .activity-view-switcher button { justify-content: space-between; min-height: 42px; }

  .activity-panel .section-head { align-items: stretch; }
  .activity-panel .holdings-toolbar { width: 100%; }
  .activity-panel .holdings-toolbar button { flex: 1; }
  .activity-panel .data-table th,
  .activity-panel .data-table td { padding-right: 10px; padding-left: 10px; }
}

/* ---------- dashboard ---------- */

.dashboard-page-head { margin-bottom: 20px; }

/* The performance metrics form the Dashboard hero's footer: one full-width row
   of tiles in the Analysis hero's type, a label and a figure each, so the
   split between the two halves ends on the strip's top edge. Supporting
   figures open above the tile on hover or focus, inside the hero's clip. */
.hero-tiles { display: grid; grid-column: 1 / -1; grid-auto-columns: minmax(0, 1fr); grid-auto-flow: column; background: rgb(var(--well-rgb) / .26); border-top: 1px solid var(--line); }
.hero-tiles[hidden] { display: none; }
/* Full labels need about 230px a tile; a narrower row swaps in one word each
   rather than wrapping. Keyed to the row, not the viewport, so it holds in
   every hero layout. */
.hero-tiles { container-type: inline-size; }
.hero-tile .label-short { display: none; }
@container (max-width: 920px) {
  .hero-tile .label-long { display: none; }
  .hero-tile .label-short { display: inline; }
}
.hero-tile { position: relative; min-width: 0; padding: 16px 24px; cursor: default; outline: none; }
.hero-tile + .hero-tile { border-left: 1px solid var(--line); }
.hero-tile:hover,
.hero-tile:focus-within { background: rgb(var(--cyan-rgb) / .05); }
.hero-tile:focus-visible { box-shadow: inset 0 0 0 2px var(--cyan); }
.hero-tile > span { display: block; color: var(--text-muted); font-size: var(--text-2xs); font-weight: 700; letter-spacing: .045em; text-transform: uppercase; }
.hero-tile > strong { display: block; margin-top: 6px; overflow: hidden; color: var(--text); font-size: 1rem; font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
.hero-tile > strong.pos { color: var(--green); }
.hero-tile > strong.neg { color: var(--red); }
.hero-tile-detail { position: absolute; z-index: 4; bottom: calc(100% - 6px); left: 12px; display: grid; gap: 5px; min-width: 190px; max-width: calc(100vw - 48px); padding: 9px 11px; visibility: hidden; opacity: 0; color: var(--text); background: var(--surface-raised); border: 1px solid var(--line-strong); border-radius: var(--radius-sm); box-shadow: var(--shadow-pop); font-size: .7rem; transition: opacity .12s ease, visibility .12s; }
.hero-tile:last-child .hero-tile-detail { right: 12px; left: auto; }
.hero-tile:hover .hero-tile-detail,
.hero-tile:focus-within .hero-tile-detail { visibility: visible; opacity: 1; }
.hero-tile-detail > div { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.hero-tile-detail > div > span { color: var(--text-muted); }
.hero-tile-detail b { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.hero-tile-detail b.pos { color: var(--green); }
.hero-tile-detail b.neg { color: var(--red); }
.dashboard-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(350px, .9fr);
}
.dashboard-hero.single { grid-template-columns: 1fr; }
.hero-portfolio,
.hero-fire { position: relative; min-width: 0; min-height: 292px; padding: 24px; }
/* The chart is anchored to the panel's bottom edge, so whichever hero half is
   taller the plot still ends flush with the foot instead of leaving dead
   space on one side. */
.hero-portfolio { display: flex; flex-direction: column; overflow: hidden; }

.eyebrow { color: var(--text-muted); }
.hero-title-row { position: relative; z-index: 2; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.hero-title-row > span { color: var(--text-muted); font-size: var(--text-xs); }
.hero-value {
  position: relative;
  z-index: 2;
  margin-top: 9px;
  color: var(--text);
  font-size: clamp(2.25rem, 5vw, 3.25rem);
  font-variant-numeric: tabular-nums;
  font-weight: 760;
  letter-spacing: -0.045em;
  line-height: 1;
}
.hero-chart-caption { position: relative; z-index: 2; margin: 9px 0 6px; color: var(--text-muted); font-size: 0.7rem; }
/* The plot is out of flow and anchored to the panel's bottom edge so it can be
   most of the panel's height without making the panel taller: a compounding
   curve spends most of its width near the floor, so the text above sits over
   empty plot and the curve's late climb has somewhere to go. The height is set
   to land the newest point around three quarters up the panel -- Chart.js
   reserves a little padding above the top value, hence 79 rather than 75.
   It spans the panel edge to edge, ignoring the panel padding the text obeys,
   and sits 12px into the bottom padding: a value line is a shape, not a
   paragraph, and stopping it short of the card's sides only draws attention to
   the margin. */
.hero-chart-wrap { position: absolute; z-index: 1; right: 0; bottom: 12px; left: 0; height: 79%; }
.hero-fire { display: flex; flex-direction: column; background: rgb(var(--well-rgb) / .2); border-left: 1px solid var(--line); }
.fire-headline { color: var(--cyan); }
.fire-caption { position: relative; z-index: 1; margin-top: 9px; color: var(--text-muted); font-size: 0.8rem; }
.fire-caption b { font-weight: 700; }
.fire-caption .goal-ahead { color: var(--green-bright); }
.fire-caption .goal-behind { color: var(--red-bright); }

/* The strip takes the panel's slack, so both hero halves end on the same line:
   text at the top of each, one graphic at the foot. */
.fire-timeline { margin-top: auto; padding-top: 20px; padding-bottom: 18px; }

/* The date strip itself, drawn by IF.renderDateStrip and shared by the FIRE
   hero above and the contribution scenarios on the FIRE page: names above the
   track, dates below it, every label pinned under its own mark. Only the
   spacing around it belongs to the panel that hosts it. */
.fire-timeline-track { position: relative; height: 4px; background: var(--surface-soft); border-radius: var(--radius-pill); }
.fire-timeline-mark {
  position: absolute;
  top: 50%;
  width: 11px;
  height: 11px;
  margin: -5.5px 0 0 -5.5px;
  /* The ring is the panel's own ground: two projections a few months apart
     land within a couple of percent of each other on this scale, and without
     it the adjacent marks merge into one wider dot. */
  border: 2px solid var(--surface);
  border-radius: 50%;
  box-sizing: content-box;
}
/* One colour per named projection, wherever it is drawn. */
.mark-plan { z-index: 2; background: var(--cyan); }
.mark-recent { z-index: 1; background: var(--blue); }
/* Pink, not green: green and red mean ahead and behind everywhere else, and a
   series colour must not read as a verdict. */
.mark-historical { background: var(--pink); }
.mark-custom { background: var(--text-soft); }
.mark-goal { background: var(--amber); }
/* Labels are positioned under their marks rather than flowed in columns, so
   the rows they sit in need a height of their own. */
.fire-timeline-labels { position: relative; }
.fire-timeline-names { height: 15px; margin-bottom: 9px; }
.fire-timeline-dates { height: 21px; margin-top: 11px; }
.fire-timeline-label { position: absolute; top: 0; min-width: 0; white-space: nowrap; }
/* A recomputed scenario moves a mark a few months, not to a different subject:
   the dot and the label it carries slide to the new date together, so the eye
   keeps hold of which one moved. The class is added a frame after the node is
   created, so a mark drawn for the first time appears in place. */
.strip-moves { transition: left 260ms ease, transform 260ms ease, max-width 260ms ease; }
@media (prefers-reduced-motion: reduce) { .strip-moves { transition: none; } }
.fire-timeline-label span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fire-timeline-label strong { display: block; overflow: hidden; color: var(--text); font-size: 0.84rem; font-variant-numeric: tabular-nums; text-overflow: ellipsis; }
.strip-delta { display: block; overflow: hidden; margin-top: 2px; color: var(--text-soft); font-size: var(--text-xs); font-variant-numeric: tabular-nums; text-overflow: ellipsis; }
.strip-delta.pos { color: var(--green); }
.strip-delta.neg { color: var(--red); }
.label-plan span { color: var(--cyan); }
.label-recent span { color: var(--blue); }
.label-historical span { color: var(--pink); }
.label-custom span { color: var(--text-soft); }
.label-goal span { color: var(--amber); }

.pulse-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.pulse-card {
  position: relative;
  min-height: 98px;
  padding: 18px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.pulse-card::before {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 3px;
  opacity: 0.75;
  content: "";
}
.pulse-gain::before { background: var(--green); }
.pulse-neutral::before { background: var(--slate); }
.pulse-dividends::before { background: var(--amber); }
.pulse-label { color: var(--text-soft); font-size: 0.88rem; }
.pulse-value {
  margin-top: 8px;
  color: var(--text);
  font-size: clamp(1.4rem, 3vw, 1.8rem);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.1;
}
.pulse-sub { margin-top: 7px; color: var(--text-muted); font-size: 0.72rem; }
.pulse-sub .pos,
.pulse-sub .neg { margin-left: 3px; }
.dashboard-chart-card { background: transparent; border: 0; border-radius: 0; }
.performance-body { padding: 12px 0 0; }
.performance-body .chart-hint { margin: 4px 0 0; text-align: right; }
.period-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 12px 0; }
.period-summary > div { min-width: 0; padding: 12px 14px; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-md); }
.period-summary > .period-summary-return { background: rgb(var(--cyan-rgb) / .08); border-color: rgb(var(--cyan-rgb) / .3); box-shadow: inset 3px 0 0 var(--cyan); }
.period-summary > div > span { display: block; color: var(--text-muted); font-size: var(--text-xs); font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.period-summary strong { display: block; overflow: hidden; margin-top: 6px; color: var(--text); font-size: 1rem; font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
.period-summary strong.pos { color: var(--green); }
.period-summary strong.neg { color: var(--red); }

/* The dashboard's four figures are one equation -- opening plus money added
 * plus gain equals ending -- so they render as a single composition bar rather
 * than four tiles. The bar is scaled by static/dashboard.js: opening and the
 * positive deltas stack left to right, and anything negative (a withdrawal, a
 * losing period) is drawn in red at the right end, so the bar minus its red
 * tail is the ending value. */
.period-equation {
  position: relative;
  display: grid;
  grid-template-areas: "opening deltas ending" "bar bar bar";
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 16px;
  margin: 12px 0;
}
.period-equation-end { grid-area: opening; min-width: 0; }
.period-equation-end > span { display: block; }
.period-equation-end > strong { display: block; overflow: hidden; margin-top: 4px; color: var(--text); font-size: clamp(1.15rem, 3.2vw, 1.5rem); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; text-overflow: ellipsis; white-space: nowrap; }
.period-equation-end-final { grid-area: ending; text-align: right; }
.period-equation-bar { grid-area: bar; display: flex; overflow: hidden; height: 10px; margin: 10px 0 0; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-pill); }
.period-equation-bar > span { width: 0; transition: width .18s ease; }
.period-equation-bar > span:hover { filter: brightness(1.18); }
.period-equation-tooltip { position: absolute; z-index: 3; padding: 5px 8px; color: var(--text); background: var(--surface-raised); border: 1px solid var(--line-strong); border-radius: var(--radius-sm); box-shadow: var(--shadow-pop); font-size: .7rem; font-variant-numeric: tabular-nums; pointer-events: none; transform: translate(-50%, -100%); white-space: nowrap; }
.period-equation-bar > span + span { box-shadow: inset 1px 0 0 var(--canvas); }
.period-equation-bar > [data-segment="opening"] { background: var(--slate); }
.period-equation-bar > [data-segment="added"] { background: var(--blue); }
.period-equation-bar > [data-segment="gain"] { background: var(--green); }
.period-equation-bar > [data-segment="withdrawn"] { background: var(--red); }
.period-equation-bar > [data-segment="loss"] { background: var(--red); }
/* Between the two ends, where the equation reads left to right: opening, what
 * was added, what it earned, ending. These are attribution, not controls, so
 * they stay flat inside the equation rather than becoming two more cards. */
.period-equation-keys { grid-area: deltas; display: flex; flex-wrap: wrap; justify-content: center; gap: 22px; }
.period-equation-key { display: flex; flex: 0 1 auto; align-items: baseline; justify-content: space-between; gap: 9px; min-width: 0; }
.period-equation-key + .period-equation-key { padding-left: 22px; border-left: 1px solid var(--line); }
/* The amount keeps its intrinsic width and the label gives way, so a narrow
 * chip loses a word of label rather than a digit of the figure. */
.period-equation-key > span { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.period-equation-key > strong { flex: 0 0 auto; color: var(--text); font-size: 0.95rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.period-equation-key.key-money > strong { color: var(--blue-bright); }
.period-equation-key.key-gain > strong { color: var(--green); }

@media (max-width: 640px) {
  .period-equation {
    grid-template-areas: "opening ending" "bar bar" "deltas deltas";
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  .period-equation-end > span { font-size: var(--text-2xs); }
  .period-equation-bar { height: 10px; margin-bottom: 9px; }
  /* Both chips still fit on one line at this width, which is what the one-word
   * labels buy: two rows of figures rather than four. */
  .period-equation-key { flex: 1 1 130px; }
  .period-equation-key + .period-equation-key { padding-left: 12px; }
  .period-equation-key > span { font-size: var(--text-2xs); }
  .period-equation-key > strong { font-size: 0.88rem; }
}

@media (max-width: 760px) {
  .dashboard-hero { grid-template-columns: minmax(0, 1fr) minmax(310px, .9fr); }
  .chart-key { display: none; }
}

@media (max-width: 640px) {
  .dashboard-hero { grid-template-columns: 1fr; }
  .hero-portfolio { min-height: 235px; padding: 20px 17px; }
  .hero-value { font-size: clamp(2rem, 10vw, 2.65rem); }
  .hero-chart-wrap { right: 0; bottom: 8px; left: 0; height: 72%; }
  /* Stacked, the panel is only as tall as it needs to be: side by side the
     minimum keeps the two halves level, but in one column that slack has
     nothing to line up with and opens a hole above the strip. */
  .hero-fire { min-height: 0; padding: 20px 17px; border-top: 1px solid var(--line); border-left: 0; }
  /* Still one row: labels may wrap, and popovers from the right half open
     leftwards so the hero's clip does not cut them. */
  .hero-tile { padding: 12px 10px; }
  .hero-tile:first-child { padding-left: 17px; }
  .hero-tile > strong { font-size: .9rem; }
  .hero-tile:nth-child(n + 3 of :not([hidden])) .hero-tile-detail { right: 8px; left: auto; }
  /* The strip is the last thing on the panel here and the panel's own padding
     is the space under it -- the desktop inset would read as a gap. */
  .fire-timeline { padding-top: 15px; padding-bottom: 0; }
  .fire-timeline-label span { font-size: .55rem; letter-spacing: .03em; }

  .pulse-card { min-height: 108px; padding: 14px 12px; }
  .pulse-label { font-size: 0.76rem; }
  .pulse-value { font-size: 1.28rem; }
  .pulse-sub { font-size: var(--text-2xs); }
  .performance-body { padding: 10px 8px 5px; }
  .performance-body .chart-hint { display: none; }
  .period-summary { grid-template-columns: 1fr; gap: 7px; }
  .period-summary > div { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 10px 12px; }
  .period-summary strong { margin-top: 0; }
}

@media (max-width: 380px) {
  .pulse-value { font-size: 1.12rem; }
}

/* ---------- FIRE page ---------- */

.fire-hero-layout { display: grid; grid-template-columns: minmax(300px, .78fr) minmax(0, 1.45fr); }
.fire-progress-card,
.fire-chart-card { min-width: 0; padding: 24px; }

.fire-hero-head { margin: 0 0 18px; padding: 0; border: 0; }
.fire-progress-value { display: block; margin-top: 8px; color: var(--text); font-size: clamp(2.5rem, 5vw, 3.5rem); font-variant-numeric: tabular-nums; letter-spacing: -0.045em; line-height: 1; }
.fire-progress-track { height: 9px; margin-top: 15px; overflow: hidden; background: var(--surface-soft); border-radius: var(--radius-pill); }
.fire-progress-track span { display: block; width: 0; height: 100%; background: linear-gradient(90deg, var(--cyan-deep), var(--green)); border-radius: inherit; transition: width 450ms ease; }
.fire-progress-money { display: flex; flex-wrap: wrap; align-items: baseline; gap: 5px; margin: 9px 0 0; }
.fire-progress-money > strong { color: var(--text); font-size: 1rem; font-variant-numeric: tabular-nums; }
.fire-progress-money span { color: var(--text-muted); font-size: 0.72rem; }
.fire-progress-money b { color: var(--text-soft); font-weight: 650; }
/* The framed 2×2 fact grid shared by the FIRE and Analysis heroes. */
.hero-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); overflow: hidden; background: rgb(var(--well-rgb) / .42); border: 1px solid var(--line); border-radius: var(--radius-md); }
.hero-facts > div { min-width: 0; padding: 12px; }
.hero-facts > div:nth-child(even) { border-left: 1px solid var(--line); }
.hero-facts > div:nth-child(n + 3) { border-top: 1px solid var(--line); }
.hero-facts span { display: block; color: var(--text-muted); font-size: var(--text-2xs); font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.hero-facts strong { display: block; overflow: hidden; margin-top: 6px; color: var(--text); font-size: 1rem; font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
.hero-facts strong.pos { color: var(--green); }
.hero-facts strong.neg { color: var(--red); }
.hero-facts small { display: block; margin-top: 4px; color: var(--text-muted); font-size: var(--text-2xs); line-height: 1.35; }
.fire-progress-card .hero-facts { margin-top: 18px; }
.fire-chart-card { display: flex; flex-direction: column; background: rgb(var(--well-rgb) / .2); border-left: 1px solid var(--line); }
.fire-chart-card .chart-key { justify-content: flex-start; flex-wrap: wrap; gap: 8px 13px; margin-bottom: 4px; }
.fire-chart-wrap { position: relative; min-height: 340px; flex: 1; }
.fire-chart-wrap canvas { position: absolute; top: 0; left: 0; width: 100% !important; height: 100% !important; }
/* The panel's one control, in the panel's head: the rows below are a table to
   be read, and a form inside the last of them made that row twice as tall as
   the rest and read as a property of the scenario rather than as the thing that
   produces it. One line, labels beside their fields. */
.contribution-scenario-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.contribution-scenario-form label { display: flex; align-items: center; gap: 7px; color: var(--text-muted); font-size: 0.72rem; white-space: nowrap; }
.contribution-scenario-form input { width: 96px; min-height: 34px; padding-top: 5px; padding-bottom: 5px; font-variant-numeric: tabular-nums; }
.contribution-scenario-status { color: var(--text-muted); font-size: 0.72rem; }
.scenario-readiness { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.scenario-readiness span { padding: 6px 9px; color: var(--text-muted); background: var(--surface-soft); border-radius: var(--radius-pill); font-size: var(--text-xs); }
/* One strip carries every scenario's date, in the dashboard hero's shape:
   names, marks, dates. The rows below it are then free to be what assumptions
   each scenario makes, rather than four separate answers to "when". */
.scenario-strip { margin: 3px 0 13px; padding: 0 14px; }
/* Two lines here: the variance under each date is a line the hero has not got. */
.scenario-strip .fire-timeline-dates { height: 40px; }
.scenario-timeline { display: grid; gap: 10px; }
/* The rows are a table: four numbers in the same order in every one, so the
   names of the columns are said once at the top rather than under each value
   four times over. On a phone the rows stack into one column and the header has
   nothing to head, so it goes and the per-value labels come back. */
.scenario-columns,
.scenario-row {
  display: grid;
  grid-template-columns: minmax(140px, .8fr) minmax(0, 3fr);
  align-items: center;
  gap: 6px 18px;
  padding: 12px 14px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
/* The row's cells are rewritten wholesale on every render, so they live in
   their own container — `display: contents` keeps them in the row's grid, and
   keeps the Custom row's form out of the way of that innerHTML. */
.scenario-row-body { display: contents; }
.scenario-row-label { min-width: 0; }
.scenario-row-label small { display: block; margin-top: 3px; color: var(--text-muted); font-size: var(--text-2xs); font-weight: 400; letter-spacing: 0; line-height: 1.35; text-transform: none; }
/* The same colour the scenario wears on the strip, so a row and its mark are
   matched by sight rather than by reading both names. */
.scenario-row-dot { display: inline-block; width: 7px; height: 7px; margin-right: 7px; vertical-align: middle; border-radius: 50%; }
.scenario-row-empty { margin: 0; color: var(--text-muted); font-size: 0.82rem; }
/* The four numbers that define a scenario: they are what one row has that
   another has not, so they read at the weight of data, under a header that
   names them once. */
.scenario-row-facts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px 18px; }
.scenario-row-facts > div { min-width: 0; }
.scenario-row-facts strong { display: block; color: var(--text); font-size: 0.92rem; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.scenario-row-facts span { display: block; min-width: 0; }
.scenario-columns { padding-top: 0; padding-bottom: 0; background: none; border: 0; }
.scenario-row-facts > div > span { display: none; }
.contribution-empty { padding: 22px; text-align: center; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-md); }
.contribution-empty > strong { display: block; margin-top: 8px; color: var(--text); font-size: 1.25rem; }
.contribution-empty p { max-width: 620px; margin: 7px auto 0; color: var(--text-muted); font-size: 0.76rem; line-height: 1.5; }
/* The panel with no targets set yet: one quiet line centred in the space the
   account list would fill, with no bottom margin since it is the last thing
   in the panel. */
.contribution-empty-line { margin-bottom: 0; text-align: center; }
/* Block, so the hit target is the whole row rather than the glyphs. */
.contribution-empty-line a { display: block; padding: 6px 0; }
.contribution-summary-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 14px; }
.contribution-summary-grid article { min-width: 0; padding: 15px; background: transparent; border: 0; border-radius: 0; }
.contribution-summary-grid span { display: block; color: var(--text-muted); font-size: 0.7rem; font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.contribution-summary-grid strong {
  display: block;
  overflow: hidden;
  margin-top: 8px;
  color: var(--text);
  font-size: 1.2rem;
  font-variant-numeric: tabular-nums;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.contribution-summary-grid small { display: block; margin-top: 5px; color: var(--text-muted); font-size: var(--text-xs); }
/* Single column: the wide viewports hold one twelve-month table, and the narrow
   ones that get two six-month halves are exactly the ones with no room to sit
   them side by side (see the heatmapSplit query in fire.js). */
.contribution-heatmap-grid { display: grid; grid-template-columns: 1fr; gap: 18px; }
/* Tighter than a general .corr-matrix cell so a full year of columns clears the
   content box with room to spare instead of scrolling at desktop widths. */
.contribution-heatmap th,
.contribution-heatmap td { padding: 8px 7px; }
/* The month still running: a real share of plan, but of an unfinished month,
   so it is outlined rather than shaded like a settled result. */
.contribution-cell-partial { box-shadow: inset 0 0 0 1px var(--line); color: var(--text-muted); }
.heatmap-half-label { margin: 0 0 6px; }
.fire-tax-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fire-tax-summary article { min-width: 0; padding: 16px; background: transparent; border: 0; border-radius: 0; }
.fire-tax-summary span { display: block; color: var(--text-muted); font-size: 0.7rem; font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.fire-tax-summary strong { display: block; overflow: hidden; margin-top: 8px; color: var(--text); font-size: 1.25rem; font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
.fire-tax-summary small { display: block; margin-top: 5px; color: var(--text-muted); font-size: var(--text-xs); }
.fire-tax-summary,
.contribution-summary-grid,
.overlap-summary { gap: 0; overflow: hidden; background: transparent; border: 1px solid var(--line); border-radius: var(--radius-md); }
.fire-tax-summary > article:not(:first-child),
.contribution-summary-grid > article:not(:first-child),
.overlap-summary > article:not(:first-child) { border-left: 1px solid var(--line); }
.fire-tax-qualified { margin: 12px 0 0; color: var(--text-muted); font-size: 0.72rem; line-height: 1.45; }
.fire-tax-details { margin-top: 12px; background: var(--surface-well); box-shadow: none; }
.fire-tax-details .table-scroll { margin: 0; }
.fire-tax-details .data-table { margin: 0; border: 0; }

@media (max-width: 980px) {
  .fire-hero-layout { grid-template-columns: 1fr; }
  .fire-chart-card { border-top: 1px solid var(--line); border-left: 0; }
  .fire-chart-wrap { height: 300px; min-height: 0; flex: 0 0 300px; }
}

@media (max-width: 640px) {

  .fire-progress-card,
  .fire-chart-card { padding: 14px; }
  .fire-chart-wrap { height: 250px; flex-basis: 250px; }
  /* The head stacks, and so does the form under it: two number fields and a
     button side by side on a phone leave the fields too narrow to read what
     was typed into them. */
  .fire-scenarios-panel .section-head { display: block; }
  .contribution-scenario-form { margin-top: 12px; }
  .contribution-scenario-form label { flex: 1 1 100%; justify-content: space-between; }
  .contribution-scenario-form input { width: 62%; min-width: 0; }
  /* No room for a shared axis: the rows keep the dates and deltas, and the
     tracks (and their tick row) drop out rather than squeeze to nothing. */
  /* Four columns of names and dates do not survive a phone; the strip's
     comparison does, stacked over the rows it labels. */
  .scenario-strip { padding: 0; }
  /* The strip is a third of its desktop width here and carries the same five
     labels, so they are set down a step to go with their shortened text. */
  .scenario-strip .fire-timeline-label strong { font-size: 0.72rem; }
  .scenario-strip .strip-delta { font-size: 0.6rem; }
  /* Shorter text on both label rows, so the room kept for them comes down with
     it: the strip sits closer to the form above and the rows below. */
  .scenario-strip .fire-timeline-names { height: 12px; margin-bottom: 7px; }
  .scenario-strip .fire-timeline-dates { height: 30px; margin-top: 8px; }
  .scenario-columns { display: none; }
  .scenario-row { grid-template-columns: minmax(0, 1fr); }
  .scenario-row-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .scenario-row-facts > div > span { display: block; margin-top: 2px; }
  /* The scenario's note sits beside its name rather than under it: on one line
     the row is a line shorter, and four of them fit a phone screen. Its width
     is the facts grid's second column, so the note starts on the same edge as
     the numbers under it rather than floating loose against the right. */
  .scenario-row-label { display: flex; align-items: baseline; gap: 10px; }
  .scenario-row-label small {
    display: inline;
    flex: 0 0 calc(50% - 9px);
    margin-top: 0;
    margin-left: auto;
  }
  .contribution-summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .contribution-summary-grid > article:nth-child(odd) { border-left: 0; }
  .contribution-summary-grid > article:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .contribution-heatmap-grid { gap: 16px; }
  /* Base target and tax buffer stay side by side; only the tax-adjusted
     target — the number the projection uses — takes the full row. */
  .fire-tax-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fire-tax-summary .fire-tax-net { grid-column: 1 / -1; border-top: 1px solid var(--line); border-left: 0; }
  .fire-tax-summary strong { font-size: 1.05rem; }
}

@media (max-width: 380px) {
  .hero-facts { grid-template-columns: 1fr; }
  .hero-facts > div:nth-child(even) { border-left: 0; }
  .hero-facts > div + div { border-top: 1px solid var(--line); }
  .contribution-summary-grid { grid-template-columns: 1fr; }
  .contribution-summary-grid > article:not(:first-child) { border-top: 1px solid var(--line); border-left: 0; }
}

/* ---------- Analysis ---------- */

.analysis-hero-body { display: grid; grid-template-columns: minmax(270px, .72fr) minmax(0, 1.55fr); min-height: 330px; }
.analysis-hero-answer { display: flex; min-width: 0; padding: 24px; flex-direction: column; }
.analysis-hero-head { margin: 0; padding: 0; border: 0; }
.analysis-hero-relative { margin-top: 22px; color: var(--text); font-size: clamp(3rem, 6vw, 4.5rem); font-variant-numeric: tabular-nums; font-weight: 760; letter-spacing: -.06em; line-height: .95; }
.analysis-hero-relative.pos { color: var(--green-bright); }
.analysis-hero-relative.neg { color: var(--red-bright); }
.analysis-hero-answer .hero-facts { margin-top: auto; }
.analysis-hero-chart { position: relative; min-width: 0; padding: 20px 22px 12px; background: rgb(var(--well-rgb) / .2); border-left: 1px solid var(--line); }
.analysis-hero-chart .performance-chart-wrap { height: 275px; }
.analysis-hero-periods { padding: 0 20px 18px; border-top: 1px solid var(--line); }
.analysis-hero-periods .period-strip { margin-top: 14px; margin-bottom: 0; }
.analysis-metric-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.analysis-number-card,
.analysis-visual-card {
  min-width: 0;
  padding: 16px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.analysis-number-card { display: flex; flex-direction: column; justify-content: center; }
.analysis-number-strip {
  display: grid;
  grid-column: 1 / -1;
  gap: 0;
  overflow: hidden;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.analysis-number-strip-two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.analysis-number-strip-four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.analysis-number-strip .analysis-number-card,
.analysis-number-strip .correlation-pair-card {
  min-height: 102px;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.analysis-number-strip > :not(:first-child) { border-left: 1px solid var(--line); }
.analysis-number-card > span,
.analysis-visual-card h3 { color: var(--text-muted); font-size: 0.74rem; font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.analysis-number-card > strong {
  margin: 8px 0 4px;
  color: var(--text);
  font-size: clamp(1.55rem, 3vw, 2rem);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  letter-spacing: -0.025em;
}
.analysis-number-card > strong.stat-value-compact { overflow: hidden; font-size: 1.35rem; text-overflow: ellipsis; white-space: nowrap; }
.analysis-number-card small,
.comparison-row small { color: var(--text-muted); font-size: 0.7rem; }
.analysis-card-wide { grid-column: span 2; }
.analysis-card-full { grid-column: 1 / -1; }
/* Desktop allocation & concentration: the four tiles fill the top row and the
   composition and target-drift charts share the row beneath it, side by side.
   The tiles are not contiguous in source (composition sits between them), so
   placement is explicit here and only at desktop widths -- phone stacking above
   is untouched. */
@media (min-width: 641px) {
  .analysis-allocation .analysis-visual-card { grid-row: 2; grid-column: span 2; }
  .analysis-market .analysis-number-strip { grid-column: span 2; }
}
.analysis-visual-card h3 { margin: 0 0 14px; }
.comparison-row {
  display: grid;
  grid-template-columns: 76px minmax(80px, 1fr) 58px 70px;
  align-items: center;
  gap: 9px;
  margin-top: 10px;
  color: var(--text-soft);
  font-size: 0.75rem;
}
.comparison-row strong { color: var(--text); font-variant-numeric: tabular-nums; text-align: right; }
.reference-track {
  position: relative;
  height: 8px;
  overflow: hidden;
  background: var(--surface-soft);
  border-radius: var(--radius-pill);
}
.reference-track > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--cyan-deep), var(--cyan));
  border-radius: inherit;
  transition: width 300ms ease;
}
.reference-track > b { position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; background: rgb(255 255 255 / .75); }
/* As tall as a plain card title: the figure beside it brings no line spacing
   of its own. The chart keeps 10px above its top label, so 4px here makes the
   title's usual 14px to the plot. */
.drawdown-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; margin-bottom: 4px; }
.analysis-visual-card .drawdown-card-head h3 { margin: 0; }
.drawdown-summary { display: flex; gap: 24px; }
.drawdown-summary > div { display: grid; grid-template-columns: auto auto; align-items: baseline; gap: 4px 8px; }
.drawdown-summary strong { color: var(--text); font-size: 1.05rem; font-variant-numeric: tabular-nums; line-height: 1; }
.drawdown-summary small { grid-column: 1 / -1; color: var(--text-muted); font-size: 0.7rem; text-align: right; }
.drawdown-chart-wrap { position: relative; width: 100%; height: 220px; }
.drawdown-chart-wrap canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
/* The largest gap sits on the title's line, and wraps under it only when the
   line is too narrow. 4px, as over the drawdown chart: the chart keeps 10px
   above its plot. */
.allocation-drift-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: 16px; margin-bottom: 4px; }
.analysis-visual-card .allocation-drift-head h3 { margin: 0; }
.allocation-drift-head small { color: var(--text-muted); font-size: 0.7rem; }
.analysis-chart-context { display: block; margin: 10px 0 0; color: var(--text-muted); font-size: 0.7rem; }
.allocation-drift-chart-wrap { position: relative; width: 100%; min-height: 180px; }
.allocation-drift-chart-wrap canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
.analysis-chart-pagination { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.analysis-chart-pagination .analysis-chart-context { margin: 0; }
.analysis-chart-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.performance-chart-wrap { position: relative; width: 100%; height: 260px; }
.performance-chart-wrap canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
.risk-return-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
/* The caption wraps under the heading only when the line is too narrow. */
.risk-return-title { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: 16px; margin-bottom: 4px; }
.analysis-visual-card .risk-return-title h3 { margin: 0; }
.risk-return-title small { color: var(--text-muted); font-size: 0.7rem; }
.risk-return-chart-wrap { position: relative; width: 100%; height: 220px; }
.risk-return-chart-wrap canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
/* Two columns: the doughnut spans both rows, the legend and the three
   non-bucket facts stack in the second. The facts belong with the legend, so
   their rule keeps to the legend's width rather than cutting the whole card. */
.composition-layout {
  display: grid;
  grid-template-areas: "chart legend" "chart facts";
  grid-template-columns: minmax(130px, 1fr) minmax(120px, auto);
  grid-template-rows: auto auto;
  align-items: center;
  gap: 16px;
  min-height: 170px;
}
/* Stretch, not a fixed height: the doughnut spans both rows, so it should use
   whatever height the legend and facts beside it come to. */
.composition-chart-wrap { position: relative; grid-area: chart; align-self: stretch; width: 100%; min-height: 150px; }
.composition-chart-wrap canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
.composition-legend { display: grid; grid-area: legend; align-self: end; align-content: center; gap: 7px; }
.composition-legend > div { display: grid; grid-template-columns: 9px minmax(0, 1fr) auto; align-items: center; gap: 7px; color: var(--text-soft); font-size: 0.72rem; }
.composition-legend i { width: 8px; height: 8px; border-radius: 2px; }
.composition-legend span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composition-legend strong { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }
.composition-facts { display: grid; grid-area: facts; align-self: start; gap: 7px; margin-top: -8px; padding-top: 8px; border-top: 1px solid var(--line); }
/* Indented by a swatch plus its gap, so the labels line up with the legend's. */
.composition-facts > div { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 7px; padding-left: 16px; color: var(--text-muted); font-size: 0.7rem; }
.composition-facts strong { color: var(--text); font-variant-numeric: tabular-nums; }
.analysis-disclosure { margin-top: 18px; overflow: hidden; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow); }
.analysis-disclosure > summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 16px; color: var(--text-soft); cursor: pointer; list-style: none; }
.analysis-disclosure > summary::-webkit-details-marker { display: none; }
.analysis-disclosure > summary::after { color: var(--cyan); font-size: 1.25rem; line-height: 1; content: "+"; }
.analysis-disclosure[open] > summary { border-bottom: 1px solid var(--line); }
.analysis-disclosure[open] > summary::after { content: "−"; }
.analysis-disclosure > summary span { display: flex; flex-direction: column; gap: 3px; }
.analysis-disclosure > summary strong { color: var(--text); font-size: 0.84rem; }
.analysis-disclosure > summary small { color: var(--text-muted); font-size: 0.72rem; }
.allocation-details { margin-top: 12px; background: var(--surface-well); box-shadow: none; }
.allocation-details .table-scroll { margin: 0; }
.allocation-details .data-table { margin: 0; border: 0; }
.advanced-analytics { margin-top: 22px; border-top: 3px solid var(--slate); }
.advanced-analytics > summary strong { letter-spacing: 0.035em; text-transform: uppercase; }
.risk-charts { margin: 0; padding: 16px; }
.correlation-pair-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 16px; }
.correlation-pair-card { display: flex; min-width: 0; padding: 14px 16px; flex-direction: column; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-md); }
.correlation-pair-card span { color: var(--text-muted); font-size: 0.7rem; font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.correlation-pair-card strong { margin: 7px 0 3px; overflow: hidden; color: var(--text); font-size: 1.05rem; text-overflow: ellipsis; white-space: nowrap; }
.correlation-pair-card small { color: var(--text-muted); font-size: 0.7rem; }
.correlation-scale { display: grid; grid-template-columns: auto minmax(20px, 1fr) auto minmax(20px, 1fr) auto; align-items: center; gap: 7px; margin: 0 2px 10px; color: var(--text-muted); font-size: var(--text-xs); }
.correlation-scale i { height: 6px; background: linear-gradient(90deg, rgb(var(--red-rgb) / .38), var(--surface-soft)); }
.correlation-scale i:last-of-type { background: linear-gradient(90deg, var(--surface-soft), rgb(var(--cyan-rgb) / .38)); }
.correlation-table-wrap { margin: 0; border: 1px solid var(--line); border-radius: var(--radius-md); }
.correlation-table-wrap .data-table { margin: 0; border: 0; }
.corr-cell-blank { background: var(--surface-well); }

@media (max-width: 760px) {
  .analysis-hero-body { grid-template-columns: 1fr; }
  .analysis-hero-chart { border-top: 1px solid var(--line); border-left: 0; }
  .analysis-diversification .analysis-section-head { align-items: stretch; }
}

@media (max-width: 640px) {

  .analysis-hero-answer { padding: 19px; }
  .analysis-hero-relative { margin-top: 18px; margin-bottom: 26px; font-size: clamp(2.8rem, 17vw, 4rem); }
  .analysis-hero-chart { padding: 15px 10px 8px; }
  .analysis-hero-chart .performance-chart-wrap { height: 230px; }
  .analysis-hero-periods { padding: 0 12px 14px; }

  /* The number cards stay paired at phone width — they are short enough to sit
     two-up, and stacking them pushed the charts off the screen. The wide and
     full cards take the whole row instead of half of it. */
  .analysis-metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .analysis-number-strip-four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .analysis-number-strip-four > :nth-child(odd) { border-left: 0; }
  .analysis-number-strip-four > :nth-child(n + 3) { border-top: 1px solid var(--line); }
  .analysis-card-wide,
  .analysis-card-full { grid-column: 1 / -1; }
  .analysis-number-card { padding: 13px; }
  .analysis-number-card > strong { font-size: clamp(1.25rem, 6vw, 1.55rem); }
  .analysis-number-card > strong.stat-value-compact { font-size: 1.05rem; }
  .comparison-row { grid-template-columns: 70px minmax(60px, 1fr) 52px; }
  .comparison-row small { grid-column: 2 / -1; }
  /* Market capture: the observation count wraps onto a line of its own here,
     doubling each row's height for a detail the percentage already implies. */
  .analysis-market .comparison-row small { display: none; }
  .drawdown-chart-wrap { height: 180px; }
  .analysis-chart-pagination { align-items: stretch; flex-direction: column; }
  .analysis-chart-actions { width: 100%; margin-left: 0; flex-direction: column; }
  .analysis-chart-actions button { width: 100%; justify-content: center; }
  .performance-chart-wrap { height: 210px; }
  .risk-return-head { display: block; }
  .risk-return-chart-wrap { height: 190px; }
  .composition-layout { grid-template-areas: "chart" "legend" "facts"; grid-template-columns: 1fr; grid-template-rows: auto auto auto; }
  /* Stacked, the chart no longer shares height with anything -- pin it back. */
  .composition-chart-wrap { height: 150px; }
  /* Stacked under the doughnut, a single column of entries is a tall thin
     ribbon in the middle of a wide card. Two entries per row halves the height
     and uses the width the chart above already claims. */
  .composition-legend { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 16px; }
  .composition-facts { grid-template-columns: repeat(3, 1fr); margin-top: 3px; }
  .composition-facts > div { display: block; padding-left: 0; text-align: center; }
  .composition-facts strong { display: block; margin-top: 3px; }
  .correlation-pair-card { padding: 13px; }
  .correlation-pair-card strong { font-size: 0.92rem; }
}

/* ---------- Look-through ---------- */

.exposure-card > strong { font-size: 1.05rem; }
.lookthrough-charts { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.lookthrough-chart-card { min-width: 0; padding: 16px; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-md); }
.lookthrough-geography-card { background: linear-gradient(155deg, rgb(var(--cyan-rgb) / .055), var(--surface-well) 48%); }
.lookthrough-sectors-card { background: linear-gradient(155deg, rgb(var(--green-rgb) / .06), var(--surface-well) 48%); }
.lookthrough-chart-card > .chart-title { display: flex; min-height: 40px; align-items: center; }
.lookthrough-chart-card > .chart-title > span:first-child { display: flex; min-height: 38px; align-items: center; }
.lookthrough-charts .chart-box { position: relative; height: 310px; }
.lookthrough-charts .chart-box canvas { position: absolute; top: 0; left: 0; width: 100% !important; height: 100% !important; }
/* Wraps so the phone's full-width toggle drops under its label, not off screen. */
.lookthrough-chart-title { flex-wrap: wrap; justify-content: space-between; gap: 10px; }
.lookthrough-chart-title .segmented-control button { font-size: 0.72rem; }
.holdings-controls { display: flex; flex-wrap: wrap; align-items: end; justify-content: flex-end; gap: 10px; }
/* The filter gives up width first, so adding the fund picker beside it can't
   push the row onto a second line and leave the heading floating beside it. */
.holdings-controls .holdings-filter { flex: 1 1 150px; min-width: 120px; }
.holdings-context { margin: 10px 0 0; color: var(--text-muted); font-size: 0.78rem; }
.panel-table-wrap { margin-top: 10px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.panel-table-wrap .data-table { margin: 0; border: 0; }
.lookthrough-holdings .panel-table-wrap { overflow: visible; border: 0; border-radius: 0; }
.lookthrough-holdings-table { background: transparent; box-shadow: none; }
@media (min-width: 761px) {
  .lookthrough-holdings-table,
  .lookthrough-holdings-table tbody { display: block; width: 100%; }
  .lookthrough-holdings-table thead { display: none; }
  .lookthrough-holdings-table tbody tr {
    display: grid;
    grid-template-columns: 26px minmax(220px, 1fr) minmax(80px, 100px) minmax(82px, 105px) minmax(90px, 120px) minmax(140px, 190px);
    gap: 5px 14px;
    align-items: baseline;
    padding: 14px 4px 11px;
    border-bottom: 1px solid var(--line);
  }
  .lookthrough-holdings-table tbody tr:hover { background: rgb(var(--blue-rgb) / .025); }
  .lookthrough-holdings-table th,
  .lookthrough-holdings-table td { padding: 0; border: 0; }
  .lookthrough-holdings-table [data-col="rank"] { grid-column: 1; grid-row: 1; color: var(--text-faint); font-size: var(--text-xs); }
  .lookthrough-holdings-table [data-col="holding"] { grid-column: 2; grid-row: 1; min-width: 0; color: var(--text); background: transparent; font-size: .88rem; }
  .lookthrough-holdings-table [data-col="portfolio_pct"] { grid-column: 3; grid-row: 1; text-align: right; }
  .lookthrough-holdings-table [data-col="value_eur"] { grid-column: 4; grid-row: 1; text-align: right; }
  .lookthrough-holdings-table [data-col="country"] { grid-column: 5; grid-row: 1; text-align: right; }
  .lookthrough-holdings-table [data-col="sector"] { grid-column: 6; grid-row: 1; overflow: hidden; text-align: right; text-overflow: ellipsis; white-space: nowrap; }
  .lookthrough-holdings-table [data-col="fund_weight_pct"]::before { margin-right: 4px; color: var(--text-muted); font-size: var(--text-2xs); }
  .lookthrough-exposure-value,
  .lookthrough-holdings-table [data-col="value_eur"] { color: var(--text); font-size: .84rem; font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
  .lookthrough-holdings-table [data-col="funds"] { grid-column: 2 / -1; grid-row: 2; overflow: hidden; text-align: left; white-space: nowrap; }
  .lookthrough-fund-chip { display: inline-flex; align-items: center; gap: 5px; margin-right: 4px; padding: 3px 7px; color: var(--text-muted); background: var(--surface-soft); border: 1px solid var(--line); border-radius: 999px; font-size: var(--text-2xs); text-decoration: none; transition: border-color .15s ease, background .15s ease, transform .15s ease; }
  a.lookthrough-fund-chip:hover { background: var(--surface-raised); border-color: var(--chip-color, var(--cyan)); transform: translateY(-1px); }
  .lookthrough-fund-chip i { width: 5px; height: 5px; flex: none; background: var(--chip-color, var(--cyan)); border-radius: 50%; box-shadow: 0 0 0 2px color-mix(in srgb, var(--chip-color, var(--cyan)) 16%, transparent); }
  .lookthrough-fund-chip strong { color: var(--text-soft); font-size: inherit; }
  .lookthrough-fund-chip span { color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .lookthrough-fund-chip.tone-1 { --chip-color: var(--cyan); }
  .lookthrough-fund-chip.tone-2 { --chip-color: var(--green); }
  .lookthrough-fund-chip.tone-3 { --chip-color: var(--amber); }
  .lookthrough-fund-chip.tone-4 { --chip-color: var(--pink); }
  .lookthrough-holdings-table[data-view="fund"] [data-col="fund_weight_pct"] { grid-column: 5; grid-row: 1; text-align: right; }
  .lookthrough-holdings-table[data-view="fund"] [data-col="fund_weight_pct"]::before { content: "Fund"; }
  .lookthrough-holdings-table[data-view="fund"] [data-col="portfolio_pct"] { grid-column: 3; }
  .lookthrough-holdings-table[data-view="fund"] [data-col="country"] { display: none; }
  .lookthrough-holdings-table[data-view="fund"] [data-col="sector"] { grid-column: 6; }
  .lookthrough-holdings-table td.empty-cell { grid-column: 1 / -1; }
}
.overlap-summary { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 16px; }
.overlap-summary article { display: flex; min-width: 0; padding: 14px 16px; flex-direction: column; background: transparent; border: 0; border-radius: 0; }
.overlap-summary span { color: var(--text-muted); font-size: 0.7rem; font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.overlap-summary strong { margin: 7px 0 3px; overflow: hidden; color: var(--text); font-size: 1.05rem; text-overflow: ellipsis; white-space: nowrap; }
.overlap-summary small { color: var(--text-muted); font-size: 0.7rem; }
.overlap-scale i { background: linear-gradient(90deg, var(--surface-soft), rgb(var(--amber-rgb) / .4)); }
.overlap-scale i:last-of-type { background: linear-gradient(90deg, rgb(var(--amber-rgb) / .4), rgb(var(--amber-rgb) / .72)); }

.lookthrough-flow {
  margin-top: 18px;
  padding: 22px 24px 18px;
}
/* The analysis hero's fact cells: one inset frame, hairline dividers, a quiet
   uppercase label over the number, and no colour of their own -- the diagram
   above already carries the colour, and repeating it here made three plain
   facts read as three separate cards. Drawn under the diagram: it is the
   reading of the diagram, not the way into it. */
.lookthrough-flow-structure {
  display: grid;
  gap: 1px;
  margin-top: 16px;
  overflow: hidden;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
.lookthrough-flow-structure .pulse-card { min-height: 0; padding: 12px; background: var(--surface-well); border: 0; border-radius: 0; box-shadow: none; }
.lookthrough-flow-structure .pulse-label { min-height: 0; color: var(--text-muted); font-size: var(--text-2xs); font-weight: 700; letter-spacing: .045em; line-height: 1.3; text-transform: uppercase; }
.lookthrough-flow-structure .pulse-value { margin-top: 6px; font-size: 1rem; font-weight: 700; letter-spacing: -.02em; }
.lookthrough-flow-structure .pulse-sub { margin-top: 4px; font-size: var(--text-2xs); line-height: 1.35; }
.lookthrough-flow-canvas { min-width: 0; margin-top: 14px; }
.lookthrough-flow-svg { display: block; overflow: visible; }
.lookthrough-flow-ribbon { transition: fill-opacity .12s ease; }
.lookthrough-flow-svg:hover .lookthrough-flow-ribbon { fill-opacity: .45; }
.lookthrough-flow-ribbon:hover { fill-opacity: 1; }
.lookthrough-flow-label {
  fill: var(--text);
  font-size: .72rem;
  font-weight: 600;
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 3px;
}
.lookthrough-flow-label.warning { fill: var(--amber); }
.lookthrough-flow-sub { fill: var(--text-muted); font-size: var(--text-2xs); font-weight: 500; font-variant-numeric: tabular-nums; }
.lookthrough-flow-empty { margin: 24px 0; color: var(--text-muted); font-size: .78rem; text-align: center; }

/* Reveals the next page of underlying assets; hidden by lookthrough.js
   once every row is on screen. */
.lookthrough-pagination { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.lookthrough-more { margin: 0; }
.lookthrough-less { margin-left: auto; }

@media (max-width: 760px) {
  .lookthrough-table-head { align-items: stretch; }
  .lookthrough-more { width: 100%; justify-content: center; }
  .lookthrough-pagination { align-items: stretch; flex-direction: column; }
  .lookthrough-less { width: 100%; margin-left: 0; justify-content: center; }
  .lookthrough-charts { grid-template-columns: 1fr; }
  .holdings-controls { display: grid; grid-template-columns: 1fr; width: 100%; }
  .lookthrough-holdings .panel-table-wrap { overflow-x: hidden; }
  .lookthrough-holdings-table { background: var(--surface-well); border: 1px solid var(--line); box-shadow: var(--shadow-sm); }
}

@media (max-width: 640px) {
  .lookthrough-flow { padding: 17px 16px 14px; }
  .lookthrough-flow-label { font-size: var(--text-2xs); }
  .lookthrough-flow-sub { font-size: .58rem; }

  .exposure-card > strong { font-size: 1rem; }
  .overlap-summary article { padding: 13px; }
  .overlap-summary strong { font-size: 0.92rem; }
  .lookthrough-charts .chart-box { height: 280px; }
}

/* ---------- Settings ---------- */

.settings-tabs {
  position: sticky;
  top: 64px;
  z-index: 35;
  display: flex;
  gap: 6px;
  margin: 0 0 26px;
  padding: 9px 0 12px;
  overflow-x: auto;
  background: rgb(12 16 23 / .96);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(16px);
}
.settings-tabs a {
  flex: 0 0 auto;
  padding: 8px 11px;
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  font-size: 0.84rem;
  text-decoration: none;
}
.settings-tabs a:hover,
.settings-tabs a.active { color: var(--text); background: var(--surface-raised); }
.settings-page-head {
  display: grid;
  grid-template-columns: minmax(0, auto) 1fr;
  grid-template-areas: "title status";
  align-items: center;
  column-gap: 16px;
}
.settings-page-head h1 { grid-area: title; }

/* The only irreversible control in the product. Red top edge rather than a red
   panel: the panel is mostly an explanation of what survives deletion, and text
   on an alarming background is text people skip. */

.settings-panel > .section-head:first-child { margin-top: 0; }
.settings-panel > .form-card { margin-top: 12px; background: var(--surface-well); box-shadow: none; }
.settings-paired-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 14px; }
.settings-paired-form label { display: grid; gap: 6px; min-width: 0; color: var(--text-soft); font-size: .78rem; font-weight: 650; }
/* A select is as wide as its longest option; a long benchmark name would
   otherwise push the label, the panel and the page past a phone's width. */
.settings-paired-form select { width: 100%; min-width: 0; }
.settings-paired-form .action-toolbar { grid-column: 1 / -1; margin-top: 0; }
#lookthrough-data { margin-top: 34px; padding-top: 4px; border-top: 1px solid var(--line); }

@media (max-width: 760px) {
  /* Full-bleed to the .container gutter. A bleed wider than that gutter widens
     the page, and the phone then zooms out and drops the bottom nav. */
  .settings-tabs { top: 58px; margin-right: -16px; margin-left: -16px; padding-right: 16px; padding-left: 16px; }
  .settings-page-head {
    grid-template-columns: 1fr;
    grid-template-areas: "title" "status";
    row-gap: 9px;
  }

  .settings-paired-form { grid-template-columns: 1fr; }
  .settings-paired-form .action-toolbar { grid-column: auto; }
}

@media (max-width: 480px) {
  .settings-tabs { margin-right: -10px; margin-left: -10px; padding-right: 10px; padding-left: 10px; }
}

/* ---------- Help ---------- */

.faq-tools { display: flex; align-items: end; justify-content: space-between; gap: 16px; margin: 4px 0 12px; }
.faq-search { display: grid; gap: 5px; width: min(420px, 100%); }
.faq-search input { width: 100%; min-height: 42px; font-size: 0.86rem; text-transform: none; }
.faq-nav { position: sticky; top: 64px; z-index: 34; display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; padding: 8px 0; background: rgb(12 16 23 / .96); backdrop-filter: blur(16px); }
.faq-nav a {
  padding: 7px 11px;
  color: var(--text-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: 0.8rem;
  text-decoration: none;
  white-space: nowrap;
}
.faq-nav a:hover { color: var(--cyan); border-color: rgb(var(--cyan-rgb) / .45); }
.faq-section { scroll-margin-top: 130px; }

.faq-section > .section-head { margin: 0 0 12px; }
.faq-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
/* A section with one entry would otherwise leave half the row empty. */
.faq-grid > article:only-child { grid-column: 1 / -1; }
.faq-grid article {
  padding: 18px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  scroll-margin-top: 90px;
  transition: border-color 200ms ease, box-shadow 200ms ease;
}
.faq-grid article:target { border-color: var(--cyan); box-shadow: 0 0 0 3px rgb(var(--cyan-rgb) / .22); }
.faq-grid h3 { margin: 0; color: var(--text-soft); }
.faq-grid p { margin: 8px 0 0; color: var(--text-muted); font-size: 0.86rem; line-height: 1.6; }
.faq-link { color: inherit; text-decoration: none; }
.faq-link:hover,
.faq-link:focus-visible { color: var(--cyan); text-decoration: underline; }

@media (max-width: 640px) {
  .faq-tools { display: grid; }
  /* Full-bleed to the .container gutter, as .settings-tabs. */
  .faq-nav { top: 58px; margin-right: -16px; margin-left: -16px; padding-right: 16px; padding-left: 16px; flex-wrap: nowrap; overflow-x: auto; }
  .faq-section { scroll-margin-top: 122px; }
  .faq-grid { grid-template-columns: 1fr; }
}

@media (max-width: 480px) {
  .faq-nav { margin-right: -10px; margin-left: -10px; padding-right: 10px; padding-left: 10px; }
}

/* Signed-out and pre-household pages: sign in, register, password reset, email
   confirmation, onboarding. One narrow column, because the 1160px content
   container is sized for dense portfolio tables and leaves a two-field form
   stranded in the middle of an empty page. Only these hosted pages use it; every
   page with portfolio data keeps the full container. */
.auth-narrow { max-width: 480px; margin: 0 auto; }
.auth-narrow .page-head { display: block; }
.auth-links { margin: 16px 0 0; color: var(--text-muted); font-size: 0.88rem; }
.auth-links a { color: var(--cyan); }
.auth-links a:hover,
.auth-links a:focus-visible { text-decoration: underline; }

/* The six-digit sign-in code. One input, styled so the digits read as a code
   rather than as a password: oversized, monospaced so no digit is narrower than
   its neighbour, and spaced far enough apart to check against the email at a
   glance. The trailing letter-spacing lands after the last digit, so the text is
   padded back by half of it to stay optically centred. */
.form-card input.code-entry {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: clamp(1.7rem, 8vw, 2.2rem);
  font-variant-numeric: tabular-nums;
  letter-spacing: .38em;
  text-indent: .38em;
  text-align: center;
  min-height: 68px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: var(--surface-well);
}
.form-card input.code-entry::placeholder { color: var(--text-faint); opacity: .25; }
.form-card input.code-entry:focus-visible { border-color: var(--cyan); }
/* Filled and unfilled are worth telling apart without reading the digits: the
   field turns cyan the moment six are in, which is also the moment the form
   submits itself. */
.code-entry.is-complete { border-color: var(--cyan); color: var(--cyan-bright); }
.code-entry-status {
  margin: 8px 0 0;
  min-height: 1.2em;
  color: var(--text-muted);
  font-size: .85rem;
  text-align: center;
}
.code-entry-status.is-working { color: var(--cyan); }
/* The button is the fallback path, not the main event -- the form submits
   itself once the sixth digit lands -- so it sits centred under the field
   rather than stretched across the card. */
.code-entry-actions { display: flex; justify-content: center; }
/* A signed-out page carries no nav, no filters and no table, so the content
   container's ordinary top padding leaves the heading sitting right under the
   header rule. Extra room above it, given up again on short screens. */
.auth-centred { padding-top: 40px; }
@media (max-height: 640px) { .auth-centred { padding-top: 16px; } }
/* Everything on one axis. The code field and its button are centred by their
   own width, and a left-aligned heading and hint above them read as a second
   column that isn't there. */
.auth-centred .page-head,
.auth-centred .hint,
.auth-centred .auth-links { text-align: center; }
/* The dense 5px gap under a page title is for a heading sitting over a table,
   where the hint is a caption. Here it is the only sentence on the page. */
.auth-centred .page-head .hint { margin-top: 12px; }
.code-entry-actions .btn-primary { min-width: 180px; }

/* A short form on one line: label-above-input fields side by side, with the
   submit aligned to their baseline. For forms of two or three brief values -- the
   Flex connection, say -- where the stacked full-width treatment produces a tall
   column of nearly empty space. Wraps to one field per line on a phone. */
.inline-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; }
.inline-form label { flex: 1 1 170px; margin: 0; }
/* A field that should not grow to fill the row: an email address is a known
   width, and stretching one across a wide panel makes it look like it expects
   more than it does. */
.inline-form label.field-narrow { flex: 0 1 320px; }
.inline-form button { flex: 0 0 auto; }
/* An .action-toolbar used as an inline form's action: it is the row's last flex
   item, not a new line, so the button keeps the fields' baseline. Without this
   the toolbar's own margin pushes the submit under a full-width select. */
.inline-form > .action-toolbar { flex: 0 0 auto; margin: 0 0 0 auto; }
@media (max-width: 640px) {
  .inline-form label,
  .inline-form label.field-narrow { flex-basis: 100%; }
  .inline-form button { width: 100%; }
}

/* ==================== public and account pages ==================== */

/* ---------- signing out ----------
   In the "More" menu rather than a header button of its own: the header already
   carries the brand, three nav links, More and the portfolio selector, and a
   sixth control is what pushes it into wrapping on a laptop. Above it, in the
   line the account email used to hold, is how old the IBKR data is: it
   qualifies every number on every page, and this is the one place in the shell
   that can say so without being in anyone's way.

   The button is styled to read as a menu row rather than as a call to action.
   Signing out is not something to invite; it is something to be able to find. */
.nav-account {
  margin-top: 5px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
}
.nav-freshness {
  display: flex;
  gap: 6px;
  align-items: center;
  padding: 4px 11px 2px;
  overflow: hidden;
  color: var(--text-muted);
  font-size: var(--text-xs);
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Green while the last successful import is recent, amber once it is not.
   Five days, not one: IBKR produces nothing over a weekend or a holiday. */
.nav-freshness-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
}
.nav-freshness-dot.fresh { background: var(--green); }
.nav-freshness-dot.late { background: var(--amber); }
.nav-signout {
  width: 100%;
  padding: 9px 11px;
  color: var(--text-soft);
  font: inherit;
  font-size: 0.84rem;
  font-weight: 650;
  text-align: left;
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav-signout:hover { color: var(--text); background: var(--surface-soft); }
/* The account group's heading is an email address, so it keeps its own case --
   unlike the "App" heading above it, which is a label. */
.mobile-menu-group.account > span { text-transform: none; letter-spacing: 0; }
.mobile-more .nav-signout { padding: 9px 12px; border-radius: 6px; }

/* ---------- legal pages and the footer that links to them ---------- */
/* Prose, not a dashboard: a measure of ~68 characters, because a terms document
   set to the full width of a desktop container is unreadable and therefore
   unread -- which defeats the point of publishing it. */
/* Centred, like the landing page. Left-aligned in a wide viewport it read
   as a column that had failed to lay out rather than as a deliberate
   measure. */
.legal-page { max-width: 44rem; margin: 0 auto; }
.legal-section { margin-top: 26px; }
.legal-section h2 {
  margin-bottom: 8px;
  color: var(--text);
  font-size: 1rem;
}
.legal-section p,
.legal-section li { color: var(--text-soft); line-height: 1.65; }
.legal-section p + p { margin-top: 10px; }
.legal-section ul { margin: 8px 0 12px; padding-left: 20px; display: grid; gap: 6px; }
.legal-table { margin-top: 10px; }
.legal-table td { vertical-align: top; }

.site-footer {
  display: flex;
  gap: 18px;
  justify-content: center;
  margin: 40px 0 24px;
}
.site-footer a { color: var(--text-muted); font-size: 0.74rem; text-decoration: none; }
.site-footer a:hover { color: var(--text-soft); text-decoration: underline; }

/* ---------- the public landing page ----------
   Same palette as the product, but an editorial rhythm rather than a second
   dashboard. The data previews are real application captures of the
   deterministic marketing household.

   The hero, asymmetric product proof, trust band and pricing each get a distinct
   silhouette. --landing-measure keeps the shorter prose readable while shared
   edges and spacing hold the composition together. */
.landing {
  --landing-measure: 42rem;
  --landing-split: minmax(0, var(--landing-measure)) minmax(0, 1fr);
  --landing-gap: clamp(38px, 5vw, 72px);
  --landing-step: clamp(48px, 6vw, 72px);
  max-width: 78rem;
  margin: 0 auto;
  overflow: clip;
}

.landing-eyebrow {
  margin-bottom: 14px;
  color: var(--cyan-bright);
}
.landing-hero {
  display: grid;
  gap: clamp(28px, 4vw, 42px);
  padding: clamp(32px, 3.4vw, 44px) 0 0;
}
.landing-hero-heading { text-align: center; }
.landing-hero h1 {
  max-width: 18ch;
  margin: 0 auto;
  font-size: clamp(3rem, 4.7vw, 4.35rem);
  line-height: 1;
  letter-spacing: -0.055em;
}
.landing-hero-details {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(24rem, .95fr);
  gap: var(--landing-gap);
  align-items: start;
  max-width: 72rem;
  margin: 0 auto;
}
.landing-lede {
  max-width: var(--landing-measure);
  color: var(--text-soft);
  font-size: 1.04rem;
  line-height: 1.68;
}
.landing-hero-action { justify-self: end; width: 100%; max-width: 38rem; }
.landing-hero-product {
  position: relative;
  z-index: 0;
  isolation: isolate;
  width: 100%;
  margin-top: 4px;
}
.landing-hero-product::before {
  position: absolute;
  z-index: 0;
  inset: -16% 8% 8%;
  background: radial-gradient(ellipse, rgb(37 190 194 / 18%), transparent 68%);
  content: "";
}
.landing-hero-product > picture { position: relative; z-index: 1; }
.landing-capture { min-width: 0; margin: 0; }
.landing-capture picture { display: block; overflow: hidden; border-radius: var(--radius-xl); }
.landing-capture img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-pop);
}
.landing-capture figcaption {
  margin-top: 12px;
  color: var(--text-muted);
  font-size: .72rem;
  text-align: center;
}
.landing-cta {
  min-height: 48px;
  padding: 13px 22px;
  font-size: 0.92rem;
  text-decoration: none;
}
.landing-section-intro {
  max-width: var(--landing-measure);
  margin-bottom: 38px;
}
.landing-section-intro h1,
.landing-section-intro h2,
.landing-data h2 {
  font-size: clamp(1.75rem, 3vw, 2.75rem);
  line-height: 1.08;
  letter-spacing: -0.035em;
}
.landing-outcomes {
  display: grid;
  gap: var(--landing-step);
  padding: var(--landing-step) 0 0;
}
.landing-story {
  display: grid;
  grid-template-columns: 1fr;
  gap: 26px;
}
.landing-outcomes-composed {
  grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
  gap: 22px;
}
.landing-outcomes-composed .landing-story {
  padding: clamp(22px, 3vw, 36px);
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  box-shadow: 0 18px 45px rgb(0 0 0 / 9%);
}
.landing-outcomes-composed .landing-story-lead {
  grid-column: 1 / -1;
  grid-template-columns: minmax(15rem, .48fr) minmax(0, 1.52fr);
  gap: var(--landing-gap);
  align-items: center;
  overflow: hidden;
}
.landing-outcomes-composed .landing-story-card {
  grid-template-rows: auto 1fr;
  align-content: space-between;
}
.landing-outcomes-composed .landing-story-fire {
  background: linear-gradient(145deg, var(--accent-soft), var(--surface-well) 72%);
  border-color: var(--accent-line);
}
.landing-feature-kicker {
  margin-bottom: 10px;
  color: var(--cyan-bright);
}
.landing-story-copy { max-width: var(--landing-measure); }
.landing-story-copy h2 {
  margin-bottom: 14px;
  font-size: clamp(1.45rem, 2.4vw, 2.15rem);
  line-height: 1.12;
  letter-spacing: -0.025em;
}
.landing-story-copy > p:last-child,
.landing-data-copy > p {
  color: var(--text-soft);
  line-height: 1.72;
}
.landing-data {
  display: grid;
  grid-template-columns: var(--landing-split);
  gap: var(--landing-gap);
  align-items: start;
  margin-top: var(--landing-step);
  padding: var(--landing-step) 0 0;
  border-top: 1px solid var(--line);
}
.landing-data { align-items: center; }
.landing-trust {
  padding: clamp(30px, 4vw, 48px);
  background:
    linear-gradient(120deg, rgb(37 190 194 / 8%), transparent 46%),
    var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
}
.landing-trust .landing-feature-kicker { margin-bottom: 12px; }
.landing-data-copy > p { margin-top: 18px; }
.landing-data-copy > a {
  display: inline-block;
  margin-top: 20px;
  font-size: .84rem;
}
.landing-data-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); }
.landing-data-facts > div { padding: 20px; background: var(--canvas); }
.landing-data-facts dt {
  margin-bottom: 5px;
  color: var(--text-muted);
}
.landing-data-facts dd { color: var(--text); font-size: .88rem; }
.landing-pricing {
  margin-top: var(--landing-step);
  padding: var(--landing-step) 0 0;
  border-top: 1px solid var(--line);
}
/* The rule separates it from the section above; /pro has none above it. */
.landing > .landing-pricing:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.landing-plans {
  display: grid;
  grid-template-columns: .8fr 1.1fr 1.1fr;
  gap: 12px;
  margin-bottom: 22px;
}
.landing-plan {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 190px;
  padding: 25px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.landing-plan-featured {
  background: linear-gradient(145deg, var(--accent-soft), var(--surface-well));
  border-color: var(--accent-line);
  box-shadow: 0 18px 42px rgb(0 0 0 / 10%);
}
.landing-plan h3 { font-size: .98rem; }
.landing-plan > p:last-child { color: var(--text-muted); font-size: .82rem; }
.landing-plan-points {
  display: grid;
  gap: 7px;
  margin: 0;
  padding-left: 1.1rem;
  color: var(--text-muted);
  font-size: .82rem;
  line-height: 1.45;
}
.landing-plan-points li::marker { color: var(--cyan-bright); }
/* A card's heading row: name left, its offer (founding places, trial) right. */
.landing-plan > div { display: flex; gap: 16px; align-items: baseline; justify-content: space-between; }
.landing-plan > div > span { color: var(--green-bright); font-size: .73rem; text-align: right; }
.landing-price { margin: 20px 0 12px; }
.landing-price strong { color: var(--text); font-size: 2.5rem; letter-spacing: -.04em; }
.landing-price span { margin-left: 5px; color: var(--text-muted); font-size: .82rem; }
/* Not uppercased, unlike every other header in .data-table. These are sentences
   of marketing copy rather than column labels, and small caps made the one
   table a stranger reads shout its whole left-hand column. */
.landing-plan-table th[scope="row"] {
  color: var(--text-soft);
  font-size: .9em;
  font-weight: 500;
  letter-spacing: normal;
  text-align: left;
  text-transform: none;
}
/* The verdict columns are read against each other, so they get equal, narrow,
   centred columns rather than a share of the page each. */
.landing-plan-table th:not(:first-child),
.landing-plan-table td:not(:first-child) { width: 6rem; text-align: center; }
.landing-yes { color: var(--green); font-weight: 700; }
.landing-no { color: var(--text-faint); }
/* No measure cap: at .8rem the caption fits the container on one line, and the
   measure broke "More about Pro" onto a second. */
.landing-note { margin: 17px auto 0; color: var(--text-muted); font-size: .8rem; line-height: 1.6; text-align: center; }
.landing-closing {
  margin: calc(var(--landing-step) * 1.5) 0 24px;
  padding: clamp(42px, 7vw, 78px) 24px;
  text-align: center;
  background:
    radial-gradient(circle at 50% 0, rgb(37 190 194 / 15%), transparent 55%),
    var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
}
.landing-closing h2 { font-size: clamp(1.9rem, 4vw, 3.2rem); letter-spacing: -.04em; }
.landing-closing .landing-lede { margin-right: auto; margin-left: auto; }
.landing-closing .landing-join { justify-content: center; }
.landing-closing .hint { margin-top: 14px; margin-bottom: 0; }

@media (max-width: 980px) {
  .landing-hero h1 { max-width: 14ch; }
  .landing-hero-details { grid-template-columns: 1fr; gap: 20px; }
  .landing-hero-action { justify-self: start; }
  .landing-story { grid-template-columns: 1fr; }
  .landing-data { grid-template-columns: 1fr; }
}
@media (max-width: 980px) {
  .landing-outcomes-composed .landing-story-lead { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .landing { --landing-step: 38px; }
  .landing-hero { gap: 38px; }
  .landing-hero h1 {
    max-width: 20ch;
    font-size: clamp(1.98rem, 9.25vw, 2.86rem);
    line-height: 1.08;
    letter-spacing: -0.04em;
  }
  .landing-lede { margin-top: 18px; font-size: .96rem; }
  .landing-section-intro { margin-bottom: 30px; }
  .landing-story { grid-template-columns: 1fr; gap: 26px; }
  .landing-outcomes-composed { grid-template-columns: 1fr; gap: 18px; }
  .landing-outcomes-composed .landing-story-lead { grid-column: auto; }
  .landing-outcomes-composed .landing-story { padding: 22px; }
  .landing-data { gap: 30px; }
  .landing-data-facts { grid-template-columns: 1fr; }
  .landing-plans { grid-template-columns: 1fr; }
  .landing-plan { min-height: 165px; }
  .landing-plan > div { align-items: flex-start; flex-direction: column; gap: 5px; }
  .landing-plan > div > span { text-align: left; }
  /* Stays a real side-by-side comparison on a phone: stacking it into cards
     (.card-rows) repeated each plan name on every row. Fixed layout gives the
     labels the space and each verdict a narrow, equal column. */
  .landing-plan-table { table-layout: fixed; width: 100%; }
  .landing-plan-table th,
  .landing-plan-table td { padding: 9px 6px; font-size: .78em; }
  .landing-plan-table th[scope="row"] { line-height: 1.35; }
  .landing-plan-table th:not(:first-child),
  .landing-plan-table td:not(:first-child) { width: 3.6rem; text-align: center; }
  .landing-closing { padding-right: 18px; padding-left: 18px; }
}

/* ---------- what Pro adds ----------
   The foot of a Free page. It borrows .analysis-disclosure for its frame, so
   only the body needs rules -- every disclosure in this sheet styles its own
   body, because the shared rule stops at the summary.

   No accent border and no colour of its own: it is a description of the
   product, not a warning, and a Free page ending in a coloured box would say
   otherwise. */
.pro-adds { margin-top: 22px; }
.pro-adds-body { display: flex; padding: 16px; flex-direction: column; align-items: flex-start; gap: 16px; }
.pro-adds-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}
.pro-adds-list li {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 13px 15px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.pro-adds-list strong { color: var(--text); font-size: .82rem; }
.pro-adds-list span { color: var(--text-muted); font-size: .76rem; line-height: 1.5; }

/* ---------- holding detail ---------- */
.holding-page { margin-bottom: 14px; }
.holding-back,
.holding-link { display: inline-block; color: var(--cyan); font-size: .8rem; text-decoration: none; }
.holding-back { margin-bottom: 12px; }
.holding-back:hover,
.holding-link:hover { color: var(--cyan-bright); text-decoration: underline; }
.holding-link-stealth { display: inline; color: inherit; cursor: pointer; font-size: inherit; text-decoration: none; }
.holding-link-stealth:hover { color: inherit; text-decoration: none; }
.holding-page-head { align-items: flex-end; justify-content: space-between; }
.holding-page-head > div:first-child { min-width: 0; }
.holding-subtitle { margin: 5px 0 0; color: var(--text-muted); font-size: .84rem; }
.holding-identity { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.holding-identity span { padding: 5px 8px; color: var(--text-muted); font-size: var(--text-xs); background: var(--surface-well); border: 1px solid var(--line); border-radius: 999px; }
.holding-empty { display: flex; flex-direction: column; gap: 5px; margin-bottom: 22px; }
.holding-empty span { color: var(--text-muted); font-size: .84rem; }
.holding-overview {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(320px, 1fr);
}
.holding-overview-main,
.holding-role-card,
.holding-chart-card,
.holding-income-chart,
.holding-timeline { min-width: 0; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.holding-overview-main {
  position: relative;
  display: flex;
  grid-row: 1 / span 3;
  flex-direction: column;
  justify-content: space-between;
  min-height: 240px;
  padding: 20px 24px;
  overflow: hidden;
  border: 0;
  border-radius: 0;
}
.holding-hero-stats { position: relative; z-index: 1; display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }
.holding-current-value { display: block; margin-top: 8px; color: var(--text); font-size: clamp(2.1rem, 5vw, 3.4rem); line-height: 1; letter-spacing: -.055em; }
/* Two facts, one per row: the number leads, its period follows. Both carry the
   signed tone (.pos/.neg), so the colour is the sign, not decoration. The period
   never wraps -- "ALL / TIME" over two lines reads as two labels. */
.holding-hero-return { display: grid; gap: 7px; justify-items: end; padding-top: 2px; text-align: right; }
.holding-hero-return p { display: flex; align-items: baseline; gap: 6px; margin: 0; }
.holding-hero-return strong { font-size: clamp(1.05rem, 2.1vw, 1.55rem); line-height: 1; letter-spacing: -.035em; font-variant-numeric: tabular-nums; }
.holding-hero-return em { font-style: normal; white-space: nowrap; }
.holding-hero-chart { position: absolute; right: -8px; bottom: -1px; left: -8px; height: 130px; opacity: .92; }
.holding-hero-chart canvas { width: 100% !important; height: 100% !important; }
.holding-hero-weight { position: absolute; right: 20px; bottom: 15px; z-index: 2; display: flex; align-items: baseline; gap: 7px; padding: 6px 9px; background: rgb(var(--well-rgb) / .72); border: 1px solid var(--line); border-radius: var(--radius-md); backdrop-filter: blur(4px); }
.holding-hero-weight strong { color: var(--text); font-size: 1rem; font-variant-numeric: tabular-nums; }
.holding-role-card { display: flex; flex-direction: column; justify-content: center; padding: 8px 24px; background: rgb(var(--well-rgb) / .2); border: 0; border-top: 1px solid var(--line); border-left: 1px solid var(--line); border-radius: 0; }
.holding-role-card .holding-target-track { margin-top: 8px; margin-bottom: 4px; }
.holding-overview.holding-single-account .holding-role-card { justify-content: flex-start; padding-top: 24px; padding-bottom: 30px; }
.holding-overview.holding-single-account .holding-pulse-grid { padding-top: 4px; padding-bottom: 4px; }
.holding-overview.holding-single-account .holding-target-track { margin: 0; overflow: visible; }
.holding-overview.holding-single-account .holding-target-actual { overflow: hidden; }
.holding-overview.holding-single-account .holding-target-label { top: calc(100% + 13px); right: 0; bottom: auto; left: 0; height: auto; justify-content: center; padding: 0; color: var(--text-muted); text-align: center; text-shadow: none; }
.holding-overview.holding-single-account .holding-target-track-full .holding-target-label { color: var(--text-muted); text-shadow: none; }
.holding-target-track { position: relative; height: 30px; margin: 20px 0 13px; overflow: hidden; background: var(--surface-raised); border-radius: var(--radius-md); }
.holding-target-actual { display: block; height: 100%; background: linear-gradient(90deg, var(--cyan-deep), var(--cyan)); border-radius: inherit; }
.holding-target-track i { position: absolute; top: 5px; z-index: 1; width: 2px; height: 20px; background: var(--amber); box-shadow: 0 0 0 2px var(--surface-well); }
.holding-target-label { position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 0 9px; color: var(--text); font-size: var(--text-xs); font-variant-numeric: tabular-nums; line-height: 1.15; pointer-events: none; text-shadow: 0 1px 2px var(--surface-raised); }
.holding-target-track-full .holding-target-label { color: var(--text-on-accent); text-shadow: 0 1px 2px var(--cyan-deep); }
.holding-target-label span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.holding-target-label strong { color: inherit; font-weight: 650; }
.holding-account-map { margin-top: 17px; padding-top: 14px; border-top: 1px solid var(--line); }
.holding-overview > .holding-account-map { grid-column: 2; margin-top: 0; padding: 17px 24px 13px; background: rgb(var(--well-rgb) / .2); border-top: 0; border-bottom: 1px solid var(--line); border-left: 1px solid var(--line); }
.holding-account-track { display: flex; gap: 2px; height: 20px; overflow: hidden; background: var(--surface-raised); border-radius: var(--radius-pill); }
.holding-account-track i { display: flex; flex: 0 0 auto; box-sizing: border-box; align-items: center; gap: 8px; min-width: 3px; height: 100%; overflow: hidden; padding: 0 7px; color: var(--text-on-accent); font-style: normal; line-height: 1.15; background: var(--blue); }
.holding-account-track i:nth-child(2) { background: var(--slate); }
.holding-account-track i:nth-child(3n) { background: var(--cyan-deep); }
.holding-account-track b { overflow: hidden; font-size: .6rem; text-overflow: ellipsis; white-space: nowrap; }
/* The share sits at the right edge of its own segment and never shrinks: the
   label truncates first, since the number is the fact being compared. */
.holding-account-track em { margin-left: auto; flex: none; font-size: .58rem; font-style: normal; font-variant-numeric: tabular-nums; }
.holding-account-segment-compact { gap: 3px !important; padding-right: 4px !important; padding-left: 4px !important; }
.holding-account-segment-compact b { display: none; }
.holding-account-segment-narrow { padding: 0 !important; }
.holding-account-segment-narrow b,
.holding-account-segment-narrow em { display: none; }
.holding-pulse-grid { grid-column: 2; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; padding: 8px 12px 0; background: rgb(var(--well-rgb) / .2); border-left: 1px solid var(--line); }
.holding-pulse-grid .pulse-card { min-height: 0; padding: 8px 12px 10px; background: transparent; border: 0; border-radius: 0; box-shadow: none; }
.holding-pulse-grid .pulse-card::before { display: none; }
.holding-pulse-grid .pulse-card + .pulse-card { border-left: 1px solid var(--line); }
.holding-pulse-grid .pulse-label { color: var(--text-muted); font-size: var(--text-2xs); font-weight: 700; letter-spacing: .045em; text-transform: uppercase; }
.holding-pulse-grid .pulse-value { margin-top: 6px; overflow: hidden; color: var(--text); font-size: 1rem; font-variant-numeric: tabular-nums; line-height: 1.1; text-overflow: ellipsis; white-space: nowrap; }
.holding-pulse-grid .pulse-sub { margin-top: 4px; color: var(--text-muted); font-size: var(--text-xs); }
.holding-position-strip { display: grid; grid-column: 1 / -1; grid-template-columns: auto repeat(4, minmax(0, 1fr)); align-items: center; background: rgb(var(--well-rgb) / .36); border-top: 1px solid var(--line); }
.holding-position-strip > span { padding: 14px 20px; }
.holding-position-strip > div { display: flex; min-width: 0; padding: 12px 18px; align-items: baseline; justify-content: space-between; gap: 10px; border-left: 1px solid var(--line); }
.holding-position-strip strong { overflow: hidden; color: var(--text); font-size: .88rem; font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }

.holding-performance { position: relative; min-width: 0; }
.holding-section > .section-head { margin-top: 0; }

.holding-section-head { align-items: center; }
.holding-section-title { display: flex; min-width: 0; flex: 1 1 auto; align-items: baseline; justify-content: flex-start; gap: 8px; }
.holding-chart-switcher { flex: none; }
/* The marker for a holding whose daily history was rebuilt from today's surviving
   lots rather than reported day by day: amber because the figures answer a
   narrower question, and a link because that is what Help explains. margin-right
   keeps it beside the heading in a space-between .section-head. */
.holding-reconstructed { margin-left: auto; text-decoration: none; }
.holding-reconstructed:hover,
.holding-reconstructed:focus-visible { text-decoration: underline; }
.holding-period-strip { grid-template-columns: repeat(6, minmax(68px, 1fr)); margin: 0 0 10px; }
.holding-period-strip button { min-height: 46px; }
.holding-period-summary { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.holding-chart-card { padding: 15px; }
.holding-chart-wrap { position: relative; height: 330px; }
.holding-chart-wrap .chart-empty { height: 100%; }
.holding-chart-wrap canvas { width: 100% !important; height: 100% !important; }
.holding-chart-legend { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 16px; min-height: 20px; margin: 0 0 10px; color: var(--text-muted); font-size: .72rem; }
.holding-chart-legend-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.holding-chart-legend-swatch { display: inline-block; flex: none; }
.holding-chart-legend-line { width: 28px; height: 0; border-top: 2px solid var(--holding-legend-color); }
.holding-chart-legend-dotted { border-top-style: dotted; }
.holding-chart-legend-point { width: 9px; height: 9px; background: var(--holding-legend-color); border: 1px solid var(--holding-legend-color); border-radius: 50%; }
.holding-income-layout { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(280px, .65fr); gap: 12px; }
.holding-section h3 { margin: 0 0 13px; color: var(--text); font-size: .84rem; }
.holding-sector-bars i { display: block; height: 5px; overflow: hidden; background: var(--surface-raised); border-radius: 999px; }
.holding-sector-bars i b { display: block; height: 100%; background: var(--cyan); border-radius: inherit; }
.holding-income-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.holding-income-chart { position: relative; height: 170px; padding: 12px; }
.holding-income-chart canvas { width: 100% !important; height: 100% !important; }
.holding-secondary-grid { display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(360px, .92fr); gap: 16px; }
.holding-secondary-grid > .holding-section { min-width: 0; }
.holding-secondary-grid > .holding-income[hidden] + .holding-activity { grid-column: 1 / -1; }
.holding-secondary-grid .holding-income-layout { grid-template-columns: 1fr; }
.holding-secondary-grid .holding-income-stats { order: 2; }
.holding-lookthrough .section-head { align-items: baseline; }
.holding-lookthrough .section-head a,
.holding-activity .section-head a { color: var(--cyan); font-size: .75rem; text-decoration: none; }
.holding-exposure-card { min-width: 0; }
.holding-fund-flow { display: grid; grid-template-columns: minmax(0, 1fr) 28px minmax(0, 1fr); align-items: stretch; margin-bottom: 12px; }
.holding-fund-flow > article { padding: 16px 17px; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.holding-fund-flow > i { display: grid; place-items: center; color: var(--cyan); font-size: 1.1rem; font-style: normal; }
.holding-fund-flow h3 { margin: 0 0 10px; }
.holding-fund-flow .holding-sector-bars { display: flex; flex-wrap: wrap; gap: 7px 16px; }
.holding-fund-flow .holding-sector-bars > div,
.holding-fund-flow .holding-sector-bars > div + div { display: inline-flex; grid-template-columns: none; align-items: baseline; gap: 5px; margin: 0; color: var(--text-muted); white-space: nowrap; }
.holding-fund-flow .holding-sector-bars > div::before { width: 7px; height: 7px; background: var(--cyan); border-radius: 2px; content: ""; }
.holding-fund-flow .holding-sector-bars > div:nth-child(2)::before { background: var(--green); }
.holding-fund-flow .holding-sector-bars > div:nth-child(3)::before { background: var(--amber); }
.holding-fund-flow .holding-sector-bars > div:nth-child(4)::before { background: var(--pink); }
.holding-fund-flow .holding-sector-bars > div:nth-child(5)::before { background: var(--slate); }
.holding-fund-flow .holding-sector-bars strong { color: var(--text); }
.holding-fund-flow .holding-sector-bars i { display: none; }
.holding-lookthrough-alert { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 12px; padding: 11px 14px; background: color-mix(in srgb, var(--amber) 8%, var(--surface-well)); border: 1px solid color-mix(in srgb, var(--amber) 35%, var(--line)); border-radius: var(--radius-lg); font-size: .75rem; }
.holding-lookthrough-alert span { color: var(--text-muted); }
.holding-exposure-card { padding: 17px; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.holding-asset-allocation { margin-bottom: 14px; }
.holding-asset-strip { display: flex; height: 9px; overflow: hidden; background: var(--surface-raised); border-radius: 999px; }
.holding-asset-strip > i { flex: var(--holding-share) 1 0; min-width: 2px; }
.holding-asset-strip .cyan, .holding-asset-legend .cyan { background: var(--cyan); }
.holding-asset-strip .green, .holding-asset-legend .green { background: var(--green); }
.holding-asset-strip .amber, .holding-asset-legend .amber { background: var(--amber); }
.holding-asset-strip .pink, .holding-asset-legend .pink { background: var(--pink); }
.holding-asset-strip .slate, .holding-asset-legend .slate { background: var(--slate); }
.holding-asset-strip .other, .holding-asset-legend .other { background: var(--text-muted); }
.holding-asset-legend { display: flex; flex-wrap: wrap; gap: 7px 13px; margin-top: 8px; color: var(--text-muted); font-size: var(--text-xs); }
.holding-asset-legend span { display: inline-flex; align-items: center; gap: 5px; }
.holding-asset-legend i { width: 7px; height: 7px; border-radius: 2px; }
.holding-asset-legend strong { color: var(--text); font-weight: 600; }
.holding-sector-bars > div + div { margin-top: 11px; }
.holding-sector-bars > div { display: grid; grid-template-columns: 1fr auto; gap: 5px 12px; color: var(--text-muted); font-size: .75rem; }
.holding-sector-bars i { grid-column: 1 / -1; }
.holding-company-list { margin: 0; padding: 0; list-style: none; counter-reset: company; }
.holding-company-list li { display: grid; grid-template-columns: minmax(150px, .65fr) minmax(120px, 1fr) auto; align-items: center; gap: 14px; padding: 10px 0; border-top: 1px solid var(--line); font-size: .77rem; }
.holding-company-list li:first-child { padding-top: 0; border-top: 0; }
.holding-company-list span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.holding-company-list .holding-underlying-name { min-width: 0; display: grid; gap: 2px; }
.holding-underlying-name b,
.holding-underlying-name small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.holding-underlying-name b { color: var(--text); font-weight: 600; }
.holding-underlying-name small { color: var(--text-muted); font-size: var(--text-xs); }
.holding-company-list li i { display: block; height: 7px; overflow: hidden; background: var(--surface-raised); border-radius: 999px; }
.holding-company-list li i b { display: block; height: 100%; background: var(--cyan); border-radius: inherit; }
.holding-company-list li.unresolved i b { background: repeating-linear-gradient(135deg, var(--slate), var(--slate) 5px, var(--surface-soft) 5px, var(--surface-soft) 10px); }
.holding-company-list strong { color: var(--text-muted); }
.holding-underlying-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 12px; }
.holding-underlying-head h3 { margin: 0; }
.holding-asset-filter { grid-auto-columns: minmax(74px, 1fr); justify-content: flex-end; }
.holding-asset-filter button { min-height: 48px; padding: 7px 9px; font: inherit; font-size: var(--text-xs); cursor: pointer; }
.holding-assets-limit { align-self: center; color: var(--text-muted); font-size: .7rem; }
.holding-underlying-empty { display: block !important; color: var(--text-muted); text-align: center; }
.lookthrough-holdings { scroll-margin-top: 82px; }
.holding-timeline { margin: 0; padding: 5px 17px; list-style: none; }
.holding-timeline li { display: grid; grid-template-columns: 14px minmax(0, 1fr) auto; align-items: center; gap: 12px; padding: 13px 0; border-top: 1px solid var(--line); }
.holding-timeline li:first-child { border-top: 0; }
.holding-timeline li > i { width: 9px; height: 9px; background: var(--slate); border-radius: 50%; }
.holding-timeline li.buy > i { background: var(--green); }
.holding-timeline li.sell > i { background: var(--red); }
.holding-timeline li.income > i { background: var(--cyan); }
.holding-timeline li > div { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; min-width: 0; }
.holding-timeline li > div span { color: var(--text); font-size: .78rem; font-weight: 650; }
.holding-timeline li > div strong { min-width: 0; overflow: hidden; color: var(--text-muted); font-size: .75rem; font-weight: 400; text-overflow: ellipsis; white-space: nowrap; }
.holding-timeline li > div small { grid-column: 1 / -1; color: var(--text-muted); font-size: var(--text-xs); }
.holding-timeline li > b { font-size: .8rem; font-weight: 600; }
.holding-timeline-empty { display: block !important; color: var(--text-muted); font-size: .78rem; }
.activity-filter-context { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; padding: 10px 12px; color: var(--text-muted); font-size: .76rem; background: var(--surface-well); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.activity-filter-context strong { color: var(--text); }
.activity-filter-context a { margin-left: auto; color: var(--cyan); }

@media (max-width: 980px) {
  .holding-period-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .holding-income-layout { grid-template-columns: 1fr; }
  .holding-income-stats { order: 2; }
  .holding-secondary-grid { grid-template-columns: 1fr; gap: 0; }
}

@media (max-width: 640px) {
  .holding-page-head { align-items: flex-start; }
  .holding-page-head > div:first-child { width: 100%; }
  .holding-identity { display: none; }
  .holding-overview { grid-template-columns: 1fr; }
  .holding-overview-main,
  .holding-role-card { min-height: 0; padding: 18px; }
  .holding-overview-main { grid-row: auto; min-height: 205px; }
  .holding-role-card { border-top: 1px solid var(--line); border-left: 0; }
  .holding-hero-stats { gap: 12px; }
  .holding-pulse-grid { grid-column: 1; border-left: 0; }
  .holding-overview > .holding-account-map { grid-column: 1; padding: 12px 18px; border-top: 1px solid var(--line); border-left: 0; }
  .holding-position-strip { grid-column: 1; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .holding-position-strip > span { grid-column: 1 / -1; padding: 12px 18px 6px; }
  .holding-position-strip > div { display: grid; padding: 10px 18px; border-left: 0; }
  .holding-position-strip > div:nth-of-type(even) { border-left: 1px solid var(--line); }

  .holding-section-head { align-items: flex-start; }
  .holding-chart-switcher { align-self: flex-start; margin-top: 12px; }
  .holding-lookthrough .section-head,
  .holding-activity .section-head { flex-direction: row; align-items: baseline; justify-content: space-between; }
  .holding-period-strip { display: flex; margin-right: -16px; padding-right: 16px; overflow-x: auto; }
  .holding-period-strip button { flex: 0 0 68px; min-height: 48px; }
  .holding-period-summary { grid-template-columns: 1fr; }
  .holding-chart-wrap { height: 250px; }
  .holding-chart-card { padding: 10px 8px; }
  .holding-income-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .holding-income-stats article:last-child { grid-column: 1 / -1; }
  .holding-income-chart { height: 190px; }
  .holding-fund-flow { grid-template-columns: 1fr; }
  .holding-fund-flow > i { height: 28px; transform: rotate(90deg); }
  .holding-lookthrough-alert { align-items: flex-start; flex-direction: column; gap: 4px; }
  .holding-company-list li { grid-template-columns: minmax(100px, 1fr) minmax(80px, .7fr) auto; gap: 9px; }
  .holding-underlying-head { align-items: flex-start; flex-direction: column; }
  .holding-asset-filter { justify-content: flex-start; }
  .holding-timeline { padding: 4px 13px; }
  .holding-timeline li { grid-template-columns: 12px minmax(0, 1fr); gap: 9px; }
  .holding-timeline li > b { grid-column: 2; }
}

/* A compact top inset keeps headings close to their accent edge without
   crowding the content below. Horizontal padding remains page-specific. */

/* On a phone each section keeps its card -- background, full border and
   shadow -- on tighter padding than the desktop box. Keep this after every
   page-specific panel rule because the hosted sheet loads last. */

/* ---------- the operator status page ----------
   Deliberately plain. It is read when something is wrong, by one person, and
   every element it needs (.data-table, .badge, .alert) already exists. */
.ops-page { margin: 0 auto; }
.ops-table th[scope="row"] { color: var(--text); font-weight: 600; text-align: left; }
.ops-note { margin-top: 16px; }
.ops-data-controls { display: flex; align-items: center; gap: 10px; }
.ops-data-controls form { margin: 0; }
/* The per-instrument evidence, opened by clicking the row above it. It carries the
   long-form text that used to stack inside the coverage cells; as one run-on
   paragraph that was no more readable there, so each fact gets its own labelled
   line and the diagnosis is stated in words before any of it. */
.ops-table [data-ops-row] { cursor: pointer; }
.ops-why { padding: 4px 0 8px; }
.ops-why ul { margin: 0 0 12px; padding-left: 18px; }
.ops-why li { margin-bottom: 4px; }
.ops-why p { margin: 0 0 12px; }
.ops-why dl {
  display: grid;
  margin: 0;
  gap: 2px 14px;
  grid-template-columns: max-content minmax(0, 1fr);
}
.ops-why dt { color: var(--text-muted); font-size: 0.85rem; grid-column: 1; }
.ops-why dd { margin: 0; font-size: 0.9rem; grid-column: 2; }
.ops-why dd.hint { margin: 0 0 4px; }

@media (max-width: 760px) {
  .ops-page .page-head { flex-wrap: wrap; }
  .ops-page .page-head > p { flex-basis: 100%; order: 3; }
  .ops-data-controls { width: 100%; flex-wrap: wrap; }
  .ops-data-controls .segmented-control { flex: 1; }
}

@media (max-width: 480px) {
  .ops-data-controls form { width: 100%; }
  .ops-data-controls form button { width: 100%; }
}

/* The one-paragraph summary at the top of each legal document. Larger than the
   body, because it is the part most people will read instead of the rest. */
.legal-lede {
  margin-bottom: 4px;
  padding: 16px 18px;
  color: var(--text);
  font-size: 0.95rem;
  line-height: 1.6;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}

/* Inline links in prose. There is no global `a` colour in this stylesheet -- the
   app's links all carry a class -- so a plain <a> inside a paragraph fell back
   to the browser's default dark blue, which on this background is very nearly
   invisible. Scoped to the pages that contain prose rather than fixed globally,
   because this stylesheet is shared and a global
   link colour would restyle it too. */
.landing a:not(.btn-primary),
.legal-page a { color: var(--cyan); }
.landing a:not(.btn-primary):hover,
.legal-page a:hover { color: var(--cyan-bright); text-decoration: underline; }

/* The signup call to action, and the demo's leave-and-sign-up form. */
.landing-join-block { width: 100%; }
.landing-join {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 26px;
}
.landing-hero-action .landing-join { flex-wrap: nowrap; justify-content: flex-end; margin-top: 0; }
.landing-hero-action .landing-join input { min-width: 0; }
.landing-join .landing-cta { white-space: nowrap; }
.landing-join input {
  flex: 0 1 320px;
  min-height: 46px;
  padding: 0 14px;
  color: var(--text);
  font-size: 0.95rem;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
}
.landing-join input::placeholder { color: var(--text-faint); }
.landing-join input:focus-visible { border-color: var(--cyan); box-shadow: var(--focus); outline: none; }
.landing-join-note {
  margin-top: 12px;
  color: var(--text-muted);
  font-size: 0.8rem;
  text-align: center;
}
.landing-hero-action .landing-join-note { text-align: right; }
@media (max-width: 980px) {
  .landing-hero-action .landing-join { justify-content: flex-start; }
  .landing-hero-action .landing-join-note { text-align: left; }
}
@media (max-width: 640px) {
  .landing-hero-action .landing-join { flex-wrap: wrap; }
  .landing-join input,
  .landing-join .landing-cta { flex: 1 1 100%; }
}

/* ---------- IBKR tracker page ----------
   A tighter, product-led companion to the landing page. The landing page
   introduces the whole product; this page answers one question quickly: what
   happens to an Interactive Brokers account after it is connected? */
.ibkr-page {
  --ibkr-gap: clamp(28px, 5vw, 68px);
  max-width: 76rem;
  margin: 0 auto;
  overflow: clip;
}
.ibkr-section-intro { max-width: 38rem; }
.ibkr-section-intro h2 {
  font-size: clamp(1.9rem, 3.5vw, 3.1rem);
  line-height: 1.06;
  letter-spacing: -.045em;
}
.ibkr-section-intro > p:last-child {
  margin-top: 15px;
  color: var(--text-soft);
  line-height: 1.65;
}
.ibkr-page a:not(.btn-primary):not(.btn-secondary) { color: var(--cyan); }
.ibkr-page a:not(.btn-primary):not(.btn-secondary):hover { color: var(--cyan-bright); }
@media (max-width: 760px) {
  .ibkr-page { --ibkr-gap: 30px; }
}

/* The connection page leads with the broker boundary. Its visual is a simple
   four-stage handoff, so the most important promise is visible before any
   product screenshots. */
.ibkr-connection-page .ibkr-connection-hero {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(22rem, 1fr);
  gap: clamp(30px, 5vw, 58px);
  align-items: center;
  padding: clamp(40px, 6vw, 78px) 0 0;
}
.ibkr-connection-page .ibkr-connection-hero-copy {
  max-width: none;
}
.ibkr-connection-page .ibkr-connection-hero-copy h1 {
  max-width: none;
  font-size: clamp(2.8rem, 5.5vw, 4.8rem);
  line-height: .99;
  letter-spacing: -.06em;
}
.ibkr-connection-page .ibkr-connection-hero-copy > p:not(.landing-eyebrow) {
  max-width: 40rem;
  margin-top: 21px;
  color: var(--text-soft);
  font-size: 1.02rem;
  line-height: 1.7;
}
.ibkr-connection-page .ibkr-connection-hero-actions {
  max-width: 45rem;
  margin-top: 26px;
}
.ibkr-connection-page .ibkr-connection-hero-actions .landing-join {
  justify-content: flex-start;
  margin-top: 0;
}
.ibkr-connection-page .ibkr-connection-hero-actions .landing-join-note { text-align: left; }
.ibkr-connection-page .ibkr-connection-map {
  max-width: none;
  margin: 0;
  padding: clamp(21px, 3vw, 32px);
  background: linear-gradient(145deg, rgb(var(--cyan-rgb) / .1), var(--surface-well) 58%);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow);
}
.ibkr-connection-page .ibkr-map-header {
  display: flex;
  align-items: baseline;
  justify-content: flex-start;
  gap: 16px;
  padding-bottom: 19px;
  border-bottom: 1px solid var(--line);
}
.ibkr-connection-page .ibkr-map-header span {
  color: var(--text-muted);
}
.ibkr-connection-page .ibkr-connection-map ol {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  margin: 25px 0 0;
  padding: 0;
  list-style: none;
}
.ibkr-connection-page .ibkr-connection-map ol::before {
  position: absolute;
  top: 15px;
  bottom: 15px;
  left: 17px;
  width: 1px;
  height: auto;
  background: var(--line-strong);
  content: "";
}
.ibkr-connection-page .ibkr-connection-map li {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 34px 1fr;
  column-gap: 12px;
  gap: 4px 12px;
  min-width: 0;
}
.ibkr-connection-page .ibkr-connection-map li > span {
  display: grid;
  grid-row: 1 / 3;
  width: 26px;
  height: 26px;
  margin: 0;
  place-items: center;
  color: var(--text-on-accent);
  font-size: var(--text-xs);
  font-weight: 800;
  background: var(--cyan);
  border: 4px solid var(--surface);
  border-radius: var(--radius-pill);
  box-sizing: content-box;
}
.ibkr-connection-page .ibkr-connection-map li strong { color: var(--text); font-size: .86rem; }
.ibkr-connection-page .ibkr-connection-map li small { color: var(--text-muted); font-size: .76rem; }
.ibkr-connection-page .ibkr-connection-map > p {
  margin: 8px 0 0;
  padding-top: 17px;
  color: var(--text-muted);
  font-size: .8rem;
  border-top: 1px solid var(--line);
}
.ibkr-connection-page .ibkr-map-readonly {
  display: block;
  margin-top: 25px;
  color: var(--green-bright);
  font-size: .86rem;
}
.ibkr-connection-page .ibkr-connection-map > p b { color: var(--text-soft); }
.ibkr-connection-page .ibkr-connection-map > p span { display: block; margin-top: 3px; }
.ibkr-connection-page .ibkr-safety {
  margin-top: clamp(72px, 10vw, 128px);
}
.ibkr-connection-page .ibkr-section-intro {
  max-width: 42rem;
  margin: 0 auto 33px;
  text-align: center;
}
.ibkr-connection-page .ibkr-section-intro h2 {
  font-size: clamp(1.9rem, 3.5vw, 3rem);
  line-height: 1.06;
  letter-spacing: -.045em;
}
.ibkr-connection-page .ibkr-safety-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}
.ibkr-connection-page .ibkr-safety-grid article {
  min-width: 0;
  padding: 22px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.ibkr-connection-page .ibkr-safety-icon {
  display: grid;
  width: 28px;
  height: 28px;
  margin-bottom: 18px;
  place-items: center;
  color: var(--text-on-accent);
  font-size: .72rem;
  font-weight: 800;
  background: var(--cyan);
  border-radius: var(--radius-pill);
}
.ibkr-connection-page .ibkr-safety-grid article:nth-child(2) .ibkr-safety-icon { background: var(--blue); }
.ibkr-connection-page .ibkr-safety-grid article:nth-child(3) .ibkr-safety-icon { background: var(--green); }
.ibkr-connection-page .ibkr-safety-grid article:nth-child(4) .ibkr-safety-icon { background: var(--amber); }
.ibkr-connection-page .ibkr-safety-grid h3 { margin-bottom: 9px; font-size: 1rem; }
.ibkr-connection-page .ibkr-safety-grid p { color: var(--text-muted); font-size: .82rem; line-height: 1.65; }
.ibkr-connection-page .ibkr-connection-control {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: clamp(30px, 5vw, 68px);
  align-items: start;
  margin-top: clamp(62px, 9vw, 112px);
  padding: clamp(30px, 4vw, 48px);
  background: linear-gradient(120deg, rgb(var(--cyan-rgb) / .08), transparent 56%), var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
}
.ibkr-connection-page .ibkr-connection-control h2 {
  font-size: clamp(1.8rem, 3vw, 2.7rem);
  line-height: 1.06;
  letter-spacing: -.04em;
}
.ibkr-connection-page .ibkr-connection-control > div > p:last-child {
  max-width: 28rem;
  margin-top: 16px;
  color: var(--text-soft);
  font-size: .9rem;
  line-height: 1.7;
}
.ibkr-connection-page .ibkr-connection-control ol {
  display: grid;
  gap: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.ibkr-connection-page .ibkr-connection-control li {
  display: grid;
  gap: 3px;
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
.ibkr-connection-page .ibkr-connection-control li strong { color: var(--text); font-size: .87rem; }
.ibkr-connection-page .ibkr-connection-control li span { color: var(--text-muted); font-size: .8rem; }
.ibkr-connection-page .ibkr-product {
  margin-top: clamp(72px, 10vw, 128px);
}
.ibkr-connection-page .ibkr-product-capture {
  max-width: 72rem;
  margin: 0 auto;
}
.ibkr-connection-page .ibkr-product-capture img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-pop);
}
.ibkr-connection-page .ibkr-product-capture figcaption {
  margin-top: 11px;
  color: var(--text-muted);
  font-size: .72rem;
  text-align: center;
}
.ibkr-connection-page .ibkr-product-links {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 19px 0 4px;
  font-size: .82rem;
}
.ibkr-connection-page .ibkr-product-links a { color: var(--cyan); text-decoration: none; }
.ibkr-connection-page .ibkr-product-links a:hover { color: var(--cyan-bright); text-decoration: underline; }
.ibkr-connection-page .ibkr-product-links span { color: var(--text-faint); }

@media (max-width: 980px) {
  .ibkr-connection-page .ibkr-connection-hero { grid-template-columns: 1fr; }
  .ibkr-connection-page .ibkr-connection-hero-copy { max-width: 42rem; margin: 0 auto; text-align: center; }
  .ibkr-connection-page .ibkr-connection-hero-copy h1 { margin-right: auto; margin-left: auto; }
  .ibkr-connection-page .ibkr-connection-hero-copy > p:not(.landing-eyebrow) { margin-right: auto; margin-left: auto; }
  .ibkr-connection-page .ibkr-connection-hero-actions { margin-right: auto; margin-left: auto; }
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join { justify-content: center; }
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join-note { text-align: center; }
  .ibkr-connection-page .ibkr-safety-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ibkr-connection-page .ibkr-connection-control { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .ibkr-connection-page .ibkr-connection-hero { padding-top: 28px; }
  .ibkr-connection-page .ibkr-connection-hero-copy { max-width: 42rem; text-align: center; }
  .ibkr-connection-page .ibkr-connection-hero-copy h1 {
    margin-right: auto;
    margin-left: auto;
    max-width: 15ch;
    font-size: clamp(2.35rem, 10vw, 3.45rem);
    line-height: 1.06;
  }
  .ibkr-connection-page .ibkr-connection-hero-copy > p:not(.landing-eyebrow) { margin-right: auto; margin-left: auto; font-size: .96rem; }
  .ibkr-connection-page .ibkr-connection-hero-actions { margin-right: auto; margin-left: auto; }
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join { justify-content: center; }
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join-note { text-align: center; }
  .ibkr-connection-page .ibkr-connection-map ol { grid-template-columns: 1fr; gap: 18px; }
  .ibkr-connection-page .ibkr-connection-map ol::before { display: block; }
  .ibkr-connection-page .ibkr-safety { margin-top: 70px; }
  .ibkr-connection-page .ibkr-safety-grid { grid-template-columns: 1fr; }
  .ibkr-connection-page .ibkr-safety-grid article { padding: 20px; }
  .ibkr-connection-page .ibkr-connection-control { margin-top: 70px; padding: 26px 22px; }
  .ibkr-connection-page .ibkr-product { margin-top: 70px; }
}
@media (max-width: 640px) {
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join { flex-wrap: wrap; }
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join input,
  .ibkr-connection-page .ibkr-connection-hero-actions .landing-join .landing-cta { flex: 1 1 100%; }
  .ibkr-connection-page .ibkr-map-header { align-items: flex-start; flex-direction: column; gap: 5px; }
  .ibkr-connection-page .ibkr-connection-map { padding: 20px; }
  .ibkr-connection-page .ibkr-connection-map ol { grid-template-columns: 1fr; gap: 18px; }
  .ibkr-connection-page .ibkr-connection-map li { grid-template-columns: 36px 1fr; column-gap: 10px; }
  .ibkr-connection-page .ibkr-connection-map li > span { grid-row: 1 / 3; margin: 0; }
  .ibkr-connection-page .ibkr-product-links { flex-wrap: wrap; }
}

/* A second-level heading inside a settings panel: separates a form from the
   table above it without looking like another section. */
.settings-subhead {
  margin: 22px 0 10px;
}

/* ---------- the Flex query setup guide ----------
   Open while there is no connection yet, which is when it is needed. Getting
   this wrong is the most likely way a new user fails, and the failure is
   delayed: the import succeeds and a page is simply missing data. Once a
   connection exists it collapses to its summary. */
.connection-safety,
.onboarding-context {
  margin-bottom: 22px;
  color: var(--text-soft);
  background: rgb(var(--cyan-rgb) / .08);
  border-left: 3px solid var(--cyan);
  border-radius: var(--radius-sm);
}
.connection-safety { padding: 16px; margin-top: 16px; }
.onboarding-context { padding: 12px 14px; }
.connection-safety strong,
.connection-safety span,
.onboarding-context strong,
.onboarding-context span { display: block; }
.connection-safety span,
.onboarding-context span { margin-top: 2px; color: var(--text-muted); font-size: 0.84rem; }
.connection-safety-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 0;
}
.connection-safety-grid > div {
  min-width: 0;
  padding: 16px;
  background: rgb(var(--cyan-rgb) / .06);
  border: 1px solid rgb(var(--cyan-rgb) / .14);
  border-radius: var(--radius-sm);
}
.connection-safety-grid strong { color: var(--text-soft); font-size: .82rem; }
.connection-safety-grid span { font-size: .8rem; line-height: 1.5; }
/* Per-row Replace token / Disconnect disclosures in the connection table. */
.connection-row-action { margin-top: 8px; }
.connection-row-action summary { cursor: pointer; font-size: 0.86rem; color: var(--text-soft); }
.connection-row-action[data-required] summary { color: var(--amber); font-weight: 700; }
.connection-row-action[open] { padding: 8px 0; }
.connection-row-action .field-form { margin-top: 8px; }
.connection-row-action .hint { margin: 6px 0; }
.import-attention a { margin-left: 4px; font-weight: 600; }
/* ---------- labelled field forms ----------
   A form of labelled fields, each on its own line with its help text under it
   and the submit in a full-width toolbar at the foot. Onboarding, Settings and
   the Flex connection form all use it, so the same question is asked the same
   way wherever it is met. `-grid` puts the fields two across on a wide screen.

   It replaced .onboarding-form and the near-identical .connection-form, which
   had drifted apart while Settings rendered the same fields through
   .form-card/.settings-form-grid -- three layouts for one job. */
.field-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
}
.field-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 20px; }
.field-form label { margin: 0; color: var(--text-soft); font-size: 0.88rem; }
.field-form input:not([type="checkbox"]):not([type="radio"]),
.field-form select { display: block; width: 100%; min-height: 42px; margin-top: 5px; }
.field-form label small { display: block; margin-top: 5px; color: var(--text-muted); line-height: 1.4; }
/* The action spans the columns rather than sitting in the next field's cell. */
.field-form > .action-toolbar { grid-column: 1 / -1; }
.onboarding-footer {
  grid-column: 1 / -1;
  align-items: center;
  justify-content: space-between;
  margin: 8px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.onboarding-passkey-actions { margin-top: 0; }
.onboarding-passkey-actions form { margin: 0; }
.onboarding-table-form .onboarding-footer { margin-top: 20px; }
.connection-journey {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 0 0 22px;
  padding: 0;
  list-style: none;
}
.connection-journey li {
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.connection-journey li.current { border-color: rgb(var(--cyan-rgb) / .48); background: rgb(var(--cyan-rgb) / .08); }
.connection-journey button {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  height: 100%;
  padding: 13px;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  background: transparent;
  border: 0;
}
.connection-journey button:focus-visible { border-radius: var(--radius-sm); outline: none; box-shadow: var(--focus); }
.connection-step-number {
  display: grid;
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
  color: var(--cyan);
  font-size: 0.78rem;
  font-weight: 750;
  border: 1px solid rgb(var(--cyan-rgb) / .4);
  border-radius: 50%;
  place-items: center;
}
.connection-journey strong,
.connection-journey button > span:last-child,
.connection-journey small { display: block; }
.connection-journey strong { color: var(--text); font-size: 0.86rem; }
.connection-journey small { margin-top: 4px; color: var(--text-muted); font-size: 0.76rem; line-height: 1.4; }
.connection-step-panels {
  display: grid;
  margin-bottom: 6px;
  border-top: 1px solid var(--line);
}
.connection-step-panel {
  grid-area: 1 / 1;
  min-width: 0;
  padding: 22px 2px 12px;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}
.connection-step-panel.active { visibility: visible; opacity: 1; pointer-events: auto; }
.connection-step-panel > p { max-width: none; margin: 9px 0 0; color: var(--text-muted); font-size: 0.86rem; line-height: 1.6; }
.connection-step-panel > p strong { color: var(--text-soft); }
/* Lets connection_fields.html group two fields for JS relocation (mobile
   only, connection-setup.js) without the wrapper becoming a grid item of the
   desktop two-column .field-form-grid it started in. */
.connection-fields-embed { display: contents; }
.setup-guide {
  margin-bottom: 18px;
  padding: 14px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.setup-guide > summary {
  color: var(--text);
  font-size: 0.9rem;
  cursor: pointer;
}
.setup-guide > summary small { color: var(--text-muted); font-weight: 400; }
.setup-subhead {
  margin: 16px 0 0;
  color: var(--text-soft);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.setup-section-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px 24px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}
.setup-section-grid li { display: flex; align-items: flex-start; gap: 8px; color: var(--text-soft); font-size: 0.82rem; }
.setup-section-grid li > span { color: var(--green); font-weight: 750; }
.setup-section-grid strong,
.setup-section-grid small { display: block; }
.setup-section-grid small { margin-top: 2px; color: var(--text-muted); }
.setup-options { margin: 10px 0 0; }
.setup-options div { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.setup-options div:last-child { border-bottom: 0; }
.setup-options dt { color: var(--text-muted); font-size: 0.78rem; }
.setup-options dd { margin: 0; color: var(--text-soft); font-size: 0.78rem; font-weight: 650; text-align: right; }
.setup-steps { margin: 9px 0 0; padding-left: 20px; color: var(--text-muted); font-size: 0.86rem; line-height: 1.6; }
.setup-steps li { margin-top: 10px; }
.setup-steps li:first-child { margin-top: 0; }
.setup-steps strong { color: var(--text-soft); }
/* Layout comes from .field-form; this only spaces it off the step above. */
.connection-form { margin-top: 6px; }
.connection-submit { grid-column: 1 / -1; }
.token-expiry-selects {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, .8fr) minmax(0, 1fr);
  gap: 6px;
  margin-top: 5px;
}
.token-expiry-selects select {
  width: 100%;
  min-width: 0;
  min-height: 42px;
  margin-top: 0;
  /* Three narrow columns for short values (a month name, a day, a year) --
     the 32px clearance the generic select rule reserves for a long option
     elsewhere is too much room to give up here, and was clipping the day. */
  padding-right: 12px;
}
.connection-submit {
  align-items: center;
  justify-content: space-between;
  margin: 8px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.connection-validation {
  margin-top: 22px;
  padding: 20px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.connection-validation-head { display: flex; align-items: flex-start; gap: 14px; }
.connection-validation-head h3 { margin: 0; color: var(--text); font-size: 1rem; }
.connection-validation-head p { margin: 6px 0 0; color: var(--text-muted); line-height: 1.55; }
.connection-validation-icon {
  display: grid;
  flex: 0 0 34px;
  width: 34px;
  height: 34px;
  color: var(--cyan);
  font-weight: 800;
  border: 1px solid rgb(var(--cyan-rgb) / .42);
  border-radius: 50%;
  place-items: center;
}
.connection-validation.verified .connection-validation-icon { color: var(--green); border-color: rgb(var(--green-rgb) / .45); }
.connection-validation.failed .connection-validation-icon { color: var(--red); border-color: rgb(var(--red-rgb) / .45); }
.connection-validation.waiting .connection-validation-icon { color: var(--amber); border-color: rgb(var(--amber-rgb) / .45); }
.connection-validation.checking { border-bottom-color: rgb(var(--cyan-rgb) / .35); }
.connection-validation-spinner {
  width: 15px;
  height: 15px;
  border: 2px solid rgb(var(--cyan-rgb) / .25);
  border-top-color: var(--cyan);
  border-radius: 50%;
  animation: connection-spin .8s linear infinite;
}
.connection-verification-progress {
  height: 3px;
  margin-top: 20px;
  overflow: hidden;
  background: rgb(var(--cyan-rgb) / .12);
  border-radius: var(--radius-pill);
}
.connection-verification-progress span {
  display: block;
  width: 38%;
  height: 100%;
  background: var(--cyan);
  border-radius: inherit;
  animation: connection-progress 1.35s ease-in-out infinite;
}
@keyframes connection-spin { 99% { transform: rotate(360deg); } }
@keyframes connection-progress {
  from { transform: translateX(-110%); }
  100% { transform: translateX(290%); }
}
.connection-checks {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}
.connection-checks li { display: flex; align-items: center; gap: 8px; color: var(--text-muted); font-size: 0.82rem; }
.connection-checks li > span { display: grid; width: 22px; height: 22px; border: 1px solid var(--line-strong); border-radius: 50%; place-items: center; }
.connection-checks li.done { color: var(--green); }
.connection-checks li.active { color: var(--cyan); }
.connection-checks li.pending { color: var(--text-faint); }
.connection-checks li.failed { color: var(--red); }
.connection-step-footer { min-height: 61px; }
.token-expiry-field { min-width: 0; }
.connection-validation-actions { margin-top: 20px; }
.connection-validation-next { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-left: auto; }
.connection-validation-next form { margin: 0; }
@media (max-width: 760px) {
  .connection-journey { grid-template-columns: repeat(2, 1fr); }
  .field-form-grid { grid-template-columns: 1fr; }
  .setup-section-grid { grid-template-columns: 1fr; }
  .connection-checks { grid-template-columns: 1fr; }
  /* Onboarding only, same scope as below: the current step's card takes most
     of the row, at 70/15/15, the other two shrink to just their number
     circle, so the tab list takes less of the screen once fields live inside
     each step. Three fixed layouts rather than flex sizing to content, since
     min-content for the shrunk cards is what was wrapping their number. */
  .connection-journey:has(~ #connection-form) {
    display: grid;
    grid-template-columns: 70fr 15fr 15fr;
    gap: 8px;
  }
  .connection-journey:has(~ #connection-form):has(li:nth-child(2).current) {
    grid-template-columns: 15fr 70fr 15fr;
  }
  .connection-journey:has(~ #connection-form):has(li:nth-child(3).current) {
    grid-template-columns: 15fr 15fr 70fr;
  }
  .connection-journey:has(~ #connection-form) li { min-width: 0; }
  .connection-journey:has(~ #connection-form) button { padding: 10px 8px; }
  .connection-journey:has(~ #connection-form) li:not(.current) button {
    justify-content: center;
    padding: 8px 2px;
  }
  .connection-journey:has(~ #connection-form) li:not(.current) .connection-step-number {
    flex: 0 0 auto;
  }
  .connection-journey:has(~ #connection-form) li:not(.current) button > span:last-child { display: none; }
  /* Onboarding only (the step form immediately follows; Settings' guide sits
     inside a <details> instead, so this never matches there): trade the
     desktop stacked-grid, which reserves the tallest panel's height under
     every step, for plain show/hide, so a short step's fields sit right
     under it instead of behind empty space. connection-setup.js relocates
     the fields into these same panels only under this breakpoint. */
  .connection-step-panels:has(+ #connection-form) {
    display: block;
  }
  .connection-step-panels:has(+ #connection-form) .connection-step-panel {
    grid-area: auto;
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    display: none;
  }
  .connection-step-panels:has(+ #connection-form) .connection-step-panel.active {
    display: block;
    padding: 14px 2px 4px;
  }
  /* Once relocated, these labels are no longer inside .field-form, which
     normally gives them this same block layout -- restate it here. */
  .connection-step-panel .connection-fields-embed {
    display: block;
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid var(--line);
  }
  .connection-step-panel .connection-fields-embed label {
    display: block;
    margin: 0 0 18px;
    color: var(--text-soft);
    font-size: 0.88rem;
  }
  .connection-step-panel .connection-fields-embed label:last-child { margin-bottom: 0; }
  .connection-step-panel .connection-fields-embed input:not([type="checkbox"]):not([type="radio"]),
  .connection-step-panel .connection-fields-embed select {
    display: block;
    width: 100%;
    min-height: 42px;
    margin-top: 5px;
  }
  .connection-step-panel .connection-fields-embed label small {
    display: block;
    margin-top: 5px;
    color: var(--text-muted);
    line-height: 1.4;
  }
}
@media (max-width: 380px) {
  /* At this width even the current step's 70% column is too narrow for its
     title and description on one line each; the description only repeats
     what the panel body says next, so drop it here and shrink the title
     rather than let either wrap. */
  .connection-journey:has(~ #connection-form) li.current button > span:last-child small {
    display: none;
  }
  .connection-journey:has(~ #connection-form) button { gap: 6px; }
  .connection-journey:has(~ #connection-form) li.current strong { font-size: 0.76rem; }
}
@media (max-width: 480px) {
  .connection-safety-grid { grid-template-columns: 1fr; }
  .connection-journey { grid-template-columns: 1fr; }
}

/* ---------- passkeys ---------- */
.passkey-button { width: 100%; margin-bottom: 4px; }
.login-code-form { display: grid; gap: 14px; }
.login-code-form .btn-primary { justify-self: center; }
.login-new-note { text-align: center; }
/* A rule across the page with the word centred in it. Separates "use a
   passkey" from "email me a code" without either looking secondary. */
.auth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 16px 0;
  color: var(--text-muted);
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}
.passkey-list { display: grid; gap: 8px; margin-top: 12px; }
.passkey-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface-well);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.passkey-row strong { color: var(--text); font-size: 0.88rem; }
.passkey-row small { color: var(--text-muted); font-size: 0.76rem; }
.passkey-row form { margin-left: auto; }

/* ---------- the demo ribbon ----------
   Above the sticky header and in normal flow, so it is the first thing on the
   page and does not eat vertical space on a phone for the rest of the session.
   Its colours are the .alert.info pair from the shared sheet; only the layout
   is here, the same division the operator status page follows. */
.demo-ribbon {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 16px;
  padding: 6px 16px;
  color: var(--blue-bright);
  background: rgb(var(--blue-rgb) / .11);
  border-bottom: 1px solid rgb(var(--blue-rgb) / .36);
  font-size: 0.8rem;
  text-align: center;
}
.demo-ribbon strong { color: var(--text); }
.demo-ribbon-form { margin: 0; }
/* The call to action is a button, not a link: it is the one thing a demo
   visitor is meant to press. Sized down from the shared .btn-primary so the
   ribbon stays one line of chrome rather than a band. */
.demo-ribbon-cta {
  min-height: 28px;
  padding: 4px 12px;
  color: var(--text-on-accent);
  font-size: 0.78rem;
  text-decoration: none;
}
.demo-ribbon-cta:hover { color: var(--text-on-accent); }

/* The signed-out header lays itself out with margin-left:auto on the sign-in
   link (shared sheet). With a demo link in front of it, that link is the one
   doing the pushing and sign-in only needs the gap. */
.header-demo {
  margin-left: auto;
  font-size: 0.84rem;
  text-decoration: none;
  color: var(--cyan-bright);
  background: transparent;
  border-color: var(--cyan);
}
.header-demo:hover { background: rgb(var(--cyan-rgb) / .1); border-color: var(--cyan-bright); }
.header-demo + .header-signin { margin-left: 12px; }

/* ---------- allocation targets ----------

   The shared .card-rows treatment gives any cell holding an input the full
   card width, because most settings inputs are too wide to halve. Allocation
   is the exception: a percentage and a short select fit side by side, and
   stacking them made every row three tall blocks. Two rows per holding --
   ticker and name, then both inputs -- as the owner asked. */

.allocation-name-cell strong + small { margin-left: 8px; color: var(--text-muted); }

@media (max-width: 640px) {
  #allocation-targets .card-rows tr {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px 12px;
    padding: 10px 12px;
  }
  /* Ticker and name on one line, the name truncated rather than wrapping: a
     fund's full name is longer than any phone is wide, and wrapping it was
     most of the card's height. */
  #allocation-targets .card-rows tr > .allocation-name-cell {
    display: flex;
    align-items: baseline;
    min-width: 0;
    padding-bottom: 6px;
  }
  #allocation-targets .allocation-name-cell small {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  #allocation-targets .card-rows tr > *:not(:first-child):has(input:not([type=hidden]), select) {
    grid-column: auto;
  }
  /* Same height as well as same width: the number input and the select are the
     two halves of one line, and left to their intrinsic heights they differ
     enough to stop reading as a pair. */
  #allocation-targets .allocation-target-input .compact-number,
  #allocation-targets .compact-group {
    width: 100%;
    min-width: 0;
    height: 36px;
    box-sizing: border-box;
  }
}

/* ---------- household accounts ----------

   Two lines per card, as the owner asked: the account number with Hide on the
   right of the same header line, then both inputs side by side underneath.
   That needs two departures from the shared .card-rows treatment -- the header
   cell stops spanning the card so Hide can sit beside it, and an input cell
   stops taking the full width so the two fields share the line. */

@media (max-width: 640px) {
  /* The shared full-width rule repeated verbatim but for the .account-rows
     class, so it matches at equal specificity and wins on load order. A
     shorter :has() here loses: specificity inside :has() comes from its most
     specific argument, and the shared one carries three :not()s. */
  .account-rows tr > *:not(:first-child):has(input:not([type=hidden]):not([type=checkbox]):not([type=radio]), select) {
    grid-column: auto;
  }
  /* Explicit placement rather than source order: the cells are Account,
     Display name, Monthly contribution, Hide, and Hide has to land on the
     first line without moving in the DOM, where it belongs to the desktop
     table's last column. */
  .account-rows tr > *:first-child { grid-area: 1 / 1; }
  /* Both bottom-aligned, because the contribution label wraps to two lines on
     a narrow phone and the name label does not: aligned on the labels, the
     two inputs would sit at different heights. */
  .account-rows td[data-label="Display name"] { grid-area: 2 / 1; justify-content: end; }
  .account-rows td[data-label^="Monthly contribution"] { grid-area: 2 / 2; justify-content: end; }
  /* Label and checkbox on one line, right-aligned, carrying the same rule
     under it as the account number so the header reads as one line. The
     shared input sizing stretches a bare checkbox to 34px tall and 13px wide,
     which is what made this corner of the card look broken. */
  .account-rows td[data-label="Hide"] {
    grid-area: 1 / 2;
    flex-direction: row;
    gap: 8px;
    align-items: center;
    justify-content: end;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
  }
  .account-rows td[data-label="Hide"] input[type="checkbox"] {
    width: 18px;
    min-width: 0;
    height: 18px;
    min-height: 0;
    margin: 0;
    accent-color: var(--cyan);
  }
}

/* ---------- the plan entitlement list ----------

   Label left, standing right, one line each, wrapping to two on a narrow
   phone. Replaces a three-column table whose middle column was mostly em
   dashes; see the note in settings.html. */

.plan-list { display: flex; flex-direction: column; gap: 0; margin: 0; }
.plan-list > div {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
}
.plan-list > div:last-child { border-bottom: 0; }
.plan-list dt { color: var(--text-soft); }
.plan-list dd { margin: 0; color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---------- recent imports ----------

   A compact log rather than a full reconciliation table. Diagnostics take a
   second line only when an import has something useful to report. */

.import-list { display: grid; margin-top: 12px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.import-list > .hint:only-child { padding: 12px; }
.import-log-row { display: grid; grid-template-columns: 140px minmax(100px, 220px) 72px auto; align-items: center; justify-content: start; gap: 10px; padding: 9px 11px; }
.import-log-row + .import-log-row { border-top: 1px solid var(--line); }
.import-log-row time { color: var(--text); font-size: .78rem; font-variant-numeric: tabular-nums; }
.import-log-row strong { overflow: hidden; color: var(--text-soft); font-size: .78rem; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.import-log-row > span:not(.badge) { color: var(--text-muted); font-size: .7rem; text-transform: capitalize; }
.import-log-row .badge { justify-self: start; }
.import-log-row small { grid-column: 2 / -1; color: var(--text-muted); font-size: .7rem; overflow-wrap: anywhere; }

@media (max-width: 760px) {
  .import-log-row { grid-template-columns: minmax(0, 1fr) auto; gap: 5px 10px; }
  .import-log-row strong { grid-column: 1; grid-row: 2; }
  .import-log-row > span:not(.badge) { grid-column: 2; grid-row: 2; text-align: right; }
  .import-log-row .badge { grid-column: 2; grid-row: 1; }
  .import-log-row small { grid-column: 1 / -1; }
}

/* ---------- next contribution ----------

   A result, not a form: the amount input sits inline in each account's header
   line and everything below it is read-only. Grouped by account because the
   calculation is per account -- money in one broker account cannot buy a
   holding in another, and a flat list would imply it could.

   One dense line per bucket -- ticker, bar, projected/target, amount -- so the
   panel stays short between the history chart and holdings. Every configured
   bucket is listed, not only the funded ones: an overweight bar sitting past
   its target tick is the reason that bucket receives nothing. */

.dashboard-contribution .hint { margin-bottom: 10px; }

.contribution-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  font-size: .78rem;
}

.contribution-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.contribution-key::before {
  content: "";
  width: 12px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--slate);
}

.contribution-key-now::before { background: var(--blue); }

.contribution-key-add::before { background: var(--green); }

.contribution-key-target::before {
  width: 3px;
  height: 10px;
  border-radius: 1px;
  background: var(--text-soft);
}

.contribution-account + .contribution-account { margin-top: 16px; }

.contribution-account-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 16px;
}

.contribution-account-name { font-weight: 600; }

/* A lone account has no name line for Reset to sit beside, so the room is kept
   whether or not Reset shows; it then clears the legend without moving it. */
.contribution-account-head:has(> .contribution-account-name:empty) { padding-top: 14px; }

.contribution-amount-group {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
}

.contribution-reset {
  border: 0;
  padding: 0;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: .78rem;
  text-decoration: underline;
  cursor: pointer;
}

.contribution-reset:hover { color: var(--text); }

.contribution-amount {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  color: var(--text-muted);
  font-size: .82rem;
}

.contribution-amount .compact-number { width: 96px; min-width: 96px; padding: 3px 8px; }
/* The stepper buttons beside the field are the arrows; the native spinner
   would draw a second pair inside it. */
.contribution-amount .compact-number { -moz-appearance: textfield; appearance: textfield; }
.contribution-amount .compact-number::-webkit-outer-spin-button,
.contribution-amount .compact-number::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.contribution-stepper { position: relative; display: inline-flex; gap: 4px; align-self: stretch; }

/* Out of flow above the arrows: in the line it took width from the input, and
   the whole line shifted the moment an amount was edited. */
.contribution-stepper .contribution-reset {
  position: absolute;
  right: 0;
  bottom: 100%;
  margin-bottom: 2px;
  line-height: 1.2;
  white-space: nowrap;
}

.contribution-step {
  min-width: 32px;
  padding: 0 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-well);
  color: var(--text-muted);
  font: inherit;
  font-size: .7rem;
  cursor: pointer;
}

.contribution-step:hover { color: var(--text); }

.contribution-rows {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}

.contribution-row {
  display: grid;
  grid-template-columns: minmax(56px, auto) minmax(60px, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 3px 0;
  font-size: .86rem;
  line-height: 1.35;
}

/* An unfunded bucket stays legible but recedes: the eye should land on the
   lines that actually receive money. */
.contribution-row:not(.is-funded) { color: var(--text-muted); }

.contribution-ticker {
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.contribution-value {
  min-width: 68px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.contribution-row.is-funded .contribution-value { color: var(--green); font-weight: 600; }

.contribution-track {
  position: relative;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-well);
}

.contribution-now,
.contribution-add,
.contribution-target { position: absolute; top: 0; bottom: 0; }

.contribution-now {
  left: 0;
  border-radius: var(--radius-pill);
  background: var(--blue);
}

.contribution-add {
  border-radius: var(--radius-pill);
  background: var(--green);
}

.contribution-target {
  width: 3px;
  top: -3px;
  bottom: -3px;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--text-soft);
}

.contribution-meta {
  color: var(--text-muted);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.contribution-target-label { color: var(--text-faint); }

/* Held to one line at any width: it sits under rows that move as an amount
   is typed, and a wrapping line would move them again. */
.contribution-summary {
  margin: 4px 0 0;
  overflow: hidden;
  color: var(--text-muted);
  font-size: .82rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.contribution-note {
  margin: 4px 0 0;
  color: var(--text-muted);
  font-size: .82rem;
}

@media (max-width: 640px) {
  /* Name above, amount on its own full-width line: at 390px the parts of the
     header line do not fit beside each other and the input was pushed off the
     right edge. */
  .contribution-account-head { flex-direction: column; align-items: stretch; }
  .contribution-amount-group { justify-content: flex-start; width: 100%; }
  /* The input gives up width before the label wraps: at 320px the fixed
     96px box pushed "Contribution (€)" onto two lines. */
  .contribution-amount { flex: 1 1 auto; min-width: 0; white-space: nowrap; }
  .contribution-amount .compact-number { width: 100%; min-width: 64px; }
  /* The projected/target pair is the first thing to go: the bar and the amount
     carry the answer on their own. */
  .contribution-meta { display: none; }
}

@media (min-width: 981px) {
  /* Two columns on desktop: a bucket line is short and the panel is full-width,
     so one column left two thirds of the row empty. Grid, not CSS columns, so
     the bars in both columns share one width. */
  .contribution-rows {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 36px;
  }
}
