/* ══════════════════════════════════════════════════════════════════════
   content-v2.css, Content pages (legal, admin, about, FMG, error)
   Rem-based · fluid clamp() typography · full breakpoint system
   Base assumption: 1rem = 16px (browser default, never override :root)

   Breakpoints:
     xs   < 30rem  (480px)   small mobile
     sm   < 48rem  (768px)   mobile
     md   < 80rem  (1280px)  tablet / small desktop
     lg   < 120rem (1920px)  1080p desktop
     xl   < 160rem (2560px)  1440p / QHD
     2xl  ≥ 160rem (2560px+) 4K / UHD
══════════════════════════════════════════════════════════════════════ */

/* ── One scrollbar, not two ─────────────────────────────────────────────
   main-dashboard.css pins html and body to height: 100% so the dashboard can be a
   fixed-viewport app shell. Content pages load that file too, and their content is far
   taller than the viewport, so both elements ended up shorter than what they contained:
   two nested scroll containers, and a browser draws a scrollbar for each.

   Released here rather than there, so the dashboard shell is untouched. html carries no
   page-type class, only body does, hence :has(). .shell already sets min-height: 100dvh,
   so a content page still fills a short viewport without the pinned body.           ---- */
html:has(body:not(.is-dashboard)),
body:not(.is-dashboard) { height: auto; }

/* ── Fluid type scale ───────────────────────────────────────────────── */
:root {
  --ct-2xs:  clamp(0.5625rem, 0.5rem   + 0.15vw, 0.6875rem); /* 9–11px  */
  --ct-xs:   clamp(0.625rem,  0.575rem + 0.2vw,  0.75rem);   /* 10–12px */
  --ct-sm:   clamp(0.6875rem, 0.625rem + 0.25vw, 0.9375rem); /* 11–15px */
  --ct-base: clamp(0.8125rem, 0.75rem  + 0.3vw,  1.0625rem); /* 13–17px */
  --ct-md:   clamp(0.875rem,  0.8rem   + 0.35vw, 1.125rem);  /* 14–18px */
  --ct-lg:   clamp(1rem,      0.9rem   + 0.5vw,  1.5rem);    /* 16–24px */
  --ct-xl:   clamp(1.25rem,   1rem     + 1vw,    2.25rem);   /* 20–36px */
  --ct-hero: clamp(1.5rem,    1.1rem   + 1.5vw,  3rem);      /* 24–48px */

  /* Fluid spacing, replaces hardcoded px gaps/margins */
  --cs-2xs: clamp(0.25rem,  0.2rem  + 0.15vw, 0.375rem);
  --cs-xs:  clamp(0.375rem, 0.3rem  + 0.25vw, 0.625rem);
  --cs-sm:  clamp(0.5rem,   0.4rem  + 0.35vw, 0.875rem);
  --cs-md:  clamp(0.75rem,  0.6rem  + 0.5vw,  1.25rem);
  --cs-lg:  clamp(1rem,     0.8rem  + 0.75vw, 1.75rem);
  --cs-xl:  clamp(1.5rem,   1rem    + 1.25vw, 3rem);
  --cs-2xl: clamp(2rem,     1.5rem  + 2vw,    4.5rem);

  /* Content max-widths, fluid from mobile up to 4K */
  --content-w:      min(92vw, 62rem);    /* full-bleed on mobile, caps at 992px */
  --content-w-wide: min(96vw, 90rem);   /* admin/analytics, caps at 1440px */

  /* Hairline used for table rows/borders, overridden in light mode below */
  --md-hairline:     rgba(255,255,255,.04);
  /* Amber callout body text, overridden in light mode below */
  --md-callout-text: #e0b97a;
  /* Footer bar background, overridden in light mode below */
  --md-footer-bg:    var(--md-surface);
  /* AI-disclaimer red, bright on dark, darker in light for AA contrast */
  --md-error-text:   #ff4444;
}

/* ── Gain / loss on content pages ──────────────────────────────────────────
   main-dashboard.css owns these tokens, but its light values are scoped to
   html[data-dash-theme="light"], the DASHBOARD toggle. Content pages toggle
   html[data-theme="light"], so they never received them and kept the dark hexes
   on a white card. Both themes are re-pointed here, for content pages only.

   Same hues the dashboard uses, moved only as far as AA requires, the way
   --flame already is. Measured against the worst surface each theme puts them on,
   not just the most common one: --md-surf-1 #111F2A in dark, --md-surf-3 #e6edf2
   in light. #BF6A65 reads 4.36 on the dark card, which is the miss Lighthouse
   reports on the falling indices in Today's Markets, and the light pair was far
   worse at 3.84 and 3.19. Anything using var(--gain) / var(--loss) as text on a
   content page depends on these: the weekly-trends badges, the AI stock changes
   and the admin ticks, not only that one table. */
body:not(.is-dashboard) {
  --gain:  #1AA09F;   /* 5.24 on #111F2A */
  --loss:  #C77872;   /* 5.07 on #111F2A */
  --amber: #d7a52b;   /* 7.43 on #111F2A */
}
html[data-theme="light"] body:not(.is-dashboard) {
  --gain:  #0F6E6D;   /* 6.05 on white, 5.12 on #e6edf2 */
  --loss:  #A8443E;   /* 5.90 on white, 4.99 on #e6edf2 */
  --amber: #8a6200;   /* 5.49 on white, 4.64 on #e6edf2; #d7a52b read 2.26 */
}

/* ── Light mode (content pages only; the dashboard stays dark) ──────────
   A pre-paint script in _Layout_md3v2 sets html[data-theme] from the saved
   choice, falling back to the OS (prefers-color-scheme). When it resolves to
   "light" we re-point the shared MD3 tokens to a light palette for content
   pages only (body:not(.is-dashboard)). The dashboard and its dark tokens are
   never touched. The body background follows --md-background automatically. */
html[data-theme="light"] body:not(.is-dashboard) {
    color-scheme: light;

    /* MD3 cyan light tonal palette (derived from the dark primary) */
    --md-background:        #f8fafd;
    --md-surface:           #f8fafd;
    --md-surf-1:            #ffffff;
    --md-surf-2:            #eef3f7;
    --md-surf-3:            #e6edf2;

    --md-on-background:     #191c1e;
    --md-on-surface:        #191c1e;
    --md-surface-variant:   #dce4e8;
    --md-on-surface-var:    #40484c;
    --md-outline:           #70787d;
    --md-outline-var:       #c4ccd1;

    --md-primary:           #006780;
    --md-on-primary:        #ffffff;
    --md-primary-container: #b8eafe;
    --md-on-primary-cont:   #001f29;
    --md-secondary:         #46626a;

    --md-hairline:          rgba(0,0,0,.07);
    --md-callout-text:      #8a5a00;
    --md-error-text:        #ba1a1a;   /* MD3 error, ~6:1 on white */

    /* Prominent cyan chrome: header + footer get the primary container tint.
       The brand icon flips to solid primary so it stays distinct from the
       now-tinted header bar. (Dashboard stays dark and is unaffected.) */
    --md-topbar-bg:         var(--md-primary-container);
    --md-brand-icon-bg:     var(--md-primary);
    --md-brand-icon-fg:     var(--md-on-primary);
    --md-footer-bg:         var(--md-primary-container);
}

/* ── Theme toggle button (header trail, content pages only) ───────────── */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem;
  flex-shrink: 0;
  padding: 0;
  border: 0;
  border-radius: var(--shape-full);
  background: transparent;
  color: var(--md-on-background);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 150ms ease, color 150ms ease;
}
.theme-toggle:hover  { background: color-mix(in srgb, var(--md-on-background) 8%, transparent); }
.theme-toggle:active { background: color-mix(in srgb, var(--md-on-background) 12%, transparent); }
.theme-toggle:focus-visible { outline: 2px solid var(--md-primary); outline-offset: 2px; }
.theme-toggle svg { width: 1.25rem; height: 1.25rem; }
/* Show the current state: sun while in light mode, moon while in dark mode.
   (Dark is the default, so the sun is hidden until data-theme="light".) */
.theme-toggle .theme-toggle-sun { display: none; }
html[data-theme="light"] .theme-toggle .theme-toggle-moon { display: none; }
html[data-theme="light"] .theme-toggle .theme-toggle-sun  { display: block; }

/* Smooth crossfade only while toggling (the .theme-anim class is added by the
   toggle handler for ~250ms, so page load and hovers are never animated). */
@media (prefers-reduced-motion: no-preference) {
  html.theme-anim,
  html.theme-anim * {
    transition: background-color .25s ease, color .25s ease,
                border-color .25s ease, fill .25s ease;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   LEGAL / CONTENT PAGE SHELL
══════════════════════════════════════════════════════════════════════ */
.legal-page {
  max-width: var(--content-w);
  margin: var(--cs-lg) auto var(--cs-2xl);   /* tighter top gap under the header; keep bottom breathing room */
  padding: 0 var(--cs-xl) var(--cs-2xl);
}
.legal-page a { color: var(--md-primary); }
.legal-page a:hover { opacity: .8; }

/* ── Hero ───────────────────────────────────────────────────────────── */
/* MD3 Expressive surface: two soft tonal blooms over the flat container colour rather
   than the flat colour alone, so the card reads as lit rather than printed. Mixed from
   --md-primary and --md-secondary rather than fixed hexes, so it tints correctly in
   both themes and follows the brand if that ever moves.

   Kept low (14% and 10%) and pushed to the right, away from the eyebrow, title and meta
   on the left, so nothing sits on a gradient while it is being read. The existing
   overflow: hidden clips the blooms to the card's rounded corners. */
.legal-hero {
  background:
    radial-gradient(100% 130% at 92% 18%,
      color-mix(in srgb, var(--md-primary) 22%, transparent) 0%, transparent 58%),
    radial-gradient(80% 115% at 66% 118%,
      color-mix(in srgb, var(--md-secondary) 16%, transparent) 0%, transparent 55%),
    var(--md-surf-1);
  border: 1px solid var(--md-outline-var);
  border-radius: var(--shape-xl);
  padding: var(--cs-2xl) var(--cs-2xl) var(--cs-xl);
  margin-bottom: var(--cs-xl);
  position: relative;
  overflow: hidden;
}
.legal-hero::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--md-primary), var(--md-secondary));
  border-radius: var(--shape-xl) var(--shape-xl) 0 0;
}
.legal-hero-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  color: var(--md-primary);
  letter-spacing: .18em;
  text-transform: uppercase;
  margin-bottom: var(--cs-xs);
}
.legal-hero-title {
  font-family: var(--font-display);
  font-size: var(--ct-xl);
  font-weight: 700;
  color: var(--md-on-background);
  line-height: 1.2;
  margin-top: 0;
  margin-bottom: var(--cs-md);
}
.legal-hero-meta {
  display: flex; flex-wrap: wrap; gap: var(--cs-lg);
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
}
.legal-hero-meta span { display: flex; align-items: center; gap: 0.375rem; }
.legal-hero-meta span::before {
  content: ''; display: block;
  width: 0.3125rem; height: 0.3125rem; border-radius: 50%;
  background: var(--md-primary); opacity: .6;
}
/* Shared "stale data" pill (amber warning tonal). MD3 tonal + full (pill) shape;
   same component is defined in main-dashboard.css for the AI Mood popup. Amber
   reads as caution (data is behind), not error. Theme-safe: bright amber on
   dark, darker amber text on the lighter fill in light mode. */
.stale-pill {
  display: inline-flex; align-items: center;
  padding: 0.0625rem 0.5rem;
  border-radius: var(--shape-full, 999px);
  background: color-mix(in srgb, #FFB300 22%, transparent);
  color: #FFB300;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
html[data-dash-theme="light"] .stale-pill {
  color: #8A5A00;
  background: color-mix(in srgb, #FFB300 30%, transparent);
}
.legal-hero-meta .stale-pill::before { display: none; }

/* ── Back link → "Free Live Dashboard" CTA ──────────────────────────────
   Not a quiet breadcrumb anymore: a gradient pill with a pulsing LIVE dot
   and a breathing glow, the first thing the eye lands on. */
.legal-back,
.legal-page a.legal-back {
  display: inline-flex; align-items: center; gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: var(--ct-sm);
  font-weight: 700;
  color: var(--md-on-primary, #06282e);
  text-decoration: none;
  padding: 0.6rem 1.25rem;
  border-radius: var(--shape-full);
  border: none;
  background: var(--md-primary);
  margin-bottom: var(--cs-lg);
  transition: transform .18s cubic-bezier(0.2, 0, 0, 1), box-shadow .18s;
  letter-spacing: .04em;
  box-shadow: var(--md-elev-1, 0 1px 3px rgba(0, 0, 0, .3));
}
.legal-back:hover,
.legal-page a.legal-back:hover {
  color: var(--md-on-primary, #06282e);
  opacity: 1;
  transform: translateY(-2px) scale(1.03);
  box-shadow: var(--md-elev-2, 0 4px 14px rgba(0, 0, 0, .28));
  filter: brightness(1.06);
}
.legal-back::after { content: '\2192'; font-size: var(--ct-md); }
/* Live equalizer bars: three bars rising and falling like a moving market.
   currentColor so they follow the button's on-primary role in both themes. */
.eq-bars {
  display: inline-flex; align-items: flex-end; gap: 2px;
  width: 14px; height: 13px;
}
.eq-bars i {
  flex: 1;
  background: currentColor;
  border-radius: 1px;
  animation: eq-bounce 1.1s ease-in-out infinite;
}
.eq-bars i:nth-child(1) { animation-delay: 0s;    }
.eq-bars i:nth-child(2) { animation-delay: -0.35s; }
.eq-bars i:nth-child(3) { animation-delay: -0.7s;  }
@keyframes eq-bounce {
  0%, 100% { height: 30%; }
  50%      { height: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .eq-bars i { animation: none; height: 60%; }
  .eq-bars i:nth-child(2) { height: 100%; }
}

/* ── Table of contents ──────────────────────────────────────────────── */
.legal-toc {
  background: var(--md-surf-1);
  border: 1px solid var(--md-outline-var);
  border-radius: var(--shape-lg);
  padding: var(--cs-lg) var(--cs-xl);
  margin-bottom: var(--cs-xl);
}
.legal-toc-title {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  color: var(--md-on-surface-var);
  letter-spacing: .14em;
  text-transform: uppercase;
  margin-bottom: var(--cs-md);
}
.legal-toc ol {
  list-style: none; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.25rem var(--cs-xl);
}
.legal-toc ol li a {
  font-family: var(--font-body);
  font-size: var(--ct-base);
  color: var(--md-primary);
  text-decoration: none;
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.25rem 0;
  transition: color .15s;
}
.legal-toc ol li a:hover { color: var(--md-on-primary-cont); }
.legal-toc ol li a .toc-num {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  color: var(--md-on-surface-var);
  min-width: 1.125rem;
}

/* ── Section card ───────────────────────────────────────────────────── */
.legal-section {
  background: var(--md-surf-1);
  border: 1px solid var(--md-outline-var);
  border-radius: var(--shape-lg);
  padding: var(--cs-xl) var(--cs-2xl);
  margin-bottom: var(--cs-md);
  scroll-margin-top: 5rem;
}
.legal-section-header {
  display: flex; align-items: baseline; gap: var(--cs-md);
  margin-bottom: var(--cs-md);
  padding-bottom: var(--cs-md);
  border-bottom: 1px solid var(--md-outline-var);
}
.legal-section-num {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  color: var(--md-primary);
  letter-spacing: .1em;
  min-width: 1.75rem;
  flex-shrink: 0;
}
.legal-section-title {
  font-family: var(--font-display);
  font-size: var(--ct-lg);
  font-weight: 700;
  color: var(--md-on-background);
  line-height: 1.3;
}
.legal-subhead {
  font-family: var(--font-display);
  font-size: var(--ct-md);
  font-weight: 700;
  color: var(--md-on-background);
  line-height: 1.35;
  margin: var(--cs-lg) 0 var(--cs-sm);
}

/* ── Dashboard CTA (funnels content-page readers into the live dashboard) ── */
/* Hidden by default; JS in _DashboardCta.cshtml reveals it only for visitors
   who arrived from outside the site (not internal nav). Two classes so this
   wins over the .dash-cta display rule below. */
.dash-cta.dash-cta--prehide { display: none; }
.dash-cta {
  display: flex; align-items: center; gap: var(--cs-lg);
  margin: var(--cs-lg) 0 var(--cs-xl);
  padding: var(--cs-lg) var(--cs-xl);
  border-radius: var(--shape-lg);
  background: linear-gradient(135deg,
      color-mix(in srgb, var(--md-primary) 14%, var(--md-surf-3)) 0%,
      var(--md-surf-3) 72%);
  border: 1px solid color-mix(in srgb, var(--md-primary) 30%, transparent);
  text-decoration: none;
  transition: transform .15s ease, box-shadow .2s ease, border-color .2s ease;
}
.dash-cta:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--md-primary) 55%, transparent);
  box-shadow: 0 10px 30px color-mix(in srgb, var(--md-primary) 20%, transparent);
}
.dash-cta-live {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-mono); font-size: .7rem; font-weight: 700;
  letter-spacing: .12em; color: var(--md-error-text); flex-shrink: 0;
}
.dash-cta-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--md-error-text);
  animation: dash-cta-pulse 1.8s ease-in-out infinite;
}
.dash-cta-body { flex: 1 1 auto; display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.dash-cta-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--ct-lg); color: var(--md-on-background); line-height: 1.25;
}
.dash-cta-sub {
  font-family: var(--font-body); font-size: var(--ct-sm);
  color: var(--md-on-surface-var); line-height: 1.4;
}
.dash-cta-free, .dash-exit-free {
  /* Text uses the on-surface role (guaranteed AA contrast on the card); primary
     is used only as the icon + border accent, never as the text colour. */
  display: inline-flex; align-items: center; gap: .3rem; width: fit-content;
  font-family: var(--font-mono); font-size: .72rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--md-on-background);
  background: color-mix(in srgb, var(--md-primary) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--md-primary) 40%, transparent);
  padding: 3px 10px; border-radius: 999px;
}
.dash-cta-free { margin-top: .3rem; }
.dash-exit-free { margin: .15rem 0 var(--cs-md); }
.dash-cta-free .material-symbols-outlined,
.dash-exit-free .material-symbols-outlined { font-size: 15px; color: var(--md-primary); }
.dash-cta-action {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: .4rem;
  padding: .6rem 1.15rem; border-radius: 999px;
  background: var(--md-primary); color: var(--md-on-primary);
  font-family: var(--font-body); font-weight: 600; font-size: var(--ct-sm);
  white-space: nowrap;
}
.dash-cta:hover .dash-cta-action { background: color-mix(in srgb, var(--md-primary) 88%, #000); }
.dash-cta-action .material-symbols-outlined { font-size: 18px; transition: transform .15s ease; }
.dash-cta:hover .dash-cta-action .material-symbols-outlined { transform: translateX(3px); }

@keyframes dash-cta-pulse {
  0%, 100% { opacity: 1;  transform: scale(1); }
  50%      { opacity: .4; transform: scale(.8); }
}
@media (max-width: 640px) {
  .dash-cta { flex-direction: column; align-items: flex-start; gap: var(--cs-md); }
  .dash-cta-action { align-self: stretch; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .dash-cta-dot { animation: none; }
  .dash-cta:hover { transform: none; }
}

/* ── Exit-intent modal (desktop, external landers, once/session) ─────────── */
.dash-exit { position: fixed; inset: 0; z-index: 5000; }
.dash-exit[hidden] { display: none; }
.dash-exit-scrim {
  position: absolute; inset: 0;
  background: rgba(0,0,0,.5);
  opacity: 0; transition: opacity .22s ease;
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.dash-exit.open .dash-exit-scrim { opacity: 1; }
.dash-exit-dialog {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -48%) scale(.97);
  width: min(440px, calc(100vw - 32px));
  box-sizing: border-box;
  padding: var(--cs-xl) var(--cs-xl) var(--cs-lg);
  border-radius: var(--shape-lg);
  background: var(--md-surf-3);
  /* signature cyan -> purple glow, matching the AI Mood popup + nav drawer */
  box-shadow:
    0 0 0 1px rgba(6,182,212,.5),
    0 0 0 3px rgba(168,85,247,.2),
    0 0 40px rgba(6,182,212,.18),
    0 24px 60px rgba(0,0,0,.55);
  opacity: 0;
  transition: transform .25s cubic-bezier(.34,1.56,.64,1), opacity .2s ease;
}
.dash-exit.open .dash-exit-dialog { transform: translate(-50%, -50%) scale(1); opacity: 1; }
.dash-exit-close {
  position: absolute; top: .6rem; right: .6rem;
  width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
  border: none; background: none; border-radius: 50%; cursor: pointer;
  color: var(--md-on-surface-var); transition: background .15s;
}
.dash-exit-close:hover { background: color-mix(in srgb, var(--md-on-background) 8%, transparent); }
.dash-exit-live {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-mono); font-size: .7rem; font-weight: 700;
  letter-spacing: .12em; color: var(--md-error-text);
}
.dash-exit-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--md-error-text);
  animation: dash-cta-pulse 1.8s ease-in-out infinite;
}
.dash-exit-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--ct-xl); color: var(--md-on-background);
  line-height: 1.2; margin: .5rem 0 .35rem;
}
.dash-exit-sub {
  font-family: var(--font-body); font-size: var(--ct-sm);
  color: var(--md-on-surface-var); line-height: 1.5; margin: 0 0 var(--cs-sm);
}
.dash-exit-list {
  list-style: none; margin: 0 0 var(--cs-lg); padding: 0;
  display: grid; gap: .45rem;
}
.dash-exit-list li {
  position: relative; padding-left: 1.5rem;
  font-family: var(--font-body); font-size: var(--ct-sm);
  color: var(--md-on-surface-var); line-height: 1.4;
}
.dash-exit-list li::before {
  content: 'check'; font-family: 'Material Symbols Outlined';
  position: absolute; left: 0; top: 0;
  font-size: 1rem; color: var(--md-primary);
}
.about-newhere {
  font-family: var(--font-body); font-size: var(--ct-sm);
  color: var(--md-on-surface-var); margin: 0 0 var(--cs-lg);
}
.about-newhere a { color: var(--md-primary); text-decoration: none; }
.about-newhere a:hover { text-decoration: underline; }
.dash-exit-action {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .7rem 1.3rem; border-radius: 999px;
  background: var(--md-primary); color: var(--md-on-primary) !important;
  font-family: var(--font-body); font-weight: 600; font-size: var(--ct-sm);
  text-decoration: none;
}
.dash-exit-action .material-symbols-outlined { font-size: 18px; }
.dash-exit-action:hover { background: color-mix(in srgb, var(--md-primary) 88%, #000); }

@media (prefers-reduced-motion: reduce) {
  .dash-exit-dot { animation: none; }
  .dash-exit-scrim, .dash-exit-dialog { transition: none; }
}
.legal-section p {
  font-family: var(--font-body);
  font-size: var(--ct-md);
  line-height: 1.75;
  color: var(--md-on-surface);
  margin-bottom: var(--cs-md);
}
.legal-section p:last-child { margin-bottom: 0; }
.legal-section ul { padding-left: var(--cs-xl); margin-bottom: var(--cs-md); }
.legal-section ul li {
  font-family: var(--font-body);
  font-size: var(--ct-md);
  line-height: 1.75;
  color: var(--md-on-surface);
  margin-bottom: 0.25rem;
}
.legal-section ul li::marker { color: var(--md-primary); }

/* ── Callout / warning block ────────────────────────────────────────── */
.legal-callout {
  background: rgba(255,167,38,.07);
  border: 1px solid rgba(255,167,38,.25);
  border-left: 3px solid var(--amber);
  border-radius: var(--shape-sm);
  padding: var(--cs-lg) var(--cs-xl);
  margin: var(--cs-md) 0;
}
.legal-callout p {
  font-size: var(--ct-base) !important;
  color: var(--md-callout-text) !important;
  margin-bottom: 0 !important;
}

/* ── Contact card ───────────────────────────────────────────────────── */
.legal-contact {
  background: var(--md-primary-container);
  border: 1px solid rgba(77,208,225,.2);
  border-radius: var(--shape-lg);
  padding: var(--cs-xl) var(--cs-2xl);
  margin-top: var(--cs-xl);
  display: flex; align-items: center; gap: var(--cs-xl);
}
.legal-contact-icon {
  width: 3rem; height: 3rem;
  border-radius: var(--shape-md);
  background: rgba(77,208,225,.15);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.375rem;
  flex-shrink: 0;
}
.legal-contact-body { flex: 1; }
.legal-contact-body strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--ct-md);
  font-weight: 700;
  color: var(--md-on-primary-cont);
  margin-bottom: 0.25rem;
}
.legal-contact-body span {
  font-family: var(--font-body);
  font-size: var(--ct-base);
  color: var(--md-on-primary-cont);
  opacity: .8;
}
.legal-contact-body a { color: var(--md-on-primary-cont); font-weight: 600; }

/* ── Modifier: variants ─────────────────────────────────────────────── */
.legal-page--wide        { max-width: var(--content-w-wide); }
.legal-section--highlight { border-left: 3px solid var(--md-primary); }
.legal-section--table    { padding: 0; overflow-x: auto; }
.legal-section--mt       { margin-top: var(--cs-xl); }
.legal-contact--spaced   { margin-top: var(--cs-2xl); }

/* ── Support buttons ────────────────────────────────────────────────── */
.support-links {
  display: flex; gap: 0.875rem; flex-wrap: wrap; margin-top: 1rem;
}
.support-btn {
  display: inline-flex; align-items: center; gap: 0.625rem;
  padding: 0.6875rem 1.25rem;
  border-radius: 0.625rem;
  text-decoration: none;
  font-family: var(--font-body);
  font-size: var(--ct-md);
  font-weight: 600;
  color: var(--md-on-surface);
  background: var(--md-surface);
  border: 1.5px solid var(--md-outline-var);
  transition: border-color .15s, transform .15s, background .15s;
}
.support-btn:hover { transform: translateY(-2px); background: var(--md-primary-container); }
.support-btn-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.625rem; height: 1.625rem; border-radius: 0.375rem;
  font-size: 0.9375rem; flex-shrink: 0;
}
.support-btn-body { display: flex; flex-direction: column; }
.support-btn-name { font-size: var(--ct-md); font-weight: 700; color: var(--md-on-surface); line-height: 1.2; }
.support-btn-sub  { font-size: var(--ct-xs); font-weight: 400; color: var(--md-on-surface); opacity: .7; margin-top: 0.0625rem; }
.support-btn-bmc  .support-btn-icon { background: #FFDD00; }
.support-btn-kofi .support-btn-icon { background: #29abe0; }
.support-btn-bmc:hover  { border-color: #FFDD00; }
.support-btn-kofi:hover { border-color: #29abe0; }

/* ── Table of contents ──────────────────────────────────────────────── */
.legal-section-num.wn-date {
  font-size: var(--ct-xs);
  min-width: 2.75rem;
  background: var(--md-primary-container);
  color: var(--md-on-primary-cont);
  border-radius: 0.375rem;
  padding: 0.125rem 0.5rem;
  letter-spacing: .04em;
}
.wn-list { padding-left: var(--cs-xl); margin: 0; }
.wn-list li {
  font-family: var(--font-body);
  font-size: var(--ct-md);
  line-height: 1.75;
  color: var(--md-on-surface);
  margin-bottom: 0.375rem;
}
.wn-list li::marker { color: var(--md-primary); }

/* ══════════════════════════════════════════════════════════════════════
   DATA SOURCES PAGE
══════════════════════════════════════════════════════════════════════ */
.ds-table {
  width: 100%; border-collapse: collapse;
  font-size: var(--ct-base);
  margin-top: var(--cs-md);
}
.ds-table th {
  text-align: left; padding: var(--cs-xs) var(--cs-md);
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--md-on-surface-var);
  border-bottom: 1px solid var(--md-outline-var);
}
.ds-table td {
  padding: var(--cs-xs) var(--cs-md);
  color: var(--md-on-surface);
  border-bottom: 1px solid var(--md-hairline);
  vertical-align: top;
}
.ds-table tr:last-child td { border-bottom: none; }
.ds-table tr:hover td { background: var(--md-surf-2); }
.ds-table-note {
  margin-top: var(--cs-md);
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
}
/* Sub-heading inside a numbered section, for a second table under the first.
   MD3 Title Small: a real h3 in the outline, sized below the section h2. */
.ds-subhead {
  margin: var(--cs-lg) 0 var(--cs-sm);
  font-family: var(--font-display);
  font-size: var(--ct-md);
  font-weight: 600;
  color: var(--md-on-background);
  line-height: 1.3;
}

.ds-compare-p    { margin-top: 0.75rem; }
.ds-compare-link { color: var(--md-primary); font-weight: 600; }

/* Generic responsive wrapper: lets any content table scroll horizontally on
   narrow screens instead of overflowing the page. Reusable across pages. */
.content-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-top: var(--cs-md); }
.content-table-wrap .ds-table { margin-top: 0; }

/* ── MD3 Expressive table card (guide pages) ──────────────────────────
   Opt-in skin over ds-table / va-table: the table becomes a tonal card
   (large corner, contained surface), the header row gets a tonal fill
   with Label type in sentence case instead of the admin mono-caps, and
   rows keep a gentle hover state layer. Admin tables are untouched. */
.md3-table-card {
  border: 1px solid var(--md-outline-var);
  border-radius: 16px;                        /* shape.corner.large */
  background: var(--md-surf-1);
  overflow: hidden; overflow-x: auto;
  margin-top: var(--cs-md);
}
.md3-table-card table { margin-top: 0; }
.md3-table-card th {
  background: var(--md-surf-3);               /* tonal header band */
  font-family: var(--font-body);
  font-size: var(--ct-sm);
  font-weight: 700;                           /* Label Large, Emphasized */
  letter-spacing: .01em; text-transform: none;
  color: var(--md-on-surface);
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--md-outline-var);
}
.md3-table-card td { padding: 0.7rem 1rem; }

/* Alternating row tint: traces a row across wide multi-column tables (MD3 §4).
   Hover uses surf-3 so it still reads as a state change on striped rows. */
.md3-table-card tbody tr:nth-child(even) td { background: var(--md-surf-2); }
.md3-table-card tbody tr:hover td { background: var(--md-surf-3); }

/* Sticky identity column: on narrow screens the card scrolls horizontally and
   the row label would scroll out of view. Backgrounds must be opaque here, or
   scrolled cells show through. Header sits above it on the z axis. */
.md3-table-card th:first-child,
.md3-table-card td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  font-weight: 600;                           /* row identity leads */
  background: var(--md-surf-1);
  border-right: 1px solid var(--md-outline-var);
}
.md3-table-card th:first-child { background: var(--md-surf-3); z-index: 2; }
.md3-table-card tbody tr:nth-child(even) td:first-child { background: var(--md-surf-2); }
.md3-table-card tbody tr:hover td:first-child { background: var(--md-surf-3); }

/* ── Comparison table ───────────────────────────────────────────────── */
.cmp-table {
  width: 100%; border-collapse: collapse;
  font-size: var(--ct-base);
  margin-top: var(--cs-md);
}
.cmp-table th {
  text-align: center; padding: var(--cs-xs) var(--cs-md);
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--md-on-surface-var);
  border-bottom: 2px solid var(--md-outline-var);
}
.cmp-table th:first-child { text-align: left; }
.cmp-table td {
  padding: var(--cs-xs) var(--cs-md);
  text-align: center;
  color: var(--md-on-surface);
  border-bottom: 1px solid var(--md-hairline);
}
.cmp-table td:first-child { text-align: left; font-weight: 600; }
.cmp-table tr:last-child td { border-bottom: none; }
.cmp-table tr:hover td { background: var(--md-surf-2); }
.cmp-table .cmp-gmd { color: var(--md-primary); font-weight: 700; }
.cmp-yes  { color: var(--gain); font-weight: 700; }
.cmp-no   { color: var(--md-outline); }
.cmp-part { color: var(--amber, #f59e0b); }

/* ══════════════════════════════════════════════════════════════════════
   ABOUT PAGE
══════════════════════════════════════════════════════════════════════ */
.about-feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13.75rem, 1fr));
  gap: 1rem;
  margin-top: 0.75rem;
}
.about-feature-card {
  background: var(--md-surface-2);
  border: 1px solid var(--md-outline-var);
  border-radius: 0.75rem;
  padding: 1rem;
}
.about-feature-title {
  font-size: var(--ct-base);
  font-weight: 700;
  color: var(--md-primary);
  margin-bottom: 0.375rem;
}
.about-feature-card p {
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
  line-height: 1.6;
  margin: 0;
}

.about-faq { display: flex; flex-direction: column; gap: 1rem; margin-top: 0.75rem; }
.about-faq-item {
  border-left: 3px solid var(--md-primary);
  padding-left: 1rem;
}
.about-faq-q {
  font-size: var(--ct-md);
  font-weight: 700;
  color: var(--md-on-surface);
  margin: 0 0 0.375rem;
}
.about-faq-a {
  font-size: var(--ct-base);
  color: var(--md-on-surface-var);
  line-height: 1.6;
  margin: 0;
}

.about-comparison-wrap { overflow-x: auto; }
/* ── Footer link nav, MD3 icon list in a tonal card ────────────────── */
.content-footer {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.25rem 1.5rem;
  margin-top: var(--cs-xl);
  padding: 1.25rem 1.5rem;
  background: var(--md-footer-bg);
  border: 1px solid var(--md-outline-var);
  border-radius: 16px;
}
/* The support ask, at the end of a page the reader has just finished. Sized for a
   reading surface rather than the dashboard's 10px data strip: Label Large, 14sp,
   with a real touch target, because this one is on phones where the dashboard chip
   never appears. */
.content-footer-support {
  margin: 1.25rem 0 0;
  text-align: center;
}

/* Doubled selector (.legal-page a.content-footer-coffee), for the same reason as
   .legal-hero-cta below: ".legal-page a { color: var(--md-primary) }" is 0,1,1 and
   beats a bare class at 0,1,0. Declared singly, the dark text here silently lost to
   primary blue, which is #006780 on #FF6433, a contrast ratio of 2.19:1 and a plain
   accessibility failure. The dark brown is 5.82:1 and passes AA.

   Anything painted on a brand background inside .legal-page needs this treatment. */
.content-footer-coffee,
.legal-page a.content-footer-coffee {
  display: inline-block;
  padding: 0.625rem 1.25rem;
  border-radius: 6.25rem;
  /* Ko-fi brand orange, same as the dashboard chip, so the two read as one thing. */
  background: #FF6433;
  color: #2E1500;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25;
  text-decoration: none;
  transition: opacity .15s ease;
}

.content-footer-coffee:hover,
.legal-page a.content-footer-coffee:hover { opacity: .85; color: #2E1500; }

.content-footer-coffee:focus-visible,
.legal-page a.content-footer-coffee:focus-visible {
  outline: 0.125rem solid var(--md-primary);
  outline-offset: 0.1875rem;
}

/* The shared partial ships data-tooltip-pos="bottom", which is right in the top bar
   and wrong at the end of a page: below the last element, the bubble is drawn past
   the content and can land off-screen. Put it back above, the site's default.

   Tag plus class plus attribute (0,2,1) so it beats the base rule at 0,2,0 whatever
   order the two stylesheets happen to load in. Same approach as the wall-mode theme
   toggle further down: the attribute is fixed in shared markup, so the surface that
   differs fixes it here. */
a.content-footer-coffee[data-tooltip-pos="bottom"]::before {
  top: auto;
  bottom: calc(100% + 0.5rem);
  transform: translateX(-50%) translateY(0.25rem);
}

a.content-footer-coffee[data-tooltip-pos="bottom"]::after {
  top: auto;
  bottom: calc(100% + 0.125rem);
  transform: translateX(-50%) translateY(0.25rem);
  border-top: 0.3125rem solid #2a2d36;
  border-bottom: none;
}

a.content-footer-coffee[data-tooltip-pos="bottom"]:hover::before,
a.content-footer-coffee[data-tooltip-pos="bottom"]:hover::after,
a.content-footer-coffee[data-tooltip-pos="bottom"]:focus-visible::before,
a.content-footer-coffee[data-tooltip-pos="bottom"]:focus-visible::after {
  transform: translateX(-50%) translateY(0);
}

.content-footer-copy {
  margin: 0.75rem 0 0;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--md-on-surface-var);
}
.content-footer-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6875rem 0.75rem;
  border-radius: 10px;
  color: var(--md-on-surface);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease;
}
.content-footer-link .material-symbols-outlined {
  font-size: 20px;
  color: var(--md-primary);
  transition: color 120ms ease;
}
.content-footer-link:hover {
  background-color: color-mix(in srgb, var(--md-primary) 8%, transparent);
  color: var(--md-primary);
}
.content-footer-link:active {
  background-color: color-mix(in srgb, var(--md-primary) 12%, transparent);
}
.content-footer-link:focus-visible {
  outline: 2px solid var(--md-primary);
  outline-offset: 2px;
  background-color: color-mix(in srgb, var(--md-primary) 12%, transparent);
}

/* ── AI disclaimer ──────────────────────────────────────────────────── */
.ai-disclaimer-section { border-left: 4px solid var(--md-error-text); }
.ai-disclaimer-num     { color: var(--md-error-text); }
.ai-disclaimer-title   { color: var(--md-error-text); }
.ai-callout     { border-color: var(--md-error-text); background: rgba(255,68,68,0.08); }
.ai-callout--mt { border-color: var(--md-error-text); background: rgba(255,68,68,0.08); margin-top: 0.75rem; }
.ai-callout-warning { color: var(--md-error-text); font-weight: 700; }
.ai-callout-bold    { font-weight: 700; }

/* ── Utility links ──────────────────────────────────────────────────── */
.content-link       { color: var(--md-primary); font-weight: 600; }
.content-link-plain { color: var(--md-primary); }
.kofi-btn-img       { border: 0; height: 2.25rem; }

/* ══════════════════════════════════════════════════════════════════════
   ADMIN, VISITOR ANALYTICS
══════════════════════════════════════════════════════════════════════ */
.status-strip     { display: none !important; }
.bottom-row       { display: none !important; }
footer.movers-bar { display: none !important; }

/* SignalR live indicators are meaningless on static content pages (no hub
   connection here) and clash with the light header bar, hide them. */
.chip-live        { display: none !important; }
#conn-status      { display: none !important; }

.va-wrap {
  max-width: var(--content-w-wide);
  margin: 0 auto;
  padding: var(--cs-xl) var(--cs-md);
}
.va-hero { margin-bottom: var(--cs-xl); }
.va-hero-eyebrow {
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--md-primary);
  margin-bottom: 0.375rem;
}
.va-hero-title {
  font-size: clamp(1.625rem, 4vw, 2.375rem);
  font-weight: 800;
  color: var(--md-on-surface);
  line-height: 1.15;
}
.va-hero-sub {
  font-size: var(--ct-sm);
  color: var(--md-on-surface-var);
  margin-top: 0.375rem;
}
.va-kpi-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--cs-md);
  margin-bottom: var(--cs-xl);
}
.va-kpi {
  background: var(--md-surface-1);
  border: 1px solid var(--md-outline-var);
  border-radius: 1rem;
  padding: var(--cs-md) var(--cs-lg);
}
.va-kpi-label {
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
  margin-bottom: 0.5rem;
}
.va-kpi-value {
  font-size: clamp(2rem, 5vw, 3rem);
  font-weight: 900;
  color: var(--md-primary);
  line-height: 1;
}
.va-kpi-sub {
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
  margin-top: 0.25rem;
}
.va-kpi--live                  { border-color: var(--gain); }
.va-kpi--live .va-kpi-label    { color: var(--gain); }
.va-kpi--live .va-kpi-value    { color: var(--gain); }

.va-kpi--peak                  { border-color: #a855f7; }
.va-kpi--peak .va-kpi-label    { color: #a855f7; }
.va-kpi--peak .va-kpi-value    { color: #a855f7; }

.va-card {
  background: var(--md-surface-1);
  border: 1px solid var(--md-outline-var);
  border-radius: 1rem;
  padding: var(--cs-lg);
  margin-bottom: var(--cs-md);
}
.va-card-title {
  font-size: var(--ct-sm);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
  margin-bottom: var(--cs-md);
}
.va-breakdown-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17.5rem, 1fr));
  gap: var(--cs-md);
  margin-bottom: var(--cs-xl);
}
.va-bar-row {
  display: flex; align-items: center; gap: 0.625rem;
  margin-bottom: 0.625rem;
  font-size: var(--ct-md);
}
.va-bar-label {
  flex: 0 0 auto; width: 10.625rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--md-on-surface); font-weight: 500;
}
.va-bar-track {
  flex: 1; background: var(--md-outline-var);
  border-radius: 0.25rem; height: 0.4375rem; overflow: hidden;
}
.va-bar-fill { height: 100%; border-radius: 0.25rem; background: var(--md-primary); }
.va-bar-count {
  flex: 0 0 2.75rem; text-align: right;
  color: var(--md-on-surface-var);
  font-size: var(--ct-base);
}
.va-hourly {
  display: flex; align-items: flex-end; gap: 0.1875rem;
  height: 3.75rem; margin-bottom: var(--cs-lg);
}
.va-hourly-col {
  flex: 1; height: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end;
}
.va-hourly-bar {
  width: 100%; background: var(--md-primary);
  border-radius: 0.125rem 0.125rem 0 0;
  opacity: .65; min-height: 0.125rem;
}
.va-hourly-hr {
  margin-top: 0.1875rem;
  font-size: 0.5625rem; line-height: 1;
  color: var(--md-on-surface-var);
  font-variant-numeric: tabular-nums;
}
.va-table-wrap { overflow-x: auto; }
.va-table { width: 100%; border-collapse: collapse; font-size: var(--ct-base); }
.va-table th {
  text-align: left; padding: 0.625rem 0.75rem;
  border-bottom: 1px solid var(--md-outline-var);
  font-size: var(--ct-xs);
  font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--md-on-surface-var);
}
.va-table td {
  padding: 0.5625rem 0.75rem;
  border-bottom: 1px solid var(--md-hairline);
  color: var(--md-on-surface); vertical-align: top;
  max-width: 13.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* IP cell must never truncate: a full IPv6 + the confirmed check need to stay
   visible. The admin table has the horizontal room (it can scroll if needed). */
.va-table td.va-ip-cell { max-width: none; overflow: visible; text-overflow: clip; }
.va-table tr:last-child td { border-bottom: none; }
.va-table tr:hover td { background: var(--md-surf-2); }
/* Prose comparison tables (e.g. Trader vs Gambler): cells wrap to full, clear
   sentences instead of the compact admin-table ellipsis truncation. */
.va-table--wrap td { white-space: normal; max-width: none; overflow: visible; text-overflow: clip; }
/* Small info-icon link (e.g. glance-table label -> matching FAQ answer). */
.fmg-faq-icon { display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; margin-left: 0.1rem; vertical-align: middle; color: var(--md-primary); text-decoration: none; opacity: .7; }
.fmg-faq-icon:hover { opacity: 1; }
.fmg-faq-icon .material-symbols-outlined { font-size: 1.15rem; }
/* Numbered steps inside a FAQ answer (e.g. how to stay disciplined). */
.fmg-steps { margin: 0.5rem 0 0; padding-left: 1.25rem; }
.fmg-steps li { margin-bottom: 0.5rem; line-height: 1.55; }

/* ── Trader / Gambler self-test quiz ──────────────────────────────────────── */
.quiz-form { display: grid; gap: 0.85rem; }
.quiz-q { border: 1px solid var(--md-outline-var); border-radius: 0.9rem; padding: 1rem 1.1rem; margin: 0; background: var(--md-surf-2, var(--md-surface)); }
.quiz-q-text { font-weight: 600; line-height: 1.5; margin: 0 0 0.85rem; }
.quiz-q-num { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; margin-right: 0.45rem; border-radius: 50%; background: var(--md-primary); color: #fff; font-size: var(--ct-xs); font-weight: 700; }
.quiz-scale { display: flex; align-items: center; justify-content: space-between; gap: 0.4rem; flex-wrap: wrap; }
.quiz-scale-end { font-size: var(--ct-xs); color: var(--md-on-surface-var); flex: 0 0 auto; }
.quiz-scale label { cursor: pointer; position: relative; }
.quiz-scale input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.quiz-scale label span { display: inline-flex; align-items: center; justify-content: center; width: 2.4rem; height: 2.4rem; border-radius: 50%; border: 1.5px solid var(--md-outline-var); font-weight: 700; transition: background .15s, border-color .15s, color .15s; }
.quiz-scale input:checked + span { background: var(--md-primary); border-color: var(--md-primary); color: #fff; }
.quiz-scale input:focus-visible + span { outline: 2px solid var(--md-primary); outline-offset: 2px; }
.quiz-submit { margin-top: 0.35rem; padding: 0.8rem 1.6rem; border: none; border-radius: 2rem; background: var(--md-primary); color: #fff; font-weight: 700; font-size: var(--ct-base); cursor: pointer; }
.quiz-submit:hover:not(:disabled) { filter: brightness(1.08); }
.quiz-submit:disabled { opacity: .45; cursor: not-allowed; }
.quiz-progress { margin-left: 0.75rem; font-size: var(--ct-sm); color: var(--md-on-surface-var); }
.quiz-result { margin-top: 1.5rem; border: 1px solid var(--md-outline-var); border-radius: 1rem; padding: 1.5rem; background: var(--md-surf-2, var(--md-surface)); text-align: center; }
.quiz-result-score { font-size: 2.6rem; font-weight: 800; color: var(--md-primary); line-height: 1.1; }
.quiz-result-score small { font-size: 1.1rem; color: var(--md-on-surface-var); font-weight: 600; }
.quiz-result-title { font-size: 1.4rem; margin: 0.35rem 0 0.75rem; }
.quiz-result-text { line-height: 1.6; margin: 0 auto 1.1rem; max-width: 42rem; }
.quiz-result-cta a { display: inline-block; margin: 0.3rem; }
.quiz-result-cta a.quiz-dash-cta { display: inline-block; margin: 0.3rem 0 0; padding: 0.8rem 1.6rem; border-radius: 2rem; background: var(--md-primary); color: #fff; font-weight: 700; font-size: var(--ct-base); text-decoration: none; }
.quiz-result-cta a.quiz-dash-cta:hover { color: #fff; filter: brightness(1.08); }
.quiz-dash-sub { margin: 0.5rem auto 0; max-width: 32rem; font-size: var(--ct-sm); color: var(--md-on-surface-var); line-height: 1.5; }
/* In the left-aligned intro (vs the centered result box) the sub-line hugs the button */
.quiz-intro .quiz-dash-sub { margin-left: 0.25rem; text-align: left; }

.va-ok { color: var(--md-primary); font-weight: 700; }

/* Admin: Recent Visits card header + on-demand bot-hygiene button */
.va-card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.va-btn {
    font: inherit; font-size: var(--ct-sm); font-weight: 600; line-height: 1;
    color: var(--md-on-primary); background: var(--md-primary);
    border: none; border-radius: 999px; padding: 0.55rem 1.1rem; cursor: pointer;
    transition: filter 120ms ease, opacity 120ms ease;
}
.va-btn:hover { filter: brightness(1.08); }
.va-btn:disabled { opacity: 0.6; cursor: default; }
.va-hygiene-msg { margin-top: 0.6rem; font-size: var(--ct-sm); color: var(--md-on-surface-var); }

/* Smooth in-page anchor jumps (ToC, glance-table info icons), MD3 motion.
   Honors reduced-motion; scroll-margin gives the target a little breathing room. */
@media (prefers-reduced-motion: no-preference) { html, body, main { scroll-behavior: smooth; } }
:target { scroll-margin-top: 1rem; }

/* ── Physical AI guide ────────────────────────────────────────────────────── */
/* MD3 media card: vertical (image on top) on mobile, horizontal (image left,
   text right) on desktop. */
.pai-figure { display: flex; flex-direction: column; margin: 1.25rem 0; border: 1px solid var(--md-outline-var); border-radius: 16px; overflow: hidden; background: var(--md-surf-2, var(--md-surface)); }
.pai-img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block; }
/* Phones: guide images are wide banners, never a full-viewport wall.
   Explicit height cap because aspect-ratio alone has proven unreliable
   in some mobile browsers/WebViews. */
@media (max-width: 48rem) {
  .pai-img { aspect-ratio: auto; height: clamp(140px, 26vh, 230px); object-fit: cover; }
}
.pai-figure figcaption { margin: 0; padding: 0.9rem 1.1rem; font-size: var(--ct-base); color: var(--md-on-surface-var); line-height: 1.5; }
@media (min-width: 641px) {
  .pai-figure { flex-direction: row; align-items: stretch; }
  .pai-img { flex: 0 0 240px; width: 240px; aspect-ratio: auto; height: auto; }
  .pai-figure figcaption { align-self: center; }
  /* Banner variant for portrait/square sources: full-width center-cropped
     strip with the caption below, instead of a skinny image tower next to
     an empty caption cavern. */
  .pai-figure--banner { flex-direction: column; }
  .pai-figure--banner .pai-img { flex: none; width: 100%; height: 300px; }
}
/* Dividends-vs-bonds guide: dual-coded side chips so the two sides of the
   comparison read at a glance - bond = blue + lock (fixed, contractual),
   dividend stock = green + rising chart (growing, at risk). */
.dvb-side {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.1rem 0.55rem; border-radius: var(--shape-full, 999px);
  font-weight: 700; white-space: nowrap;
}
.dvb-side .material-symbols-outlined { font-size: 1rem; }
.dvb-bond { color: #2979FF; background: rgba(41, 121, 255, .10); border: 1px solid rgba(41, 121, 255, .30); }
.dvb-div  { color: #1AA09F; background: rgba(76, 175, 80, .10);  border: 1px solid rgba(76, 175, 80, .30); }
html[data-theme="light"] body:not(.is-dashboard) .dvb-bond { color: #1655b8; }
html[data-theme="light"] body:not(.is-dashboard) .dvb-div  { color: #2e7d32; }
/* Phones: chips must not force wide table columns - drop the pill box,
   keep only the color + icon coding, and let the label wrap. */
@media (max-width: 48rem) {
  .dvb-side { white-space: normal; padding: 0; border: none; background: none; gap: 0.2rem; }
  .dvb-side .material-symbols-outlined { font-size: 0.875rem; }
}

.pai-list { list-style: none; padding: 0; margin: 0.75rem 0; display: grid; gap: 0.6rem; }
.pai-list li { padding: 0.75rem 1rem; border: 1px solid var(--md-outline-var); border-radius: 14px; line-height: 1.55; }
.quiz-share { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; margin-top: 1.1rem; }
.quiz-share-item { display: inline-flex; align-items: center; padding: 0.55rem 1.1rem; border-radius: 2rem; border: 1.5px solid var(--md-outline-var); background: transparent; color: var(--md-on-surface); font-weight: 600; font-size: var(--ct-sm); cursor: pointer; text-decoration: none; }
.quiz-share-item:hover { border-color: var(--md-primary); color: var(--md-primary); }
.va-chip {
  display: inline-block;
  padding: 0.1875rem 0.625rem; border-radius: 0.625rem;
  font-size: var(--ct-xs); font-weight: 700;
  border: 1px solid var(--md-outline-var);
  color: var(--md-on-surface-var);
}
.va-chip.mobile  { border-color: var(--gain);        color: var(--gain); }
.va-chip.tablet  { border-color: var(--amber);       color: var(--amber); }
.va-chip.desktop { border-color: var(--md-primary);  color: var(--md-primary); }
.va-chip--inline { flex: 0 0 auto; }
.va-back {
  display: inline-block; margin-bottom: var(--cs-lg);
  font-size: var(--ct-md); font-weight: 600; color: var(--md-primary);
  text-decoration: none;
}
.va-back:hover { text-decoration: underline; }
.va-empty { font-size: var(--ct-xs); color: var(--md-on-surface-var); }
.va-meta  { font-size: var(--ct-2xs); color: var(--md-on-surface-var); }
.va-td-total { font-weight: 700; color: var(--md-primary); }
.va-td-muted { color: var(--md-on-surface-var); }
/* User-Agent cell. Capped and clipped so one 300-character string cannot stretch
   the table past the viewport; the full value stays in the title tooltip. Mono,
   because reading these is about spotting a token like "wv" or "HeadlessChrome"
   rather than reading prose. */
.va-td-ua {
  font-family: var(--font-mono);
  font-size: var(--ct-2xs);
  color: var(--md-on-surface-var);
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════════
   ADMIN, AFFILIATES
══════════════════════════════════════════════════════════════════════ */
.aff-status-chips  { display: flex; gap: 0.625rem; flex-wrap: wrap; margin-bottom: var(--cs-xl); }
.aff-name          { font-weight: 700; font-size: var(--ct-xs); color: var(--md-on-surface); }
.aff-website       { font-size: var(--ct-2xs); color: var(--md-on-surface-var); }
.aff-website a     { color: var(--md-primary); text-decoration: none; }
.aff-td-panel      { font-size: var(--ct-sm); color: var(--md-on-surface-var); }
.aff-td-payout     { font-size: var(--ct-sm); color: var(--md-on-surface); }
.aff-td-center     { text-align: center; }
.aff-not-set       { font-size: var(--ct-2xs); color: var(--md-on-surface-var); }
.aff-td-notes      { font-size: var(--ct-2xs); color: var(--md-on-surface-var); max-width: 10rem; }
.aff-how-to-list   { font-size: var(--ct-xs); color: var(--md-on-surface-var); line-height: 1.8; }

.aff-mgmt-table { width: 100%; border-collapse: collapse; font-size: var(--ct-xs); }
.aff-mgmt-table th {
  text-align: left; padding: 0.625rem 0.875rem;
  font-size: var(--ct-2xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--md-on-surface-var); border-bottom: 2px solid var(--md-outline-var);
  white-space: nowrap;
}
.aff-mgmt-table td {
  padding: 0.75rem 0.875rem;
  border-bottom: 1px solid var(--md-outline-var);
  vertical-align: middle;
}
.aff-mgmt-table tr:last-child td { border-bottom: none; }
.aff-mgmt-table tr:hover td { background: var(--md-surf-2); }
.aff-cat-chip {
  font-size: var(--ct-2xs); font-weight: 700; letter-spacing: .06em;
  padding: 0.125rem 0.5rem; border-radius: var(--shape-chip);
  background: var(--md-surf-3); color: var(--md-on-surface-var); white-space: nowrap;
}
.aff-status-chip {
  font-size: var(--ct-2xs); font-weight: 800; letter-spacing: .08em;
  padding: 0.125rem 0.5625rem; border-radius: var(--shape-chip);
  border: 1px solid; white-space: nowrap;
}
.aff-check   { color: var(--gain); font-weight: 700; }
.aff-missing { color: var(--loss); font-weight: 700; }
.aff-link-chip {
  font-size: var(--ct-2xs); font-weight: 700;
  color: var(--gain); text-decoration: none;
  padding: 0.125rem 0.5rem; border-radius: var(--shape-chip);
  background: var(--gain-cont); white-space: nowrap;
}
.aff-apply-btn {
  font-size: var(--ct-2xs); font-weight: 700;
  color: var(--md-primary); text-decoration: none;
  padding: 0.1875rem 0.625rem; border-radius: var(--shape-full);
  border: 1px solid var(--md-primary); white-space: nowrap;
  transition: background .15s;
}
.aff-apply-btn:hover { background: rgba(77,208,225,.1); }

/* ══════════════════════════════════════════════════════════════════════
   FINANCIAL MARKETS GUIDE
══════════════════════════════════════════════════════════════════════ */
.fmg-disclaimer { margin-top: 1rem; }

/* Live-levels band, funnels "markets today" search intent to the live dashboard */
.fmg-live-band {
  margin: var(--cs-lg) 0;
  padding: var(--cs-md) var(--cs-lg);
  border: 1px solid var(--md-outline-var);
  border-left: 3px solid var(--md-primary);
  border-radius: var(--cs-xs);
  background: color-mix(in srgb, var(--md-primary) 6%, transparent);
}
.fmg-live-band-head {
  display: flex; align-items: center; gap: 0.5rem;
  font-weight: 600; margin-bottom: 0.5rem;
}
.fmg-live-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: var(--md-primary);
  animation: fmgLivePulse 2s ease-in-out infinite;
}
@keyframes fmgLivePulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: .4;  transform: scale(.8); }
}
@media (prefers-reduced-motion: reduce) {
  .fmg-live-dot { animation: none; }
}
.fmg-live-band a       { color: var(--md-primary); text-decoration: none; }
.fmg-live-band a:hover { text-decoration: underline; }
.fmg-live-cta {
  display: inline-block; margin-top: 0.5rem; font-weight: 600;
}
.fmg-back-top {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.625rem; height: 1.625rem; border-radius: 50%;
  border: 1px solid var(--md-outline-var);
  color: var(--md-primary);
  font-size: var(--ct-md);
  text-decoration: none; flex-shrink: 0;
  transition: background 0.15s, border-color 0.15s;
}
.fmg-back-top:hover { background: var(--md-primary-container); border-color: var(--md-primary); }
.fmg-asset-title {
  font-size: var(--ct-lg);
  font-weight: 700;
  margin: 1.75rem 0 0.5rem;
  color: var(--md-primary);
}
.fmg-asset-title:first-of-type { margin-top: 0.5rem; }
.fmg-sources {
  font-size: var(--ct-sm);
  margin-top: 0.375rem;
  color: var(--md-on-surface-var);
}
.fmg-sources a       { color: var(--md-primary); text-decoration: none; }
.fmg-sources a:hover { text-decoration: underline; }
.fmg-sources-list    { margin: 0.75rem 0 0 1.25rem; line-height: 2; }
.fmg-sources-list a       { color: var(--md-primary); text-decoration: none; }
.fmg-sources-list a:hover { text-decoration: underline; }

/* ══════════════════════════════════════════════════════════════════════
   WEEKLY MARKET TRENDS
   Desktop: all sections stacked, pills hidden. Mobile (<=720px): sticky
   quick-jump pills filter to one market at a time (mirrors the dashboard).
══════════════════════════════════════════════════════════════════════ */
.wt-tabs { display: none; }

/* Neutral market label above each section heading (trend is shown by the
   coloured left border, which reads correctly in both light and dark). */
.wt-pill-label {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 0.75rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase;
  padding: 0.125rem 0.625rem;
  border-radius: var(--shape-full);
  background: var(--md-surf-3);
  color: var(--md-on-surface-var);
  margin-bottom: var(--cs-xs);
}

/* Trend accent: green up, red down, amber mixed. A border avoids the
   contrast pitfalls of coloured text on light backgrounds. */
.wt-trend-up    { border-left: 3px solid var(--gain); }
.wt-trend-down  { border-left: 3px solid var(--loss); }
.wt-trend-mixed { border-left: 3px solid var(--amber); }

/* Trend badge: a coloured circle + direction arrow in each section header,
   so the page reads as more than a wall of text. */
.wt-trend-badge {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.875rem; height: 1.875rem; flex-shrink: 0;
  border-radius: var(--shape-full);
  font-size: 0.9rem; font-weight: 700; line-height: 1;
}
.wt-badge-up    { background: var(--gain-cont);  color: var(--gain); }
.wt-badge-down  { background: var(--loss-cont);  color: var(--loss); }
.wt-badge-mixed { background: var(--amber-cont); color: var(--amber); }
.wt-badge-up::before    { content: "\25B2"; }   /* up triangle */
.wt-badge-down::before  { content: "\25BC"; }   /* down triangle */
.wt-badge-mixed::before { content: "\2192"; }   /* right arrow */

/* Per-section subject image as a small MD3 leading thumbnail in the header
   (renders only when the file exists; falls back to the trend badge). */
.wt-thumb {
  width: 3.5rem; height: 3.5rem;     /* 56dp leading media */
  flex-shrink: 0;
  border-radius: var(--shape-md);    /* 12dp rounded square */
  object-fit: cover;
  background: var(--md-surf-2);
}
/* Center the leading thumbnail against the heading (the shared header uses
   baseline alignment, which would misalign the image). */
.wt-section .legal-section-header { align-items: center; }

.wt-cta { margin-top: var(--cs-sm); }
.wt-cta a {
  color: var(--md-primary); text-decoration: none;
  font-weight: 600; font-size: 0.875rem;
}
.wt-cta a:hover { text-decoration: underline; }

.wt-disclaimer {
  margin-top: var(--cs-lg);
  font-size: 0.8125rem; line-height: 1.5;
  color: var(--md-on-surface-var);
  font-style: italic;
}

@media (max-width: 720px) {
  .wt-tabs {
    display: flex; flex-wrap: nowrap; gap: 0.375rem;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    position: sticky; top: 0.5rem; z-index: 20;
    margin: 0 0 var(--cs-md);
    padding: 0.375rem;
    background: var(--md-surf-2);
    border: 1px solid var(--md-outline-var);
    border-radius: var(--shape-full);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05),
                0 2px 10px rgba(0, 0, 0, 0.28);
  }
  .wt-tabs::-webkit-scrollbar { display: none; }
  .wt-tab {
    flex: 0 0 auto;
    font-family: var(--font-body);
    font-size: 0.8125rem; font-weight: 600;
    padding: 0.4375rem 0.875rem;
    border-radius: var(--shape-full);
    border: 1px solid var(--md-outline-var);
    background: var(--md-surf-2);
    color: var(--md-on-surface-var);
    cursor: pointer; white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
  }
  .wt-tab.is-active {
    background: var(--md-primary-container);
    color: var(--md-on-primary-cont);
    border-color: transparent;
  }
  /* Only the active section is shown on mobile (class set by weekly-trends.js;
     ignored on desktop, where every section stays visible). */
  .wt-section.is-hidden { display: none; }

  /* Keep the thumbnail beside the title on mobile (the shared header stacks to
     a column by default); MD3 list-item style with leading media. */
  .wt-section .legal-section-header { flex-direction: row; align-items: center; }
}

/* ══════════════════════════════════════════════════════════════════════
   HOW TO INVEST IN AI  (the AI stack)
══════════════════════════════════════════════════════════════════════ */
/* The pyramid is the page's centrepiece, not a peer of the body sections, so it
   gets an expressive treatment: a tonal container at the extra-large corner
   radius, an overline, and a Headline-role title one step above the section
   titles (--ct-xl vs --ct-lg). */
.ai-pyramid {
  margin: var(--cs-lg) 0;
  padding: var(--cs-lg) var(--cs-md) var(--cs-md);
  background: var(--md-surf-1);
  border: 1px solid var(--md-outline-var);
  border-radius: var(--shape-xl);               /* shape.corner.extra-large, as .legal-hero */
}
.ai-pyramid-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  color: var(--md-primary);
  letter-spacing: .14em;
  text-transform: uppercase;
  text-align: center;
  margin-bottom: var(--cs-2xs);
}
.ai-pyramid-title {
  font-family: var(--font-display);
  font-size: var(--ct-xl);                      /* Headline role, above section titles */
  font-weight: 700;
  color: var(--md-on-background);
  line-height: 1.2;
  letter-spacing: -.01em;                       /* tighter tracking at display size */
  text-align: center;
  margin-bottom: var(--cs-md);
  text-wrap: balance;
}
.ai-pyramid svg { width: 100%; max-width: 32rem; height: auto; display: block; margin: 0 auto; overflow: visible; }
.ai-pyramid text {
  fill: #fff; font-family: var(--font-body); font-size: 23px; font-weight: 700;
  letter-spacing: .2px; text-anchor: middle; dominant-baseline: middle; pointer-events: none;
}
.ai-pyramid a { cursor: pointer; outline: none; }
.aip-band {
  stroke: rgba(255, 255, 255, .22); stroke-width: .75;
  transition: filter .15s ease, opacity .15s ease;
}
/* persistent "go" signifier (chevron), brightens on interaction */
.aip-go {
  fill: rgba(255, 255, 255, .8); font-size: 26px; font-weight: 700;
  text-anchor: middle; dominant-baseline: middle; pointer-events: none;
  transition: fill .15s ease, transform .15s ease; transform-box: fill-box; transform-origin: center;
}
/* MD3 state layers: hover lifts, press dims, keyboard focus shows a ring */
.ai-pyramid a:hover .aip-band   { filter: brightness(1.12); }
.ai-pyramid a:hover .aip-go     { fill: #fff; transform: translateX(2px); }
.ai-pyramid a:active .aip-band  { filter: brightness(.94); opacity: .9; }
.ai-pyramid a:focus-visible .aip-band {
  stroke: var(--md-on-surface, #fff); stroke-width: 2.5;
  filter: brightness(1.12) drop-shadow(0 0 3px rgba(124, 77, 255, .6));
}

.ai-pyramid-hint {
  display: flex; align-items: center; justify-content: center; gap: 0.4rem;
  margin: var(--cs-sm) 0 0; font-size: 0.875rem; font-weight: 600;
  color: var(--md-on-surface-var);
}
.ai-pyramid-hint .material-symbols-outlined { font-size: 1.1rem; }

/* sponsored partner cards (bottom of the page) */
.ai-partners-note {
  font-size: 0.8125rem; font-style: italic; color: var(--md-on-surface-var);
  margin: 0 0 var(--cs-md);
}
.ai-partners-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--cs-md);
}
@media (max-width: 560px) { .ai-partners-grid { grid-template-columns: 1fr; } }
.ai-partner-card {
  display: flex; flex-direction: column; overflow: hidden; text-decoration: none;
  background: var(--md-surf-2, var(--md-surface));
  border: 1px solid var(--md-hairline, rgba(0, 0, 0, .08));
  border-radius: var(--shape-lg, 16px);
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
.ai-partner-card:hover {
  box-shadow: var(--md-elev-2, 0 4px 14px rgba(0, 0, 0, .18));
  transform: translateY(-2px); border-color: var(--md-primary);
}
/* Capped, uniform banner height so cards stay compact and align regardless of
   the source image's shape (kept short so the block never dominates the page).
   Targets the class rather than any descendant img, so the styling is explicit
   and a future non-logo image inside the card does not inherit banner sizing. */
.ai-partner-logo {
  width: 100%; height: clamp(84px, 9vw, 120px);
  object-fit: cover; display: block;
}
.ai-partner-cta {
  margin-top: auto;                     /* pin CTA to card bottom so the row lines up */
  padding: 0.75rem 1rem; text-align: center; font-weight: 700; font-size: 0.9375rem;
  color: var(--md-primary);
}
/* ── In-article partner strip (/markets-today) ─────────────────────────────────
   The banner grid above is an end-of-page block: the reader has finished, and it
   reads as a footer. This one interrupts, so it is built the opposite way. It is a
   single row of small cards with a label rail on the left, sitting between two
   content cards with its own hairlines above and below, which is what tells the eye
   it is not part of the article. Nothing here inherits from .ai-partner-*: same
   images, different job. */
.mtd-adstrip {
  display: flex;
  align-items: stretch;
  gap: var(--cs-lg);
  margin: var(--cs-lg) 0;
  padding: var(--cs-md) 0;
  border-top: 1px solid var(--md-hairline, rgba(0, 0, 0, .08));
  border-bottom: 1px solid var(--md-hairline, rgba(0, 0, 0, .08));
}
/* The label rail. Fixed width so the cards start on the same line whatever the
   disclosure wraps to, and centred vertically against the row of images. */
.mtd-adstrip-label {
  flex: 0 0 8.5rem;
  display: flex; flex-direction: column; justify-content: center; gap: 0.35rem;
}
.mtd-adstrip-tag {
  font-family: var(--font-mono);
  font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--md-on-surface-var);
}
.mtd-adstrip-note {
  font-size: 0.6875rem; line-height: 1.35; font-style: italic;
  color: var(--md-on-surface-var); opacity: 0.75;
}
.mtd-adstrip-track {
  flex: 1 1 auto; min-width: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--cs-md);
}
.mtd-adstrip-card {
  display: flex; flex-direction: column; overflow: hidden; text-decoration: none;
  border-radius: var(--shape-md, 12px);
  background: var(--md-surf-2, var(--md-surface));
  border: 1px solid var(--md-hairline, rgba(0, 0, 0, .08));
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}
.mtd-adstrip-card:hover {
  box-shadow: var(--md-elev-2, 0 4px 14px rgba(0, 0, 0, .18));
  transform: translateY(-2px);
  border-color: var(--md-primary);
}
/* Shorter than .ai-partner-logo on purpose: this block sits mid-read, so it has to
   be scannable in one glance without pushing the next section off the screen. */
.mtd-adstrip-img {
  width: 100%; height: clamp(64px, 6vw, 88px);
  object-fit: cover; display: block;
}
/* --md-primary, not the partner's own BrandColor. The brand hexes are chosen to sit on
   the partner's own white site: #2962FF and #2979FF both fail AA against this card in
   dark mode, while the teal ones pass, so the row failed contrast at random depending
   on which four were drawn. The logo already carries the branding. */
.mtd-adstrip-cta {
  margin-top: auto;
  padding: 0.5rem 0.6rem; text-align: center;
  font-size: 0.75rem; font-weight: 700; line-height: 1.3;
  color: var(--md-primary);
}
/* Below the guide breakpoint the label rail stops paying for its width: it becomes a
   single line above a two-up grid, so the images keep as much room as the column has. */
@media (max-width: 720px) {
  .mtd-adstrip { flex-direction: column; gap: var(--cs-sm); }
  .mtd-adstrip-label { flex: 0 0 auto; flex-direction: row; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
  .mtd-adstrip-track { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* faint circuit contour around the pyramid, follows the theme */
.aip-circuit polyline {
  fill: none; stroke: var(--md-outline, rgba(120, 120, 140, .45));
  stroke-width: 1; stroke-dasharray: 3 5; opacity: .5;
}
.aip-circuit circle { fill: var(--md-on-surface-var, #8a8a9a); opacity: .45; }

.ai-stocks { list-style: none; margin: var(--cs-sm) 0 0; padding: 0; }
.ai-stock {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--cs-md);
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--md-hairline, rgba(0, 0, 0, .07));
}
.ai-stock:last-child { border-bottom: none; }
.ai-stock-name { font-weight: 600; color: var(--md-on-surface); }
.ai-stock-tkr {
  font-family: var(--font-mono); font-size: 0.75rem; font-weight: 700;
  color: var(--md-on-surface-var); background: var(--md-surf-3);
  padding: 1px 6px; border-radius: var(--shape-full); margin-left: 0.25rem;
}
.ai-stock-quote { display: inline-flex; align-items: baseline; gap: 0.5rem; white-space: nowrap; }
.ai-stock-price { font-family: var(--font-mono); font-weight: 600; color: var(--md-on-surface); }
.ai-stock-chg   { font-family: var(--font-mono); font-size: 0.8125rem; font-weight: 700; }
.ai-stock-chg.up   { color: var(--gain); }
.ai-stock-chg.down { color: var(--loss); }
.ai-note { font-size: 0.8125rem; font-style: italic; color: var(--md-on-surface-var); margin-top: var(--cs-sm); }

/* ══════════════════════════════════════════════════════════════════════
   STEP LIST - visible numbered path, mirrors the HowTo structured data
══════════════════════════════════════════════════════════════════════ */
.pai-steps { list-style: none; counter-reset: step; padding: 0; margin: var(--cs-md) 0; display: grid; gap: 0.6rem; }
.pai-steps li {
  counter-increment: step;
  position: relative;
  padding: 0.85rem 1rem 0.85rem 3.25rem;
  border: 1px solid var(--md-outline-var);
  border-radius: 14px;
  background: var(--md-surf-1);
  line-height: 1.55;
}
.pai-steps li::before {
  content: counter(step);
  position: absolute;
  left: 0.85rem; top: 0.85rem;
  width: 1.75rem; height: 1.75rem;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--md-primary-container);
  color: var(--md-on-primary-cont);
  font-size: var(--ct-sm); font-weight: 700;
}

/* ══════════════════════════════════════════════════════════════════════
   WORLD HEATMAP (/world-heatmap) - live country-ETF tiles, theme-aware.
   Self-contained here so the content page needs no dashboard stylesheet.
══════════════════════════════════════════════════════════════════════ */
/* Live-data page: compress the whole vertical stack so every region is on one
   screen on desktop, matching the "everything on one screen" spirit rather than
   a reading-guide layout. All scoped to .wh-live-page so other content pages,
   and the shared hero/section/back styles, are untouched. */
.wh-live-page { margin-top: var(--cs-sm); }
.wh-live-page .legal-section { padding: var(--cs-lg) var(--cs-xl); }
/* Standardised content-page hero: MD3 hero rhythm with room to breathe (padding
   ~24-48dp, 16dp headline->supporting, 24dp supporting->button), capped below
   the base hero's 4.5rem so it never dominates. Doubled class (0,2,0) so it
   beats the responsive .legal-hero rules (0,1,0) later in the file, including
   the min-width:120rem block. */
.legal-hero.legal-hero--tight { padding: var(--cs-xl); margin-bottom: var(--cs-md); }
.legal-hero--tight .legal-hero-title { margin-bottom: var(--cs-md); }   /* ~16dp */
.legal-hero--tight .legal-hero-meta { gap: var(--cs-md); }

/* ── Hero action, sharing the meta row ───────────────────────────────────────
   The Free Live Dashboard button used to sit on a line of its own under the meta,
   which cost the hero a full button height plus its 24dp top margin on every
   content page while the row beside it sat half empty.

   Pure CSS, and it reaches all thirty pages that render _HeroDashboardCta because
   every one of them builds the hero the same way: eyebrow, title, meta, then the
   partial as the last child. Nothing in the markup moves.

   Wide screens only. Below the content breakpoint the meta already wraps to two
   lines and there is no spare width to put a pill in, so the hero keeps stacking
   and the button keeps its own margin. */
@media (min-width: 641px) {
  /* Grid rather than a wrapping flex row. Flex was the obvious reach and the wrong
     one: with flex-wrap a line that does not fit wraps rather than shrinking, so a
     page with a long meta (How to Become a Trader) bounced the button onto its own
     row again, which is the row this exists to remove. Grid places the two in the
     same row by declaration, and minmax(0, 1fr) lets the meta column shrink so its
     own chips wrap instead. */
  .legal-hero--tight {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--cs-lg);
    /* No row-gap. The eyebrow and the title already carry their own bottom margins,
       and adding a gap on top of them gave back almost exactly the height that moving
       the button had saved: the hero came out three pixels shorter than before. */
    row-gap: 0;
  }

  /* Full width, so the meta and the action share the row below them rather than
     being pulled up alongside the title. */
  .legal-hero--tight .legal-hero-eyebrow,
  .legal-hero--tight .legal-hero-title { grid-column: 1 / -1; }

  .legal-hero--tight .legal-hero-meta { grid-column: 1; }
  .legal-hero--tight .legal-hero-cta  { grid-column: 2; justify-self: end; }

  /* Carries .legal-page and the element type because the base rule is
     `.legal-page a.legal-hero-cta`, which outranks a plain two-class selector and
     would otherwise keep its 24dp top margin. */
  .legal-page .legal-hero--tight a.legal-hero-cta,
  .legal-hero--tight .legal-hero-cta { margin-top: 0; }
}

/* MD3 hero primary action: Filled Button, Full (pill) shape, primary/onPrimary
   tokens, hug-content, left-aligned under the supporting text. Mirrors the
   .dash-cta-action pattern; ~24dp spacer above via cs-md. */
/* Doubled selector (.legal-page a.legal-hero-cta) so the onPrimary text colour
   beats the generic ".legal-page a { color: primary }" link rule, which would
   otherwise paint the label primary-cyan on the cyan pill and hide it. Same
   pattern .legal-back uses. */
.legal-hero-cta,
.legal-page a.legal-hero-cta {
  display: inline-flex; align-items: center; gap: 0.55rem;
  margin-top: var(--cs-lg);   /* ~24dp supporting-text -> button */
  padding: 0.65rem 1.3rem; min-height: 2.5rem; box-sizing: border-box;
  border-radius: 999px;
  background: var(--md-primary); color: var(--md-on-primary);
  font-family: var(--font-body); font-weight: 600; font-size: var(--ct-sm);
  letter-spacing: .01em; text-decoration: none;
  transition: filter .15s ease;
}
.legal-hero-cta:hover,
.legal-page a.legal-hero-cta:hover { filter: brightness(1.08); opacity: 1; color: var(--md-on-primary); }
.legal-hero-cta::after { content: '\2192'; font-size: var(--ct-md); }
.legal-hero-cta .eq-bars i { background: var(--md-on-primary); }

/* The whole heatmap is one pane of glass: the same specular ramp as the kiosk
   clock cards, brightest at the top edge, most of the lift spent in the first
   third and gone by 62%, so it reads as glass catching a light source rather
   than a tinted rectangle. A modifier, because .legal-section is shared by
   every content page and must not pick this up. */
.legal-section.wh-panel {
  position: relative;
  overflow: hidden;
  padding: var(--cs-md);
  border-radius: var(--cs-md);
  border: 1px solid var(--md-outline-var);
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .13) 0%,
      rgba(255, 255, 255, .05) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .05);
}
html[data-theme="light"] .legal-section.wh-panel {
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .75) 0%,
      rgba(255, 255, 255, .30) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .45);
}
/* Gated like the kiosk: the blur is the expensive part, so it is opt-in for
   screens that can afford it rather than paid for on every phone. */
@media (min-width: 721px) {
  .legal-section.wh-panel {
    -webkit-backdrop-filter: blur(16px) saturate(150%);
    backdrop-filter: blur(16px) saturate(150%);
  }
}

/* Ambient light under the glass, the kiosk's .mkc-sky idea with this page's
   palette: green, amber and red, the same three colours as the barometer.
   Static rather than phase-driven, since a heatmap has no clock to follow. */
.wh-sky {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.wh-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(58px);
  /* Capped by contrast, not by taste. The tiles are semi-transparent, so the
     blob shows through and lifts the background the numbers sit on. Measured
     worst case (a blob at full strength directly behind the darkest tile):
     .30 gives 4.07 and fails, .20 is 4.52 and only just passes, .18 is 4.62.
     Raising this without re-measuring will quietly break WCAG AA on the tiles. */
  opacity: .18;
}
/* The same low-poly field as the kiosk wall, shared via _FacetField.cshtml.
   currentColor, so light mode gets dark facets on a pale field rather than
   white ones vanishing. The svg opacity is the single dial for the whole
   effect: the polygons carry their own spread and are tuned there. */
.wh-facets { position: absolute; inset: 0; }
.wh-facets svg {
  display: block; width: 100%; height: 100%;
  color: var(--md-on-surface);
  /* Kiosk parity, same as the clocks page: the polygon opacities are tuned for
     a dial of 1 and anything lower makes the field invisible. Affordable here
     only because the tiles are now near-opaque, so the facets no longer reach
     the numerals. Measured worst case 5.55 with this at full strength. */
  opacity: 1;
}
.wh-blob--1 { width: 18rem; height: 18rem; left: -4rem;  top: -5rem;    background: #1AA09F; }
.wh-blob--2 { width: 20rem; height: 20rem; right: -5rem; top: 20%;      background: #BF6A65; }
.wh-blob--3 { width: 17rem; height: 17rem; left: 42%;    bottom: -7rem; background: #d7a52b; }
/* Content rides above the blobs. Without this the sky paints over the tiles,
   because it is the only positioned child of the panel. */
.legal-section.wh-panel > *:not(.wh-sky) { position: relative; z-index: 1; }

.wh-region { margin: var(--cs-sm) 0 0; }
.wh-region:first-child { margin-top: 0; }
.wh-region-head {
  font-family: var(--font-body);
  font-size: var(--ct-sm); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--md-on-surface-var);
  margin: 0 0 var(--cs-xs);
}
/* Footnote as a tonal surface rather than a trailing italic line: it defines
   what a tile IS, so it belongs to the board. Scoped modifier on purpose, the
   bare .ai-note on the seven other pages is a genuine aside and unchanged. */
.ai-note--panel {
  margin-top: var(--cs-md);
  padding: var(--cs-sm) var(--cs-md);
  border-radius: var(--cs-xs);
  background: var(--md-surf-1);
  border: 1px solid var(--md-outline-var);
}

/* Board = tiles plus the barometer beside them. */
.wh-board { display: flex; align-items: stretch; gap: var(--cs-md); }
.wh-board-main { flex: 1 1 auto; min-width: 0; }

/* Vertical read of the whole board. Green sits at the top because the tiles are
   green when up, so the axis matches the grid and needs no legend. Same +/-2.5%
   saturation as the tile colours, so needle and colours never disagree. */
.wh-baro {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center;
  gap: var(--cs-2xs);
  width: 3.75rem;
  padding: var(--cs-2xs) 0;
}
/* Word ends, like the Markets Today arc, so both barometers read as one
   instrument. The number stays a real percentage rather than an invented
   0-100 score: a reader can check it against the tiles beside it. */
.wh-baro-cap {
  text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
}
.wh-baro-track {
  position: relative;
  flex: 1 1 auto;
  width: 10px;
  min-height: 8rem;
  border-radius: 999px;
  background: linear-gradient(180deg, #1AA09F 0%, #d7a52b 50%, #BF6A65 100%);
}
.wh-baro-marker {
  position: absolute;
  left: 50%; bottom: var(--wh-pos, 50%);
  width: 1.125rem; height: 1.125rem;
  transform: translate(-50%, 50%);
  border-radius: 50%;
  background: var(--md-surf-1);
  border: 3px solid var(--md-on-background);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
  transition: bottom .6s cubic-bezier(.2, 0, 0, 1);
}
.wh-baro-cap, .wh-baro-val {
  font-family: var(--font-mono); font-size: var(--ct-2xs);
  color: var(--md-on-surface-var); white-space: nowrap;
}
.wh-baro-val { font-weight: 700; color: var(--md-on-surface); }
@media (prefers-reduced-motion: reduce) { .wh-baro-marker { transition: none; } }

.wh-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.55rem;
  /* Size each tile to its own content; the grid default (stretch) padded shorter
     tiles up to the tallest in the row, which read as dead space. */
  align-items: start;
}
.wh-tile {
  display: flex; flex-direction: column; gap: 0.2rem;
  padding: 0.8rem 0.95rem;
  border-radius: var(--cs-xs);
  border: 1px solid var(--md-outline-var);
  background: var(--md-surf-1);
  transition: transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s,
              background-color .45s cubic-bezier(.2,0,0,1),
              border-color .45s cubic-bezier(.2,0,0,1);
}
.wh-tile:hover { transform: scale(1.03); box-shadow: 0 6px 18px rgba(0,0,0,.25); }
/* Two columns on a phone, and the desktop breathing room is handed back: at
   375px the wider padding costs tile width, the one thing a 2-column grid
   cannot spare. Must sit after the .wh-tile base rule, same specificity. */
@media (max-width: 720px) {
  .wh-grid { grid-template-columns: repeat(2, 1fr); gap: 0.4rem; }
  .wh-tile { padding: 0.6rem 0.8rem; }
  .ai-note--panel { padding: var(--cs-sm); }
  /* The barometer turns horizontal and sits above the grid. Vertical cost the
     tiles 40% of their width (names wrapped) and stretched the bar to the full
     height of all three regions, roughly 950px. Across the top it costs one
     row of height, keeps its labels, and leaves the grid full width. */
  .wh-board { flex-direction: column-reverse; gap: var(--cs-sm); }
  .wh-baro {
    /* Reversed so SELLOFF sits at the red end and RALLY at the green end. */
    flex-direction: row-reverse;
    align-items: center;
    width: auto;
    gap: var(--cs-xs);
    padding: 0;
  }
  .wh-baro-track {
    width: auto; height: 8px; min-height: 0;
    background: linear-gradient(90deg, #BF6A65 0%, #d7a52b 50%, #1AA09F 100%);
  }
  .wh-baro-marker {
    width: 1rem; height: 1rem; border-width: 2px;
    left: var(--wh-pos, 50%); bottom: 50%;
    transform: translate(-50%, 50%);
    transition: left .6s cubic-bezier(.2, 0, 0, 1);
  }
  .wh-baro-val { order: -1; }
}
.wh-tile-name {
  font-family: var(--font-body);
  font-size: 0.875rem; font-weight: 700; letter-spacing: .01em; line-height: 1.25;
  color: var(--md-on-surface);
}
.wh-tile-pct {
  font-family: var(--font-mono);
  font-size: 1.0625rem; font-weight: 700; line-height: 1.1;
}
/* The tile background already carries direction and size, and the arrow carries
   direction again for anyone who cannot separate red from green. Tinting the
   number too put green on green: every tile failed 4.5:1, worst 2.80 on the
   biggest mover, because the tint deepens with the move while the text colour
   stayed fixed. The number is the thing you read, so it takes the on-surface
   colour and clears the bar on every tile in both themes. */
/* Fixed light, not a theme token. The tint is written inline by both renderers
   and is the same deep colour in either theme, so a token that flips dark in
   light mode would put dark text on a dark green tile. A tinted tile is always
   a dark surface, so its text is always light. Flat tiles carry no tint and
   keep the tokens. */
.wh-tile.up .wh-tile-name, .wh-tile.dn .wh-tile-name,
.wh-tile.up .wh-tile-pct,  .wh-tile.dn .wh-tile-pct  { color: #f2f5f6; }
.wh-tile.up .wh-tile-meta, .wh-tile.dn .wh-tile-meta { color: rgba(242, 245, 246, .88); }
.wh-tile.flat .wh-tile-pct { color: var(--md-on-surface-var); }
.wh-tile-meta {
  font-family: var(--font-mono);
  font-size: var(--ct-xs); color: var(--md-on-surface-var);
}
.wh-loading, .wh-meta { color: var(--md-on-surface-var); font-size: var(--ct-sm); }
.wh-status { display: flex; align-items: center; gap: var(--cs-sm); margin-bottom: var(--cs-md); flex-wrap: wrap; }
.wh-live {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.2rem 0.6rem; border-radius: 2rem;
  font-family: var(--font-mono); font-size: var(--ct-xs);
  font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  border: 1px solid var(--md-outline-var);
}
.wh-live-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.wh-live.is-open { color: #1AA09F; border-color: rgba(46,160,67,.4); }
.wh-live.is-open .wh-live-dot { background: #1AA09F; animation: wh-live-pulse 1.8s ease-in-out infinite; }
.wh-live.is-closed { color: var(--md-on-surface-var); }
.wh-live.is-closed .wh-live-dot { background: var(--md-on-surface-var); }
html[data-theme="light"] .wh-live.is-open { color: #135c28; }
@keyframes wh-live-pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) { .wh-live-dot { animation: none !important; } }
.wh-status .wh-meta { margin: 0; }

/* ── Period toggle (Today / 7 days) ──────────────────────────────────────────
   MD3 Expressive segmented button. Two separate pills rather than one divided
   container: Expressive carries selection in SHAPE, and a shared container with
   a hairline divider cannot morph its segments independently.

   Type is Label Large (14sp), not a --dt-* clamp. Those are for ticker and data
   density; this is a control the reader taps and must stay at reading size.

   The selected pill morphs from a full radius to an asymmetric one and lifts
   slightly, matching the footer-link treatment on the dashboard so the site has
   one expressive idiom rather than two. */
.wh-period {
  display: inline-flex;
  gap: 0.375rem;
  margin-left: auto;
}
.wh-period-btn {
  appearance: none;
  background: transparent;
  border: 1px solid var(--md-hairline, rgba(0, 0, 0, .22));
  border-radius: var(--shape-full, 6.25rem);
  color: var(--md-on-surface-variant, var(--md-on-surface));
  font-family: inherit;
  font-size: 0.875rem;         /* Label Large */
  font-weight: 600;
  line-height: 1.25rem;
  letter-spacing: 0.00625rem;
  padding: 0.5rem 1.125rem;    /* 2.5rem tall: a real touch target */
  cursor: pointer;
  transform-origin: center;
  transition: background .28s cubic-bezier(0.175, 0.885, 0.32, 1.275),
              color .18s ease,
              border-radius .28s cubic-bezier(0.175, 0.885, 0.32, 1.275),
              transform .28s cubic-bezier(0.175, 0.885, 0.32, 1.275),
              border-color .18s ease;
}
.wh-period-btn:hover {
  background: color-mix(in srgb, var(--md-primary) 12%, transparent);
  border-color: color-mix(in srgb, var(--md-primary) 45%, transparent);
  color: var(--md-on-surface);
}
.wh-period-btn:focus-visible {
  outline: 0.125rem solid var(--md-primary);
  outline-offset: 0.125rem;
}
.wh-period-btn:active { transform: scale(0.96); }

/* Selected: filled, heavier, and shape-morphed. The asymmetric radius is the
   expressive signal; colour alone would leave the state invisible to anyone
   who cannot separate the two fills. */
.wh-period-btn.is-active {
  background: var(--md-primary);
  border-color: var(--md-primary);
  color: var(--md-on-primary);
  font-weight: 700;
  border-radius: 0.375rem 1.25rem 0.375rem 1.25rem;
  transform: scale(1.04);
  box-shadow: var(--md-elev-1, 0 0.0625rem 0.1875rem rgba(0, 0, 0, .28));
}
.wh-period-btn.is-active:hover {
  background: var(--md-primary);
  color: var(--md-on-primary);
}

/* Motion is the decoration here, not the information: the fill and the radius
   still distinguish the states with the animation removed. */
@media (prefers-reduced-motion: reduce) {
  .wh-period-btn { transition: background .01s linear, color .01s linear; }
  .wh-period-btn.is-active,
  .wh-period-btn:active { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   FORMULA CALLOUT - shaded box for the one line worth remembering
══════════════════════════════════════════════════════════════════════ */
.pai-formula {
  margin: var(--cs-md) 0;
  padding: var(--cs-md) var(--cs-lg);
  background: var(--md-primary-container);
  color: var(--md-on-primary-cont);
  border-radius: var(--cs-xs);
  font-size: var(--ct-lg);
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
}

/* ══════════════════════════════════════════════════════════════════════
   PULL QUOTE - tonal surface, primary accent rule (MD3 expressive)
══════════════════════════════════════════════════════════════════════ */
.pai-quote {
  margin: var(--cs-lg) 0;
  padding: var(--cs-md) var(--cs-lg);
  background: var(--md-surf-2);
  border-left: 3px solid var(--md-primary);
  border-radius: var(--cs-xs);
}
.pai-quote p {
  margin: 0;
  font-size: var(--ct-lg);
  line-height: 1.5;
  font-style: italic;
  color: var(--md-on-surface);
}
.pai-quote cite {
  display: block;
  margin-top: var(--cs-sm);
  font-size: var(--ct-sm);
  font-style: normal;
  font-weight: 600;
  color: var(--md-on-surface-var);
}

/* ══════════════════════════════════════════════════════════════════════
   ERROR PAGE
══════════════════════════════════════════════════════════════════════ */
.err-wrap {
  max-width: 40rem;
  margin: 0 auto;
  padding: var(--cs-xl) var(--cs-md);
  text-align: center;
}
.err-code {
  font-size: clamp(4.5rem, 16vw, 7.5rem);
  font-weight: 900; line-height: 1;
  color: var(--loss); opacity: .18;
  letter-spacing: -.04em; user-select: none;
}
.err-icon {
  font-size: 3rem;
  margin: var(--cs-lg) 0 var(--cs-md);
  color: var(--loss);
}
.err-title {
  font-size: clamp(1.25rem, 4vw, 1.75rem);
  font-weight: 800; color: var(--md-on-surface);
  margin-bottom: var(--cs-xs);
}
.err-sub {
  font-size: var(--ct-md);
  color: var(--md-on-surface-var);
  line-height: 1.6; margin-bottom: var(--cs-xl);
}
.err-card {
  background: var(--md-outline-var);
  border: 1px solid var(--md-outline-var);
  border-radius: 0.75rem;
  padding: var(--cs-lg); margin-bottom: var(--cs-xl);
  text-align: left;
}
.err-card-label {
  font-size: var(--ct-2xs); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--md-on-surface-var); margin-bottom: var(--cs-xs);
}
.err-request-id {
  font-family: monospace; font-size: var(--ct-xs);
  color: var(--md-primary); word-break: break-all;
}
.err-home {
  display: inline-flex; align-items: center; gap: var(--cs-xs);
  padding: 0.75rem 1.75rem; border-radius: 1.5rem;
  background: var(--md-primary); color: var(--md-on-primary);
  font-size: var(--ct-base); font-weight: 700;
  text-decoration: none; transition: opacity .15s;
}
.err-home:hover { opacity: .85; }

/* ══════════════════════════════════════════════════════════════════════
   RESPONSIVE BREAKPOINTS
   xs   < 30rem  (480px)   small mobile
   sm   < 48rem  (768px)   mobile
   md   < 80rem  (1280px)  tablet, base styles cover this range
   lg   ≥ 80rem  (1280px)  large desktop
   xl   ≥ 120rem (1920px)  1440p / QHD
   2xl  ≥ 160rem (2560px)  4K / UHD
══════════════════════════════════════════════════════════════════════ */

/* ── xs, small mobile (< 480px) ───────────────────────────────────── */
@media (max-width: 30rem) {
  /* Layout */
  .legal-page   { padding: 0 var(--cs-sm) var(--cs-xl); }
  .legal-hero   { padding: var(--cs-lg) var(--cs-md); }
  .legal-section { padding: var(--cs-md) var(--cs-lg); }
  .legal-section-header { flex-direction: column; gap: var(--cs-xs); }
  .legal-contact { flex-direction: column; text-align: center; gap: var(--cs-md); }
  .legal-contact-icon { margin: 0 auto; }
  .legal-toc    { padding: var(--cs-md) var(--cs-lg); }
  .legal-toc ol { grid-template-columns: 1fr; }

  /* Hero text */
  .legal-hero-eyebrow { font-size: var(--ct-2xs); }
  .legal-hero-meta    { gap: var(--cs-sm); flex-wrap: wrap; }

  /* Support buttons, stack vertically */
  .support-links  { flex-direction: column; }
  .support-btn    { width: 100%; justify-content: flex-start; }

  /* About */
  .about-feature-grid { grid-template-columns: 1fr; }
  .content-footer     { grid-template-columns: 1fr; padding: 1rem; }

  /* Visitor analytics */
  .va-wrap         { padding: var(--cs-md) var(--cs-sm); }
  .va-kpi-grid     { grid-template-columns: repeat(2, 1fr); gap: var(--cs-sm); }
  .va-kpi          { padding: var(--cs-sm) var(--cs-md); }
  .va-kpi-value    { font-size: clamp(1.5rem, 7vw, 2rem); }
  .va-breakdown-grid { grid-template-columns: 1fr; }
  .va-bar-label    { width: 6.5rem; font-size: var(--ct-xs); }
  .va-table th, .va-table td { padding: 0.375rem 0.5rem; font-size: var(--ct-xs); }
  .va-table td     { max-width: 8rem; }

  /* Content tables are a communication surface, not an admin grid: the dense
     va-table clamp above drops to 10-12px, well under the surrounding prose.
     Restore MD3 body sizing and padding for .md3-table-card only. */
  .md3-table-card td { padding: 0.7rem 0.8rem; font-size: var(--ct-base); max-width: none; }
  .md3-table-card th { padding: 0.7rem 0.8rem; font-size: var(--ct-sm); }
  .md3-table-card td:first-child,
  .md3-table-card th:first-child { max-width: 7.5rem; }

  /* Affiliates, horizontal scroll, tighter cells */
  .aff-mgmt-table  { font-size: var(--ct-2xs); }
  .aff-mgmt-table th, .aff-mgmt-table td { padding: 0.375rem 0.5rem; }
  .aff-td-notes    { max-width: 6rem; }

  /* Comparison table */
  .cmp-table       { font-size: var(--ct-2xs); }
  .cmp-table th, .cmp-table td { padding: 0.25rem 0.375rem; }

  /* Data / content tables */
  .ds-table        { font-size: var(--ct-2xs); }
  .ds-table th, .ds-table td { padding: 0.25rem 0.375rem; }

  /* Error page */
  .err-wrap        { padding: var(--cs-lg) var(--cs-sm); }
  .err-home        { width: 100%; justify-content: center; }
}

/* ── sm, mobile (< 768px) ─────────────────────────────────────────── */
@media (max-width: 48rem) {
  /* Layout */
  .legal-page     { padding: 0 var(--cs-md) var(--cs-xl); }
  .legal-hero     { padding: var(--cs-xl) var(--cs-lg) var(--cs-lg); }
  .legal-section  { padding: var(--cs-lg) var(--cs-xl); }
  .legal-toc ol   { grid-template-columns: 1fr; }
  .legal-contact  { flex-direction: column; text-align: center; gap: var(--cs-md); }
  .legal-contact-icon { margin: 0 auto; }

  /* Hero */
  .legal-hero-title { font-size: clamp(1.25rem, 5vw, 1.75rem); }
  .legal-hero-meta  { gap: var(--cs-sm); }

  /* Support */
  .support-links  { gap: var(--cs-sm); }

  /* Visitor analytics */
  .va-kpi-grid    { grid-template-columns: repeat(3, 1fr); gap: var(--cs-sm); }
  .va-kpi-value   { font-size: clamp(1.75rem, 5vw, 2.5rem); }
  .va-breakdown-grid { grid-template-columns: 1fr; }
  .va-bar-label   { width: 7.5rem; }
  .va-table th, .va-table td { padding: 0.4375rem 0.625rem; }

  /* Affiliates */
  .aff-mgmt-table { font-size: var(--ct-xs); }
  .aff-mgmt-table th, .aff-mgmt-table td { padding: 0.5rem 0.625rem; }

  /* Comparison table */
  .cmp-table      { font-size: var(--ct-xs); }
  .cmp-table th, .cmp-table td { padding: var(--cs-2xs) var(--cs-xs); }

  /* Data / content tables */
  .ds-table       { font-size: var(--ct-xs); }
  .ds-table th, .ds-table td { padding: var(--cs-2xs) var(--cs-xs); }
}

/* ── md, tablet / small desktop (< 1280px), base styles cover this ─ */

/* ── lg, large desktop (≥ 1280px) ─────────────────────────────────── */
@media (min-width: 80rem) {
  :root {
    --content-w:      min(80vw, 72rem);
    --content-w-wide: min(88vw, 100rem);
  }
  .legal-section      { padding: var(--cs-xl) var(--cs-2xl); }
  .about-feature-grid { grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
  .va-breakdown-grid  { grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); }
  .va-kpi-grid        { grid-template-columns: repeat(5, 1fr); }
}

/* ── xl, 1440p / QHD (≥ 1920px) ──────────────────────────────────── */
@media (min-width: 120rem) {
  :root {
    --content-w:      min(70vw, 80rem);
    --content-w-wide: min(82vw, 112rem);
  }
  .legal-hero         { padding: var(--cs-2xl); }
  .va-kpi-grid        { gap: var(--cs-lg); }
  .va-breakdown-grid  { grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr)); }
  .aff-mgmt-table th, .aff-mgmt-table td { padding: 0.875rem 1rem; }
}

/* ── 2xl, 4K / UHD (≥ 2560px) ────────────────────────────────────── */
@media (min-width: 160rem) {
  :root {
    --content-w:      min(60vw, 90rem);
    --content-w-wide: min(72vw, 130rem);
  }
  .legal-section      { padding: var(--cs-2xl); }
  .about-feature-grid { grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
  .va-kpi-grid        { gap: var(--cs-xl); }
  .va-kpi             { padding: var(--cs-lg) var(--cs-xl); }
  .va-kpi-value       { font-size: clamp(3rem, 4vw, 4rem); }
  .va-breakdown-grid  { grid-template-columns: repeat(auto-fit, minmax(26rem, 1fr)); }
  .aff-mgmt-table th, .aff-mgmt-table td { padding: 1rem 1.25rem; }
  .va-table th, .va-table td { padding: 0.75rem 1rem; font-size: var(--ct-base); }
}

/* ══════════════════════════════════════════════════════════════════════
   MARKETS TODAY (/markets-today)
   The daily brief page. MD3 Expressive: tonal container per brief, a
   primary-coloured overline, display type for the headline and a shape
   scale that matches .legal-hero. Session chips reuse .wh-live.
   ══════════════════════════════════════════════════════════════════════ */

/* Row of open/closed chips under the hero. Layout only: the chips
   themselves are the shared .wh-live component. */
.mtd-sessions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cs-xs);
  justify-content: center;
  margin: 0 0 var(--cs-lg);
}

/* Times swapped to the reader's zone by markets-today.js. The dotted rule
   hints that the value is localised rather than fixed. */
.mtd-time {
  font-family: var(--font-mono);
  border-bottom: 1px dotted var(--md-outline-var);
}

.mtd-empty {
  padding: var(--cs-md);
  background: var(--md-surf-2);
  border-radius: var(--shape-lg);
  color: var(--md-on-surface-var);
}

/* ── One brief ───────────────────────────────────────────────────────── */
/* Tonal surface rather than an outlined card: MD3 Expressive leans on
   colour rather than borders to separate a block from the page. */
.mtd-brief {
  position: relative;
  background: var(--md-surf-2);
  border-radius: var(--shape-xl);          /* shape.corner.extra-large, as .legal-hero */
  padding: var(--cs-lg) var(--cs-lg) var(--cs-md);
  margin: 0 0 var(--cs-lg);
  overflow: hidden;
}

/* Expressive accent edge, echoing the .legal-section top gradient. */
.mtd-brief::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: linear-gradient(180deg, var(--md-primary), var(--md-secondary));
}

.mtd-brief-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cs-xs);
  margin-bottom: var(--cs-xs);
}

.mtd-brief-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--md-primary);
}

.mtd-brief-time {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
}

/* Headline carries the page: display face, large role, balanced wrap. */
.mtd-brief-headline {
  font-family: var(--font-display);
  font-size: var(--ct-lg);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -.01em;
  color: var(--md-on-background);
  margin: 0 0 var(--cs-xs);
  text-wrap: balance;
}

.mtd-brief-summary {
  font-size: var(--ct-md);
  line-height: 1.6;
  color: var(--md-on-surface);
  margin: 0 0 var(--cs-md);
}

.mtd-brief-block { margin-bottom: var(--cs-sm); }
.mtd-brief-block p { margin: 0; }

.mtd-brief-block-title {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
  margin-bottom: var(--cs-2xs);
}

/* ── World table ─────────────────────────────────────────────────────── */
.mtd-region { margin-bottom: var(--cs-lg); }

.mtd-region-title {
  font-family: var(--font-display);
  font-size: var(--ct-md);
  font-weight: 700;
  color: var(--md-on-background);
  margin: 0 0 var(--cs-xs);
}

/* Wide tables scroll inside their own box so the page never scrolls sideways. */
.mtd-table-wrap {
  overflow-x: auto;
  border-radius: var(--shape-lg);
  border: 1px solid var(--md-outline-var);
}

.mtd-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--ct-sm);
}

.mtd-table th,
.mtd-table td {
  padding: var(--cs-xs) var(--cs-sm);
  text-align: left;
  white-space: nowrap;
}

.mtd-table th {
  background: var(--md-surf-2);
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
}

.mtd-table tbody tr + tr td { border-top: 1px solid var(--md-outline-var); }

.mtd-table td:nth-child(2),
.mtd-table td:nth-child(3) { font-family: var(--font-mono); text-align: right; }

.mtd-table th:nth-child(2),
.mtd-table th:nth-child(3) { text-align: right; }

.mtd-ticker {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
  margin-left: .35rem;
}

/* Same greens and reds the world heatmap uses, including its light-theme
   contrast fix, so a rise looks identical across the site. */
.mtd-up   { color: var(--gain); }
.mtd-down { color: var(--loss); }

@media (max-width: 640px) {
  .mtd-brief { padding: var(--cs-md) var(--cs-md) var(--cs-sm); }
  .mtd-brief-head { flex-direction: column; align-items: flex-start; gap: var(--cs-2xs); }
}

/* ── Market temperature, the day-arc ─────────────────────────────────────
   One 0-100 reading per session plotted on a shared track, so the reader
   sees the mood handed from Tokyo to London to New York rather than a
   single snapshot. Marker positions come from a dynamic style binding
   (style="@left"), which is data, not styling. */
.mtd-arc {
  background: var(--md-surf-2);
  border-radius: var(--shape-xl);
  padding: var(--cs-md) var(--cs-lg) var(--cs-md);
  margin: 0 0 var(--cs-lg);
}

.mtd-arc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cs-sm);
  margin-bottom: var(--cs-sm);
}

.mtd-arc-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--md-primary);
}

.mtd-arc-tone {
  font-family: var(--font-display);
  font-size: var(--ct-lg);
  font-weight: 700;
  line-height: 1.15;
  color: var(--md-on-background);
}

/* Expressive focal number: large, tabular, quiet in colour so the tone
   word stays the headline and the digits support it. */
/* The reading, and the loudest thing in the card. Underscored with the temperature
   gradient so the number carries its own scale: an expressive accent that means
   something rather than decoration. */
.mtd-arc-value {
  font-family: var(--font-mono);
  font-size: var(--ct-xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--md-on-surface);
  padding-bottom: .2em;
  border-bottom: 3px solid transparent;
  border-image: linear-gradient(90deg, #1AA09F, #d7a52b) 1;
}

/* The scale itself. Same reds and greens as the heatmap, so a rise reads
   the same everywhere on the site. */
/* ── The daily temperature chart ─────────────────────────────────────────────
   Was a horizontal value bar with a marker per reading, which suited the three or
   four readings of one day. Ten days broke it: the temperature moves little from
   day to day, so a fortnight of points landed inside a fifteen-percent band of the
   track and their labels overlapped. Time on the x axis fixes that by construction,
   the spacing no longer depends on the values at all. */
/* Positioning context for the axis labels, which are HTML rather than SVG text so
   they keep a real font size at every width. Bottom padding is the day-number row. */
.mtd-arc-plot {
  position: relative;
  margin: var(--cs-lg) 0 var(--cs-sm);
  padding-bottom: 1.6rem;
}

.mtd-arc-chart {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* A tonal surface behind the plot, one step up from the card, so the chart reads as
   its own object rather than ink floating on the card. */
.mtd-arc-panel {
  fill: color-mix(in srgb, var(--md-on-surface) 4%, transparent);
  stroke: var(--md-outline-var);
  stroke-opacity: .35;
  stroke-width: 1;
}

.mtd-arc-grid {
  stroke: var(--md-outline-var);
  stroke-width: 1;
  stroke-dasharray: 3 5;
  opacity: .45;
}

/* Balanced is the reference the eye should find first, so it is the solid one. */
.mtd-arc-grid.is-mid { stroke-dasharray: none; opacity: .7; }

/* The scale as colour: green at confident, amber at balanced, red at nervous. Gives
   the band labels something to be anchored to rather than floating in the margin. */
.mtd-arc-bar { opacity: .9; }

/* Band names in the right gutter the chart reserves for them (PadR in the markup),
   centred on their own gridline. */
.mtd-arc-band {
  position: absolute;
  right: 0;
  transform: translateY(-50%);
  font-size: var(--ct-xs);
  letter-spacing: .02em;
  color: var(--md-on-surface-var);
  white-space: nowrap;
  pointer-events: none;
}

/* The value carries its band's colour, so the label and the bar beside it are saying
   the same thing twice, which is what makes the bar legible without a legend. */
.mtd-arc-band-v { font-family: var(--font-mono); font-weight: 700; }
.mtd-arc-band-v.is-hi  { color: var(--gain); }
.mtd-arc-band-v.is-mid { color: var(--amber); }
.mtd-arc-band-v.is-lo  { color: var(--loss); }

/* Day numbers under their points, on the row the container's padding reserves. */
.mtd-arc-day {
  position: absolute;
  bottom: 0;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  color: var(--md-on-surface-var);
  pointer-events: none;
}

.mtd-arc-axis {
  margin: 0 0 var(--cs-xs);
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
}

/* The chart said in words, for a reader who does not read charts. */
.mtd-arc-read {
  margin: 0 0 var(--cs-xs);
  font-size: var(--ct-sm);
  line-height: 1.55;
  color: var(--md-on-surface);
}
.mtd-arc-read strong { font-family: var(--font-mono); }

/* Colour comes from the gradient in the markup, which needs explicit stops rather
   than tokens; this only keeps the shape from taking a stroke. */
.mtd-arc-area { stroke: none; }

.mtd-arc-line {
  fill: none;
  stroke: var(--md-primary);
  stroke-width: 2.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* Light core, primary ring. Big enough to read as the data rather than as a joint in
   the line, which is what the 4px version looked like. */
.mtd-arc-pt circle {
  fill: color-mix(in srgb, var(--md-primary) 18%, var(--md-surf-1));
  stroke: var(--md-primary);
  stroke-width: 2.5;
}

/* The newest reading is the one that matters now, so it is solid and haloed. */
.mtd-arc-pt.is-latest circle {
  fill: var(--md-primary);
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--md-primary) 55%, transparent));
}

/* The day numbers moved out of the SVG into .mtd-arc-day, and .mtd-arc-scale went
   with the old horizontal value bar, so neither has markup any more. */
.mtd-arc-day.is-latest { color: var(--md-on-surface); }

/* ── Overnight shift ─────────────────────────────────────────────────────────
   Where the temperature actually moves: a median of 17 points between one day's
   settled reading and the next morning's, against 1.5 within a day. Stated plainly
   every day, because the number itself is the information, and only given the
   accent treatment on a big move, so the emphasis keeps its meaning. */
.mtd-arc-shift {
  margin: 0 0 var(--cs-sm);
  font-size: var(--ct-sm);
  line-height: 1.55;
  color: var(--md-on-surface-var);
}

.mtd-arc-shift strong { color: var(--md-on-surface); }

.mtd-arc-shift.is-big {
  padding: var(--cs-xs) var(--cs-sm);
  border-left: 3px solid var(--md-primary);
  border-radius: 0 var(--shape-sm, .5rem) var(--shape-sm, .5rem) 0;
  background: color-mix(in srgb, var(--md-primary) 8%, transparent);
  color: var(--md-on-surface);
}

.mtd-arc-note {
  font-size: var(--ct-sm);
  line-height: 1.55;
  color: var(--md-on-surface-var);
  margin: 0;
}

/* The weights read as figures rather than prose, so the eye can pick out what the
   number is made of without reading the sentence. */
.mtd-arc-note strong {
  font-family: var(--font-mono);
  color: var(--md-on-surface);
}

.mtd-arc-note a { white-space: nowrap; }

/* ── The read on the tape (AI Mood lede) ─────────────────────────────────────
   Sits directly under .mtd-arc and shares its surface and radius so the two read
   as one unit: the arc gives the number, this gives the opinion. The leading
   primary rule is the only thing separating them, marking this as commentary
   rather than a second measurement. */
.mtd-mood {
  background: var(--md-surf-2);
  border-left: 0.1875rem solid var(--md-primary);
  border-radius: var(--shape-xl);
  padding: var(--cs-md) var(--cs-lg);
  margin: 0 0 var(--cs-lg);
}

.mtd-mood-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cs-sm);
  flex-wrap: wrap;
  margin-bottom: var(--cs-sm);
}

/* Same treatment as .mtd-arc-eyebrow. It is an h2 here rather than a div, because
   it heads a real section and the page outline should say so; the margin reset
   keeps it rendering exactly as the eyebrow beside it. */
.mtd-mood-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--md-primary);
  margin: 0;
}

.mtd-mood-meta {
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
}

/* Body Large: this is the one piece of prose on the page written to be read as a
   voice rather than scanned, so it sits a step above the surrounding copy. */
.mtd-mood-text {
  font-size: var(--ct-md);
  line-height: 1.6;
  color: var(--md-on-surface);
  margin: 0 0 var(--cs-sm);
}

.mtd-mood-note {
  font-size: var(--ct-xs);
  line-height: 1.5;
  color: var(--md-on-surface-var);
  margin: 0;
}

@media (max-width: 640px) {
  .mtd-mood { padding: var(--cs-md); }
}

@media (max-width: 640px) {
  .mtd-arc { padding: var(--cs-md); }

  /* The chart reserves a fixed share of its width for band names, which is about 50px
     here, so the words are dropped and only the values label the axis. The words are
     still in the caption directly beneath. */
  .mtd-arc-band-name { display: none; }

  /* Fourteen day labels sit about 17px apart on a phone, which two digits very nearly
     fill, so every second one goes. The dots all stay: the shape of the line is the
     point, and the caption still gives the date range at both ends. Marked from the end
     of the series, so the latest day always keeps its label. */
  .mtd-arc-day.is-thinnable { display: none; }
  .mtd-arc-head { align-items: flex-start; }
}

/* ── /is-the-market-open: exchange clocks ──────────────────────────────────────
   Phase is carried three ways on purpose: dial colour, the tonal chip, and the
   text label. Colour alone would fail in greyscale and for colourblind readers,
   and this page's whole job is being unambiguous about open versus closed.
   Every colour resolves through the shared tokens, so light and dark both work
   without a second stylesheet. ------------------------------------------------ */

/* Phase colours are literal here, not token aliases, and identical in both themes.
   The wall is read as an instrument at a glance, often across a room on a spare monitor,
   so the mint and the amber are the page's own signal rather than the dashboard's
   gain green and callout tan, which shift per theme and were tuned for text. */
.mkc-page {
  --mkc-open:    #57e5c6;
  --mkc-edge:    #dc9f59;
  --mkc-lunch:   var(--md-primary);
  --mkc-shut:    var(--md-outline);
  /* Sized so three rows of four plus the header and legend clear a 900px viewport without
     scrolling, which is the whole promise of the page. */
  --mkc-dial:    5.875rem;
}

/* No hero on this page: the clocks are the content and a tall hero pushed all twelve below
   the fold. The header is two lines total, the question and then the answer, because every
   line here costs a row of clocks. */
.mkc-head { margin: 0 0 var(--cs-sm); }

.mkc-head .legal-hero-title {
  font-size: var(--ct-lg);
  line-height: 1.25;
  margin: 0 0 .15rem;
}

/* Answer and status on one line, baseline aligned, wrapping only when they truly cannot fit. */
.mkc-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .35rem var(--cs-sm);
}

.mkc-status {
  font-size: var(--ct-xs);
  color: var(--md-outline);
  font-variant-numeric: tabular-nums;
  margin: 0;
  white-space: nowrap;
}

/* isolation so the blurred sky behind the cards cannot bleed over neighbouring sections. */
.mkc-wall {
  position: relative;
  isolation: isolate;
  margin: 0 0 var(--cs-md);
  padding: var(--cs-xs);
  border-radius: 1.75rem;
  overflow: hidden;
}

/* The light the glass refracts. Hue is set by market-clocks.js from the UTC hour. */
.mkc-sky {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.mkc-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(58px);
  opacity: .42;
  transition: background 2s linear;
}

/* The wall's facet field, behind the counters on the ordinary page too, so the
   page reads the same on a laptop as on the display. Shared geometry lives in
   _FacetField.cshtml; this only sets hue and overall strength. Held below the
   kiosk's full strength because these cards are glass and the facets show
   through onto the countdown text. */
.mkc-sky-facets { position: absolute; inset: 0; }
.mkc-sky-facets svg {
  display: block; width: 100%; height: 100%;
  color: var(--md-on-surface);
  /* Kiosk parity. The polygon opacities (.010 to .130) are tuned for a dial of
     1: anything lower multiplies the brightest facet below 8% white and the
     field stops being visible at all. */
  opacity: 1;
}

.mkc-blob--1 { width: 18rem; height: 18rem; left: -3rem;  top: -4rem; }
.mkc-blob--2 { width: 20rem; height: 20rem; right: -4rem; top: 2rem; }
.mkc-blob--3 { width: 19rem; height: 19rem; left: 38%;    bottom: -6rem; }

/* Offset sits under the city as a quiet attribute of the place, not of the countdown. */
/* --md-outline is the token for borders and disabled text. These two lines are
   content: the offset tells you which day you are looking at, and the boundary is
   what the countdown is counting to. Both read as greyed out against a glass card,
   in every mode, so they move a step up the surface ramp. Size stays as it was on
   the dense twelve-card grid, where the whole page fitting one screen is the
   promise; the showcase sizes are set separately. */
.mkc-offset {
  font-size: var(--ct-2xs);
  color: var(--md-on-surface-var);
  margin: 0 0 var(--cs-2xs);
}

.mkc-answer {
  font-size: var(--ct-base);
  line-height: 1.35;
  color: var(--md-on-surface);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.mkc-empty {
  font-size: var(--ct-base);
  line-height: 1.6;
  color: var(--md-on-surface-var);
  background: var(--md-surf-2);
  border-radius: 1rem;
  padding: var(--cs-md);
}

/* MD3 title-small with a rule that runs to the edge. Used by the session map heading. */
.mkc-region-title {
  display: flex;
  align-items: center;
  gap: var(--cs-sm);
  font-size: var(--ct-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--md-outline);
  margin: 0 0 var(--cs-xs);
}

.mkc-region-title::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--md-hairline);
}

/* auto-fill, not auto-fit: auto-fit collapses empty tracks, so a region holding one
   exchange (Middle East, Africa) would stretch that card across the full width. */
/* Fixed six per row, two rows of six. A fluid auto-fill count made the wall reflow into
   ragged rows at some widths, and the twelve are a deliberate set, not a feed.
   grid-auto-rows: 1fr keeps every card the same height whatever text it carries. */
/* Four per row, three rows. Six fitted, but a 9px ring and readable numerals need the
   width. grid-auto-rows: 1fr keeps every card the same height whatever text it carries. */
.mkc-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: var(--cs-xs);
}

/* ── Exchange picker ──────────────────────────────────────────────────────────
   Chips above the wall. Absent in wall mode from the markup, not hidden here: a
   kiosk is configured by URL, and a control on an unattended screen is a trap. */
.mkc-picker {
  margin: 0 0 var(--cs-sm);
}

.mkc-picker-title {
  margin: 0 0 var(--cs-xs);
  font-size: var(--ct-sm);
  font-weight: 500;
  color: var(--md-on-surface-var);
}

.mkc-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

/* Filter chip, MD3: 32dp high, full shape, state layer via color-mix so it works
   in both themes without a second palette.
   .mkc-pick, not .mkc-chip: that name is already the phase chip inside every clock
   card, and reusing it had the two sets of rules overwriting each other. */
/* MD3 Expressive filter chip.

   Contained at rest on surface-container, filling with primary when selected.
   The corners morph out of their symmetrical resting shape on hover and on
   selection, sharpening one diagonal and softening the other, which is what
   stops a row of these reading as identical pills.

   Motion uses the expressive overshoot curve so a press settles past its target
   and back, rather than easing politely into place. Disabled under
   prefers-reduced-motion below.

   Selection is never carried by colour alone: the weight changes, the shape
   changes, and aria-pressed states it programmatically. */
.mkc-pick {
  display: inline-flex;
  align-items: center;
  min-height: 2.5rem;
  padding: 0 var(--cs-md);
  border: none;
  border-radius: 1rem;                       /* corner.medium, symmetrical */
  background: var(--md-surf-3);              /* surface-container */
  color: var(--md-on-surface);
  font-family: inherit;
  font-size: 0.875rem;                       /* label.large, 14sp */
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition:
    background    .3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
    color         .3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
    border-radius .3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
    transform     .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.mkc-pick:hover {
  background: color-mix(in srgb, var(--md-primary) 14%, var(--md-surf-3));
  border-radius: 0.25rem 1.5rem 0.25rem 1.5rem;
  transform: scale(1.05);
}

.mkc-pick:active { transform: scale(.97); }

.mkc-pick:focus-visible {
  outline: 0.125rem solid var(--md-primary);
  outline-offset: 0.125rem;
}

.mkc-pick.is-on {
  background: var(--md-primary);
  color: var(--md-on-primary);
  font-weight: 700;
  border-radius: 0.25rem 1.5rem 0.25rem 1.5rem;
}

.mkc-pick.is-on:hover {
  background: var(--md-primary);
  border-radius: 1.5rem 0.25rem 1.5rem 0.25rem;   /* morph the other way */
}

@media (prefers-reduced-motion: reduce) {
  .mkc-pick { transition: background .2s ease, color .2s ease; }
  .mkc-pick:hover,
  .mkc-pick:active { transform: none; }
}

/* ── The picker on a wall ─────────────────────────────────────────────────────
   Same chip, read from across a room: scaled in vmin like the dials, and the
   heading dropped, since a display does not need to be told what its own
   controls are. The note under the row goes too; the chip states say it. */
body.is-wall .mkc-picker { margin: 0 0 var(--cs-sm); text-align: center; }
body.is-wall .mkc-picker-title,
body.is-wall .mkc-picker-note { display: none; }

body.is-wall .mkc-chips { justify-content: center; gap: var(--cs-xs); }

/* Deliberately more restrained than the reading-mode chip: every rem this row
   takes comes out of the dials, and on a wall the clocks are the content. */
body.is-wall .mkc-pick {
  min-height: clamp(2.25rem, 3.6vmin, 3.25rem);
  padding: 0 clamp(0.75rem, 1.6vmin, 1.5rem);
  font-size: clamp(0.8125rem, 1.5vmin, 1.25rem);
  border-radius: clamp(1rem, 2vmin, 1.75rem);
}

body.is-wall .mkc-pick.is-on,
body.is-wall .mkc-pick:hover {
  border-radius: 0.25rem clamp(1.5rem, 3.5vmin, 3rem) 0.25rem clamp(1.5rem, 3.5vmin, 3rem);
}

.mkc-picker-note {
  margin: var(--cs-xs) 0 0;
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
}

/* ── Wall / kiosk add-market menu ────────────────────────────────────────────
   An MD3 menu, not a native select: a chip-shaped trigger at the end of the chip
   row opens a tonal, rounded, elevated surface that springs in. Scaled in vmin
   like the chips so it reads from across a room. */
body.is-wall .mkc-add { position: relative; display: inline-flex; }

/* Cancel borrows the .mkc-pick chip look, whose display overrides the hidden
   attribute, so a hidden Cancel still showed. Restore the attribute's effect. */
.mkc-add-cancel[hidden] { display: none !important; }

/* Trigger, closed state: a tonal surface-container-high pill with a medium corner,
   the label and a trailing chevron that rotates on open. Neutral rather than primary
   so it reads as a control, not a selected market. Sized to match the chips beside it. */
body.is-wall .mkc-add-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5em;
  min-height: clamp(2.25rem, 3.6vmin, 3.25rem);
  padding: 0 clamp(0.85rem, 1.8vmin, 1.6rem);
  border: none;
  border-radius: var(--shape-md, 0.75rem);
  background: var(--md-surf-2);
  color: var(--md-on-surface);
  font-family: inherit;
  font-size: clamp(0.8125rem, 1.5vmin, 1.25rem);
  font-weight: 500;
  cursor: pointer;
  transition: background .18s ease;
}

body.is-wall .mkc-add-label { line-height: 1; }

/* How full the wall is, so the cap is visible before you hit it. */
body.is-wall .mkc-add-count {
  font-family: var(--font-mono);
  font-size: .85em;
  font-weight: 700;
  color: var(--md-primary);
}

body.is-wall .mkc-add-trigger:hover,
body.is-wall .mkc-add.is-open .mkc-add-trigger {
  background: color-mix(in srgb, var(--md-on-surface) 10%, var(--md-surf-2));
}

/* The chevron is high-emphasis (primary) and flips to point up while the menu is open,
   the one moving part that says "this expands". */
body.is-wall .mkc-add-chevron {
  color: var(--md-primary);
  transition: transform .24s cubic-bezier(0.2, 0, 0, 1);
}
body.is-wall .mkc-add.is-open .mkc-add-chevron { transform: rotate(180deg); }

/* Panel, open state: surface-container-highest, matching medium corner, high elevation,
   and MD3 emphasized-decelerate motion (fast in, settling out). */
body.is-wall .mkc-add-menu {
  position: absolute;
  top: calc(100% + .5rem);
  left: 50%;
  transform: translateX(-50%);
  transform-origin: top center;
  min-width: max(14rem, 100%);
  max-height: 60vh;
  overflow-y: auto;
  padding: clamp(.4rem, .8vmin, .85rem);
  background: var(--md-surf-3);
  border: 1px solid var(--md-outline-var);
  border-radius: var(--shape-md, 0.75rem);
  box-shadow:
    0 4px 10px rgba(0, 0, 0, .24),
    0 12px 30px rgba(0, 0, 0, .34);
  z-index: 20;
  text-align: left;
  animation: mkc-menu-in .22s cubic-bezier(0.05, 0.7, 0.1, 1);
}

@keyframes mkc-menu-in {
  from { opacity: 0; transform: translateX(-50%) scaleY(.85) translateY(-.4rem); }
  to   { opacity: 1; transform: translateX(-50%) scaleY(1)   translateY(0); }
}

/* Search: an MD3 filled tonal field, pinned to the top of the panel so it stays
   reachable while the list scrolls under it. */
body.is-wall .mkc-add-search {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .35rem;
  padding: 0 clamp(.6rem, 1.2vmin, 1rem);
  background: color-mix(in srgb, var(--md-on-surface) 7%, var(--md-surf-3));
  border-radius: var(--shape-sm, 0.5rem);
}

body.is-wall .mkc-add-search-icon { color: var(--md-on-surface-var); flex-shrink: 0; }

body.is-wall .mkc-add-search-input {
  flex: 1;
  min-width: 0;
  min-height: clamp(2.2rem, 3.4vmin, 3rem);
  border: none;
  background: none;
  color: var(--md-on-surface);
  font-family: inherit;
  font-size: clamp(.85rem, 1.5vmin, 1.25rem);
}
body.is-wall .mkc-add-search-input:focus { outline: none; }
body.is-wall .mkc-add-search-input::placeholder { color: var(--md-on-surface-var); }
body.is-wall .mkc-add-search:focus-within {
  outline: 2px solid var(--md-primary);
  outline-offset: 1px;
}

body.is-wall .mkc-add-empty {
  margin: 0;
  padding: clamp(.8rem, 1.6vmin, 1.4rem);
  text-align: center;
  color: var(--md-on-surface-var);
  font-size: clamp(.8rem, 1.4vmin, 1.15rem);
}

body.is-wall .mkc-add-group {
  margin: .55rem .6rem .15rem;
  font-size: clamp(.6rem, 1.05vmin, .8rem);
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
}
body.is-wall .mkc-add-section:first-of-type .mkc-add-group { margin-top: .15rem; }

/* List item: generous padding, on-surface text, and a neutral state-layer overlay on
   hover and press (deepening on active), the M3 state-layer model. */
body.is-wall .mkc-add-item {
  display: flex;
  align-items: center;
  gap: .6rem;
  width: 100%;
  padding: clamp(.6rem, 1.1vmin, 1rem) clamp(.7rem, 1.3vmin, 1.1rem);
  border: none;
  background: none;
  cursor: pointer;
  border-radius: var(--shape-sm, 0.5rem);
  color: var(--md-on-surface);
  font-family: inherit;
  font-size: clamp(.85rem, 1.5vmin, 1.3rem);
  text-align: left;
  transition: background .14s ease;
}

body.is-wall .mkc-add-item:hover,
body.is-wall .mkc-add-item:focus-visible {
  outline: none;
  background: color-mix(in srgb, var(--md-on-surface) 8%, transparent);
}
body.is-wall .mkc-add-item:active {
  background: color-mix(in srgb, var(--md-on-surface) 12%, transparent);
}

/* Leading checkmark. It holds its space whether or not the market is on the wall, so
   the city names line up in one column instead of shifting as you tick things. */
body.is-wall .mkc-add-check {
  flex-shrink: 0;
  margin-right: .1rem;
  color: var(--md-on-primary-cont);
  opacity: 0;
  transform: scale(.6);
  transition: opacity .16s ease, transform .2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

/* Selected: a tonal container plus the tick, the MD3 selected-item treatment. */
body.is-wall .mkc-add-item.is-on {
  background: var(--md-primary-container);
  color: var(--md-on-primary-cont);
}
body.is-wall .mkc-add-item.is-on:hover {
  background: color-mix(in srgb, var(--md-on-primary-cont) 8%, var(--md-primary-container));
}
body.is-wall .mkc-add-item.is-on .mkc-add-check { opacity: 1; transform: scale(1); }
body.is-wall .mkc-add-item.is-on .mkc-add-venue {
  color: color-mix(in srgb, var(--md-on-primary-cont) 75%, transparent);
}

body.is-wall .mkc-add-item[hidden],
body.is-wall .mkc-add-section[hidden] { display: none; }

body.is-wall .mkc-add-city { font-weight: 600; margin-right: auto; }

body.is-wall .mkc-add-venue {
  color: var(--md-on-surface-var);
  font-size: .78em;
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  body.is-wall .mkc-add-menu    { animation: none; }
  body.is-wall .mkc-add-chevron { transition: none; }
  body.is-wall .mkc-add-check   { transition: none; }
}

/* The note is hidden on a wall to keep it clean, but the replace-mode instruction
   must be seen, so it comes back only while replacing, in a live colour. */
body.is-wall .mkc-picker--wall.is-replacing .mkc-picker-note {
  display: block;
  color: var(--md-primary);
  font-size: clamp(0.85rem, 1.7vmin, 1.4rem);
  font-weight: 600;
}

/* Replace mode: the shown chips are the replace targets, so make them look tappable,
   a soft pulse that says "pick one" without shouting over the dials. */
body.is-wall .mkc-picker--wall.is-replacing .mkc-pick:not(.mkc-pick--all) {
  outline: 2px solid color-mix(in srgb, var(--md-primary) 60%, transparent);
  outline-offset: 2px;
  animation: mkc-replace-pulse 1.4s ease-in-out infinite;
}

@keyframes mkc-replace-pulse {
  0%, 100% { outline-color: color-mix(in srgb, var(--md-primary) 25%, transparent); }
  50%      { outline-color: var(--md-primary); }
}

@media (prefers-reduced-motion: reduce) {
  body.is-wall .mkc-picker--wall.is-replacing .mkc-pick:not(.mkc-pick--all) { animation: none; }
}

/* A filtered grid has no fixed shape to fill, so the explicit row and column counts
   are replaced by auto-fit and the dials grow into the space they freed.

   --mkc-dial is redefined here rather than on .mkc-page because the cards are
   descendants of the grid, and a custom property resolves from the nearest ancestor
   that declares it. The narrow-viewport overrides that set it on .mkc-page are
   therefore bypassed, which is why both filtered sizes are restated at 640px below. */
.mkc-grid.is-filtered {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  grid-template-rows: none;
  --mkc-dial: clamp(7rem, 14vw, 11rem);
}

.mkc-grid.is-filtered .mkc-card { padding: var(--cs-sm); }

/* Four or fewer. The reason to filter is to look at these markets, so they take the
   room: a dial that fills the space, city names at a size you read rather than scan,
   and a capped measure so two clocks do not stretch to the width of a monitor.
   Declared after .is-filtered, which carries the same specificity, so order decides. */
.mkc-grid.is-few {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  --mkc-dial: clamp(9rem, 22vw, 17rem);
  max-width: 64rem;
  margin-inline: auto;
  gap: var(--cs-sm);
}

.mkc-grid.is-few .mkc-city { font-size: clamp(1.1rem, 2.4vw, 1.9rem); }

/* ── Showcase: three clocks or fewer ──────────────────────────────────────────
   Default is the normal stacked card with a much larger dial. Stacked, the dial
   gets the card's whole width, which at three across is far bigger than anything
   a landscape split can give it.

   The landscape card is an enhancement applied further down, and only once the
   column is genuinely wide enough to hold the session line unwrapped beside the
   dial. Applied unconditionally it produced a 199px text column in which
   "Xetra · 09:00-17:30" broke over four lines, which is worse than either. */
.mkc-grid.is-showcase {
  grid-template-columns: repeat(var(--mkc-n, 1), minmax(0, 1fr));
  /* Sized so the dial and every text line fit the card together. At 58vw/count the
     dial took the whole card and pushed the session, local time, boundary and phase
     chip out of it, which is a bigger clock and a worse card. */
  --mkc-dial: clamp(7rem, calc(30vw / var(--mkc-n, 1)), 15rem);
  max-width: min(100%, calc(var(--mkc-n, 1) * 34rem));
  margin-inline: auto;
}

.mkc-grid.is-showcase .mkc-card {
  padding: var(--cs-md);
  /* Nothing here is optional. The twelve-card layout hides some of these lines for
     space; at three across there is room for all of them, and losing them is what
     made the large dial a downgrade. */
  overflow: visible;
}

.mkc-grid.is-showcase .mkc-session,
.mkc-grid.is-showcase .mkc-local,
.mkc-grid.is-showcase .mkc-boundary,
.mkc-grid.is-showcase .mkc-offset,
.mkc-grid.is-showcase .mkc-chip { display: block; }

.mkc-grid.is-showcase .mkc-chip { width: fit-content; }

/* 3vw put the city at 39px on a 1300px screen, which crowded the card as much as
   the dial did. Large enough to lead the card, not large enough to be the card. */
.mkc-grid.is-showcase .mkc-city { font-size: clamp(1.15rem, 1.8vw, 1.8rem); }

.mkc-grid.is-showcase .mkc-session,
.mkc-grid.is-showcase .mkc-local,
.mkc-grid.is-showcase .mkc-boundary { font-size: var(--ct-sm); }

/* Restored: the normal card hides these to fit twelve on a screen, and here there
   is nothing but room. */
.mkc-grid.is-showcase .mkc-boundary,
.mkc-grid.is-showcase .mkc-offset { display: block; }

/* Grid children default to min-width: auto, so a nowrap line cannot shrink and the
   track grows past the card instead, which is why the hours were running off the
   right edge. Zero lets them shrink, and wrapping is allowed again: in a 15rem
   column the session line breaks to two lines at worst, and two readable lines beat
   one clipped one. The four-fragment mess earlier came from a 194px column, which
   the minimum now prevents. */
.mkc-grid.is-showcase .mkc-card > * { min-width: 0; }

/* These are secondary on a twelve-card wall, where --md-outline is right. Here they
   are the card's content, and at this size that token reads as disabled text. */
.mkc-grid.is-showcase .mkc-offset {
  color: var(--md-on-surface-var);
  /* --ct-2xs is 9 to 11px, sized for twelve dense cards. On a card this size that is
     not small-print, it is unreadable. */
  font-size: var(--ct-sm);
}

.mkc-grid.is-showcase .mkc-boundary {
  color: var(--md-on-surface);
  font-weight: 500;
}

.mkc-grid.is-showcase .mkc-local { color: var(--md-on-surface-var); }

/* ── Landscape card ───────────────────────────────────────────────────────────
   City and dial in the left column, every text line stacked in the right.

   Column one is placed explicitly by row. Column two is left to auto-placement,
   which fills the first free cells in that column from the top, so the optional
   boundary and reason lines can come and go without leaving holes. .sr-only is
   position: absolute, so it takes no cell at all.

   One and two clocks only. Three never gets the room: the page container caps the
   grid near 1100px whatever the viewport, so three columns are about 358px each,
   and a landscape split of that leaves a 99px text column with the session line
   wrapped to two ragged lines. Measured, not assumed. Three clocks keep the
   stacked card, where the dial gets the full column width and every line has room
   to sit under it.

   Gating on viewport is a proxy for column width, which is what actually matters.
   It holds for one and two because those columns are wide regardless. */
@media (min-width: 34rem) {
  .mkc-grid.is-showcase.is-n1 .mkc-card {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--cs-md);
    align-content: center;
    justify-items: start;
    text-align: left;
  }

  .mkc-grid.is-showcase.is-n1 .mkc-city   { grid-column: 1; grid-row: 1; margin: 0; }
  .mkc-grid.is-showcase.is-n1 .mkc-offset { grid-column: 1; grid-row: 2; }
  .mkc-grid.is-showcase.is-n1 .mkc-dial   { grid-column: 1; grid-row: 3; }

  .mkc-grid.is-showcase.is-n1 .mkc-session,
  .mkc-grid.is-showcase.is-n1 .mkc-local,
  .mkc-grid.is-showcase.is-n1 .mkc-boundary,
  .mkc-grid.is-showcase.is-n1 .mkc-reason,
  .mkc-grid.is-showcase.is-n1 .mkc-chip { grid-column: 2; }

  .mkc-grid.is-showcase.is-n1 .mkc-session { align-self: end; }
}

@media (min-width: 64rem) {
  .mkc-grid.is-showcase.is-n2 .mkc-card {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--cs-md);
    align-content: center;
    justify-items: start;
    text-align: left;
  }

  .mkc-grid.is-showcase.is-n2 .mkc-city   { grid-column: 1; grid-row: 1; margin: 0; }
  .mkc-grid.is-showcase.is-n2 .mkc-offset { grid-column: 1; grid-row: 2; }
  .mkc-grid.is-showcase.is-n2 .mkc-dial   { grid-column: 1; grid-row: 3; }

  .mkc-grid.is-showcase.is-n2 .mkc-session,
  .mkc-grid.is-showcase.is-n2 .mkc-local,
  .mkc-grid.is-showcase.is-n2 .mkc-boundary,
  .mkc-grid.is-showcase.is-n2 .mkc-reason,
  .mkc-grid.is-showcase.is-n2 .mkc-chip { grid-column: 2; }

  .mkc-grid.is-showcase.is-n2 .mkc-session { align-self: end; }
}



.mkc-caveat {
  font-size: var(--ct-xs);
  line-height: 1.5;
  color: var(--md-outline);
  background: var(--md-surf-2);
  border-radius: .875rem;
  padding: var(--cs-sm) var(--cs-md);
  margin: var(--cs-md) 0;
}

/* Expressive tonal container rather than a bordered card: the surface itself
   carries the elevation, which is what MD3 Expressive asks for. */
/* Frosted glass over the sky above. Same material the AI Mood popup uses, so this is an
   extension of the house style rather than a new one. */
.mkc-card {
  position: relative;
  z-index: 1;
  /* The specular sheen down the top half, which is what makes this read as a pane of glass
     catching a light source rather than as a tinted rectangle. Real glass is brightest at
     the top edge and falls off fast, so the ramp is front-loaded: most of the lift is spent
     in the first third and it is gone by 62%, leaving the lower half clean for the dial.
     Two stops rather than one, because a single linear fade to transparent greys out through
     the middle instead of falling away.

     A background layer, not a ::before. The card already spends ::after on the New York
     marker, and an absolutely positioned pseudo-element inside a box whose children are all
     static would paint over the city name and the countdown. */
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .13) 0%,
      rgba(255, 255, 255, .05) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .05);
  /* Every card carries its continent on the rim, not just the trading ones. The legend
     below the wall names five regions, and a closed market is still on its continent, so
     a neutral rim left four of the five legend colours pointing at nothing for most of
     the day. Low alpha keeps the glass intact; the live cards lift to 70% further down. */
  border: 1px solid color-mix(in srgb, var(--mkc-phase) 34%, transparent);
  border-radius: 1.625rem;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 6px 20px rgba(0, 0, 0, .28);
  padding: var(--cs-sm) var(--cs-2xs);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .1rem;
}

/* Blur is the single most expensive thing on this page: one compositing layer per card,
   twelve of them, on a page that also ticks every second. Desktop only. Mobile keeps the
   translucent fill, which reads almost the same and costs nothing. */
@media (min-width: 641px) {
  .mkc-card {
    -webkit-backdrop-filter: blur(16px) saturate(150%);
    backdrop-filter: blur(16px) saturate(150%);
  }
}

/* The chip sits on the baseline of every card regardless of how many text lines are above
   it, so a row of six reads as one object rather than six ragged ones. */
.mkc-card .mkc-chip { margin-top: auto; }

/* The live ones still lead: brighter glass and the same continent colour raised from the
   base 32% to full strength, so the trading markets read first without the closed ones
   losing their region. */
/* The sheen is restated in every rule that sets background, here and in both light-mode
   rules below. background is a shorthand: naming only a colour drops the gradient layer
   with it, and a live card would go flat while the closed ones beside it kept their glass. */
.mkc-card.is-open,
.mkc-card.is-auction,
.mkc-card.is-power,
.mkc-card.is-lunch {
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .16) 0%,
      rgba(255, 255, 255, .06) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .085);
  border-color: color-mix(in srgb, var(--mkc-phase) 72%, transparent);
}

/* Continent accents are gone. The rim now carries trading state, the same colour the
   dial and the countdown already use, so a card says one thing loudly instead of two
   things quietly. Geography was costing a five-colour legend to explain something the
   city name already tells you. */

/* Light mode: white-on-white glass is invisible, so the frost inverts. The panes become
   near-opaque white over a much fainter sky, which reads as frosted rather than as the
   luminous night version, and keeps small text legible. */
/* Light mode gets the sheen as a highlight rather than a lift: more white on an already
   near-white pane is invisible, so the top instead goes fully opaque and fades to the
   translucent body, which is how glass over a pale ground actually behaves. */
html[data-theme="light"] body:not(.is-dashboard) .mkc-card {
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .92) 0%,
      rgba(255, 255, 255, .30) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .62);
  border-color: rgba(0, 0, 0, .08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .9), 0 4px 14px rgba(0, 0, 0, .08);
}

html[data-theme="light"] body:not(.is-dashboard) .mkc-card.is-open,
html[data-theme="light"] body:not(.is-dashboard) .mkc-card.is-auction,
html[data-theme="light"] body:not(.is-dashboard) .mkc-card.is-power,
html[data-theme="light"] body:not(.is-dashboard) .mkc-card.is-lunch {
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .95) 0%,
      rgba(255, 255, 255, .34) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .78);
}

html[data-theme="light"] body:not(.is-dashboard) .mkc-blob      { opacity: .22; }
html[data-theme="light"] body:not(.is-dashboard) .mkc-dial-track { stroke: rgba(0, 0, 0, .12); }

/* Same scoping the rest of this file uses for light mode: html[data-theme] is set
   pre-paint, and only content pages are re-pointed. */

.mkc-dial {
  position: relative;
  width: var(--mkc-dial);
  height: var(--mkc-dial);
  margin-bottom: var(--cs-2xs);
}

.mkc-dial svg { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Thick enough to read as an instrument. At 7 the ring looked like a border.

   Both rings are a ladder of ticks rather than a solid stroke, which is what makes
   the dial read as a gauge instead of a progress bar. pathLength="100" in the markup
   normalises the circumference, so the dash pair is read directly as a percentage of
   the ring and never needs recomputing against 257.6.

   "1.36 0.64" is a period of 2, so 50 ticks, with the gap taking a third of each step.
   It was 40 ticks on a 2.5 period whose gap took 58%, which left the ring reading as
   separated dashes rather than as a machined scale. Narrower gaps and more of them is
   the whole difference between a countdown and an instrument. */
.mkc-dial-track,
.mkc-dial-fill {
  fill: none;
  stroke-width: 9;
  stroke-dasharray: 1.36 0.64;
}

.mkc-dial-track { stroke: rgba(255, 255, 255, .16); }

/* Only a live session glows, so trading markets pull the eye with no extra label.
   Keyed off --mkc-phase rather than currentColor: an SVG stroke does not inherit from it. */
.mkc-card.is-open    .mkc-dial-fill,
.mkc-card.is-auction .mkc-dial-fill,
.mkc-card.is-power   .mkc-dial-fill,
.mkc-card.is-lunch   .mkc-dial-fill {
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mkc-phase) 48%, transparent));
}

/* butt, not round: round caps on a 1.05-long tick swell it into a dot and close the
   gaps the ticks exist to make. The progress is a mask now, not this element's own
   dash offset, so there is no dashoffset left to animate. */
.mkc-dial-fill {
  stroke: var(--mkc-shut);
  stroke-linecap: butt;
  transition: stroke .3s ease;
}

/* Google Sans Display carries tnum, verified in the shipped woff2, so the digits
   do not jitter as the countdown ticks. No extra font needed. */
.mkc-count {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Google Sans Display', 'Google Sans', system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  /* Sized to fit H:MM:SS inside the ring, which is the widest form the dial ever shows.
     var(--ct-md) overflowed and clipped the seconds. */
  font-size: var(--ct-sm);
  font-weight: 500;
  letter-spacing: -.02em;
  white-space: nowrap;
  color: var(--md-on-surface);
}

.mkc-city {
  font-size: var(--ct-base);
  font-weight: 500;
  color: var(--md-on-surface);
  margin: 0;
}

.mkc-local,
.mkc-boundary,
.mkc-reason {
  font-size: var(--ct-xs);
  line-height: 1.35;
  margin: 0;
}

.mkc-local    { color: var(--md-on-surface-var); font-variant-numeric: tabular-nums; }
.mkc-boundary { color: var(--md-on-surface-var); }
.mkc-reason   { color: var(--md-callout-text); font-weight: 500; }

/* Tonal chip, MD3 assist-chip proportions. */
.mkc-chip {
  margin-top: var(--cs-2xs);
  display: inline-block;
  font-size: var(--ct-2xs);
  line-height: 1;
  padding: .3rem .6rem;
  border-radius: 999px;
  background: var(--md-surf-3);
  color: var(--md-on-surface-var);
}

/* New York is roughly 45% of world equity value, so it gets a permanent marker while the
   wall rotates around it. A dot and a brighter pane, deliberately quiet: it must be
   findable in one sweep without out-shouting the phase colours, which are the real signal. */
/* Same class count as .mkc-card and later in the file, so this wins outright: without the
   gradient restated, New York would be the one flat pane on a wall of glass ones. */
.mkc-card--primary {
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .16) 0%,
      rgba(255, 255, 255, .06) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .085);
  border-color: rgba(255, 255, 255, .28);
}

.mkc-card--primary::after {
  content: "";
  position: absolute;
  top: .7rem;
  right: .7rem;
  width: .35rem;
  height: .35rem;
  border-radius: 50%;
  background: var(--md-primary);
}

html[data-theme="light"] body:not(.is-dashboard) .mkc-card--primary {
  background:
    linear-gradient(180deg,
      rgba(255, 255, 255, .95) 0%,
      rgba(255, 255, 255, .34) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .82);
  border-color: rgba(0, 0, 0, .16);
}

/* One variable drives ring, glow and chip, so the three can never disagree about phase. */
.mkc-card              { --mkc-phase: var(--mkc-shut); }
.mkc-card.is-open      { --mkc-phase: var(--mkc-open); }
.mkc-card.is-auction,
.mkc-card.is-power     { --mkc-phase: var(--mkc-edge); }
.mkc-card.is-lunch     { --mkc-phase: var(--mkc-lunch); }

.mkc-dial-fill { stroke: var(--mkc-phase); }

/* Opaque, and the text lifted off the pure phase hue.
   Two problems, one fix. The phase colour on a 20% wash of itself measured
   4.13:1 for the closed and pre-open chips against 4.5 required at this size,
   and only 4.59:1 when open. The wash was also transparent, sitting on a
   translucent card over a blurred blob, so an auditing tool cannot resolve a
   real background at all and reports the whole stack.
   Mixing the fill into an opaque surface and the text toward on-surface makes
   the value computable and clears 4.5 on every phase in both themes.

   Re-measured after the ring colours became literal mint and amber, identical in
   both themes. Dark is comfortable at a 70% text mix, worst case first: closed
   5.56, edge 6.49, lunch 7.01, open 7.60. Light is not: against a near-white chip
   the same 70% mix put open at 2.55, because 70% of a bright mint plus 30% of a
   near-black on-surface is still a pale colour. The hue is the thing being kept
   identical, not the text weight, so light mode pulls the text further toward
   on-surface and clears 4.5 again: at 42% it measures open 4.88, edge 5.84,
   shut 7.66, lunch 8.70.

   42% rather than the 45% that first cleared: 45% put the open chip at exactly
   4.50, which is the threshold itself and not a margin. Going much below 40 starts
   turning the mint and the amber grey, which is the one thing this chip exists to
   say, so the usable band is narrow and 42 sits in the middle of it. */
.mkc-chip {
  background: color-mix(in srgb, var(--mkc-phase) 14%, var(--md-surf-2));
  color: color-mix(in srgb, var(--mkc-phase) 70%, var(--md-on-surface));
}

html[data-theme="light"] body:not(.is-dashboard) .mkc-chip {
  color: color-mix(in srgb, var(--mkc-phase) 42%, var(--md-on-surface));
}

.mkc-card.is-closed  .mkc-count,
.mkc-card.is-holiday .mkc-count { color: var(--md-outline); }

/* ── 24h session map ──────────────────────────────────────────────────────── */

/* Hours as prose. Deliberately plain: these exist to be quoted by an answer engine and
   read by anyone who wants the schedule rather than the live state. */
.mkc-hours { margin: var(--cs-lg) 0; }

/* The table is the same material as the clocks: a tonal glass container with a large
   corner radius, so it reads as part of the wall rather than as an HTML table dropped
   underneath it. Scrolls itself instead of widening the page, which is how a six-column
   table normally breaks a phone. */
/* ── Trading hours table, Material Design 3 ────────────────────────────────────
   Built to the M3 data-table spec rather than to the page's glass: solid surface
   containers, dividers instead of zebra, and the venue as an assist chip. Glass was
   the wrong material here, a table needs a stable ground for long rows of numbers.

   Type is the M3 scale at fixed sizes, not the fluid --ct-* clamps: those are for
   dense dashboard readouts, and a table people read is a communication surface.
     label-large   14/500   column headers
     title-medium  16/500   exchange names
     body-medium   14/400   data cells
     label-small   11/500   venue chips
   ------------------------------------------------------------------------------ */

.mkc-hours-scroll {
  overflow-x: auto;
  border-radius: 12px;                     /* shape-corner-medium */
  background: var(--md-surf-1);            /* surface-container-low */
}

.mkc-hours-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

/* Header row: surface-container, 56dp, label-large. */
.mkc-hours-table thead th {
  height: 3.5rem;
  background: var(--md-surf-2);
  color: var(--md-on-surface);
  font-size: .875rem;
  font-weight: 500;
  letter-spacing: .00625em;
  text-align: left;
  white-space: nowrap;
  padding: 0 1rem 0 0;                     /* 16dp between columns */
  border-bottom: 1px solid var(--md-outline-var);
}

/* 24dp at the start and end of every row. */
.mkc-hours-table th:first-child,
.mkc-hours-table td:first-child { padding-left: 1.5rem; }
.mkc-hours-table th:last-child,
.mkc-hours-table td:last-child  { padding-right: 1.5rem; }

/* Data rows: 52dp, body-medium, horizontal dividers only. M3 tables separate
   columns with whitespace, never with vertical rules. */
.mkc-hours-table tbody td,
.mkc-hours-table tbody th {
  height: 3.25rem;
  padding: 0 1rem 0 0;
  text-align: left;
  vertical-align: middle;
  white-space: nowrap;
  border-bottom: 1px solid var(--md-outline-var);
  font-size: .875rem;
  font-weight: 400;
  color: var(--md-on-surface-var);         /* on-surface-variant */
}

.mkc-hours-table tbody tr:last-child td,
.mkc-hours-table tbody tr:last-child th { border-bottom: 0; }

/* Exchange name: title-medium on-surface, the one primary column. */
.mkc-hours-table tbody th {
  font-size: 1rem;
  font-weight: 500;
  color: var(--md-on-surface);
}

/* Name and chip share the cell, but the chip is pushed to the column's trailing edge so
   the twelve chips form a straight column. Left as an inner flex wrapper rather than
   display:flex on the th itself, which would stop it being a table-cell and break the
   column widths the rest of the table depends on. */
/* Venue as an M3 assist chip, now that it has its own column: the table aligns the chips
   into a straight edge for free, which is what made them look wrong when they trailed the
   city name inside a stretching cell.
   32dp high, shape-corner-small (8dp), secondary-container with its on-color, label-small. */
.mkc-hours-venue {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3.25rem;
  height: 2rem;
  padding: 0 .625rem;
  border-radius: 8px;
  background: var(--md-secondary-cont);
  color: var(--md-on-secondary-cont);
  font-size: .6875rem;
  /* Matches .mkc-venue on the cards: the same twelve codes appear in both places and it
     would be odd for NYSE to be bold on its card and not in the table under it. */
  font-weight: 700;
  letter-spacing: .03em;
}

/* State layers: 8% on-surface on hover, 12% plus a 2dp primary outline on focus. */
.mkc-hours-table tbody tr {
  transition: background .15s cubic-bezier(.2, 0, 0, 1);
}

.mkc-hours-table tbody tr:hover {
  background: color-mix(in srgb, var(--md-on-surface) 8%, transparent);
}

.mkc-hours-table tbody tr:focus-within {
  background: color-mix(in srgb, var(--md-on-surface) 12%, transparent);
  outline: 2px solid var(--md-primary);
  outline-offset: -2px;
}

/* The sentences exist to be quoted, so they stay readable prose rather than shrinking into
   a footnote: MD3 body-medium, two columns on a wide screen so twelve of them do not turn
   into a wall of text. */
.mkc-hours-prose {
  margin: var(--cs-md) 0 0;
  columns: 2;
  column-gap: var(--cs-xl);
}

.mkc-hours-prose p {
  break-inside: avoid;
  margin: 0 0 var(--cs-sm);
  font-size: .875rem;
  line-height: 1.6;
  color: var(--md-on-surface-var);
}

/* One block per exchange, each its own link target. Kept whole across the column
   break so a heading never ends a column with its answer starting the next, and
   given scroll-margin so landing on #london from a search result does not put the
   heading under the sticky top bar. */
.mkc-venue {
  break-inside: avoid;
  margin: 0 0 var(--cs-md);
  scroll-margin-top: 5rem;
}

.mkc-venue-title {
  margin: 0 0 var(--cs-2xs);
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--md-on-surface);
}

/* The yes or no, which is what the question asked. Full on-surface against the
   schedule sentence below it in on-surface-variant, so the answer leads and the
   detail supports rather than the two competing. */
.mkc-venue-state {
  margin: 0 0 var(--cs-2xs);
  font-size: .875rem;
  line-height: 1.6;
  color: var(--md-on-surface);
}

@media (max-width: 720px) {
  .mkc-hours-prose { columns: 1; }
}

.mkc-hours-note {
  font-size: var(--ct-xs);
  color: var(--md-outline);
  line-height: 1.5;
  margin: var(--cs-sm) 0 0;
}

/* Deep links land on a card or an hours row, so keep them clear of the top bar. */
.mkc-card[id],
.mkc-hours-table tr[id] { scroll-margin-top: 5rem; }

.mkc-map { margin: var(--cs-xl) 0 var(--cs-lg); }

.mkc-map-rows { display: flex; flex-direction: column; gap: .3rem; }

.mkc-map-row {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  align-items: center;
  gap: var(--cs-xs);
}

/* Rows outside the reader's selection. Only the bars fade, never the labels: the
   label is text and dimming it far enough to read as secondary would drop it under
   the contrast floor. The bars carry the emphasis, which is where the information
   is anyway. */
.mkc-map-row.is-muted .mkc-map-bar { opacity: .28; }

.mkc-map-label {
  font-size: var(--ct-xs);
  color: var(--md-on-surface-var);
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mkc-map-track {
  position: relative;
  height: .55rem;
  background: var(--md-surf-2);
  border-radius: 999px;
}

.mkc-map-bar {
  position: absolute;
  top: 0;
  height: .55rem;
  border-radius: 999px;
  background: var(--md-outline-var);
}

.mkc-map-bar.is-live { background: var(--mkc-open); }

.mkc-map-scale {
  display: flex;
  justify-content: space-between;
  margin: var(--cs-2xs) 0 0 7.5rem;
  font-size: var(--ct-2xs);
  color: var(--md-outline);
  font-variant-numeric: tabular-nums;
}

.mkc-map-note {
  font-size: var(--ct-sm);
  line-height: 1.55;
  color: var(--md-on-surface-var);
  margin: var(--cs-sm) 0 0;
}

@media (max-width: 1024px) {
  .mkc-page { --mkc-dial: 5.5rem; }
  .mkc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

}

@media (max-width: 640px) {
  /* Three across so all twelve stay on one screen, which is the point of the page. */
  .mkc-page { --mkc-dial: 4rem; }
  .mkc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .mkc-card { padding: var(--cs-xs) 2px; border-radius: 1.125rem; }
  .mkc-boundary, .mkc-offset { display: none; }

  /* Filtered sizes restated: those rules declare --mkc-dial on .mkc-grid, which sits
     closer to the cards than .mkc-page, so the phone dial above would be ignored.
     A 22vw dial is fine on a monitor and absurd on a handset. */
  .mkc-grid.is-filtered {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
    --mkc-dial: 5.5rem;
  }

  .mkc-grid.is-few {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 10.5rem), 1fr));
    --mkc-dial: 7rem;
    max-width: none;
  }

  .mkc-grid.is-few .mkc-city { font-size: 1.05rem; }
  .mkc-grid.is-filtered .mkc-card { padding: var(--cs-xs); }

  /* The landscape card needs a text column beside the dial, and a phone has no
     width to give one. Back to the stacked card, one per row, with a dial sized
     to the screen rather than to a column that is not there. */
  .mkc-grid.is-showcase {
    grid-template-columns: 1fr;
    --mkc-dial: min(58vw, 15rem);
    max-width: none;
  }

  .mkc-grid.is-showcase .mkc-card {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
    padding: var(--cs-sm);
  }

  .mkc-grid.is-showcase .mkc-city,
  .mkc-grid.is-showcase .mkc-offset,
  .mkc-grid.is-showcase .mkc-dial,
  .mkc-grid.is-showcase .mkc-session,
  .mkc-grid.is-showcase .mkc-local,
  .mkc-grid.is-showcase .mkc-boundary,
  .mkc-grid.is-showcase .mkc-reason,
  .mkc-grid.is-showcase .mkc-chip { grid-column: 1; grid-row: auto; }

  .mkc-grid.is-showcase .mkc-city { font-size: 1.4rem; }
  .mkc-grid.is-showcase .mkc-session { align-self: auto; }
  .mkc-map-row { grid-template-columns: 4.5rem minmax(0, 1fr); }
  .mkc-map-scale { margin-left: 5.5rem; }
  /* Two boundaries only happen during an Asian lunch break, where the line
     would otherwise wrap awkwardly inside a half-width card. */
  .mkc-boundary { font-size: var(--ct-2xs); }
}

@media (prefers-reduced-motion: reduce) {
  .mkc-dial-fill { transition: none; }
}

/* ── Wall mode ─────────────────────────────────────────────────────────────────
   The whole viewport as a clock wall, for a TV, a spare monitor or a desk
   display. Entered from the button on the page or by loading with ?wall=1.

   Note the class is is-wall on the body, not mkc-wall: .mkc-wall is already the
   section that holds the sky, the grid and the legend.

   Everything below the wall is hidden with CSS rather than dropped from the
   markup. The hours table, the twelve sentences and the FAQ are the reason this
   page answers anything for a crawler or an assistant, and a display mode must
   not cost that.                                                            ---- */

body.is-wall .site-nav-launcher,
body.is-wall .mkc-map,
body.is-wall .mkc-caveat,
body.is-wall .mkc-hours,
body.is-wall .legal-section,
body.is-wall .dash-cta,
/* The exit-intent modal from the same partial. The CTA card above was hidden here but
   this was not, and being shown by script rather than rendered in flow, it fired over
   the clocks: a "Before you go" funnel on a display nobody is leaving, carrying an
   "Open the Dashboard" link that in kiosk would strand the app off the clocks. The
   script now returns early in wall mode too; this is the belt to that pair of braces. */
body.is-wall #dash-exit,
body.is-wall .content-footer,
/* The copyright line is a sibling of .content-footer in _ContentFooter.cshtml, not a child
   of it, so hiding the nav alone left "© GMD" stranded on the wall. The signature already
   says where the display came from. */
body.is-wall .content-footer-copy,
/* Same trap as the copyright line above: the support ask is a sibling of
   .content-footer, so hiding the nav left a Ko-fi button alone on the wall. An
   unattended display should not be asking anyone for money. */
body.is-wall .content-footer-support,
/* The mobile bottom nav is an in-flow grid row of .shell, 80px of it, so a wall was always
   100dvh of clocks plus 80px and could not help but scroll. Nothing taps a TV anyway. */
body.is-wall .mobile-bottom-nav { display: none; }

/* The page owns the viewport: no max-width, no auto margins, no bottom run-off. */
body.is-wall .mkc-page {
  max-width: none;
  /* Fill the row, do not re-claim the viewport. .shell is already min-height: 100dvh and
     main is its 1fr track, so a second 100dvh here counted the viewport twice: the page
     started 11px down and ended 11px past the fold, which is why the wall scrolled by a
     hair. min-height: 100% cannot do it either, because main is a stretched grid item with
     an auto height and a percentage has nothing definite to resolve against, so the page
     collapsed to its content and left a band of black above the signature.

     So: 100dvh for a definite height the grid can actually divide, plus flex: 1 to absorb
     any rounding against main. main's own padding is zeroed above, which is what stops the
     dvh from overshooting the fold. */
  min-height: 100dvh;
  flex: 1;
  margin: 0;
  /* The bottom pad is the signature's lane. It is fixed to the bottom edge, so without a
     reserved strip it sat on top of the last row of cards and covered their phase chips,
     which are the one thing on the card that names the state in words. Inside the height
     thanks to border-box, so reserving it costs no scroll.

     3rem, measured rather than guessed. main's padding is zeroed above, so the only other
     reservation under the grid is .mkc-wall's own ~10px: 48 + 10 puts the last card row at
     887 on a 945 viewport, which clears a signature whose top edge is 896 without leaving
     the band of dead black that 68px of stacked padding produced. */
  padding: var(--cs-sm) var(--cs-sm) 3rem;
  display: flex;
  flex-direction: column;
}

body.is-wall .shell { padding-top: 0; }

/* A wall must never show a scrollbar: it is a display, not a document. The content is
   sized to the viewport and its last row sits on the fold, so any few pixels past it
   are decorative. Clip rather than scroll, on both the body and the element that
   actually scrolls (html). */
html:has(body.is-wall) { overflow: hidden; }
body.is-wall { overflow: hidden; }

/* main is the 1fr row of .shell, so it already owns the leftover viewport. Two things are
   needed for the wall to use it: a flex column, so .mkc-page can stretch into the height
   rather than sit at its content size, and no padding of its own. That padding was ~11px
   top and bottom, and it is the entire reason a 100dvh page ended 11px past the fold and
   the wall scrolled by a hair. Removing it here is better than subtracting it in a calc()
   somewhere else, which would silently rot the day the token changes. */
body.is-wall main {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0;
  gap: 0;
}

/* The top bar goes, but the theme toggle stays: a wall display is the one place a
   viewer cannot reach a menu, and a dark wall in a bright room (or the reverse) is
   the first thing they will want to change. Keeping the real control rather than
   cloning it means it keeps its id, and the layout's existing toggle script binds
   to it untouched. */
body.is-wall .top-bar {
  position: fixed;
  top: 0;
  right: 0;
  left: auto;
  width: auto;
  height: auto;
  min-height: 0;
  padding: var(--cs-xs);
  background: none;
  border: none;
  box-shadow: none;
  z-index: 4;
}

body.is-wall .top-bar-lead,
body.is-wall .fs-brand-url,
body.is-wall .top-bar-trail > *:not(.theme-toggle) { display: none; }

body.is-wall .theme-toggle { opacity: .45; transition: opacity .2s ease; }
body.is-wall .theme-toggle:hover,
body.is-wall .theme-toggle:focus-visible { opacity: 1; }

/* The toggle keeps the site tooltip, only repositioned.
   It ships as data-tooltip-pos="bottom", which is right for a top bar but not for a
   control parked in a screen corner: the bubble is centred on the button, so at top
   right it runs past the right edge, and in kiosk, where the button sits at the bottom
   left, it renders below the bottom of the screen and is simply never seen. Same bubble,
   same arrow, same timing, different anchor. */

/* Browser wall mode, button top right: still below, but anchored to the button's right
   edge instead of centred, so the bubble grows inward. The arrow stays centred because
   it points at the button, not at the bubble. */
body.is-wall .theme-toggle::before {
  left: auto;
  right: 0;
  transform: translateY(-4px);
}

body.is-wall .theme-toggle:hover::before,
body.is-wall .theme-toggle:focus-visible::before { transform: translateY(0); }

/* Kiosk: the toggle sits in the kiosk header, immediately right of the clock, so the
   tooltip keeps the bubble below and anchored to the button's right edge. That is what
   body.is-wall already sets and kiosk inherits, so there is nothing to override here
   beyond undoing the old bottom-left treatment, which pointed the bubble sideways. */

/* Kiosk only: in the header, to the right of the clock, and left of the space reserved
   for the window's caption buttons.
   It used to sit bottom left, because in a packaged app the page runs to the top edge
   and the top right corner is where Windows draws the close button. Now that the header
   exists and reserves that corner, the control belongs with the other header furniture
   rather than stranded in an opposite corner. */
body.is-kiosk .top-bar {
  top: 0;
  bottom: auto;
  left: auto;
  right: var(--mkc-caption-reserve);
  display: flex;
  align-items: center;
  height: var(--mkc-header-h);
  padding: 0 var(--cs-xs);
}

/* The toggle ships at a fixed 2.25rem, sized for the site top bar. In the kiosk header
   that made it half again as tall as the clock and the brand mark beside it, so the row
   read as a small header with one oversized control in it. Centres already matched; it
   is the box that was wrong. Scaled in vmin like the rest of the display, to the same
   height as the clock block, and the glyph with it. */
body.is-kiosk .top-bar .theme-toggle {
  width:  clamp(1.7rem, 3.6vmin, 2.6rem);
  height: clamp(1.7rem, 3.6vmin, 2.6rem);
}

body.is-kiosk .top-bar .theme-toggle svg {
  width:  clamp(1rem, 2.2vmin, 1.6rem);
  height: clamp(1rem, 2.2vmin, 1.6rem);
}

/* ── Kiosk support ask, top right ─────────────────────────────────────────────
   The corner the top bar vacates when kiosk moves it to bottom left. Fixed and
   padded to the same --cs-xs as the bar was, so the two sit symmetrically in
   opposite corners rather than one looking hand-placed.

   Held back at .45 opacity like the wall's theme toggle and lifting to full on
   hover or focus: an unattended screen is looked at for hours, and an ask that
   competes with the dials the whole time stops being an ask and becomes noise.

   MD3 Expressive on interaction, matching the filter chips a few rules up: fills
   with primary, morphs its corners across the diagonal, and springs forward on
   the overshoot curve. Scaled in vmin, because this is read from across a room. */
/* ── Kiosk support dialog ────────────────────────────────────────────────────
   An MD3 basic dialog. Deliberately NOT scaled in vmin like the rest of the wall:
   this is a communication surface someone reads and acts on up close, so it takes
   real reading sizes (Body Medium 14sp, Label Large 14sp on the buttons, Headline
   Small for the title) rather than the dense across-the-room type the dials use. */
.mkc-support {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--cs-md);
}

/* display:flex above beats the hidden attribute, which left a full-screen, fully
   transparent overlay sitting over the clocks and swallowing every click on the page.
   The attribute has to be given its meaning back explicitly. */
.mkc-support[hidden] { display: none !important; }

.mkc-support-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  opacity: 0;
  transition: opacity .22s ease;
}

.mkc-support-dialog {
  position: relative;
  width: min(28rem, 100%);
  max-height: 90vh;
  overflow-y: auto;
  padding: 1.5rem;                          /* 24dp */
  background: var(--md-surf-2);             /* surface-container-high */
  border-radius: 1.75rem;                   /* corner.extra-large, 28dp */
  box-shadow: 0 8px 32px rgba(0, 0, 0, .45);
  text-align: center;
  opacity: 0;
  transform: scale(.9);
  transition:
    opacity   .2s ease,
    transform .26s cubic-bezier(0.05, 0.7, 0.1, 1);
}

.mkc-support.is-open .mkc-support-scrim  { opacity: 1; }
.mkc-support.is-open .mkc-support-dialog { opacity: 1; transform: scale(1); }

/* Hero icon, 24dp and centred, which is the layout that centres the headline too. */
.mkc-support-icon {
  font-size: 1.5rem;
  color: var(--md-primary);
}

.mkc-support-title {
  margin: .5rem 0 0;
  font-family: var(--font-display);
  font-size: 1.5rem;                        /* headline.small, 24sp */
  font-weight: 600;
  line-height: 1.25;
  color: var(--md-on-surface);
}

.mkc-support-body {
  margin: .75rem 0 0;
  font-size: .875rem;                       /* body.medium, 14sp */
  line-height: 1.5;
  color: var(--md-on-surface-var);
}
.mkc-support-body p { margin: 0 0 .6rem; }
.mkc-support-body p:last-child { margin-bottom: 0; }

.mkc-support-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem;
  margin-top: 1.5rem;
}

.mkc-support-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;                       /* 40dp */
  padding: 0 1.5rem;
  border: none;
  border-radius: var(--shape-full, 999px);
  font-family: inherit;
  font-size: .875rem;                       /* label.large, 14sp */
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background .18s ease, transform .18s ease;
}

/* Scoped through the dialog so these beat `.legal-page a`, which is (0,1,1) and was
   painting the filled button's label in the primary colour, i.e. invisible on its own
   primary background. */
.mkc-support-dialog .mkc-support-btn--text {
  background: none;
  color: var(--md-primary);
}
.mkc-support-dialog .mkc-support-btn--text:hover {
  background: color-mix(in srgb, var(--md-primary) 12%, transparent);
}

.mkc-support-dialog .mkc-support-btn--filled {
  background: var(--md-primary);
  color: var(--md-on-primary);
}
.mkc-support-dialog .mkc-support-btn--filled:hover { transform: scale(1.04); }

.mkc-support-btn:focus-visible {
  outline: 2px solid var(--md-primary);
  outline-offset: 2px;
}

.mkc-support-note {
  margin: .9rem 0 0;
  font-size: .75rem;
  color: var(--md-on-surface-var);
  opacity: .8;
}

@media (prefers-reduced-motion: reduce) {
  .mkc-support-scrim,
  .mkc-support-dialog { transition: opacity .15s ease; }
  .mkc-support-dialog { transform: none; }
  .mkc-support.is-open .mkc-support-dialog { transform: none; }
  .mkc-support-btn--filled:hover { transform: none; }
}

/* Bottom LEFT. It started top right, which the header's clock now owns, and moved to
   bottom right, which the packaged app's own feedback button owns. Bottom left is the
   corner nothing claims any more: the theme toggle that used to sit here has gone up
   into the header. */
.mkc-kiosk-support {
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 4;
  padding: var(--cs-xs);
}

.kiosk-support-link {
  display: inline-flex;
  align-items: center;
  min-height: clamp(1.9rem, 3.2vmin, 2.8rem);
  padding: 0 clamp(0.6rem, 1.4vmin, 1.25rem);
  border-radius: clamp(0.75rem, 1.8vmin, 1.4rem);
  background: var(--md-surf-3);
  color: var(--md-on-surface);
  font-size: clamp(0.72rem, 1.3vmin, 1.1rem);
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  /* .45 borrowed from the wall's theme toggle, which is a glyph in a corner nobody
     needs to find. This is a sentence someone is meant to read from across a room,
     and at .45 it was simply too faint to do its job. */
  opacity: .8;
  transition:
    opacity       .2s ease,
    background    .3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
    color         .3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
    border-radius .3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
    transform     .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.kiosk-support-link:hover,
.kiosk-support-link:focus-visible {
  opacity: 1;
  background: var(--md-primary);
  color: var(--md-on-primary);
  font-weight: 700;
  border-radius: 0.25rem clamp(1.5rem, 3.5vmin, 3rem) 0.25rem clamp(1.5rem, 3.5vmin, 3rem);
  transform: scale(1.05);
}

.kiosk-support-link:focus-visible {
  outline: 0.125rem solid var(--md-primary);
  outline-offset: 0.125rem;
}

/* The shared markup ships data-tooltip-pos="bottom" (right for the top bar). In the
   bottom-left corner a bubble drawn below runs off the screen, so pull it back above
   the link and anchor it to the LEFT edge so it also never spills past the side. Same
   bubble, same arrow, different anchor, exactly how wall mode repositions the theme
   toggle's tooltip. */
.mkc-kiosk-support .kiosk-support-link[data-tooltip-pos="bottom"]::before {
  top: auto;
  bottom: calc(100% + 8px);
  right: auto;
  left: 0;
  transform: translateX(0) translateY(4px);
}

.mkc-kiosk-support .kiosk-support-link[data-tooltip-pos="bottom"]::after {
  top: auto;
  bottom: calc(100% + 2px);
  right: auto;
  left: clamp(1rem, 4vmin, 3rem);
  transform: translateX(0) translateY(4px);
  border-top: 5px solid #2a2d36;
  border-bottom: none;
}

.mkc-kiosk-support .kiosk-support-link[data-tooltip-pos="bottom"]:hover::before,
.mkc-kiosk-support .kiosk-support-link[data-tooltip-pos="bottom"]:hover::after,
.mkc-kiosk-support .kiosk-support-link[data-tooltip-pos="bottom"]:focus-visible::before,
.mkc-kiosk-support .kiosk-support-link[data-tooltip-pos="bottom"]:focus-visible::after {
  transform: translateX(0) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .kiosk-support-link { transition: opacity .2s ease, background .2s ease, color .2s ease; }
  .kiosk-support-link:hover,
  .kiosk-support-link:focus-visible { transform: none; }
}

/* The wall takes whatever the header leaves, and the grid stretches inside it,
   so twelve cards divide the real estate instead of sitting in a fixed block. */
body.is-wall .mkc-wall {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* The section's normal bottom margin separates it from the prose that follows on the
     content page. On the wall there is no prose, only the signature, and the page already
     reserves a lane for that. Keeping the margin stacked a third gap under the cards and
     left a band of dead black between the last row and the mark. */
  margin-bottom: 0;
}

body.is-wall .mkc-grid {
  flex: 1;
  min-height: 0;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
}

/* Six across only once the width can carry it. Below that the aspect decides:
   a portrait panel gets a tall 3x4, which is the shape a phone or a rotated
   monitor actually is. */
@media (max-width: 1200px) {
  body.is-wall .mkc-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-template-rows: repeat(3, minmax(0, 1fr));
  }
}

@media (orientation: portrait) {
  body.is-wall .mkc-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: repeat(4, minmax(0, 1fr));
  }
}

/* Filtered wall: drop the fixed 6x2 / 4x3 / 3x4 shapes, which assume twelve cards
   and would otherwise leave holes. Declared after those blocks so it wins without
   needing !important, and repeated inside the portrait and narrow queries because
   those set explicit rows. */
/* Five or more: back to the wall exactly as it looks with all twelve.

   Below five, a filtered wall is a trading-desk view and the dials should grow into
   the space. From five up there is no space to grow into, and a fifth clock at a
   bespoke size next to a sixth at another is just an inconsistent wall. The cards
   simply fill the first cells of the standard grid and leave the rest empty.

   The grid falls back on its own: body.is-wall .mkc-grid carries one more element
   than .mkc-grid.is-filtered, so the 6x2, 4x3 and 3x4 shapes and their breakpoints
   win with nothing restated here. Only the dial needs saying, because a custom
   property resolves from the nearest ancestor that declares it, and the content
   page set one on the grid itself. inherit pulls the wall's own value down from
   .mkc-page rather than repeating the clamp and letting the two drift. */
body.is-wall .mkc-grid.is-filtered:not(.is-few) {
  --mkc-dial: inherit;
  max-width: none;
}
/* Four markets or fewer on a wall: the trading-desk configuration.

   Keyed on is-few, not is-showcase, so four behaves like three. Four is is-few but
   not is-showcase, so it used to miss these rules and keep the content page's
   max-width: 64rem. Inside a 1024px cap, four columns are 256px while the dial
   asked for 288px, which overflowed and scrolled the wall.

   The card is a grid here, not the flex box the wall rules were written against,
   so gap and justify-content from body.is-wall .mkc-card are restated as their
   grid equivalents rather than left to mean something different. */
body.is-wall .mkc-grid.is-few {
  grid-template-columns: repeat(var(--mkc-n, 1), minmax(0, 1fr));
  grid-template-rows: none;
  /* Bounded by both axes, because a wall is a fixed rectangle and only one of the
     two ever binds.

     Dividing by the count alone sized the dial to its column and ignored the
     height: three clocks each got 23vmin, about 210px, while 430px of vertical
     space sat empty above and below them. Dividing by height alone overflows the
     moment a second clock appears.

     48vh is the height budget: 100dvh less the header, the filter chips, the
     signature and the card's own city and text lines. 78vw split by the count is
     the width each column can give. Whichever is smaller decides, so one clock is
     held by the height and three are held by their columns. */
  --mkc-dial: clamp(9rem, min(48vh, calc(78vw / var(--mkc-n, 1))), 40rem);
  max-width: none;
}

/* Stacked, not the landscape split the content page uses at one and two clocks.
   On a wall the dial is the content and the column is the constraint: splitting it
   sideways caps the dial at roughly half the column and leaves the text a strip too
   narrow to read anyway. Stacked, the dial takes the full column width and the
   lines sit under it, which is the same reasoning that sent three-across back to
   stacked in reading mode. */
body.is-wall .mkc-grid.is-few .mkc-card {
  display: grid;
  grid-template-columns: 1fr;
  row-gap: .25rem;
  align-content: center;
  justify-items: center;
  text-align: center;
}

body.is-wall .mkc-grid.is-few .mkc-city,
body.is-wall .mkc-grid.is-few .mkc-offset,
body.is-wall .mkc-grid.is-few .mkc-dial,
body.is-wall .mkc-grid.is-few .mkc-session,
body.is-wall .mkc-grid.is-few .mkc-local,
body.is-wall .mkc-grid.is-few .mkc-boundary,
body.is-wall .mkc-grid.is-few .mkc-reason,
body.is-wall .mkc-grid.is-few .mkc-chip { grid-column: 1; grid-row: auto; }

body.is-wall .mkc-grid.is-few .mkc-city { font-size: clamp(1.6rem, 5vmin, 4.5rem); }

body.is-wall .mkc-grid.is-few .mkc-session,
body.is-wall .mkc-grid.is-few .mkc-local,
body.is-wall .mkc-grid.is-few .mkc-offset,
body.is-wall .mkc-grid.is-few .mkc-boundary { font-size: clamp(.85rem, 2vmin, 1.8rem); }

body.is-wall .mkc-grid.is-few .mkc-chip { font-size: clamp(.8rem, 1.8vmin, 1.6rem); }

/* A portrait wall has no width for a text column beside a 34vmin dial. Same call
   as the phone: stack it, and let the dial use the width instead. */
@media (orientation: portrait) {
  body.is-wall .mkc-grid.is-few {
    grid-template-columns: 1fr;
    --mkc-dial: clamp(10rem, 42vmin, 44rem);
  }

  body.is-wall .mkc-grid.is-few .mkc-card {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
  }

  body.is-wall .mkc-grid.is-few .mkc-city,
  body.is-wall .mkc-grid.is-few .mkc-offset,
  body.is-wall .mkc-grid.is-few .mkc-dial,
  body.is-wall .mkc-grid.is-few .mkc-session,
  body.is-wall .mkc-grid.is-few .mkc-local,
  body.is-wall .mkc-grid.is-few .mkc-boundary,
  body.is-wall .mkc-grid.is-few .mkc-reason,
  body.is-wall .mkc-grid.is-few .mkc-chip { grid-column: 1; grid-row: auto; }
}

/* Dials scale with the viewport rather than sitting at a fixed rem: the whole
   point of a wall is being readable from across a room, and vmin tracks the
   smaller axis so a wide TV does not overflow vertically. */
body.is-wall .mkc-page { --mkc-dial: clamp(7rem, 18vmin, 20rem); }
body.is-wall .mkc-city { font-size: clamp(1.05rem, 2.5vmin, 2.2rem); }

/* The countdown is sized off the dial, not off the viewport, so the digits keep
   the same relationship to the ring at every screen size instead of drifting
   small inside a large circle.

   The multiplier is set by the widest string the dial ever shows, HH:MM:SS, at
   eight characters: Sydney counts 12:35:03 to its next open and Mumbai 16:20:03.
   Eight tabular figures run about 4.6em, and the usable width inside the ring is
   roughly three quarters of the dial, which caps this at .159. Anything larger
   clips the leading and trailing digits, which is what .215 did. */
body.is-wall .mkc-count {
  font-size: calc(var(--mkc-dial) * .15);
  white-space: nowrap;
}

body.is-wall .mkc-offset,
body.is-wall .mkc-session,
body.is-wall .mkc-local,
body.is-wall .mkc-boundary { font-size: clamp(0.72rem, 1.45vmin, 1.15rem); }

body.is-wall .mkc-chip { font-size: clamp(0.68rem, 1.3vmin, 1rem); }

body.is-wall .mkc-card { gap: .25rem; justify-content: center; }

/* ── Wall contrast ──────────────────────────────────────────────────────────
   The glass is a white veil: a 5% white fill over three blurred colour blobs.
   At card size that reads as frost. Stretched to a sixth of a screen it reads
   as fog sitting on top of the numbers.

   So on the wall the fill inverts to the page's own background instead of to
   white, which darkens in dark mode and lightens in light mode from one token,
   and the sky is pulled back so it lights the gaps between cards rather than
   hazing their faces. Content then sits on a surface instead of inside one.  */

/* The sheen is restated here for the same reason it is restated on the live cards and in
   light mode: background is a shorthand, and these two rules outrank the base card, so
   naming only a fill silently drops the gradient layer. On the wall it is scaled up a
   little, because a card stretched to a sixth of a screen shows a gentle ramp over a much
   longer distance and the same values read as almost nothing. */
body.is-wall .mkc-card {
  /* Side rims, one per edge, phase-keyed like the top. Radial rather than another inset
     shadow: an inset from the left runs the full height of the card, and these are meant to
     bloom from the middle of each edge and fade out towards the corners, the way light
     catches the curve of a glass pane. Anchored at 0% 50% and 100% 50%, so the brightest
     point sits exactly at the vertical centre of each side.

     Layer order is top-down: both side rims sit over the top sheen, which sits over the
     fill. They overlap only in the corners, where both are already near zero. */
  background:
    radial-gradient(ellipse 32% 44% at 0% 50%,
      color-mix(in srgb, var(--mkc-phase) 12%, transparent), transparent 72%),
    radial-gradient(ellipse 32% 44% at 100% 50%,
      color-mix(in srgb, var(--mkc-phase) 12%, transparent), transparent 72%),
    linear-gradient(180deg,
      rgba(255, 255, 255, .10) 0%,
      rgba(255, 255, 255, .035) 34%,
      rgba(255, 255, 255, 0)    62%),
    color-mix(in srgb, var(--md-background) 62%, transparent);
  border-color: color-mix(in srgb, var(--mkc-phase) 48%, transparent);
  /* The top rim, in three parts: a crisp bright hairline on the edge itself, a short bloom
     falling from it into the card, and the existing drop shadow underneath.

     The bloom is keyed to --mkc-phase rather than to white, so it costs nothing to have a
     trading card glow mint or amber along its top while a closed one stays grey: --mkc-shut
     is already the phase value for closed, so one declaration covers all twelve states.

     The negative spread on the bloom is what keeps it a rim rather than an inner glow: it
     pulls the shadow in from every edge, and the 6px y-offset pushes what is left down from
     the top only. */
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--md-on-surface) 42%, transparent),
    inset 0 7px 16px -7px color-mix(in srgb, var(--mkc-phase) 55%, transparent),
    0 10px 32px rgba(0, 0, 0, .40);
}

/* The light-mode card rule carries one more class than body.is-wall .mkc-card, so it wins on
   the wall too and the rim above never paints. Restated at higher specificity, with a white
   hairline instead of an on-surface one: on-surface is near-black in light mode, which would
   have drawn a shadow along the top edge rather than a highlight. */
html[data-theme="light"] body:not(.is-dashboard).is-wall .mkc-card {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 7px 16px -7px color-mix(in srgb, var(--mkc-phase) 42%, transparent),
    0 8px 24px rgba(0, 0, 0, .12);
  /* background needs restating for the same specificity reason as the shadow above. The
     rims run a little stronger here: they sit on a near-white pane, where the dark theme's
     tint of a pale phase colour is close to invisible. */
  background:
    radial-gradient(ellipse 32% 44% at 0% 50%,
      color-mix(in srgb, var(--mkc-phase) 17%, transparent), transparent 72%),
    radial-gradient(ellipse 32% 44% at 100% 50%,
      color-mix(in srgb, var(--mkc-phase) 17%, transparent), transparent 72%),
    linear-gradient(180deg,
      rgba(255, 255, 255, .92) 0%,
      rgba(255, 255, 255, .30) 34%,
      rgba(255, 255, 255, 0)   62%),
    rgba(255, 255, 255, .62);
}

/* Both rims restated, a few points hotter. A trading card is the one being read from across
   the room, and its phase colour is a live green or amber rather than the closed grey, so it
   can carry more without turning into decoration. */
body.is-wall .mkc-card.is-open,
body.is-wall .mkc-card.is-auction,
body.is-wall .mkc-card.is-power,
body.is-wall .mkc-card.is-lunch {
  background:
    radial-gradient(ellipse 32% 44% at 0% 50%,
      color-mix(in srgb, var(--mkc-phase) 15%, transparent), transparent 72%),
    radial-gradient(ellipse 32% 44% at 100% 50%,
      color-mix(in srgb, var(--mkc-phase) 15%, transparent), transparent 72%),
    linear-gradient(180deg,
      rgba(255, 255, 255, .13) 0%,
      rgba(255, 255, 255, .045) 34%,
      rgba(255, 255, 255, 0)    62%),
    color-mix(in srgb, var(--md-background) 52%, transparent);
  border-color: color-mix(in srgb, var(--mkc-phase) 88%, transparent);
}

/* The side edges as a lit line rather than a flat border: ordinary at top and bottom, full
   phase colour across the middle. border-color cannot vary along an edge and border-image
   would drop the 1.625rem radius, so the line is drawn as two thin vertical strips on a
   pseudo-element instead.

   z-index: -1 is doing real work. .mkc-card is position: relative with z-index: 1, so it
   opens a stacking context; a positioned pseudo-element at auto would paint above the card's
   own text, since the city name and countdown are static children. Negative z-index puts the
   strips above the card's background and below its content, which is exactly where an edge
   light belongs.

   The strips are straight while the corners are round, so both gradients are transparent
   through the first and last 12%: the overshoot past the curve has no colour in it to show.
   ::before is free here, ::after is spoken for by the New York marker. */
body.is-wall .mkc-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background-image:
    linear-gradient(to bottom,
      transparent 12%,
      color-mix(in srgb, var(--mkc-phase) 85%, transparent) 50%,
      transparent 88%),
    linear-gradient(to bottom,
      transparent 12%,
      color-mix(in srgb, var(--mkc-phase) 85%, transparent) 50%,
      transparent 88%);
  background-size: 1.5px 100%, 1.5px 100%;
  background-position: left center, right center;
  background-repeat: no-repeat;
}

/* A trading card's edge line goes to full strength. Closed markets keep the muted version
   above, so the wall still separates live from shut at a glance. */
body.is-wall .mkc-card.is-open::before,
body.is-wall .mkc-card.is-auction::before,
body.is-wall .mkc-card.is-power::before,
body.is-wall .mkc-card.is-lunch::before {
  background-image:
    linear-gradient(to bottom,
      transparent 10%,
      var(--mkc-phase) 50%,
      transparent 90%),
    linear-gradient(to bottom,
      transparent 10%,
      var(--mkc-phase) 50%,
      transparent 90%);
  background-size: 2px 100%, 2px 100%;
}

body.is-wall .mkc-blob { opacity: .26; }

/* Kiosk cards let more through than wall cards do, because in kiosk there is something
   behind them worth seeing: the faceted field. 62% of the page background at rest drops
   to 44%, and the live ones from 52% to 36%, so a facet edge running under a card stays
   readable through it and the glass picks up the fold instead of masking it.

   Safe to go this far only because the phase chip is opaque now. It mixes into a surface
   token rather than washing over whatever is behind it, so its measured contrast does not
   move when the card thins. The dials and the city names sit on near-background either
   way, since the facets top out around 5% of on-surface. */
body.is-kiosk .mkc-card {
  background: color-mix(in srgb, var(--md-background) 44%, transparent);
}

body.is-kiosk .mkc-card.is-open,
body.is-kiosk .mkc-card.is-auction,
body.is-kiosk .mkc-card.is-power,
body.is-kiosk .mkc-card.is-lunch {
  background: color-mix(in srgb, var(--md-background) 36%, transparent);
}

/* Text lifts in kiosk. The muted tokens are calibrated for a dense card at arm's length,
   and across a room --md-outline on a thinned card is close to unreadable. Everything
   moves onto on-surface and keeps its hierarchy through alpha instead of through hue, so
   light mode inverts with it rather than needing a second set of colours. */
body.is-kiosk .mkc-session,
body.is-kiosk .mkc-local,
body.is-kiosk .mkc-boundary,
body.is-kiosk .mkc-offset {
  color: color-mix(in srgb, var(--md-on-surface) 80%, transparent);
}

/* The moon comes up with it. At .45 it read as disabled rather than quiet, and it is the
   only control on the screen, so it has to be findable without being hunted for. */
body.is-kiosk .theme-toggle {
  opacity: .9;
  color: var(--md-on-surface);
}

/* Saturate rather than blur harder: the point is to make what shows through the
   glass more vivid, not to smear more of it across the card. */
@media (min-width: 641px) {
  body.is-wall .mkc-card {
    -webkit-backdrop-filter: blur(22px) saturate(190%);
    backdrop-filter: blur(22px) saturate(190%);
  }
}

/* The two things read from across a room get full contrast, not the muted
   variant that suits a dense card at arm's length. */
body.is-wall .mkc-city { color: var(--md-on-surface); }
body.is-wall .mkc-card.is-closed .mkc-count,
body.is-wall .mkc-card.is-holiday .mkc-count { color: var(--md-on-surface-var); }

/* Kiosk lifts them again, and must sit after the wall rule above: same specificity, so
   source order is the only thing deciding it. Closed markets still read a step back from
   the trading ones, but a legible step rather than the dimmest token on the page. */
body.is-kiosk .mkc-card.is-closed  .mkc-count,
body.is-kiosk .mkc-card.is-holiday .mkc-count {
  color: color-mix(in srgb, var(--md-on-surface) 88%, transparent);
}

body.is-wall .mkc-head { margin-bottom: var(--cs-xs); }

/* The full session, on every card at every size. It was wall-only on the theory that a
   normal card is too dense for it, but the card has room to spare and the line answers the
   other half of the page's question: not just how long until the bell, but what the hours
   actually are. It also carries the exchange's name, which is the one thing a card had no
   way of stating outside wall mode. */
.mkc-session {
  display: block;
  margin: 0;
  font-size: var(--ct-xs);
  line-height: 1.35;
  color: var(--md-on-surface-var);
  font-family: var(--font-mono);
  letter-spacing: .02em;
}

/* The venue is the exchange's name, so it carries the weight while the hours beside it stay
   regular. 700 rather than 500: this is a mono face at a small size, where 500 is close to
   indistinguishable from 400, and the code is meant to be findable at a glance across a
   room. Lifted to full on-surface too, since weight alone on a muted colour still reads as
   secondary. */
.mkc-venue {
  font-weight: 700;
  color: var(--md-on-surface);
}

/* ── The signature ──────────────────────────────────────────────────────────
   A wall display is seen by people who did not open it, so it has to say where
   it came from. Bottom-right, out of the grid's way, breathing slowly so it
   reads as alive rather than as a static watermark burned into a panel.     ---- */

/* ── Kiosk backdrop ─────────────────────────────────────────────────────────
   Not a flat field. A charcoal-to-near-black gradient for depth, with a fine
   tessellated wireframe over it, which is what lets the cards read as elevated
   surfaces catching light rather than as rectangles drawn on black.

   Kiosk only, and behind everything: z-index 0 against the cards' 1, so the mesh
   never competes with a dial. Built from tokens, so light mode gets dark lines on
   a pale field instead of white lines vanishing into white.                  ---- */

.mkc-facets { display: none; }

body.is-kiosk .mkc-facets {
  display: block;
  position: fixed;
  inset: 0;
  /* -1, not 0. A positioned element at z-index 0 paints above ordinary in-flow
     content, so this gradient covered the answer sentence and the header: the cards
     survived only because they carry z-index 1 of their own. Negative puts it behind
     the text while still sitting above the page canvas. */
  z-index: -1;
  pointer-events: none;
  /* The gradient field: lifted at the top where the header sits, settling to the
     page background below, so the wall has a horizon rather than a wash. */
  background:
    radial-gradient(120% 75% at 50% 0%,
      color-mix(in srgb, var(--md-surf-2) 60%, transparent) 0%,
      transparent 55%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--md-surf-2) 40%, var(--md-background)) 0%,
      var(--md-background) 60%);
}

/* The facets. Each polygon carries its own opacity in the markup, so this only sets the
   hue and an overall ceiling. Kept low on purpose: the facets are meant to be felt as
   depth behind the glass, not read as shapes competing with the dials. */
body.is-kiosk .mkc-facets svg {
  display: block;
  width: 100%;
  height: 100%;
  color: var(--md-on-surface);
  /* The one dial for the whole effect. Each facet carries its own opacity in the markup
     and this scales all of them together, so strength is tuned here rather than across
     twenty-four polygons. */
  opacity: 1;
}

/* The brand now lives in the kiosk header, so the foot carries only a quiet
   copyright line. Centred at the bottom, muted, and out of the way of the dials.
   Shown in wall mode only; the reading page has the content footer for this. */
.mkc-copyright { display: none; }

body.is-wall .mkc-copyright {
  display: block;
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: var(--cs-xs);
  z-index: 3;
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(.7rem, 1.4vmin, 1.15rem);
  letter-spacing: .08em;
  color: var(--md-on-surface-var);
  opacity: .7;
}

/* ── Kiosk header ────────────────────────────────────────────────────────────
   A branded bar across the top of the kiosk only: the GMD mark and the display's
   name on the left, a live UTC clock on the right. Browser wall mode keeps the
   site top bar, so this renders solely under body.is-kiosk. flex: 0 0 auto so it
   takes its own height off the top and the grid fills what is left, and lifted
   above the faceted glass with z-index. */
.mkc-kiosk-header { display: none; }

/* Shared by the header and by the theme toggle parked inside it, so the two agree on
   where the right edge stops. --mkc-caption-reserve is the strip left clear for the
   window's caption buttons (three at 46 device-independent pixels each, plus margin);
   drop it to about 3rem for a frame that only draws a close button. */
body.is-kiosk {
  --mkc-caption-reserve: 9rem;
  --mkc-toggle-w: 3rem;
  --mkc-header-h: clamp(3rem, 6.6vmin, 5.5rem);
}

/* The header runs to the top edge in kiosk, so it reads as the window's own bar and the
   toggle parked in it (fixed, at top: 0) lines up with the clock instead of floating
   above it. Also hands the ~11px back to the grid. */
body.is-kiosk .mkc-page { padding-top: 0; }

body.is-kiosk .mkc-kiosk-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cs-sm);
  flex: 0 0 auto;
  position: relative;
  z-index: 3;
  /* Pinned rather than content-sized so the toggle, which is fixed rather than a child
     of this row, can be given the same height and centre on the same line. */
  height: var(--mkc-header-h);
  padding: clamp(.3rem, 1.1vmin, 1rem) clamp(.4rem, 1.4vmin, 1.3rem);
  /* Right edge, in order: the clock, then the theme toggle, then the space left clear
     for the window's caption buttons. The reserve exists because kiosk is what the
     packaged Windows app runs, where the page reaches the top edge and that corner is
     where Windows draws the X: the clock was sitting under it. Both numbers are
     variables (see body.is-kiosk) because how much room the caption needs depends on
     whether the window shows one button or all three, at 46 device-independent pixels
     each, so a display can be tuned in one place. */
  padding-right: calc(var(--mkc-caption-reserve) + var(--mkc-toggle-w) + clamp(.4rem, 1.4vmin, 1.3rem));
  margin-bottom: var(--cs-xs);
  border-bottom: 1px solid var(--md-outline-var);
}

/* Reuses the site .brand-icon / .brand-text, so nothing here restyles the mark. */
body.is-kiosk .mkc-kh-brand {
  display: flex;
  align-items: center;
  gap: var(--sp-md, .75rem);
  text-decoration: none;
}

body.is-kiosk .mkc-kh-clock {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.05;
}

body.is-kiosk .mkc-kh-time {
  font-family: var(--font-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  font-size: clamp(.95rem, 2.1vmin, 2rem);
  color: var(--md-primary);
}

body.is-kiosk .mkc-kh-date {
  font-size: clamp(.6rem, 1.1vmin, .95rem);
  color: var(--md-on-surface-var);
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* The brand reuses the site .brand-text, whose sizes are tuned for the top bar. On a
   wall header the row only needs to be legible, not lead, so both lines come down a
   step. Scoped here so the top bar everywhere else is untouched. */
body.is-kiosk .mkc-kh-brand .brand-name { font-size: clamp(.85rem, 1.9vmin, 1.35rem); }
body.is-kiosk .mkc-kh-brand .brand-sub  { font-size: clamp(.55rem, 1vmin, .8rem); }
body.is-kiosk .mkc-kh-brand .brand-icon {
  width:  clamp(1.6rem, 3.2vmin, 2.3rem);
  height: clamp(1.6rem, 3.2vmin, 2.3rem);
  font-size: clamp(.6rem, 1.15vmin, .8rem);
}

/* Kiosk only: drop the question and the answer line. An unattended display carries
   the branded header and the dials, each ring already showing its market's state, so
   the prose sentence ("No. All 12 exchanges are closed. Sydney opens first, in...")
   is redundant there. Browser wall mode (?wall=1) keeps it, since a person opened it
   and the sentence is the quick answer. The element stays in the DOM so the countdown
   script has nothing to trip over. */
body.is-kiosk .mkc-head { display: none; }

/* ── The toggle ─────────────────────────────────────────────────────────────
   Hidden until the script proves it can run: a button that does nothing is
   worse than no button, and this one is useless without JS.                ---- */

.mkc-wall-btn {
  display: none;
  align-items: center;
  gap: .4rem;
  padding: .4rem .85rem;
  border: 1px solid var(--md-outline-var);
  border-radius: var(--shape-chip);
  background: color-mix(in srgb, var(--md-on-surface) 6%, transparent);
  color: var(--md-on-surface-var);
  font-family: inherit;
  font-size: var(--ct-sm);
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}

.mkc-page.is-wall-ready .mkc-wall-btn { display: inline-flex; }

.mkc-wall-btn:hover {
  color: var(--md-on-surface);
  background: color-mix(in srgb, var(--md-on-surface) 12%, transparent);
}

.mkc-wall-btn:focus-visible {
  outline: 2px solid var(--md-primary);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  body.is-wall .mkc-signature { animation: none; opacity: .85; }
}
