/*
 * ASTROCARTO — styles.css
 * ─────────────────────────────────────────────────────────────
 * All visual styling for the application.
 *
 * SECTIONS (in order)
 *   1.  Design tokens (:root CSS variables — colors, sizes)
 *   2.  Base reset
 *   3.  Loading screen
 *   4.  Header bar (logo, center pill, dropdowns, geo search)
 *   5.  Map container + frame strips (top/bottom label zones)
 *   6.  Frame SVG overlay (connector lines)
 *   7.  Leaflet overrides + tile filter
 *   8.  Bottom HUD (statusbar, click-hint)
 *   9.  Side panel (relocation chart)
 *  10.  Aspect / checkbox controls
 *  11.  Mobile settings panel + geo search modal
 *  12.  Front page
 *  13.  Mobile responsive overrides (@media ≤ 640px)
 */

/* ── DESIGN TOKENS ─────────────────────────────────────────── */
:root {
  /* Premium dark base — deep navy-indigo instead of pure black.
     Gold + violet accents read as a warm overlay on this base
     rather than as tiny glints against void. Every panel/HUD
     token derives from the same hue so surfaces feel unified. */
  --bg:           #0A0F24;
  --bg-panel:     rgba(10, 15, 36, 0.96);
  --bg-hud:       rgba(10, 15, 36, 0.92);
  --border:       rgba(255,255,255,0.09);
  --border-hi:    rgba(255,255,255,0.22);
  --gold:         #C8A84E;
  --gold-hi:      #F5D060;
  --gold-dim:     rgba(200,168,78,0.18);
  --t1:           #F6F4EF;
  --t2:           #C4C2D0;
  --t3:           #7A7888;
  --t4:           #44424F;

  /* Top-chrome background — the gradient painted on every top
     strip in the app (.fp-nav, #auth-topbar, #header,
     .auth-shell-nav). Per-theme overrides below give each theme
     a "darker version of itself" chrome, so the header always
     feels native to its theme rather than an imported black bar.
     Default here is the historical near-black dark-theme chrome. */
  --chrome-bg:    linear-gradient(180deg,
                    rgba(14, 12, 8, 0.97) 0%,
                    rgba(6, 8, 16, 0.95) 100%);
  --c-natal:        #D4AE52;
  --c-parans:       #5BBDE0;
  --c-midpoints:    #D45BAA;
  --c-transits:     #7DD45B;
  --c-progressions: #3ECFC4;
  --header-h: 62px;
  --strip-h:  100px;
  --strip-w:  88px;   /* left + right map gutters. Sized so the side label
                         cluster (glyph @14px, aspect @26px, angle @37px,
                         stem end @44px) + stem run to the map edge visually
                         matches the 30-px-tall label cluster + 56-px stem
                         used in the 100-px top/bottom strips — premium
                         frame symmetry without wasting map pixels.
                         Mobile overrides to 64 px. */
  --panel-w:  384px;
  --radius:   7px;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { width: 100%; height: 100%; overflow: hidden; background: var(--bg); }
body { font-family: 'JetBrains Mono', monospace; color: var(--t1); }
button { font-family: inherit; cursor: pointer; border: none; }
::-webkit-scrollbar { width: 2px; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.10); }

/* ── LOADING ──────────────────────────────────────────────── */
#loading {
  position: fixed; inset: 0; z-index: 9999;
  background: var(--bg);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 22px;
  transition: opacity 0.7s ease;
}
#loading.out { opacity: 0; pointer-events: none; }
.spinner {
  width: 36px; height: 36px;
  border: 1px solid rgba(200,168,78,0.15);
  border-top-color: var(--gold);
  border-radius: 50%;
  animation: spin 1.5s linear infinite;
}
.loading-name {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(14px, 4.5vw, 22px); font-weight: 300; letter-spacing: 0.20em; color: var(--gold-hi);
}
.loading-sub { font-size: 8.5px; letter-spacing: 0.26em; color: var(--t3); text-transform: uppercase; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── LOGOUT CURTAIN ────────────────────────────────────────────
   Full-viewport overlay injected from JS the moment the user
   clicks Log out, destroyed by the subsequent full-page reload.
   z-index above every other stacking context (account menu is
   2400, auth-topbar 2300, modals 3000–9999) so nothing can peek
   through during the sign-out window. var(--bg) makes it auto-
   theme; reusing .spinner / .loading-name / .loading-sub
   vocabulary makes the curtain → reload → #loading boot-screen
   handoff visually seamless. */
#logout-curtain {
  position: fixed;
  inset: 0;
  z-index: 100000;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
}

/* Logging-out lockdown — JS adds `html.logging-out` the instant
   Log out is clicked, before the curtain paints. These rules
   then instantly visibility-hide the account-menu popover and
   the auth-topbar so they stop contributing compositor frames
   during the brief curtain-up-to-reload window. visibility
   (not display) keeps layout stable, avoiding reflow-driven
   repaints; !important defeats the popover's own .open-state
   rules without touching them. */
html.logging-out #account-menu,
html.logging-out #auth-topbar {
  visibility: hidden !important;
  transition: none !important;
}

/* ── HEADER ───────────────────────────────────────────────── */
#header {
  position: fixed; top: 0; left: 0; right: 0; height: var(--header-h);
  /* Chrome bg comes from the --chrome-bg token, so this strip is
     a "darker version of the active theme" in every theme —
     near-black in Dark, deep walnut in Light, midnight sapphire
     in Atlas Blue. */
  background: var(--chrome-bg);
  /* Gold separator line at the bottom */
  border-bottom: 1px solid rgba(200,168,78,0.50);
  /* Subtle inner glow along the top */
  box-shadow:
    0 1px 0 0 rgba(200,168,78,0.14) inset,
    0 8px 32px rgba(0,0,0,0.60);
  backdrop-filter: blur(40px); -webkit-backdrop-filter: blur(40px);
  display: grid;
  /* max-content | minmax(0, 1fr) | max-content
     Slice A4 rebuilt the header layout after moving birth details
     out of the header (now a chip below the header over #frame-top).
     The header now holds only the logo (left), the quick toolbar
     (center), and the right-side controls. Left = logo's intrinsic
     ~314px (nowrap, post-Slice-7 wordmark). Center = the remaining
     viewport space (1fr, min 0) so the toolbar pill shrinks rather
     than overlapping right; .header-center has overflow-x: auto so
     items scroll horizontally inside the column when the viewport
     is narrow (e.g., half-width desktop). Right = buttons' max-
     content so account/menu/settings are always fully visible. */
  grid-template-columns: max-content minmax(0, 1fr) max-content;
  column-gap: 24px;
  align-items: center;
  padding: 0 24px;
  z-index: 500;
}

/* Left column — logo */
.header-left {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; justify-content: center;
  min-width: 0;
}
.logo {
  font-family: 'Cormorant Garamond', serif;
  font-size: 14px; font-weight: 600; letter-spacing: 0.18em; color: var(--gold-hi);
  display: flex; align-items: center; gap: 10px; white-space: nowrap;
  cursor: pointer; transition: opacity .18s;
}
.logo:hover { opacity: 0.75; }
.logo-star { font-size: 22px; color: var(--gold-hi); opacity: 1.0; }

/* Center pill — gold-accented border, very subtle gold tint */
.header-center {
  display: flex; align-items: center; gap: 4px;
  background: rgba(200,168,78,0.04);
  border: 1px solid rgba(200,168,78,0.40);
  border-radius: 10px;
  padding: 5px 8px;
  /* Faint inner shadow for depth */
  box-shadow: 0 0 0 1px rgba(0,0,0,0.4) inset;
  min-width: 0;
  /* Slice A4: scroll toolbar items horizontally inside the pill
     when the center column gets too narrow (e.g., half-width
     desktop). Prevents overlap onto .header-right. */
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(200,168,78,0.30) transparent;
}
.header-center::-webkit-scrollbar { height: 6px; }
.header-center::-webkit-scrollbar-track { background: transparent; }
.header-center::-webkit-scrollbar-thumb {
  background: rgba(200,168,78,0.30);
  border-radius: 3px;
}

/* Gold separator between control groups */
.h-div {
  width: 1px; height: 18px;
  background: linear-gradient(180deg, transparent, rgba(200,168,78,0.50), transparent);
  flex-shrink: 0; margin: 0 3px;
}

/* ── LAYER BUTTONS ── */
.layer-row { display: flex; align-items: center; gap: 2px; }
.layer-btn {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 12px; height: 30px;
  background: transparent;
  border: 1px solid transparent; border-radius: 6px;
  color: rgba(240,236,220,0.85);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: 0.05em; white-space: nowrap;
  transition: all 0.18s ease;
}
.layer-btn:hover {
  color: var(--gold-hi);
  background: rgba(200,168,78,0.08);
  border-color: rgba(200,168,78,0.20);
}
/* SVG line-style preview */
.layer-btn .lstyle { opacity: 0.35; transition: all .2s; }
.layer-btn:hover .lstyle { opacity: 0.85; }

/* ── ACTIVE LAYER — gold highlight ── */
.layer-btn.on {
  color: var(--gold-hi);
  background: linear-gradient(135deg,
    rgba(200,168,78,0.18) 0%,
    rgba(200,168,78,0.10) 100%);
  border-color: rgba(200,168,78,0.45);
  box-shadow:
    0 0 10px rgba(200,168,78,0.12),
    0 0 0 1px rgba(200,168,78,0.08) inset;
}
.layer-btn.on .lstyle { opacity: 1; }

/* Right column — icon buttons */
.header-right { display: flex; align-items: center; gap: 8px; justify-content: flex-end; justify-self: end; }
.icon-btn {
  width: 32px; height: 32px;
  border: 1px solid rgba(200,168,78,0.18) !important;
  border-radius: var(--radius);
  background: rgba(200,168,78,0.04);
  color: rgba(240,236,220,0.90); font-size: 14px;
  display: flex; align-items: center; justify-content: center;
  transition: all .18s;
}
.icon-btn:hover {
  border-color: rgba(200,168,78,0.45) !important;
  color: var(--gold-hi);
  background: rgba(200,168,78,0.10);
  box-shadow: 0 0 8px rgba(200,168,78,0.10);
}

/* ── SHARED STYLE FOR ALL HEADER DROPDOWN TRIGGERS ── */
/* Width, Aspect, Color buttons all share this compact style */
.width-ctrl { position: relative; flex-shrink: 0; }
.width-ctrl-btn {
  height: 30px; padding: 0 11px;
  display: flex; align-items: center; gap: 6px;
  background: transparent;
  border: 1px solid transparent; border-radius: 6px;
  color: rgba(240,236,220,0.90);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: .04em;
  cursor: pointer; white-space: nowrap; transition: all .18s;
}
.width-ctrl-btn:hover { color: var(--gold-hi); background: rgba(200,168,78,0.08); border-color: rgba(200,168,78,0.20); }
.width-ctrl-btn.open  { color: var(--gold-hi); background: rgba(200,168,78,0.10); border-color: rgba(200,168,78,0.35); }
.width-ctrl-label {
  font-size: 8.5px; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(200,168,78,0.85);
}
.width-ctrl-chevron { opacity: .5; font-size: 6px; color: rgba(200,168,78,0.70); transition: transform .18s; }
.width-ctrl-btn.open .width-ctrl-chevron { transform: rotate(180deg); }

.width-dropdown {
  /* Slice A6: position: fixed + body-portal via JS so the dropdown
     escapes .header-center's overflow-x scroll clip. JS sets inline
     top/left from triggerEl.getBoundingClientRect() on open. */
  display: none; position: fixed; top: calc(100% + 7px); left: 0;
  min-width: 136px; max-width: calc(100vw - 16px);
  background: linear-gradient(180deg, rgba(14,12,8,0.99), rgba(6,8,16,0.98));
  border: 1px solid rgba(200,168,78,0.45); border-radius: 10px;
  overflow: hidden; z-index: 9000;
  box-shadow: 0 16px 48px rgba(0,0,0,0.7), 0 0 0 1px rgba(200,168,78,0.06) inset;
}
.width-dropdown.open { display: block; }
.width-option {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 16px;
  font-family: 'JetBrains Mono', monospace; font-size: 11.5px; color: #FFFFFF;
  cursor: pointer; transition: background .12s, color .12s; gap: 16px;
}
.width-option:hover { background: rgba(200,168,78,0.08); color: var(--gold-hi); }
.width-option.on    { color: var(--gold-hi); background: rgba(200,168,78,0.06); }
.width-option .check { opacity: 0; font-size: 9px; color: var(--gold); }
.width-option.on .check { opacity: 1; }

/* ── GEO SEARCH ─────────────────────────────────────────────── */
.geo-search { position: relative; flex-shrink: 0; }
.geo-search-input {
  height: 30px; width: 180px;
  background: rgba(200,168,78,0.06);
  border: 1px solid rgba(200,168,78,0.40); border-radius: 6px;
  color: rgba(240,236,220,0.95);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: .04em; padding: 0 12px;
  outline: none; transition: border-color .18s, width .22s ease, background .18s;
}
.geo-search-input::placeholder { color: rgba(240,236,220,0.60); }
.geo-search-input:focus {
  border-color: rgba(200,168,78,0.70);
  background: rgba(200,168,78,0.10);
  width: 220px;
}

.geo-dropdown {
  /* Slice A6: position: fixed + body-portal (see .width-dropdown). */
  display: none; position: fixed; top: calc(100% + 7px); left: 0;
  min-width: 230px; max-width: calc(100vw - 16px); max-height: 264px; overflow-y: auto;
  background: var(--bg-panel);
  border: 1px solid var(--border-hi); border-radius: 10px;
  z-index: 9000; box-shadow: 0 16px 48px rgba(0,0,0,0.7);
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.08) transparent;
}
.geo-dropdown.open { display: block; }
.geo-group-label {
  font-size: 8px; letter-spacing: .20em; text-transform: uppercase;
  color: #A8A6C0; padding: 10px 15px 4px; pointer-events: none;
}
.geo-item {
  padding: 8px 15px; font-size: 11.5px; color: #FFFFFF;
  cursor: pointer; transition: background .12s, color .12s;
  display: flex; align-items: center; gap: 8px;
}
.geo-item:hover, .geo-item.active { background: rgba(255,255,255,0.06); color: var(--t1); }
.geo-item-icon { font-size: 11px; opacity: 0.5; width: 15px; text-align: center; }

/* ── MAP ─────────────────────────────────────────────────────── */
/* The map sits inside a full rectangular frame: top + bottom strips
   (--strip-h tall) and left + right gutters (--strip-w wide).
   The side gutters are reserved for future line entry/exit labels. */
#map {
  position: fixed;
  top: calc(var(--header-h) + var(--strip-h));
  left: var(--strip-w); right: var(--strip-w);
  bottom: var(--strip-h);
  transition: right .42s cubic-bezier(.4,0,.2,1);
  background: var(--bg);
  /* Map frame — single continuous gold rectangle drawn exactly at
     the map's perimeter. Previously the four frame strips each
     carried a border on their map-facing edge, but the top/bottom
     strips span the full window width so their borders extended
     past the map and cut visible seams across the corners where
     they met the side gutters. Drawing ONE border on #map is
     geometry-correct (matches the map's box exactly) and removes
     every corner seam with no loss of the gold frame impression. */
  border: 1px solid rgba(200,168,78,0.22);
}
#map.shrunk { right: calc(var(--panel-w) + var(--strip-w)); }

/* ── FRAME STRIPS ─────────────────────────────────────────────
   Four fixed UI zones forming a rectangular frame around the map:
   top / bottom (full-width) and left / right (between them). They
   never move with the map. Borders on the map-facing edges form a
   continuous gold rectangle around the geographic surface.
─────────────────────────────────────────────────────────────── */
.frame-strip {
  position: fixed; left: 0; right: 0;
  height: var(--strip-h);
  background: var(--bg-panel);
  z-index: 402;
  overflow: hidden;
  transition: right .42s cubic-bezier(.4,0,.2,1);
}
#frame-top {
  top: var(--header-h);
  /* Background intentionally inherited from .frame-strip
     (var(--bg-panel)) so the four frame pieces share ONE uniform
     surface tone. The previous directional gold-fade gradients were
     removed: each strip used a different fade direction, so corners
     where strips met showed a visible hue jump (top strip's bottom
     edge was plain panel while the side strip's top edge was at its
     strongest gold-tint point), and the right strip's outward fade
     produced a brighter "haze" band along the far-right edge that
     the other three sides had no equivalent of. */
}
#frame-bottom {
  bottom: 0;
}
.frame-strip.shrunk { right: var(--panel-w); }

/* Side gutters — reserved space for future line entry/exit labels
   on the east and west sides of the map. Same dark/gold language as
   the top/bottom strips. They sit between the top and bottom strips
   so the four pieces form a single continuous frame. */
.frame-side {
  position: fixed;
  top: calc(var(--header-h) + var(--strip-h));
  bottom: var(--strip-h);
  width: var(--strip-w);
  background: var(--bg-panel);
  z-index: 402;
  overflow: hidden;
  transition: right .42s cubic-bezier(.4,0,.2,1);
}
#frame-left {
  left: 0;
  /* Inherits background from .frame-side — see #frame-top note. */
}
#frame-right {
  right: 0;
  /* Inherits background from .frame-side — see #frame-top note. */
}
#frame-right.shrunk { right: var(--panel-w); }


/* SVG overlay — connector lines + labels for all four frame edges.
   Spans the FULL window (not just the map) so left/right labels can
   render inside the side gutters. updateLabels() converts map-space
   crossings to svg-space by adding --strip-w to all x coordinates. */
#frame-svg {
  position: fixed;
  top: var(--header-h);
  left: 0; right: 0;
  bottom: 0;
  pointer-events: none;
  z-index: 403;
  overflow: hidden;
  transition: right .42s cubic-bezier(.4,0,.2,1);
}
#frame-svg.shrunk { right: var(--panel-w); }
/* SMOOTH-PAN Step D (zoom) — during an animated zoom, each label group glides to
   its precise target (set by glideLabelsForZoom on zoomanim). This transition is
   matched to Leaflet's own zoom transition (.25s cubic-bezier(0,0,.25,1)) so the
   labels move in step with the scaling lines, then are rebuilt exactly at
   zoomend (the class is removed). No .labels-zooming during pan → pan transforms
   stay instant (Step D live tracking). */
#frame-svg.labels-zooming g {
  transition: transform .25s cubic-bezier(0,0,.25,1);
}
#frame-svg text {
  pointer-events: none;
  white-space: nowrap;
}
#frame-svg .frame-side-label-layer {
  pointer-events: none;
}

/* Leaflet overrides */
.leaflet-bar a { background: var(--bg-hud) !important; color: var(--t3) !important; border-color: var(--border) !important; border-radius: 0 !important; }
.leaflet-bar a:hover { color: var(--t1) !important; background: rgba(255,255,255,0.06) !important; }
.leaflet-bar { border: 1px solid var(--border) !important; border-radius: var(--radius) !important; box-shadow: none !important; overflow: hidden; }
.leaflet-popup-content-wrapper {
  /* Surface is token-driven so the popup themes with the app:
     dark → navy, light → cream, atlas-blue → lifted sapphire.
     The previous hardcoded rgba(6,8,16,0.97) looked fine in dark
     mode but collapsed against --t1 (navy-ink) in light mode,
     rendering the content nearly invisible. */
  background: var(--bg-panel) !important;
  border: 1px solid var(--border-hi) !important;
  border-radius: 10px !important; padding: 0 !important;
  box-shadow: 0 24px 64px rgba(0,0,0,.75) !important;
  color: var(--t1) !important;
  font-family: 'JetBrains Mono', monospace !important; font-size: 11px !important;
}
.leaflet-popup-content { margin: 13px 16px !important; line-height: 1.75; }
.leaflet-popup-tip-container, .leaflet-popup-close-button, .leaflet-attribution-flag { display: none !important; }
/* Attribution strip — legible on desktop + mobile, over light topo/OSM tiles in
   all UI themes. Base = high-contrast dark pill (used by dark + atlas); light
   theme overrides to a light pill below. Compact + wraps so it never runs under
   the bottom-right zoom control. */
.leaflet-control-attribution {
  background: rgba(6,8,16,0.82) !important;
  color: #e6ebf5 !important;
  font-size: 11px !important;
  line-height: 1.45 !important;
  padding: 2px 8px !important;
  border-radius: 5px !important;
  max-width: 78vw;
  white-space: normal;
}
.leaflet-control-attribution a { color: #9ec5ff !important; text-decoration: underline; }

/* OSM basemap failure notice (Slice 6B) — compact, non-modal, near top-center of
   the map. Shown only when the OSM/MapLibre/PMTiles basemap fails; it never blocks
   the chart/sidebar UI or astro interactions (sits inside the map container). */
.osm-basemap-error {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1100;                 /* above Leaflet controls (1000), below app modals */
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 86vw;
  padding: 7px 10px 7px 14px;
  background: rgba(6, 8, 16, 0.88);
  color: #e6ebf5;
  font-size: 13px;
  line-height: 1.3;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}
.osm-basemap-error-msg { white-space: nowrap; }
.osm-basemap-error-retry {
  flex: none;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  color: #06202f;
  background: #9ec5ff;
  border: 0;
  border-radius: 5px;
  padding: 4px 12px;
}
.osm-basemap-error-retry:hover { background: #b9d6ff; }
html[data-theme="light"] .osm-basemap-error {
  background: rgba(253, 248, 234, 0.95);
  color: #23304a;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
}
html[data-theme="light"] .osm-basemap-error-retry { color: #fff; background: #1565c0; }

/* ── BASEMAP TILES ──────────────────────────────────────────────────
   Slice M3: the basemap is now a real theme-specific MapTiler style
   (light = landscape; dark + atlas-blue share basic-v2-dark), chosen
   per-theme in app.js and swapped live on theme change. The old
   invert/hue-rotate filter that faked a dark map from the light
   dataviz tiles is gone — no filter applies to .tile-carto today;
   the class stays on the tile layer as a styling hook.              */

/* ── BOTTOM HUD ───────────────────────────────────────────────── */
#statusbar {
  position: fixed; bottom: calc(var(--strip-h) + 10px); left: 20px; z-index: 404;
  background: var(--bg-hud); border: 1px solid var(--border);
  border-radius: var(--radius); backdrop-filter: blur(20px);
  padding: 7px 14px; font-size: 10.5px; letter-spacing: .09em; color: var(--t1);
  pointer-events: none;
}
#click-hint {
  position: fixed; bottom: calc(var(--strip-h) + 10px); left: 50%; transform: translateX(-50%);
  z-index: 404; background: var(--bg-hud); border: 1px solid var(--border);
  border-radius: var(--radius); backdrop-filter: blur(20px);
  padding: 7px 20px; font-size: 10.5px; letter-spacing: .14em;
  color: var(--t1); text-transform: uppercase;
  pointer-events: none; transition: opacity .5s; white-space: nowrap;
}
#click-hint.gone { opacity: 0; }

/* ── SIDE PANEL ───────────────────────────────────────────────── */
#panel {
  position: fixed; top: var(--header-h); right: 0;
  width: var(--panel-w); bottom: 0;
  background: var(--bg-panel); border-left: 1px solid var(--border);
  backdrop-filter: blur(48px); -webkit-backdrop-filter: blur(48px);
  transform: translateX(100%);
  transition: transform .42s cubic-bezier(.4,0,.2,1);
  z-index: 450; display: flex; flex-direction: column; overflow: hidden;
}
#panel.open { transform: translateX(0); }

/* ══════════════════════════════════════════════════════════════════
   AI ASSISTANT UI SHELL v1 (frontend-only mock)
   Scoped classes for the Dashboard card, the #assistant-page surface,
   the map side-panel Location|AI tabs, and the shared chat shell.
   Token-based so it adapts to dark / light / atlas-blue. No real AI.
   ══════════════════════════════════════════════════════════════════ */

/* Map page AI Assistant — centered floating window + minimized dock.
   A spacious expanded workspace over the map (like the chart-wheel modal),
   not a side-panel extension. No heavy backdrop so the map stays visible.
   z-index 1200 sits above #panel (450) but below #chart-modal (9999). */
#ai-window {
  position: fixed; z-index: 1200;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 780px; max-width: calc(100vw - 96px);
  height: 680px; max-height: calc(100vh - 120px);
  display: flex; flex-direction: column;
  background: var(--bg-panel, rgba(20,18,34,0.98)); border: 1px solid var(--gold-dim);
  border-radius: 16px; box-shadow: 0 32px 90px rgba(0,0,0,0.62);
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
}
#ai-window[hidden] { display: none; }
.ai-win-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.ai-win-title { font-family: 'Cormorant Garamond', serif; font-style: italic; font-size: 18px; color: var(--t1); }
.ai-win-actions { display: flex; gap: 6px; }
.ai-win-btn {
  width: 28px; height: 28px; border-radius: 7px; background: transparent;
  border: 1px solid var(--border); color: var(--t2); cursor: pointer;
  font-size: 13px; line-height: 1; transition: all .15s;
  display: inline-flex; align-items: center; justify-content: center;
}
.ai-win-btn:hover { color: var(--gold-hi); border-color: rgba(200,168,78,0.5); }
/* Inside the window the shared shell fills the body (overrides the page host). */
.ai-window-host { flex: 1; min-height: 0; height: auto; max-width: none; margin: 0; }

/* Bottom-center of the viewport — floats over the map, independent of the
   relocation side panel (#panel z-index 450), never clipped by or scrolling
   with it. z-index 1200 keeps it below #chart-modal (9999). */
#ai-dock {
  position: fixed; z-index: 1200; left: 50%; bottom: 26px; transform: translateX(-50%);
  width: auto; max-width: calc(100vw - 32px);
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 16px; border-radius: 999px; cursor: pointer;
  background: var(--bg-panel, rgba(20,18,34,0.98)); border: 1px solid var(--gold-dim);
  box-shadow: 0 12px 36px rgba(0,0,0,0.45);
  color: var(--t1); font-family: 'JetBrains Mono', monospace; font-size: 11px;
}
#ai-dock[hidden] { display: none; }
#ai-dock:hover { border-color: rgba(200,168,78,0.6); }
.ai-dock-label #ai-dock-loc { color: var(--gold-hi); }
.ai-dock-caret { color: var(--gold-hi); }

@media (max-width: 640px) {
  #ai-window {
    inset: var(--header-h) 0 0 0; transform: none;
    width: auto; max-width: none; height: auto; max-height: none; border-radius: 0;
  }
  #ai-dock { left: 12px; right: 12px; bottom: 16px; transform: none; max-width: none; justify-content: center; }
}

/* "Ask AI about this location" CTA at the top of the Location view */
.ai-ask-btn {
  width: 100%; margin-bottom: 16px; padding: 10px 14px;
  background: linear-gradient(135deg, rgba(200,168,78,0.20) 0%, rgba(200,168,78,0.10) 100%);
  border: 1px solid rgba(200,168,78,0.45); border-radius: var(--radius);
  color: var(--gold-hi); font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: all .2s;
}
.ai-ask-btn:hover { border-color: rgba(200,168,78,0.75); }
/* [hidden] companion: .ai-ask-btn's explicit display:inline-flex (author
   class) overrides the UA `[hidden]{display:none}` rule, so the entitlement
   gate's `el.hidden = true` (syncAskAiEntitlement) needs this to actually
   hide the button for free/anonymous users. Same specificity trap noted at
   .fp-field[hidden] / .charts-save-row[hidden] below. */
.ai-ask-btn[hidden] { display: none; }

/* Shared chat shell */
.ai-shell { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 18px 22px 16px; }
.ai-shell-host {
  width: 100%; max-width: 760px; margin: 8px auto 0;
  display: flex; flex-direction: column;
  height: calc(100vh - var(--header-h) - 230px); min-height: 320px;
}
.ai-messages {
  flex: 1; min-height: 0; overflow-y: auto; padding: 4px 2px 10px;
  display: flex; flex-direction: column; gap: 10px;
  scrollbar-width: thin; scrollbar-color: var(--gold) rgba(255,255,255,0.08);
}
.ai-messages::-webkit-scrollbar { width: 12px; }
.ai-messages::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); }
.ai-messages::-webkit-scrollbar-thumb { background: var(--gold); border-radius: 6px; border: 2px solid transparent; background-clip: padding-box; }
.ai-messages::-webkit-scrollbar-thumb:hover { background: var(--gold-hi); }

.ai-msg {
  font-family: 'JetBrains Mono', monospace; font-size: 12px; line-height: 1.65;
  padding: 10px 14px; border-radius: 10px; max-width: 86%;
}
.ai-msg-assistant { align-self: flex-start; background: rgba(255,255,255,0.04); border: 1px solid var(--border); color: var(--t1); }
.ai-msg-user { align-self: flex-end; background: rgba(200,168,78,0.12); border: 1px solid rgba(200,168,78,0.30); color: var(--t1); }

@media (max-width: 640px) {
  .ai-shell-host { height: calc(100vh - var(--header-h) - 160px); max-width: none; }
}

/* ── Dashboard assistant WORKSPACE (page surface only; map panel unaffected) ── */
.assistant-workspace { align-items: stretch; padding: calc(52px + 14px) 0 0; }
/* AI assistant topbar: brand/back swap toggled by JS on #/assistant. The ID
   rule beats any .auth-topbar-brand display so the [hidden] attribute hides. */
#auth-topbar-back[hidden], #auth-topbar-brand[hidden] { display: none; }
.assistant-workspace .ai-shell-host {
  max-width: 860px; margin: 0 auto; width: 100%;
  /* Fill the flex column; the message list (.ai-messages) is the ONLY scroll
     area. No 100vh height calc — it overshot the mobile visible viewport and
     let scrolled content slide under the pinned composer. height:auto beats
     the base .ai-shell-host calc height. */
  flex: 1 1 auto; min-height: 0; height: auto; overflow: hidden;
}
.ai-shell-page { padding: 8px 22px 18px; }

/* Bound the Dashboard assistant page to the *visible* viewport so the pinned
   composer sits at the real bottom on mobile (dvh tracks the dynamic browser
   toolbar; the vh line is the fallback). The page itself never scrolls — only
   .ai-messages does. id-level specificity intentionally beats the generic
   .auth-page rules (overflow-y:auto + inset:0's bottom:0). Scoped to
   #assistant-page only; the map AI window and other auth pages are untouched. */
#assistant-page.assistant-workspace {
  bottom: auto;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/* Controls bar — Charts / Locations / chat options */
.ai-ctrlbar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-shrink: 0; }
.ai-ctrl-wrap { position: relative; }
.ai-ctrl-spacer { flex: 1 1 auto; }
.ai-ctrl {
  background: rgba(255,255,255,0.03); border: 1px solid var(--border); color: var(--t1);
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; padding: 7px 12px;
  border-radius: 999px; cursor: pointer; transition: all .15s;
  display: inline-flex; align-items: center; gap: 6px;
}
.ai-ctrl:hover, .ai-ctrl.open { border-color: rgba(200,168,78,0.5); }
.ai-ctrl-k { color: var(--t3); text-transform: uppercase; letter-spacing: 0.12em; }
.ai-ctrl-v { color: var(--gold-hi); }
.ai-caret { color: var(--t3); font-size: 9px; }
.ai-ctrl-icon { color: var(--gold-hi); font-weight: 600; }

/* Popovers (charts / locations / options / plus / settings) */
.ai-pop {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 9000;
  min-width: 220px; max-width: 320px; padding: 6px;
  background: var(--bg-panel, rgba(20,18,34,0.98)); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 16px 48px rgba(0,0,0,0.5);
  display: flex; flex-direction: column; gap: 2px;
}
.ai-pop[hidden] { display: none; }
.ai-pop-right { left: auto; right: 0; }
.ai-pop-up { top: auto; bottom: calc(100% + 8px); }
.ai-pop-item {
  text-align: left; background: transparent; border: 0; border-radius: 7px; color: var(--t1);
  font-family: 'JetBrains Mono', monospace; font-size: 11px; padding: 8px 10px;
  cursor: pointer; transition: background .12s;
}
.ai-pop-item:hover:not([disabled]) { background: rgba(200,168,78,0.10); color: var(--gold-hi); }
.ai-pop-item[disabled] { opacity: 0.45; cursor: default; }
.ai-pop-note {
  color: var(--t3); font-family: 'JetBrains Mono', monospace; font-size: 9.5px;
  font-style: italic; padding: 6px 10px 4px; line-height: 1.5;
}
.ai-set-group { padding: 4px 4px 8px; }
.ai-set-title {
  color: var(--gold-hi); font-family: 'JetBrains Mono', monospace; font-size: 9px;
  letter-spacing: 0.16em; text-transform: uppercase; padding: 4px 8px;
}
.ai-set-opt {
  width: 100%; text-align: left; background: transparent; border: 1px solid transparent;
  border-radius: 7px; color: var(--t2); font-family: 'JetBrains Mono', monospace;
  font-size: 11px; padding: 7px 10px; cursor: pointer; transition: all .12s;
}
.ai-set-opt:hover { background: rgba(200,168,78,0.08); }
.ai-set-opt.is-active { border-color: rgba(200,168,78,0.45); color: var(--gold-hi); }
.ai-set-desc { color: var(--t3); font-size: 9.5px; }

/* ChatGPT-style composer */
.ai-composer {
  display: flex; align-items: center; gap: 8px; flex-shrink: 0;
  padding: 8px 10px; margin-top: 8px;
  background: rgba(255,255,255,0.03); border: 1px solid var(--border); border-radius: 26px;
}
.ai-composer:focus-within { border-color: rgba(200,168,78,0.5); }
.ai-comp-btn {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  background: transparent; border: 1px solid var(--border); color: var(--t2);
  font-size: 15px; line-height: 1; cursor: pointer; transition: all .15s;
  display: inline-flex; align-items: center; justify-content: center;
}
.ai-comp-btn:hover { color: var(--gold-hi); border-color: rgba(200,168,78,0.5); }
.ai-composer-input {
  flex: 1 1 auto; background: transparent; border: 0; outline: none; color: var(--t1);
  font-family: 'JetBrains Mono', monospace; font-size: 12px; height: 34px;
}
.ai-composer-input::placeholder { color: var(--t3); }
.ai-comp-send {
  flex: none; width: 36px; height: 36px; border-radius: 50%;
  background: linear-gradient(135deg, rgba(200,168,78,0.30), rgba(200,168,78,0.16));
  border: 1px solid rgba(200,168,78,0.6); color: var(--gold-hi);
  font-size: 16px; line-height: 1; cursor: pointer; transition: all .15s;
  display: inline-flex; align-items: center; justify-content: center;
}
.ai-comp-send:hover { border-color: var(--gold-hi); }
.ai-comp-send[disabled], .ai-composer-input[disabled] { opacity: 0.45; cursor: default; }

/* Phase F Slice 2 — premium feature lock (Relocation Themes, AI Chat).
   Shared by the themes panel locked state and the AI composer lock note. */
.feature-lock { display: flex; flex-direction: column; gap: 4px; padding: 6px 0; }
.feature-lock-title {
  color: var(--t1); font-family: 'JetBrains Mono', monospace;
  font-size: 11px; font-weight: 600; line-height: 1.4;
}
.feature-lock-body {
  color: var(--t3); font-family: 'JetBrains Mono', monospace;
  font-size: 10px; line-height: 1.5;
}
.feature-lock-cta {
  align-self: flex-start; margin-top: 2px; color: var(--gold-hi);
  font-family: 'JetBrains Mono', monospace; font-size: 10px; text-decoration: none;
}
.feature-lock-cta:hover { text-decoration: underline; }
.ai-lock-note { padding: 8px 12px; margin-top: 6px; }

@media (max-width: 640px) {
  .assistant-workspace .ai-shell-host { max-width: none; }
  .ai-shell-page { padding: 6px 12px 12px; }
  .ai-ctrl-v { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Dashboard assistant — keep Charts/Locations + the composer inside narrow
     viewports (no horizontal overflow / right-side clipping). The default
     flex min-width:auto on the input + pills stops them shrinking, so the row
     spilled past the screen. Scoped to #assistant-page so the map AI window
     (good as-is) is untouched. */
  #assistant-page .ai-ctrlbar { flex-wrap: wrap; gap: 8px; }
  #assistant-page .ai-ctrl-spacer { display: none; }
  #assistant-page .ai-ctrlbar > .ai-ctrl-wrap { flex: 1 1 0; min-width: 0; }
  #assistant-page .ai-ctrlbar > .ai-ctrl-wrap:last-child { flex: 0 0 auto; }  /* options ⋯ stays compact */
  #assistant-page .ai-ctrl { width: 100%; min-width: 0; overflow: hidden; }
  #assistant-page .ai-ctrl-icon { width: auto; }
  #assistant-page .ai-ctrl-v { min-width: 0; }
  #assistant-page .ai-composer { min-width: 0; max-width: 100%; position: relative; }
  #assistant-page .ai-composer-input { min-width: 0; }

  /* Assistant popovers (Charts/Locations/options + composer plus/settings):
     make them viewport-safe on mobile. The base .ai-pop has min-width:220px
     and anchors to its (now narrow) control, so from a right-half control it
     ran off the right edge. Drop the min-width and re-anchor each dropdown to
     a full-width parent: control-bar dropdowns span the control row (opening
     below it) and composer popovers span the composer (opening above it), so
     they always sit inside the viewport. */
  #assistant-page .ai-pop { min-width: 0; max-width: calc(100vw - 32px); box-sizing: border-box; }
  #assistant-page .ai-ctrlbar { position: relative; }
  #assistant-page .ai-ctrlbar > .ai-ctrl-wrap { position: static; }
  #assistant-page .ai-ctrlbar .ai-pop { left: 0; right: 0; width: auto; max-width: none; }
  #assistant-page .ai-composer .ai-ctrl-wrap { position: static; }
  #assistant-page .ai-composer .ai-pop { left: 0; right: 0; width: auto; max-width: none; }
}

/* ── AI Chat History page (#/ai-history) — Slice H2 ───────────────────
   Minimal saved-chat list: title + date/time + favourite star + a
   per-row actions menu. Token-based so it tracks dark / light /
   atlas-blue; gold scrollbar matches the rest of the app. */
.ai-hist-wrap { max-width: 560px; }

.ai-hist-filters {
  display: inline-flex; gap: 2px; padding: 3px; margin: 0 auto 16px;
  border: 1px solid var(--border); border-radius: 999px;
}
.ai-hist-filter {
  background: transparent; border: 0; color: var(--t3);
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  letter-spacing: 0.08em; padding: 6px 16px; border-radius: 999px;
  cursor: pointer; transition: background .15s, color .15s;
}
.ai-hist-filter:hover { color: var(--gold-hi); }
.ai-hist-filter.is-active { background: rgba(200,168,78,0.14); color: var(--gold-hi); }

.ai-hist-notice {
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--gold-hi);
  background: rgba(200,168,78,0.10); border: 1px solid var(--gold-dim);
  border-radius: var(--radius); padding: 8px 12px; margin-bottom: 12px; text-align: center;
}
.ai-hist-notice[hidden] { display: none; }

.ai-hist-list {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 58vh; overflow-y: auto; padding: 2px; margin-bottom: 18px;
  scrollbar-width: thin; scrollbar-color: var(--gold) rgba(255,255,255,0.08);
}
.ai-hist-list::-webkit-scrollbar { width: 12px; }
.ai-hist-list::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); }
.ai-hist-list::-webkit-scrollbar-thumb { background: var(--gold); border-radius: 6px; border: 2px solid transparent; background-clip: padding-box; }
.ai-hist-list::-webkit-scrollbar-thumb:hover { background: var(--gold-hi); }

.ai-hist-empty {
  color: var(--t3); font-family: 'JetBrains Mono', monospace; font-size: 11px;
  text-align: center; padding: 28px 12px; line-height: 1.6;
}

.ai-hist-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: rgba(255,255,255,0.02);
}
.ai-hist-row-main { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ai-hist-star { color: var(--gold-hi); font-size: 12px; flex: none; }
.ai-hist-title {
  color: var(--t1); font-family: 'Cormorant Garamond', serif; font-size: 17px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ai-hist-row-side { display: flex; align-items: center; gap: 10px; flex: none; }
.ai-hist-date {
  color: var(--t3); font-family: 'JetBrains Mono', monospace; font-size: 9.5px;
  letter-spacing: 0.04em; white-space: nowrap;
}

.ai-hist-menu-wrap { position: relative; }
.ai-hist-menu-btn {
  width: 28px; height: 28px; border-radius: 7px; background: transparent;
  border: 1px solid var(--border); color: var(--t2); cursor: pointer;
  font-size: 14px; line-height: 1; transition: all .15s;
  display: inline-flex; align-items: center; justify-content: center;
}
.ai-hist-menu-btn:hover, .ai-hist-menu-btn.open { color: var(--gold-hi); border-color: rgba(200,168,78,0.5); }

.ai-hist-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 9000;
  min-width: 180px; padding: 6px;
  background: var(--bg-panel, rgba(20,18,34,0.98)); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 16px 48px rgba(0,0,0,0.5);
  display: flex; flex-direction: column; gap: 2px;
}
.ai-hist-menu[hidden] { display: none; }
.ai-hist-menu-item {
  text-align: left; background: transparent; border: 0; border-radius: 7px; color: var(--t1);
  font-family: 'JetBrains Mono', monospace; font-size: 11px; padding: 8px 10px;
  cursor: pointer; transition: background .12s, color .12s;
}
.ai-hist-menu-item:hover { background: rgba(200,168,78,0.10); color: var(--gold-hi); }
.ai-hist-danger { color: #e06a5e; }
.ai-hist-danger:hover { background: rgba(224,106,94,0.12); color: #e06a5e; }

@media (max-width: 640px) {
  .ai-hist-list { max-height: none; }
  .ai-hist-title { font-size: 16px; }
}

/* Panel header */
.panel-head {
  padding: 26px 26px 20px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  /* Subtle top glow — the only astro decoration on the panel */
  background: linear-gradient(180deg, rgba(200,168,78,0.04) 0%, transparent 100%);
}
.panel-head-row { display: flex; align-items: flex-start; justify-content: space-between; }
.panel-city {
  font-family: 'Cormorant Garamond', serif;
  font-size: 30px; font-weight: 400; line-height: 1.05; color: var(--t1);
  letter-spacing: 0.02em;
}
.panel-tag {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 10px;
  font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--gold-hi); border: 1px solid rgba(200,168,78,0.30);
  border-radius: 4px; padding: 4px 10px;
}
.panel-tag::before { content: '✦'; font-size: 9px; opacity: 0.75; }
.panel-meta { font-size: 10.5px; color: var(--t1); letter-spacing: .07em; margin-top: 9px; }

/* Selected-line inline row under meta */
.panel-line-row {
  display: flex; align-items: center; gap: 8px;
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--border);
}
.panel-line-lbl { font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: var(--t2); white-space: nowrap; }
#selected-line-name { font-size: 12px; color: var(--t1); font-weight: 500; }
#selected-line-type { font-size: 10px; color: var(--t2); margin-left: auto; white-space: nowrap; }

/* Close button */
.close-btn {
  width: 28px; height: 28px; flex-shrink: 0;
  border: 1px solid var(--border) !important; border-radius: 6px;
  background: transparent; color: var(--t3); font-size: 11px;
  display: flex; align-items: center; justify-content: center;
  transition: all .18s;
}
.close-btn:hover { border-color: var(--border-hi) !important; color: var(--t1); background: rgba(255,255,255,0.06); }

/* Panel scrollable body */
.panel-body {
  flex: 1; overflow-y: auto; padding: 22px 26px 40px;
  scrollbar-width: thin; scrollbar-color: var(--gold) rgba(255,255,255,0.08);
}
.panel-body::-webkit-scrollbar {
  width: 12px;
}
.panel-body::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.08);
}
.panel-body::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.panel-body::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}

/* Side-panel chart wheel — soft inset halo lifts the disc off the
   panel surface in every theme without requiring any change to the
   canvas paint. Margin is symmetric and a touch generous so the
   wheel reads as the panel's centrepiece, not crowded between rows. */
#chart-canvas {
  width: 84%; aspect-ratio: 1; display: block; margin: 6px auto 14px;
  border-radius: 50%;
  cursor: zoom-in;
  transition: filter .18s, transform .18s, box-shadow .18s;
  box-shadow:
    0 18px 40px rgba(0, 0, 0, 0.32),
    0 0 0 1px var(--border) inset,
    0 0 28px rgba(200, 168, 78, 0.05) inset;
}
#chart-canvas:hover { filter: brightness(1.06); }
html[data-theme="light"] #chart-canvas {
  box-shadow:
    0 14px 34px rgba(28, 24, 48, 0.10),
    0 0 0 1px rgba(28, 24, 48, 0.10) inset,
    0 0 24px rgba(168, 131, 58, 0.06) inset;
}
html[data-theme="light"] #chart-canvas:hover { filter: brightness(0.98); }
.chart-hint {
  text-align: center; font-size: 9px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--t3); margin-bottom: 24px;
  cursor: zoom-in; transition: color .18s;
}
.chart-hint:hover { color: var(--t2); }

/* Section blocks */
.block { margin-bottom: 26px; }
.block-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 13.5px; font-weight: 400; letter-spacing: .12em; text-transform: uppercase;
  color: var(--t1); padding-bottom: 10px; margin-bottom: 2px;
  border-bottom: 1px solid var(--border);
}

/* Data rows */
.drow {
  display: flex; align-items: center; justify-content: space-between;
  padding: 9px 0; border-bottom: 1px solid rgba(255,255,255,.05); font-size: 12px;
}
.drow:last-child { border-bottom: none; }
.dlabel { color: var(--t1); display: flex; align-items: center; gap: 9px; font-size: 12px; }
.glyph  { font-size: 16px; width: 19px; text-align: center; opacity: 0.95; color: var(--t1); }
.dval   { color: var(--t1); letter-spacing: 0.03em; font-size: 12px; }
.badge  {
  display: inline-block; padding: 4px 9px; margin-left: 4px;
  border: 1px solid rgba(200,168,78,0.36); border-radius: 4px;
  font-size: 11px; letter-spacing: .11em; color: var(--gold-hi);
  background: rgba(200,168,78,0.06);
  line-height: 1.1;
}
/* Sign glyph inside a badge — bumped up so the symbol reads
   clearly while the 3-letter abbreviation stays compact. */
.badge-sym {
  font-size: 15px;
  margin-right: 3px;
  vertical-align: -1px;
  color: var(--gold-hi);
}

/* All numbers in the panel use tabular figures so columns of
   degrees / house numbers line up no matter which digits appear. */
.dval, .house-val, .badge { font-variant-numeric: tabular-nums; }

/* Right-hand cluster on each Planets row: a fixed-width Position
   cell followed by a small House pill. Replaces the inline styles
   that were repeated on every row. */
.planet-vals {
  display: flex; align-items: center; gap: 14px;
}
.planet-vals .dval {
  min-width: 100px; text-align: right; white-space: nowrap;
}
.house-val {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 38px; padding: 3px 8px;
  border: 1px solid rgba(255,255,255,0.14); border-radius: 4px;
  font-size: 10.5px; color: var(--t1); letter-spacing: 0.05em;
  background: rgba(255,255,255,0.03);
}

/* Header row above the planet list — the column captions. */
.planet-head {
  padding: 4px 0 10px;
  font-size: 9px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--t3);
}
.planet-head .planet-vals span {
  display: inline-block; color: var(--t3);
}

/* Angular Houses: keep the four cardinal lines easy to scan.
   The (1st) / (10th) suffix is dropped to a quieter style so the
   eye lands on the Asc / MC / Dsc / IC name first, then the value. */
.angle-suffix {
  margin-left: 8px;
  font-size: 9px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--t3);
}
.angles-block .drow { padding: 9px 0; }
.angles-block .dval { white-space: nowrap; }


/* ── ASPECT MODE DROPDOWN ── */
/* Tiny premium checkboxes */
.asp-check-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 16px;
  cursor: pointer;
  transition: background .12s;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; color: #FFFFFF;
}
.asp-check-row:hover { background: rgba(255,255,255,0.06); }
.asp-checkbox {
  width: 13px; height: 13px; flex-shrink: 0;
  border: 1px solid rgba(255,255,255,0.30);
  border-radius: 2px;
  background: rgba(255,255,255,0.04);
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; color: var(--gold); line-height: 1;
  transition: border-color .15s, background .15s;
}
.asp-check-row.checked .asp-checkbox {
  border-color: var(--gold);
  background: rgba(200,168,78,0.18);
}
.asp-divider {
  height: 1px; background: rgba(255,255,255,0.08);
  margin: 3px 0;
}
/* BODY-1: small group label inside the desktop planet dropdown (always dark). */
.asp-section-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 8px; letter-spacing: .20em; text-transform: uppercase;
  color: rgba(255,255,255,0.45);
  padding: 5px 16px 3px;
}
/* AST-MAP-1: asteroid rows in the desktop dropdown. Own class so the
   planetMode handlers (scoped to .asp-check-row) never grab them; visuals
   mirror .asp-check-row, and the checkbox reuses .asp-checkbox. */
.ast-check-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 16px; cursor: pointer; transition: background .12s;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: #FFFFFF;
}
.ast-check-row:hover { background: rgba(255,255,255,0.06); }
.ast-check-row.checked .asp-checkbox {
  border-color: var(--gold); background: rgba(200,168,78,0.18);
}

/* ── FS-ANGLE-1: shared Fixed Stars selector (desktop dropdown + mobile sheet +
   Advanced Settings drawer). Built by wireFixedStarHost(). Base styling targets
   DARK surfaces (the portaled dropdown is always dark); light-theme overrides
   for the drawer (#advanced-drawer) + mobile (#mobile-menu) are below. Uses
   native <details>/<summary> for collapse (default-collapsed). */
.fs-host { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; }
.fs-section { border-top: 1px solid rgba(255,255,255,0.08); }
.fs-section > summary, .fs-group > summary { list-style: none; cursor: pointer; outline: none; }
.fs-section > summary::-webkit-details-marker,
.fs-group   > summary::-webkit-details-marker { display: none; }
.fs-section-head, .fs-group-head { display: flex; align-items: center; gap: 6px; }
.fs-section-head {
  padding: 8px 16px; color: rgba(255,255,255,0.92);
  font-size: 8.5px; letter-spacing: .14em; text-transform: uppercase;
}
.fs-section-head::before, .fs-group-head::before {
  content: '▸'; font-size: 8px; opacity: .6; flex-shrink: 0;
  transition: transform .12s;
}
.fs-section[open] > .fs-section-head::before,
.fs-group[open]   > .fs-group-head::before { transform: rotate(90deg); }
.fs-total { opacity: .6; }
.fs-body { padding-bottom: 4px; }
/* FS UX: hint explaining that selected Fixed Stars display via the Natal /
   Parans layers (replaces the removed per-mode toggles). */
.fs-hint {
  padding: 7px 16px 8px 26px;
  font-size: 11px; line-height: 1.35;
  color: rgba(255,255,255,0.55);
}
.fs-angle-toggle {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 16px 7px 26px; cursor: pointer; transition: background .12s;
  color: rgba(255,255,255,0.9);
}
.fs-angle-toggle:hover { background: rgba(255,255,255,0.06); }
/* FS-2 hotfix: toggle labels ("Show as planet-star parans" is long) wrap instead
   of clipping/forcing horizontal overflow on narrow surfaces. */
.fs-angle-label { flex: 1 1 auto; min-width: 0; line-height: 1.3; }
.fs-group-head {
  padding: 6px 16px 6px 26px; color: rgba(255,255,255,0.82);
  font-size: 10px; transition: background .12s; flex-wrap: wrap;
}
.fs-group-head:hover { background: rgba(255,255,255,0.05); }
/* FS-2 hotfix: let the group label take available width and WRAP rather than
   clip/overflow on narrow surfaces; count + Clear stay sized on the row. */
.fs-group-label { flex: 1 1 auto; min-width: 0; white-space: normal; line-height: 1.3; }
.fs-count { opacity: .55; flex-shrink: 0; }
.fs-clear {
  font-family: inherit; font-size: 8.5px; letter-spacing: .06em;
  padding: 2px 8px; cursor: pointer; flex-shrink: 0;
  color: var(--gold-hi); background: rgba(200,168,78,0.12);
  border: 1px solid rgba(200,168,78,0.35); border-radius: 4px;
}
.fs-clear:hover { background: rgba(200,168,78,0.24); border-color: var(--gold); }
.fs-stars { display: flex; flex-direction: column; }
.fs-star {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 16px 6px 38px; cursor: pointer; transition: background .12s;
  color: rgba(255,255,255,0.85);
}
.fs-star:hover { background: rgba(255,255,255,0.06); }
/* FS-2 hotfix: star names (incl. multi-word "Deneb Algedi") + the ✦ marker must
   never clip — wrap inside the row instead. */
.fs-star-name { flex: 1 1 auto; min-width: 0; white-space: normal; line-height: 1.35; }
.fs-box {
  width: 13px; height: 13px; flex-shrink: 0;
  border: 1px solid rgba(255,255,255,0.30); border-radius: 2px;
  background: rgba(255,255,255,0.04);
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; color: var(--gold); line-height: 1;
}
.fs-star.checked .fs-box, .fs-angle-toggle.on .fs-box {
  border-color: var(--gold); background: rgba(200,168,78,0.18);
}
/* Light-theme readability — ONLY in the drawer + mobile sheet (the portaled
   desktop dropdown is dark in every theme, so it keeps the light text above). */
html[data-theme="light"] #advanced-drawer .fs-section-head,
html[data-theme="light"] #advanced-drawer .fs-angle-toggle,
html[data-theme="light"] #advanced-drawer .fs-group-head,
html[data-theme="light"] #advanced-drawer .fs-star,
html[data-theme="light"] #mobile-menu .fs-section-head,
html[data-theme="light"] #mobile-menu .fs-angle-toggle,
html[data-theme="light"] #mobile-menu .fs-group-head,
html[data-theme="light"] #mobile-menu .fs-star { color: var(--t1); }
html[data-theme="light"] #advanced-drawer .fs-star:hover,
html[data-theme="light"] #advanced-drawer .fs-angle-toggle:hover,
html[data-theme="light"] #advanced-drawer .fs-group-head:hover,
html[data-theme="light"] #mobile-menu .fs-star:hover,
html[data-theme="light"] #mobile-menu .fs-angle-toggle:hover,
html[data-theme="light"] #mobile-menu .fs-group-head:hover { background: rgba(28,24,48,0.05); }
html[data-theme="light"] #advanced-drawer .fs-box,
html[data-theme="light"] #mobile-menu .fs-box {
  border-color: rgba(28,24,48,0.30); background: rgba(28,24,48,0.04);
}
html[data-theme="light"] #advanced-drawer .fs-section,
html[data-theme="light"] #mobile-menu .fs-section { border-top-color: rgba(28,24,48,0.10); }

.asp-ok-row {
  padding: 8px 16px 10px;
  display: flex; justify-content: flex-end;
  /* POLISH: pin Apply to the bottom so it stays reachable when the dropdown
     scrolls. Opaque background (matches the dropdown's bottom) + a faint top
     border separate it from the scrolling content above. */
  position: sticky; bottom: 0;
  background: rgba(6,8,16,0.98);
  border-top: 1px solid rgba(255,255,255,0.06);
}
.asp-ok-btn {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; letter-spacing: .10em;
  padding: 5px 16px; cursor: pointer;
  background: rgba(200,168,78,0.14);
  border: 1px solid rgba(200,168,78,0.40);
  border-radius: 4px; color: var(--gold-hi);
  transition: background .15s, border-color .15s;
}
.asp-ok-btn:hover { background: rgba(200,168,78,0.26); border-color: var(--gold); }


.aspect-mode-ctrl { position: relative; flex-shrink: 0; }
.aspect-mode-btn {
  height: 30px; padding: 0 11px;
  display: flex; align-items: center; gap: 6px;
  background: transparent;
  border: 1px solid transparent; border-radius: 6px;
  color: rgba(240,236,220,0.90);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: .04em;
  cursor: pointer; white-space: nowrap; transition: all .18s;
}
.aspect-mode-btn:hover { color: var(--gold-hi); background: rgba(200,168,78,0.08); border-color: rgba(200,168,78,0.20); }
.aspect-mode-btn.open  { color: var(--gold-hi); background: rgba(200,168,78,0.10); border-color: rgba(200,168,78,0.35); }
.aspect-mode-label { font-size: 8.5px; letter-spacing: .16em; text-transform: uppercase; color: rgba(200,168,78,0.85); }
.aspect-mode-chevron { opacity: .5; font-size: 6px; color: rgba(200,168,78,0.70); transition: transform .18s; }
.aspect-mode-btn.open .aspect-mode-chevron { transform: rotate(180deg); }
.aspect-mode-dropdown {
  /* Slice A6: position: fixed + body-portal (see .width-dropdown).
     Covers both Aspects (#aspect-mode-dropdown) and Planets
     (#planet-mode-dropdown) since both use this class. */
  display: none; position: fixed; top: calc(100% + 7px); left: 0;
  min-width: 210px; max-width: calc(100vw - 16px);
  /* POLISH: cap the height and scroll WITHIN the dropdown when content (e.g.
     expanded Asteroids / Fixed Stars sections) exceeds the viewport, so the
     menu never runs off-screen and the sticky Apply row stays reachable. A
     visible, site-styled (gold) scrollbar appears only when needed;
     scrollbar-gutter keeps the layout stable so content doesn't shift. */
  max-height: calc(100vh - 96px);
  background: linear-gradient(180deg, rgba(14,12,8,0.99), rgba(6,8,16,0.98));
  border: 1px solid rgba(200,168,78,0.28); border-radius: 10px;
  overflow-x: hidden; overflow-y: auto; z-index: 9000;
  scrollbar-width: thin; scrollbar-color: rgba(200,168,78,0.40) transparent;
  scrollbar-gutter: stable;
  box-shadow: 0 16px 48px rgba(0,0,0,0.7), 0 0 0 1px rgba(200,168,78,0.06) inset;
}
.aspect-mode-dropdown::-webkit-scrollbar { width: 10px; }
.aspect-mode-dropdown::-webkit-scrollbar-track { background: transparent; }
.aspect-mode-dropdown::-webkit-scrollbar-thumb {
  background: rgba(200,168,78,0.38); border-radius: 5px;
  border: 2px solid transparent; background-clip: padding-box;
}
.aspect-mode-dropdown::-webkit-scrollbar-thumb:hover {
  background: rgba(200,168,78,0.60); background-clip: padding-box;
}
.aspect-mode-dropdown.open { display: block; }
.aspect-mode-option {
  display: flex; align-items: center; justify-content: space-between;
  padding: 9px 16px;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: #FFFFFF;
  cursor: pointer; transition: background .12s; gap: 12px;
}
.aspect-mode-option:hover { background: rgba(200,168,78,0.08); color: var(--gold-hi); }
.aspect-mode-option.on { background: rgba(200,168,78,0.06); color: var(--gold-hi); }
.aspect-mode-option .check { opacity: 0; font-size: 9px; color: var(--gold); }
.aspect-mode-option.on .check { opacity: 1; }
.aspect-sym { font-size: 13px; width: 18px; text-align: center; opacity: 0.70; }

/* Planets dropdown has 13 options + Apply button → taller list.
   Cap height and allow vertical scrolling so it stays inside the viewport. */
#planet-mode-dropdown { max-height: min(75vh, 520px); overflow-y: auto; }

/* ── COLOR MODE DROPDOWN ── */
.color-mode-ctrl { position: relative; flex-shrink: 0; }
.color-mode-btn {
  height: 30px; padding: 0 11px;
  display: flex; align-items: center; gap: 6px;
  background: transparent;
  border: 1px solid transparent; border-radius: 6px;
  color: rgba(240,236,220,0.90);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: .04em;
  cursor: pointer; white-space: nowrap; transition: all .18s;
}
.color-mode-btn:hover { color: var(--gold-hi); background: rgba(200,168,78,0.08); border-color: rgba(200,168,78,0.20); }
.color-mode-btn.open  { color: var(--gold-hi); background: rgba(200,168,78,0.10); border-color: rgba(200,168,78,0.35); }
.color-mode-label { font-size: 8.5px; letter-spacing: .16em; text-transform: uppercase; color: rgba(200,168,78,0.85); }
.color-mode-chevron { opacity: .5; font-size: 6px; color: rgba(200,168,78,0.70); transition: transform .18s; }
.color-mode-btn.open .color-mode-chevron { transform: rotate(180deg); }
.color-mode-dropdown {
  /* Slice A6: position: fixed + body-portal (see .width-dropdown). */
  display: none; position: fixed; top: calc(100% + 7px); left: 0;
  min-width: 160px; max-width: calc(100vw - 16px);
  background: linear-gradient(180deg, rgba(14,12,8,0.99), rgba(6,8,16,0.98));
  border: 1px solid rgba(200,168,78,0.28); border-radius: 10px;
  overflow: hidden; z-index: 9000;
  box-shadow: 0 16px 48px rgba(0,0,0,0.7), 0 0 0 1px rgba(200,168,78,0.06) inset;
}
.color-mode-dropdown.open { display: block; }
.color-mode-option {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 16px;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: #FFFFFF;
  cursor: pointer; transition: background .12s; gap: 16px;
}
.color-mode-option:hover { background: rgba(200,168,78,0.08); color: var(--gold-hi); }
.color-mode-option.on { color: var(--gold-hi); background: rgba(200,168,78,0.06); }
.color-mode-option .check { opacity: 0; font-size: 9px; color: var(--gold); }
.color-mode-option.on .check { opacity: 1; }

/* Light theme — quick-settings dropdown contrast (C1-B). The four
   toolbar dropdowns (Planets + Aspects share .aspect-mode-dropdown,
   plus Color Mode and Line Width) are hardcoded DARK panels that get
   body-portaled over the light map (Slice A6), but their Apply /
   active / check / hover states read the gold theme tokens, which the
   light theme darkens for cream surfaces — dark gold on a near-black
   panel was barely visible (the Apply button especially). Re-pin the
   gold tokens to their dark-theme values on these dark islands, the
   same pattern .auth-shell-nav / #front-page .fp-nav use. Dark and
   Atlas are untouched (light-scoped). */
html[data-theme="light"] .aspect-mode-dropdown,
html[data-theme="light"] .color-mode-dropdown,
html[data-theme="light"] .width-dropdown {
  --gold:     #C8A84E;
  --gold-hi:  #F5D060;
  --gold-dim: rgba(200, 168, 78, 0.18);
}
/* Layer button line-style SVG previews */
.layer-btn .lstyle { flex-shrink: 0; }

/* ── RESET MAP BUTTON ── */
.reset-map-btn {
  height: 30px; padding: 0 11px;
  display: flex; align-items: center; gap: 5px;
  background: transparent;
  border: 1px solid transparent; border-radius: 6px;
  color: rgba(200,168,78,0.80);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: .08em; white-space: nowrap;
  cursor: pointer; flex-shrink: 0;
  transition: all .18s;
}
.reset-map-btn:hover {
  color: var(--gold-hi);
  background: rgba(200,168,78,0.08);
  border-color: rgba(200,168,78,0.25);
}
.reset-map-btn .reset-icon { font-size: 11px; opacity: 0.80; }

/* Slice C5: subtle group separator between Reset and the toolbar
   Chart button, reusing the same 1px gold-gradient vocabulary as
   .h-div so it matches the dividers used between Planets/Aspects/etc.
   Pseudo-element keeps the button's padding symmetric and avoids any
   app.html change. Scoped to the desktop toolbar id only; the mobile
   menu button (#mm-current-chart-btn) is unaffected, and the entire
   .header-center is display:none on mobile anyway. */
#current-chart-btn {
  position: relative;
  margin-left: 7px;
}
#current-chart-btn::before {
  content: "";
  position: absolute;
  left: -4px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 18px;
  background: linear-gradient(180deg, transparent, rgba(200,168,78,0.50), transparent);
  pointer-events: none;
}

/* ── CLEAR LINE X BUTTON ── */
#clear-line-btn {
  width: 18px; height: 18px; flex-shrink: 0;
  display: none; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--border); border-radius: 4px;
  color: var(--t2); font-size: 9px; line-height: 1;
  cursor: pointer; transition: all .15s; margin-left: 6px;
}
#clear-line-btn:hover { background: rgba(255,255,255,0.14); color: var(--t1); border-color: var(--border-hi); }
#clear-line-btn.visible { display: flex; }

/* Score bars */
.score-drow { flex-direction: column; align-items: stretch; gap: 7px; }
.score-top  { display: flex; justify-content: space-between; font-size: 10.5px; }
.score-key  { color: var(--t1); }
.bar-track  { height: 2px; background: rgba(255,255,255,.07); border-radius: 2px; }
.bar-fill   { height: 100%; border-radius: 2px; opacity: 0.75; transition: width 1.1s cubic-bezier(.4,0,.2,1); }

/* Selected-line highlight on the map — subtle gold glow via CSS on the Leaflet path */
.leaflet-interactive.selected-line {
  filter: drop-shadow(0 0 4px currentColor);
}

/* ══════════════════════════════════════════════════════════
   MOBILE RESPONSIVE  (≤ 640px)
   Strategy:
     - Front page  : scale logo with clamp(), shrink spacing
     - Map header  : show logo + ☰ hamburger; hide center pill
     - Mobile menu : full-width drawer below header with all controls
     - Side panel  : full-width on mobile
     - Frame strips: narrower (60px) to save vertical space
══════════════════════════════════════════════════════════ */

/* ── Mobile settings button (hidden on desktop, shown on mobile) ── */
#mobile-menu-btn {
  display: none;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: transparent; color: #D8D6E4;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: .08em; white-space: nowrap;
  align-items: center; justify-content: center;
  cursor: pointer; flex-shrink: 0;
  transition: border-color .18s, background .18s, color .18s;
}
#mobile-menu-btn.open {
  border-color: var(--gold); background: rgba(200,168,78,0.10); color: var(--gold-hi);
}

/* ── Mobile account-menu trigger ("Menu") — sole right-side header
       button on phones. Hidden on desktop. Map Settings now lives
       inside the popover this trigger opens, not as a sibling button. */
#mobile-account-btn {
  display: none;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: transparent; color: #D8D6E4;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: .08em; white-space: nowrap;
  align-items: center; justify-content: center;
  cursor: pointer; flex-shrink: 0;
  transition: border-color .18s, background .18s, color .18s;
}
#mobile-account-btn.open {
  border-color: var(--gold); background: rgba(200,168,78,0.10); color: var(--gold-hi);
}

/* ── Mobile settings panel — full-screen scrollable overlay ──
   Uses overflow-y:auto on the INNER div only.
   No floating dropdowns: all options are inline (no clipping). */
#mobile-menu {
  display: none;
  position: fixed;
  top: var(--header-h); left: 0; right: 0; bottom: 0;
  background: var(--bg-panel);
  backdrop-filter: blur(40px);
  z-index: 490;
  overflow: hidden; /* inner div scrolls */
}
#mobile-menu.open { display: block; }
#mobile-menu-inner {
  height: 100%; overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px 0 40px;
  display: flex; flex-direction: column;
}

/* Section heading */
.mm-section-title {
  font-size: 8px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--t3); padding: 14px 20px 6px;
}
/* BODY-1: sub-group label inside the mobile body list (container already pads
   20px horizontally, so this only needs vertical spacing). */
.mm-body-subhead {
  font-size: 8px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--t3); padding: 8px 0 4px;
}
.mm-divider { height: 1px; background: var(--border); margin: 6px 0; }

/* ── Layers ── */
.mm-layers {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 6px; padding: 0 20px;
}
.mm-layer-btn {
  display: flex; align-items: center; gap: 6px;
  padding: 10px 12px; height: auto; min-height: 40px;
  border: 1px solid transparent; border-radius: 6px;
  background: transparent; color: #D8D6E4;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: .03em;
  cursor: pointer; transition: all .18s;
  -webkit-tap-highlight-color: transparent;
}
.mm-layer-btn.on {
  color: #FFF; border-color: var(--border-hi);
  background: rgba(255,255,255,0.10);
}
.mm-layer-btn .lstyle { opacity: 0.4; flex-shrink: 0; }
.mm-layer-btn.on .lstyle { opacity: 1; }

/* ── Inline option lists (aspects, color, width) ──
   These REPLACE floating dropdowns. Options always visible. */
.mm-option-list {
  display: flex; flex-direction: column; padding: 0 20px; gap: 2px;
}
.mm-option {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 14px; border-radius: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #D8D6E4;
  cursor: pointer; transition: background .12s;
  -webkit-tap-highlight-color: transparent;
}
.mm-option:hover, .mm-option:active { background: rgba(255,255,255,0.06); }
.mm-option.on { background: rgba(255,255,255,0.08); color: #FFF; }
.mm-option-check { font-size: 10px; color: var(--gold); opacity: 0; }
.mm-option.on .mm-option-check { opacity: 1; }

/* Aspect checkboxes (multi-select) */
.mm-asp-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #D8D6E4;
  cursor: pointer; transition: background .12s;
  -webkit-tap-highlight-color: transparent;
}
.mm-asp-row:active { background: rgba(255,255,255,0.06); }
.mm-asp-box {
  width: 16px; height: 16px; flex-shrink: 0;
  border: 1px solid rgba(255,255,255,0.25); border-radius: 3px;
  background: rgba(255,255,255,0.04);
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; color: var(--gold);
}
.mm-asp-row.checked .mm-asp-box {
  border-color: var(--gold); background: rgba(200,168,78,0.18);
}
/* AST-MAP-1: mobile asteroid rows. Own class (planetMode handlers are scoped to
   .mm-asp-row), visuals mirror .mm-asp-row; the box reuses .mm-asp-box. */
.mm-ast-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #D8D6E4;
  cursor: pointer; transition: background .12s;
  -webkit-tap-highlight-color: transparent;
}
.mm-ast-row:active { background: rgba(255,255,255,0.06); }
.mm-ast-row.checked .mm-asp-box {
  border-color: var(--gold); background: rgba(200,168,78,0.18);
}
html[data-theme="light"] .mm-ast-row { color: var(--t1); }
html[data-theme="light"] .mm-ast-row:active { background: rgba(28, 24, 48, 0.05); }

/* ── Light theme — mobile Map Settings menu (#mobile-menu) contrast fix ──
   The base .mm-* rules above hardcode light text (#D8D6E4 / #FFF) and
   white-alpha overlays built for the dark panel; on the cream light-theme
   panel they read as near-invisible. These overrides remap them onto the
   light-theme ink variables (--t1 / --t2) and ink-alpha overlays so the
   menu is as readable as the Advanced Settings drawer. Light theme ONLY —
   Dark (:root) and Atlas are dark surfaces and are left untouched.
   The gold check/active states (var(--gold), .mm-option-check, checked
   .mm-asp-box) already adapt via the theme variable, so they are kept. */
html[data-theme="light"] .mm-section-title { color: var(--t2); }
html[data-theme="light"] .mm-layer-btn { color: var(--t1); }
html[data-theme="light"] .mm-layer-btn.on {
  color: var(--t1); background: rgba(28, 24, 48, 0.08);
}
html[data-theme="light"] .mm-option { color: var(--t1); }
html[data-theme="light"] .mm-option:hover,
html[data-theme="light"] .mm-option:active { background: rgba(28, 24, 48, 0.05); }
html[data-theme="light"] .mm-option.on {
  color: var(--t1); background: rgba(28, 24, 48, 0.07);
}
html[data-theme="light"] .mm-asp-row { color: var(--t1); }
html[data-theme="light"] .mm-asp-row:active { background: rgba(28, 24, 48, 0.05); }
html[data-theme="light"] .mm-asp-box {
  border-color: rgba(28, 24, 48, 0.30);
  background: rgba(28, 24, 48, 0.04);
}

/* ── Geo search trigger ── */
.mm-geo-trigger {
  margin: 0 20px;
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.04);
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #D8D6E4;
  cursor: pointer; transition: border-color .18s;
}
.mm-geo-trigger:active { border-color: rgba(200,168,78,0.50); }
#mm-geo-chosen { color: var(--t3); }

/* Reset button inline */
.mm-reset-btn {
  width: calc(100% - 40px);
  margin: 6px 20px 0;
  min-height: 42px;
  height: auto;
  padding: 0 14px;
  border-radius: var(--radius);
  border: 1px solid rgba(200,168,78,0.28);
  background: rgba(255,255,255,0.045);
  color: #D8D6E4; font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  cursor: pointer; display: flex; align-items: center; justify-content: flex-start; gap: 8px;
  transition: border-color .18s, background .18s, color .18s;
}
.mm-reset-btn:active {
  color: var(--gold-hi);
  border-color: rgba(200,168,78,0.55);
  background: rgba(200,168,78,0.10);
}
.mm-reset-btn span { flex: 0 0 auto; opacity: 0.82; }
.mm-chart-action-btn {
  color: var(--gold-hi);
  border-color: rgba(200,168,78,0.42);
  background: linear-gradient(135deg, rgba(200,168,78,0.14), rgba(200,168,78,0.06));
}

/* Global action buttons row */
.mm-close-row {
  padding: 20px 20px 0;
  display: flex; flex-direction: column; gap: 8px;
}
.mm-apply-btn {
  width: 100%; height: 44px; border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(200,168,78,0.22), rgba(200,168,78,0.12));
  border: 1px solid rgba(200,168,78,0.50);
  color: var(--gold-hi); font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
  cursor: pointer; transition: all .18s;
}
.mm-apply-btn:active { background: rgba(200,168,78,0.35); }
.mm-close-btn {
  width: 100%; height: 40px; border-radius: var(--radius);
  border: 1px solid var(--border); background: transparent;
  color: var(--t3); font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
  cursor: pointer; transition: all .18s;
}
.mm-close-btn:active { background: rgba(255,255,255,0.04); }

/* ── Geo Search Modal ──
   Full-screen modal above the settings panel for easy location entry */
#mm-geo-modal {
  display: none;
  position: fixed; inset: 0; z-index: 600;
  background: var(--bg-panel);
  flex-direction: column;
}
#mm-geo-modal.open { display: flex; }
.mm-geo-modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
#mm-geo-modal-input {
  flex: 1; height: 40px; padding: 0 14px;
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--border-hi); border-radius: var(--radius);
  color: #FFF; font-family: 'JetBrains Mono', monospace;
  font-size: 12px; outline: none;
}
.mm-geo-modal-cancel {
  height: 40px; padding: 0 16px; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: transparent; color: var(--t2);
  font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .08em;
  cursor: pointer; white-space: nowrap;
}
.mm-geo-modal-results {
  flex: 1; overflow-y: auto;
  padding: 8px 0;
}

@media (max-width: 640px) {

  /* ── Design token overrides ── */
  :root {
    --header-h:  56px;
    --strip-h:   60px;
    --strip-w:   64px;   /* widened from 14px so left/right label clusters
                            (glyph @14, aspect @26, type @37, stem to 44)
                            sit inside the gutter instead of overlapping
                            the map. 64px = cluster width + a 20-px stem. */
    --label-gap: 22px;   /* min spacing between adjacent frame labels —
                            wider than desktop's 14px so the AC/DC text
                            row (~13px wide w/ letter-spacing) and 12-px
                            glyphs don't visually collide on small phones. */
    --panel-w:   100vw;  /* side panel goes full-width on mobile */
  }

  /* ── Front page ── */
  .fp-rule { height: 28px; margin-bottom: 18px; }

  /* Reduce front page side padding on mobile */
  #front-page { padding-left: 12px; padding-right: 12px; }

  /* Higher specificity (#front-page .fp-logo) beats the desktop
     .fp-logo rule which comes later in the cascade.
     letter-spacing !important ensures 0.38em desktop value is
     fully overridden. Font size is capped so text fits any phone. */
  #front-page .fp-logo {
    font-size: clamp(28px, 7.5vw, 42px) !important;
    letter-spacing: 0 !important;
    gap: 10px !important;
    margin-bottom: 4px;
    width: 100%;
    justify-content: center;
  }
  #front-page .fp-logo-star { font-size: clamp(26px, 7vw, 40px) !important; }

  .fp-tagline { font-size: 8px; margin-bottom: 20px; }

  .fp-headline {
    font-size: clamp(16px, 5vw, 24px);
    margin-bottom: 10px;
  }

  .fp-desc {
    font-size: 10px; line-height: 1.65;
    margin-bottom: 28px;
  }

  .fp-form { gap: 12px; }

  /* Stack date and time vertically on narrow screens */
  .fp-row { grid-template-columns: 1fr; gap: 12px; }

  .fp-btn { height: 44px; font-size: 10px; }

  /* ── Map header ── */
  /* Hide desktop center pill + right icons */
  /* Hide desktop center pill; right col handled below */
  .header-center { display: none; }

  /* Standalone "Map Settings" header button is replaced by the
     "Map Settings" entry inside the mobile account-menu. The button
     stays in the DOM (so its click handler in app.js doesn't error)
     but is no longer rendered — the lone "Menu" trigger reads
     cleaner on a phone-width header. */
  #mobile-menu-btn { display: none; }
  /* Show the mobile account-menu trigger ("Menu") — sole right-side
     header button on phones. */
  #mobile-account-btn { display: flex; }
  /* Hide desktop icon buttons individually — header-right stays in grid flow */
  .header-right .icon-btn { display: none; }

  /* Logo area — compact */
  .header-left {
    align-items: flex-start;
  }
  .logo { font-size: 17px; letter-spacing: 0.22em; }
  .logo-star { font-size: 17px; }

  /* Header grid: logo left | center hidden | settings btn right */
  #header {
    grid-template-columns: 1fr 0 auto;
    padding: 0 14px;
    gap: 0;
  }

  /* ── Map & frame ── */
  /* Status bar compact */
  #statusbar { font-size: 9px; padding: 5px 10px; left: 8px; }
  #click-hint { font-size: 9px; padding: 5px 12px; }

  /* ── Side panel — full width ── */
  #panel {
    width: 100vw;
    top: var(--header-h);
  }
  /* Panel opens as overlay — don't shrink the map */
  #map.shrunk { right: 0; }
  .frame-strip.shrunk { right: 0; }
  #frame-right.shrunk { right: 0; }
  #frame-svg.shrunk { right: 0; }

  /* ── Mobile menu controls sizing ── */
  .aspect-mode-dropdown,
  .color-mode-dropdown,
  .width-dropdown {
    /* Inside the mobile menu these open upward to avoid going offscreen */
    top: auto; bottom: calc(100% + 7px);
  }
}

/* ══════════════════════════════════════════════════════════
   FRONT PAGE
══════════════════════════════════════════════════════════ */
#front-page {
  position: fixed; inset: 0; z-index: 2000;
  background: var(--bg);
  /* Warm gold wash at the top, deep violet haze near the bottom —
     the "dusk sky" feel the reference used to frame the hero. */
  background-image:
    radial-gradient(ellipse 80% 50% at 50% 0%,
      rgba(200,168,78,0.08) 0%, transparent 62%),
    radial-gradient(ellipse 60% 50% at 50% 100%,
      rgba(48,34,92,0.22) 0%, transparent 72%);
  /* Flex column (not grid) is deliberate: the map-page logo
     handler restores this panel with an INLINE
     `style.display = 'flex'`, which beats any stylesheet rule.
     Matching the stylesheet layout to flex-column means the
     inline value is a no-op instead of an override, so the
     layout stays stable across hide → reveal cycles. */
  display: flex;
  flex-direction: column;
  /* Vertical scrolling for the hero + landing sections. overflow-y:scroll
     (not auto) + scrollbar-gutter:stable keeps a visible, stable scroll
     affordance now that the page is taller than the hero — mirrors the
     .adv-body / Charts+Account auth-page gold scrollbar treatment. X is
     clipped so the decorative backdrop layers never leak. */
  overflow-x: hidden;
  overflow-y: scroll;
  scrollbar-gutter: stable;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scrollbar-width: auto;
  scrollbar-color: var(--gold) rgba(255,255,255,0.08);
  padding: 0;
  transition: opacity .55s ease, visibility .55s ease;
}
/* Visible gold scrollbar on the front page. Wider + solid-gold thumb on a
   subtly visible track so the scroll affordance reads clearly (the previous
   --gold-dim thumb at 0.18 alpha was too faint). Scoped to #front-page only,
   so .adv-body / Charts / Account / global scrollbars are unaffected. */
#front-page::-webkit-scrollbar { width: 14px; }
#front-page::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); }
#front-page::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 7px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
#front-page::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}
/* Light mode: --gold / --gold-dim read pale on the cream surface, so use an
   explicit dark gold/brown thumb + slightly darker track. #front-page only. */
html[data-theme="light"] #front-page {
  scrollbar-color: rgba(138,105,32,0.95) rgba(0,0,0,0.08);
}
html[data-theme="light"] #front-page::-webkit-scrollbar-track {
  background: rgba(0,0,0,0.08);
}
html[data-theme="light"] #front-page::-webkit-scrollbar-thumb {
  background: rgba(138,105,32,0.92);
}
html[data-theme="light"] #front-page::-webkit-scrollbar-thumb:hover {
  background: rgba(138,105,32,1);
}
#front-page.hidden { opacity: 0; visibility: hidden; pointer-events: none; }

/* Decorative top rule — hidden globally now that .fp-logo is symbol-only
   on the 9 auth/settings surfaces. The rule was an accent for a text
   wordmark; with the logo reduced to ✦ glyph only, the rule rendered
   inconsistently (visible on most pages, perceptually overpowered by
   busy section content on Account). Hiding everywhere keeps the rule
   + ✦ treatment consistent across pages. */
.fp-rule {
  width: 1px; height: 44px;
  background: linear-gradient(to bottom, transparent, rgba(200,168,78,0.35));
  margin-bottom: 28px;
  display: none;
}

/* Logo: symbol-only on auth/settings pages. The previous letter-spacing
   came from when this carried a wordmark; with a single ✦ it added
   trailing pad inside the span and shifted the visible glyph left of
   .fp-rule's page-centered axis. width:100% + justify-content:center
   guarantees the glyph sits on the same center as the rule line. */
.fp-logo {
  font-family: 'Cormorant Garamond', serif;
  font-size: 42px; font-weight: 600;
  color: var(--gold-hi);
  display: flex; align-items: center; justify-content: center; gap: 12px;
  width: 100%;
  margin-bottom: 6px;
}
.fp-logo-star { font-size: 40px; color: var(--gold-hi); }

/* Shared brand-symbol mark — replaces the old ✦ glyph beside the
   "ASTRO RELOCATION AI" wordmark across every header/logo surface.
   Sized in 1em so it inherits each spot's existing font-size, and drawn
   with currentColor so it picks up the existing gold token per theme
   (dark / light / atlas-blue). Used as inline <svg> + <use href="#brand-symbol">. */
.brand-symbol {
  width: 1em; height: 1em;
  display: inline-block; flex: none;
  vertical-align: -0.14em;
}

/* Tagline */
.fp-tagline {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px; letter-spacing: .28em; text-transform: uppercase;
  color: var(--t3); margin-bottom: 36px;
}

/* Headline */
.fp-headline {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(20px, 2.8vw, 30px);
  font-weight: 300; letter-spacing: 0.04em;
  color: var(--t1); text-align: center; line-height: 1.22;
  margin-bottom: 14px; max-width: 560px;
}

/* Description */
.fp-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: .06em; line-height: 1.85;
  color: var(--t3); text-align: center;
  max-width: 400px; margin-bottom: 44px;
}

/* Form card */
.fp-form {
  width: 100%; max-width: 440px;
  display: flex; flex-direction: column; gap: 14px;
}

/* Row of two inputs side by side */
.fp-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
}

/* Field wrapper */
.fp-field {
  display: flex; flex-direction: column; gap: 5px;
  /* UI Bugfix — let grid items shrink below the input's
     intrinsic min-width (`<input>` defaults to size=20 →
     ~150-180px in monospace). Without this, narrow columns
     force the rightmost input to overflow its grid cell. */
  min-width: 0;
}

/* Slice L2.1 — restore the HTML `hidden` attribute on form rows.
   The selectors above set explicit `display: flex / grid`, which
   wins on specificity over the user-agent's `[hidden] { display:
   none }` rule. Without this override the L2 coordinates toggle
   could not hide the place field. Specificity here is (0,1,1) so
   it beats the plain `.fp-field` / `.fp-row` rules. Scoped to
   the form-row classes so no other `[hidden]` consumer is affected.
   L2.2 — added `.charts-save-row[hidden]` for the Charts-page
   create / edit form, which wraps inputs in `.charts-save-row`
   instead of `.fp-field`. */
.fp-field[hidden],
.fp-row[hidden],
.charts-save-row[hidden] {
  display: none;
}

/* UI Bugfix — stack narrow-card .fp-row pairs (signup
   first-chart, Charts-page Edit form, Current Chart modal) at
   tablet-portrait and below. These surfaces sit inside cards
   capped at max-width: 460px via `.auth-form` / modal width,
   so a 2-column layout yields ~206px-wide columns — too
   narrow for the input's intrinsic min-width AND for the
   "Birth time (optional)" label to fit on one line. Front-
   page form (no .auth-form / .cc-form ancestor) is excluded
   and keeps its existing layout. Higher specificity than the
   global `.fp-row { 1fr 1fr }` rule below — wins regardless
   of cascade order. 820px matches the existing front-page
   hero breakpoint at ~3793 for codebase consistency. */
@media (max-width: 820px) {
  .auth-form .fp-row,
  .cc-form .fp-row {
    grid-template-columns: 1fr;
  }
}
.fp-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: .20em; text-transform: uppercase;
  color: var(--gold-hi);
  opacity: 0.85;
}
.fp-input {
  height: 40px; padding: 0 14px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: #FFFFFF;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px; letter-spacing: .04em;
  outline: none;
  transition: border-color .18s, background .18s;
  -webkit-appearance: none; appearance: none;
  color-scheme: dark;
  /* UI Bugfix — single-control rows on Charts-page create/edit
     wrap the input in .charts-save-row (block div) rather than
     .fp-field (flex-column with align-items: stretch). Block
     parents don't stretch their inline-block children, so the
     input would sit at its default size=20 content width on
     those rows. width: 100% with the global box-sizing: border-
     box keeps the input inside its container; it's a no-op for
     inputs already stretched via .fp-field flex or .fp-row
     grid cells. */
  width: 100%;
}
.fp-input::placeholder { color: var(--t4); }
.fp-input:focus {
  border-color: rgba(200,168,78,0.50);
  background: rgba(200,168,78,0.05);
}

/* CTA button */
.fp-btn {
  margin-top: 6px;
  height: 48px; border-radius: var(--radius);
  background: linear-gradient(135deg,
    rgba(200,168,78,0.18) 0%, rgba(200,168,78,0.10) 100%);
  border: 1px solid rgba(200,168,78,0.45);
  color: var(--gold-hi);
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  cursor: pointer; transition: all .22s;
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.fp-btn:hover {
  background: linear-gradient(135deg,
    rgba(200,168,78,0.30) 0%, rgba(200,168,78,0.18) 100%);
  border-color: rgba(200,168,78,0.75);
  color: #F5D060;
  box-shadow: 0 0 28px rgba(200,168,78,0.14);
}
.fp-btn-arrow { opacity: 0.65; font-size: 14px; }

/* Slice L2 — manual coordinates fallback. The toggle button sits
   under the place field (or lat/lng row when active) and switches
   the birth form between place-text mode and manual-coords mode.
   Styled as a subtle inline link so it disappears into the form
   chrome — the place-text path remains the visual default. The
   .fp-msg slot pairs with the front-page form to surface inline
   validation errors (the Current Chart modal already has its own
   .auth-msg slot). */
.fp-coords-toggle {
  margin: -2px 0 6px;
  text-align: left;
}
.fp-coords-toggle-link {
  background: none;
  border: none;
  /* Slice L2.1 — was var(--gold-dim) (rgba(200,168,78,0.18) — a
     borders token, far too low contrast for text). Switch to
     --t2 for a comfortable, readable default; hover stays gold. */
  color: var(--t2);
  cursor: pointer;
  font-size: 12px;
  letter-spacing: 0.04em;
  padding: 4px 0;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color .18s;
}
.fp-coords-toggle-link:hover,
.fp-coords-toggle-link:focus-visible {
  color: var(--gold-hi);
  outline: none;
}
.fp-msg {
  color: var(--gold-hi);
  font-size: 12px;
  letter-spacing: 0.02em;
  min-height: 1em;
  padding: 4px 0;
}
.fp-msg:empty {
  min-height: 0;
  padding: 0;
}

/* Slice L6 — city autocomplete dropdown. The list is absolutely
   positioned under the place-input within its *-place-field
   wrapper; the wrapper gets position:relative so the list
   anchors correctly. Visual language matches .fp-input
   (dark panel, faint border) with gold accent on the active
   row. Mobile breakpoint raises the row height for touch. */
#fp-place-field,
#cc-place-field,
#create-chart-place-field,
#signup-chart-place-field {
  position: relative;
}
.autocomplete-list {
  position: absolute;
  left: 0; right: 0;
  top: 100%;
  margin-top: 4px;
  max-height: 280px;
  overflow-y: auto;
  background: #14131A;
  border: 1px solid var(--border-hi);
  border-radius: var(--radius);
  box-shadow: 0 12px 28px rgba(0,0,0,0.45);
  list-style: none;
  padding: 4px 0;
  z-index: 50;
}
.autocomplete-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 14px;
  cursor: pointer;
  color: var(--t1);
  font-family: 'JetBrains Mono', monospace;
  transition: background .12s;
}
.autocomplete-item:hover,
.autocomplete-item.is-active {
  background: rgba(200,168,78,0.10);
}
.autocomplete-item-main {
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--t1);
}
.autocomplete-item-meta {
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--t3);
}
.autocomplete-item.is-active .autocomplete-item-main {
  color: var(--gold-hi);
}
@media (max-width: 768px) {
  .autocomplete-item {
    padding: 12px 14px;
  }
  .autocomplete-item-main {
    font-size: 13px;
  }
}

/* Slice L7.1 — light-theme overrides for the autocomplete dropdown.
   The base rules above hardcode a dark panel that suits the dark +
   atlas-blue themes. In the cream-palette light theme the dark
   panel + light text inverted the rest of the UI, making city
   suggestions hard to read. Mirror the existing light-theme
   override pattern used by .fp-input and .tile-carto. Atlas-blue
   inherits the dark-theme rules (no override needed). */
html[data-theme="light"] .autocomplete-list {
  background: rgba(253, 248, 234, 0.98);
  border-color: rgba(28, 24, 48, 0.28);
  box-shadow: 0 12px 28px rgba(28, 24, 48, 0.18);
}
html[data-theme="light"] .autocomplete-item {
  color: var(--t1);
}
html[data-theme="light"] .autocomplete-item-main {
  color: var(--t1);
}
html[data-theme="light"] .autocomplete-item-meta {
  color: var(--t3);
}
html[data-theme="light"] .autocomplete-item:hover,
html[data-theme="light"] .autocomplete-item.is-active {
  background: rgba(168, 131, 58, 0.10);
}
html[data-theme="light"] .autocomplete-item.is-active .autocomplete-item-main {
  color: var(--gold-hi);
}

/* ── EXPANDED CHART MODAL ──────────────────────────────────────
   Centered overlay opened by clicking the small chart wheel in
   the side panel. Same dark/gold visual language as the rest of
   the app — just bigger so the relocation details can breathe. */
#chart-modal {
  position: fixed; inset: 0; z-index: 9999;
  display: none; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .22s ease;
}
#chart-modal.open { display: flex; opacity: 1; }
.chart-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(4, 6, 14, 0.78);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  cursor: zoom-out;
}
.chart-modal-frame {
  position: relative;
  /* Frame is forced tall (height: 92vh) so the stage always has
     plenty of vertical room for a large wheel. Width tracks the
     viewport's smaller side, capped at 920px on big screens. */
  width: min(92vmin, 920px);
  height: 92vh;
  max-height: 92vh;
  background: var(--bg-panel);
  border: 1px solid var(--gold-dim);
  border-radius: 14px;
  box-shadow:
    0 36px 110px rgba(0,0,0,0.55),
    0 0 90px rgba(200,168,78,0.07),
    0 0 0 1px var(--border) inset;
  display: flex; flex-direction: column;
  overflow: hidden;
}
html[data-theme="light"] .chart-modal-frame {
  box-shadow:
    0 30px 90px rgba(28, 24, 48, 0.18),
    0 0 60px rgba(168, 131, 58, 0.08),
    0 0 0 1px rgba(28, 24, 48, 0.06) inset;
}
.chart-modal-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  padding: 16px 24px 14px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, rgba(200,168,78,0.06) 0%, transparent 100%);
}
.chart-modal-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 19px; font-weight: 400; letter-spacing: 0.04em;
  color: var(--t1);
}
.chart-modal-sub {
  margin-top: 4px;
  font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--t3);
}
.chart-modal-close {
  width: 34px; height: 34px;
  background: transparent; color: var(--t2);
  border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px;
  display: flex; align-items: center; justify-content: center;
  transition: color .18s, border-color .18s, background .18s;
}
.chart-modal-close:hover {
  color: var(--t1); border-color: var(--border-hi);
  background: rgba(255,255,255,0.06);
}
html[data-theme="light"] .chart-modal-close:hover {
  background: rgba(28, 24, 48, 0.05);
}
.chart-modal-stage {
  /* Phase D Slice 2 (refinement v3.1): min-height: 92 % gives the
     wheel a slightly smaller footprint than v3 (R ≈ 370 vs ≈ 404
     on a typical desktop) and leaves ~70 px of the Positions
     section visible above the fold so users see there is more
     content below to scroll to. */
  flex: 0 0 auto;
  height: 92%;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 18px 22px 22px;
  overflow: hidden;
  background:
    radial-gradient(circle at 50% 38%,
      rgba(200,168,78,0.06) 0%,
      transparent 62%),
    var(--bg-panel);
}
html[data-theme="light"] .chart-modal-stage {
  background:
    radial-gradient(circle at 50% 38%,
      rgba(168, 131, 58, 0.06) 0%,
      transparent 62%),
    var(--bg-panel);
}
/* The canvas is sized in JS (drawExpandedChart) to the stage's
   width — so the wheel stays large. The wheel inside is anchored
   to the top of the canvas with a capped radius, which keeps it
   visible regardless of viewport height. The unused bottom of
   the canvas is hidden by the stage's overflow: hidden. */
#chart-modal-canvas {
  display: block;
  margin: 0 auto;
}
@media (max-width: 768px) {
  /* Mobile positioning fix — top-align the modal (not centered) with a
     safe-area top inset so the .chart-modal-head + close X always clear
     the notch / browser UI, and cap the frame to the visible dynamic
     viewport (dvh) minus the insets so the head is never clipped and the
     existing .chart-modal-scroll body scrolls internally. #chart-modal is
     z-index 9999 (above #header), so only the browser/notch inset matters.
     The desktop layout (centered, .chart-modal-frame height: 92vh) is
     unchanged — these overrides are mobile-only. */
  #chart-modal {
    align-items: flex-start;
    padding: max(14px, env(safe-area-inset-top)) 0 max(12px, env(safe-area-inset-bottom));
  }
  .chart-modal-frame {
    width: 96vw;
    height: auto;
    max-height: calc(100dvh
      - max(14px, env(safe-area-inset-top))
      - max(12px, env(safe-area-inset-bottom)));
  }
  .chart-modal-stage {
    padding: 12px;
    /* Slice H1.2: lock mobile stage height to the frame width (96vw).
       The earlier H1.1 attempt used `height: auto`, which let the
       stage collapse to the canvas's pre-set DOM dimensions before
       JS resized it. The HTML canvas spec defaults to 300 × 150 when
       no width/height attributes are present (see app.html
       #chart-modal-canvas), so on first paint drawExpandedChart()
       read stage.clientHeight ≈ 150 + 24 px padding, computed
       stageH ≈ 150, capped visH = min(size, stageH) at 150, and the
       wheel radius collapsed to ~64 px instead of ~170 — the wheel
       rendered tiny. Mobile needs a concrete, measurable stage
       height BEFORE JS draws. 96vw keeps the stage roughly square
       with the width-bound canvas inside it (canvas square ≈
       96vw − 24 px after the 12 px padding on both axes, because
       global box-sizing is border-box), so stageH ≈ stageW and
       visH = size — restoring full mobile R while keeping the dead
       zone between wheel and Positions essentially zero. Desktop's
       `height: 92%` above remains unchanged. */
    height: 96vw;
  }
}

/* Phase D Slice 1 — natal-mode action row inside #chart-modal.
   Inline display:none on the element keeps it out of layout in
   relocation mode; JS flips display:flex on natal-mode open. */
.chart-modal-actions {
  display: flex;
  gap: 12px;
  padding: 0 22px 18px;
  justify-content: center;
  flex-wrap: wrap;
}
@media (max-width: 768px) {
  .chart-modal-actions { padding: 0 12px 14px; }
}

/* ── NEAREST-2GRP: "Nearest active points" — two-group compact panel +
   expanded modal. The modal REUSES the chart-modal visual shell
   (.chart-modal-backdrop / -frame / -head / -close / -scroll); only the
   open/centering + a compact list-frame size are re-declared here. */
#nearest-modal {
  position: fixed; inset: 0; z-index: 10000;
  display: none; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .22s ease;
}
#nearest-modal.open { display: flex; opacity: 1; }
/* A compact list frame — narrower and height-to-content (capped), unlike the
   tall square chart-wheel frame. */
.nearest-modal-frame {
  width: min(92vmin, 560px);
  height: auto;
  max-height: 86vh;
}
.nearest-modal-scroll { padding-bottom: 10px; }
.nearest-modal-section { padding: 16px 22px 4px; }

/* Quiet sub-group caption — clearly subordinate to the serif .block-title /
   modal title. Shared by the compact panel groups and the modal sections. */
.nearest-group-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--t3);
  padding: 2px 0 8px;
}
.nearest-group { margin-bottom: 18px; }
.nearest-group:last-child { margin-bottom: 0; }
.nearest-empty { color: var(--t3); font-size: 10px; }

/* "View more" control under the compact panel — opens the expanded modal. */
.nearest-viewmore {
  display: block; width: 100%;
  margin-top: 12px; padding: 8px 0;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--gold-hi); background: rgba(200,168,78,0.08);
  border: 1px solid var(--gold-dim); border-radius: 6px;
  cursor: pointer; transition: background .15s, border-color .15s;
}
.nearest-viewmore:hover { background: rgba(200,168,78,0.16); border-color: var(--border-hi); }

/* Multi-word fixed-star names ("Zubeneschamali", "Deneb Algedi") must wrap
   rather than overflow the row. Scoped to nearest rows so the Planets list is
   untouched. */
#nearest-lines .dlabel,
.nearest-modal-section .dlabel {
  flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere;
}

@media (max-width: 768px) {
  #nearest-modal {
    align-items: flex-start;
    padding: max(14px, env(safe-area-inset-top)) 0 max(12px, env(safe-area-inset-bottom));
  }
  .nearest-modal-frame {
    width: 96vw;
    max-height: calc(100dvh
      - max(14px, env(safe-area-inset-top))
      - max(12px, env(safe-area-inset-bottom)));
  }
}

/* ── Phase D Slice 2 (refinement v3) — chart-modal scroll
   architecture. The frame stays clipped (overflow:hidden); the
   head sits fixed at the top; everything below scrolls inside
   .chart-modal-scroll. The stage uses min-height: 100 % so the
   wheel fills the visible viewport on first paint (restoring
   the pre-Slice-2 wheel size); the positions + aspects rows
   below extend past the fold and are reached by scrolling. All
   colors are theme tokens — Dark / Light / Atlas inherit
   automatically. */
.chart-modal-scroll {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* Phase D Slice 2 (refinement v3.1): force a visible, always-on
     scrollbar so users can drag it with the mouse and see at a
     glance that there is more content below. Themed via tokens
     so Dark / Light / Atlas all read consistent. */
  overflow-y: scroll;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--gold) rgba(255,255,255,0.08);
}
.chart-modal-scroll::-webkit-scrollbar {
  width: 12px;
}
.chart-modal-scroll::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.08);
}
.chart-modal-scroll::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.chart-modal-scroll::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}
.chart-modal-bottom {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 18px;
  padding: 14px 22px 18px;
  border-top: 1px solid var(--border);
  background: linear-gradient(0deg,
              rgba(200, 168, 78, 0.04) 0%, transparent 100%);
  flex-shrink: 0;
}
.chart-modal-positions,
.chart-modal-aspects {
  flex: 1 1 50%;
  min-width: 0;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--t2);
}
/* Section title (top of each column). */
.chart-modal-section-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--t1);
  border-bottom: 1px solid var(--gold-dim);
  padding-bottom: 4px;
  margin: 0 0 8px;
}
/* Subgroup title (Angles / Planets / ASC aspects / etc.). */
.chart-modal-subtitle {
  font-size: 9.5px;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--gold-hi);
  margin: 8px 0 4px;
}
.chart-modal-subtitle:first-child { margin-top: 0; }

/* Positions tables — name / degree / sign / house grid (Slice A3.2,
   alignment fixed in A3.3). Columns are FIXED px (not em) and identical
   for the header row and data rows — like the Aspects tables — so the
   header labels sit exactly above their values. em columns broke this:
   they resolve against each element's own font-size, and the header
   (8.5px) is smaller than the rows (12px), so em columns came out
   narrower on the header and shifted every label left. House is a fixed
   column (no `auto`) so the header and value widths match; it sits right
   after Sign, not floated to the panel edge. Angles use cols 1-3 only. */
.chart-modal-positions-group { margin-bottom: 10px; }
.chart-modal-positions-group:last-child { margin-bottom: 0; }
.chart-modal-positions-headers,
.chart-modal-positions-row {
  display: grid;
  grid-template-columns: 76px 52px 92px 44px;
  gap: 8px;
  padding: 3px 0;
  align-items: baseline;
}
.chart-modal-positions-headers {
  font-size: 8.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--t3);
  border-bottom: 1px solid var(--gold-dim);
  padding-bottom: 3px;
  margin-bottom: 4px;
}
.chart-modal-positions-row .name   { color: var(--t3); }
.chart-modal-positions-row .deg    { color: var(--t1); }
.chart-modal-positions-row .sign   { color: var(--t1); }
.chart-modal-positions-row .house  { color: var(--t3); }
.chart-modal-positions-row .retro  { color: var(--gold-hi); }

/* Aspects rows — 4-column grid: body / aspect / body / orb. */
.chart-modal-aspects-group { margin-bottom: 10px; }
.chart-modal-aspects-group:last-child { margin-bottom: 0; }
.chart-modal-aspects-headers,
.chart-modal-aspects-row {
  display: grid;
  /* Phase D Slice 2 (refinement v3.1): all four columns fixed
     px width — replacing the previous `1fr` Orb column that
     spread orb values toward the panel's right edge while the
     short "ORB" header text sat far from them visually. With a
     fixed 60 px Orb column, header and value sit in the same
     compact column directly above each other. The Aspect column
     widens 72 → 88 so "conjunction" (≈ 73 px at 11 px mono) fits
     without bleeding into the next cell. */
  grid-template-columns: 60px 88px 60px 60px;
  gap: 10px;
  padding: 2px 0;
  align-items: baseline;
}
.chart-modal-aspects-headers {
  font-size: 8.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--t3);
  border-bottom: 1px solid var(--gold-dim);
  padding-bottom: 3px;
  margin-bottom: 4px;
}
.chart-modal-aspects-headers > span:last-child { text-align: right; }
.chart-modal-aspects-row .a    { color: var(--t1); }
.chart-modal-aspects-row .type { color: var(--t2); }
.chart-modal-aspects-row .b    { color: var(--t1); }
.chart-modal-aspects-row .orb  { color: var(--t3); text-align: right; }
.chart-modal-aspects-empty,
.chart-modal-aspects-note {
  color: var(--t3);
  font-size: 10px;
  letter-spacing: 0.04em;
  font-style: italic;
  padding: 2px 0;
}

@media (max-width: 768px) {
  .chart-modal-bottom {
    flex-direction: column;
    padding: 12px 12px 14px;
    gap: 14px;
  }
  .chart-modal-positions,
  .chart-modal-aspects {
    flex: 0 0 auto;
    /* Slice H1: desktop bumps body to 12 px for readability, but the
       narrow mobile aspect grid (76 px Aspect col) would crowd
       "conjunction" at 12 px mono. Revert to the pre-H1 11 px here. */
    font-size: 11px;
  }
  .chart-modal-subtitle {
    /* Slice H1: subtitle is uppercase 0.20em — keep mobile at the
       pre-H1 8.5 px to preserve column fit in the narrow layout. */
    font-size: 8.5px;
  }
  .chart-modal-aspects-headers,
  .chart-modal-aspects-row {
    grid-template-columns: 48px 76px 48px 52px;
    gap: 6px;
  }
  .chart-modal-positions-headers,
  .chart-modal-positions-row {
    /* Fixed px (A3.3), identical header/row template. Sum 240px + gaps
       fits the narrowest target (~336px content at 360px viewport):
       68 name ("N. Node R") · 48 deg ("14°20'") · 84 sign ("Sagittarius")
       · 40 house ("H12"/"HOUSE"). No overlap, no float. */
    grid-template-columns: 68px 48px 84px 40px;
    gap: 6px;
  }
}

/* ── ADVANCED SETTINGS DRAWER ─────────────────────────────────
   Right-side drawer surfaced by the header ⚙ icon. Uses the
   shared AstroCarto.Settings store; opens with a draft snapshot
   of live values and commits on Apply.                         */
#advanced-drawer {
  position: fixed;
  top: var(--header-h);
  right: 0;
  width: 380px;
  max-width: 92vw;
  height: calc(100vh - var(--header-h));
  background: var(--bg-panel);
  border-left: 1px solid var(--gold-dim);
  box-shadow: -12px 0 32px rgba(0, 0, 0, 0.45);
  z-index: 2100;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.32s cubic-bezier(.4, 0, .2, 1);
  backdrop-filter: blur(8px);
  overscroll-behavior: contain;
}
#advanced-drawer.open { transform: translateX(0); }
/* Chart-edit context (Charts page Create/Edit form): the .auth-page
   overlay sits at z-index 2200, so the drawer needs to lift above it
   to be visible. The class is added by openForChartEdit and removed
   on close, so map-page behavior (default z-index 2100) stays intact. */
#advanced-drawer.is-chart-edit { z-index: 2300; }
.adv-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px;
  border-bottom: 1px solid var(--gold-dim);
}
.adv-title {
  font-size: 11.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--gold-hi);
}
#adv-close {
  background: none; border: 0; color: var(--t2);
  font-size: 16px; line-height: 1; padding: 4px 8px; cursor: pointer;
  transition: color 0.15s;
}
#adv-close:hover { color: var(--gold-hi); }
.adv-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: scroll;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--gold) rgba(255,255,255,0.08);
  padding: 2px 0 4px;
}
.adv-body::-webkit-scrollbar {
  width: 12px;
}
.adv-body::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.08);
}
.adv-body::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.adv-body::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}
/* Current-chart anchor between .adv-head and .adv-body.
   Shown only when a saved chart is loaded; the Save-to-chart
   button persists the current draft into that chart's savedState. */
.adv-anchor {
  padding: 10px 18px 12px;
  border-bottom: 1px solid var(--gold-dim);
  background: rgba(255, 255, 255, 0.015);
}
.adv-anchor[hidden] { display: none; }
.adv-anchor-label {
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--t3);
}
.adv-anchor-name {
  margin: 2px 0 8px;
  font-size: 13px; color: var(--gold-hi);
  letter-spacing: 0.02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.adv-anchor-btn {
  display: block; width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: 1px solid var(--gold-dim);
  color: var(--gold-hi);
  font-family: inherit; font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase;
  border-radius: 3px; cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.adv-anchor-btn:hover:not(:disabled) {
  background: rgba(212, 175, 110, 0.08);
  border-color: var(--gold-hi);
}
.adv-anchor-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.adv-anchor-msg {
  min-height: 14px;
  margin-top: 6px;
  font-size: 10.5px; letter-spacing: 0.04em;
  color: #E86A6A;
}
.adv-anchor-msg.ok { color: var(--c-progressions); }
.adv-section {
  padding: 14px 18px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.adv-section:last-child { border-bottom: none; }
.adv-sec-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 4px;
}
.adv-sec-title {
  font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--t1);
}
.adv-sec-reset {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--t3);
  font-size: 9px; letter-spacing: 0.06em;
  padding: 3px 8px; border-radius: 3px; cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.adv-sec-reset:hover { border-color: var(--gold-dim); color: var(--gold-hi); }
/* UI-GUIDE-TOOLTIPS-1: helper text bumped from --t3 to --t2 (and opacity
   decay removed) so Advanced Settings guidance is readable in light / dark /
   atlas-blue themes. */
.adv-sec-desc {
  font-size: 10.5px; color: var(--t2);
  margin-bottom: 6px; line-height: 1.45;
}
.adv-sec-hint {
  font-size: 10px; color: var(--gold);
  opacity: 0.95;
  font-style: italic;
  margin-bottom: 10px; line-height: 1.4;
}
.adv-rows { display: flex; flex-direction: column; gap: 12px; }
.adv-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
}
.adv-row-label { color: var(--t1); font-size: 11.5px; flex: 1 1 auto; }
.adv-row-note  { color: var(--t2); font-size: 10px; font-style: italic; }
.adv-row-placeholder .adv-row-label { color: var(--t3); }
.adv-row-placeholder { opacity: 0.7; }

/* UI-GUIDE-TOOLTIPS-1: shared fixed-position guide tooltip for the top-bar
   layer buttons (Natal/Parans/Midpoints/Transits/Progressions). Appended to
   <body> by app.js so .header-center's overflow-x:auto cannot clip it.
   Theme-safe via vars; high contrast (--t1 on --bg-panel); elevated z-index
   above portaled dropdowns; pointer-events:none so it never blocks clicks.
   Hidden entirely on touch (hover:none) to avoid stuck overlays. */
.guide-tip {
  position: fixed;
  z-index: 9600;
  max-width: 264px;
  padding: 9px 12px;
  border-radius: 9px;
  background: var(--bg-panel);
  color: var(--t1);
  border: 1px solid var(--border-hi);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.40);
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.01em;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity 0.12s ease, transform 0.12s ease;
}
.guide-tip.show { opacity: 1; transform: translateY(0); }
@media (hover: none) { .guide-tip { display: none !important; } }

/* Toggle button */
.adv-toggle {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  color: var(--t2);
  padding: 4px 14px; border-radius: 14px;
  font-size: 10px; letter-spacing: 0.1em; cursor: pointer;
  min-width: 54px;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.adv-toggle.on {
  background: rgba(200, 168, 78, 0.13);
  border-color: rgba(200, 168, 78, 0.55);
  color: var(--gold-hi);
}

/* Radio + chip groups + datetime */
.adv-row-radio, .adv-row-tristate, .adv-row-chipgroup, .adv-row-datetime {
  flex-direction: column; align-items: stretch;
}
.adv-row-radio .adv-row-label,
.adv-row-tristate .adv-row-label,
.adv-row-chipgroup .adv-row-label,
.adv-row-datetime .adv-row-label { margin-bottom: 6px; }

/* Datetime row — datetime-local input + Now / Clear buttons. */
.adv-dt-controls {
  display: flex; gap: 6px; align-items: center;
}
.adv-dt-input {
  flex: 1 1 auto;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  color: var(--t1);
  padding: 4px 8px; border-radius: var(--radius);
  font-family: inherit; font-size: 11px; letter-spacing: 0.02em;
  color-scheme: dark;
}
.adv-dt-input:focus {
  outline: none; border-color: var(--gold-dim);
}
.adv-dt-now, .adv-dt-clear {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  color: var(--t2);
  padding: 4px 10px; border-radius: var(--radius);
  font-size: 10.5px; letter-spacing: 0.04em; cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.adv-dt-clear { padding: 4px 8px; font-size: 13px; line-height: 1; }
.adv-dt-now:hover, .adv-dt-clear:hover {
  border-color: var(--gold-dim); color: var(--gold-hi);
}
.adv-dt-note { margin-top: 4px; font-size: 9.5px; }
.adv-radio-group, .adv-chip-row, .adv-tri-header {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.adv-radio, .adv-chip, .adv-tri-opt {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  color: var(--t2);
  padding: 4px 10px; border-radius: var(--radius);
  font-size: 10.5px; letter-spacing: 0.04em; cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.adv-radio:hover, .adv-chip:hover, .adv-tri-opt:hover {
  border-color: var(--gold-dim); color: var(--t1);
}
.adv-radio.on, .adv-chip.on, .adv-tri-opt.on {
  background: rgba(200, 168, 78, 0.13);
  border-color: rgba(200, 168, 78, 0.55);
  color: var(--gold-hi);
}
.adv-tri-header { margin-bottom: 6px; }
/* BODY-1: visual sub-groups for the drawer planet selector. */
.adv-chip-group { margin-bottom: 8px; }
.adv-chip-group:last-child { margin-bottom: 0; }
.adv-chip-group-head {
  font-size: 8px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--t3); margin-bottom: 5px;
}

/* Footer actions */
.adv-foot {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid var(--gold-dim);
  background: var(--bg-hud);
}
.adv-foot-spacer { flex: 1 1 auto; }
.adv-foot-btn {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  color: var(--t2);
  padding: 5px 12px; border-radius: var(--radius);
  font-size: 10.5px; letter-spacing: 0.06em; cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.adv-foot-btn:hover:not(.disabled):not(:disabled) {
  border-color: var(--gold-dim); color: var(--gold-hi);
}
.adv-foot-primary {
  background: rgba(200, 168, 78, 0.16);
  border-color: rgba(200, 168, 78, 0.6);
  color: var(--gold-hi);
}
.adv-foot-btn.disabled, .adv-foot-btn:disabled {
  opacity: 0.35; cursor: not-allowed; color: var(--t3);
}

/* Mobile — reuse existing mobile menu; hide the desktop drawer. */
@media (max-width: 900px) {
  #advanced-drawer { display: none; }
}

/* At phone widths (<=640) re-show the drawer and re-shape it as a
   full-screen mobile panel that matches the existing #mobile-menu
   visual contract. This block MUST come AFTER the 900-rule above
   so its overrides win at <=640 via source order. At 641-900 only
   the 900-rule matches → drawer stays hidden (existing tablet
   behavior preserved). At >=901 neither media query matches →
   desktop drawer is byte-identical to today. */
@media (max-width: 640px) {
  #advanced-drawer {
    display: flex;
    position: fixed;
    top: var(--header-h);
    left: 0; right: 0; bottom: 0;
    width: auto;
    max-width: none;
    height: auto;
    border-left: none;
    box-shadow: none;
    transform: translateY(100%);
    transition: transform 0.28s cubic-bezier(.4,0,.2,1);
    z-index: 2400;
  }
  #advanced-drawer.open { transform: translateY(0); }

  /* Touch-friendly sizing — generous padding, larger tap targets,
     readable type. Mirrors the spacing rhythm used by #mobile-menu. */
  #advanced-drawer .adv-head      { padding: 16px 18px; }
  #advanced-drawer .adv-title     { font-size: 14px; }
  #advanced-drawer .adv-body      { padding: 8px 0 24px; }
  #advanced-drawer .adv-section   { padding: 18px 18px; }
  #advanced-drawer .adv-row       { min-height: 40px; }
  #advanced-drawer .adv-row-label { font-size: 13px; }
  #advanced-drawer .adv-toggle    { min-height: 32px; padding: 0 14px; }
  #advanced-drawer .adv-radio,
  #advanced-drawer .adv-chip,
  #advanced-drawer .adv-tri-opt   { padding: 8px 14px; font-size: 12px; }
  #advanced-drawer .adv-foot      {
    padding: 12px 14px env(safe-area-inset-bottom, 12px);
    gap: 8px;
  }
  #advanced-drawer .adv-foot-btn  { min-height: 38px; font-size: 12px; }
}

/* ── AUTH PAGES ───────────────────────────────────────────────
   Reuse the front-page shell so signup / login / account stay
   visually consistent. Hidden by default; app.js toggles the
   `active` class based on the current hash route. */
.auth-page {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 2200;   /* above #front-page (2000) so the overlay wins */
  overflow-y: auto;
  background: var(--bg);
  padding: 48px 24px;
  flex-direction: column;
  align-items: center;
}
.auth-page.active { display: flex; }
.auth-form { width: 100%; max-width: 460px; margin-top: 28px; }

/* Charts + Account + Sign up are long auth overlays. Match the app's drawer
   scroll affordance without changing other auth-page surfaces. */
#charts-page.auth-page,
#signup-page.auth-page,
#account-page.auth-page {
  overflow-y: scroll;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scrollbar-gutter: stable;
  scrollbar-width: auto;
  scrollbar-color: var(--gold) rgba(255,255,255,0.08);
}
#charts-page.auth-page::-webkit-scrollbar,
#signup-page.auth-page::-webkit-scrollbar,
#account-page.auth-page::-webkit-scrollbar {
  width: 14px;
}
#charts-page.auth-page::-webkit-scrollbar-track,
#signup-page.auth-page::-webkit-scrollbar-track,
#account-page.auth-page::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.08);
}
#charts-page.auth-page::-webkit-scrollbar-thumb,
#signup-page.auth-page::-webkit-scrollbar-thumb,
#account-page.auth-page::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 7px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
#charts-page.auth-page::-webkit-scrollbar-thumb:hover,
#signup-page.auth-page::-webkit-scrollbar-thumb:hover,
#account-page.auth-page::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}

/* Standalone static pages (privacy.html / terms.html /
   astrology-disclaimer.html, plus the reset/forgot/verify shells):
   force the same visible, styled scrollbar as the long auth overlays
   above, so the scroll affordance on the long legal pages is obvious.
   CSS-only scoping trick: app.html's auth overlays are <div>s, while
   every standalone static page uses <main class="auth-page"> — so
   main.auth-page cannot affect app.html. These pages run no theme JS
   (always the dark :root palette), so no light-theme variant needed. */
main.auth-page {
  overflow-y: scroll;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scrollbar-gutter: stable;
}
/* Why NO scrollbar-color/scrollbar-width here: since Chrome/Edge 121,
   setting either standard property on an element DISABLES its
   ::-webkit-scrollbar* custom styling — the element falls back to the
   standard scrollbar, which on Windows 11 desktop Chromium is a fluent
   OVERLAY bar that auto-hides when idle (i.e. "no visible scrollbar").
   Leaving only the ::-webkit-scrollbar rules below forces the classic,
   always-visible custom gold bar. The standard properties are scoped to
   non-WebKit engines (Firefox) where they are the only styling option. */
@supports not selector(::-webkit-scrollbar) {
  main.auth-page {
    scrollbar-width: auto;
    scrollbar-color: var(--gold) rgba(255,255,255,0.08);
  }
}
main.auth-page::-webkit-scrollbar { width: 14px; }
main.auth-page::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); }
main.auth-page::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 7px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
main.auth-page::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}

/* Light mode: keep these app scroll containers' scrollbars visible on the
   pale cream surface — explicit dark gold/brown thumb + slightly visible
   track. Mirrors the #front-page light override; targeted to these
   containers only (no global scrollbar styling). */
html[data-theme="light"] #charts-page.auth-page,
html[data-theme="light"] #signup-page.auth-page,
html[data-theme="light"] #account-page.auth-page,
html[data-theme="light"] .panel-body,
html[data-theme="light"] .adv-body,
html[data-theme="light"] .chart-modal-scroll {
  scrollbar-color: rgba(138,105,32,0.95) rgba(0,0,0,0.08);
}
html[data-theme="light"] #charts-page.auth-page::-webkit-scrollbar-track,
html[data-theme="light"] #signup-page.auth-page::-webkit-scrollbar-track,
html[data-theme="light"] #account-page.auth-page::-webkit-scrollbar-track,
html[data-theme="light"] .panel-body::-webkit-scrollbar-track,
html[data-theme="light"] .adv-body::-webkit-scrollbar-track,
html[data-theme="light"] .chart-modal-scroll::-webkit-scrollbar-track {
  background: rgba(0,0,0,0.08);
}
html[data-theme="light"] #charts-page.auth-page::-webkit-scrollbar-thumb,
html[data-theme="light"] #signup-page.auth-page::-webkit-scrollbar-thumb,
html[data-theme="light"] #account-page.auth-page::-webkit-scrollbar-thumb,
html[data-theme="light"] .panel-body::-webkit-scrollbar-thumb,
html[data-theme="light"] .adv-body::-webkit-scrollbar-thumb,
html[data-theme="light"] .chart-modal-scroll::-webkit-scrollbar-thumb {
  background: rgba(138,105,32,0.92);
}
html[data-theme="light"] #charts-page.auth-page::-webkit-scrollbar-thumb:hover,
html[data-theme="light"] #signup-page.auth-page::-webkit-scrollbar-thumb:hover,
html[data-theme="light"] #account-page.auth-page::-webkit-scrollbar-thumb:hover,
html[data-theme="light"] .panel-body::-webkit-scrollbar-thumb:hover,
html[data-theme="light"] .adv-body::-webkit-scrollbar-thumb:hover,
html[data-theme="light"] .chart-modal-scroll::-webkit-scrollbar-thumb:hover {
  background: rgba(138,105,32,1);
}

/* Dashboard scroll affordance. The dashboard box is already correctly sized
   (top:52px + inset bottom:0 → height = viewport − 52px) and scrolls when its
   cards exceed the viewport, but it kept the base overflow-y:auto WITHOUT a
   styled scrollbar — so it fell back to the platform OVERLAY scrollbar, which
   auto-hides on Windows. Result: clipped cards with no visible scroll cue.
   Give it the same gold scrollbar as Charts/Account, BUT — unlike them — keep
   overflow-y:auto (inherited) and do NOT add scrollbar-gutter:stable, so a
   dashboard whose content fits shows NO scrollbar and NO phantom gutter. A
   styled ::-webkit-scrollbar makes Chromium use a classic, space-reserving bar
   that appears only on overflow. Scoped to #dashboard-page; Charts/Account and
   every other surface are untouched. */
#dashboard-page.auth-page {
  scrollbar-width: auto;
  scrollbar-color: var(--gold) rgba(255,255,255,0.08);
}
#dashboard-page.auth-page::-webkit-scrollbar {
  width: 14px;
}
#dashboard-page.auth-page::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.08);
}
#dashboard-page.auth-page::-webkit-scrollbar-thumb {
  background: var(--gold);
  border-radius: 7px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
#dashboard-page.auth-page::-webkit-scrollbar-thumb:hover {
  background: var(--gold-hi);
  background-clip: padding-box;
}
html[data-theme="light"] #dashboard-page.auth-page {
  scrollbar-color: rgba(138,105,32,0.95) rgba(0,0,0,0.08);
}
html[data-theme="light"] #dashboard-page.auth-page::-webkit-scrollbar-track {
  background: rgba(0,0,0,0.08);
}
html[data-theme="light"] #dashboard-page.auth-page::-webkit-scrollbar-thumb {
  background: rgba(138,105,32,0.92);
}
html[data-theme="light"] #dashboard-page.auth-page::-webkit-scrollbar-thumb:hover {
  background: rgba(138,105,32,1);
}

.auth-opt {
  color: var(--t3); font-size: 10px; font-weight: 400;
  letter-spacing: 0.08em; text-transform: none; margin-left: 6px;
}
.auth-msg {
  min-height: 18px;
  margin: 6px 0 12px;
  color: #E86A6A;
  font-size: 11px;
  letter-spacing: 0.04em;
}
.auth-msg.ok { color: var(--c-progressions); }

/* Signup form uses a small divider heading to separate the
   account section from the first-chart section. Minimal — just
   a labeled rule that reuses the gold-accent palette. */
.signup-section-divider {
  display: flex; align-items: center; gap: 10px;
  margin: 22px 0 12px;
  color: var(--gold-hi);
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
}
.signup-section-divider::before,
.signup-section-divider::after {
  content: ''; flex: 1 1 auto;
  height: 1px; background: var(--gold-dim);
}

/* Inline radio pair (House system chooser on signup + Charts forms).
   Two pill-style options sitting side-by-side under the label. */
.fp-radio-row {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin-top: 4px;
}
.fp-radio {
  position: relative;
  display: inline-flex; align-items: center;
  padding: 6px 14px;
  border: 1px solid var(--gold-dim);
  border-radius: 3px;
  color: var(--t2);
  font-size: 11px; letter-spacing: 0.08em;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.fp-radio input {
  position: absolute; opacity: 0; width: 0; height: 0; margin: 0;
}
.fp-radio:hover { border-color: var(--gold-hi); color: var(--gold-hi); }
.fp-radio:has(input:checked) {
  border-color: var(--gold-hi);
  color: var(--gold-hi);
  background: rgba(212, 175, 110, 0.08);
}

/* Front-page auth row (Sign up · Log in) */
.fp-auth-row {
  display: flex; gap: 8px; align-items: center; justify-content: center;
  margin-top: 18px;
  color: var(--t3); font-size: 11px; letter-spacing: 0.04em;
}
.fp-auth-btn {
  background: transparent;
  border: 1px solid var(--gold-dim);
  color: var(--gold-hi);
  padding: 4px 14px; border-radius: 4px;
  font-family: inherit; font-size: 11px; letter-spacing: 0.12em;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.fp-auth-btn:hover,
.fp-auth-btn:focus,
.fp-auth-btn:focus-visible {
  text-decoration: none;
}
.fp-auth-btn:hover {
  background: rgba(200, 168, 78, 0.08);
  border-color: var(--gold-hi);
}
/* Phase C Slice 12 polish — reset-password / verify-email dynamic
   action slot. The success / invalid / no-token states inject
   `<a class="fp-btn" …>` into `#rp-action` (or `#vf-action` for
   verify-email). `.fp-btn` doesn't declare text-decoration, so the
   browser-default anchor underline shows through. Target the slot
   by id + element — higher specificity than .fp-btn, scoped so it
   can't bleed elsewhere. Covers every link state including :visited
   and :focus-visible; outline/focus-ring is preserved. */
#rp-action a,
#rp-action a:link,
#rp-action a:visited,
#rp-action a:hover,
#rp-action a:focus,
#rp-action a:focus-visible,
#rp-action a:active,
#vf-action a,
#vf-action a:link,
#vf-action a:visited,
#vf-action a:hover,
#vf-action a:focus,
#vf-action a:focus-visible,
#vf-action a:active {
  text-decoration: none;
  text-decoration-line: none;
}
.fp-auth-sep { color: var(--t4); }

/* Account page value rows */
.account-row {
  display: flex; justify-content: space-between;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
}
.account-row:last-of-type { border-bottom: none; margin-bottom: 14px; }
.account-key { color: var(--t3); letter-spacing: 0.08em; text-transform: uppercase; font-size: 10px; }
.account-val { color: var(--t1); }

/* ── Account settings sections ────────────────────────────────
   Change-password block is a standard settings section with a
   subtle divider rule above the title. Danger zone below uses
   the same base but switches the accent color family to ink-red
   so a destructive action reads unmistakably as destructive —
   without inventing a new visual language for it. */
.account-section {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 12px;
}
.account-section-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 17px; font-weight: 400; letter-spacing: 0.04em;
  color: var(--t1);
  margin-bottom: 2px;
}

/* Danger zone — visually separated block with a tinted border +
   very subtle red-ink wash. Deliberately understated (no big red
   banner); the message and the confirmation flow carry the
   weight. */
.account-danger {
  margin-top: 24px;
  padding: 20px;
  border: 1px solid rgba(232, 106, 106, 0.32);
  border-radius: var(--radius);
  background: rgba(232, 106, 106, 0.04);
  display: flex; flex-direction: column; gap: 12px;
}
.account-danger-title { color: #E86A6A; }
.account-danger-body {
  font-size: 11.5px; color: var(--t2); line-height: 1.7;
}
.account-danger-warn {
  font-size: 11.5px; color: var(--t1); line-height: 1.7;
}
.account-danger-warn em {
  font-style: normal; color: #E86A6A;
}
.account-danger-confirm {
  display: none;
  margin-top: 8px; padding-top: 16px;
  border-top: 1px solid rgba(232, 106, 106, 0.22);
  flex-direction: column; gap: 12px;
}
.account-danger-confirm.is-open { display: flex; }
.account-danger-actions {
  display: flex; gap: 10px; align-items: center; justify-content: flex-end;
  flex-wrap: wrap;
}

/* Danger-variant of the primary CTA — ink-red glow instead of
   gold. Reuses all other .fp-btn shape / sizing / transitions so
   the button reads as "same family, destructive intent". */
.fp-btn.is-danger {
  background: linear-gradient(135deg,
    rgba(232, 106, 106, 0.18) 0%, rgba(232, 106, 106, 0.08) 100%);
  border-color: rgba(232, 106, 106, 0.55);
  color: #F09A9A;
}
.fp-btn.is-danger:hover {
  background: linear-gradient(135deg,
    rgba(232, 106, 106, 0.30) 0%, rgba(232, 106, 106, 0.14) 100%);
  border-color: rgba(232, 106, 106, 0.82);
  color: #F5B4B4;
  box-shadow: 0 0 28px rgba(232, 106, 106, 0.14);
}
html[data-theme="light"] .fp-btn.is-danger {
  background: linear-gradient(135deg,
    rgba(176, 48, 48, 0.18) 0%, rgba(176, 48, 48, 0.08) 100%);
  border-color: rgba(176, 48, 48, 0.50);
  color: #8F2424;
}
html[data-theme="light"] .fp-btn.is-danger:hover {
  background: linear-gradient(135deg,
    rgba(176, 48, 48, 0.28) 0%, rgba(176, 48, 48, 0.12) 100%);
  border-color: rgba(176, 48, 48, 0.75);
  color: #6B1A1A;
  box-shadow: 0 0 28px rgba(176, 48, 48, 0.12);
}

/* Header auth pill — shown when signed-out. */
.header-auth-pill {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--gold-dim);
  color: var(--gold-hi);
  padding: 4px 12px; border-radius: 999px;
  font-family: inherit; font-size: 10px; letter-spacing: 0.1em;
  cursor: pointer;
  max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.header-auth-pill:hover {
  background: rgba(200, 168, 78, 0.12);
  border-color: var(--gold-hi);
}

/* Header utility button — opens the account menu popover.
   Paired with the ⚙ Advanced Settings icon in the header-right;
   the two are visually matched but semantically distinct
   (settings = product; menu = account). */
.header-util-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--gold-dim);
  border-radius: 50%;
  color: var(--gold-hi);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  padding: 0;
}
.header-util-btn:hover {
  background: rgba(200, 168, 78, 0.12);
  border-color: var(--gold-hi);
  color: var(--t1);
}
.header-util-btn.open {
  background: rgba(200, 168, 78, 0.18);
  border-color: var(--gold-hi);
  color: var(--t1);
}

@media (max-width: 900px) {
  /* Scope the mobile-hide to the MAP page header (#header) only.
     The auth-topbar reuses .header-util-btn for its own account
     trigger; an unqualified selector was hiding that trigger too,
     leaving the Dashboard (and every auth-overlay page) with no
     way to open the account menu on mobile. */
  #header .header-auth-pill,
  #header .header-util-btn { display: none; }
}

/* ── AUTH TOPBAR — persistent brand + utility on overlay pages. */
#auth-topbar {
  position: fixed; top: 0; left: 0; right: 0;
  height: 52px;
  z-index: 2300;    /* above every .auth-page (2200) */
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 24px;
  /* Chrome bg from theme token — see --chrome-bg at :root. */
  background: var(--chrome-bg);
  border-bottom: 1px solid var(--gold-dim);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
}
#auth-topbar[hidden] { display: none; }

/* ── AUTH SHELL NAV — used on the unauthenticated shell pages
   (signup + login). Same 52 px dark-navy gradient strip +
   gold-dim bottom border as #auth-topbar so the site's top-row
   system stays consistent. Lives INSIDE each auth-page (not a
   shared singleton) so it appears exactly when that page is
   active; the .auth-page padding-top: calc(52px + 48px) already
   reserves space for a 52 px top bar, so no layout shift. */
.auth-shell-nav {
  position: fixed; top: 0; left: 0; right: 0;
  height: 52px;
  z-index: 2300;    /* same as #auth-topbar */
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 24px;
  /* Chrome bg from theme token — see --chrome-bg at :root. */
  background: var(--chrome-bg);
  border-bottom: 1px solid var(--gold-dim);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
}

.auth-topbar-brand {
  background: transparent; border: 0;
  color: var(--gold-hi);
  font-family: 'Cormorant Garamond', serif;
  font-size: 14px; font-weight: 400; letter-spacing: 0.18em;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 4px;
}
.auth-topbar-brand:hover { color: var(--t1); }
.auth-topbar-brand .fp-logo-star {
  color: var(--gold);
  font-size: 14px;
}
.auth-topbar-name { letter-spacing: 0.18em; }

/* When the auth-topbar is visible, auth-page content needs
   room underneath it. The assistant page keeps this padding model
   (it doesn't scroll — own 100dvh / inner-scroll layout); the scrolling
   overlay pages below switch to a top offset instead — see scroll-polish. */
.auth-page { padding-top: calc(52px + 48px); }

/* ── Scroll polish — keep each private page's scrollbar clear of the
   52px fixed top bar (#auth-topbar on signed-in overlays,
   .auth-shell-nav on signup/login; both at z 2300, above .auth-page
   z 2200). A scrolling .auth-page pinned to top:0 paints the top ~52px
   of its own right-edge scrollbar UNDER the bar, so the scrollbar looked
   hidden at the top-right corner (reported on Account + Charts; shared by
   every scrolling overlay page). Fix: start these pages' scroll viewport
   BELOW the bar (top:52px) and drop the matching 52px from padding-top —
   content stays in the same place, but the scrollbar + its track now begin
   at the bar's bottom edge. #assistant-page keeps its own model (not
   listed); #front-page is not an .auth-page and is untouched. */
#dashboard-page.auth-page,
#charts-page.auth-page,
#account-page.auth-page,
#signup-page.auth-page,
#login-page.auth-page,
#preferences-page.auth-page,
#subscription-page.auth-page,
#ai-history-page.auth-page {
  top: 52px;
}
#charts-page.auth-page,
#account-page.auth-page,
#signup-page.auth-page,
#login-page.auth-page,
#preferences-page.auth-page,
#subscription-page.auth-page,
#ai-history-page.auth-page {
  padding-top: 48px;   /* was calc(52px + 48px); the 52px is now the `top` offset */
}

/* ── ACCOUNT MENU popover. Fixed near top-right; opened by any
   element with class .js-account-menu-trigger. */
#account-menu {
  position: fixed;
  top: 66px; right: 18px;  /* clears both 62 px #header and 52 px #auth-topbar */
  width: 260px;
  z-index: 2400;
  background: linear-gradient(180deg,
    rgba(14, 12, 24, 0.98),
    rgba(6, 8, 16, 0.98));
  border: 1px solid var(--gold-dim);
  border-radius: 8px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55);
  padding: 4px;
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 0.14s, transform 0.14s;
}
#account-menu.open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.acct-menu-head {
  display: flex; align-items: center; gap: 11px;
  padding: 12px 12px 10px;
}
/* Clickable identity block (Dashboard shortcut). Same layout as
   the base .acct-menu-head — only affordance changes. */
.acct-menu-head-btn {
  cursor: pointer;
  transition: background 0.15s;
}
.acct-menu-head-btn:hover,
.acct-menu-head-btn:focus-visible {
  background: rgba(255, 255, 255, 0.04);
  outline: none;
}
.acct-menu-avatar {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(145deg,
    rgba(200, 168, 78, 0.38),
    rgba(200, 168, 78, 0.10));
  color: var(--gold-hi);
  border: 1px solid var(--gold-dim);
  border-radius: 50%;
  font-family: 'Cormorant Garamond', serif;
  font-size: 19px; font-weight: 500;
}
.acct-menu-identity {
  min-width: 0; flex: 1 1 auto;
  line-height: 1.2;
}
.acct-menu-name {
  color: var(--t1); font-size: 12px; letter-spacing: 0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.acct-menu-email {
  color: var(--t3); font-size: 10px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.acct-menu-sep {
  height: 1px;
  background: var(--gold-dim);
  margin: 2px 6px;
}
.acct-menu-item {
  display: block; width: 100%;
  background: transparent; border: 0;
  color: var(--t1);
  font-family: inherit; font-size: 11.5px; letter-spacing: 0.04em;
  text-align: left; padding: 9px 12px;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.acct-menu-item:hover {
  background: rgba(200, 168, 78, 0.10);
  color: var(--gold-hi);
}
.acct-menu-item-danger { color: var(--t2); }
.acct-menu-item-danger:hover {
  background: rgba(232, 106, 106, 0.12);
  color: #F09A9A;
}

/* Guest mode — app.js adds `is-guest` on #account-menu when the
   user is not signed in. Every child carrying [data-auth-required]
   (identity block, Preferences / Subscription / Account items,
   Log out, and the surrounding separators) is hidden so the menu
   collapses to just the theme toggle — a lightweight utility /
   appearance menu for guests. The theme row has no
   data-auth-required, so it stays visible and fully functional
   in both states. */
#account-menu.is-guest [data-auth-required] {
  display: none !important;
}

/* Map-first launch — hide the Preferences and Subscription menu items.
   AI defaults (Preferences) and billing (Subscription) are not live yet,
   so these links are hidden from the account menu for now. The pages and
   routes (#preferences-page / #subscription-page, applyRoute, PROTECTED_
   ROUTES) are left intact for later re-enable — remove this rule to bring
   the links back. CSS-only by data-action because .acct-menu-item sets an
   explicit display, so a [hidden] attribute would be overridden; this
   mirrors the existing data-mobile-only / Slice F1 menu-hiding pattern.
   Specificity (1,2,0) beats the base .acct-menu-item rule; no !important
   needed (the is-guest rule above already hides them when logged out).
   Account, Log out and the theme switcher are untouched and stay visible. */
#account-menu .acct-menu-item[data-action="preferences"],
#account-menu .acct-menu-item[data-action="subscription"] {
  display: none;
}

/* ── Mobile-only menu items inside #account-menu ──
   "Advanced settings" (data-mobile-only) and "Log in"
   (data-mobile-only + data-guest-only) are gated through three
   rules with identical specificity (1, 2, 0). Source order is the
   tiebreak — no !important anywhere — so the cascade is:
     R1 hide-by-default → R2 mobile-show → R3 guest-only-hide.
   Mobile logged-in: A visible (R2 wins via order over R1), L hidden
   (R3 wins via order over R2). Mobile guest: A visible, L visible
   (R3 doesn't match because is-guest is active). Desktop / tablet:
   only R1 fires. The pre-existing is-guest rule above matches a
   different attribute (data-auth-required) so does not interact. */
#account-menu .acct-menu-item[data-mobile-only],
#account-menu .acct-menu-sep[data-mobile-only] {
  display: none;
}
@media (max-width: 640px) {
  #account-menu .acct-menu-item[data-mobile-only] { display: flex; }
  #account-menu .acct-menu-sep[data-mobile-only]  { display: block; }
  /* Slice F1: the two map-only items (Map Settings + Advanced
     settings) and the separator that follows them only make sense
     while the map is the current view. body.route-map is toggled
     by applyRoute() — present when the hash is empty (map view),
     absent on every auth-page overlay (dashboard / charts /
     preferences / subscription / account / signup / login).
     data-action targeting (not the generic data-mobile-only)
     keeps the mobile-only Log in item unaffected; the
     data-mobile-only separator is the only one in the menu and
     belongs with this map-only block, so it goes too. Specificity
     0,2,2 wins against the mobile-show rules above (0,2,1). */
  body:not(.route-map) #account-menu .acct-menu-item[data-action="map-settings"],
  body:not(.route-map) #account-menu .acct-menu-item[data-action="advanced"],
  body:not(.route-map) #account-menu .acct-menu-sep[data-mobile-only] {
    display: none;
  }
}
#account-menu:not(.is-guest) [data-guest-only] {
  display: none;
}

/* ── Empty-state modal — shown from the Dashboard Open Map
   button when there is no current chart AND no saved charts.
   Two explicit choices: Create a chart / Continue without. */
#no-chart-modal {
  position: fixed; inset: 0;
  z-index: 3000;   /* above everything, including menus */
  display: none;
}
#no-chart-modal.open { display: block; }
.no-chart-backdrop {
  position: absolute; inset: 0;
  background: rgba(6, 8, 16, 0.75);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.no-chart-frame {
  position: relative;
  width: min(440px, 92vw);
  margin: 18vh auto 0;
  padding: 28px 28px 24px;
  background: linear-gradient(180deg,
    rgba(14, 12, 24, 0.98),
    rgba(6, 8, 16, 0.98));
  border: 1px solid var(--gold-dim);
  border-radius: 10px;
  box-shadow: 0 24px 56px rgba(0, 0, 0, 0.6);
  display: flex; flex-direction: column; gap: 10px;
}
.no-chart-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 26px; font-style: italic; font-weight: 400;
  color: var(--t1); line-height: 1.15;
}
.no-chart-body {
  font-size: 12px; line-height: 1.6;
  color: var(--t2);
  margin-bottom: 6px;
}
.no-chart-actions {
  display: flex; flex-direction: column; gap: 8px;
  margin-top: 6px;
}

/* ── Slice C: Current Chart modal ──
   Opened from the desktop toolbar "Current Chart" button or the
   mobile menu entry. Lets users edit the current map session's
   birth details (date / time / place). z-index 9500 sits above
   Slice A6 portaled dropdowns (z-index 9000). Visual language
   follows the existing #no-chart-modal pattern. */
#current-chart-modal {
  position: fixed; inset: 0;
  z-index: 9500;
  display: none;
}
#current-chart-modal.open { display: block; }
.cc-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(6, 8, 16, 0.75);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.cc-modal-frame {
  position: relative;
  width: min(460px, 92vw);
  margin: 12vh auto 0;
  padding: 24px 24px 20px;
  /* Slice C6: frame bg uses var(--bg-panel) so it auto-themes
     (dark navy / cream / atlas sapphire) instead of being locked to
     the original hard-coded dark gradient. Border keeps the gold-dim
     token used by .chart-modal-frame so the rim re-tones across
     themes. Backdrop + shadow ship dark by default and get
     light-theme overrides further down (mirroring the existing
     .chart-modal-frame light overrides). */
  background: var(--bg-panel);
  border: 1px solid var(--gold-dim);
  border-radius: 12px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.75),
              0 0 0 1px rgba(200,168,78,0.06) inset;
  display: flex; flex-direction: column; gap: 10px;
}
.cc-modal-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 24px; font-style: italic; font-weight: 400;
  color: var(--t1); line-height: 1.15;
}
.cc-modal-body {
  font-size: 11.5px; line-height: 1.55;
  color: var(--t2);
  margin-bottom: 4px;
}
.cc-modal-empty {
  font-size: 11px; line-height: 1.55;
  color: var(--t3);
  font-style: italic;
  padding: 6px 10px;
  background: rgba(200,168,78,0.05);
  border-left: 2px solid rgba(200,168,78,0.30);
  border-radius: 0 4px 4px 0;
}
.cc-form { display: flex; flex-direction: column; gap: 10px; }
.cc-modal-actions {
  display: flex; flex-direction: row; gap: 10px;
  justify-content: flex-end;
  margin-top: 4px;
}
.cc-modal-secondary-actions {
  display: flex;
  justify-content: flex-start;
  margin-top: -2px;
}
.cc-modal-secondary-actions .fp-auth-btn {
  flex: 0 1 auto;
  min-width: 160px;
}
.cc-modal-actions .fp-btn { flex: 0 1 auto; min-width: 140px; }
.cc-modal-actions .fp-auth-btn { flex: 0 1 auto; min-width: 100px; }
@media (max-width: 520px) {
  .cc-modal-frame {
    margin: 6vh auto 0;
    padding: 18px 18px 16px;
  }
  .cc-modal-actions {
    flex-direction: column-reverse;
  }
  .cc-modal-secondary-actions .fp-auth-btn,
  .cc-modal-actions .fp-btn,
  .cc-modal-actions .fp-auth-btn { width: 100%; min-width: 0; }
}

/* ── Dashboard status card — "Chart currently in use". */
.dash-current {
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px 0 6px;
  min-height: 58px;
}
.dash-current-name {
  color: var(--t1);
  font-family: 'Cormorant Garamond', serif;
  font-size: 24px; font-style: italic; font-weight: 400;
  line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dash-current-meta {
  color: var(--t3);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: 0.08em;
}
.dash-current-action {
  align-self: flex-start;
  margin-top: 8px;
}

/* ── DASHBOARD REDESIGN (Phase 2 polish) ─────────────────────
   Same DOM, same ids, same layout meaning. Visuals upgraded to
   match the reference's weight: gold-tinted gradients on cards,
   a decorative world-map hint on the Atlas card, slightly larger
   typography, softer card borders, and subtle staggered entrance. */
.dashboard-page {
  /* The 52px top-bar clearance is now handled by `top: 52px` (scroll-polish
     block) so the dashboard's scrollbar clears the bar too when it appears;
     this keeps just the 24px breathing room + 72px bottom. Net top gap
     (52px offset + 24px padding) is unchanged from before. */
  padding: 24px 24px 72px;
  /* Calm dual-gradient wash — gold top-left, violet bottom-right,
     echoing the front page but at lower intensity so the dashboard
     reads as minimal rather than decorative. */
  background-image:
    radial-gradient(ellipse 70% 40% at 18% 0%,
      rgba(200,168,78,0.055) 0%, transparent 58%),
    radial-gradient(ellipse 60% 50% at 82% 100%,
      rgba(48,34,92,0.14) 0%, transparent 70%);
}
.dashboard-inner {
  width: 100%; max-width: 1120px; margin: 0 auto;
  display: flex; flex-direction: column; gap: 28px;
}

.dashboard-hero {
  display: flex; flex-direction: column; gap: 12px;
  padding-bottom: 4px;
  /* Border removed — whitespace + the gradient backdrop separate
     the hero from the cards more gracefully. */
  border-bottom: 0;
}
.dashboard-date {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--gold-hi); opacity: 0.9;
}
.dashboard-greeting {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(32px, 4.6vw, 52px);
  font-style: italic; font-weight: 400;
  color: var(--t1);
  line-height: 1.08;
  letter-spacing: 0.005em;
  max-width: 820px;
  margin: 0;
}
.dashboard-greeting em { font-style: italic; color: var(--gold-hi); }
.dashboard-tagline {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(15px, 1.7vw, 19px);
  font-style: italic;
  color: var(--gold); opacity: 0.9;
  max-width: 640px;
}

/* Card primitives — base styles shared by every dash-card
   instance. The Charts + Relocations cards inside `.dashboard-grid`
   pick up a stronger surface treatment in the rule below so they
   feel like designed surfaces rather than empty dark rectangles. */
.dash-card {
  position: relative;
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0.022) 0%,
    rgba(255, 255, 255, 0.008) 100%);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 22px 24px;
  display: flex; flex-direction: column; gap: 10px;
  transition: border-color 0.18s ease, background 0.18s ease;
}
.dash-card:hover { border-color: var(--gold-dim); }
.dash-card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 18px;
  margin-bottom: 2px;
}
.dash-card-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 26px; font-style: italic; font-weight: 400;
  color: var(--t1);
  line-height: 1.18;
  margin-top: 4px;
  letter-spacing: 0.005em;
}
.dash-card-body { flex: 1 1 auto; min-width: 0; }
.dash-card-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12.5px; color: var(--t2); line-height: 1.75;
  margin-top: 10px; max-width: 52ch;
}
.eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--gold-hi); opacity: 0.9;
}

/* Charts + Relocations cards — stronger, more designed surface.
   Scoped via .dashboard-grid > .dash-card so the Atlas card
   (which is a SIBLING of the grid, not a child) is never
   affected. Richer gradient + soft gold border + inner highlight
   + lift shadow gives the two grid cards depth and visually
   links them to the Atlas card's gold system. */
.dashboard-grid > .dash-card {
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0.045) 0%,
    rgba(255, 255, 255, 0.012) 100%);
  border: 1px solid rgba(200, 168, 78, 0.16);
  border-radius: 12px;
  padding: 24px 26px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.04),
    0 1px 2px rgba(0, 0, 0, 0.35);
}
.dashboard-grid > .dash-card:hover {
  border-color: rgba(200, 168, 78, 0.32);
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0.06) 0%,
    rgba(255, 255, 255, 0.018) 100%);
}

/* ══════════════════════════════════════════════════════════════════
   DASHBOARD GRID CARDS — reference-image artwork (v4)
   ──────────────────────────────────────────────────────────────────
   Each of the two grid cards (Charts + Relocations) wears a
   theme-specific illustrated PNG from frontend/assets/ as
   its background artwork. The SIX source files are:

     Charts      — Dark2 / Light2 / Atlas2
     Relocations — Dark2 / Light2 / Atlas2

   The reference illustrations are composed with the figure in
   the right half and near-empty wash on the left, which maps
   directly to the existing card layout (eyebrow + title +
   content on the left, Manage / Save-from-map in the upper-
   right). No layout changes required — the artwork slots into
   the content space already there.

   The artwork is painted via a ::after pseudo-element at
   z-index 0 so existing content (head / current-chart / rows)
   stays above via its z-index 1 rule. overflow: hidden clips
   the image to the card's rounded corners.

   The Atlas card is a SIBLING of .dashboard-grid (not a child)
   so NONE of these selectors can reach it. Its composition +
   Europe-map image stay untouched. ───────────────────────── */
.dashboard-grid > .dash-card {
  overflow: hidden;    /* clip artwork to the rounded rectangle */
}
.dashboard-grid > .dash-card::after {
  /* Base paint slot — the actual background-image URL is set
     per-theme, per-card below. Position anchors right so the
     illustration stays aligned with the card's right edge at
     narrow breakpoints; `cover` guarantees the artwork fills
     the card without letterboxing, and `no-repeat` keeps it a
     single canvas. */
  content: '';
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center right;
  background-repeat: no-repeat;
  pointer-events: none;
  z-index: 0;
}

/* ── Dark theme (default) ─────────────────────────────────── */
.dashboard-grid > .dash-card.dash-card-charts::after {
  background-image: url('assets/charts-card-dark.png');
}
.dashboard-grid > .dash-card.dash-card-relocations::after {
  background-image: url('assets/relocations-card-dark.png');
}

/* ── Light theme ─────────────────────────────────────────── */
html[data-theme="light"] .dashboard-grid > .dash-card.dash-card-charts::after {
  background-image: url('assets/charts-card-light.png');
}
html[data-theme="light"] .dashboard-grid > .dash-card.dash-card-relocations::after {
  background-image: url('assets/relocations-card-light.png');
}

/* ── Atlas Blue theme ────────────────────────────────────── */
html[data-theme="atlas-blue"] .dashboard-grid > .dash-card.dash-card-charts::after {
  background-image: url('assets/charts-card-atlas.png');
}
html[data-theme="atlas-blue"] .dashboard-grid > .dash-card.dash-card-relocations::after {
  background-image: url('assets/relocations-card-atlas.png');
}

/* ── AI Relocation Assistant + AI Chat History dashboard cards.
   Same per-theme image pattern as Charts/Relocations: a card-sized
   ::after layer paints the illustration; the content (head + desc +
   cta) sits at z-index 1 via the rule a few blocks below — extended
   to cover .dash-card-desc / .dash-card-cta so the AI cards' text
   and button render above the artwork. */
.dashboard-grid > .dash-card.dash-card-assistant::after {
  background-image: url('assets/dashboard-cards/ai-relocation-assistant-card-dark.png');
}
.dashboard-grid > .dash-card.dash-card-history::after {
  background-image: url('assets/dashboard-cards/ai-chat-history-card-dark.png');
}
html[data-theme="light"] .dashboard-grid > .dash-card.dash-card-assistant::after {
  background-image: url('assets/dashboard-cards/ai-relocation-assistant-card-light.png');
}
html[data-theme="light"] .dashboard-grid > .dash-card.dash-card-history::after {
  background-image: url('assets/dashboard-cards/ai-chat-history-card-light.png');
}
html[data-theme="atlas-blue"] .dashboard-grid > .dash-card.dash-card-assistant::after {
  background-image: url('assets/dashboard-cards/ai-relocation-assistant-card-atlas.png');
}
html[data-theme="atlas-blue"] .dashboard-grid > .dash-card.dash-card-history::after {
  background-image: url('assets/dashboard-cards/ai-chat-history-card-atlas.png');
}

/* The new V1 dark + atlas AI Relocation Assistant artworks are a different
   aspect ratio than the other dashboard illustrations (2.21:1 vs ~2.67:1).
   With the shared base anchor (`center right`) they would crop the inner
   scene unevenly and surface a visible inner frame ("card-inside-card"
   look). Centering on both axes keeps the scene fully visible. Scoped via
   `:not([data-theme="light"])` so the light-theme AI Assistant card keeps
   its existing positioning entirely untouched. */
html:not([data-theme="light"]) .dashboard-grid > .dash-card.dash-card-assistant::after {
  background-position: center;
}

/* Content above the artwork — head / current-chart / places-list
   sit at z-index 1 so the artwork never paints on top of text
   or buttons. Scoped to grid-card direct children so the Atlas
   card's own z-index system is untouched. */
.dashboard-grid > .dash-card > .dash-card-head,
.dashboard-grid > .dash-card > .dash-current,
.dashboard-grid > .dash-card > .dash-rows,
.dashboard-grid > .dash-card > .dash-card-desc,
.dashboard-grid > .dash-card > .dash-card-cta {
  position: relative;
  z-index: 1;
}

/* Launch v1 — AI dashboard cards are shown as disabled "Coming soon"
   tiles (AI is paused for the map-first launch). The card + its artwork
   stay visible; the description is dimmed, the CTA is inert, and a small
   pill badge marks the state. Scoped to .coming-soon so the Charts /
   Relocations cards are untouched. The badge sits as the second child of
   the flex .dash-card-head, so the existing justify-content:space-between
   pushes it to the top-right with no positioning hacks. */
.dash-soon-badge {
  flex: 0 0 auto;
  align-self: flex-start;
  padding: 3px 9px;
  border: 1px solid var(--gold-dim, rgba(200, 168, 78, 0.4));
  border-radius: 999px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--t2);
  white-space: nowrap;
}
.dashboard-grid > .dash-card.coming-soon > .dash-card-desc {
  opacity: 0.5;
}
.dashboard-grid > .dash-card.coming-soon .dash-cta-btn {
  opacity: 0.5;
  pointer-events: none;
  cursor: default;
}

/* ══════════════════════════════════════════════════════════════════
   LOWER-CARD STABILITY — fixed height + internal scroll
   ──────────────────────────────────────────────────────────────────
   Cards are locked to a stable desktop height so the grid doesn't
   stretch or shrink with saved-place count. The Relocations list
   scrolls inside the card when it overflows; its max-width keeps
   the rows (and the delete × at the right edge of each row) in
   the quieter left/centre portion of the card, well inside the
   card padding and clear of the illustrated figure on the right.
   Charts-card content stays compact at the top; empty visual
   space below is filled by the artwork. Mobile stacks naturally
   (grid collapses at ≤ 760 px) — fixed height still applies and
   looks fine at single-column width. ────────────────────────── */
.dashboard-grid > .dash-card {
  height: 260px;
}

/* Relocations list — base layout that applies in BOTH states
   (empty / loading / error AND populated). Keeps card geometry
   stable: the box that holds the list is the same shape in
   every state; only the paint on top changes.

   The visual "content well" — background scrim, backdrop blur,
   rounded corners, inner padding — lives on a separate rule
   below gated by `:has(> .dash-row)`, so it paints ONLY when
   the JS has rendered at least one .dash-row (populated state).
   In empty / loading / error the list holds a single .dash-empty
   child instead, no well rule matches, and the constellation
   artwork shows through unobstructed. */
.dashboard-grid > .dash-card-relocations > .dash-rows {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  /* Constrain row width so the delete button at the row's
     right edge sits ~62 % across the card — inside the card
     padding and clear of the artwork's right-side figure. */
  max-width: 62%;
  /* Visible custom scrollbar — only paints when scroll is
     active, so it's inert in the empty state. */
  scrollbar-width: thin;
  scrollbar-color: rgba(200, 168, 78, 0.48) transparent;
}
.dashboard-grid > .dash-card-relocations > .dash-rows::-webkit-scrollbar {
  width: 6px;
}
.dashboard-grid > .dash-card-relocations > .dash-rows::-webkit-scrollbar-thumb {
  background: rgba(200, 168, 78, 0.48);
  border-radius: 3px;
}
.dashboard-grid > .dash-card-relocations > .dash-rows::-webkit-scrollbar-thumb:hover {
  background: rgba(200, 168, 78, 0.72);
}
.dashboard-grid > .dash-card-relocations > .dash-rows::-webkit-scrollbar-track {
  background: transparent;
}

/* Content well — populated state ONLY. :has(> .dash-row) gates
   every paint property below so the well cannot appear in
   empty / loading / error states (which render a single
   .dash-empty child, not .dash-row children). Theme-specific
   variants below also all use :has(> .dash-row), so in every
   theme the empty state is well-free. */
.dashboard-grid > .dash-card-relocations > .dash-rows:has(> .dash-row) {
  background: linear-gradient(90deg,
    rgba(8, 12, 28, 0.60) 0%,
    rgba(8, 12, 28, 0.60) 84%,
    rgba(8, 12, 28, 0) 100%);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  border-radius: 8px;
  padding: 4px 6px 4px 10px;
}

/* Light theme — cream scrim tint (populated state only). */
html[data-theme="light"] .dashboard-grid > .dash-card-relocations > .dash-rows:has(> .dash-row) {
  background: linear-gradient(90deg,
    rgba(252, 247, 232, 0.78) 0%,
    rgba(252, 247, 232, 0.78) 84%,
    rgba(252, 247, 232, 0) 100%);
  scrollbar-color: rgba(138, 105, 32, 0.55) transparent;
}
html[data-theme="light"] .dashboard-grid > .dash-card-relocations > .dash-rows:has(> .dash-row)::-webkit-scrollbar-thumb {
  background: rgba(138, 105, 32, 0.55);
}
html[data-theme="light"] .dashboard-grid > .dash-card-relocations > .dash-rows:has(> .dash-row)::-webkit-scrollbar-thumb:hover {
  background: rgba(138, 105, 32, 0.78);
}

/* Atlas Blue — sapphire scrim (populated state only). */
html[data-theme="atlas-blue"] .dashboard-grid > .dash-card-relocations > .dash-rows:has(> .dash-row) {
  background: linear-gradient(90deg,
    rgba(8, 24, 56, 0.62) 0%,
    rgba(8, 24, 56, 0.62) 84%,
    rgba(8, 24, 56, 0) 100%);
}

/* Empty-state text — no container, just the message. Compact
   width keeps the line short and away from the artwork's right
   side; a faint theme-matched text halo handles readability
   wherever the short line happens to overlap the constellation. */
.dashboard-grid > .dash-card-relocations > .dash-rows > .dash-empty {
  max-width: 240px;
  padding: 20px 0 14px;
  text-align: left;
  text-shadow: 0 0 10px rgba(8, 12, 28, 0.75);
}
html[data-theme="light"] .dashboard-grid > .dash-card-relocations > .dash-rows > .dash-empty {
  text-shadow: 0 0 10px rgba(252, 247, 232, 0.88);
}
html[data-theme="atlas-blue"] .dashboard-grid > .dash-card-relocations > .dash-rows > .dash-empty {
  text-shadow: 0 0 10px rgba(8, 24, 56, 0.80);
}

/* Row separators — the pre-existing default (rgba white-alpha)
   reads noisy against the new well. Soften to a subtle inset
   line so rows delineate without visual clutter. */
.dashboard-grid > .dash-card-relocations > .dash-rows .dash-row {
  border-bottom-color: rgba(255, 255, 255, 0.05);
}
html[data-theme="light"] .dashboard-grid > .dash-card-relocations > .dash-rows .dash-row {
  border-bottom-color: rgba(28, 24, 48, 0.08);
}

/* Delete × — always-visible "chip" treatment so the action
   reads as clickable against any theme's artwork. Background
   + stronger border + comfortable tap size. */
.dashboard-grid > .dash-card-relocations .dash-row-actions {
  /* Pull the action column in a touch so the chip has space
     from the well's right edge and the scrollbar. */
  margin-right: 2px;
}
.dashboard-grid > .dash-card-relocations .dash-row-x {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(200, 168, 78, 0.32);
  color: var(--t2);
  padding: 4px 10px;
  font-size: 13px;
  min-width: 26px;
  text-align: center;
  line-height: 1;
}
.dashboard-grid > .dash-card-relocations .dash-row-x:hover {
  background: rgba(232, 106, 106, 0.14);
  border-color: rgba(232, 106, 106, 0.55);
  color: #E86A6A;
}
html[data-theme="light"] .dashboard-grid > .dash-card-relocations .dash-row-x {
  background: rgba(28, 24, 48, 0.06);
  border-color: rgba(168, 131, 58, 0.38);
}
html[data-theme="light"] .dashboard-grid > .dash-card-relocations .dash-row-x:hover {
  background: rgba(176, 48, 48, 0.10);
  border-color: rgba(176, 48, 48, 0.55);
  color: #8F2424;
}

/* Atlas CTA card — upgraded to feel like the primary action.
   Gold-tinted gradient on top of the shared surface, stronger
   border, more padding, decorative MiniWorld behind the text. */
.dash-card-atlas {
  flex-direction: row; align-items: center; gap: 28px;
  padding: 28px 30px;
  overflow: hidden;
  background:
    linear-gradient(135deg,
      rgba(200, 168, 78, 0.12) 0%,
      rgba(40, 28, 72, 0.16) 100%),
    linear-gradient(180deg,
      rgba(255, 255, 255, 0.025) 0%,
      rgba(255, 255, 255, 0.008) 100%);
  border-color: var(--gold-dim);
}
.dash-card-atlas:hover { border-color: rgba(200,168,78,0.42); }
.dash-card-atlas .dash-card-body { position: relative; z-index: 1; }
.dash-card-atlas .dash-card-cta  { position: relative; z-index: 1; flex: 0 0 auto; }
.dash-card-atlas .dash-card-title {
  font-size: clamp(26px, 2.6vw, 34px);
  margin-top: 6px;
}
/* Pin the Atlas card's description to its previous size and
   line-height. The base `.dash-card-desc` was bumped for the
   grid cards; this override keeps the Atlas body copy — the one
   you asked to leave alone — visually unchanged. */
.dash-card-atlas .dash-card-desc {
  font-size: 11px;
  line-height: 1.7;
  max-width: 48ch;
}

/* ── Decorative Europe-map backdrop for the Atlas card. The
   element is an <img> that points at the exact provided asset
   (frontend/assets/atlas-card-europe-map.png). This rule
   is ONLY about fitting + integrating that image into the card
   theme — object-fit covers the full card, a gentle gradient
   mask softens both edges so the title area and the Open-map
   CTA stay dominant. ────────────────────────────────────────── */
.dash-atlas-world {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* Cover the full card area; the image's heart-of-Europe focal
     region stays centred, with minor top/bottom crop since the
     asset is wider than the card. */
  object-fit: cover;
  object-position: center center;
  /* Slight overall dim so the photo doesn't fight the card's
     gold-tinted gradient underneath. */
  opacity: 0.85;
  pointer-events: none;
  z-index: 0;
  /* Edge mask: gentler on the left so the image blends into the
     card's gold gradient behind the title/description, and a
     stronger fade on the right so the CTA button area stays
     calm and the button remains the focal element there. */
  -webkit-mask-image: linear-gradient(to right,
    rgba(0,0,0,0.35) 0%,
    rgba(0,0,0,0.85) 18%,
    rgba(0,0,0,1)    38%,
    rgba(0,0,0,1)    70%,
    rgba(0,0,0,0.55) 88%,
    rgba(0,0,0,0.25) 100%);
          mask-image: linear-gradient(to right,
    rgba(0,0,0,0.35) 0%,
    rgba(0,0,0,0.85) 18%,
    rgba(0,0,0,1)    38%,
    rgba(0,0,0,1)    70%,
    rgba(0,0,0,0.55) 88%,
    rgba(0,0,0,0.25) 100%);
}

.dash-cta-btn {
  background: linear-gradient(180deg,
    rgba(200, 168, 78, 0.22) 0%, rgba(200, 168, 78, 0.10) 100%);
  border: 1px solid var(--gold-hi);
  color: var(--gold-hi);
  padding: 12px 22px; border-radius: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: 10px;
}
.dash-cta-btn:hover {
  background: linear-gradient(180deg,
    rgba(200, 168, 78, 0.32) 0%, rgba(200, 168, 78, 0.16) 100%);
  box-shadow: 0 0 0 1px rgba(200,168,78,0.35),
              0 10px 36px rgba(200,168,78,0.14);
  color: #F5D060;
}

/* Two-column grid for the charts + places cards. Unchanged
   breakpoint; same children, same collapse behavior. */
.dashboard-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 22px;
}
@media (max-width: 760px) {
  .dashboard-grid    { grid-template-columns: 1fr; }
  .dash-card-atlas   { flex-direction: column; align-items: flex-start; gap: 18px; padding: 24px; }
  .dash-atlas-world  { opacity: 0.55; width: 100%; }
  /* Map-first launch: give the Atlas card's title + eyebrow the same dark
     text-shadow the grid cards use below, so they read cleanly over the
     (already mobile-dimmed, .dash-atlas-world opacity above) Europe-map
     artwork. The Atlas card is a sibling of .dashboard-grid, so it needs
     its own selector rather than joining the .dashboard-grid > ... list. */
  .dash-card-atlas .dash-card-title,
  .dash-card-atlas .eyebrow {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  }

  /* Slice F3: on mobile the dashboard grid collapses to single-column
     and the Charts / Relocations cards narrow significantly, but the
     ::after artwork keeps its native scale + center-right position,
     so it overlaps with the text on the left of the card. Dim the
     artwork and add a subtle dark text-shadow so the title and
     eyebrow read cleanly without removing or replacing the
     illustration. Scoped to the two illustrated grid cards only —
     the Atlas / Open Map card uses its own .dash-atlas-world SVG
     dimming above and is unaffected. Theme-agnostic: the opacity
     and text-shadow tone work on all three themes (dark / light /
     atlas-blue) without per-theme overrides because the artwork
     URLs are already theme-swapped at the parent ::after rules. */
  /* Map-first launch: the AI Relocation Assistant + AI Chat History
     "Coming soon" cards are added to the Charts/Relocations dimming +
     text-shadow treatment below so their title/eyebrow read clearly
     over the artwork on mobile. Their Coming-soon badge, dimmed
     description and inert CTA keep the existing disabled treatment. */
  .dashboard-grid > .dash-card.dash-card-charts::after,
  .dashboard-grid > .dash-card.dash-card-relocations::after,
  .dashboard-grid > .dash-card.dash-card-assistant::after,
  .dashboard-grid > .dash-card.dash-card-history::after {
    opacity: 0.35;
  }
  .dashboard-grid > .dash-card.dash-card-charts .dash-card-title,
  .dashboard-grid > .dash-card.dash-card-relocations .dash-card-title,
  .dashboard-grid > .dash-card.dash-card-assistant .dash-card-title,
  .dashboard-grid > .dash-card.dash-card-history .dash-card-title,
  .dashboard-grid > .dash-card.dash-card-charts .eyebrow,
  .dashboard-grid > .dash-card.dash-card-relocations .eyebrow,
  .dashboard-grid > .dash-card.dash-card-assistant .eyebrow,
  .dashboard-grid > .dash-card.dash-card-history .eyebrow {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  }
}

/* Subtle staggered entrance so the page assembles rather than
   snap-paints. Respects reduced-motion users. */
@keyframes dash-fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.dashboard-page .dashboard-hero,
.dashboard-page .dash-card-atlas,
.dashboard-page .dashboard-grid > .dash-card {
  animation: dash-fade-up 500ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.dashboard-page .dashboard-hero            { animation-delay: 40ms;  }
.dashboard-page .dash-card-atlas           { animation-delay: 120ms; }
.dashboard-page .dashboard-grid > .dash-card:nth-child(1) { animation-delay: 200ms; }
.dashboard-page .dashboard-grid > .dash-card:nth-child(2) { animation-delay: 260ms; }
@media (prefers-reduced-motion: reduce) {
  .dashboard-page .dashboard-hero,
  .dashboard-page .dash-card-atlas,
  .dashboard-page .dashboard-grid > .dash-card {
    animation: none;
  }
}

/* Pill-style action in card head ("Manage →"). Upgraded from a
   tiny text link to a readable, gently-bordered pill so it's
   easier to notice and click, while still reading as secondary
   to the primary Open-map CTA on the Atlas card. */
.dash-link-btn {
  background: transparent;
  border: 1px solid rgba(200, 168, 78, 0.22);
  color: var(--gold-hi);
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 7px 14px;
  border-radius: 4px;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}
.dash-link-btn:hover {
  background: rgba(200, 168, 78, 0.10);
  border-color: rgba(200, 168, 78, 0.50);
  color: var(--t1);
}
.dash-link-muted {
  color: var(--t3);
  border-color: transparent;
  background: transparent;
  cursor: default;
}
.dash-link-muted:hover {
  color: var(--t3);
  border-color: transparent;
  background: transparent;
}

/* List rows inside cards. Slightly larger type + a bit more
   vertical padding so rows scan cleanly and feel clickable. */
.dash-rows {
  display: flex; flex-direction: column; gap: 0;
  margin-top: 6px;
}
.dash-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  padding: 12px 0;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  cursor: pointer;
}
.dash-row:last-child { border-bottom: none; }
.dash-row:hover .dash-row-name { color: var(--gold-hi); }
.dash-row-body { min-width: 0; flex: 1 1 auto; }
.dash-row-name {
  color: var(--t1); font-size: 13px; letter-spacing: 0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color 0.15s;
}
.dash-row-meta {
  color: var(--t3); font-size: 10.5px; letter-spacing: 0.04em;
  margin-top: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dash-row-meta .cat { color: var(--gold); margin-right: 6px; }
.dash-row-actions { flex-shrink: 0; display: flex; gap: 4px; }
.dash-row-x {
  background: none; border: 1px solid transparent;
  color: var(--t3); font-family: inherit;
  padding: 3px 8px; border-radius: 3px;
  font-size: 12px; cursor: pointer; line-height: 1;
  transition: border-color 0.15s, color 0.15s;
}
.dash-row-x:hover { border-color: rgba(232,106,106,0.5); color: #E86A6A; }

.dash-empty {
  color: var(--t3); font-size: 12px; font-style: italic;
  line-height: 1.6;
  padding: 14px 0; text-align: center;
}

.dashboard-foot {
  display: flex; gap: 10px; align-items: center; justify-content: center;
  margin-top: 6px;
  color: var(--t3); font-size: 11px; letter-spacing: 0.04em;
}

/* Save-place button inside the side panel. Minimal, matches the
   existing small pill vocabulary. */
.panel-save-place-btn {
  display: inline-block;
  background: transparent;
  border: 1px solid var(--gold-dim);
  color: var(--gold-hi);
  padding: 4px 10px; border-radius: 3px;
  font-family: inherit; font-size: 9.5px; letter-spacing: 0.1em;
  cursor: pointer; margin-top: 6px;
  transition: background 0.15s, border-color 0.15s;
}
.panel-save-place-btn:hover {
  background: rgba(200, 168, 78, 0.10);
  border-color: var(--gold-hi);
}
.panel-save-place-btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* ── SAVED CHARTS — Dashboard + Charts page shared styling ─── */
.charts-section { margin: 18px 0 12px; }
.charts-section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 8px;
}
.charts-section-title {
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--t2);
}
.charts-list {
  display: flex; flex-direction: column; gap: 6px;
}
.charts-empty {
  color: var(--t3); font-size: 11px; font-style: italic;
  padding: 10px 0; text-align: center;
}

.chart-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color 0.15s, background 0.15s;
}
.chart-row:hover { border-color: var(--gold-dim); background: rgba(200,168,78,0.05); }
/* Active chart row — subtle gold-tinted outline so the user can
   spot the "chart currently in use" at a glance. Complements the
   inline "Current" badge on the name line. */
.chart-row.chart-row-active {
  border-color: var(--gold-hi);
  background: rgba(212, 175, 110, 0.07);
}

.chart-row-body { flex: 1 1 auto; min-width: 0; }
.chart-row-name {
  color: var(--t1); font-size: 12px; letter-spacing: 0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chart-row-badge {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--gold-hi);
  border: 1px solid var(--gold-hi);
  border-radius: 2px;
  vertical-align: middle;
}
/* Slice F2: inline USE pill on non-current chart rows. Visually
   parallel to .chart-row-badge (same size, position, uppercase
   letter-spacing, border-radius) but rendered as a <button> so it
   reads as clearly clickable. Softer gold tone than CURRENT so the
   active chart's CURRENT badge still visually pops. Lives inside
   .chart-row-name alongside the chart name; the name ellipsizes
   before the pill on narrow widths, same as today with CURRENT. */
.chart-row-use-btn {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--gold);
  background: transparent;
  border: 1px solid var(--gold-dim);
  border-radius: 2px;
  vertical-align: middle;
  cursor: pointer;
  font-family: inherit;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.chart-row-use-btn:hover {
  color: var(--gold-hi);
  border-color: var(--gold-hi);
  background: rgba(200, 168, 78, 0.08);
}
.chart-row-meta {
  color: var(--t3); font-size: 9.5px; letter-spacing: 0.04em;
  margin-top: 2px;
}
.chart-row-meta .cat { color: var(--gold); margin-right: 6px; }
/* "Default settings" / "Custom settings" pill on each chart row.
   Sits at the right edge of the meta line so name + last-opened
   stay the primary read; default state is muted, custom state
   takes a subtle gold accent matching the existing badge system. */
.chart-row-settings {
  margin-left: 10px;
  padding: 1px 7px;
  border-radius: 2px;
  font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--t3);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.chart-row-settings.is-custom {
  color: var(--gold-hi);
  border-color: var(--gold-dim);
  background: rgba(200, 168, 78, 0.06);
}


.chart-row-actions {
  display: flex; gap: 4px; flex-shrink: 0;
}
.chart-action-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--t2);
  padding: 3px 8px; border-radius: 3px;
  font-family: inherit; font-size: 9.5px; letter-spacing: 0.06em;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.chart-action-btn:hover { border-color: var(--gold-dim); color: var(--gold-hi); }
.chart-action-btn.danger:hover { border-color: rgba(232,106,106,0.6); color: #E86A6A; }

/* Charts-page form cards — primary + secondary variants share
   the same base chrome; the .is-secondary modifier tones the
   secondary card down so hierarchy between "Create a new chart"
   and "Save the chart shown on the map" reads at a glance. */
.charts-save-card {
  padding: 20px 18px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--gold-dim);
  border-radius: var(--radius);
  margin-bottom: 18px;
}
.charts-save-card .charts-section-title {
  margin-bottom: 10px;
}
.charts-save-row { margin-bottom: 8px; }
/* UI Bugfix — Advanced settings button on the Charts-page
   create/edit card sits inside a .charts-save-row wrapper, so
   the .fp-auth-btn default inline-block content width left it
   visibly narrow next to the full-width Chart name / Category /
   Notes inputs and the full-width Save Changes / Create chart
   .fp-btn CTA. Scoped to .charts-save-row so other .fp-auth-btn
   usages (Refresh in .charts-section-head, Cancel edit as a
   direct .charts-save-card child, Send-verification, etc.) keep
   their content-width / row-flex layout. */
.charts-save-row .fp-auth-btn { width: 100%; }
/* Match the 8 px inter-row rhythm after the Birth date / Birth time
   grid row — the default .fp-row has no bottom margin, so inside
   the Charts create form it would sit flush against the following
   City/country input. Scoped to .charts-save-card so the signup
   and front-page forms keep their own default rhythm. */
.charts-save-card .fp-row { margin-bottom: 8px; }
.charts-save-card .fp-btn { margin-top: 10px; }

/* Secondary variant — neutral border, softer bg, muted title
   + a one-line explanatory sub-copy. Visually recedes so the
   primary Create card above it reads as the main action. */
.charts-save-card.is-secondary {
  padding: 16px 16px;
  background: rgba(255, 255, 255, 0.018);
  border-color: var(--border);
  margin-top: 6px;
}
.charts-save-card.is-secondary .charts-section-title {
  font-size: 12px;
  color: var(--t2);
  letter-spacing: 0.14em;
  margin-bottom: 4px;
}
.charts-save-card-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--t3);
  letter-spacing: 0.04em;
  line-height: 1.6;
  margin: 0 0 12px;
  max-width: 42ch;
}

/* Primary CTA polish — full-width, slightly taller, subtly richer
   gradient + soft gold glow so "Create chart" reads as the main
   action of the page. Scoped to the id so other .fp-btn uses
   (Back to Dashboard, front page, save-current button, etc.)
   keep their existing treatment. */
#create-chart-btn {
  width: 100%;
  height: 52px;
  margin-top: 14px;
  background: linear-gradient(135deg,
    rgba(200, 168, 78, 0.28) 0%,
    rgba(200, 168, 78, 0.14) 100%);
  border-color: rgba(200, 168, 78, 0.60);
  box-shadow: 0 10px 32px rgba(200, 168, 78, 0.10);
}
#create-chart-btn:hover {
  background: linear-gradient(135deg,
    rgba(200, 168, 78, 0.42) 0%,
    rgba(200, 168, 78, 0.22) 100%);
  border-color: rgba(200, 168, 78, 0.82);
  box-shadow: 0 12px 36px rgba(200, 168, 78, 0.22);
}
html[data-theme="light"] #create-chart-btn {
  background: linear-gradient(135deg,
    rgba(168, 131, 58, 0.30) 0%,
    rgba(168, 131, 58, 0.14) 100%);
  border-color: rgba(168, 131, 58, 0.58);
  box-shadow: 0 10px 32px rgba(168, 131, 58, 0.10);
}
html[data-theme="light"] #create-chart-btn:hover {
  background: linear-gradient(135deg,
    rgba(168, 131, 58, 0.42) 0%,
    rgba(168, 131, 58, 0.22) 100%);
  border-color: rgba(138, 105, 32, 0.80);
  box-shadow: 0 12px 36px rgba(168, 131, 58, 0.22);
}

/* ══════════════════════════════════════════════════════════════════
   FRONT PAGE — v2 visual redesign (Phase 1)
   Adapts the reference's two-column hero composition onto the
   existing #front-page markup. Form ids, submit wiring, and the
   auth-button ids are unchanged; only layout + dressing change.
══════════════════════════════════════════════════════════════════ */

/* Backdrop — faint star dust. Layered as a single element via
   multiple radial-gradients so we don't need an extra DOM tree. */
.fp-stars {
  position: absolute; inset: 0; pointer-events: none;
  z-index: 0;
  opacity: 0.55;
  background-image:
    radial-gradient(1px 1px at 6%  12%, rgba(255,255,255,0.35), transparent 60%),
    radial-gradient(1px 1px at 18% 28%, rgba(255,255,255,0.28), transparent 60%),
    radial-gradient(1px 1px at 29% 8%,  rgba(255,255,255,0.30), transparent 60%),
    radial-gradient(1px 1px at 42% 34%, rgba(255,255,255,0.22), transparent 60%),
    radial-gradient(1px 1px at 54% 12%, rgba(255,255,255,0.32), transparent 60%),
    radial-gradient(1px 1px at 66% 24%, rgba(255,255,255,0.24), transparent 60%),
    radial-gradient(1px 1px at 77% 8%,  rgba(255,255,255,0.30), transparent 60%),
    radial-gradient(1px 1px at 88% 32%, rgba(255,255,255,0.28), transparent 60%),
    radial-gradient(1px 1px at 12% 62%, rgba(255,255,255,0.30), transparent 60%),
    radial-gradient(1px 1px at 26% 78%, rgba(255,255,255,0.26), transparent 60%),
    radial-gradient(1px 1px at 40% 68%, rgba(255,255,255,0.22), transparent 60%),
    radial-gradient(1px 1px at 58% 82%, rgba(255,255,255,0.32), transparent 60%),
    radial-gradient(1px 1px at 72% 72%, rgba(255,255,255,0.26), transparent 60%),
    radial-gradient(1px 1px at 86% 88%, rgba(255,255,255,0.30), transparent 60%),
    radial-gradient(1px 1px at 94% 54%, rgba(255,255,255,0.22), transparent 60%);
}

/* Backdrop — faint gold constellation scaffold. The SVG scales
   across the full viewport; individual dots twinkle softly. The
   outer opacity + drop-shadow pair give the whole layer a soft
   gold halo so dots read as "glowing" rather than flat fills;
   line stroke-width is lifted out of sub-pixel territory so the
   connecting scaffold is actually visible. The fp-twinkle
   keyframes + per-circle animation-delay stagger are unchanged
   — only the opacity range moves up so the pulse never drops
   below a readable floor. Light mode sets opacity:0 on this
   element (higher specificity), so every value here is dark-
   mode-only in practice. */
.fp-constellation {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  opacity: 0.55;
  z-index: 0;
  filter: drop-shadow(0 0 2px rgba(200, 168, 78, 0.40));
}
.fp-constellation .fp-constellation-lines line {
  stroke: var(--gold);
  stroke-width: 0.25;
  opacity: 0.85;
  vector-effect: non-scaling-stroke;
}
.fp-constellation .fp-constellation-dots circle {
  fill: var(--gold);
  animation: fp-twinkle 4s ease-in-out infinite;
}
.fp-constellation .fp-constellation-dots circle:nth-child(3n)   { animation-delay: .4s; }
.fp-constellation .fp-constellation-dots circle:nth-child(3n+1) { animation-delay: 1.2s; }
.fp-constellation .fp-constellation-dots circle:nth-child(3n+2) { animation-delay: 2.0s; }
@keyframes fp-twinkle {
  /* 4:1 dim-to-bright ratio gives each dot a visibly soft pulse
     rather than a constant glow; outer opacity 0.55 multiplies
     through, so effective peak stays subtle (~0.55) while the
     trough drops to ~0.14 — clearly noticeable animation, never
     flashy. Duration + easing + per-circle delay offsets are
     unchanged, so the organic staggered cadence is preserved. */
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 1.00; }
}

/* Top navigation. flex: 0 0 auto so the nav never shrinks away
   from the top when #front-page is a flex column. Dark gradient
   + gold-dim bottom border mirror the dashboard's #auth-topbar so
   both pages share one intentional "dark top strip" treatment.
   The light-mode override at (0,3,0) specificity re-skins these
   same two properties, so this base rule only surfaces in dark
   mode — light mode stays exactly as it was. */
.fp-nav {
  flex: 0 0 auto;
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding: 22px clamp(18px, 4vw, 48px);
  /* Chrome bg from theme token — see --chrome-bg at :root. */
  background: var(--chrome-bg);
  border-bottom: 1px solid var(--gold-dim);
}
.fp-nav-brand {
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--t1);
}
.fp-nav-logo {
  color: var(--gold-hi);
  font-size: 18px;
  line-height: 1;
}
.fp-nav-wordmark {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px; letter-spacing: 0.34em;
  color: var(--gold-hi);
}
.fp-nav-links {
  display: inline-flex; align-items: center; gap: 8px;
}
.fp-nav-link {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--t2);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: 0.22em; text-transform: uppercase;
  padding: 7px 16px;
  border-radius: 999px;
  cursor: pointer;
  transition: border-color .18s ease, color .18s ease, background .18s ease;
}
.fp-nav-link:hover {
  border-color: rgba(200,168,78,0.55);
  color: var(--gold-hi);
}
.fp-nav-link-solid {
  border-color: rgba(200,168,78,0.55);
  color: var(--gold-hi);
  background: linear-gradient(180deg,
    rgba(200,168,78,0.18) 0%, rgba(200,168,78,0.06) 100%);
}
.fp-nav-link-solid:hover {
  background: linear-gradient(180deg,
    rgba(200,168,78,0.28) 0%, rgba(200,168,78,0.10) 100%);
  color: #F5D060;
}

/* Hero — two-column grid inside a flex-column page. flex: 1 1 auto
   so it expands to fill the space between nav and footer, keeping
   the footer pinned to the bottom of the viewport. */
.fp-hero {
  flex: 1 1 auto;
  position: relative; z-index: 2;
  width: 100%; max-width: 1180px;
  margin: 0 auto;
  padding: clamp(16px, 3vw, 40px) clamp(18px, 4vw, 48px) clamp(32px, 5vw, 64px);
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
}
.fp-left  { min-width: 0; }
.fp-right {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  max-width: 560px;
  justify-self: center;
}

/* Eyebrow rule + uppercase label above the title */
.fp-eyebrow-row {
  display: flex; align-items: center; gap: 14px;
  margin-bottom: 24px;
}
.fp-eyebrow-rule {
  width: 42px; height: 1px;
  background: rgba(200,168,78,0.6);
}
.fp-eyebrow-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--gold-hi);
}

/* Hero title — large italic serif. `em` marks the gold accent phrase. */
.fp-hero-title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 400; font-style: italic;
  font-size: clamp(38px, 5.5vw, 66px);
  line-height: 1.05; letter-spacing: 0.005em;
  color: var(--t1);
  margin: 0 0 22px;
  max-width: 560px;
}
.fp-hero-title em {
  font-style: italic;
  color: var(--gold-hi);
}

.fp-hero-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px; line-height: 1.8;
  color: var(--t2);
  max-width: 480px;
  margin: 0 0 32px;
}
.fp-hero-desc em {
  font-style: italic;
  color: var(--t1);
}

/* The form keeps its internal classes (.fp-row / .fp-field / .fp-input
   / .fp-btn) — only the outer wrapper gets the new card treatment
   when it sits inside the left hero column. Specificity beats the
   earlier `.fp-form { max-width: 440px }` rule without editing it. */
.fp-left .fp-form {
  max-width: 520px;
  padding: 22px;
  background: linear-gradient(180deg,
    rgba(200,168,78,0.05) 0%, rgba(200,168,78,0.015) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Sigil — pure CSS rotating orbits + planet dots, with an inline
   SVG compass star at the center. No JS, no image assets. */
.fp-sigil {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
}
.fp-sigil-orbit {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
}
.fp-sigil-orbit-1 {
  width: 95%; height: 95%;
  border: 1px solid rgba(200,168,78,0.15);
  animation: fp-rotate 120s linear infinite;
}
.fp-sigil-orbit-2 {
  width: 78%; height: 78%;
  border: 1px dashed rgba(200,168,78,0.11);
  animation: fp-rotate 80s linear infinite reverse;
}
.fp-sigil-orbit-3 {
  width: 60%; height: 60%;
  border: 1px solid rgba(200,168,78,0.11);
  animation: fp-rotate 50s linear infinite;
}
.fp-sigil-orbit-4 {
  width: 42%; height: 42%;
  border: 1px dashed rgba(200,168,78,0.16);
  animation: fp-rotate 30s linear infinite reverse;
}
.fp-sigil-dot {
  position: absolute;
  width: 8px; height: 8px; border-radius: 50%;
  transform: translate(-50%, -50%);
  top: 0; left: 50%;
}
.fp-sigil-orbit-2 .fp-sigil-dot { top: 50%; left: 0;  }
.fp-sigil-orbit-3 .fp-sigil-dot { top: 0;   left: 80%; }
.fp-sigil-orbit-4 .fp-sigil-dot { top: 80%; left: 30%; }
.fp-sigil-dot-sun     { background: #E6C75F; box-shadow: 0 0 14px #E6C75F; }
.fp-sigil-dot-venus   { background: #D8B982; box-shadow: 0 0 14px #D8B982; }
.fp-sigil-dot-mars    { background: #C85B57; box-shadow: 0 0 14px #C85B57; }
.fp-sigil-dot-jupiter { background: #B59A54; box-shadow: 0 0 14px #B59A54; }

.fp-sigil-center {
  width: 28%;
  color: var(--gold-hi);
  z-index: 2;
}

.fp-sigil-label {
  position: absolute;
  bottom: 3%;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  z-index: 2;
}
.fp-sigil-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--t3);
}
.fp-sigil-motto {
  font-family: 'Cormorant Garamond', serif;
  font-size: 16px; font-style: italic;
  color: var(--t2);
  margin-top: 4px;
}

@keyframes fp-rotate {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Footer strip. flex: 0 0 auto so it always sits at the bottom of
   the flex column and never shrinks. Pairs with .fp-hero's
   flex: 1 1 auto to keep the footer pinned. */
.fp-foot {
  flex: 0 0 auto;
  position: relative; z-index: 2;
  border-top: 1px solid var(--border);
  padding: 16px clamp(18px, 4vw, 48px);
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--t3);
}

/* ── Mobile fallbacks ─────────────────────────────────────────────
   The reference is desktop-first. On narrow screens we drop the
   sigil column entirely so the form stays the focal point, and we
   simplify the nav + footer. Existing mobile overrides for
   .fp-form / .fp-row / .fp-btn at line ~953 still apply. */
@media (max-width: 820px) {
  .fp-hero {
    grid-template-columns: 1fr;
    gap: 28px;
    padding: 12px 18px 40px;
  }
  .fp-right { display: none; }
  .fp-hero-title {
    font-size: clamp(30px, 8vw, 46px);
    margin-bottom: 16px;
  }
  .fp-hero-desc { font-size: 11px; margin-bottom: 24px; }
  .fp-left .fp-form { padding: 18px; max-width: none; }
  .fp-foot {
    padding: 14px 18px;
    gap: 6px;
  }
  .fp-foot-right { display: none; }
}

@media (max-width: 520px) {
  .fp-nav { padding: 16px 14px; }
  /* Top-bar / header brand wordmarks: hide on mobile, keep ✦ glyph only.
     .fp-nav-wordmark is the front-page hero brand; .auth-topbar-name is the
     #auth-topbar (Dashboard/Account/Preferences/Subscription/Charts overlay)
     and the .auth-shell-nav (Signup/Login) brand; .logo-name wraps the text
     in <header id="header"> (Map view). */
  .fp-nav-wordmark,
  .auth-topbar-name,
  .logo-name { display: none; }
  .fp-nav-link {
    font-size: 9.5px; letter-spacing: 0.2em;
    padding: 6px 12px;
  }
  .fp-eyebrow-label { font-size: 9.5px; letter-spacing: 0.22em; }
}

/* ══════════════════════════════════════════════════════════════════
   FRONT PAGE — landing sections below the hero
   ──────────────────────────────────────────────────────────────────
   Additive, #front-page-scoped layout for the Features / MCP / Private
   Beta / Coming Feature / About sections. Reuses the hero token palette
   (--gold-hi, --t1/2/3, --border, --radius) and the two hero fonts so
   the sections match the existing visual style and adapt to all themes.
   ══════════════════════════════════════════════════════════════════ */
#front-page .fp-section {
  position: relative; z-index: 2;
  width: 100%; max-width: 1180px;
  margin: 0 auto;
  padding: clamp(28px, 5vw, 64px) clamp(18px, 4vw, 48px);
}
#front-page .fp-section-head { margin-bottom: clamp(20px, 3vw, 32px); }
#front-page .fp-section-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--gold-hi); margin-bottom: 12px;
}
#front-page .fp-section-title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 300; letter-spacing: 0.02em;
  font-size: clamp(26px, 3.4vw, 40px);
  color: var(--t1); line-height: 1.2; margin: 0;
}
/* Optional section intro paragraph (used by the Trust section). */
#front-page .fp-section-intro {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px; line-height: 1.8; color: var(--t2);
  max-width: 680px; margin: 0 0 28px;
}

/* Features grid */
#front-page .fp-features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 20px);
}
#front-page .fp-feature-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: rgba(255,255,255,0.015);
  padding: clamp(18px, 2vw, 26px);
}
#front-page .fp-feature-title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500; font-size: 21px; letter-spacing: 0.01em;
  color: var(--t1); margin: 0 0 10px;
}
#front-page .fp-feature-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px; line-height: 1.7; color: var(--t2); margin: 0;
}

/* MCP / agentic block — gold-tinted highlight panel */
#front-page .fp-mcp {
  border: 1px solid rgba(200,168,78,0.3); border-radius: var(--radius);
  background:
    radial-gradient(ellipse 70% 100% at 0% 0%, rgba(200,168,78,0.07) 0%, transparent 70%);
  padding: clamp(24px, 3.4vw, 44px);
}
#front-page .fp-mcp .fp-section-title { max-width: 760px; }
#front-page .fp-mcp-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px; line-height: 1.85; color: var(--t2);
  max-width: 760px; margin: 18px 0 0;
}

/* Private Beta tiers */
#front-page .fp-beta {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 20px); align-items: stretch;
}
#front-page .fp-beta-tier {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: rgba(255,255,255,0.015);
  padding: clamp(20px, 2.2vw, 28px);
  display: flex; flex-direction: column;
}
#front-page .fp-beta-tier-featured { border-color: rgba(200,168,78,0.45); }
#front-page .fp-beta-tag {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--gold-hi); margin-bottom: 12px;
}
#front-page .fp-beta-name {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500; font-size: 24px; color: var(--t1); margin: 0 0 12px;
}
#front-page .fp-beta-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px; line-height: 1.7; color: var(--t2); margin: 0;
}

/* Coming Feature — intentionally minimal */
#front-page .fp-coming { display: flex; flex-wrap: wrap; gap: 14px; }
#front-page .fp-coming-item {
  border: 1px dashed rgba(200,168,78,0.4); border-radius: var(--radius);
  background: rgba(255,255,255,0.015);
  padding: 16px 24px;
}
#front-page .fp-coming-name {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500; font-size: 20px; color: var(--t1); margin: 0;
}
/* Map-first launch — "Coming soon" sub-label on each Coming Feature item. */
#front-page .fp-coming-soon {
  margin-top: 8px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--gold);
}
/* The AI Assistant Chat item opens the "coming soon" modal, so it reads as
   interactive. The Local Space Map item stays a plain (non-clickable) card. */
#front-page .fp-coming-item-ai { cursor: pointer; transition: border-color .18s, background .18s; }
#front-page .fp-coming-item-ai:hover { border-color: rgba(200,168,78,0.7); background: rgba(255,255,255,0.03); }

/* AI "coming soon" modal — mirrors the #chart-modal pattern (z-index 9999,
   .open toggles display). On-demand only; pure presentational. */
#ai-coming-soon-modal {
  position: fixed; inset: 0; z-index: 9999;
  display: none; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .2s ease;
}
#ai-coming-soon-modal.open { display: flex; opacity: 1; }
#ai-coming-soon-modal .ai-cs-backdrop {
  position: absolute; inset: 0;
  background: rgba(4, 6, 14, 0.78);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  cursor: pointer;
}
#ai-coming-soon-modal .ai-cs-frame {
  position: relative;
  width: min(90vw, 420px);
  background: var(--bg-panel);
  border: 1px solid var(--gold-dim);
  border-radius: 14px;
  box-shadow:
    0 36px 110px rgba(0,0,0,0.55),
    0 0 90px rgba(200,168,78,0.07),
    0 0 0 1px var(--border) inset;
  padding: 28px 28px 24px;
  text-align: center;
}
#ai-coming-soon-modal .ai-cs-close {
  position: absolute; top: 12px; right: 12px;
  width: 30px; height: 30px;
  background: transparent; color: var(--t2);
  border: 1px solid var(--border); border-radius: 8px;
  font-size: 11px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: color .18s, border-color .18s, background .18s;
}
#ai-coming-soon-modal .ai-cs-close:hover { color: var(--t1); background: rgba(255,255,255,0.06); }
#ai-coming-soon-modal .ai-cs-title {
  font-family: 'Cormorant Garamond', serif;
  font-size: 25px; font-weight: 400; letter-spacing: 0.03em;
  color: var(--t1); margin: 2px 0 12px;
}
#ai-coming-soon-modal .ai-cs-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12.5px; line-height: 1.65; color: var(--t2); margin: 0 0 22px;
}
#ai-coming-soon-modal .ai-cs-ok {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--gold-hi); background: rgba(200,168,78,0.08);
  border: 1px solid var(--gold-dim); border-radius: 8px;
  padding: 10px 24px; cursor: pointer;
  transition: color .18s, border-color .18s, background .18s;
}
#ai-coming-soon-modal .ai-cs-ok:hover { border-color: rgba(200,168,78,0.5); background: rgba(200,168,78,0.14); }

/* About the Creator */
#front-page .fp-about {
  display: flex; gap: clamp(20px, 3vw, 40px); align-items: center;
}
#front-page .fp-about-photo {
  flex: 0 0 auto;
  width: clamp(96px, 12vw, 140px); height: clamp(96px, 12vw, 140px);
  border-radius: 50%;
  border: 1px solid rgba(200,168,78,0.4);
  background:
    radial-gradient(ellipse 80% 80% at 50% 30%, rgba(200,168,78,0.12) 0%, transparent 72%),
    rgba(255,255,255,0.02);
  display: flex; align-items: center; justify-content: center;
}
#front-page .fp-about-photo-glyph { font-size: clamp(30px, 4vw, 44px); color: var(--gold-hi); }
/* Creator photo — fills the existing gold-bordered circle; the source
   asset is a 420px square (retina for the 96-140px container). */
#front-page .fp-about-img {
  width: 100%; height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
/* Creator name — byline under the section title, next to the photo. */
#front-page .fp-about-name {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--gold-hi); margin-top: 12px;
}
#front-page .fp-about-text { flex: 1 1 auto; }
#front-page .fp-about-desc {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px; line-height: 1.85; color: var(--t2);
  max-width: 680px; margin: 16px 0 0;
}

/* Front-page hero badge under the CTA */
#front-page .fp-hero-badge {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--t3); margin-top: 18px;
}

/* Landing sections collapse to one column on narrow viewports — matches
   the hero's single-column breakpoint. */
@media (max-width: 860px) {
  #front-page .fp-features,
  #front-page .fp-beta { grid-template-columns: 1fr; }
  #front-page .fp-about { flex-direction: column; align-items: flex-start; text-align: left; }
}

.charts-save-card.disabled { opacity: 0.5; pointer-events: none; }

/* ══════════════════════════════════════════════════════════════════
   THEME — Light mode (global)
   ──────────────────────────────────────────────────────────────────
   The token block below lives on the document root, so every
   element that already reads its colors from CSS variables
   (--bg, --t1, --gold, etc.) re-themes automatically across
   every page: Front, Dashboard, Signup, Login, Account, Charts,
   Preferences, Subscription, Map — and any future page that
   follows the same token vocabulary.

   Dark-chrome islands — #header, #auth-topbar, #account-menu —
   re-scope the dark-theme values back onto themselves further
   down in this block, so those three surfaces stay a deep navy
   "top chrome / popover" layer over the light body. That
   mirrors the system already in use on .fp-nav (dark strip over
   cream body).

   A small number of hard-coded rgba(255,255,255,...) tints in
   card/input/row rules need explicit ink-tinted counterparts;
   those follow the token block below.
══════════════════════════════════════════════════════════════════ */
html[data-theme="light"] {
  /* color-scheme flips native controls (scrollbars, date/time
     pickers, focus rings) so the browser renders them in light
     rather than dark mode. */
  color-scheme: light;

  /* Warm ivory page + cream paper surfaces. */
  --bg:           #F4EEDD;
  --bg-panel:     rgba(253, 248, 234, 0.96);
  --bg-hud:       rgba(253, 248, 234, 0.92);

  /* Subtle ink-tinted borders instead of white-alpha on dark. */
  --border:       rgba(28, 24, 48, 0.12);
  --border-hi:    rgba(28, 24, 48, 0.28);

  /* Slightly deepened gold so it stays legible on cream. */
  --gold:         #A8833A;
  --gold-hi:      #8A6920;
  --gold-dim:     rgba(168, 131, 58, 0.22);

  /* Navy-ink text stack — cohesive with the dark theme's hue
     family, just inverted in value. */
  --t1:           #1C1830;
  --t2:           #4E4858;
  --t3:           #7C7684;
  --t4:           #B2ADB8;

  /* Top-chrome — deep walnut/espresso. Dark enough to read as
     strong header chrome; warm enough to belong to the cream
     theme's hue family instead of landing as an unrelated near-
     black strip above the page. */
  --chrome-bg:    linear-gradient(180deg,
                    rgba(48, 36, 20, 0.97) 0%,
                    rgba(30, 22, 14, 0.95) 100%);
}

/* ══════════════════════════════════════════════════════════════════
   THEME — Atlas Blue (global)
   ──────────────────────────────────────────────────────────────────
   Third member of the AstroCarto theme family. Inspired by the
   Atlas card's Europe-map reference: rich sapphire/cobalt page
   + darker midnight chrome + warm cream text + the same gold
   system shared with Dark mode (so the gold-meridian aesthetic
   reads identically on either theme). color-scheme stays `dark`
   because this is a dark-variant theme — native controls render
   in dark mode. All existing rules that use the token vocabulary
   auto-re-theme; no per-element overrides required beyond the
   page decorative washes below.
══════════════════════════════════════════════════════════════════ */
html[data-theme="atlas-blue"] {
  color-scheme: dark;

  /* Rich sapphire page + lifted cobalt card surfaces. */
  --bg:           #0C2247;
  --bg-panel:     rgba(18, 40, 78, 0.94);
  --bg-hud:       rgba(18, 40, 78, 0.90);

  /* Warm-tan alpha borders — brass-on-sapphire feel instead of
     white-on-dark. Matches the Atlas card's gold identity. */
  --border:       rgba(255, 220, 180, 0.11);
  --border-hi:    rgba(255, 220, 180, 0.24);

  /* Gold system is identical to Dark mode — the premium bright
     gold is the shared AstroCarto signature across both dark
     themes. */
  --gold:         #C8A84E;
  --gold-hi:      #F5D060;
  --gold-dim:     rgba(200, 168, 78, 0.22);

  /* Warm cream text stack — a touch warmer than Dark mode's pure
     cream so it reads luxurious on sapphire rather than clinical. */
  --t1:           #F6EFDD;
  --t2:           #C8C6D6;
  --t3:           #8A90A8;
  --t4:           #52576B;

  /* Top-chrome — deep midnight sapphire, clearly darker than the
     #0C2247 page base so the header reads as a strong strip
     rather than blending flat into the page. */
  --chrome-bg:    linear-gradient(180deg,
                    rgba(5, 15, 34, 0.97) 0%,
                    rgba(3, 10, 22, 0.95) 100%);
}

/* Dark-chrome islands — re-scope the dark-theme palette back onto
   the top-chrome + popover surfaces so their hardcoded dark bgs
   and their token-driven children (logo, buttons, pills, menu
   items) keep reading bright-gold on deep-navy even when the app
   is in light mode. This is the same pattern already used by
   .fp-nav — one consistent "dark chrome over light content"
   system across every page. .auth-shell-nav (login / signup
   shell) is grouped here too so its brand + Back pill inherit
   the same treatment. */
html[data-theme="light"] #header,
html[data-theme="light"] #auth-topbar,
html[data-theme="light"] #account-menu,
html[data-theme="light"] .auth-shell-nav {
  --t1:        #F6F4EF;
  --t2:        #C4C2D0;
  --t3:        #7A7888;
  --t4:        #44424F;
  --gold:      #C8A84E;
  --gold-hi:   #F5D060;
  --gold-dim:  rgba(200, 168, 78, 0.22);
  --border:    rgba(255, 255, 255, 0.09);
  --border-hi: rgba(255, 255, 255, 0.22);
}

/* Page background wash — replace the dark radial gradients with a
   softer cream-and-gold dusk. Atlas card gold/violet remains, per
   the "do not touch Atlas card composition" constraint. */
html[data-theme="light"] #front-page {
  background-image:
    radial-gradient(ellipse 80% 50% at 50% 0%,
      rgba(200, 168, 78, 0.18) 0%, transparent 62%),
    radial-gradient(ellipse 60% 50% at 50% 100%,
      rgba(168, 131, 58, 0.12) 0%, transparent 72%);
}
html[data-theme="light"] .dashboard-page {
  background-image:
    radial-gradient(ellipse 70% 40% at 18% 0%,
      rgba(200, 168, 78, 0.14) 0%, transparent 58%),
    radial-gradient(ellipse 60% 50% at 82% 100%,
      rgba(168, 131, 58, 0.09) 0%, transparent 70%);
}

/* Atlas Blue — replace the dark-theme dusk wash (gold + violet)
   with a sapphire-appropriate atmosphere: a gold glow top/centre
   plus a blue-mist accent from the opposite corner. Keeps the
   atmospheric depth the reference image shows without reading as
   purple dusk over a sapphire base. */
html[data-theme="atlas-blue"] #front-page {
  background-image:
    radial-gradient(ellipse 80% 50% at 50% 0%,
      rgba(200, 168, 78, 0.12) 0%, transparent 62%),
    radial-gradient(ellipse 60% 50% at 50% 100%,
      rgba(80, 130, 200, 0.18) 0%, transparent 72%);
}
html[data-theme="atlas-blue"] .dashboard-page {
  background-image:
    radial-gradient(ellipse 70% 40% at 18% 0%,
      rgba(200, 168, 78, 0.10) 0%, transparent 58%),
    radial-gradient(ellipse 60% 50% at 82% 100%,
      rgba(80, 130, 200, 0.14) 0%, transparent 70%);
}

/* Decorative star + constellation overlays were white-on-dark;
   they add nothing on cream and would only read as faint noise. */
html[data-theme="light"] #front-page .fp-stars,
html[data-theme="light"] #front-page .fp-constellation {
  opacity: 0;
}

/* Front-page sigil wheel — on the dark theme the orbits, planet
   dots, and SVG compass read clearly because gold has high
   contrast against deep navy. On cream the original alphas
   (0.11–0.16) make rings nearly invisible, the pale-gold dots
   blend in, and the 0.6/0.8 SVG stroke-widths render sub-pixel
   and vanish. This block boosts only the three visibility knobs
   without touching orbit radii, animation, layout, or markup. */
html[data-theme="light"] #front-page .fp-sigil-orbit-1 {
  border-color: rgba(138, 105, 32, 0.38);
}
html[data-theme="light"] #front-page .fp-sigil-orbit-2 {
  border-color: rgba(138, 105, 32, 0.30);
}
html[data-theme="light"] #front-page .fp-sigil-orbit-3 {
  border-color: rgba(138, 105, 32, 0.32);
}
html[data-theme="light"] #front-page .fp-sigil-orbit-4 {
  border-color: rgba(138, 105, 32, 0.38);
}

/* Planet dots — swap the dark-theme bright golds for deepened
   hues so each dot reads against cream, and soften the glow so
   they don't produce a halo on a light bg. */
html[data-theme="light"] #front-page .fp-sigil-dot-sun {
  background: #B5902E;
  box-shadow: 0 0 10px rgba(181, 144, 46, 0.45);
}
html[data-theme="light"] #front-page .fp-sigil-dot-venus {
  background: #9C7E2E;
  box-shadow: 0 0 10px rgba(156, 126, 46, 0.40);
}
html[data-theme="light"] #front-page .fp-sigil-dot-mars {
  background: #8B3D39;
  box-shadow: 0 0 10px rgba(139, 61, 57, 0.45);
}
html[data-theme="light"] #front-page .fp-sigil-dot-jupiter {
  background: #7C6828;
  box-shadow: 0 0 10px rgba(124, 104, 40, 0.40);
}

/* SVG strokes — bump the compass rings + spokes' stroke-width via
   CSS so the lines are visibly present rather than sub-pixel. The
   two circles that carry stroke="currentColor" + the 12 spokes
   are all targeted here; the inner r=2 navy pupil has no stroke
   attribute so stroke-width alone doesn't draw anything on it. */
html[data-theme="light"] #front-page .fp-sigil-center line,
html[data-theme="light"] #front-page .fp-sigil-center circle {
  stroke-width: 1.4;
}

/* Form inputs: flip from dark-on-dark to ink-on-cream. Scope is
   global (not page-scoped) so signup / login / charts / account
   forms all theme correctly. */
html[data-theme="light"] .fp-input {
  background: rgba(28, 24, 48, 0.04);
  color: var(--t1);
  color-scheme: light;
}
html[data-theme="light"] .fp-input::placeholder {
  color: var(--t4);
}
html[data-theme="light"] .fp-input:focus {
  background: rgba(168, 131, 58, 0.08);
  border-color: rgba(168, 131, 58, 0.50);
}

/* Form card + nav pill glass surfaces — retune the subtle
   rgba(255,255,255,...) fills to ink-tinted cream. */
html[data-theme="light"] #front-page .fp-left .fp-form {
  background: linear-gradient(180deg,
    rgba(253, 248, 234, 0.70) 0%,
    rgba(253, 248, 234, 0.40) 100%);
  border-color: var(--border);
}

/* Primary CTA — keeps a gold fill, but over cream the gradient
   needs a touch more body. Scope is global (not page-scoped) so
   every .fp-btn instance (front page, auth forms, charts save
   card, dashboard CTAs that reuse .fp-btn) themes consistently. */
html[data-theme="light"] .fp-btn {
  background: linear-gradient(135deg,
    rgba(168, 131, 58, 0.28) 0%, rgba(168, 131, 58, 0.14) 100%);
  border-color: rgba(168, 131, 58, 0.55);
  color: var(--gold-hi);
}
html[data-theme="light"] .fp-btn:hover {
  background: linear-gradient(135deg,
    rgba(168, 131, 58, 0.38) 0%, rgba(168, 131, 58, 0.22) 100%);
  border-color: rgba(138, 105, 32, 0.75);
  color: #6A4F18;
  box-shadow: 0 0 28px rgba(168, 131, 58, 0.18);
}
/* Top-row consistency — unify the Front page's .fp-nav with the
   Dashboard's #auth-topbar in light mode. Both pages get the same
   dark gradient strip with a gold-dim bottom edge. Body content
   below stays cream on both, so the visual system reads as "dark
   top strip over cream content" across the two pages — one
   intentional treatment, not two competing ones.

   Mechanism: scope the dark-theme CSS variables onto .fp-nav
   itself. Because vars cascade to descendants, every nav child
   (logo, wordmark, Log-in / Sign-up pills) reads the dark
   palette automatically — so .fp-nav-link-solid's own gold
   gradient + .fp-nav-link's hover colors all resolve correctly
   without per-element overrides. */
html[data-theme="light"] #front-page .fp-nav {
  --t1:       #F6F4EF;
  --t2:       #C4C2D0;
  --t3:       #7A7888;
  --t4:       #44424F;
  --gold:     #C8A84E;
  --gold-hi:  #F5D060;
  --gold-dim: rgba(200, 168, 78, 0.22);
  --border:   rgba(255, 255, 255, 0.09);
  /* Background now comes from the root-level --chrome-bg override
     for light mode (deep walnut); border stays gold-dim as set
     above. No per-.fp-nav background declaration needed. */
}

/* Dashboard cards — base surface uses rgba(255,255,255,...) on
   dark. Retune to a gentle cream gradient tinted with ink for
   depth. The :not(.dash-card-atlas) filter is load-bearing: the
   Atlas card carries both .dash-card and .dash-card-atlas, and
   without the filter this (0,3,0) selector beats .dash-card-atlas
   (0,1,0) and replaces its gold/violet hero gradient with cream —
   which then bleeds through the Europe-map image mask's faded
   edges, producing the "light wash on the sides" effect. */
html[data-theme="light"] .dashboard-page .dash-card:not(.dash-card-atlas) {
  background: linear-gradient(180deg,
    rgba(253, 248, 234, 0.85) 0%,
    rgba(253, 248, 234, 0.55) 100%);
}

/* Atlas card — re-assert the dark hero treatment in light mode
   with an OPAQUE navy base stacked behind the gold/violet +
   rgba-white highlight layers. The opaque base is the critical
   piece: without it, every layer above is semi-transparent so
   the cream page shows through, especially at the Europe-map
   image's edge-masked fades. Composition, border, padding,
   image, and text-color pins below are all untouched. */
html[data-theme="light"] .dashboard-page .dash-card-atlas {
  background:
    linear-gradient(135deg,
      rgba(200, 168, 78, 0.16) 0%,
      rgba(40, 28, 72, 0.22) 100%),
    linear-gradient(180deg,
      rgba(255, 255, 255, 0.035) 0%,
      rgba(255, 255, 255, 0.012) 100%),
    #0B102A;
  border-color: rgba(200, 168, 78, 0.32);
}
html[data-theme="light"] .dashboard-page .dash-card-atlas:hover {
  border-color: rgba(200, 168, 78, 0.46);
}
html[data-theme="light"] .dashboard-page .dashboard-grid > .dash-card {
  background: linear-gradient(180deg,
    rgba(255, 252, 241, 0.92) 0%,
    rgba(253, 248, 234, 0.65) 100%);
  border-color: rgba(168, 131, 58, 0.22);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    0 1px 2px rgba(28, 24, 48, 0.06);
}
html[data-theme="light"] .dashboard-page .dashboard-grid > .dash-card:hover {
  border-color: rgba(168, 131, 58, 0.40);
  background: linear-gradient(180deg,
    rgba(255, 254, 247, 0.95) 0%,
    rgba(253, 248, 234, 0.75) 100%);
}

/* Per-theme card artwork is painted via background-image on the
   grid-card ::after — the six image URLs live together in the
   base artwork block above so there are no further per-theme
   overrides for the card decoration in this file. */

/* Row separators inside cards were white-alpha on dark — needs ink. */
html[data-theme="light"] .dashboard-page .dash-row {
  border-bottom-color: rgba(28, 24, 48, 0.10);
}

/* Chart rows — shared between Dashboard and Charts page. Global
   scope so both surfaces theme identically. */
html[data-theme="light"] .chart-row {
  background: rgba(253, 248, 234, 0.55);
}
html[data-theme="light"] .chart-row:hover {
  background: rgba(168, 131, 58, 0.08);
}
html[data-theme="light"] .chart-row.chart-row-active {
  background: rgba(168, 131, 58, 0.10);
}

/* Atlas card stays as-is (dark gold/violet hero); only make sure
   its inner text doesn't inherit the light ink colors — pin it to
   the cream text family so the hero still reads correctly. */
html[data-theme="light"] .dashboard-page .dash-card-atlas .dash-card-title,
html[data-theme="light"] .dashboard-page .dash-card-atlas .eyebrow {
  color: #F5D060;
}
html[data-theme="light"] .dashboard-page .dash-card-atlas .dash-card-desc {
  color: #C4C2D0;
}
html[data-theme="light"] .dashboard-page .dash-card-atlas .dash-cta-btn {
  color: #F5D060;
  border-color: #F5D060;
}

/* ══════════════════════════════════════════════════════════════════
   MAP PAGE — Light-mode overrides
   ──────────────────────────────────────────────────────────────────
   Slice M3: the light theme's basemap is now the real MapTiler
   `landscape` style (selected in app.js), so the old gentle sepia
   tint on .tile-carto is gone — the natural style needs no filter.

   The map #header stays dark (dark-chrome island, scoped above),
   so buttons/logo inside it keep their existing treatment. The
   side panel, statusbar, click-hint, and frame strips all read
   --bg-panel / --bg-hud / --t1 etc. and re-theme automatically.
══════════════════════════════════════════════════════════════════ */
html[data-theme="light"] .leaflet-control-attribution {
  background: rgba(253, 248, 234, 0.92) !important;
  color: #23304a !important;
}
html[data-theme="light"] .leaflet-control-attribution a {
  color: #1565c0 !important;
}

/* #header drops a box-shadow 0 8px 32px rgba(0,0,0,0.60) below
   itself as an elevation cue. In dark mode that lands on a dark
   frame-top and is invisible; in light mode it lands on the
   cream frame-top and renders as a visible dark band under the
   chrome (muddying the symbols rendered in that upper gutter).
   Same blur also bleeds a subtler dark tint into the upper edges
   of the left/right side gutters. Retune to an ink-tinted soft
   shadow at 0.12 alpha — still registers as "lifted header" but
   doesn't stain the cream surface below. */
html[data-theme="light"] #header {
  box-shadow:
    0 1px 0 0 rgba(200, 168, 78, 0.14) inset,
    0 8px 32px rgba(28, 24, 48, 0.12);
}

/* Map popup (line label / tooltip) — swap the heavy black drop
   shadow for an ink-tinted elevation in light mode so the popup
   still reads as a floating premium surface on the cream map
   without casting a harsh black halo. Background + text contrast
   is already fixed via the token-driven base rule. */
html[data-theme="light"] .leaflet-popup-content-wrapper {
  box-shadow: 0 20px 56px rgba(28, 24, 48, 0.24) !important;
}

/* Row separators inside the side panel were white-alpha on dark;
   retint to a soft ink on cream so they still delineate rows
   without hard lines. */
html[data-theme="light"] .drow {
  border-bottom-color: rgba(28, 24, 48, 0.07);
}

/* Modals — dark backdrop + navy frame shadow become cream
   backdrop + ink-tinted shadow. Frame bg uses var(--bg-panel)
   which auto-themes; only the backdrop color + shadow need to
   shift. */
html[data-theme="light"] .chart-modal-backdrop {
  background: rgba(244, 238, 221, 0.80);
}
html[data-theme="light"] .chart-modal-frame {
  box-shadow:
    0 30px 100px rgba(28, 24, 48, 0.18),
    0 0 80px rgba(168, 131, 58, 0.08);
}
html[data-theme="light"] .no-chart-backdrop {
  background: rgba(244, 238, 221, 0.75);
}

/* Slice C6: Current Chart modal light-theme readability — match the
   .chart-modal-frame light pattern. Cream backdrop and ink/gold-
   tinted shadow replace the dark defaults so the modal reads
   correctly on the warm-ivory page. Frame bg already auto-themes
   via var(--bg-panel); text inside (var(--t1)/--t2/--t3) and the
   .fp-* form controls already have their own light overrides. */
html[data-theme="light"] .cc-modal-backdrop {
  background: rgba(244, 238, 221, 0.80);
}
html[data-theme="light"] .cc-modal-frame {
  box-shadow:
    0 30px 100px rgba(28, 24, 48, 0.18),
    0 0 80px rgba(168, 131, 58, 0.08);
}

/* ══════════════════════════════════════════════════════════════════
   ACCOUNT MENU — Theme toggle row (Dark | Light)
   Matches the existing .acct-menu vocabulary. Two inline pills
   sit under a tiny uppercase label. The .is-active pill gets the
   gold-highlight treatment already used elsewhere in the menu.
══════════════════════════════════════════════════════════════════ */
.acct-menu-theme-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px 10px;
}
.acct-menu-theme-label {
  flex: 0 0 auto;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--t3);
}
.acct-menu-theme-opts {
  flex: 1 1 auto;
  display: inline-flex; gap: 4px; justify-content: flex-end;
}
.acct-menu-theme-opt {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--t2);
  font-family: inherit;
  font-size: 10.5px; letter-spacing: 0.10em;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.acct-menu-theme-opt:hover {
  border-color: var(--gold-dim);
  color: var(--gold-hi);
}
.acct-menu-theme-opt.is-active {
  background: rgba(200, 168, 78, 0.14);
  border-color: var(--gold-hi);
  color: var(--gold-hi);
}

/* ══════════════════════════════════════════════════════════════════
   FRONT-PAGE top-row theme toggle
   ──────────────────────────────────────────────────────────────────
   Compact two-pill group that slots to the LEFT of the Log in /
   Sign up buttons inside .fp-nav. Shares the [data-theme-set]
   contract with the account-menu toggle — a single global click
   delegation in app.js handles both surfaces. The .fp-nav already
   scopes dark-theme CSS variables, so these pills always render
   with bright-gold on deep-navy regardless of app theme.
══════════════════════════════════════════════════════════════════ */
.fp-nav-end {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.fp-theme-toggle {
  display: inline-flex;
  align-items: center;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 999px;
  gap: 2px;
}
.fp-theme-opt {
  background: transparent;
  border: 0;
  color: var(--t3);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.fp-theme-opt:hover {
  color: var(--gold-hi);
}
.fp-theme-opt.is-active {
  background: rgba(200, 168, 78, 0.14);
  color: var(--gold-hi);
}

@media (max-width: 520px) {
  .fp-nav-end { gap: 6px; }
  .fp-theme-toggle { padding: 2px; }
  .fp-theme-opt {
    font-size: 9.5px; letter-spacing: 0.18em;
    padding: 4px 10px;
  }
}

/* ── LEGAL PAGES + FOOTER LEGAL LINKS (map-first launch, L1-B) ──────
   privacy.html / terms.html / astrology-disclaimer.html are standalone
   static pages reusing the .auth-page.active dark shell (the
   reset-password.html pattern: full-viewport, internal scroll). The
   .legal-doc block gives them a readable prose measure in the app's
   type system; .fp-foot-links adds the legal nav to the front-page
   footer (only .fp-foot-right is hidden on mobile, so the links stay
   visible; flex-wrap lets them wrap under the brand line). */
.fp-foot { flex-wrap: wrap; }
.fp-foot-links {
  display: flex; flex-wrap: wrap; gap: 14px;
}
.fp-foot-links a {
  color: var(--t3); text-decoration: none;
  transition: color .18s;
}
.fp-foot-links a:hover { color: var(--gold-hi); }

.legal-doc {
  width: 100%; max-width: 720px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12.5px; line-height: 1.75;
  color: var(--t2); text-align: left;
}
.legal-doc h1 {
  font-family: 'Cormorant Garamond', serif;
  font-size: clamp(26px, 4vw, 34px); font-weight: 300;
  letter-spacing: 0.03em; color: var(--t1);
  margin: 0 0 8px; text-align: center;
}
.legal-meta {
  text-align: center;
  font-size: 9.5px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--t3); margin-bottom: 36px;
}
.legal-doc h2 {
  font-family: 'Cormorant Garamond', serif;
  font-size: 21px; font-weight: 500; letter-spacing: 0.01em;
  color: var(--t1); margin: 34px 0 10px;
}
.legal-doc p  { margin: 0 0 12px; }
.legal-doc ul { margin: 0 0 12px; padding-left: 20px; }
.legal-doc li { margin-bottom: 6px; }
.legal-doc strong { color: var(--t1); font-weight: 500; }
.legal-doc a { color: var(--gold-hi); text-decoration: none; }
.legal-doc a:hover { text-decoration: underline; }
.legal-table {
  width: 100%; border-collapse: collapse;
  margin: 0 0 12px; font-size: 11.5px;
}
.legal-table th, .legal-table td {
  border: 1px solid var(--border);
  padding: 8px 10px; vertical-align: top; text-align: left;
}
.legal-table th { color: var(--t1); font-weight: 500; }
.legal-foot {
  margin: 44px 0 8px; padding-top: 18px;
  border-top: 1px solid var(--border);
  display: flex; flex-wrap: wrap; gap: 16px; justify-content: center;
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
}
.legal-foot a { color: var(--t3); text-decoration: none; transition: color .18s; }
.legal-foot a:hover { color: var(--gold-hi); }

/* Signup legal notice — static copy under the Create-account button. */
.signup-legal-note {
  margin-top: 10px;
  font-size: 10.5px; line-height: 1.6; color: var(--t3);
  text-align: center;
}
.signup-legal-note a { color: var(--gold-hi); text-decoration: none; }
.signup-legal-note a:hover { text-decoration: underline; }
