/* ══════════════════════════════════════════════════════════════════════
   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;
}

/* ── 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 ───────────────────────────────────────────────────────────── */
.legal-hero {
  background: 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: #4CAF50; 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);
}
/* 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); }

/* 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: #2ea043; }
.wh-blob--2 { width: 20rem; height: 20rem; right: -5rem; top: 20%;      background: #e5534b; }
.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, #2ea043 0%, #d7a52b 50%, #e5534b 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, #e5534b 0%, #d7a52b 50%, #2ea043 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: #2ea043; border-color: rgba(46,160,67,.4); }
.wh-live.is-open .wh-live-dot { background: #2ea043; 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: #2ea043; }
.mtd-down { color: #e5534b; }
html[data-theme="light"] .mtd-up   { color: #135c28; }
html[data-theme="light"] .mtd-down { color: #99261b; }

@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. */
.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-var);
}

/* The scale itself. Same reds and greens as the heatmap, so a rise reads
   the same everywhere on the site. */
.mtd-arc-track {
  position: relative;
  height: 10px;
  border-radius: var(--shape-full, 999px);
  background: linear-gradient(90deg, #e5534b 0%, #d7a52b 50%, #2ea043 100%);
  /* Fixed bottom gap, not a clamp token: it has to clear the staggered labels
     below the track, whose offsets are fixed rem values. */
  margin: var(--cs-lg) 0 4rem;
}

.mtd-arc-marker {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.mtd-arc-dot {
  width: 16px;
  height: 16px;
  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);
}

/* The newest reading is the one that matters now, so it gets the accent. */
.mtd-arc-marker:last-child .mtd-arc-dot {
  border-color: var(--md-primary);
  transform: scale(1.15);
}

.mtd-arc-label {
  position: absolute;
  top: 1.25rem;
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  font-weight: 700;
  white-space: nowrap;
  color: var(--md-on-surface-var);
}

/* Stagger every second label so two close readings do not collide. */
.mtd-arc-marker:nth-child(even) .mtd-arc-label { top: 2.4rem; }

.mtd-arc-scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--ct-xs);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--md-on-surface-var);
  margin-bottom: var(--cs-sm);
}

.mtd-arc-note {
  font-size: var(--ct-sm);
  line-height: 1.55;
  color: var(--md-on-surface-var);
  margin: 0;
}

/* ── 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); }
  .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);
}

/* 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,
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; }

/* 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, button bottom left: to the right of the button, which is the site's existing
   data-tooltip-pos="right" treatment reproduced here, since the attribute is set in the
   shared layout and cannot vary per mode. */
body.is-kiosk .theme-toggle::before {
  top: 50%;
  bottom: auto;
  left: calc(100% + 8px);
  right: auto;
  transform: translateY(-50%) translateX(-4px);
}

body.is-kiosk .theme-toggle::after {
  top: 50%;
  bottom: auto;
  left: calc(100% + 2px);
  transform: translateY(-50%) translateX(-4px);
  border: 5px solid transparent;
  border-right-color: #2a2d36;
  border-left: none;
}

body.is-kiosk .theme-toggle:hover::before,
body.is-kiosk .theme-toggle:hover::after,
body.is-kiosk .theme-toggle:focus-visible::before,
body.is-kiosk .theme-toggle:focus-visible::after { transform: translateY(-50%) translateX(0); }

/* Kiosk only: bottom left instead of top right.
   In a browser the viewport starts below the browser chrome, so top right is nothing
   but page. In a packaged app the page runs to the top edge and that corner is where
   Windows draws the close button, which the toggle was sitting on top of.
   Bottom left is the corner nothing else claims: macOS keeps its controls top left,
   the signature is centred, and the legend that used to sit here is gone. */
body.is-kiosk .top-bar {
  top: auto;
  bottom: 0;
  right: auto;
  left: 0;
}

/* ── 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. */
.mkc-kiosk-support {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 4;
  padding: var(--cs-xs);
}

.kiosk-support-link {
  display: inline-flex;
  align-items: center;
  min-height: clamp(2.5rem, 5vmin, 4.5rem);
  padding: 0 clamp(0.75rem, 2vmin, 2rem);
  border-radius: clamp(1rem, 2.5vmin, 2rem);
  background: var(--md-surf-3);
  color: var(--md-on-surface);
  font-size: clamp(0.875rem, 2vmin, 1.75rem);
  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;
}

@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;
}

.mkc-signature { display: none; }

body.is-wall .mkc-signature {
  display: block;
  position: fixed;
  /* Centred on the wall rather than tucked into the right corner: on a display seen
     from across a room the mark is the only thing that says where this came from, and
     the corner is the first thing a viewer's eye skips. The breathe animation is
     opacity only, so the centring transform is never fighting it. */
  left: 50%;
  transform: translateX(-50%);
  bottom: var(--cs-xs);
  z-index: 3;
  font-family: var(--font-mono);
  font-size: clamp(1.35rem, 3.1vmin, 3rem);
  font-weight: 700;
  letter-spacing: .12em;
  /* Brand colour, through the token rather than the hex, so it stays the cyan
     #4DD0E1 in dark and drops to #006780 in light without a second rule. The
     halo is mixed from the same token for the same reason. */
  color: var(--md-primary);
  text-shadow: 0 0 clamp(8px, 1.4vmin, 18px) color-mix(in srgb, var(--md-primary) 35%, transparent);
  opacity: .8;
  animation: mkc-sig-breathe 6s ease-in-out infinite;
  /* No underline: .legal-page a carries the site's link styling, and a rule under a
     wordmark reads as a typo from across a room rather than as an affordance. */
  text-decoration: none;
}

/* Hover and keyboard focus settle the mark at full strength. The animation has to be
   dropped rather than overridden: a running animation beats a plain opacity
   declaration, so setting opacity alone would do nothing here. */
body.is-wall .mkc-signature:hover,
body.is-wall .mkc-signature:focus-visible {
  animation: none;
  opacity: 1;
}

body.is-wall .mkc-signature:focus-visible {
  outline: 2px solid var(--md-primary);
  outline-offset: .35rem;
  border-radius: .35rem;
}

/* A narrower range than a plain fade: the mark is brand now, so it should stay
   legible at the bottom of the breath rather than dissolving. */
@keyframes mkc-sig-breathe {
  0%, 100% { opacity: .6; }
  50%      { opacity: .95; }
}

/* ── 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; }
}
