/* Macro dashboard — dark, typographic, AlphaHunterz.
   Surfaces, type and spacing are deliberately identical to the strategy dashboard so the two
   read as siblings. The SERIES palette differs: this page carries far more categorical data,
   and the sector colours used there fail the colour-vision gates at this density
   (Health Care vs Industrials measured at normal-vision dE 6.2 against a floor of 15).
   See docs/design_system.md. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
  --bg: #0b0e14;
  --panel: #141922;
  /* The CARD surfaces are translucent so the brand mark behind the page stays visible through
     them. Only cards: a dropdown menu or a table cell that lets the page through is harder to
     read, not more atmospheric. Measured against the wash below — at panel 1.0 the mark shows
     only in the gutters between cards, which is what made the portfolio look sealed off. */
  --panel-t: rgba(20, 25, 34, .66);
  --panel2-t: rgba(27, 34, 48, .62);
  --panel2: #1b2230;
  --border: #242c3a;
  --text: #e6edf6;
  --muted: #8494ad;
  --accent: #4db6e8;
  --green: #3ecf8e;
  --red: #f2615c;
  --amber: #f2c94c;
}

html, body, #root { background: var(--bg) !important; }
body {
  color: var(--text);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}
/* margin-inline:auto is load-bearing. Without it `.wrap` capped the width but pinned the
   content to the LEFT edge — the Macro page only looked centred because it is a
   dbc.Container, which Bootstrap centres for it, while the Stocks and Portfolio pages
   are plain divs and were not. */
.wrap { max-width: 1320px; margin-inline: auto; padding: 0 1.25rem 4rem; }
a { color: var(--accent); }

/* ---------------- hero ---------------- */
.hero {
  display: flex; gap: 2rem; align-items: center; justify-content: space-between;
  flex-wrap: wrap; max-width: 1320px; margin: 0 auto; padding: 2.5rem 1.25rem 1.5rem;
}
.hero-left { flex: 1 1 520px; }
.hero-mark { height: 62px; width: auto; display: block; margin-bottom: 1rem; }
.hero-h {
  font-size: clamp(1.9rem, 4.2vw, 2.9rem); font-weight: 700; letter-spacing: -0.02em;
  margin: 0 0 .5rem; line-height: 1.08;
}
.hero-sub { color: var(--muted); font-size: 1.02rem; margin: 0 0 1rem; max-width: 62ch; }
.pill-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.pill {
  font-size: .72rem; letter-spacing: .04em; text-transform: uppercase;
  padding: .28rem .6rem; border-radius: 999px;
  border: 1px solid var(--border); color: var(--muted); background: var(--panel2-t);
}
.pill-live { color: var(--green); border-color: rgba(62,207,142,.35); }
.pill-live::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--green); margin-right: .4rem; vertical-align: middle;
}

/* ---------------- KPI ---------------- */
.kpi-row { display: grid; gap: .9rem; grid-template-columns: repeat(5, minmax(0, 1fr)); }
@media (max-width: 1100px) { .kpi-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .65rem; }
  .kpi-row > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.kpi {
  background: var(--panel-t); border: 1px solid var(--border); border-radius: 12px;
  padding: 1rem 1.1rem; height: 100%;
}
.kpi-l { color: var(--muted); font-size: .74rem; text-transform: uppercase; letter-spacing: .06em; }
.kpi-v { font-size: 1.65rem; font-weight: 650; margin-top: .25rem; letter-spacing: -.02em;
         font-variant-numeric: tabular-nums; }
.kpi-v.pos { color: var(--green); }
.kpi-v.neg { color: var(--red); }
.kpi-s { color: var(--muted); font-size: .78rem; margin-top: .15rem; line-height: 1.35; }

/* ---------------- sections ---------------- */
.sec { margin-top: 3.25rem; }
.sec-h {
  font-size: 1.45rem; font-weight: 650; letter-spacing: -.015em; margin-bottom: .4rem;
  padding-bottom: .6rem; border-bottom: 1px solid var(--border);
}
.sec-sub { color: var(--muted); font-size: .92rem; max-width: 84ch; margin: .75rem 0 1.25rem;
           line-height: 1.6; }
.body-p { color: #c7d3e3; line-height: 1.68; margin-bottom: .9rem; max-width: 84ch; }

/* the provenance strip under every chart: universe, weighting, coverage, history start */
.prov {
  color: var(--muted); font-size: .72rem; margin-top: .45rem; line-height: 1.5;
  border-left: 2px solid var(--border); padding-left: .6rem;
}
.prov b { color: #a9b6cb; font-weight: 500; }

/* ---------------- panels ---------------- */
.panel {
  background: var(--panel-t); border: 1px solid var(--border); border-radius: 14px;
  padding: 1.1rem 1.2rem 1rem; height: 100%;
}
.panel-h { font-size: 1.02rem; font-weight: 620; margin-bottom: .15rem; }
.panel-s { color: var(--muted); font-size: .84rem; margin-bottom: .7rem; line-height: 1.5; }
.grid2 { display: grid; gap: 1.1rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid3 { display: grid; gap: 1.1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* minmax(0, 1fr), NOT 1fr. A bare `1fr` track carries an implicit min-content floor, so the
   560px-wide chart inside .gscroll pushes the track open instead of scrolling inside it:
   measured on a 390px phone, every panel rendered 601px wide and the page scrolled sideways
   by 318px, clipping titles mid-word and pushing the heatmap and modal off screen. The whole
   scroll-inside-the-panel design below never got a chance to run. */
@media (max-width: 980px) { .grid2, .grid3 { grid-template-columns: minmax(0, 1fr); } }

/* ---------------- stat grid ---------------- */
.sg { display: grid; gap: .55rem; }
.sg-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.sg-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.sg-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
@media (max-width: 820px) { .sg-3, .sg-4 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
.sg-item { background: var(--panel2-t); border: 1px solid var(--border); border-radius: 9px;
           padding: .6rem .7rem; }
.sg-k { color: var(--muted); font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; }
.sg-v { font-size: 1.02rem; font-variant-numeric: tabular-nums; margin-top: .15rem; }
.sg-v.pos { color: var(--green); }
.sg-v.neg { color: var(--red); }

/* ---------------- notes ---------------- */
.note-t { color: var(--accent); font-size: .74rem; text-transform: uppercase;
          letter-spacing: .06em; margin-bottom: .3rem; }
.callout {
  background: var(--panel-t); border: 1px solid var(--border);
  border-left: 3px solid var(--accent); border-radius: 10px; padding: 1.1rem 1.3rem;
  color: #c7d3e3; line-height: 1.65;
}
.callout.warn { border-left-color: var(--amber); }

/* thin-sample badge — the honest marker on a bucket below 30 effective members */
.badge-thin {
  display: inline-block; font-size: .66rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--amber); border: 1px solid rgba(242,201,76,.35); border-radius: 999px;
  padding: .1rem .45rem; margin-left: .4rem; vertical-align: middle;
}

/* ---------------- controls ---------------- */
.ctl-row { display: flex; gap: 1.4rem; flex-wrap: wrap; align-items: center;
           margin-bottom: .9rem; }
.ctl-lab { color: var(--muted); font-size: .72rem; text-transform: uppercase;
           letter-spacing: .05em; margin-right: .5rem; }
.ctl .form-check-label, .ctl label { color: var(--muted) !important; font-size: .85rem; }
.ctl .form-check-input:checked { background-color: var(--accent); border-color: var(--accent); }

/* ---------------- scroll-instead-of-squeeze ---------------- */
.gscroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.gscroll::-webkit-scrollbar { height: 6px; }
.gscroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
/* On a phone held upright, forcing EVERY chart to 560px meant every one of them had to be
   scrolled sideways to be read — fine on a wide screen, tiring in the hand. A time series
   compresses to 360px perfectly well; what genuinely cannot is the correlation heatmap (11
   labelled rows and columns) and the wide tables. So only those keep the scroll. */
@media (max-width: 700px) {
  .gscroll { border-right: 1px solid var(--border); }
  .gscroll > div { min-width: 0; width: 100%; }
  /* The exceptions: squeezing these makes them unreadable rather than merely small. */
  #corr-heat, .gscroll .dash-table-container,
  .gscroll table { min-width: 560px; }
  /* Tighter frame so the plot area itself keeps as much of the width as possible. */
  .panel { padding: .8rem .7rem; }
  .panel-h { font-size: .95rem; }
  .panel-s { font-size: .8rem; }
}

/* ---------------- entry gate ---------------- */
/* The modal repaints every dbc modal on the page; there is only one, deliberately. */
.smodal .modal-content, .modal-content {
  background: var(--panel) !important; border: 1px solid var(--border) !important;
  color: var(--text); border-radius: 14px;
}
.consent-head { border-bottom: 1px solid var(--border) !important; }
.consent-head .modal-title { font-size: 1.15rem; font-weight: 650; letter-spacing: -.01em; }
.consent-body { max-height: 68vh; overflow-y: auto; }
.consent-p { color: #c7d3e3; line-height: 1.6; font-size: .95rem; margin-bottom: .4rem; }
.consent-hr { border-color: var(--border); opacity: 1; margin: 1rem 0; }
.consent-lead { font-weight: 600; font-size: .95rem; margin-bottom: .5rem; }
.consent-list { padding-left: 1.15rem; margin-bottom: .9rem; }
.consent-li { color: #c7d3e3; line-height: 1.55; font-size: .89rem; margin-bottom: .55rem; }
.consent-li::marker { color: var(--accent); font-weight: 600; }
.consent-fine { color: var(--muted); font-size: .76rem; }
.consent-foot { border-top: 1px solid var(--border) !important; }
.agree-btn {
  background: var(--accent) !important; border-color: var(--accent) !important;
  color: #06121b !important; font-weight: 600;
}
.agree-btn:hover { filter: brightness(1.08); }
.decline-btn { color: var(--muted) !important; text-decoration: none; }
.decline-btn:hover { color: var(--text) !important; }
.declined { max-width: 620px; margin: 6rem auto; padding: 0 1.25rem; text-align: center; }
.decl-h { font-size: 1.5rem; font-weight: 650; margin-bottom: .5rem; }
.decl-p { color: var(--muted); }
@media (max-width: 576px) {
  .consent-body { max-height: 74vh; }
  .consent-foot { flex-direction: column-reverse; }
  .consent-foot .btn { width: 100%; }
}

/* ---------------- footer ---------------- */
.foot { background: #080b10; border-top: 1px solid var(--border);
        margin-top: 4rem; padding: 2rem 1.25rem; }
.foot-in { max-width: 1320px; margin: 0 auto; }
.foot-legal { color: var(--muted); font-size: .78rem; line-height: 1.6; max-width: 100ch; }
.foot-legal strong { color: var(--amber); }
.foot-meta { color: var(--muted); font-size: .74rem; margin-top: .8rem;
             font-variant-numeric: tabular-nums; }

@media (max-width: 576px) {
  .hero { padding: 1.75rem 1rem 1rem; }
  .hero-mark { height: 48px; }
  .kpi-v { font-size: 1.35rem; }
  .sec { margin-top: 2.25rem; }
  .sec-h { font-size: 1.2rem; }
}

/* ---------------- cohort comparison ---------------- */
/* The two halves of the market read as a comparison, so the value columns are equal width
   and tabular — the eye should be able to run down them without re-anchoring. */
.coh-table td, .coh-table th { border-color: var(--border) !important; }
.coh-table th { color: var(--muted); font-size: .72rem; text-transform: uppercase;
                letter-spacing: .05em; font-weight: 500; }
.coh-table td:first-child { color: var(--muted); font-size: .86rem; width: 42%; }
.coh-table td:nth-child(2), .coh-table td:nth-child(3) {
  font-variant-numeric: tabular-nums; text-align: right; width: 24%; font-size: .95rem;
}
.coh-table td.pos { color: var(--green); }
.coh-table td.neg { color: var(--red); }
/* Bootstrap paints EVERY cell with --bs-table-bg, which is opaque, so the rows came out as
   solid black bands on a page where every other rectangle lets the mark behind it through.
   Setting the variables is not enough on its own — .table-hover writes a background on the
   cell itself — so the cells are cleared too and the stripe and hover are re-added as
   translucent tints. */
/* Written for EVERY .table on the page, not for the two that exist today. This had to be
   fixed twice — once for the cohort table, then again for the sector one — because the first
   rule named a class instead of the condition. A third dbc.Table would have been a third
   black slab. */
.panel .table, .coh-table, .sect-table {
  --bs-table-bg: transparent; --bs-table-accent-bg: transparent;
  --bs-table-hover-bg: transparent; --bs-table-striped-bg: transparent;
  --bs-table-color: var(--text); border-color: var(--border);
}
.panel .table > :not(caption) > * > *,
.coh-table > :not(caption) > * > *,
.sect-table > :not(caption) > * > * {
  background-color: transparent; color: var(--text); border-color: var(--border);
  box-shadow: none;
}
.panel .table tbody tr:nth-child(even) > *,
.coh-table tbody tr:nth-child(even) > *,
.sect-table tbody tr:nth-child(even) > * { background-color: rgba(255, 255, 255, .022); }
.panel .table tbody tr:hover > *,
.coh-table tbody tr:hover > *,
.sect-table tbody tr:hover > * { background-color: rgba(77, 182, 232, .06); }
.panel .table thead th, .coh-table thead th, .sect-table thead th {
  color: var(--muted); font-weight: 600;
}
.coh-table tbody tr:first-child td { font-weight: 600; color: var(--text); }

/* ---------------------------------------------------------------------------
   Explorer controls. Filters sit in ONE row directly above the chart they act
   on, so the relationship is positional rather than remembered.
   --------------------------------------------------------------------------- */
.ctlbar { display: flex; gap: 1.25rem; align-items: flex-end; flex-wrap: wrap;
          margin: 0 0 .9rem; }
.ctl { display: flex; flex-direction: column; gap: .35rem; }
.ctl-grow { flex: 1 1 320px; min-width: 260px; }
.ctl-l { color: var(--muted); font-size: .72rem; text-transform: uppercase;
         letter-spacing: .05em; font-weight: 500; }

/* Dash 4.4's Dropdown is NOT react-select — it renders its own `.dash-dropdown-*` tree and
   ships a white control. The legacy `.Select-*` selectors every example uses match nothing
   here; these class names were read off the rendered DOM. Verified: the control, the search
   box and the option list all default to a white background with our light text on top,
   i.e. invisible, so each surface is set explicitly rather than inherited. */
.ctl-dd.dash-dropdown, .ctl-dd .dash-dropdown-content,
.ctl-dd .dash-dropdown-grid-container, .ctl-dd .dash-dropdown-search-container,
.ctl-dd .dash-dropdown-focus-target {
  background: var(--panel2) !important; color: var(--text) !important;
  border-color: var(--border) !important; border-radius: 8px;
}
.ctl-dd .dash-dropdown-value, .ctl-dd .dash-dropdown-value-item,
.ctl-dd .dash-dropdown-search, .ctl-dd .dash-dropdown-trigger-icon,
.ctl-dd .dash-dropdown-search-icon { color: var(--text) !important; }
/* The menu panel is a SIBLING of the trigger inside .dash-dropdown-wrapper, not a child of
   the element carrying .ctl-dd — which is why a descendant selector on .ctl-dd silently
   matches nothing. Scoped to the wrapper, verified against the rendered tree. */
.dash-dropdown-wrapper .dash-dropdown-options,
.dash-dropdown-wrapper .dash-dropdown-search-container,
.dash-dropdown-wrapper .dash-dropdown-content {
  background: var(--panel2) !important; border-color: var(--border) !important;
  border-radius: 8px; color: var(--text) !important;
}
.dash-dropdown-wrapper .dash-dropdown-search { background: var(--panel) !important; color: var(--text) !important;
  border: 1px solid var(--border) !important; border-radius: 6px; }
.dash-dropdown-wrapper .dash-dropdown-search::placeholder { color: var(--muted) !important; }
.dash-dropdown-wrapper .dash-dropdown-option { color: var(--text) !important; padding: .45rem .7rem;
  border-color: var(--border) !important; }
.dash-dropdown-wrapper .dash-dropdown-option:hover { background: var(--panel) !important; }
/* Group headings are disabled options: recessive, not clickable, and clearly not a choice. */
.dash-dropdown-wrapper .dash-dropdown-option[aria-disabled="true"],
.dash-dropdown-wrapper .dash-dropdown-option.disabled {
  color: var(--muted) !important; font-size: .72rem; text-transform: uppercase;
  letter-spacing: .05em; cursor: default; pointer-events: none; padding-top: .7rem;
  background: transparent !important;
}
/* The default focus ring is a browser-blue box; keep focus visible but on-palette. */
.ctl-dd:focus-within { outline: none; border-color: var(--accent) !important;
  box-shadow: 0 0 0 2px rgba(77, 182, 232, .25); }

/* Radio hit targets are deliberately larger than the dot: the whole label is clickable. */
.ctl-radio { display: flex; gap: .25rem; flex-wrap: wrap; }
.ctl-radio label { display: inline-flex; align-items: center; gap: .4rem;
                   padding: .42rem .7rem; border: 1px solid var(--border);
                   border-radius: 999px; color: var(--muted); font-size: .82rem;
                   cursor: pointer; background: var(--panel2); }
.ctl-radio label:hover { color: var(--text); border-color: var(--accent); }
.ctl-radio input { accent-color: var(--accent); margin: 0; }

/* Same pill as the radios — it sits in the same bar and does the same kind of job, so it
   should not look like a different class of control. Checked state is filled rather than
   outlined: which universe you are in changes the answer, so it has to be legible at a
   glance rather than by squinting at a tickbox. */
.ctl-check { display: flex; gap: .25rem; flex-wrap: wrap; }
.ctl-check label { display: inline-flex; align-items: center; gap: .4rem;
                   padding: .42rem .7rem; border: 1px solid var(--border);
                   border-radius: 999px; color: var(--muted); font-size: .82rem;
                   cursor: pointer; background: var(--panel2); white-space: nowrap; }
.ctl-check label:hover { color: var(--text); border-color: var(--accent); }
.ctl-check label:has(input:checked) { color: var(--text); border-color: var(--accent);
                   background: rgba(77, 182, 232, .14); }
.ctl-check input { accent-color: var(--accent); margin: 0; }

@media (max-width: 640px) {
  .ctlbar { gap: .75rem; }
  .ctl-grow { flex: 1 1 100%; }
}

/* The menu floats over a chart, so it needs its own opaque surface and a shadow — without
   one the plot lines read straight through the option labels. */
.dash-dropdown-wrapper .dash-dropdown-content {
  box-shadow: 0 14px 40px rgba(0, 0, 0, .55); border: 1px solid var(--border);
  overflow: hidden;
}
/* 55 metrics in ten groups, so the list must be tall enough that scrolling reads as "there
   is more" rather than as a truncated menu.
   Dash builds this on Radix Popover, which writes `max-height: min(200px, 100vh - 100px)`
   and `overflow: hidden` as an INLINE style on .dash-dropdown-content. An inline declaration
   outranks any stylesheet rule of normal weight, so the 200px cap silently clipped a 420px
   list — !important is load-bearing here, not decoration. */
.dash-dropdown-wrapper .dash-dropdown-content {
  max-height: min(58vh, 460px) !important; overflow: hidden !important;
}
.dash-dropdown-wrapper .dash-dropdown-options,
.dash-dropdown-wrapper .dash-options-list {
  max-height: min(50vh, 400px) !important; overflow-y: auto !important;
}

/* Affordance for the correlation heatmap: the cells are clickable, which nothing about a
   heatmap otherwise suggests. */
.hint { color: var(--muted); font-size: .78rem; margin-top: .5rem; font-style: italic; }
#corr-heat .nsewdrag { cursor: pointer !important; }

/* The drill-down modal inherits Bootstrap's light surface otherwise. */
#corr-modal .modal-content { background: var(--panel); border: 1px solid var(--border);
                             color: var(--text); border-radius: 12px; }
#corr-modal .modal-header, #corr-modal .modal-footer { border-color: var(--border); }
#corr-modal .modal-title { color: var(--text); font-size: 1.05rem; font-weight: 600; }
#corr-modal .btn-close { filter: invert(1) grayscale(1) brightness(1.6); opacity: .7; }

/* The heatmap hint and its escape hatch share a row: the click affordance and the
   "just show me the overall history" option belong together. */
.hintrow { display: flex; align-items: baseline; gap: .75rem; flex-wrap: wrap;
           margin-top: .5rem; }
.hintrow .hint { margin-top: 0; }
.linkbtn { color: var(--accent) !important; text-decoration: none !important;
           padding: 0 !important; font-size: .8rem; border: 0; }
.linkbtn:hover { text-decoration: underline !important; }

/* Numeric table cells: right-aligned and tabular, so a reader can run down a column. The
   cohort table already does this; the sector table was left-aligned and ragged. */
.sect-table td:not(:first-child), .sect-table th:not(:first-child) {
  text-align: right; font-variant-numeric: tabular-nums;
}
.sect-table th { color: var(--muted); font-size: .7rem; text-transform: uppercase;
                 letter-spacing: .04em; font-weight: 500; }
.sect-table td, .sect-table th { padding: .3rem .45rem !important; font-size: .84rem; }
.sect-table td:first-child { color: var(--text); }

/* ---------------------------------------------------------------------------
   Brand backdrop, entry blur, and the loading state
   --------------------------------------------------------------------------- */

/* The oversized mark, blurred, behind everything. Fixed rather than absolute so it does not
   travel with the scroll, and pointer-events:none so it can never intercept a click on a
   chart sitting above it. Deliberately very low contrast — it is a wash, not a watermark to
   be read. */
.brandwash {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.brandwash img {
  /* EXPLICIT height, not max-width. The source file is 256x236px, so with `width: auto` it
     rendered at its natural 256px and the max-width cap never bound — which is why raising
     that cap from 150vw to 300vw changed nothing at all, twice. A max-* rule can only ever
     shrink an image; making one bigger needs a real dimension.
     `max(512px, 60vh)` is at least double the old 256px on any screen and keeps scaling on
     tall ones. Blur goes up with it: the mark is being enlarged about 4x from source, and at
     2px the upscaling artefacts were starting to show through. */
  width: auto; height: max(512px, 60vh);
  max-width: none; max-height: none; object-fit: contain;
  /* .075 was invisible through a card even at 40% panel alpha — its contribution came to
     about .03. At .20 behind a .66 card the mark reads clearly and still does not compete
     with the text on top of it. */
  opacity: .20; filter: blur(3px) grayscale(1) brightness(2.4);
}
/* Everything real sits above the wash. NOTE: only z-index — Bootstrap's backdrop must keep
   its own `position: fixed`, and forcing it to `relative` made it cover only part of the
   viewport, leaving a hard horizontal seam across the middle of the entry screen. */
.wrap, .container, #page, #keep-host { position: relative; z-index: 1; }

/* The gate frosts whatever is behind it — on arrival that is the brand wash, and on a later
   drill-down it is the page. Applied to the shared backdrop so both modals behave alike. */
.modal-backdrop.show {
  backdrop-filter: blur(7px) saturate(.8);
  -webkit-backdrop-filter: blur(7px) saturate(.8);
  background: rgba(4, 6, 10, .72); opacity: 1 !important;
}

/* The mark in the gate's own header, beside the title. */
.consent-mark { height: 26px; width: auto; margin-right: .6rem; vertical-align: -6px; }

/* ---- loading ------------------------------------------------------------- */
/* Shown while the page is being BUILT server-side after acceptance. Without it the reader
   clicks "enter" and watches an empty screen, which reads as a freeze rather than as work. */
/* Centred on the VIEWPORT, not on a block at the top of the document.
   `min-height: 62vh` centred it inside a box that began where #page begins, so on
   anything but a short screen the mark and spinner sat high — nearer the top third
   than the middle, which is where the eye goes when a page is thinking. Fixed
   positioning with inset:0 makes "the middle" mean the middle of the screen at any
   height, and it no longer moves if the reader has scrolled.
   The scrim is translucent rather than solid so the blurred backdrop mark stays
   visible behind it — that continuity is the point of having it at the page root. */
.loading {
  /* Starts BELOW the nav bar and sits under it, so the menu stays visible and clickable
     while a page is loading. At inset:0 and z-index 2500 the spinner covered the whole
     screen including the nav — which during a slow load reads as "the menu disappeared",
     and left the reader with no way out except waiting. */
  position: fixed; inset: 52px 0 0 0; z-index: 800;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1.4rem;
  background: rgba(11, 14, 20, .72);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.load-mark { width: 168px; max-width: 46vw; opacity: .92; }
.load-t { color: var(--muted); font-size: .86rem; letter-spacing: .02em; }
/* The "generating your report" overlay reuses the loading mark + spinner, but covers the whole
   viewport (nav included) because a report is a deliberate, blocking action the reader started. */
.pdf-overlay {
  position: fixed; inset: 0; z-index: 4000;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1.4rem;
  background: rgba(11, 14, 20, .82);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
/* A single blurred line sweeping around the circle's centre — a diameter that rotates, bright
   at the middle and fading to nothing at both ends, softened with a blur so it reads as a glow
   sweeping past rather than a hard bar. (The old page-load cue, brought back.) */
.spinner {
  width: 48px; height: 48px; position: relative;
}
.spinner::before {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 48px; height: 5px; border-radius: 5px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(77, 182, 232, .12) 22%, var(--accent) 50%,
    rgba(77, 182, 232, .12) 78%, transparent 100%);
  filter: blur(1.8px);
  transform-origin: center;
  animation: spin 1.3s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Respect a reader who has asked for less motion: keep the cue as a still, faint line. */
@media (prefers-reduced-motion: reduce) {
  .spinner::before { animation: none; opacity: .7; }
}

/* Dash's own overlay tint would grey the mark out; we supply the whole visual instead. */
#keep-host .dash-loading, #keep-host [data-dash-is-loading],
#page-loading .dash-loading, #page-loading [data-dash-is-loading] { background: transparent; }

/* The conditional view leads with a sentence, not a chart: the number is the finding and the
   box plot is the evidence for it. */
.cd-headline { font-size: 1.02rem; line-height: 1.55; margin-bottom: .9rem; color: var(--text); }
.cd-headline b { color: var(--accent); font-variant-numeric: tabular-nums; }

/* Plotly draws its margins in pixels, so a 56px left margin that is 10% of a desktop chart is
   15% of a phone one. These trim the frame; the plot itself is resized by Plotly's own
   responsive handling. */
@media (max-width: 700px) {
  .js-plotly-plot .modebar { transform: scale(.85); transform-origin: top right; }
  .ctlbar { gap: .6rem; }
  .sec-h { font-size: 1.15rem; }
  .sec-sub { font-size: .86rem; }
}

/* ---------------------------------------------------------------------------
   Axis dragging, removed. Page scrolling, restored.

   Plotly puts invisible drag handles around every chart: one over the plot area
   (.nsewdrag) and one along each axis and corner. The axis ones rescale THAT axis
   when dragged, which is a feature nobody on this page asked for and which two
   readers hit by accident — a swipe that starts anywhere near the left margin
   silently stretches the y-axis, and on a phone the same swipe is how you scroll,
   so the page stays put and the chart distorts instead.

   Disabling pointer events on the axis handles alone is the surgical fix: box zoom
   inside the plot still works, the reset button still undoes it, and the axes stop
   being draggable at all. Doing this in CSS rather than with `fixedrange` is
   deliberate — `fixedrange` would also kill the zoom the reset button exists for.
   --------------------------------------------------------------------------- */
.js-plotly-plot .draglayer .nsdrag,
.js-plotly-plot .draglayer .ewdrag,
.js-plotly-plot .draglayer .nwdrag,
.js-plotly-plot .draglayer .nedrag,
.js-plotly-plot .draglayer .swdrag,
.js-plotly-plot .draglayer .sedrag { pointer-events: none !important; }

/* Vertical swipes belong to the page, horizontal ones to the chart. `pan-y` hands
   the browser every up/down gesture before Plotly can claim it, so scrolling over a
   chart scrolls the page — the single worst thing about reading this on a phone. */
.js-plotly-plot .nsewdrag,
.js-plotly-plot .draglayer { touch-action: pan-y !important; }
.dash-graph, .js-plotly-plot { touch-action: pan-y; }

/* ---------------------------------------------------------------------------
   The entry button, while the page is being built.

   The click now closes the modal immediately, but the button is visible for the
   frame in between and a dead-looking button is what made people click twice. It
   goes transparent and grows a spinner in place, so the last thing the reader sees
   before the modal leaves is the click being acknowledged.
   --------------------------------------------------------------------------- */
.agree-btn:disabled {
  position: relative;
  color: transparent !important;
  opacity: 1;
  cursor: progress;
}
.agree-btn:disabled::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px; height: 16px;
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

/* ---------------------------------------------------------------------------
   Portrait on a phone: ask for the rotation instead of shrinking the charts.

   These charts are wide by nature — twenty years of weekly points, eleven sector
   series, an 11x11 matrix. They are genuinely good on a phone held sideways and
   genuinely bad squeezed into a 390px column, and the previous attempt (a fixed
   1180px viewport) traded that for a page rendered at a third scale, legible only
   by pinching every panel.

   So: the layout stays the normal responsive one, and portrait gets this overlay.
   Pure CSS — it appears and disappears with the device, with no callback, no resize
   listener and no re-render of the page underneath. `orientation: portrait` alone
   would also catch a narrow desktop window, hence the max-width bound; the
   `pointer: coarse` requirement keeps it off laptops with touchscreens.

   Screen orientation cannot be locked from a web page outside fullscreen, so asking
   is the whole mechanism available. It is stated as a reason, not an instruction.
   --------------------------------------------------------------------------- */
.rotate { display: none; }

@media (orientation: portrait) and (max-width: 900px) and (pointer: coarse) {
  .rotate {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 3000;
    align-items: center;
    justify-content: center;
    background: var(--bg, #0b0e14);
    padding: 32px 26px;
    text-align: center;
  }
  .rot-in { max-width: 34ch; }
  .rot-icon {
    font-size: 46px;
    line-height: 1;
    color: var(--accent, #4db6e8);
    margin-bottom: 18px;
    animation: rot-turn 2.6s ease-in-out infinite;
  }
  .rot-h { font-size: 20px; margin: 0 0 10px; color: var(--text, #e6edf3); }
  .rot-p { font-size: 14px; line-height: 1.6; color: var(--muted, #8b949e); margin: 0; }
  /* The page underneath must not scroll behind the overlay, or a reader who swipes
     lands somewhere unexpected when they finally do rotate. */
  body { overflow: hidden; }
}

@keyframes rot-turn {
  0%, 45%  { transform: rotate(0deg); }
  60%, 90% { transform: rotate(90deg); }
  100%     { transform: rotate(0deg); }
}

/* ---------------------------------------------------------------------------
   Top navigation and the Stock page.
   --------------------------------------------------------------------------- */
.navbar {
  /* FIXED, not sticky. Sticky still participates in layout, so the bar slid under the hero
     on short pages; fixed keeps it locked at the top of the viewport at every scroll
     position, which is what a navigation bar is for. The body carries matching top padding
     so nothing hides underneath it. */
  position: fixed; top: 0; left: 0; right: 0; z-index: 900;
  display: grid; grid-template-columns: 32px 1fr 32px; align-items: center;
  gap: 1rem; padding: .5rem 1.1rem;
  background: rgba(11, 14, 20, .88);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
.nav-mark { width: 30px; height: 30px; opacity: .92; }
/* The links sit in the centre cell, so they are centred on the PAGE rather than between
   whatever happens to be beside them. */
.nav-links { display: flex; gap: .3rem; justify-content: center; }
#root { padding-top: 52px; }
.nav-link {
  display: inline-block; padding: .42rem 1.15rem; border-radius: 7px;
  font-size: 1rem; font-weight: 500; letter-spacing: .01em;
  color: var(--muted); text-decoration: none;
  border: 1px solid transparent; transition: background .15s, color .15s;
}
.nav-link:hover { color: var(--text); background: var(--panel); }
/* The active tab is marked by BOTH colour and a border — a single colour cue on a nav is the
   one place a colour-blind reader cannot fall back on a label, because every label is present. */
.nav-link.is-active {
  color: var(--text); background: var(--panel);
  border-color: var(--border); font-weight: 600;
}

/* 1fr auto 1fr, so the MIDDLE column is centred on the card no matter how wide the company
   name or the numbers are. Under space-between the dial simply took whatever gap was left
   between them, which is why its centre never matched the card's. */
.co-head {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 1.2rem;
  align-items: start; margin: .4rem 0 1.4rem;
}
.co-head > :last-child { justify-self: end; }
.co-name { font-size: 1.5rem; margin: 0 0 .35rem; letter-spacing: -.02em; color: var(--text); }
.co-tags { display: flex; flex-wrap: wrap; gap: .45rem; align-items: center; }
.co-tick {
  font-weight: 700; font-size: .82rem; letter-spacing: .06em;
  padding: .16rem .5rem; border-radius: 5px;
  background: var(--panel2-t); color: var(--text);
}
.co-tag { font-size: .82rem; color: var(--muted); }
.co-tag-dim { color: var(--muted); opacity: .75; }
.co-kpis { display: flex; gap: 1.6rem; }
.co-kl { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.co-kv { font-size: 1.15rem; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.co-fine { color: var(--muted); font-size: .8rem; margin-top: 1.4rem; }

/* One measure per row: label, value, position within the sector, sector median. The bar is
   the point of the page — a multiple on its own is not information. */
.cmp-tbl { display: flex; flex-direction: column; gap: .1rem; }
.cmp-row {
  display: grid; grid-template-columns: minmax(0, 8.5rem) 4.2rem minmax(0, 1fr) 6.5rem;
  gap: .6rem; align-items: center; padding: .34rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, .04);
}
.cmp-l { font-size: .84rem; color: var(--muted); }
.cmp-v { font-size: .92rem; color: var(--text); font-variant-numeric: tabular-nums; text-align: right; }
.cmp-m { font-size: .76rem; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.cmp-bar { position: relative; height: 16px; }
.cmp-track {
  position: absolute; left: 0; right: 0; top: 7px; height: 2px;
  background: var(--border); border-radius: 2px;
}
.cmp-mid { position: absolute; left: 50%; top: 3px; width: 1px; height: 10px; background: var(--muted); opacity: .55; }
.cmp-dot {
  position: absolute; top: 3px; width: 10px; height: 10px; margin-left: -5px;
  border-radius: 50%; background: var(--accent);
  /* A 2px ring in the surface colour so the marker stays readable when it lands on the tick */
  box-shadow: 0 0 0 2px var(--panel);
}
@media (max-width: 700px) {
  .cmp-row { grid-template-columns: minmax(0, 1fr) 3.6rem; }
  .cmp-bar, .cmp-m { display: none; }
  .co-kpis { gap: 1rem; }
  .co-head { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .co-head > :last-child { justify-self: center; }
  .co-title, .co-tags { justify-content: center; }
}

/* The quality score is the one number on the company page a reader will look for first. */
.co-kq { font-size: 1.6rem; line-height: 1.1; color: var(--accent); }
.co-ks { font-size: .7rem; color: var(--muted); margin-top: .1rem; }

/* ---------------------------------------------------------------------------
   The company table, the weight bar, and the portfolio view.
   --------------------------------------------------------------------------- */
/* The Stocks page needs the width; the reading pages do not. `.wrap` caps the text column,
   so the table page opts out and the table centres itself in whatever is available. Without
   this the last column (Weight) fell off the right edge on a laptop. */
.wrap-wide { max-width: none !important; width: 100%; padding-inline: 1.2rem; }
.tblwrap { margin-top: .5rem; margin-inline: auto; max-width: 1760px; }
/* Let the table use its space rather than squeezing 13 columns into a fixed box. */
.tblwrap .dash-spreadsheet, .tblwrap .dash-spreadsheet-container,
.tblwrap .dash-spreadsheet-inner { width: 100% !important; max-width: 100% !important; }
.tblwrap .dash-spreadsheet-inner table { width: 100% !important; }
/* Row hover was Dash's default: a white fill with white text on it, i.e. an invisible row.
   A faint grey lift keeps every value readable and still marks the row under the cursor. */
.tblwrap .dash-spreadsheet-inner tr:hover td,
.tblwrap .dash-spreadsheet-inner tr:hover td.dash-cell {
  background-color: #1c2330 !important;
  color: var(--text) !important;
}
.tblwrap .dash-spreadsheet-inner tr:hover td.dash-cell input { color: var(--text) !important; }
.tblwrap .dash-table-container { font-variant-numeric: tabular-nums; }
/* Dash paints its own filter row and pagination in light theme defaults. */
.tblwrap input, .tblwrap .dash-filter input {
  background: var(--panel) !important; color: var(--text) !important;
  border: 1px solid var(--border) !important; border-radius: 5px !important;
  padding: 2px 6px !important;
}
.tblwrap .previous-next-container, .tblwrap .page-number, .tblwrap .current-page,
.tblwrap .last-page, .tblwrap .first-page { color: var(--muted) !important; }
.tblwrap .dash-spreadsheet-container .dash-spreadsheet-inner td.focused {
  outline: 2px solid var(--accent) !important;
}
.tblwrap .dash-cell-value { color: inherit; }

/* Sits directly beneath the fixed nav bar (52px), not under where it used to be.
   An earlier duplicate of this rule set top:52px above and was silently beaten by
   this one — same specificity, later wins. Fixed at the definition instead. */
.wbar { position: sticky; top: 52px; z-index: 500; }
.wbar-in {
  display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap;
  padding: .5rem .8rem; margin: .8rem 0 .2rem;
  background: var(--panel); border: 1px solid var(--border); border-radius: 9px;
}
.wb-i { display: flex; align-items: baseline; gap: .4rem; }
.wb-l { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.wb-v { font-size: 1rem; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.wb-warn { font-size: .78rem; color: var(--warn, #e0a458); }
.wb-right { margin-left: auto; }
.wb-clear { color: var(--muted) !important; text-decoration: none !important; }
.wb-go {
  font-size: .84rem; font-weight: 600; color: var(--accent); text-decoration: none;
  padding: .3rem .7rem; border: 1px solid var(--border); border-radius: 7px;
}
.wb-go:hover { background: var(--panel2); }
.kbd {
  font: 600 .8rem/1 Inter, system-ui, sans-serif; padding: .12rem .38rem;
  border: 1px solid var(--border); border-radius: 4px; background: var(--panel2);
  color: var(--text);
}
.inline-link { color: var(--accent); text-decoration: none; font-weight: 600; }

.empty { max-width: 62ch; margin: 1.4rem auto 0; text-align: left; }
.empty-h { font-size: 1.15rem; color: var(--text); margin: 0 0 .6rem; }
.empty-p { color: var(--muted); font-size: .92rem; line-height: 1.65; }
.empty-fine { font-size: .82rem; opacity: .85; }

.pf-kpis { margin: .2rem 0 1.2rem; flex-wrap: wrap; gap: 1.5rem; }
.pf-tbl { display: flex; flex-direction: column; }
.pf-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: .42rem 0; border-bottom: 1px solid rgba(255, 255, 255, .04);
}
.pf-l { font-size: .86rem; color: var(--muted); }
.pf-v { font-size: .98rem; color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }
.co-modal-body { max-height: 76vh; }

/* The secondary line under a hero paragraph: context, not headline. */
.hero-note { font-size: .88rem; color: var(--muted); max-width: 78ch; }

/* ---------------------------------------------------------------------------
   Portfolio readability.

   The donut, the price line and the correlation grid were each squeezed into half
   a column, which is why they were hard to read: a 620px double ring in a 400px box
   is a smudge. The donut now takes the full width, and the remaining charts get a
   taller frame so their labels have somewhere to go.
   --------------------------------------------------------------------------- */
.pf-charts .js-plotly-plot { min-height: 380px; }
.pf-tall { height: 0; }
@media (min-width: 1100px) {
  /* Below this the grid already collapses to one column, so the override is only
     needed where two columns would otherwise be forced. */
  .pf-charts { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
}
.pf-tbl { font-size: .95rem; }
.pf-row { padding: .52rem 0; }

/* The combined-fundamentals rows now span the panel, so cap the reading width and centre
   them rather than stretching eleven label/value pairs across 1,300px. */
.pf-tbl-wide { max-width: 760px; margin-inline: auto; }

/* ---------------------------------------------------------------------------
   Company logos and the Quality Meter dial.
   --------------------------------------------------------------------------- */
.co-logo {
  object-fit: contain; border-radius: 6px; flex: 0 0 auto;
}
.co-title { display: flex; align-items: center; gap: .7rem; }
/* The table's logo column: a fixed narrow cell so it does not resize between pages. */
.tblwrap td.dash-cell.column-0, .tblwrap th.column-0 { width: 42px; max-width: 42px; padding: 2px 4px !important; }
.tblwrap td.dash-cell.column-0 img { width: 26px; height: 26px; object-fit: contain;
  border-radius: 4px; display: block; }
.tblwrap .dash-cell-value.cell-markdown p { margin: 0; }

.co-gaugewrap {
  /* The label and the caption centre on the SAME axis as the dial. Left-aligned text above a
     centred dial reads as a misalignment even when the dial itself is placed correctly. */
  min-width: 250px; text-align: center; justify-self: center;
}
.co-gauge { margin: -4px 0 -2px; }
.co-gauge .js-plotly-plot { height: 165px !important; }
.pf-gauge { max-width: 520px; margin-inline: auto; }

/* The conditional view's episode warning. Same weight as the headline it qualifies, because
   a result resting on one market episode is not a smaller finding — it is a different kind
   of statement, and a reader who misses that misreads the number entirely. */
.cd-warn {
  margin-top: .55rem; padding: .55rem .7rem; border-radius: 8px;
  background: rgba(224, 168, 74, .10); border-left: 3px solid #e0a84a;
  color: var(--text); font-size: .93rem; line-height: 1.45;
}

/* A company record carries TWO marks, in two regions.

   The COMPANY's sits behind the header, where it identifies whose record is open. The BRAND's
   sits behind the chart and every figure under it — the part that gets screenshotted and
   passed around — so the numbers never travel without their source attached.

   Both are absolute rather than fixed: they belong to the card and must scroll with it. */
.co-head, .co-body { position: relative; }
.co-wash, .co-brandwash {
  position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  display: flex; justify-content: center;
}
.co-wash { align-items: center; }
.co-wash img {
  /* Bounded by the header, so it scales to that band rather than to the viewport. */
  width: auto; height: 150%; max-height: none;
  opacity: .11; filter: blur(2.5px) grayscale(1) brightness(1.9);
}
.co-brandwash { align-items: flex-start; }
.co-brandwash img {
  /* Half the page wash's `max(512px, 60vh)`. At page scale inside a modal it reads as a
     background; at half it reads as a signature, which is what it is here. */
  width: auto; height: max(256px, 30vh); max-width: none; max-height: none;
  margin-top: 4vh; opacity: .17; filter: blur(3px) grayscale(1) brightness(2.4);
}
/* Everything in the record sits above whichever wash is behind it.

   :not(.co-wash) is load-bearing. A blanket `.co-head > *` gave the wash `position: relative`
   too, which cancelled its `absolute`, put it back in flow, and made it a FOURTH item in a
   three-column grid — the name slid into the middle column, the dial into the right, and the
   figures wrapped onto a second row. */
.co-head > :not(.co-wash), .co-fine, .grid2, .grid3, .panel {
  position: relative; z-index: 1;
}

/* ============================================================================
   Trading Systems — the password-gated strategy record (systems.py)
   Same tokens as everything above; the section is a sibling of the macro views,
   not a different site. What is new here is the lock screen and the sub-menu.
   ========================================================================== */

/* ---------------- the lock ---------------- */
/* min-height, not height: on a short laptop window the request block below the fold
   was unreachable because the flex centring pinned the card to the viewport. */
.lock { min-height: 78vh; display: flex; align-items: center; justify-content: center;
        padding: 3rem 1.25rem 4rem; }
.lock-in-wrap {
  max-width: 46rem; width: 100%;
  background: var(--panel-t); border: 1px solid var(--border); border-radius: 16px;
  padding: 2.2rem 2rem 1.9rem;
}
.lock-mark { height: 46px; width: auto; display: block; margin-bottom: 1.1rem; opacity: .95; }
.lock-h { font-size: clamp(1.6rem, 3.4vw, 2.1rem); font-weight: 700;
          letter-spacing: -.02em; margin: 0 0 .8rem; }
.lock-p { color: #c7d3e3; line-height: 1.68; margin-bottom: .9rem; max-width: 68ch; }
.lock-row { display: flex; gap: .6rem; margin-top: 1.2rem; flex-wrap: wrap; }
/* Translucent like every other surface on the site, so the mark behind the page shows
   through this card rather than stopping at it. Solid panels are what made the section
   read as bolted on instead of part of the same page. */
.lock-in {
  flex: 1 1 16rem; min-width: 0;
  background: var(--panel2-t); border: 1px solid var(--border); border-radius: 9px;
  color: var(--text); padding: .6rem .8rem; font-size: .95rem;
}
.lock-in:focus { outline: none; border-color: var(--accent);
                 box-shadow: 0 0 0 2px rgba(77,182,232,.18); }
.lock-go { flex: 0 0 auto; }
/* Reserved height, so the card does not jump the first time a wrong password is typed. */
.lock-err { color: var(--red); font-size: .84rem; margin-top: .6rem; min-height: 1.2em; }
.lock-hr { border-color: var(--border); margin: 1.6rem 0 1.2rem; opacity: 1; }
.lock-ask { color: var(--muted); font-size: .88rem; line-height: 1.6; max-width: 68ch; }
.lock-req {
  display: inline-block; margin-top: .5rem; text-decoration: none;
  border: 1px solid var(--accent); color: var(--accent);
  border-radius: 9px; padding: .5rem .9rem; font-size: .9rem;
}
.lock-req:hover { background: rgba(77,182,232,.1); color: var(--accent); }
.lock-alt { color: var(--muted); font-size: .82rem; margin-top: .7rem; }
/* Selectable, and monospaced so a hand-copied address is checkable character by
   character. This is the path that works when the browser has no mail handler. */
.lock-mail { color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
             user-select: all; }

/* ---------------- the sub-menu ---------------- */
.sys-tabs { display: flex; gap: .4rem; flex-wrap: wrap; margin: 1.6rem 0 2rem;
            border-bottom: 1px solid var(--border); padding-bottom: .7rem; }
.sys-tab {
  background: transparent; border: 1px solid transparent; border-radius: 9px;
  color: var(--muted); font-size: .92rem; font-weight: 500;
  padding: .45rem .85rem; cursor: pointer;
}
.sys-tab:hover { color: var(--text); background: var(--panel-t); }
.sys-tab.is-active { color: var(--text); background: var(--panel2-t);
                     border-color: var(--border); }

/* ---------------- one system ---------------- */
.sys-head { display: flex; align-items: baseline; gap: .75rem; flex-wrap: wrap; }
.sys-h { margin-bottom: .2rem; }
.sys-note { color: var(--muted); font-size: .88rem; margin: -.4rem 0 1.2rem; max-width: 84ch; }
.sys-desc { margin: 1.4rem 0 1.8rem; }
.sys-body > .panel { margin-bottom: 1.4rem; }
.sys-body .panel .dash-graph { margin-top: .4rem; }
.sys-warn {
  color: var(--amber); background: rgba(242,201,76,.07);
  border: 1px solid rgba(242,201,76,.28); border-radius: 10px;
  padding: .6rem .85rem; font-size: .86rem; margin: 1rem 0 0;
}
.sys-fine { color: var(--muted); font-size: .78rem; line-height: 1.6;
            margin-top: .8rem; max-width: 90ch; }
/* Four tiles, not the macro page's five. Same breakpoints so the two rows step
   down together and the site keeps one rhythm. */
.kpi-row-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 1.2rem; }
@media (max-width: 1100px) { .kpi-row-4 { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 640px) { .kpi-row-4 { grid-template-columns: repeat(2, minmax(0,1fr)); } }

/* ---------------- the holdings accordion ---------------- */
/* Identical rules to strategies_dashboard/assets/custom.css: this is the same component
   showing the same book, and the two pages are meant to read as siblings. */
.hold-acc { margin-bottom: .5rem; }
.hold-acc .accordion-item { background: transparent; border: 0;
                            border-bottom: 1px solid var(--border); }
.hold-acc .accordion-button {
  background: transparent; color: var(--text); font-size: .88rem; font-weight: 550;
  padding: .7rem .2rem; box-shadow: none;
}
.hold-acc .accordion-button:not(.collapsed) { background: transparent; color: var(--accent); }
.hold-acc .accordion-button:focus { box-shadow: none; border-color: transparent; }
/* the chevron is a background image, so it is recoloured with a filter */
.hold-acc .accordion-button::after { filter: invert(62%) sepia(14%) saturate(700%)
                                             hue-rotate(175deg) brightness(95%); }
.hold-acc .accordion-body { padding: .2rem .2rem 1rem; }
.hold-detail p { color: #c7d3e3; line-height: 1.68; margin-bottom: .8rem;
                 font-size: .88rem; max-width: 82ch; }
.hold-detail strong { color: var(--text); font-weight: 600; }
/* The second stat grid needs air above it or the two read as one twelve-cell block. */
.hold-h2 { margin-top: 1.1rem; }

/* ---------------- the deep readout inside one position ---------------- */
/* A <details>, not a second accordion: this is already one level deep and nesting
   Bootstrap accordions would put a chevron inside a chevron. Native disclosure keeps
   the keyboard behaviour and costs no JavaScript. */
.deep-wrap { margin-top: 1.1rem; border-top: 1px solid var(--border); padding-top: .8rem; }
.deep-sum { color: var(--accent); font-size: .84rem; cursor: pointer; list-style: none;
            padding: .2rem 0; }
.deep-sum::-webkit-details-marker { display: none; }
.deep-sum::before { content: '▸ '; }
.deep-wrap[open] .deep-sum::before { content: '▾ '; }
.deep { padding-top: .9rem; }
.deep > * + * { margin-top: 1.2rem; }
/* Bull and bear side by side, so neither can be read without the other in view.
   Stacked on a narrow screen, and the ORDER there puts the bear case second — the
   same order it is written in, never reversed by a layout. */
.cases { display: grid; gap: 1rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 820px) { .cases { grid-template-columns: 1fr; } }
.case { border-left: 2px solid var(--border); padding-left: .8rem; }
.case-bull { border-left-color: var(--green); }
.case-bear { border-left-color: var(--red); }
.case .body-p { font-size: .86rem; margin-bottom: 0; }
.hold-ul { color: #c7d3e3; font-size: .86rem; line-height: 1.6; padding-left: 1.1rem;
           margin: 0; max-width: 90ch; }
.hold-ul li { margin-bottom: .4rem; }

/* one analyst seat */
.seats { display: grid; gap: .7rem; }
.seat { background: var(--panel2-t); border: 1px solid var(--border); border-radius: 10px;
        padding: .65rem .8rem; }
.seat-head { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.seat-n { font-weight: 600; font-size: .86rem; }
.seat-d { font-size: .7rem; letter-spacing: .06em; text-transform: uppercase;
          color: var(--muted); }
.seat-d.pos { color: var(--green); }
.seat-d.neg { color: var(--red); }
.seat-c { font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.seat-p { color: #c7d3e3; font-size: .84rem; line-height: 1.6; margin: .35rem 0 0;
          max-width: 90ch; }
.seat-r { color: var(--muted); font-size: .8rem; line-height: 1.55; margin: .35rem 0 0;
          max-width: 90ch; }

/* ---------------- the ETF book's group table ---------------- */
/* Groups only — this book publishes no fund names, so there is no row to expand into and
   no accordion. A plain table is the honest shape for that. */
.gt { width: 100%; border-collapse: collapse; font-size: .88rem; min-width: 40rem; }
.gt th { color: var(--muted); font-size: .7rem; text-transform: uppercase;
         letter-spacing: .05em; font-weight: 600; text-align: left;
         padding: .5rem .6rem; border-bottom: 1px solid var(--border); }
.gt td { padding: .5rem .6rem; border-bottom: 1px solid var(--border); }
.gt tbody tr:last-child td { border-bottom: 0; }
.gt tbody tr:hover td { background: rgba(77, 182, 232, .06); }
.gt .gt-num { text-align: right; font-variant-numeric: tabular-nums; }
.gt .gt-dim { color: var(--muted); }

/* ---------------- chart help ---------------- */
/* The ⓘ sits beside the heading, not over the plot — Plotly owns that corner with its own
   modebar, and a reader looking for help does not look inside the chart anyway. */
.helprow { display: inline-flex; gap: .3rem; margin-left: .5rem; vertical-align: middle; }
.helpb {
  width: 18px; height: 18px; line-height: 1; padding: 0;
  border-radius: 50%; border: 1px solid var(--border);
  background: var(--panel2-t); color: var(--muted);
  font-size: .72rem; font-weight: 700; font-style: italic; font-family: Georgia, serif;
  cursor: pointer; flex: 0 0 auto;
}
.helpb:hover { color: var(--accent); border-color: var(--accent); background: var(--panel); }
.helpb-vid { font-style: normal; font-size: .6rem; font-family: inherit; }
.panel-h-help, .sec-h-help { display: flex; align-items: center; gap: .1rem; }
/* The heading keeps its own bottom margin; the flex row must not eat it. */
.sec-h-help { flex-wrap: wrap; }

.help-head { border-bottom: 1px solid var(--border); }
.help-body { padding-top: 1rem; }
.help-body > div + div { margin-top: 1.1rem; }
.help-body .body-p { margin-bottom: 0; font-size: .92rem; }

/* First-chart metric selector: a colour-coded pill per market series. The colour is the
   metric's own line colour, set inline; this rule carries only shape and spacing. */
.mv-pills { display: flex; flex-wrap: wrap; gap: .4rem; margin: .2rem 0 .6rem; }
.mv-pill { padding: .4rem .85rem; border: 1.5px solid; border-radius: 999px;
           font-size: .82rem; font-weight: 600; cursor: pointer; line-height: 1;
           font-family: inherit; transition: filter .12s, background .12s; }
.mv-pill:hover { filter: brightness(1.18); }

/* Portfolio: quality-gauge + fundamentals pairing, and the AI commentary panel. */
.pf-top { align-items: stretch; }
.pf-comm-btn { margin: .1rem 0 .9rem; }
.pf-comm-p { color: var(--text); line-height: 1.62; margin: 0 0 .8rem; font-size: .95rem; }
.pf-comm-p:last-child { margin-bottom: 0; }
.pf-comm-empty { color: var(--muted); font-style: italic; }

/* Combined-fundamentals with a market-median yardstick column. */
.pf-row3 {
  display: grid; grid-template-columns: 1fr 6.5rem 8rem; gap: .6rem; align-items: baseline;
  padding: .5rem 0; border-bottom: 1px solid var(--border);
}
.pf-row3:last-child { border-bottom: none; }
.pf-row3 .pf-l { color: var(--muted); }
.pf-row3 .pf-v { text-align: right; color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.pf-row3 .pf-vm { text-align: right; color: var(--muted); font-variant-numeric: tabular-nums; }
.pf-row3 .pf-hdr { font-size: .74rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 600; }

/* Portfolio hero with the Download-PDF action on the right. */
.pf-hero { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.pf-pdf-btn { flex: 0 0 auto; white-space: nowrap; text-decoration: none; align-self: center; }

/* Rebalance selector + worst-case stress panel. */
.pf-rebal-ctl { margin: .2rem 0 .9rem; max-width: 18rem; }
.pf-stress .co-kpis { margin: .4rem 0 1rem; }

/* ---- Info (i) buttons added to the company detail modal and Portfolio page ---- */
/* Quality-meter caption inside the company modal: keep the label and its (i) on one
   centred line rather than letting the button drop below the small-caps label. */
.co-kl-help { display: inline-flex; align-items: center; justify-content: center; gap: .3rem; }
.co-kl-help .helprow { margin-left: 0; }
.co-gaugewrap .co-kl-help { width: 100%; }
/* The (i) that explains the headline KPI tiles, trailing the Portfolio sub-heading. */
.hero-p-help { display: inline; }
.hero-p-help .helprow { margin-left: .35rem; }
/* Two stacked modals: the help pop-up must sit above the company/record modal and its
   backdrop. react-bootstrap raises a stacked modal on its own, but pin it defensively so
   an (i) opened from inside the record modal is never trapped behind it. */
#help-modal { z-index: 3060; }

/* Trailing-12-month margin sub-group inside the company Profitability panel. */
.panel-s-ttm { margin-top: .7rem; padding-top: .55rem; border-top: 1px solid var(--border, #242c3a); }
