/* ============================================================
   EPRA Data (fen-api) dashboard — stylesheet

   Every selector is nested under the wrapper class .epra-fen-app using
   native CSS nesting, so this CSS can be loaded globally on a Concrete
   CMS page that already has its own site theme (Bootstrap-based) without
   the two fighting over shared selectors -- same pattern already proven
   on the sibling EPRA BPR Database and EPRA Total Markets Table packages.
   :root (custom property definitions) and @keyframes blocks are the one
   documented exception and stay unscoped at the top level: :root can't be
   nested meaningfully, and @keyframes can't be nested at all.
   ============================================================ */

    /* ---- EPRA brand palette ----
       Tokens now come from the vendored static/assets/design-system/foundations/
       colors_and_type.css (linked in the block view.php's head BEFORE this file),
       not redefined here. This block only bridges fen-api's existing
       --epra-navy/-gold/-grey/... variable names to the canonical ones, so the
       ~150 existing var(--epra-navy)/var(--epra-muted)/etc. references throughout
       this file keep working without a full rename sweep — same approach used for
       BPR's Phase 1 migration and mirrored exactly in frontend/index.html's own
       <style> block (keep both in sync).
       Real value changes, not just renames: fen-api's old navy (#0A4D8C) and gold
       (#F5B833) were TMT-aligned, not the canonical brand blue (#12497F)/orange
       (#EBA61C) — deliberately switched to canonical now rather than waiting for
       TMT's own Phase 3 migration (2026-09-08 decision).
       --epra-blue/--epra-light-blue/--epra-europe/--epra-na/--epra-apac/--epra-em
       were defined but never referenced anywhere else in this file — dropped as
       dead code. */
    :root {
      --epra-navy:       var(--epra-blue);
      --epra-navy-dark:  var(--epra-blue-dark);
      --epra-gold:       var(--epra-orange);
      --epra-grey:       var(--epra-paper-tint);
      --epra-grey-2:     var(--color-border);
      --epra-text:       var(--epra-blue);
      --epra-muted:      var(--color-fg-muted);
      --epra-pos:        var(--color-success);
      --epra-neg:        var(--color-danger);
    }

    @keyframes fadeIn { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: none; } }
div.ccm-page .section-divider {
  min-height: 100px;
}
.epra-fen-app {
    /* ---- Was a bare `* { box-sizing: border-box; }` + `body { ... }` in
       the standalone dashboard. Left unscoped, `body { background: ... }`
       would repaint the ENTIRE Concrete page's background and fight the
       site theme sitewide, since this dashboard is embedded as a fragment
       inside a real page, not the whole document. Converted to apply only
       within this wrapper instead -- same visual result for the dashboard
       itself, no leakage onto the rest of the site. ---- */
    box-sizing: border-box;
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    /* Real theme's main page background ($body-bg in the theme's own SCSS)
       is #F0F0F0 -- confirmed against the theme's compiled source,
       2026-09-10. Was a hand-picked close approximation (#EFEFF0) before;
       now the actual canonical token. Doubly worth getting right here since
       this block is embedded as a fragment on a real themed Concrete page
       (see the comment above) -- this makes it blend seamlessly instead of
       a near-miss. */
    color: var(--epra-text);
    font-size: 14px;
    /* overflow-x: hidden;          -- page can never scroll sideways.
       (Was a nested comment whose stray closing star-slash silently
       invalidated the very next rule, the box-sizing one below.) */

    & * { box-sizing: border-box; }

    /* The various "visuals now come from Bootstrap ... bootstrap-overrides.css"
       comments elsewhere in this file describe an override that was never
       actually wired up on this production page -- index-data.php's <link>
       tags only load colors_and_type.css, not bootstrap-overrides.css
       (confirmed 2026-09-17), so every select still gets the real theme's
       plain compiled Bootstrap background-color: var(--bs-body-bg), the
       page's own grey, not white. (frontend/index.html, the standalone dev
       harness, does link bootstrap-overrides.css and doesn't need this --
       the gap is production-only.) Same gap exists on TMT and BPR's
       production pages too -- fixed the same targeted way in each rather
       than wiring in the full bootstrap-overrides.css file (a bigger change
       pulling in nav-tab/button overrides this request didn't ask for). One
       rule here covers every .form-select/.form-control in the app. */
    & .form-select, & .form-control { background-color: white; }

    /* Sticky top: banner + tabs always visible while scrolling */
    /* NOTE: sticky positioning is relative to the nearest scrolling ancestor,
       not to being a direct child of <body>, so nesting under .epra-fen-app
       should not break it in principle -- but worth a visual check once this
       is actually installed on a real Concrete page, since the site theme's
       own header will sit above this content and could affect where "top: 0"
       actually lands. */
    /* z-index: only needs to clear this page's OWN content scrolling beneath
       it (plain static flow, z-index: auto) -- 100 was carried over from an
       earlier draft and turned out high enough to paint over the site
       theme's own header mega-menu once this tab bar goes sticky (confirmed
       on the live site, 2026-09-30). 2 matches the sticky <thead> elsewhere
       in this file, used for the same "just above ordinary content"
       purpose -- comfortably clear of the theme's own navigation. */
    & .topbar {
      position: sticky;
      top: 0; left: 0; right: 0;
      z-index: 2;
      /* No horizontal padding of its own -- this page now sits inside the
         real theme's container-xl (via #middle, added 2026-09-14), so the
         tab bar and main's own content already line up via that outer
         gutter. Container-conversion pass, 2026-09-15, same fix as BPR's
         <main>/TMT's .dl-wrap/.disc-wrap/.meth-wrap: main's own bespoke
         1500px max-width was dropped for the same reason -- it could never
         actually engage, container-xl is always narrower. */
    }
    /* Mobile: the six tabs wrap to two rows, and the bar has no background,
       so content scrolling underneath showed through the gaps between tabs
       while it also ate a big slice of a small screen. Plain flow instead
       below 760px. 2026-10-20. */
    @media (max-width: 760px) { & .topbar { position: static; } }
    & main { padding: 12px 0 22px; }

    /* ---- Tabs ----
       2026-09-15 restyle: each tab is now its own fully-enclosed, rounded
       "chip" instead of Bootstrap's classic notebook-tab look (one shared
       bottom border, square bottom corners merging into the panel below).
       That old look read as its own separate mini-app sitting on the page;
       this reads as a normal part of the page instead, matching the
       broader move away from the dashboard looking like a self-contained
       app. Mirrored from frontend/index.html exactly (same design there).
       Same technique as .db-kpi's own top-accent cards further down this
       file: NO real border on the sides/bottom at all -- a spread-only,
       zero-blur box-shadow (0 0 0 1px) stands in for one instead. A real
       border participates in the browser's per-side corner math, so a
       THICKER colored border-top next to THINNER plain sides visibly
       clashes right at the curve (this took three attempts to track down:
       an inset shadow, then a mismatched-radius ::before bar, both had the
       same root cause). box-shadow doesn't have that problem -- it always
       traces the element's own border-radius as a single, uniform sweep
       regardless of what real border is also present, so a border-top can
       be layered on top of it with no seam. Only the truly active tab gets
       a real border-top; padding-top is reduced by exactly its width so
       the tab's total height and the text's vertical position stay
       identical to the inactive tabs -- nothing shifts on select. */
    /* margin-top/margin-left: .epra-fen-app sets overflow-x:hidden on
       itself (stops the page scrolling sideways) -- .epra-tmt-app has no
       such property on its own wrapper at all, only on unrelated inner
       components. An ancestor's overflow clips anything a descendant's
       box-shadow bleeds past its own edge (the "fake border" trick here
       spreads 1px beyond the tab's own box), so without this buffer the
       first tab's outline gets clipped flush against .epra-fen-app's own
       left/top edge -- confirmed by testing in devtools; TMT never hits
       this since it has no matching overflow to clip against. */
    & .nav-tabs { border-bottom: none; gap: 8px; margin: 4px 0 0 2px; }
    & .nav-tabs .nav-link {
      margin-bottom: 0;
      border: none;
      border-radius: 10px;
      padding: 9px 18px;
      background: white;
      color: var(--epra-muted);
      /* .epra-fen-app sets a page-wide font-size:14px (own convention,
         untouched -- not part of this pass), but .epra-tmt-app never sets
         its own font-size at all, so its tabs inherit the real theme's
         actual body font-size (16px, confirmed against the theme's
         compiled SCSS -- stock Bootstrap default, never customized).
         Pinned explicitly here so this one shared component renders
         pixel-identically in both apps regardless of each app's own
         broader (and different) font-size convention elsewhere. */
      font-size: 16px;
      font-weight: 600;
      box-shadow: 0 0 0 1px var(--epra-grey-2), 0 1px 2px rgba(10,77,140,0.06);
      transition: transform .15s ease, box-shadow .15s ease, color .15s ease;
    }
    /* The outline stays neutral grey on hover -- only the truly active tab
       gets the blue outline + top accent. Coloring it blue on hover too
       (an earlier version did this) made a merely-hovered tab look
       basically indistinguishable from the actually-active one. */
    & .nav-tabs .nav-link:hover:not(.active) {
      color: var(--epra-navy);
      transform: translateY(-1px);
      box-shadow: 0 0 0 1px var(--epra-grey-2), 0 3px 8px rgba(10,77,140,0.14);
    }
    & .nav-tabs .nav-link.active {
      color: var(--epra-navy);
      border-top: 4px solid var(--epra-navy);
      padding-top: 5px;
      box-shadow: 0 0 0 1px var(--epra-grey-2), 0 2px 6px rgba(10,77,140,0.12);
    }

    /* ---- Panels ---- */
    & .panel {
      background: white; border: 1px solid var(--epra-grey-2);
      border-radius: 6px; padding: 16px; margin-bottom: 14px;
      box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    }
    & .panel h2 {
      margin: 0 0 14px; font-size: 12px; font-weight: 700;
      color: var(--epra-navy); text-transform: uppercase; letter-spacing: 0.08em;
    }

    /* ---- Controls ---- */
    & .controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; align-items: end; }
    & .field { display: flex; flex-direction: column; gap: 5px; }
    & .field label { font-size: 11px; color: var(--epra-navy); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; }
    /* .form-select visuals now come from Bootstrap (background/arrow/
       border-radius fixed at the shared bootstrap-overrides.css level,
       2026-09-10) -- select-standardization pass. .field input (date/text
       fields, not part of this pass) keeps its own bespoke styling. */
    & .field input {
      padding: 6px 10px; border: 1px solid var(--epra-grey-2); border-radius: 5px;
      background: white; font-size: 13px; font-family: inherit; color: var(--epra-navy);
      font-weight: 500; cursor: text;
    }
    & .field input:focus {
      outline: 2px solid var(--epra-navy); outline-offset: 0;
      border-color: var(--epra-navy);
    }

    /* button.primary / button.secondary visuals now come from Bootstrap
       (btn-primary / btn-outline-primary) -- 2026-09-10 button-standardization
       pass, same as BPR and frontend/index.html. Old bespoke uppercase/
       letter-spacing treatment dropped in favour of Bootstrap's standard
       button typography. */

    /* Horizon quick-pick buttons (and the D/M/Q/Y frequency strip below
       them). Was a fused .btn-group -- with 9-10 buttons needing to wrap
       across two rows in a narrow sidebar, the fused/connected-segment
       look (shared borders, square corners at the wrap seam) read broken
       rather than deliberate. Same fix as .region-pills below: dropped
       .btn-group, switched to individually-rounded pill buttons with a
       gap and their own active state -- wrapping to a second row now
       just looks like a second row of pills, not a seam. 2026-09-25.
       margin-top bumped for more breathing room below the date fields. */
    & .horizons { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 16px; }

    & .actions { margin-top: 14px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
    & .status { color: var(--epra-muted); font-size: 13px; }
    & .status.error { color: var(--epra-neg); font-weight: 600; }

    /* ---- Charts ---- */
    & .chart-wrap { position: relative; height: 460px; }

    /* ---- Tables (unified, lean style across the dashboard) ---- */
    & table {
      width: 100%;
      border-collapse: collapse;
      font-size: 13px;
    }
    & th, & td {
      padding: 8px 14px;
      white-space: nowrap;
      border: 0;
    }
    /* Default: first column left, others right-aligned */
    & th, & td { text-align: right; }
    & th:first-child, & td:first-child { text-align: left; }
    /* Header band — navy, spans every column including the first */
    & thead th {
      background: var(--epra-navy);
      color: white;
      font-weight: 600;
      text-transform: uppercase;
      font-size: 11px;
      letter-spacing: 0.04em;
    }
    /* Sub-header band — for the dates row under the horizons */
    & thead th.subhead {
      background: var(--epra-grey);
      color: var(--epra-muted);
      font-weight: 500;
      font-size: 11px;
      text-transform: none;
      letter-spacing: 0;
    }
    /* Body rows */
    & tbody td {
      color: var(--epra-text);
      border-bottom: 1px solid var(--epra-grey-2);
    }
    & tbody tr:last-child td { border-bottom: 0; }
    /* Light zebra striping for the data-heavy tables (Performance, Time series,
       Constituents) to make wide rows easier to follow. */
    & #an-ret-table tbody tr:nth-child(even) td,
    & #an-vol-table tbody tr:nth-child(even) td,
    & #ts-table    tbody tr:nth-child(even) td,
    & #cn-table    tbody tr:nth-child(even) td { background: #f4f7fb; }
    & tbody tr:hover td { background: rgba(10, 77, 140, 0.08) !important; }

    /* Returns & risk: numeric cells centred, first column left */
    & table.an-table th, & table.an-table td { text-align: center; }
    & table.an-table th:first-child, & table.an-table td:first-child { text-align: left; }
    /* Two-row header bands: navy + grey sit flush, no white seam */
    & table.an-table thead tr:first-child th { border-bottom: 0; padding-bottom: 8px; }
    & table.an-table thead tr:nth-child(2) th { border-top: 0; padding-top: 6px; }

    /* Compact (single-horizon) variant — tighter padding for the side-by-side layout */
    & table.an-table.compact th, & table.an-table.compact td { padding: 6px 10px; font-size: 12px; }

    /* R&R page: settings | full returns + volatility tables. */
    & .an-page {
      display: grid;
      grid-template-columns: 300px minmax(0, 1fr);
      gap: 16px;
      align-items: stretch;
      justify-content: center;
    }
    & .an-note { font-size: 11px; color: var(--epra-muted); margin-top: 12px; line-height: 1.5; }
    & .an-pa-note { font-size: 11px; font-weight: 400; color: var(--epra-muted); text-transform: none; letter-spacing: 0; }
    & .an-page > .panel { margin-bottom: 0; }
    & .an-controls { grid-template-columns: 1fr; }
    & .an-col-settings {
      position: sticky;
      top: 152px;
      align-self: start;
      z-index: 1;
      background: white;
    }
    & .an-col-table { display: flex; flex-direction: column; min-width: 0; }
    & .an-col-table .scroll { max-height: none; min-height: 0; }
    /* Both tables side by side so returns + volatility are always visible together */
    & .an-tables {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 16px;
      align-items: start;
    }
    & .an-tables > .panel { margin-bottom: 0; min-width: 0; }
    @media (max-width: 1150px) { & .an-tables { grid-template-columns: 1fr; } }
    /* Denser cells so all 9 horizons fit side by side */
    & .an-tables table.an-table.compact th,
    & .an-tables table.an-table.compact td { padding: 5px 4px; font-size: 11px; }
    & .an-tables table.an-table.compact th:first-child,
    & .an-tables table.an-table.compact td:first-child {
      max-width: 104px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    & .an-col-chart { display: flex; flex-direction: column; min-width: 0; }
    & .an-col-chart .an-chart-fill {
      flex: 1; height: 100%; min-height: 480px; min-width: 0;
    }
    @media (max-width: 800px) {
      & .an-page { grid-template-columns: 1fr; }
      & .an-col-settings { position: static; z-index: auto; }
    }

    /* Scroll wrapper + sticky header (entire thead as a block) */
    & .scroll {
      max-height: 380px; overflow: auto;
      border: 1px solid var(--epra-grey-2); border-radius: 4px;
    }
    /* Sticky <thead> keeps both header rows pinned together as one block,
       so there's never a sub-pixel white gap between the navy and grey rows
       and they can't visually overlap body content. */
    & .scroll table { border-collapse: separate; border-spacing: 0; }
    & .scroll table thead {
      position: sticky;
      top: 0;
      z-index: 2;
    }
    & .num.pos { color: var(--epra-pos); font-weight: 600; }
    & .num.neg { color: var(--epra-neg); font-weight: 600; }
    & .hidden { display: none; }

    /* Smooth tab content swap */
    & section[id^="view-"] { animation: fadeIn 0.18s ease; }

    /* Color customization panel */
    & details.color-panel { margin-top: 12px; margin-bottom: 0!important; }
    & details.color-panel > summary {
      cursor: pointer; font-size: 12px; font-weight: 600;
      color: var(--epra-navy); padding: 4px 0;
      list-style: none;
    }
    & details.color-panel > summary::before {
      content: "▸ "; display: inline-block; transition: transform 0.15s ease;
    }
    & details.color-panel[open] > summary::before { content: "▾ "; }
    /* Label sits on its own line above the palette+reset row now (rather
       than sharing one row with them) -- every row's palette then starts
       at the same x position regardless of label length, instead of
       drifting with how long that particular label is. .color-row-controls
       is the new wrapper (see renderColorRows() in fen.js) holding palette
       (left) + reset (right) as their own row. 2026-09-25. */
    & .color-row {
      display: flex; flex-direction: column; gap: 4px;
      padding: 4px 0; font-size: 12px;
      margin-bottom: 6px!important;
    }
    & .color-row .label { color: var(--epra-text); }
    & .color-row-controls {
      display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 0!important;
    }
    /* flex-wrap lives on .palette only, not .color-row-controls -- just the
       swatches wrap onto a second line when they don't fit; reset stays put
       on the right. min-width:0 lets this flex child actually shrink/wrap
       instead of forcing its full unwrapped width. */
    & .palette { display: inline-flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
    & .palette .swatch {
      width: 18px; height: 18px; border-radius: 3px;
      border: none; cursor: pointer; padding: 0; position: relative;
      transition: transform 0.1s ease, box-shadow 0.1s ease;
    }
    & .palette .swatch:hover { transform: scale(1.1); }
    /* Border-based selection was unreadable on swatches close to the
       accent navy (a couple of the blues especially) -- a two-tone ring
       (white then navy) reads on every swatch colour regardless, and the
       checkmark is a second, redundant cue on top so it's never ambiguous
       which swatch is picked even at a glance. Text-shadow on the check
       keeps it visible against light swatches too (light blue, grey),
       where a plain white glyph alone would wash out. Kept deliberately
       thin/small (1px+2px ring, 9px check) after the first pass read as
       too heavy. 2026-09-25. */
    & .palette .swatch.selected {
      box-shadow: 0 0 0 1px white, 0 0 0 2.5px var(--epra-navy);
    }
    & .palette .swatch.selected::after {
      content: "\2713";
      position: absolute; inset: 0;
      display: flex; align-items: center; justify-content: center;
      color: white; font-size: 9px; font-weight: 700; line-height: 1;
      text-shadow: 0 0 2px rgba(0,0,0,0.85), 0 0 1px rgba(0,0,0,0.85);
    }
    & .color-row button.reset {
      background: transparent; border: 1px solid var(--epra-grey-2);
      color: var(--epra-muted); padding: 2px 8px; border-radius: 4px;
      font-size: 11px; cursor: pointer; font-family: inherit;
    }
    & .color-row button.reset:hover { background: var(--epra-grey); color: var(--epra-navy); }

    /* Mode toggle (Search / Regions / Sectors) — segmented control */
    /* Four options (Search / Regions / Sectors / Countries) have to fit the
       narrow settings column, so the row wraps rather than overflowing —
       matches frontend/index.html's own .mode-switch rule. */
    & .mode-switch {
      display: inline-flex; flex-wrap: wrap; gap: 2px;
      background: white; border: 1px solid var(--epra-grey-2);
      border-radius: 4px; padding: 3px; margin-bottom: 6px;
      align-self: flex-start; width: fit-content; max-width: 100%;
    }
    & .mode-switch button {
      background: transparent; color: var(--epra-muted); border: none;
      padding: 5px 14px; border-radius: 3px; cursor: pointer;
      font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
      text-transform: uppercase; font-family: inherit;
      transition: all 0.15s ease;
    }
    & .mode-switch button:hover:not(.active) { color: var(--epra-navy); background: rgba(18,73,127,0.06); }
    & .mode-switch button.active {
      background: var(--epra-navy); color: white;
    }
    & .mode-hint {
      font-size: 12px; color: var(--epra-muted);
      padding: 6px 10px; background: var(--epra-grey);
      border-radius: 4px; line-height: 1.4;
    }

    /* Region pills (multi-select toggle). Visuals now come from Bootstrap
       (btn-outline-primary btn-sm) -- 2026-09-10 button-standardization
       pass. Kept as a flex-wrap group, not a .btn-group -- these are
       independently-toggled multi-select pills, not a joined segmented
       control, so pill-shaped individual buttons with a gap read better
       than a fused strip. */
    & .region-pills { display: flex; flex-wrap: wrap; gap: 6px; }

    /* Time series page: controls on the LEFT (sticky), chart+table on the RIGHT */
    & .ts-page {
      display: grid;
      grid-template-columns: 300px minmax(0, 1fr);  /* minmax allows the chart to shrink */
      gap: 16px;
      align-items: stretch;
    }
    & .ts-page > .panel,
    & .ts-page > .ts-col-right > .panel { margin-bottom: 0; }
    & .ts-controls { grid-template-columns: 1fr; gap: 10px; }
    & .ts-col-settings {
      position: sticky;
      top: 152px;
      align-self: start;
      padding: 14px;
    }
    & .ts-col-settings .actions { margin-top: 10px; }
    /* Start & End dates each on their own row (stacked, not side-by-side) */
    & .ts-dates {
      display: grid;
      grid-template-columns: 1fr;
      gap: 10px;
    }
    & .ts-dates .field { gap: 4px; }
    /* Make the D/M/Q/Y buttons square and uniform */
    & #ts-frequency-strip button {
      min-width: 28px;
      padding: 4px 8px;
      font-weight: 700;
    }
    & .ts-col-right { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
    & .ts-col-right .panel { margin-bottom: 0; min-width: 0; }
    & .ts-col-right .chart-wrap { min-width: 0; }
    /* Keep the sticky settings cleanly above any chart overflow */
    & .ts-col-settings { z-index: 1; background: white; }
    /* Collapse earlier so a narrow viewport doesn't squeeze the chart */
    @media (max-width: 1100px) {
      & .ts-page { grid-template-columns: 1fr; }
      & .ts-col-settings { position: static; z-index: auto; }
    }

    /* Regions page: controls on the LEFT, charts on the RIGHT */
    & .rg-page {
      display: grid;
      grid-template-columns: 300px minmax(0, 1fr);
      gap: 16px;
      align-items: stretch;
    }
    & .rg-page > .panel { margin-bottom: 0; }
    & .rg-controls { grid-template-columns: 1fr; }
    & .rg-col-charts { display: flex; flex-direction: column; min-width: 0; }

    /* Settings panel stays pinned just below the topbar while charts scroll */
    & .rg-col-settings {
      position: sticky;
      top: 152px;                            /* clear the banner + tabs */
      align-self: start;                     /* don't stretch in the grid row */
      z-index: 1; background: white;         /* same as .ts-col-settings */
    }
    /* Compact region picker: 2-column grid, smaller pills */
    & .rg-col-settings .region-pills {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 4px;
    }
    & .rg-col-settings .region-pills button {
      padding: 4px 8px;
      font-size: 11px;
      letter-spacing: 0.02em;
    }

    /* Chart grid inside the right column. auto-fit/minmax, not a fixed column
       count + viewport breakpoint: this page sits inside the theme's
       container-xl (see the topbar comment above -- same lesson learned
       there), which caps content width at 1140px no matter how wide the
       viewport gets. A viewport-based breakpoint has no way to know that;
       auto-fit reacts to the grid's own actual rendered width instead, so it
       keeps giving each card a sane minimum (currently resolves to 2-up in
       container-xl's ~824px right column) without needing a second manual
       re-tune if the container width ever changes again. 340px is comfortably
       above the ~265px/card that 3-up would be at container-xl width (too
       tight for the 9-tick x-axis labels, e.g. "-40 -30 -20 -10 0 10 20 30
       40") and below the ~405px/card 2-up actually gets.
       2026-10-02. */
    & .rg-grid {
      display: grid;
      gap: 14px;
      grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
      margin: 0;
    }
    /* Single column: un-stick the settings panel (as .ts-/.an- already do),
       or the charts scroll up underneath -- and over -- it. 2026-10-20. */
    @media (max-width: 760px) {
      & .rg-page { grid-template-columns: 1fr; }
      & .rg-grid { grid-template-columns: 1fr; }
      & .rg-col-settings { position: static; }
    }
    & .rg-card {
      background: white;
      border: none;
      border-radius: 6px;
      padding: 8px 8px 4px;
      width: 100%;
    }
    & .rg-card h3 {
      margin: 0 0 6px; text-align: center;
      color: var(--epra-navy); font-size: 14px; font-weight: 600;
      letter-spacing: 0.02em;
    }
    & .rg-card .chart-wrap-rg { position: relative; height: 430px; }

    /* ---- Searchable multi-select ---- */
    & .smselect { position: relative; }
    & .smselect-input {
      width: 100%; padding: 8px 10px; border: 1px solid var(--epra-grey-2);
      border-radius: 4px; background: white; font-size: 14px; font-family: inherit;
      cursor: pointer;
    }
    & .smselect-input:focus { outline: none; border-color: var(--epra-navy); box-shadow: 0 0 0 2px rgba(0,47,95,0.15); }
    & .smselect-dropdown {
      position: absolute; left: 0; right: 0; top: 100%; z-index: 50;
      background: white; border: 1px solid var(--epra-navy); border-top: none;
      max-height: 280px; overflow-y: auto; box-shadow: 0 4px 12px rgba(0,0,0,0.1);
      display: none;
    }
    & .smselect.open .smselect-dropdown { display: block; }
    & .smselect-option {
      padding: 7px 10px; font-size: 13px; cursor: pointer;
      border-bottom: 1px solid var(--epra-grey);
    }
    & .smselect-option:hover { background: var(--epra-grey); }
    & .smselect-option.selected { background: rgba(0,47,95,0.08); font-weight: 600; color: var(--epra-navy); }
    & .smselect-option .check { color: var(--epra-gold); margin-right: 4px; }
    & .smselect-chips {
      display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;
    }
    & .chip {
      display: inline-flex; align-items: center; gap: 6px;
      background: var(--epra-navy); color: white;
      padding: 3px 8px; border-radius: 12px; font-size: 11px; font-weight: 500;
    }
    & .chip .x { cursor: pointer; opacity: 0.8; font-weight: 700; }
    & .chip .x:hover { opacity: 1; }
    /* ===================== DASHBOARD TAB ===================== */
    & .db-wrap { display: flex; flex-direction: column; gap: 16px; }
    /* Controls row -- each .field is its own label-above-control column
       (the base .field rule above already gives it that), laid out in a
       flex row with align-items: flex-end so every field's control lines
       up along its bottom edge regardless of the field's own height (date
       input vs. btn-group vs. select vs. the label-less .actions buttons/
       status) -- same technique as .controls further up this file.
       flex-wrap lets fields reflow onto a second line once they no longer
       fit, rather than running off the panel edge: an earlier grid-based
       version (grid-auto-flow: column) only reflowed below 760px, which
       Constituents -- the tab with the most fields -- could exceed well
       before reaching a narrow/mobile width (confirmed on the live site,
       2026-09-30: the actions/status group ran off the right edge at
       ordinary desktop widths). */
    & .db-controls-row {
      display: flex;
      flex-wrap: wrap;
      align-items: flex-end;
      column-gap: 16px;
      row-gap: 12px;
    }
    & .db-controls-row .actions { margin-top: 0; }
    @media (max-width: 760px) {
      & .db-controls-row { flex-direction: column; align-items: stretch; }
    }

    /* Hero band */
    & .dhero {
      background: linear-gradient(135deg, var(--epra-navy) 0%, var(--epra-navy-dark) 100%);
      color: white; border-radius: 12px; padding: 22px 28px;
      display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 24px; align-items: center;
      box-shadow: 0 4px 14px rgba(10,77,140,0.18);
    }
    & .dhero .lbl { font-size: 11px; text-transform: uppercase; letter-spacing: 0.8px; color: rgba(255,255,255,0.75); font-weight: 600; }
    & .dhero .big { font-size: 34px; font-weight: 800; letter-spacing: -0.5px; margin: 4px 0 0; line-height: 1.05; }
    & .dhero .ds { display: flex; gap: 28px; flex-wrap: wrap; }
    & .dhero .d .l { display: block; color: rgba(255,255,255,0.75); text-transform: uppercase; letter-spacing: 0.5px; font-size: 10px; margin-bottom: 2px; }
    & .dhero .d .v { font-weight: 700; font-size: 22px; }
    & .dhero .d .v.up { color: #5BE5A0; }
    & .dhero .d .v.down { color: #FF9A8C; }
    & .dhero .d .v.flat { color: rgba(255,255,255,0.8); }
    /* Mobile: the auto-width stats column took nearly the whole row, squeezing
       the market-cap column to a sliver so its text overlapped the stats.
       Stack the two instead. 2026-10-20. */
    @media (max-width: 760px) {
      & .dhero { grid-template-columns: 1fr; gap: 16px; padding: 18px 20px; }
      & .dhero .big { font-size: 28px; }
      & .dhero .ds { gap: 12px 22px; }
    }

    /* Sector trends: region selector as a single-select line + tall wide chart.
       Visuals now come from Bootstrap (.btn-group of btn-outline-primary
       btn-sm) -- 2026-09-10 button-standardization pass, single-select
       exclusive like .db-quick/.horizons, so fused (no gap) is correct here,
       unlike the multi-select .region-pills above. flex-wrap kept as a
       narrow-viewport safety net. */
    & .st-region-line { display: flex; flex-wrap: wrap; }
    & .st-chart-wrap { position: relative; width: 100%; height: 540px; }

    /* Snapshot quick-pick strip. Visuals now come from Bootstrap (.btn-group
       of btn-outline-primary btn-sm, pill-radius via bootstrap-overrides.css)
       -- 2026-09-10 button-standardization pass, single-select exclusive so
       no gap: a true fused strip, rounded only at the two outer ends. */
    & .db-quick { display: inline-flex; flex-wrap: wrap; }

    /* Once a fused strip wraps it reads broken (square corners and shared
       borders at the seam) -- same problem .horizons hit on 2026-09-25. Below
       the width where each strip starts wrapping, un-fuse it into separate
       pills with a gap; the fused look stays where it fits on one line.
       .x.btn-group > .btn ties Bootstrap's own btn-group corner/margin rules
       on specificity and this file loads after the theme, so it wins without
       !important. The ~900px Sector trends strip wraps below container-xl's
       widest step; the Snapshot strip only on phones. 2026-10-20. */
    @media (max-width: 1199px) {
      & .st-region-line { gap: 6px; }
      & .st-region-line.btn-group > .btn {
        margin-left: 0; border-radius: var(--bs-btn-border-radius); flex: 0 1 auto;
      }
    }
    @media (max-width: 760px) {
      & .st-region-line { flex-direction: column; }
      & .db-quick { gap: 6px; }
      & .db-quick.btn-group > .btn { margin-left: 0; border-radius: var(--bs-btn-border-radius); }
    }

    /* 5-up KPI boxes. minmax(0, 1fr), not plain 1fr: plain 1fr won't shrink
       below the content's min width, which pushed the 2-up layout past the
       right edge of a 375px screen. 2026-10-20. */
    & .db-kpis { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; }
    @media (max-width: 1100px) { & .db-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
    @media (max-width: 620px)  { & .db-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
    @media (max-width: 420px)  { & .db-kpis { grid-template-columns: 1fr; } }
    & .db-kpi {
      background: white; border-radius: 10px; padding: 16px 18px;
      box-shadow: 0 1px 3px rgba(10,77,140,0.06);
      border-top: 4px solid var(--epra-navy);
      display: flex; flex-direction: column; gap: 6px;
    }
    & .db-kpi.eur { border-top-color: var(--epra-gold); }
    & .db-kpi.na { border-top-color: #0B3863; }
    & .db-kpi.ap { border-top-color: #5BA7E0; }
    & .db-kpi.em { border-top-color: #3FB8AF; }
    & .db-kpi.gl { border-top-color: var(--epra-navy); }
    & .db-kpi .l { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--epra-muted); font-weight: 700; }
    & .db-kpi .fig { font-size: 24px; font-weight: 700; color: var(--epra-navy); letter-spacing: -0.3px; }
    & .db-kpi .sub { font-size: 12px; color: var(--epra-muted); display: flex; gap: 12px; flex-wrap: wrap; }
    & .db-kpi .sub strong { color: var(--epra-text); }
    & .db-kpi-rets { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 2px; padding-top: 8px; border-top: 1px solid var(--epra-grey-2); }
    & .db-kpi-rets .rr { display: flex; flex-direction: column; gap: 1px; }
    & .db-kpi-rets .rl { font-size: 9px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--epra-muted); font-weight: 700; }
    & .db-kpi-rets .rv { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
    & .db-kpi-rets .rv.up { color: var(--epra-pos); }
    & .db-kpi-rets .rv.down { color: var(--epra-neg); }
    & .db-kpi-rets .rv.flat { color: var(--epra-muted); }

    /* 5-up region pie grid */
    & .db-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
    @media (max-width: 1100px) { & .db-grid { grid-template-columns: repeat(3, 1fr); } }
    @media (max-width: 620px)  { & .db-grid { grid-template-columns: repeat(2, 1fr); } }
    & .db-card {
      background: white; border: 1px solid var(--epra-grey-2); border-radius: 8px;
      padding: 14px 12px; display: flex; flex-direction: column; align-items: center; gap: 8px;
      box-shadow: 0 1px 2px rgba(0,0,0,0.04);
      min-width: 0;   /* allow grid item to shrink below the canvas intrinsic width */
    }
    /* Title box is always two lines tall, so a title that wraps ("Developed
       North America (EGNA)" at 5-up) no longer pushes its pie below the others. */
    & .db-card h3 {
      margin: 0; font-size: 12px; font-weight: 700; color: var(--epra-navy);
      text-transform: uppercase; letter-spacing: 0.5px; text-align: center;
      line-height: 1.3; min-height: 2.6em;
      display: flex; align-items: center; justify-content: center;
    }
    & .db-pie { position: relative; width: 100%; height: 140px; }
    & .db-donut-center {
      position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
      text-align: center; pointer-events: none;
    }
    & .db-donut-center .l { font-size: 8px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--epra-muted); font-weight: 700; }
    & .db-donut-center .v { font-size: 13px; font-weight: 800; color: var(--epra-navy); letter-spacing: -0.3px; }
    & .db-card .db-total { font-size: 16px; font-weight: 800; color: var(--epra-navy); letter-spacing: -0.3px; }
    & .db-card .db-total-lbl { font-size: 9px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--epra-muted); font-weight: 600; margin-top: -4px; }
    & .db-rets { display: flex; gap: 20px; margin-top: 2px; }
    & .db-rets .r { text-align: center; }
    & .db-rets .r .l { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--epra-muted); font-weight: 600; }
    & .db-rets .r .v { font-size: 15px; font-weight: 700; }
    & .db-rets .r .v.up { color: var(--epra-pos); }
    & .db-rets .r .v.down { color: var(--epra-neg); }
    & .db-rets .r .v.flat { color: var(--epra-muted); }

    /* Shared sector legend */
    & .db-legend {
      display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 22px;
      background: white; border: 1px solid var(--epra-grey-2); border-radius: 8px;
      padding: 14px 18px; box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    }
    & .db-legend .li { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--epra-text); }
    & .db-legend .li .dot { width: 12px; height: 12px; border-radius: 3px; flex-shrink: 0; }

    /* ===================== CONSTITUENTS TAB ===================== */
    /* Checkbox dropdown (country / sector) with select-all controls. The
       trigger button carries the real .form-select class (added in JS,
       CheckDropdown constructor) so it renders with whatever the live
       theme's actual select look is -- background, arrow icon, border,
       radius, padding, font -- instead of a hand-copied approximation that
       would drift the next time the theme changes. Only the bits a real
       <select> wouldn't need are set here: it isn't natively full-width,
       and a <button>'s default text-align is center, not left. */
    & .cn-multi { position: relative; }
    & .cn-multi-btn {
      width: 100%; min-width: 150px; text-align: left; cursor: pointer;
    }
    & .cn-multi-btn:hover { border-color: var(--epra-navy); }
    & .cn-multi-panel {
      position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
      background: white; border: 1px solid var(--epra-grey-2); border-radius: 5px;
      box-shadow: 0 4px 14px rgba(10,77,140,0.15);
      min-width: 210px; max-width: 280px;
    }
    & .cn-multi-actions {
      display: flex; gap: 6px; padding: 8px;
      border-bottom: 1px solid var(--epra-grey-2);
    }
    & .cn-multi-actions button {
      flex: 1; background: white; border: 1px solid var(--epra-grey-2);
      border-radius: 4px; padding: 4px 6px; font-size: 10px; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.03em;
      color: var(--epra-navy); cursor: pointer; font-family: inherit;
    }
    & .cn-multi-actions button:hover { background: var(--epra-grey); border-color: var(--epra-navy); }
    & .cn-multi-list { max-height: 240px; overflow-y: auto; padding: 6px; }
    & .cn-multi-list label {
      display: flex; align-items: center; gap: 7px; padding: 4px 6px;
      font-size: 12px; color: var(--epra-text); cursor: pointer;
      border-radius: 3px; white-space: nowrap;
    }
    & .cn-multi-list label:hover { background: rgba(10,77,140,0.06); }
    & .cn-multi-list input[type="checkbox"] { accent-color: var(--epra-navy); cursor: pointer; }

    /* "incl. free-float cap" — tiny label centred above the download button at month end.
       Absolutely positioned so it never shifts the row of buttons. Sits back in
       the top .actions row (2026-10-02), pushed to the far right of that row --
       .actions is already display:flex, so margin-left: auto on this one child
       is enough, no extra wrapper needed. */
    & .cn-dl-wrap { position: relative; display: inline-flex; margin-left: auto; }
    & .cn-dl-note {
      position: absolute; bottom: calc(100% + 2px); left: 0; right: 0;
      text-align: center; font-size: 9px; line-height: 1; white-space: nowrap;
      color: var(--epra-muted); pointer-events: none;
    }

    & .cn-scroll { max-height: calc(100vh - 300px); }
    & table.cn-table th, & table.cn-table td { padding: 5px 8px; font-size: 11px; }
    /* Name column: left-aligned, truncated with tooltip */
    & table.cn-table td:first-child {
      text-align: left; max-width: 210px;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    & table.cn-table th:first-child { text-align: left; }
    /* Sortable headers */
    & table.cn-table thead th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
    & table.cn-table thead th.sortable:hover { background: var(--epra-navy-dark); }
    & table.cn-table thead th .arrow { opacity: 0.55; font-size: 9px; margin-left: 2px; }
    & .cn-reit-tag {
      display: inline-block; padding: 1px 5px; border-radius: 3px;
      font-size: 9px; font-weight: 700; letter-spacing: 0.3px;
    }
    & .cn-reit-tag.yes { background: rgba(10,77,140,0.10); color: var(--epra-navy); }
    & .cn-reit-tag.no { background: var(--epra-grey); color: var(--epra-muted); }

    /* Top 5 countries by region — "league" grid */
    & .db-league-card {
      background: white; border: 1px solid var(--epra-grey-2); border-radius: 8px;
      padding: 16px 18px; box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    }
    & .db-league-card h3 {
      margin: 0 0 12px; font-size: 12px; font-weight: 700; color: var(--epra-navy);
      text-transform: uppercase; letter-spacing: 0.6px;
    }
    & .db-league { display: grid; grid-template-columns: repeat(5, minmax(0,1fr)); gap: 10px; align-items: start; }
    @media (max-width: 1100px) { & .db-league { grid-template-columns: repeat(3, 1fr); } }
    @media (max-width: 700px)  { & .db-league { grid-template-columns: repeat(2, 1fr); } }
    @media (max-width: 520px)  { & .db-league { grid-template-columns: 1fr; } }
    & .dlcol { border-radius: 8px; overflow: hidden; border: 1px solid var(--epra-grey-2); }
    & .dlcol-hdr { padding: 8px 10px 7px; border-bottom: 1px solid var(--epra-grey-2); }
    & .dlcol-hdr .reg-name { display: block; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: var(--epra-muted); }
    & .dlcol-hdr .reg-total { display: block; font-size: 13px; font-weight: 700; color: var(--epra-navy); font-variant-numeric: tabular-nums; margin-top: 1px; }
    & .dlrow { display: grid; grid-template-columns: 16px minmax(0,1fr) auto; gap: 4px; align-items: start; padding: 5px 10px; border-bottom: 1px dashed var(--epra-grey-2); }
    & .dlrow:last-child { border-bottom: none; }
    & .dlrow .rank { font-size: 10px; color: var(--epra-muted); font-weight: 700; padding-top: 1px; }
    & .dlrow .name-wrap .name { display: block; font-size: 12px; color: var(--epra-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    & .dlrow .name-wrap .bar { height: 3px; background: rgba(10,77,140,0.08); border-radius: 2px; margin-top: 3px; overflow: hidden; }
    & .dlrow .name-wrap .bar > span { display: block; height: 100%; border-radius: 2px; }
    & .dlrow .nums { text-align: right; }
    & .dlrow .nums .val { display: block; font-size: 11px; font-weight: 700; color: var(--epra-navy); font-variant-numeric: tabular-nums; }
    & .dlrow .nums .pct { display: block; font-size: 10px; color: var(--epra-muted); font-variant-numeric: tabular-nums; }
}
