:root {
  /* ===================================================================
     BRAND TOKENS — Votisia Accurate Color & Logo Style Guide (2026-08)
     The logo wave uses the FULL gradient from the artwork (#vt-grad in
     the sprite). The ramp below is derived UI chrome, never the logo.
     =================================================================== */
  --brand-blue-deep:  #0024FC;   /* Electric Blue   */
  --brand-blue:       #0050FA;   /* Votisia Blue    */
  --brand-cyan:       #00B7ED;   /* Bright Cyan     */
  --brand-transition: #2A3FF2;   /* Transition Blue */
  --brand-violet:     #5900F5;   /* Electric Violet */
  --brand-purple:     #6300F5;   /* Votisia Purple  */
  /* rgb triplets so tints can be written rgba(var(--x-rgb), .12) */
  --brand-blue-rgb:   0,80,250;
  --brand-cyan-rgb:   0,183,237;
  --brand-purple-rgb: 99,0,245;
  --brand-ramp:    linear-gradient(135deg, #0050FA 0%, #00B7ED 50%, #6300F5 100%);
  --brand-ramp-90: linear-gradient(90deg,  #0050FA 0%, #00B7ED 50%, #6300F5 100%);

  /* --- Surfaces & text --- */
  --stage: #EFEFEF;          /* behind the phone frame          */
  --surface: #FFFFFF;        /* cards, sheets, inputs           */
  --surface-2: #FAFAFA;      /* app background, soft tiles      */
  --surface-3: #F2F2F2;      /* bar tracks, inset wells         */
  --map-bg: #FBFBFB;
  --ink: #111111;
  --muted: #777777;
  --hairline: #ECECEC;
  --hairline-strong: #D9D9D9;
  --soft: #FAFAFA;          /* app background (with --surface-2) */
  --tile: #FAFAFA;          /* inset tiles/wells ON a card       */
  --tile-flat: #F3F3F5;     /* borderless option tile on the app bg (vote discs) */
  --on-brand: #FFFFFF;       /* text/icons on brand gradients   */
  --scrim: rgba(var(--shadow-rgb),0.45);
  --veil: rgba(255,255,255,0.55);      /* frosted overlay on locked Pro cards */
  --nav-veil: rgba(255,255,255,0.92);  /* bottom-nav / topbar frost      */
  --bezel: #0E0E0E;
  --bezel-2: #232323;
  --shadow-rgb: 17,17,17;              /* elevation shadows                */
  --fade-rgb: 250,250,250;             /* scroll fade under the bottom nav */
  --topbar-veil: rgba(250,250,250,0.92);
  --accent: var(--brand-blue);         /* solid UI accent (focus rings)    */
  --accent-2: var(--brand-purple);     /* second stop of UI gradients      */
  /* Gradient TEXT needs its own ramp: the true brand ramp starts too dark
     to read on a near-black background. Tiles keep the real ramp. */
  --brand-ramp-text: var(--brand-ramp);

  /* --- Mood (brand icon set: blue → violet → magenta) --- */
  --mood-pos: #5074C8;
  --mood-neu: #7269BA;
  --mood-neg: #B763B1;
  --mood-pos-rgb: 80,116,200;
  --mood-neu-rgb: 114,105,186;
  --mood-neg-rgb: 183,99,177;
  /* Solid vote discs (layouts stack/side). Brand hex in BOTH themes — the
     lightened dark-mode mood tokens would push a white mouth on the
     negative disc under 3:1, and a big solid disc is brand colour, not a
     UI accent. Not redefined in the dark block on purpose. */
  --disc-pos: #5074C8;
  --disc-neu: #7269BA;
  --disc-neg: #B763B1;
  --disc-ink: #FFFFFF;

  /* --- Charts & map (chrome greys, deliberately NOT the mood greys) --- */
  --chart-axis: #9A9AA2;
  --chart-grid: #ECECEC;
  --map-nodata: #F1F1F2;
  --map-stroke: #FFFFFF;
  --map-hover: #111111;
  /* Choropleth ramp, low → high confidence. Lightness falls as confidence
     rises on a light ground, and rises on a dark one — the three mood hues
     are too close in luminance to carry the scale on their own. */
  --map-1: #C58FC2;
  --map-2: #9E8CC9;
  --map-3: #7B8AD4;
  --map-4: #5074C8;
  --map-5: #2F4FA8;

  /* --- Legacy aliases (v1 pastel palette) — kept so nothing dangles --- */
  --lav: var(--brand-blue);
  --mint: var(--brand-purple);

  /* v2: single typeface — Inter for everything (no serif, no second face).
     The v1 Fraunces serif display role is now Inter at a heavier weight. */
  --font-display: 'Inter', system-ui, sans-serif;
}

/* --- Display type (headlines, hero numbers, stat values) ---
   No separate display face: Inter 700 + tight tracking carries the
   "display" weight; size carries the hierarchy. */
body .font-display {
  font-family: var(--font-display);
  font-weight: 700;
}

html, body { background: var(--stage); }
body {
  font-family: 'Inter', system-ui, sans-serif;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'ss01', 'cv11';
}

/* --- Wordmark / brand type --- */
.wordmark {
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  letter-spacing: -0.018em;
  color: var(--ink);
}

/* --- Gradient text --- */
.gradient-text {
  background: var(--brand-ramp-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* --- Phone frame on >=640px --- */
.stage {
  min-height: 100vh;
  display: flex;
  align-items: stretch;
  justify-content: center;
  background:
    radial-gradient(1200px 600px at 50% -10%, rgba(var(--brand-blue-rgb),0.06), transparent 60%),
    radial-gradient(900px 500px at 50% 110%, rgba(var(--brand-purple-rgb),0.06), transparent 60%),
    var(--stage);
}
.device {
  width: 100%;
  max-width: 100%;
  background: var(--soft);
  position: relative;
  overflow: hidden;
}
/* Real phones (<640px): the app must fill the VISIBLE viewport exactly.
   100vh includes the browser's collapsed URL bar, which made .device taller
   than the screen — the page itself scrolled, the sticky bottom nav sat below
   the fold, and dead space appeared under the content. dvh tracks the dynamic
   toolbar; body is locked so .app is the only scroll surface. */
@media (max-width: 639.98px) {
  html, body { height: 100%; overflow: hidden; overscroll-behavior: none; }
  .stage { height: 100vh; height: 100dvh; min-height: 0; }
  .device { height: 100%; }
  .app { overscroll-behavior-y: contain; }
  /* The nav is the last flow child of the scroll surface — in the desktop
     frame that's fine, but on phones it added ~100px of phantom scroll below
     every screen (visible as dead space + "scrolls again after the end").
     Fixed overlay + content padding removes it from the scroll math. */
  .bottom-nav-wrap {
    position: fixed; left: 0; right: 0; bottom: 0;
    padding-bottom: calc(22px + env(safe-area-inset-bottom));
  }
  .screen.has-bottom-nav { padding-bottom: calc(100px + env(safe-area-inset-bottom)); }
  .topbar { padding-top: calc(14px + env(safe-area-inset-top)); }
}

@media (min-width: 640px) {
  .stage { padding: 32px 0; align-items: center; }
  .device {
    width: 390px;
    height: 844px;
    max-width: 390px;
    border-radius: 44px;
    box-shadow:
      0 0 0 12px var(--bezel),
      0 0 0 13px var(--bezel-2),
      0 40px 100px -20px rgba(var(--shadow-rgb),0.35),
      0 20px 50px -20px rgba(var(--shadow-rgb),0.25);
  }
  .device::before {
    content: "";
    position: absolute;
    top: 12px; left: 50%;
    transform: translateX(-50%);
    width: 120px; height: 28px;
    background: var(--bezel);
    border-radius: 999px;
    z-index: 60;
  }
}

/* --- App scroll surface --- */
.app {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--soft);
  scroll-behavior: smooth;
}
.app::-webkit-scrollbar { width: 0; height: 0; }

/* --- Screens --- */
.screen { display: none; min-height: 100%; }
.screen.active { display: flex; flex-direction: column; }

/* --- Buttons --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px; padding: 16px 22px; border-radius: 16px;
  font-weight: 600; letter-spacing: -0.01em; font-size: 15px;
  transition: transform .15s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease;
  will-change: transform;
}
.btn:active { transform: scale(0.985); }
.btn-primary {
  background: var(--ink); color: var(--on-brand);
  box-shadow: 0 10px 30px -10px rgba(var(--shadow-rgb),0.35);
}
.btn-primary:hover { background: #000; }
.btn-ghost {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--hairline);
}
.btn-ghost:hover { border-color: var(--hairline-strong); }

/* --- Mood vote buttons --- */
.mood-btn {
  display: flex; align-items: center; gap: 16px;
  width: 100%; padding: 22px 22px;
  background: var(--surface); border-radius: 22px;
  border: 1px solid var(--hairline);
  box-shadow: 0 6px 20px -8px rgba(var(--shadow-rgb),0.06);
  transition: transform .15s ease, border-color .2s ease, box-shadow .2s ease;
  position: relative; overflow: hidden;
  text-align: left;
}
.mood-btn:hover { transform: translateY(-1px); box-shadow: 0 12px 30px -10px rgba(var(--shadow-rgb),0.10); }
.mood-btn:active { transform: scale(0.985); }
/* The glyph tile holds a brand face from the sprite. `color` drives the
   icon (currentColor), the tile is the same hue at low alpha — the solid
   icon at full saturation, per the "Icons in Farbe, nicht zu blass" note. */
.mood-btn .glyph {
  width: 48px; height: 48px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 48px;
}
.mood-btn .glyph svg { width: 28px; height: 28px; display: block; }
.mood-btn[data-mood="pos"] .glyph { background: rgba(var(--mood-pos-rgb),0.14); color: var(--mood-pos); }
.mood-btn[data-mood="neu"] .glyph { background: rgba(var(--mood-neu-rgb),0.14); color: var(--mood-neu); }
.mood-btn[data-mood="neg"] .glyph { background: rgba(var(--mood-neg-rgb),0.14); color: var(--mood-neg); }
.mood-btn .label { font-weight: 600; font-size: 16px; letter-spacing: -0.01em; text-align: left; }
.mood-btn .hint  { font-size: 13px; color: var(--muted); font-weight: 400; margin-top: 2px; text-align: left; }
.mood-btn .chevron { margin-left: auto; color: var(--muted); }
.mood-btn.locked { opacity: 0.4; pointer-events: none; box-shadow: none; }
.mood-btn .glyph .mouth { display: none; }

/* --- Vote moment (docs/VOTE-ANIMATION-PLAN.md) ------------------------
   Four beats driven by classes from vtVoteFx in app.js:
   press  → .mood-list.is-voting, .picked on the chosen option, .dimmed on the rest
   pick   → .picking: spring, mood-coloured ring, mouth draws itself, tile tints
   confirm→ .swap crossfades the caption (JS swaps the text in between)
   reveal → .screen.leaving / .entering around showScreenAnimated()
   --ring-rgb is the mood colour so ring and tint follow the option. */
.mood-btn { --ring-rgb: var(--mood-neu-rgb); }
.mood-btn[data-mood="pos"] { --ring-rgb: var(--mood-pos-rgb); }
.mood-btn[data-mood="neg"] { --ring-rgb: var(--mood-neg-rgb); }
.mood-list.is-voting .mood-btn { pointer-events: none; }
.mood-list.is-voting .mood-btn.dimmed {
  opacity: .38; transform: scale(.97);
  transition: opacity .25s ease, transform .25s ease;
}
.mood-btn.picked { transform: none; }
.mood-btn .glyph { position: relative; }
.mood-btn.picked .glyph { animation: vt-press .14s ease-out both; }
.mood-btn.picking .glyph { animation: vt-pick .5s cubic-bezier(.34,1.56,.64,1) both; }
.mood-list .mood-btn.picking {
  background: rgba(var(--ring-rgb),.12); border-color: rgba(var(--ring-rgb),.45);
  transition: background .3s ease, border-color .3s ease;
}
:root[data-theme="dark"] body .mood-list .mood-btn.picking { background: rgba(var(--ring-rgb),.18); }
/* check badge on the disc corner (inserted by vtVoteFx.confirm) */
.vt-check {
  position: absolute; right: -4px; bottom: -4px; width: 26px; height: 26px;
  border-radius: 50%; background: var(--surface); color: rgb(var(--ring-rgb));
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px -2px rgba(var(--shadow-rgb),.35), 0 0 0 2px var(--surface);
  animation: vt-pop .38s cubic-bezier(.34,1.56,.64,1) both;
}
.vt-check svg { width: 15px; height: 15px; }
.mood-btn .label.done { color: rgb(var(--ring-rgb)); }
@keyframes vt-pop { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
/* success pill, top right, on the result screen (reveal beat) */
.vt-success {
  /* in the topbar row, left of the round action button, so it covers chrome
     for 2.6 s rather than the screen's first heading */
  position: absolute; top: calc(13px + env(safe-area-inset-top)); right: 64px; z-index: 40;
  display: flex; align-items: center; gap: 9px;
  padding: 8px 12px 8px 8px; border-radius: 999px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--hairline);
  box-shadow: 0 12px 30px -12px rgba(var(--shadow-rgb),.35);
  font-size: 12.5px; font-weight: 600; white-space: nowrap; pointer-events: none;
  opacity: 0; transform: translateY(-10px) scale(.96);
  transition: opacity .25s ease, transform .35s cubic-bezier(.34,1.56,.64,1);
}
.vt-success.show { opacity: 1; transform: none; }
.vt-success .dot {
  width: 22px; height: 22px; border-radius: 50%; color: #fff;
  background: rgb(var(--ring-rgb, var(--mood-pos-rgb)));
  display: flex; align-items: center; justify-content: center; flex: 0 0 22px;
}
.vt-success .dot svg { width: 13px; height: 13px; }
.vt-success .sub { color: var(--muted); font-weight: 500; }
.mood-btn.picking .glyph::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 0 0 rgba(var(--ring-rgb),.5);
  animation: vt-ring .75s ease-out .1s both;
}
/* stroke-dasharray/-offset inherit into the <use> shadow tree; the mouth
   paths carry pathLength="1", so 1 = the whole stroke */
.mood-btn.picking .glyph .mouth { stroke-dasharray: 1; animation: vt-draw .45s ease-out .12s both; }
.mood-btn .copy { transition: opacity .15s ease; }
.mood-btn.swap .copy { opacity: 0; }
@keyframes vt-press { from { transform: scale(1); } to { transform: scale(.92); } }
@keyframes vt-pick  { 0% { transform: scale(.92); } 60% { transform: scale(1.14); } 100% { transform: scale(1.06); } }
@keyframes vt-ring  { to { box-shadow: 0 0 0 22px rgba(var(--ring-rgb),0); } }
@keyframes vt-draw  { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.screen.leaving  { animation: vt-leave .18s ease both; }
.screen.entering { animation: vt-enter .28s ease both; }
@keyframes vt-leave { to { opacity: 0; transform: translateY(-8px); } }
@keyframes vt-enter { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .mood-btn.picked .glyph, .mood-btn.picking .glyph, .mood-btn.picking .glyph::after,
  .mood-btn.picking .glyph .mouth, .screen.leaving, .screen.entering, .vt-check { animation: none; }
  .vt-success { transition: opacity .2s ease; transform: none; }
  .mood-list.is-voting .mood-btn.dimmed { transform: none; }
}

/* --- Vote layouts (admin → Einstellungen → vote_layout) -----------------
   <html data-vote-layout="list|stack|side">, set by vtApplyVoteLayout()
   from /api/bootstrap (or /api/meta/ui before login). `list` is the
   classic row above and needs no rules. The two big-disc layouts from the
   2026-09 mockup share one idea: the disc IS the option — solid mood
   colour, white mouth, no chevron, a flat borderless tile behind it. The
   mood name stays as the caption's first line: colour is never used alone.
   ----------------------------------------------------------------------- */
[data-vote-layout="stack"] .mood-btn,
[data-vote-layout="side"] .mood-btn {
  border-color: transparent;
  background: var(--tile-flat);
  box-shadow: none;
}
[data-vote-layout="stack"] .mood-btn:hover,
[data-vote-layout="side"] .mood-btn:hover {
  transform: none;
  box-shadow: 0 10px 28px -12px rgba(var(--shadow-rgb),0.14);
}
[data-vote-layout="stack"] .mood-btn:active,
[data-vote-layout="side"] .mood-btn:active { transform: scale(0.98); }
[data-vote-layout="stack"] .mood-btn .chevron,
[data-vote-layout="side"] .mood-btn .chevron { display: none; }
[data-vote-layout="stack"] .mood-btn .glyph,
[data-vote-layout="side"] .mood-btn .glyph {
  border-radius: 50%;
  color: var(--disc-ink);
  transition: transform .15s ease;
}
[data-vote-layout="stack"] .mood-btn .glyph .face,
[data-vote-layout="side"] .mood-btn .glyph .face { display: none; }
[data-vote-layout="stack"] .mood-btn .glyph .mouth,
[data-vote-layout="side"] .mood-btn .glyph .mouth { display: block; width: 100%; height: 100%; }
[data-vote-layout="stack"] .mood-btn[data-mood="pos"] .glyph,
[data-vote-layout="side"]  .mood-btn[data-mood="pos"] .glyph { background: var(--disc-pos); }
[data-vote-layout="stack"] .mood-btn[data-mood="neu"] .glyph,
[data-vote-layout="side"]  .mood-btn[data-mood="neu"] .glyph { background: var(--disc-neu); }
[data-vote-layout="stack"] .mood-btn[data-mood="neg"] .glyph,
[data-vote-layout="side"]  .mood-btn[data-mood="neg"] .glyph { background: var(--disc-neg); }
[data-vote-layout="stack"] .mood-btn:active .glyph,
[data-vote-layout="side"] .mood-btn:active .glyph { transform: scale(0.94); }
[data-vote-layout="stack"] .mood-btn .hint,
[data-vote-layout="side"] .mood-btn .hint { font-size: 12.5px; line-height: 1.4; }

/* stack: disc above the caption, everything centred (mockup, middle frame) */
[data-vote-layout="stack"] .mood-btn {
  flex-direction: column; align-items: center; gap: 12px;
  padding: 18px 20px 16px; border-radius: 26px;
  text-align: center;
}
[data-vote-layout="stack"] .mood-btn .glyph { width: 88px; height: 88px; flex-basis: auto; }
[data-vote-layout="stack"] .mood-btn .copy { align-items: center; }
[data-vote-layout="stack"] .mood-btn .label,
[data-vote-layout="stack"] .mood-btn .hint { text-align: center; }
[data-vote-layout="stack"] .mood-btn .label { font-size: 15px; }

/* side: disc left, caption right (mockup, right frame) */
[data-vote-layout="side"] .mood-btn {
  gap: 18px; padding: 16px 20px 16px 18px; border-radius: 26px;
}
[data-vote-layout="side"] .mood-btn .glyph { width: 76px; height: 76px; flex-basis: 76px; }
[data-vote-layout="side"] .mood-btn .label { font-size: 15.5px; }

/* the stacked variant is taller than one phone screen: tighten the header */
[data-vote-layout="stack"] [data-screen="vote"] h2,
[data-vote-layout="stack"] [data-screen="vote-locked"] h2 { font-size: 27px; }

/* --- Inline action link ---------------------------------------
   A text affordance for actions that follow on from a card's message
   rather than compete with it — a ghost button beside the text reads as
   a second control and squeezes the copy. Uses --accent, so it lifts off
   the dark ground too. Still a <button>: it drives an in-app screen
   change via data-go, not a URL. */
body .link-action {
  display: inline-flex; align-items: center; gap: 4px;
  /* vertical padding only — the text sits flush left, but the row still
     gives a ~38px touch target instead of the 20px the type alone spans */
  padding: 9px 0; border: 0; background: none; cursor: pointer;
  font-size: 13px; font-weight: 600; letter-spacing: -0.005em;
  color: var(--accent);
}
body .link-action:hover { text-decoration: underline; text-underline-offset: 3px; }
body .link-action:active { opacity: 0.7; }
body .link-action svg { width: 15px; height: 15px; }
/* As the last child the padding reads as extra space under the card's own
   padding — pull it back with a negative margin rather than removing it, so
   the touch target stays 38px. */
body .link-action:last-child { margin-bottom: -9px; }

/* --- Cards --- */
.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 22px;
  box-shadow: 0 6px 20px -8px rgba(var(--shadow-rgb),0.06);
}

/* --- Inputs --- */
.input {
  width: 100%;
  padding: 16px 18px;
  border-radius: 16px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  font-size: 16px;
  letter-spacing: -0.01em;
  outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(var(--brand-blue-rgb),0.16);
}

/* --- Country chip --- */
.country {
  display: flex; align-items: center; gap: 10px;
  width: 100%; box-sizing: border-box;
  padding: 12px 14px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--hairline);
  cursor: pointer; transition: border-color .15s ease, background .15s ease;
  font-size: 14px; font-weight: 500; letter-spacing: -0.005em;
  text-align: left;
}
.country:hover { border-color: var(--hairline-strong); }
.country.selected {
  border-color: var(--ink);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--ink);
}
.country .flag { font-size: 18px; line-height: 1; }

/* --- Pills (toggle) --- */
.pill-group {
  display: inline-flex; padding: 4px;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 999px;
}
.pill {
  /* now a real <button> in the trend tabs — reset the UA chrome so the
     spans and buttons that share this class render identically */
  border: 0; background: none; font-family: inherit;
  padding: 8px 14px; border-radius: 999px;
  font-size: 13px; font-weight: 600; color: var(--muted);
  cursor: pointer; transition: all .2s ease;
  letter-spacing: -0.005em;
  /* As a shrinking flex item every pill was squeezed until its own label
     wrapped ("7 / Tage"). A tab keeps its width; if the strip runs out of
     room it scrolls (see .pill-scroll). Groups that opt into flex-1 or
     flex-wrap still win — Tailwind's utilities are injected after this. */
  white-space: nowrap; flex: 0 0 auto;
}

/* Horizontal tab strip for narrow screens: the row never wraps, and it
   scrolls with momentum instead of overflowing the viewport. */
.pill-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin-inline: -24px;      /* bleed past the screen's 24px gutter … */
  padding-inline: 24px;      /* … so the first/last pill still aligns */
  scroll-padding-inline: 24px;
}
.pill-scroll::-webkit-scrollbar { display: none; }
.pill-scroll .pill-group { scroll-snap-type: x proximity; }
.pill-scroll .pill { scroll-snap-align: center; }
.pill.active { background: var(--ink); color: var(--on-brand); }

/* --- Bottom nav --- */
.bottom-nav-wrap {
  position: sticky; bottom: 0;
  padding: 14px 20px 22px;
  background: linear-gradient(to top, rgba(var(--fade-rgb),0.95), rgba(var(--fade-rgb),0.4) 70%, transparent);
  pointer-events: none;
  z-index: 40;
}
.bottom-nav {
  pointer-events: auto;
  background: var(--nav-veil);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  box-shadow: 0 10px 30px -10px rgba(var(--shadow-rgb),0.12);
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px;
}
.nav-tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 10px; border-radius: 999px;
  color: var(--muted); font-size: 11px; font-weight: 600;
  cursor: pointer; transition: color .2s ease, background .2s ease;
  letter-spacing: -0.005em;
}
.nav-tab.active { color: var(--ink); }
.nav-tab.active .tab-indicator { opacity: 1; }
.tab-indicator {
  width: 24px; height: 3px; border-radius: 999px;
  background: var(--brand-ramp-90);
  opacity: 0; transition: opacity .2s ease;
  margin-top: 2px;
}
.nav-tab svg { width: 20px; height: 20px; stroke-width: 1.7; }

/* --- Top bar --- */
.topbar {
  position: sticky; top: 0; z-index: 30;
  padding: 14px 20px 12px;
  background: var(--topbar-veil);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: flex; align-items: center; justify-content: space-between;
  border-bottom: 1px solid transparent;
}
@media (min-width: 640px) { .topbar { padding-top: 22px; } }

/* --- Bars (hand-rolled charts) --- */
.bar-track {
  width: 100%; height: 6px;
  background: var(--surface-3); border-radius: 999px; overflow: hidden;
}
.bar-fill { height: 100%; border-radius: 999px; transition: width .6s ease; }

/* --- 7-day vertical bars --- */
.day-bar {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.day-col {
  width: 24px; min-height: 8px; border-radius: 8px;
  background: var(--surface-3); position: relative; overflow: hidden;
  display: flex; align-items: flex-end;
}
.day-col .fill {
  width: 100%; border-radius: 8px;
  transition: height .8s cubic-bezier(.2,.7,.2,1);
}
.day-label { font-size: 11px; color: var(--muted); font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; }

/* --- Badge --- */
.badge {
  aspect-ratio: 1/1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--surface); border: 1px solid var(--hairline); border-radius: 20px;
  padding: 12px; gap: 6px; text-align: center;
  transition: transform .2s ease, box-shadow .2s ease;
}
.badge:hover { transform: translateY(-2px); box-shadow: 0 12px 30px -12px rgba(var(--shadow-rgb),0.10); }
.badge .b-icon {
  width: 44px; height: 44px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-ramp);
  color: var(--on-brand);
}
.badge .b-icon svg { width: 22px; height: 22px; stroke-width: 1.8; color: var(--on-brand); }
.badge .b-name { font-size: 11px; font-weight: 600; color: var(--ink); letter-spacing: -0.005em; line-height: 1.2; }
.badge.locked .b-icon { background: var(--surface-3); color: var(--chart-axis); }
.badge.locked .b-icon svg { color: var(--chart-axis); }
.badge.locked .b-name { color: var(--muted); }

/* --- Insights cards --- */
.insight-card {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 22px; padding: 18px;
  display: flex; flex-direction: column; gap: 12px;
  cursor: pointer; transition: transform .2s ease, box-shadow .2s ease;
  min-height: 0;
  text-align: left;
}
.insight-card:hover { transform: translateY(-2px); box-shadow: 0 14px 32px -14px rgba(var(--shadow-rgb),0.10); }
/* Insights hero chart card — tappable like an insight-card, laid out like a card */
.insight-hero { cursor: pointer; transition: transform .2s ease, box-shadow .2s ease; }
.insight-hero:hover { transform: translateY(-2px); box-shadow: 0 14px 32px -14px rgba(var(--shadow-rgb),0.10); }
.insight-card .ic-icon {
  width: 40px; height: 40px; border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--ink);
}
.insight-card .ic-icon svg { width: 20px; height: 20px; stroke-width: 1.7; }

/* --- Country flags (flat SVG, 4:3) --- */
.vt-flag {
  display: inline-block; vertical-align: -0.15em; border-radius: 3px;
  object-fit: cover; box-shadow: inset 0 0 0 1px rgba(var(--shadow-rgb),0.08);
  background: var(--surface-3);
}
.vt-flag-emoji { line-height: 1; }
.rank-row .flag .vt-flag, .country .flag .vt-flag { vertical-align: middle; }

/* --- Stat tile --- */
.stat-tile {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 18px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px;
}
.stat-tile .v { font-family: var(--font-display); font-size: 26px; font-weight: 700; letter-spacing: -0.02em; }
.stat-tile .k { font-size: 11.5px; color: var(--muted); font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; }
/* full-width row variant: label left, value right */
.stat-tile.row { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 18px; }

/* --- Glow behind logo --- */
/* Sits behind the wave only — a glow over the wordmark makes the letterforms
   read as smudged, and the guide wants the mark reproduced cleanly. */
.logo-glow::before {
  content: "";
  position: absolute; left: -30px; right: -30px; top: -34px; bottom: 44%;
  background:
    radial-gradient(closest-side, rgba(var(--brand-blue-rgb),0.16), transparent 72%),
    radial-gradient(closest-side at 72% 55%, rgba(var(--brand-purple-rgb),0.14), transparent 72%);
  filter: blur(16px);
  z-index: -1;
}

/* --- Soft tag --- */
.tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.02em; text-transform: uppercase;
  background: var(--surface); border: 1px solid var(--hairline); color: var(--muted);
}

/* --- Number-stepper feel --- */
.stepper-dot {
  width: 6px; height: 6px; border-radius: 999px; background: var(--hairline-strong);
}
.stepper-dot.active { background: var(--ink); width: 22px; }

/* --- Animations --- */
@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
.rise > * { animation: rise .6s cubic-bezier(.2,.7,.2,1) both; }
.rise > *:nth-child(1) { animation-delay: .02s; }
.rise > *:nth-child(2) { animation-delay: .10s; }
.rise > *:nth-child(3) { animation-delay: .18s; }
.rise > *:nth-child(4) { animation-delay: .26s; }
.rise > *:nth-child(5) { animation-delay: .34s; }
.rise > *:nth-child(6) { animation-delay: .42s; }
.rise > *:nth-child(7) { animation-delay: .50s; }
.rise > *:nth-child(8) { animation-delay: .58s; }

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
.float { animation: float 6s ease-in-out infinite; }

.delta-up { color: var(--mood-pos); }
.delta-down { color: var(--mood-neg); }

/* --- ECharts container baseline --- */
.chart { width: 100%; }

/* --- Country ranking row --- */
.rank-row {
  display: grid; grid-template-columns: 22px 22px 1fr auto;
  gap: 12px; align-items: center;
  padding: 12px 14px;
  border-bottom: 1px solid var(--hairline);
}
.rank-row:last-child { border-bottom: 0; }
.rank-row .rnum { font-family: var(--font-display); font-size: 18px; font-weight: 700; color: var(--muted); }
.rank-row .rname { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.rank-row .rname .top { display: flex; align-items: center; gap: 8px; }
.rank-row .rname .nm { font-weight: 600; font-size: 14px; letter-spacing: -0.005em; }
.rank-row .pct { font-family: var(--font-display); font-size: 18px; font-weight: 700; min-width: 56px; text-align: right; }
.rank-row .delta { font-size: 12px; font-weight: 600; }

/* --- Hairline divider with label --- */
.divider {
  display: flex; align-items: center; gap: 12px;
  color: var(--muted); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
}
.divider::before, .divider::after {
  content: ""; flex: 1; height: 1px; background: var(--hairline);
}

/* --- SVG world heatmap (D3 + world-atlas TopoJSON) --- */
.svg-map-wrap {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(var(--brand-blue-rgb),0.05), transparent 60%),
    var(--map-bg);
}
.svg-map {
  width: 100%;
  height: auto;
  display: block;
  aspect-ratio: 720 / 360;
}
.svg-map .graticule {
  fill: none;
  stroke: var(--chart-grid);
  stroke-width: 0.4;
  stroke-dasharray: 1.2 1.4;
  opacity: 0.85;
}
.svg-map .country-shape {
  stroke: var(--map-stroke);
  stroke-width: 0.5;
  stroke-linejoin: round;
  transition: stroke .15s ease, stroke-width .15s ease, filter .2s ease;
}
.svg-map .country-shape.has-data { cursor: pointer; }
.svg-map .country-shape.active {
  stroke: var(--map-hover);
  stroke-width: 1.1;
  filter: drop-shadow(0 0 3px rgba(var(--shadow-rgb),0.18));
}
.map-tip {
  position: absolute; pointer-events: none;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 7px 10px 7px 8px;
  font-size: 11.5px;
  box-shadow: 0 10px 30px -10px rgba(var(--shadow-rgb),0.18);
  display: flex; align-items: center; gap: 8px;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -2px);
  transition: opacity .12s ease, transform .12s ease;
  z-index: 5;
}
.map-tip.show { opacity: 1; transform: translate(-50%, -6px); }
.map-tip .tip-flag { font-size: 14px; line-height: 1; }
.map-tip .tip-name { font-weight: 600; color: var(--ink); letter-spacing: -0.005em; }
.map-tip .tip-val  { font-family: var(--font-display); font-weight: 700; color: var(--ink); margin-left: 4px; }
.map-tip .tip-val::after { content: " %"; color: var(--muted); font-weight: 400; font-family: 'Inter', sans-serif; font-size: 10.5px; }

/* ============================================================
   PRO MODE — badges, locks, paywall + simulated Google Play IAP
   On-brand: reuses the brand gradient + Inter only. The Play
   sheet deliberately uses Google's own palette (it represents
   the OS / Play Store UI, not the Votisia app).
   ============================================================ */

/* --- Pro / Free conditional visibility (toggled by html.is-pro).
   pro-only / free-only elements are authored as plain block wrappers. --- */
.pro-only { display: none; }
html.is-pro .pro-only { display: block; }
html.is-pro .free-only { display: none; }
html.is-pro .mock-ad { display: none; }
/* inline hint that should disappear once Pro is active */
html.is-pro .hide-when-pro { display: none; }

/* --- Pro badge / lockup --- */
.pro-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px; border-radius: 999px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--on-brand); background: var(--brand-ramp);
  line-height: 1; white-space: nowrap;
}
.pro-badge.lg { font-size: 12px; padding: 6px 14px; letter-spacing: 0.1em; }

/* --- Locked Pro insight card --- */
.insight-card.pro-locked { position: relative; overflow: hidden; }
.pro-blur { filter: blur(5px); opacity: 0.55; pointer-events: none; }
html.is-pro .pro-blur { filter: none; opacity: 1; pointer-events: auto; }
.pro-lock {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  background: var(--veil);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  border-radius: inherit; text-align: center; padding: 14px;
}
html.is-pro .pro-lock { display: none; }
/* No lock icon: the blur already says "locked", and the badge already says
   why — the padlock was a third way of saying the same thing. What is left
   is the feature name and the Pro badge. */
.pro-lock .lock-txt {
  font-size: 13px; font-weight: 600; color: var(--ink);
  letter-spacing: -0.01em; line-height: 1.3;
}

/* --- Pro CTA card (Profil) --- */
.pro-cta {
  position: relative; border-radius: 22px; padding: 18px;
  background: linear-gradient(135deg, rgba(var(--brand-blue-rgb),0.09), rgba(var(--brand-purple-rgb),0.09));
  border: 1px solid rgba(var(--brand-blue-rgb),0.32);
}

/* --- Mock ad slot (free only) --- */
.mock-ad {
  border: 1px dashed var(--hairline-strong); border-radius: 16px;
  padding: 14px; display: flex; align-items: center; gap: 12px;
  background: var(--surface); color: var(--muted);
}
.mock-ad .ad-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--hairline); border-radius: 6px; padding: 2px 6px;
}

/* --- Pro toggle (Profil dev / preview switch) --- */
.pro-switch { display: inline-flex; padding: 4px; background: var(--surface); border: 1px solid var(--hairline); border-radius: 999px; }
.pro-switch button {
  padding: 7px 16px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  color: var(--muted); transition: all .2s ease;
}
.pro-switch button.active { background: var(--ink); color: var(--on-brand); }

/* ============================================================
   Simulated Google Play purchase sheet (Android IAP)
   ============================================================ */
.play-scrim {
  position: absolute; inset: 0; z-index: 80;
  background: rgba(17,17,17,0.45);
  display: flex; align-items: flex-end;
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.play-scrim.show { opacity: 1; pointer-events: auto; }
.play-sheet {
  width: 100%; background: #fff;
  border-radius: 20px 20px 0 0;
  padding: 0 0 18px;
  transform: translateY(102%);
  transition: transform .30s cubic-bezier(.2,.7,.2,1);
  max-height: 94%; overflow-y: auto;
  box-shadow: 0 -20px 50px -20px rgba(17,17,17,0.30);
  font-family: 'Inter', system-ui, sans-serif;
}
.play-scrim.show .play-sheet { transform: translateY(0); }
.play-grip { width: 36px; height: 4px; border-radius: 999px; background: #E2E2E2; margin: 9px auto 4px; }
.play-hd { display: flex; align-items: center; gap: 10px; padding: 10px 20px 14px; }
.play-hd .gp-logo { width: 18px; height: 20px; flex: 0 0 18px; }
.play-hd .gp-name { font-size: 15px; font-weight: 600; color: #202124; }
.play-hd .gp-acct { font-size: 12px; color: #5f6368; margin-top: 1px; }
.play-hd .gp-more { margin-left: auto; color: #5f6368; }
.play-div { height: 1px; background: #ECECEC; }
.play-row { display: flex; align-items: center; gap: 14px; padding: 18px 20px; }
.play-app-icon {
  width: 44px; height: 44px; border-radius: 12px; flex: 0 0 44px;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.play-app-icon svg { width: 44px; height: 44px; }
.play-prod-t { font-size: 15px; font-weight: 600; color: #202124; }
.play-prod-s { font-size: 12.5px; color: #5f6368; margin-top: 2px; }
.play-prod-price { margin-left: auto; font-size: 15px; font-weight: 700; color: #202124; white-space: nowrap; }
.play-pay { display: flex; align-items: center; gap: 12px; padding: 15px 20px; cursor: pointer; }
.play-pay .pm-ic {
  width: 32px; height: 21px; border-radius: 4px; background: #1a1f71; color: #fff;
  font-size: 9px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex: 0 0 32px;
}
.play-pay .pm-t { font-size: 13.5px; color: #202124; font-weight: 500; }
.play-pay .pm-ch { margin-left: auto; color: #5f6368; }
.play-terms { font-size: 11px; color: #5f6368; line-height: 1.55; padding: 2px 20px 14px; }
.play-cta-wrap { padding: 6px 20px 2px; }
.play-btn {
  width: 100%; border-radius: 999px; padding: 13px 20px;
  background: #01875f; color: #fff; font-size: 15px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  transition: background .2s ease, transform .12s ease;
}
.play-btn:hover { background: #017050; }
.play-btn:active { transform: scale(.99); }
.play-btn[disabled] { opacity: .7; pointer-events: none; }
.play-cancel { width: 100%; text-align: center; padding: 14px; color: #01875f; font-size: 14px; font-weight: 600; }

/* multi-step stages */
.play-stage { display: none; }
.play-stage.active { display: block; }
.play-stage.center { padding: 34px 24px 14px; text-align: center; }
.play-btn.alt { background: #fff; color: #C25555; border: 1px solid #E6E6E6; }
.play-btn.alt:hover { background: #FFF5F5; }
.play-bio-ring {
  width: 64px; height: 64px; border-radius: 999px; margin: 0 auto 16px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(1,135,95,0.10); color: #01875f;
}
.play-bio-ring svg { width: 30px; height: 30px; }
.play-stage .ps-t { font-size: 15px; font-weight: 600; color: #202124; }
.play-stage .ps-s { font-size: 12.5px; color: #5f6368; margin-top: 4px; }
.play-spinner {
  width: 42px; height: 42px; border-radius: 999px; margin: 0 auto 16px;
  border: 3px solid #E6E6E6; border-top-color: #01875f;
  animation: playspin .8s linear infinite;
}
@keyframes playspin { to { transform: rotate(360deg); } }
.play-done-ic {
  width: 60px; height: 60px; border-radius: 999px; margin: 0 auto 16px;
  display: flex; align-items: center; justify-content: center;
  background: #01875f; color: #fff;
  animation: rise .4s cubic-bezier(.2,.7,.2,1) both;
}
@media (prefers-reduced-motion: reduce) {
  .play-sheet { transition: none; }
  .play-spinner { animation-duration: 1.6s; }
}

/* ============================================================
   update-19-05 — Foundation primitives (F1–F4, Phase 0)
   Shared, presentational only. Built from existing tokens so
   later workstreams (mood-tags, settings, trust/notice blocks)
   stay on-brand.
   ============================================================ */

/* --- F1: Multi-select chip (mood-tags) ---------------------- */
.chip-group { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 14px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--hairline);
  font-size: 13.5px; font-weight: 500; color: var(--ink);
  letter-spacing: -0.005em; cursor: pointer; user-select: none;
  transition: border-color .15s ease, background .15s ease,
              box-shadow .15s ease, color .15s ease;
}
.chip:hover { border-color: var(--hairline-strong); }
.chip.on {
  border-color: var(--ink); color: var(--ink); font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--ink);
  background: linear-gradient(135deg, rgba(var(--brand-blue-rgb),0.09), rgba(var(--brand-purple-rgb),0.09));
}
.chip .chip-ic { width: 14px; height: 14px; opacity: .5; }
.chip.on .chip-ic { opacity: 1; }
/* once the max is reached, dim & block the unselected ones */
.chip-group.maxed .chip:not(.on),
.chip[aria-disabled="true"] { opacity: .4; pointer-events: none; }
/* a limit of one swaps on tap — keep the others tappable */
.chip-group.maxed.swap-one .chip:not(.on) { opacity: 1; pointer-events: auto; }
.chip.pro-tag { opacity: .7; }
.chip .tag-ic { width: 16px; height: 16px; display: inline-block; vertical-align: -3px; }

/* --- F2: Toggle switch -------------------------------------- */
.switch {
  position: relative; display: inline-block; flex: 0 0 46px;
  width: 46px; height: 26px; padding: 0; border: 0;
  border-radius: 999px; background: var(--hairline-strong); cursor: pointer;
  transition: background .2s ease;
}
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; border-radius: 999px; background: var(--surface);
  box-shadow: 0 1px 3px rgba(var(--shadow-rgb),0.20);
  transition: transform .2s cubic-bezier(.2,.7,.2,1);
}
.switch[aria-pressed="true"] { background: var(--ink); }
.switch[aria-pressed="true"]::after { transform: translateX(20px); }

/* --- F3: Settings list-row ---------------------------------- */
.set-list {
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: 18px; overflow: hidden;
}
.set-row {
  display: flex; align-items: center; gap: 14px;
  width: 100%; padding: 15px 18px; text-align: left;
  background: none; border: 0;
  border-bottom: 1px solid var(--hairline);
}
.set-row:last-child { border-bottom: 0; }
/* A three-way choice needs the full row width — the inline .sr-ctrl slot
   squeezes it on a 390px screen. */
.set-row-stack { flex-direction: column; align-items: stretch; gap: 11px; }

/* --- Segmented control (Erscheinungsbild) --------------------- */
.seg {
  display: flex; padding: 3px; gap: 3px;
  background: var(--surface-3); border-radius: 999px;
}
.seg button {
  flex: 1; padding: 8px 10px; border-radius: 999px; border: 0;
  background: none; color: var(--muted);
  font-size: 12.5px; font-weight: 600; letter-spacing: -0.005em;
  cursor: pointer; transition: background .18s ease, color .18s ease;
}
.seg button.active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px rgba(var(--shadow-rgb),0.14); }

.set-row .sr-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.set-row .sr-title { font-size: 14.5px; font-weight: 600; color: var(--ink); letter-spacing: -0.005em; }
.set-row .sr-sub { font-size: 12px; font-weight: 500; color: var(--muted); line-height: 1.4; }
.set-row .sr-ctrl { margin-left: auto; display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.set-row .sr-val { font-size: 13.5px; font-weight: 600; color: var(--muted); }
.set-row .sr-chev { width: 18px; height: 18px; color: var(--muted); }
.set-row.tappable { cursor: pointer; transition: background .15s ease; }
.set-row.tappable:hover { background: var(--tile); }

/* --- F4: Soft notice panel ---------------------------------- */
.notice {
  border-radius: 18px; padding: 14px 16px;
  background: var(--tile); border: 1px solid var(--hairline);
  color: var(--ink); font-size: 13px; line-height: 1.55;
}
.notice .n-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 13.5px; font-weight: 700; color: var(--ink);
  letter-spacing: -0.01em; margin-bottom: 6px;
}
.notice .n-title svg { width: 16px; height: 16px; stroke-width: 1.8; }
.notice p { color: var(--muted); margin: 0; }
/* (the old .n-list ✓-glyph bullets were removed — itemised lists now use
   the dedicated .trust-row pattern below, with real SVG icons) */
/* calm variant — brand tint, for positive messages & central message */
.notice.calm {
  background: linear-gradient(135deg, rgba(var(--brand-blue-rgb),0.09), rgba(var(--brand-purple-rgb),0.09));
  border-color: rgba(var(--brand-blue-rgb),0.32);
}
/* muted variant — quietest, for the medical disclaimer */
.notice.muted {
  background: transparent; border: 0; padding: 12px 2px;
  font-size: 11.5px; color: var(--muted); line-height: 1.6;
}
.notice.muted .n-title {
  font-size: 11.5px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px;
}

/* --- Discount / save badge (paywall price card) ------------- */
.save-badge {
  display: inline-flex; align-items: center;
  padding: 4px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 700; line-height: 1;
  color: var(--on-brand); white-space: nowrap;
  background: var(--brand-ramp);
}

/* --- Generic Votisia modal sheet (slide-up, brand-styled) ----
   Mechanics mirror .play-scrim/.play-sheet; styling is Votisia's
   own. Lives inside .device; JS toggles .show. --- */
.vt-scrim {
  position: absolute; inset: 0; z-index: 80;
  background: var(--scrim);
  display: flex; align-items: flex-end;
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.vt-scrim.show { opacity: 1; pointer-events: auto; }
.vt-sheet {
  width: 100%; background: var(--surface);
  border-radius: 24px 24px 0 0;
  padding: 0 22px 24px;
  transform: translateY(102%);
  transition: transform .30s cubic-bezier(.2,.7,.2,1);
  max-height: 92%; overflow-y: auto;
  box-shadow: 0 -20px 50px -20px rgba(var(--shadow-rgb),0.30);
}
.vt-scrim.show .vt-sheet { transform: translateY(0); }
.vt-grip { width: 38px; height: 4px; border-radius: 999px; background: var(--hairline-strong); margin: 10px auto 2px; }
/* the share sheet holds a tall preview — let it scroll instead of overflowing */
#share-scrim .vt-sheet { max-height: 92vh; max-height: 92dvh; overflow-y: auto; -webkit-overflow-scrolling: touch; }

/* trust explainer rows */
.trust-hero {
  width: 56px; height: 56px; border-radius: 18px; margin: 6px 0 14px;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-ramp); color: var(--on-brand);
}
.trust-hero svg { width: 28px; height: 28px; }
.trust-row {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 15px 0; border-bottom: 1px solid var(--hairline);
}
.trust-row:last-of-type { border-bottom: 0; }
.trust-ic {
  width: 38px; height: 38px; border-radius: 12px; flex: 0 0 38px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, rgba(var(--brand-blue-rgb),0.10), rgba(var(--brand-purple-rgb),0.10));
  color: var(--ink);
}
.trust-ic svg { width: 18px; height: 18px; stroke-width: 1.8; }
.trust-row .tr-t { font-size: 14px; font-weight: 600; color: var(--ink); letter-spacing: -0.005em; }
.trust-row .tr-s { font-size: 12.5px; color: var(--muted); margin-top: 2px; line-height: 1.45; }

@media (prefers-reduced-motion: reduce) {
  .vt-sheet { transition: none; }
}

/* PWA install banner (Android: real prompt via beforeinstallprompt; iOS: hint) */
#vt-install {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  width: min(92vw, 370px); z-index: 220;
  animation: vt-install-rise .35s cubic-bezier(.2,.9,.3,1.2);
}
@keyframes vt-install-rise { from { opacity: 0; transform: translate(-50%, 16px); } }
.vt-install-card {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface, #fff); border: 1px solid var(--hairline, #ECECEC);
  border-radius: 18px; padding: 13px 14px;
  box-shadow: 0 18px 44px -14px rgba(var(--shadow-rgb),0.28);
}
.vt-install-ic {
  width: 40px; height: 40px; border-radius: 13px; flex: 0 0 40px;
  background: var(--brand-ramp);
  display: flex; align-items: center; justify-content: center; color: var(--on-brand);
}
.vt-install-ic svg { width: 22px; height: 22px; }
.vt-install-txt { flex: 1; min-width: 0; }
.vt-install-txt b { display: block; font-size: 13.5px; letter-spacing: -0.01em; }
.vt-install-txt span { display: block; font-size: 11.5px; color: var(--muted); line-height: 1.45; margin-top: 1px; }
.vt-install-go {
  flex: 0 0 auto; border: 0; cursor: pointer; font: inherit;
  background: var(--ink); color: var(--on-brand); font-size: 12.5px; font-weight: 600;
  padding: 9px 14px; border-radius: 999px;
}
.vt-install-x {
  flex: 0 0 auto; border: 0; cursor: pointer; background: transparent;
  color: var(--chart-axis); font-size: 15px; line-height: 1; padding: 6px;
}

/* --- Visually hidden (kept for screen readers / SEO) --- */
body .sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- Inline mood faces (vtFace() in app.js) --------------------- */
body .vt-face { display: inline-block; vertical-align: -0.22em; }
body .vt-face-pos { color: var(--mood-pos); }
body .vt-face-neu { color: var(--mood-neu); }
body .vt-face-neg { color: var(--mood-neg); }

/* ===================================================================
   DARK THEME
   `data-theme` on <html> always holds the EFFECTIVE theme — the resolver
   in index.html's <head> resolves "System" against the OS before the
   first paint, and app.js re-resolves it when the OS flips. So this file
   needs one plain attribute selector: no prefers-color-scheme branch, no
   duplicated token block, no double negation to reason about.

   The style guide's dark rule is a black ground with the SAME full-colour
   wave, so the logo needs no dark variant — the sprite's wordmark is
   currentColor and flips on its own.
   =================================================================== */
:root[data-theme="dark"] {
  --stage: #000000;          /* the guide's dark ground              */
  --surface: #17171A;        /* cards, sheets, inputs                */
  --surface-2: #0B0B0C;      /* app background                       */
  --surface-3: #202024;      /* bar tracks, inset wells              */
  --soft: #0B0B0C;
  --tile: #202024;
  --tile-flat: #17171A;
  --map-bg: #0F0F11;
  --ink: #F5F5F7;
  --muted: #9A9AA2;
  --hairline: #2A2A2E;
  --hairline-strong: #3A3A40;
  --scrim: rgba(0,0,0,0.62);
  --veil: rgba(11,11,12,0.55);
  --nav-veil: rgba(23,23,26,0.92);
  --topbar-veil: rgba(11,11,12,0.92);
  --shadow-rgb: 0,0,0;
  --fade-rgb: 11,11,12;
  /* the phone frame must stay visible against a black stage */
  --bezel: #1C1C1E;
  --bezel-2: #3A3A3C;

  /* Moods lightened for a dark ground — same hues, ~3.5:1 on --surface,
     and the steps stay separable on the map. */
  --mood-pos: #7C9BE8;
  --mood-neu: #9C93DE;
  --mood-neg: #D689D0;
  --mood-pos-rgb: 124,155,232;
  --mood-neu-rgb: 156,147,222;
  --mood-neg-rgb: 214,137,208;

  --chart-axis: #6E6E76;
  --chart-grid: #2A2A2E;
  --map-nodata: #1D1D21;
  --map-stroke: #0B0B0C;
  --map-hover: #F5F5F7;
  --map-1: #A05C9C;
  --map-2: #9C93DE;
  --map-3: #7C9BE8;
  --map-4: #4D8BFF;
  --map-5: #7FC4FF;

  /* UI accents lift off the near-black ground. The brand constants
     (--brand-blue/cyan/purple) and the logo gradient are untouched. */
  --accent: #4D8BFF;
  --accent-2: #A56BFF;
  --brand-ramp-text: linear-gradient(135deg, #4D8BFF 0%, #35CCF7 50%, #A56BFF 100%);
  --brand-ramp-90:   linear-gradient(90deg,  #4D8BFF 0%, #35CCF7 50%, #A56BFF 100%);
}

/* --- Dark: component corrections -------------------------------------
   Body-prefixed so they outrank Tailwind's runtime preflight, which is
   injected after this stylesheet. --------------------------------------- */
:root[data-theme="dark"] body .btn-primary {
  background: var(--ink); color: #0B0B0C;
  box-shadow: 0 10px 30px -12px rgba(0,0,0,0.8);
}
:root[data-theme="dark"] body .btn-primary:hover { background: #FFFFFF; }

/* Everything that was "ink on light" is now "light on ink" — the fill
   stays --ink, only the text/knob riding on it has to invert. */
:root[data-theme="dark"] body .pill.active,
:root[data-theme="dark"] body .pro-switch button.active,
:root[data-theme="dark"] body .switch[aria-pressed="true"] {
  background: var(--ink); color: #0B0B0C;
}
:root[data-theme="dark"] body .switch::after { background: #0B0B0C; }
:root[data-theme="dark"] body .stepper-dot.active { background: var(--ink); }

/* Chip selection uses an ink outline in light — too loud on black. */
:root[data-theme="dark"] body .chip.selected {
  border-color: var(--accent); color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Elevation on a dark ground reads as a lighter edge, not a heavier shadow. */
:root[data-theme="dark"] body .card,
:root[data-theme="dark"] body .mood-btn,
:root[data-theme="dark"] body .insight-card,
:root[data-theme="dark"] body .badge {
  box-shadow: 0 1px 0 0 rgba(255,255,255,0.04) inset;
}

/* In light the segmented control raises the active pill above a grey track;
   on a dark ground the raise has to go the other way, or the active option
   reads as the recessed one. */
:root[data-theme="dark"] body .seg { background: #0F0F12; }
:root[data-theme="dark"] body .seg button.active {
  background: #2E2E35; box-shadow: none;
}

/* --- Admin tool row -------------------------------------------
   A developer/admin affordance inside the product UI, so it must not read
   as a user feature: hairline-separated, muted, tagged "Admin". Injected
   by vtMountAdminReset() only for accounts with an admin role. */
body .admin-tool {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px dashed var(--hairline-strong);
}
body .admin-tool-tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); background: var(--surface-3);
  padding: 3px 6px; border-radius: 5px;
}
body .admin-tool-btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 0; border: 0; background: none; cursor: pointer;
  font-size: 12.5px; font-weight: 600; letter-spacing: -0.005em;
  color: var(--muted);
}
body .admin-tool-btn:hover { color: var(--ink); }
body .admin-tool-btn[disabled] { opacity: 0.5; pointer-events: none; }
body .admin-tool-btn svg { width: 14px; height: 14px; }

/* Pro marker inside a tab — replaces an inline-styled superscript that ran
   straight into the label ("1 JPRO"). */
.pill-pro {
  margin-left: 5px; font-size: 8.5px; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase;
  vertical-align: 2px;
  background: var(--brand-ramp-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* Fade the right edge only while there is more to scroll, so a half-visible
   tab reads as "keep going" rather than as a clipping bug. Toggled by
   vtWireScrollStrips(); without JS the strip still scrolls, just unfaded. */
.pill-scroll.has-more {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 46px), transparent calc(100% - 6px));
  mask-image: linear-gradient(90deg, #000 calc(100% - 46px), transparent calc(100% - 6px));
}
