/* ════════════════════════════════════════════════════════════════════════════
   MOBILE DASHBOARD SHELL, MD3 Expressive, active only at <= 720px
   Desktop is unaffected: every rule lives inside the max-width media query,
   and the chrome (.mobile-bottom-nav / .mnav-panel) is hidden by default.
   ════════════════════════════════════════════════════════════════════════════ */

/* Hidden by default (desktop + any width above the breakpoint) */
.mnav-panel        { display: none; }
.mtabs             { display: none; }
.ov-grid           { display: none; }   /* mobile-only "story" overview */
/* .mobile-bottom-nav lives in main-dashboard.css, it's a global app-shell element */

@media (max-width: 720px) {

  /* Lock the shell to the viewport so `main` is the ONLY scroller, keeps the
     status strip + pill tabs fixed on every tab (Sentiment was scrolling the
     whole page because its tall content escaped main). Bottom-nav clearance
     goes on the scroller (main), NOT body, body padding would scroll the page. */
  .shell { overflow: hidden; }
  main { overflow-y: auto; padding-bottom: 88px; }

  /* Hide the desktop footer bar (movers + copyright/trademark/coffee) on mobile */
  footer.movers-bar { display: none; }

  /* No per-card news flip on mobile, the News destination replaces it */
  .card-fold { display: none; }

  /* Sentiment gauges: 2-up grid (compact) instead of sparse full-width cards.
     Market Mood + partners span the full width. */
  .bottom-row { grid-template-columns: 1fr 1fr; gap: 10px; }
  .bottom-row .cat-mood,
  .bottom-row .cat-read     { grid-column: 1 / -1; }

  /* Shrink gauge internals so nothing clips in the narrower 2-up card */
  .gauge-card { padding: 10px 12px 12px; }
  .gauge-wrap { gap: 8px; }
  .gauge-arc  { width: 68px; height: 42px; }
  .gauge-info { min-width: 0; }
  .gauge-val  { font-size: 1.3rem; }
  .gauge-sub  { font-size: 10px; line-height: 1.25; white-space: normal; }

  /* Market Mood: stack the 4 cells in one column so labels aren't clipped */
  .mood-grid { grid-template-columns: 1fr; grid-template-rows: auto; }

  /* Contain the cards' 3D-transform (preserve-3d) layer so it cannot paint over
     the sticky pill bar, the cause of the pills being covered on mobile. */
  main { isolation: isolate; }
  .section-row { position: relative; z-index: 0; }

  /* ── Destination switching (driven by body[data-mdest]) ──────────────────── */
  /* News / Calendar active → hide the Invest data; show the chosen panel */
  body[data-mdest="news"]     .section-row,
  body[data-mdest="news"]     .bottom-row,
  body[data-mdest="calendar"] .section-row,
  body[data-mdest="calendar"] .bottom-row { display: none; }

  body[data-mdest="news"]     .mnav-panel[data-panel="news"],
  body[data-mdest="calendar"] .mnav-panel[data-panel="calendar"] { display: block; }

  /* Fade-through feel when a destination becomes active (MD3 emphasized) */
  .mnav-panel[data-panel] {
    animation: mnav-fade-through 220ms cubic-bezier(0.05, 0.7, 0.1, 1.0);
  }
  @keyframes mnav-fade-through {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
  }

  /* ── Placeholder content (Phase 1, real screens land in later phases) ───── */
  .mnav-panel {
    min-height: 50vh;
    display: none;
    padding: 24px 16px;
  }
  .mnav-panel-placeholder {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 12px; min-height: 40vh; text-align: center;
    color: var(--md-on-surface-var);
  }
  .mnav-panel-placeholder .material-symbols-outlined { font-size: 40px; color: var(--md-primary); }
  .mnav-panel-placeholder span:last-child { font-size: 14px; font-weight: 500; }

  /* ── News destination: MD3 Expressive cards ──────────────────────────────── */
  .mnav-panel[data-panel="news"] { padding: 0 0 12px; }
  .mnews-head { padding: 16px 12px 4px; }
  .mnews-title { font-size: 18px; font-weight: 700; color: var(--md-on-surface); }
  .mnews-filter {
    display: flex;
    gap: 8px;
    padding: 8px 12px 12px;
    overflow-x: auto;
    scrollbar-width: none;
    position: sticky;
    top: 0;
    z-index: 6;
    background: var(--md-background);
  }
  .mnews-filter::-webkit-scrollbar { display: none; }
  .mnews-chip {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 7px 14px;
    border-radius: 8px;                 /* MD3 filter-chip shape */
    border: 1px solid var(--md-outline-var);
    background: var(--md-surf-2);
    color: var(--md-on-surface-var);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 200ms cubic-bezier(0.2, 0, 0, 1), color 200ms, border-color 200ms;
  }
  .mnews-chip.is-active { background: var(--md-primary); color: var(--md-on-primary); border-color: transparent; }
  .mnews-chip.is-active::before {
    content: 'check';
    font-family: 'Material Symbols Outlined';
    font-feature-settings: 'liga';
    font-size: 16px;
    line-height: 1;
  }
  .mnews-list { display: flex; flex-direction: column; gap: 14px; padding: 0 12px; }

  /* MD3 Elevated card: surface tint + elevation shadow (no outline). The lift
     separates the card from the page even when the image is near-black. */
  .mnews-card {
    display: block;
    text-decoration: none;
    color: inherit;
    background: var(--md-surf-2);
    border-radius: 22px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 1px 3px 1px rgba(0, 0, 0, 0.15);
    transition:
      transform 160ms cubic-bezier(0.05, 0.7, 0.1, 1.0),
      box-shadow 160ms cubic-bezier(0.05, 0.7, 0.1, 1.0);
    animation: mnews-in 340ms cubic-bezier(0.05, 0.7, 0.1, 1.0) both;
  }
  /* Pressed = raise to elevation level 2 */
  .mnews-card:active {
    transform: scale(0.98);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.30), 0 4px 8px 2px rgba(0, 0, 0, 0.18);
  }

  @keyframes mnews-in {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }

  .mnews-thumb { width: 100%; aspect-ratio: 16 / 9; background: var(--md-surface); }
  .mnews-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

  .mnews-body { padding: 12px 14px 14px; }
  .mnews-meta { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }

  .mnews-source {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--md-primary) 16%, transparent);
    color: var(--md-primary);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
  }
  .mnews-time { font-size: 11px; color: var(--md-on-surface-var); }

  .mnews-headline {
    font-size: 15px;
    font-weight: 600;
    line-height: 1.32;
    color: var(--md-on-surface);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* Hero (lead story): headline overlaid on the image with a legibility scrim */
  .mnews-card--hero { position: relative; }
  .mnews-card--hero .mnews-open { position: relative; display: block; }
  .mnews-card--hero .mnews-thumb { aspect-ratio: 4 / 3; }
  .mnews-card--hero .mnews-overlay {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    padding: 40px 16px 16px;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.88) 10%, rgba(0, 0, 0, 0.45) 55%, transparent);
  }
  .mnews-card--hero .mnews-headline {
    color: #fff;
    font-size: 18px;
    font-weight: 700;
    line-height: 1.25;
    margin-top: 8px;
    -webkit-line-clamp: 3;
  }
  .mnews-card--hero .mnews-time { color: rgba(255, 255, 255, 0.75); margin-top: 6px; }
  .mnews-source--onimg {
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    backdrop-filter: blur(2px);
  }

  /* Card actions (MD3): Read more (primary, tonal) + Share (text button) */
  .mnews-open { display: block; text-decoration: none; color: inherit; }
  /* MD3 button group: related buttons kept together, 8dp gap, aligned as a unit */
  .mnews-actions {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    padding: 4px 10px 10px;
  }
  .mnews-readmore {
    display: inline-flex;
    align-items: center;
    padding: 8px 18px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--md-primary) 16%, transparent);
    color: var(--md-primary);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: background-color 160ms cubic-bezier(0.2, 0, 0, 1);
  }
  .mnews-readmore:active { background: color-mix(in srgb, var(--md-primary) 28%, transparent); }
  .mnews-share {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--md-primary);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 160ms cubic-bezier(0.2, 0, 0, 1);
  }
  .mnews-share .material-symbols-outlined { font-size: 18px; }
  .mnews-share:active { background: color-mix(in srgb, var(--md-primary) 14%, transparent); }

  /* Sponsored "Ad" card, shorter than news cards so it reads as distinct */
  .mnews-ad {
    position: relative;
    display: block;
    border-radius: 22px;
    overflow: hidden;
    background: var(--md-surf-2);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 1px 3px 1px rgba(0, 0, 0, 0.15);
    animation: mnews-in 340ms cubic-bezier(0.05, 0.7, 0.1, 1.0) both;
  }
  .mnews-ad-img { width: 100%; height: 140px; object-fit: cover; display: block; }
  .mnews-ad-cta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 12px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.01em;
  }
  .mnews-ad-badge {
    position: absolute;
    top: 8px; left: 8px;
    z-index: 1;
    padding: 2px 8px;
    border-radius: 7px;
    background: rgba(0, 0, 0, 0.60);
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    backdrop-filter: blur(2px);
  }

  /* ── Calendar destination: agenda list, sticky date headers ──────────────── */
  .mnav-panel[data-panel="calendar"] { padding: 0 0 12px; }
  .mcal-head { padding: 16px 16px 8px; }
  .mcal-title { font-size: 18px; font-weight: 700; color: var(--md-on-surface); }
  .mcal-subtitle { margin-top: 2px; font-size: 12px; color: var(--md-on-surface-var); }
  .mcal-date {
    position: sticky;
    top: 0;
    z-index: 5;
    padding: 10px 16px;
    background: var(--md-background);
    color: var(--md-primary);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.08em;
    border-bottom: 1px solid var(--md-outline-var);
  }
  .mcal-item { border-bottom: 1px solid var(--md-outline-var); }
  .mcal-event {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px 6px;
    color: var(--md-on-surface);
  }
  .mcal-time {
    flex: 0 0 auto;
    min-width: 62px;
    font-family: var(--font-mono, monospace);
    font-size: 12px;
    font-weight: 700;
    color: var(--md-on-surface-var);
  }
  .mcal-name { flex: 1; font-size: 14px; font-weight: 500; line-height: 1.3; }

  /* Gentle, low-emphasis text actions (always visible) */
  .mcal-actions { display: flex; gap: 18px; padding: 0 16px 14px 90px; }
  .mcal-action {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 0;
    background: none;
    color: var(--md-on-surface-var);
    font-size: 12px;
    font-weight: 500;
    text-decoration: none;
  }
  .mcal-action .material-symbols-outlined { font-size: 16px; color: var(--md-primary); }
  .mcal-action:active { color: var(--md-primary); }

  /* ── Status strip: condense to one horizontal scrollable chip rail ───────── */
  .status-strip {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 44px;
    padding: 6px 12px;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .status-strip::-webkit-scrollbar { display: none; }

  /* Hide the market-condition regime row entirely on mobile */
  .status-strip .ss-top-row { display: none; }

  /* Sessions: colored dot + market name only (drop the OPEN/CLOSED text) */
  .status-strip .ss-session-status { display: none; }

  /* Keep only sessions + AI Mood + the tiny streak flame; hide futures, next
     event, and calendar chip (Calendar lives in the bottom nav) */
  .status-strip .ss-items > .ss-item:not(.ss-sessions):not(.ss-aimood):not(.ss-streak) { display: none; }

  .status-strip .ss-items {
    flex: 0 0 auto;
    flex-wrap: nowrap;
    justify-content: center;
    gap: 8px;
  }
  .status-strip .ss-items > *,
  .status-strip .ss-sessions { flex: 0 0 auto; flex-wrap: nowrap; white-space: nowrap; }

  /* ── Global tier: asset-class pill tabs (MD3) ────────────────────────────── */
  .mtabs { display: none; }
  body[data-mdest="global"] .mtabs,
  body:not([data-mdest])    .mtabs {           /* pre-JS state = Global */
    display: flex;
    flex-wrap: nowrap;                 /* single row - scroll horizontally instead of wrapping */
    flex-shrink: 0;                    /* overflow-x:auto sets min-height:0; without this the
                                          flex-column `main` compresses the bar and clips the pills */
    justify-content: flex-start;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    gap: 8px;
    padding: 10px 12px;
    position: sticky;
    top: 0;
    z-index: 30;                       /* sit above the flip-cards (3D transform layers) */
    background: var(--md-background);
    border-bottom: 1px solid var(--md-outline-var);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  }
  .mtabs::-webkit-scrollbar { display: none; }

  /* Dark mode only: a black drop shadow is invisible on the near-black
     background, so the pill-tab bar loses the raised frame it has in light
     mode. Restore it the MD3 way - give the bar a lighter elevated surface
     tint plus a subtle top highlight so it reads as raised. Light mode is left
     exactly as-is (it already shows a crisp border + shadow). */
  html:not([data-dash-theme="light"]) body[data-mdest="global"] .mtabs,
  html:not([data-dash-theme="light"]) body:not([data-mdest])    .mtabs {
    background: var(--md-surf-2);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06),
                0 2px 10px rgba(0, 0, 0, 0.5);
  }

  .mtab {
    flex: 0 0 auto;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 36px;
    padding: 0 16px;
    border-radius: 8px;                 /* MD3 chip shape (not a full pill) */
    border: 1px solid var(--md-outline); /* MD3 filter-chip outline (visible, not the faint outline-variant) */
    background: var(--md-surf-2);
    color: var(--md-on-surface-var);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition:
      background-color 220ms cubic-bezier(0.05, 0.7, 0.1, 1.0),
      color 220ms cubic-bezier(0.05, 0.7, 0.1, 1.0),
      border-color 220ms cubic-bezier(0.05, 0.7, 0.1, 1.0),
      box-shadow 220ms cubic-bezier(0.05, 0.7, 0.1, 1.0),
      transform 220ms cubic-bezier(0.05, 0.7, 0.1, 1.0);
  }
  .mtab:active { transform: scale(0.96); }
  .mtab.is-active {
    background: var(--md-primary);
    color: var(--md-on-primary);
    border-color: transparent;
  }
  .mtab.is-active::before {
    content: 'check';
    font-family: 'Material Symbols Outlined';
    font-feature-settings: 'liga';
    font-size: 18px;
    line-height: 1;
  }

  /* Action pill (Sectors): opens the heatmap popup rather than switching the
     view, so it never goes .is-active. A flame-orange accent signals it apart
     from the asset-class view tabs. */
  /* Colour comes from --flame, which is defined per theme and already contrast-checked
     against the darkest light surface, so there is no light override to keep in step. */
  .mtab.mtab-action {
    color: var(--flame);
    border-color: color-mix(in srgb, var(--flame) 55%, transparent);
  }

  /* ── Show only the active asset section in Global ────────────────────────── */
  body[data-mdest="global"][data-mtab="indices"]     .section-row .card:not(.cat-markets),
  body[data-mdest="global"][data-mtab="crypto"]      .section-row .card:not(.cat-crypto),
  body[data-mdest="global"][data-mtab="commodities"] .section-row .card:not(.cat-commodities),
  body[data-mdest="global"][data-mtab="fx"]          .section-row .card:not(.cat-currencies),
  body[data-mdest="global"][data-mtab="bonds"]       .section-row .card:not(.cat-rates),
  body[data-mdest="global"]:not([data-mtab])         .section-row .card:not(.cat-markets),
  body:not([data-mdest])                             .section-row .card:not(.cat-markets) { display: none; }

  body[data-mdest="global"][data-mtab="sentiment"]   .section-row { display: none; }

  /* Gauges (sentiment) only show under the Sentiment tab */
  body[data-mdest="global"]:not([data-mtab="sentiment"]) .bottom-row,
  body:not([data-mdest])                                 .bottom-row { display: none; }

  /* ═══════════ OVERVIEW "one screen, the whole story" grid ═══════════
     Default mobile view. Replaces the section cards with a compact 2-up grid
     of headline instruments + the two risk gauges. Pre-JS (no data-mtab yet)
     also defaults to it, so there is no flash of the section cards. */
  body[data-mdest="global"][data-mtab="overview"] .section-row,
  body[data-mdest="global"][data-mtab="overview"] .bottom-row,
  body[data-mdest="global"]:not([data-mtab])      .section-row,
  body:not([data-mdest])                          .section-row { display: none; }

  body[data-mdest="global"][data-mtab="overview"] .ov-grid,
  body[data-mdest="global"]:not([data-mtab])      .ov-grid,
  body:not([data-mdest])                          .ov-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    /* No own horizontal padding - `main` already supplies the 16px page margin,
       so the cards run wide (MD3 feed layout) instead of double-padded. */
    padding: 0;
  }

  /* ── Today's read, on Overview ─────────────────────────────────────────────
     The bottom row is a Sentiment-tab thing on mobile, but this one card belongs on
     the screen people actually land on: it is the reason to open the app again
     tomorrow, and putting it behind a tab defeats the point of having it at all.
     The row is un-hidden for this card only; the gauges and Market Mood stay on
     Sentiment where they were. Declared after the rule that hides .bottom-row, same
     specificity, so source order is what makes it win. */
  body[data-mdest="global"][data-mtab="overview"] .bottom-row,
  body[data-mdest="global"]:not([data-mtab])      .bottom-row,
  body:not([data-mdest])                          .bottom-row {
    display: grid;
    grid-template-columns: 1fr;
    margin-bottom: 10px;
    /* main is a flex column, so order lifts the card above .ov-grid without moving it
       in the DOM. In source order it sits after every instrument tile, which put it
       956px down on a 812px screen: visible, but below the fold and after the reader
       has already got what they came for. It has to be the first thing on the screen
       to be the reason for the visit. */
    order: -1;
  }
  body[data-mdest="global"][data-mtab="overview"] .bottom-row > .card:not(.cat-read),
  body[data-mdest="global"]:not([data-mtab])      .bottom-row > .card:not(.cat-read),
  body:not([data-mdest])                          .bottom-row > .card:not(.cat-read) { display: none; }

  .ov-tile {
    display: flex; flex-direction: column; justify-content: space-between;
    gap: 8px; min-height: 76px;
    padding: 11px 13px;
    border: none;
    border-radius: 12px;                      /* MD3 medium - less rounded */
    /* Subtle top-down tonal gradient + elevation = MD3 Expressive depth */
    background: linear-gradient(180deg, var(--md-surf-3) 0%, var(--md-surf-2) 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05),
                0 2px 10px rgba(0, 0, 0, 0.28);
    color: var(--md-on-surface);
    text-align: left; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    position: relative; overflow: hidden;
    transition: transform .12s ease, box-shadow .15s ease;
  }
  .ov-tile:active { transform: scale(.97); }

  /* Dark mode: frosted-glass tiles for the premium depth the flat surface
     lacks over the near-black background (mirrors the desktop glass popups).
     Light mode keeps its clean tonal surface. */
  html:not([data-dash-theme="light"]) .ov-tile {
    border: 1px solid rgba(255, 255, 255, 0.08);
    backdrop-filter: blur(14px) saturate(150%);
    -webkit-backdrop-filter: blur(14px) saturate(150%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07),
                0 4px 18px rgba(0, 0, 0, 0.45);
  }
  html:not([data-dash-theme="light"]) .ov-tile:not(.ov-gauge) {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.02) 100%),
                rgba(12, 22, 32, 0.5);
  }

  /* Trend is signalled by the coloured % chip and sparkline (MD3 prefers tonal
     fills / text-colour shifts over borders for dynamic state). */

  .ov-tile-top { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
  .ov-sym {
    font-family: var(--font-body); font-size: 12px; font-weight: 600; letter-spacing: .01em;
    color: var(--md-on-surface-var);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .ov-chg {
    flex-shrink: 0; font-family: var(--font-mono); font-size: 11px; font-weight: 700;
    padding: 1px 7px; border-radius: 100px; color: var(--md-on-surface-var);
  }
  .ov-chg.up   { color: var(--gain); background: var(--gain-cont); }
  .ov-chg.down { color: var(--loss); background: var(--loss-cont); }

  /* Price on its own line (full width), sparkline as a thin strip beneath it -
     keeps long numbers like 161.6850 from being squeezed by the chart. */
  .ov-tile-bot { display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
  .ov-price {
    font-family: var(--font-mono); font-size: 17px; font-weight: 600; line-height: 1.1;
    color: var(--md-on-surface); white-space: nowrap;
    transition: color .25s ease;
  }
  .ov-price.flash-up   { color: var(--gain); }
  .ov-price.flash-down { color: var(--loss); }

  /* Prominent gradient-area sparkline = the "mini chart" wow factor */
  .ov-spark { width: 100%; height: 34px; display: block; margin-top: 2px; }
  .ov-spark-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
  .ov-spark-line.up   { stroke: var(--gain); }
  .ov-spark-line.down { stroke: var(--loss); }
  .ov-spark-area.up   { fill: url(#ov-grad-up); }
  .ov-spark-area.down { fill: url(#ov-grad-down); }
  .ov-spark-base { stroke: var(--md-outline); stroke-width: 1; stroke-dasharray: 2 2; opacity: .45; }

  /* Hidden host for the sparkline fill gradients (referenced via fill: url()) */
  .ov-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

  /* Risk gauges (VIX, F&G): both share one full-width rectangle, side by side */
  .ov-gauge-pair {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: stretch;
    gap: 8px;
  }
  .ov-gauge-unit {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; gap: 5px;
  }
  .ov-gauge-unit .ov-sym { display: inline-flex; align-items: center; gap: 4px; }
  .ov-gauge-ico { width: 13px; height: 13px; flex-shrink: 0; fill: currentColor; opacity: .75; }
  .ov-gauge-divider { width: 1px; align-self: stretch; background: rgba(255, 255, 255, 0.08); }
  .ov-gauge-meter { position: relative; width: 100%; }
  .ov-gauge-arc   { width: 100%; height: auto; display: block; overflow: visible; }
  .ov-gauge-spectrum { fill: none; stroke-width: 5; stroke-linecap: round; }
  .ov-gauge-needle {
    stroke: var(--md-on-surface); stroke-width: 1.6; stroke-linecap: round;
    transform-box: view-box; transform-origin: 32px 32px;
    transition: transform .6s cubic-bezier(.34, 1.35, .5, 1);
  }
  .ov-gauge-pivot { fill: var(--md-on-surface); r: 1.6; }
  .ov-gauge-num {
    position: absolute; left: 0; right: 0; bottom: 0; text-align: center;
    font-family: var(--font-mono); font-size: 22px; font-weight: 700;
    line-height: 1; color: var(--md-on-surface);
  }
  .ov-gauge .ov-sub {
    font-family: var(--font-body); font-size: 10px; font-weight: 700;
    letter-spacing: .04em; text-transform: uppercase; color: var(--md-on-surface-var);
    text-align: center;
  }

  /* Shared-axis X transition between tabs (MD3 emphasized) */
  @keyframes mtab-x-next { from { opacity: 0; transform: translateX(28px);  } to { opacity: 1; transform: none; } }
  @keyframes mtab-x-prev { from { opacity: 0; transform: translateX(-28px); } to { opacity: 1; transform: none; } }
  body.mtab-fwd  .section-row .card, body.mtab-fwd  .bottom-row, body.mtab-fwd  .ov-grid { animation: mtab-x-next 260ms cubic-bezier(0.05, 0.7, 0.1, 1.0); }
  body.mtab-back .section-row .card, body.mtab-back .bottom-row, body.mtab-back .ov-grid { animation: mtab-x-prev 260ms cubic-bezier(0.05, 0.7, 0.1, 1.0); }

  /* Bottom navigation bar moved to main-dashboard.css (global app shell) */

  @media (prefers-reduced-motion: reduce) {
    .mnav-panel[data-panel], .mnews-card, .mnews-ad { animation: none; }
    .mnav-icon, .mtab { transition: none; }
    body.mtab-fwd .section-row .card, body.mtab-fwd .bottom-row, body.mtab-fwd .ov-grid,
    body.mtab-back .section-row .card, body.mtab-back .bottom-row, body.mtab-back .ov-grid { animation: none; }
  }
}
