/* ============================================================
   Yubira design tokens — olive/clay palette, light + dark mode.
   Built on Bootstrap 5.3's data-bs-theme feature: structural
   dark-mode adaptation (cards, forms, modals, tables) comes free
   from Bootstrap's own [data-bs-theme=dark] rules once that
   attribute is set on <html>; what we override here is just the
   brand hue (primary/secondary) and the base surface tokens,
   since Bootstrap's compiled CSS bakes its default blue directly
   into component-scoped vars like .btn-primary's --bs-btn-bg,
   which don't react to a root --bs-primary override on their own.
   ============================================================ */

:root,
[data-bs-theme="light"] {
  --yubira-ink: #2A2A24;
  --yubira-ink-olive: #3B4A1E;
  --yubira-olive: #5B6B33;
  --yubira-olive-hover: #2E3616;
  --yubira-clay: #B5652D;
  --yubira-clay-hover: #9C561F;
  --yubira-parchment: #EDE9DA;
  --yubira-surface: #FAF8F1;
  --yubira-card-bg: #FAF8F1;
  --yubira-card-bg-rgb: 250, 248, 241; /* same value as --yubira-card-bg, split out for rgba() use (event-card hero backdrop) */
  --yubira-border: #DAD3BE;

  --bs-body-bg: var(--yubira-parchment);
  --bs-body-color: var(--yubira-ink);
  --bs-border-color: var(--yubira-border);
  --bs-primary: var(--yubira-ink-olive);
  --bs-primary-rgb: 59, 74, 30;
  --bs-link-color: var(--yubira-ink-olive);
  --bs-link-color-rgb: 59, 74, 30;
  --bs-link-hover-color: var(--yubira-olive-hover);
  --bs-link-hover-color-rgb: 46, 54, 22;
}

[data-bs-theme="dark"] {
  --yubira-ink: #ECE8D8;
  --yubira-ink-olive: #9CB36B;
  --yubira-olive: #A9B98A;
  --yubira-olive-hover: #C4D19E;
  --yubira-clay: #E08A50;
  --yubira-clay-hover: #EDA36F;
  --yubira-parchment: #23241C;
  --yubira-surface: #2C2D22;
  --yubira-card-bg: #34362A;
  --yubira-card-bg-rgb: 52, 54, 42; /* same value as --yubira-card-bg, split out for rgba() use (event-card hero backdrop) */
  --yubira-border: #454731;

  --bs-body-bg: var(--yubira-parchment);
  --bs-body-color: var(--yubira-ink);
  --bs-border-color: var(--yubira-border);
  --bs-tertiary-bg: var(--yubira-surface);
  --bs-secondary-bg: var(--yubira-surface);
  --bs-primary: var(--yubira-ink-olive);
  --bs-primary-rgb: 156, 179, 107;
  --bs-link-color: var(--yubira-ink-olive);
  --bs-link-hover-color: var(--yubira-olive-hover);
}

body {
  background-color: var(--bs-body-bg);
  color: var(--bs-body-color);
}

/* ---- Brand-color button overrides ----
   Bootstrap's shipped CSS hardcodes .btn-primary's --bs-btn-bg to a
   literal hex, not a reference to root --bs-primary — so recoloring
   the brand hue means overriding the component-scoped vars directly.
   Only primary/secondary are remapped; success/danger/warning stay
   Bootstrap defaults on purpose — "delete is red, confirm is green" is
   an established convention across every page already built, and
   fighting it for brand consistency isn't worth the confusion. */
.btn-primary {
  --bs-btn-color: #fff;
  --bs-btn-bg: var(--yubira-ink-olive);
  --bs-btn-border-color: var(--yubira-ink-olive);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--yubira-olive-hover);
  --bs-btn-hover-border-color: var(--yubira-olive-hover);
  --bs-btn-active-bg: var(--yubira-olive-hover);
  --bs-btn-active-border-color: var(--yubira-olive-hover);
  --bs-btn-disabled-bg: var(--yubira-ink-olive);
  --bs-btn-disabled-border-color: var(--yubira-ink-olive);
  --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
.btn-outline-primary {
  --bs-btn-color: var(--yubira-ink-olive);
  --bs-btn-border-color: var(--yubira-ink-olive);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--yubira-ink-olive);
  --bs-btn-hover-border-color: var(--yubira-ink-olive);
  --bs-btn-active-bg: var(--yubira-ink-olive);
  --bs-btn-active-border-color: var(--yubira-ink-olive);
  --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
.btn-secondary {
  --bs-btn-bg: var(--yubira-olive);
  --bs-btn-border-color: var(--yubira-olive);
  --bs-btn-hover-bg: var(--yubira-olive-hover);
  --bs-btn-hover-border-color: var(--yubira-olive-hover);
  --bs-btn-active-bg: var(--yubira-olive-hover);
  --bs-btn-active-border-color: var(--yubira-olive-hover);
}
.btn-outline-secondary {
  --bs-btn-color: var(--yubira-olive);
  --bs-btn-border-color: var(--yubira-olive);
  --bs-btn-hover-bg: var(--yubira-olive);
  --bs-btn-hover-border-color: var(--yubira-olive);
  --bs-btn-active-bg: var(--yubira-olive);
  --bs-btn-active-border-color: var(--yubira-olive);
}

/* ---- Content boxes: white in light mode, a genuinely brighter surface
   in dark mode — distinct from the page background either way, so the
   page doesn't read as one flat wash of color. ---- */
.card {
  --bs-card-bg: var(--yubira-card-bg);
  background-color: var(--yubira-card-bg);
}
.modal-content {
  --bs-modal-bg: var(--yubira-card-bg);
  background-color: var(--yubira-card-bg);
}
/* ---- Navbar ---- */
.yubira-navbar {
  background-color: var(--yubira-surface) !important;
  border-color: var(--yubira-border) !important;
}
.yubira-brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--yubira-ink-olive) !important;
  font-weight: 600;
}
.yubira-brand svg { display: block; }

/* ---- Theme toggle button ---- */
.theme-toggle {
  border: 1px solid var(--bs-border-color);
  background: transparent;
  color: var(--bs-body-color);
  border-radius: var(--bs-border-radius, 0.375rem);
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.theme-toggle:hover { background: var(--yubira-border); }
[data-bs-theme="dark"] .theme-toggle:hover { background: var(--yubira-border); }
.theme-toggle .icon-dark { display: none; }
[data-bs-theme="dark"] .theme-toggle .icon-light { display: none; }
[data-bs-theme="dark"] .theme-toggle .icon-dark { display: inline; }

/* ---- Language switch (globe icon + dropdown) ---- */
.lang-switch { position: relative; }
.lang-switch-btn {
  border: 1px solid var(--bs-border-color);
  background: transparent;
  color: var(--bs-body-color);
  border-radius: var(--bs-border-radius, 0.375rem);
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.lang-switch-btn:hover { background: var(--yubira-border); }
.lang-switch-menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 120px;
  background: var(--yubira-card-bg, var(--bs-body-bg));
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius, 0.375rem);
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
  z-index: 1050;
  padding: 4px;
}
.lang-switch.open .lang-switch-menu { display: block; }
.lang-switch-menu button {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border: none;
  background: transparent;
  color: var(--bs-body-color);
  border-radius: calc(var(--bs-border-radius, 0.375rem) - 2px);
  cursor: pointer;
  font-size: 0.85rem;
  text-align: left;
}
.lang-switch-menu button:hover { background: var(--yubira-border); }
.lang-switch-menu button.active { font-weight: 600; }
/* Sidebar's toggle row is a compact icon-only variant — no room for the
   "Theme"/"Language" text labels the footer row usually shows. */
.yubira-sidebar-toggle-row.icon-row { justify-content: flex-start; gap: 8px; }

/* The sidebar footer sits at the bottom of the viewport, so the language
   menu's default downward opening runs off-screen / overlaps the page
   below it — open upward here instead. */
.yubira-sidebar-footer .lang-switch-menu { top: auto; bottom: calc(100% + 6px); }

/* ---- Flatpickr date picker — themed to match Yubira's own palette
   instead of the library's stock light-only look, so it doesn't jar
   against the app's dark mode. ---- */
.flatpickr-calendar {
  background: var(--yubira-card-bg);
  border: 1px solid var(--yubira-border);
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
  color: var(--bs-body-color);
}
.flatpickr-calendar.arrowTop:before, .flatpickr-calendar.arrowTop:after { border-bottom-color: var(--yubira-border); }
.flatpickr-months, .flatpickr-weekdays, .flatpickr-innerContainer, .flatpickr-rContainer { background: var(--yubira-card-bg); }
.flatpickr-weekday { background: var(--yubira-card-bg); color: var(--bs-body-color); opacity: 0.7; }
.flatpickr-current-month, .flatpickr-current-month .flatpickr-monthDropdown-months, .flatpickr-current-month input.cur-year {
  color: var(--bs-body-color);
  background: transparent;
}
.flatpickr-current-month .flatpickr-monthDropdown-months option { background: var(--yubira-card-bg); color: var(--bs-body-color); }
span.flatpickr-weekday, .flatpickr-day { color: var(--bs-body-color); }
.flatpickr-day.prevMonthDay, .flatpickr-day.nextMonthDay, .flatpickr-day.flatpickr-disabled { color: var(--yubira-border); }
.flatpickr-day:hover { background: var(--yubira-border); border-color: var(--yubira-border); }
.flatpickr-day.today { border-color: var(--yubira-olive); }
.flatpickr-day.selected, .flatpickr-day.selected:hover {
  background: var(--yubira-olive);
  border-color: var(--yubira-olive);
  color: #fff;
}
.flatpickr-prev-month svg, .flatpickr-next-month svg { fill: var(--bs-body-color); }
.numInputWrapper span.arrowUp:after { border-bottom-color: var(--bs-body-color); }
.numInputWrapper span.arrowDown:after { border-top-color: var(--bs-body-color); }

/* ---- Left sidebar ---- */
.yubira-sidebar {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: 224px;
  background: var(--yubira-card-bg);
  border-right: 1px solid var(--yubira-border);
  display: flex;
  flex-direction: column;
  padding: 1.25rem 1rem;
  z-index: 1000;
  overflow-y: auto;
}
.yubira-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--yubira-ink-olive);
  font-weight: 700;
  margin-bottom: 1.75rem;
  text-decoration: none;
  padding: 0 0.25rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.yubira-sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
}
.yubira-sidebar-link {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 0.6rem 0.7rem;
  border-radius: 8px;
  color: var(--yubira-ink);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  transition: background 0.12s ease;
  white-space: nowrap;
}
.yubira-sidebar-link svg { flex-shrink: 0; }
.yubira-sidebar-link:hover { background: var(--yubira-surface); color: var(--yubira-ink); }
.yubira-sidebar-link.active { background: var(--yubira-ink-olive); color: #fff; }
.yubira-sidebar-link.disabled { opacity: 0.35; pointer-events: none; }
.yubira-sidebar-apps {
  border-top: 1px solid var(--yubira-border);
  padding-top: 0.6rem;
  margin-top: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.yubira-sidebar-group-label {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 0.2rem 0.7rem 0.35rem;
  color: var(--bs-secondary-color, #6c757d);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.yubira-sidebar-group-label svg { flex-shrink: 0; }
.yubira-sidebar-footer {
  border-top: 1px solid var(--yubira-border);
  padding-top: 0.6rem;
  margin-top: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.yubira-sidebar-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4rem 0.7rem;
}
body.has-sidebar { padding-left: 224px; }

@media (max-width: 860px) {
  .yubira-sidebar { width: 64px; padding: 1.25rem 0.5rem; }
  .yubira-sidebar-brand span.label,
  .yubira-sidebar-link span.label { display: none; }
  .yubira-sidebar-brand { justify-content: center; }
  .yubira-sidebar-link { justify-content: center; padding: 0.65rem; }
  .yubira-sidebar-group-label { justify-content: center; padding: 0.2rem; }
  .yubira-sidebar-group-label span { display: none; }
  body.has-sidebar { padding-left: 64px; }
  .yubira-topbar { left: 64px; }
}

/* ---- Top bar — page title header, sits beside the fixed sidebar ---- */
.yubira-topbar {
  position: fixed;
  top: 0;
  left: 224px;
  right: 0;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 1.75rem;
  background: var(--yubira-card-bg);
  border-bottom: 1px solid var(--yubira-border);
  z-index: 900;
}
.yubira-topbar-titles { min-width: 0; }
.yubira-topbar-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--yubira-ink);
  margin: 0;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.yubira-topbar-subtitle {
  font-size: 0.78rem;
  color: var(--viz-ink-secondary, #6c757d);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.yubira-topbar-actions { display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0; }

body.has-topbar { padding-top: 84px; }

/* ---- Admin impersonation banner (§4.1.4) — always-visible while an admin
   is acting as another user, so it can't be mistaken for the admin's own
   session. Sits above the sidebar/topbar (both position:fixed, top:0) by
   pushing them down 40px via a body class rather than restructuring either. */
.yubira-impersonation-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 40px;
  background: #b3261e;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  font-size: 0.85rem;
  font-weight: 600;
  z-index: 2000;
}
.yubira-impersonation-banner button {
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.4);
  color: #fff;
  padding: 0.15rem 0.6rem;
  border-radius: 4px;
  font-size: 0.78rem;
  cursor: pointer;
}
.yubira-impersonation-banner button:hover { background: rgba(255,255,255,0.28); }
body.yubira-impersonating .yubira-sidebar { top: 40px; }
body.yubira-impersonating .yubira-topbar { top: 40px; }
body.yubira-impersonating.has-topbar { padding-top: 124px; }

/* ---- Admin panel top nav (§4.1.4) — deliberately not the host sidebar;
   admin is a separate operational area, full-width bar not a left rail. ---- */
.yubira-admin-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 56px;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0 1.5rem;
  background: var(--yubira-ink-olive);
  color: #fff;
  z-index: 1000;
}
.yubira-admin-nav-brand { font-weight: 700; letter-spacing: 0.02em; white-space: nowrap; }
.yubira-admin-nav-links { display: flex; gap: 1.25rem; flex: 1; overflow-x: auto; }
.yubira-admin-nav-links a {
  color: rgba(255,255,255,0.75);
  text-decoration: none;
  font-size: 0.85rem;
  padding: 0.3rem 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.yubira-admin-nav-links a:hover { color: #fff; }
.yubira-admin-nav-links a.active { color: #fff; border-bottom-color: var(--yubira-clay); font-weight: 600; }
.yubira-admin-nav-exit { color: rgba(255,255,255,0.75); text-decoration: none; font-size: 0.85rem; white-space: nowrap; }
.yubira-admin-nav-exit:hover { color: #fff; }
body.has-admin-nav { padding-top: 56px; }

/* ---- Existing app classes, now token-driven ---- */
.auth-card {
  max-width: 420px;
  margin: 1.5rem auto 4rem;
}

.event-card {
  transition: box-shadow 0.15s ease;
}
.event-card:hover {
  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
}

/* Hero image as a card background (Dashboard) — taller than a plain card so
   the photo actually reads, left otherwise uncovered (no overlay over the
   title/date area) so it stays the focal point. Title/date text gets a
   text-shadow instead of a scrim, since it sits directly on the photo. */
.event-card.has-hero {
  background-size: cover;
  background-position: center;
  position: relative;
  overflow: hidden;
  min-height: 280px;
  cursor: pointer; /* the photo area is clickable through to Event Settings */
}
.event-card.has-hero > .card-body {
  position: relative;
  min-height: 280px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.65);
}
.event-card.has-hero .text-muted {
  color: rgba(255, 255, 255, 0.85) !important;
}

/* Action buttons sit on their own translucent panel (not a gradient) so
   they're legible regardless of what's directly behind them in the photo —
   same --yubira-card-bg-rgb token as the rest of the card, just partially
   see-through instead of a fade. Square (no border-radius), flush to the
   card's full left/right/bottom edges (no padding of its own) — the outer
   card's overflow:hidden still clips it to match the card's rounded
   silhouette at the bottom corners. Button text is reset to no text-shadow
   since it sits on its own solid-ish backdrop, not directly on the photo.
   */
.event-card.has-hero .event-card-actions {
  position: relative;
  z-index: 1;
  text-shadow: none;
}
.event-card.has-hero .event-card-actions::before {
  content: '';
  position: absolute;
  /* -1rem top mirrors the card-body's own 1rem bottom padding (the gap
     between the buttons and the card's real bottom edge once ::before's
     -2rem bottom bleed is clipped there) — same breathing room above the
     buttons as below, without adding padding to the row itself. */
  top: -1rem;
  left: -2rem;
  right: -2rem;
  bottom: -2rem; /* overshoots the card's real edge; clipped by overflow:hidden above */
  background-color: rgba(var(--yubira-card-bg-rgb), 0.7);
  z-index: -1;
  pointer-events: none;
}

.status-badge-draft { background-color: #6c757d; }
.status-badge-published { background-color: var(--yubira-ink-olive); }
.status-badge-archived { background-color: #adb5bd; }

/* ============================================================
   Reporting page — data-viz tokens and chart primitives.
   Palette is the dataviz skill's validated default categorical +
   status instance (references/palette.md), not a hand-picked set —
   see public/js/charts.js for the render functions that consume
   these as CSS custom properties.
   ============================================================ */
.viz-root {
  --viz-ink-secondary: #52514E;
  --viz-muted: #898781;
  --viz-gridline: #E1E0D9;
  --viz-baseline: #C3C2B7;

  --viz-good: #0CA30C;
  --viz-warning: #FAB219;
  --viz-serious: #EC835A;
  --viz-critical: #D03B3B;

  --viz-cat-1: #2A78D6; /* blue */
  --viz-cat-2: #1BAF7A; /* aqua */
  --viz-cat-3: #EDA100; /* yellow */
  --viz-cat-4: #008300; /* green */
  --viz-cat-5: #4A3AA7; /* violet */
  --viz-cat-6: #E34948; /* red */
  --viz-cat-7: #E87BA4; /* magenta */
  --viz-cat-8: #EB6834; /* orange */
}
[data-bs-theme="dark"] .viz-root {
  --viz-ink-secondary: #C3C2B7;
  --viz-gridline: #2C2C2A;
  --viz-baseline: #383835;

  --viz-cat-1: #3987E5;
  --viz-cat-2: #199E70;
  --viz-cat-3: #C98500;
  --viz-cat-5: #9085E9;
  --viz-cat-6: #E66767;
  --viz-cat-7: #D55181;
  --viz-cat-8: #D95926;
}

.viz-chart-title { font-size: 0.95rem; font-weight: 600; }
.viz-chart-sub { font-size: 0.8rem; color: var(--viz-ink-secondary); margin-bottom: 0.75rem; }

.viz-stackbar {
  display: flex;
  height: 24px;
  border-radius: 4px;
  overflow: hidden;
  background: var(--viz-gridline);
}
.viz-stackbar-seg { height: 100%; cursor: pointer; }
.viz-stackbar-seg + .viz-stackbar-seg { margin-left: 2px; }
.viz-stackbar-seg:hover, .viz-stackbar-seg:focus-visible { filter: brightness(1.1); }

.viz-legend { display: flex; flex-wrap: wrap; gap: 0.4rem 0.9rem; margin-top: 0.65rem; }

/* Shared by public/js/charts.js's renderLineChart (admin usage reports) —
   same visual language as marketplace.html's one-off spend chart (brand
   olive line, recessive gridlines), promoted here since renderLineChart is
   used by more than one page; marketplace.html keeps its own identical-
   looking local copy rather than being refactored to depend on this. */
.line-chart { width: 100%; height: auto; overflow: visible; }
.line-chart .chart-grid { stroke: var(--yubira-border); stroke-width: 1; }
.line-chart .chart-axis-label { font-size: 9px; fill: var(--bs-secondary-color, #6c757d); }
.line-chart .chart-line { stroke: var(--yubira-ink-olive); stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.line-chart .chart-dot { fill: var(--yubira-card-bg); stroke: var(--yubira-ink-olive); stroke-width: 2; cursor: pointer; }
.line-chart .chart-dot:hover, .line-chart .chart-dot.active { fill: var(--yubira-ink-olive); }
.chart-tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--yubira-card-bg);
  border: 1px solid var(--yubira-border);
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 0.75rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
  white-space: nowrap;
  z-index: 10;
}
.viz-legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--bs-body-color); }
.viz-legend-swatch { width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; }

.viz-barlist-row { display: grid; grid-template-columns: minmax(90px, 160px) 1fr auto; align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; }
.viz-barlist-label {
  font-size: 0.82rem;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.viz-barlist-track { background: var(--viz-gridline); border-radius: 4px; height: 18px; }
.viz-barlist-fill { height: 100%; border-radius: 4px; cursor: pointer; min-width: 2px; }
.viz-barlist-value { font-size: 0.8rem; color: var(--viz-ink-secondary); min-width: 3ch; }

.viz-tooltip {
  position: fixed;
  pointer-events: none;
  background: var(--yubira-ink);
  color: var(--yubira-surface);
  padding: 0.35rem 0.6rem;
  border-radius: 6px;
  font-size: 0.78rem;
  line-height: 1.3;
  z-index: 2000;
  opacity: 0;
  transition: opacity 0.1s ease;
  max-width: 220px;
  transform: translate(-50%, -100%);
}
.viz-tooltip.visible { opacity: 1; }
.viz-tooltip strong { display: block; font-size: 0.85rem; }

.viz-table { font-size: 0.82rem; }

.viz-stat-tile { text-align: center; padding: 0.9rem 0.5rem; }
.viz-stat-value { font-size: 1.9rem; font-weight: 700; color: var(--yubira-ink-olive); line-height: 1.1; }
.viz-stat-label { font-size: 0.78rem; color: var(--viz-ink-secondary); margin-top: 0.2rem; }
