/* ============================================================
 * Graph views
 * The 24-hour and year graph boxes, their legends, and the golden-hour/twilight layer-toggle checkboxes.
 * ============================================================ */
/* ---------- Toggle Controls ---------- */
.layer-toggle{
  display:inline-flex; align-items:center; gap:5px; font-size:12.5px; color:var(--ink-dim); cursor:pointer; margin-left:4px;
  min-height:24px; /* WCAG 2.5.8: 24x24 minimum touch target -- the label's own box, not just the checkbox glyph */
}
.layer-toggle input{accent-color:var(--gold); cursor:pointer; width:15px; height:15px; flex:none;}
/* An overlay whose data cannot apply to the moment being shown -- SkyView's Aurora outside the
   nowcast's own window. Greyed and not clickable, with the reason on the label's title, which is
   quieter than a line of status text repeating itself on every render. Kept above 4.5:1 against
   --bg-panel deliberately: WCAG exempts disabled controls, but a control you can still READ is the
   point here -- it has to say what it is in order to explain why it is off. */
/* Still fully clickable: this greys to say "there is nothing to draw for this moment", not "you may
   not touch this". The tick is a preference that outlasts the moment on screen, so the control keeps
   its normal cursor and tab order. --ink-faint clears 4.5:1 against --bg-panel in all three themes,
   which matters more here than usual -- reading the label is how you find out why nothing shows. */
.layer-toggle.is-unavailable{ color:var(--ink-faint); }
.layer-toggle.is-unavailable input{ opacity:0.6; }

/* ---------- Graph view ---------- */
.graph-box{
  position:relative;
  background:var(--bg-panel); border:1px solid var(--line-soft); border-radius:var(--radius); padding:18px;
}
/* Every graph legend site-wide is horizontally centered by default -- standing convention, see
   CLAUDE.md's "Per-tab structure" section. The old .centered modifier is now redundant (every
   .graph-legend gets this regardless) but harmless where it still appears in HTML. */
.graph-legend{display:flex; justify-content:center; gap:18px; margin-top:12px; flex-wrap:wrap;}
.legend-item{display:flex; align-items:center; gap:7px; font-size:12px; color:var(--ink-dim);}
.legend-swatch{width:12px; height:12px; border-radius:3px; border:1px solid var(--ink-faint);}
.legend-line{display:inline-block; width:18px; height:2px; border-radius:1px; vertical-align:middle;}
.legend-line-dashed{display:inline-block; width:18px; height:0; border-top:2px dashed var(--ink-faint); vertical-align:middle;}

/* ---------- "Open in NovelEarth" link, overlaid in a corner of a map that also has its own
   element on NovelEarth's shared big map (currently the World Map and Aurora Map) ---------- */
.novelearth-link-badge{
  position:absolute; top:10px; left:10px; z-index:5;
  display:inline-flex; align-items:center; gap:4px;
  background:var(--bg-panel); border:1px solid var(--line-soft); border-radius:999px;
  padding:5px 12px; font-size:11.5px; font-weight:600; color:var(--ink-dim);
  text-decoration:none; box-shadow:0 2px 8px rgba(0,0,0,0.3);
}
.novelearth-link-badge:hover{ color:var(--gold-text); border-color:var(--gold-text); }

/* ---------- Gradient legend (a continuous color-scale bar, e.g. aurora probability) ---------- */
.gradient-legend{ max-width:420px; margin:10px auto 0; }
.gradient-legend-bar{ height:14px; border-radius:7px; border:1px solid var(--ink-faint); }
.gradient-legend-ticks{ display:flex; justify-content:space-between; margin-top:4px; font-size:11px; color:var(--ink-faint); font-family:var(--font-mono); }
.gradient-legend-title{ width:100%; text-align:center; margin-top:4px; font-size:11px; color:var(--ink-faint); font-family:var(--font-mono); }

/* ---------- Bortle legend (the Light Pollution map/overlay's own 9 discrete Bortle-class
   swatches, connected into one strip instead of nine separate labeled swatches) -- same
   sizing/spacing as .gradient-legend above, but stepped solid colors rather than a continuous
   gradient, since Bortle classes are genuinely discrete steps, not a smooth scale (matches how
   the map itself renders them -- see 14-darksky-map.js's own colorForALR comment for why that's a
   hard step too, not a blend). overflow:hidden on the bar clips the swatches' own flush shared
   edges into one rounded-pill outline without rounding each individual square -- the numbers below
   are the class scale itself; the full "Class N (name)" text remains one hover away on the map,
   or in this page's own Key Definitions. */
.bortle-legend{ max-width:420px; margin:10px auto 0; }
.bortle-legend-bar{ display:flex; height:14px; border-radius:7px; overflow:hidden; border:1px solid var(--ink-faint); }
.bortle-legend-bar span{ flex:1; }
.bortle-legend-ticks{ display:flex; margin-top:4px; font-size:11px; color:var(--ink-faint); font-family:var(--font-mono); }
.bortle-legend-ticks span{ flex:1; text-align:center; }
.bortle-legend-title{ width:100%; text-align:center; margin-top:4px; font-size:11px; color:var(--ink-faint); font-family:var(--font-mono); }
/* Pointer-follows-legend highlight: hovering the map lights up the Bortle class at that point (see
   14-darksky-map.js's App.highlightBortleLegendClass, called by both the Dark Skies tab and
   NovelEarth). The unhovered swatches dim rather than the active one brightening -- the bar's colors
   ARE the data, so lightening one would misrepresent its class color, while dimming the rest keeps
   every swatch's hue honest. --gold-text (not --gold) for the outline, per the contrast rule in
   CLAUDE.md: --gold fails AA as a border color on Light theme's panels. */
.bortle-legend.has-active .bortle-legend-bar span{ opacity:.35; transition:opacity .12s ease; }
.bortle-legend.has-active .bortle-legend-bar span.is-active{ opacity:1; box-shadow:inset 0 0 0 2px var(--gold-text); }
.bortle-legend.has-active .bortle-legend-ticks span{ opacity:.45; }
.bortle-legend.has-active .bortle-legend-ticks span.is-active{ opacity:1; color:var(--gold-text); font-weight:700; }
@media (prefers-reduced-motion: reduce){
  .bortle-legend.has-active .bortle-legend-bar span{ transition:none; }
}

/* ---------- Fullscreen (a map's own controls + graph-box, via maplibregl.FullscreenControl added
   in that map's own JS) -- formatted identically to NovelEarth's own fullscreen mode
   (novelearth/css/01-novelearth.css's own "Full screen" section, mirrored here class-for-class
   under generic, non-novelearth-prefixed names): controls float as one translucent panel top-left,
   hover status + legend float bottom-center, the map itself goes full-bleed. -webkit-full-screen
   covers older WebKit (Safari); :fullscreen is the standard, unprefixed pseudo-class every current
   browser supports. ---------- */

/* Stays display:none even in fullscreen now -- App.setupFullscreenControlsCollapse's own
   .map-fs-collapse-label (just below) shows the same tab name, alongside the collapse toggle it
   needs a label next to anyway, so showing this too would just duplicate it. Left in the markup
   rather than deleted since removing it is a bigger, riskier change than just not showing it, and
   nothing has ever depended on this at runtime beyond the (now superseded) fullscreen visibility. */
.map-fs-title{
  display:none; font-family:var(--font-display); font-weight:600; font-size:15px;
  color:var(--ink); margin:0 0 10px;
}
/* Collapse toggle: prepended into .map-fs-controls-overlay by App.setupFullscreenControlsCollapse
   (shared/js/fullscreen-controls-collapse.js) rather than written into the static HTML -- like
   .map-fs-title just above, it only needs to render at all once actually in fullscreen. Lets the
   whole panel below it disappear on a narrow viewport, where the full stack of toggles/date-nav/
   time slider can otherwise eat most of a phone's fullscreen height. Mirrored identically in
   golden-hour/css/07-graph.css -- see that copy's own comment for the reasoning. */
.map-fs-collapse-bar{ display:none; }
.map-fullscreen-target:fullscreen .map-fs-collapse-bar,
.map-fullscreen-target:-webkit-full-screen .map-fs-collapse-bar,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-collapse-bar{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
}
.map-fullscreen-target:fullscreen .map-fs-controls-overlay:not(.is-collapsed) .map-fs-collapse-bar,
.map-fullscreen-target:-webkit-full-screen .map-fs-controls-overlay:not(.is-collapsed) .map-fs-collapse-bar,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-controls-overlay:not(.is-collapsed) .map-fs-collapse-bar{
  margin-bottom:10px;
}
.map-fs-collapse-label{
  font-family:var(--font-display); font-weight:600; font-size:15px; color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.map-fs-collapse-btn{
  flex:none; display:flex; align-items:center; justify-content:center;
  width:28px; height:28px; padding:0; border-radius:50%;
  border:1px solid var(--line-soft); background:var(--bg-panel-2); color:var(--ink-dim);
  cursor:pointer;
}
.map-fs-collapse-btn:hover{ color:var(--ink); border-color:var(--gold-text); }
.map-fs-collapse-btn svg{ width:16px; height:16px; display:block; }
.map-fs-controls-overlay.is-collapsed > *:not(.map-fs-collapse-bar){ display:none; }
.map-fullscreen-target:fullscreen .map-fs-controls-overlay.is-collapsed,
.map-fullscreen-target:-webkit-full-screen .map-fs-controls-overlay.is-collapsed,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-controls-overlay.is-collapsed{
  width:auto; max-height:none; overflow:visible;
}
/* For apps with ONE shared date-nav reused across tabs (Stargaze's own #sharedDateNav) -- that
   shared nav sits outside every map's own fullscreen target, so it becomes unreachable once
   fullscreen opens. A map's own date-nav wrapped in this class exists only to plug that gap, so it
   stays hidden in normal view (where the shared nav is already visible right there on the page)
   and only appears once fullscreen actually opens. display:contents rather than a plain flex/block
   in the fullscreen state keeps its buttons as direct flex items of the surrounding
   .graph-controls row, not a nested box of their own. Apps without a shared cross-tab date-nav
   (Golden Hour) don't need this -- their own per-map date-nav is never a duplicate of anything. */
.map-fs-datenav-only{ display:none; }
.map-fullscreen-target:fullscreen .map-fs-datenav-only,
.map-fullscreen-target:-webkit-full-screen .map-fs-datenav-only,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-datenav-only{ display:contents; }
/* These wrap the controls and the hover-status+legend purely so full screen mode has single
   elements to float as overlays -- in NORMAL (non-fullscreen) view they're invisible to layout
   entirely (display:contents), so wrapping them doesn't change the normal-view page look at all. */
.map-fs-controls-overlay, .map-fs-bottom-stack, .map-fs-legend-overlay{ display:contents; }

.map-fullscreen-target:fullscreen,
.map-fullscreen-target:-webkit-full-screen,

.map-fullscreen-target.maplibregl-pseudo-fullscreen{
  position:relative; background:var(--bg-deep); padding:0; overflow:hidden;
}
/* Both floating panels' own background is always a fixed dark translucent color, with everything
   inside them pinned to Dark theme's own token values unconditionally regardless of which
   light/dark/twilight theme the rest of the site is currently in -- matches NovelEarth's own
   identical choice (see its CSS for the reasoning: any other theme's palette reads as
   wrong/inconsistent against a translucent dark overlay floating over live map imagery). */
.map-fullscreen-target:fullscreen .map-fs-controls-overlay,
.map-fullscreen-target:-webkit-full-screen .map-fs-controls-overlay,
.map-fullscreen-target:fullscreen .map-fs-bottom-stack,
.map-fullscreen-target:-webkit-full-screen .map-fs-bottom-stack,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-controls-overlay,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-bottom-stack{
  --bg-panel:#1B1B1B; --bg-panel-2:#232323; --bg-raised:#2C2C2C;
  --line:#3A3A3A; --line-soft:#2A2A2A;
  --ink:#EDEDED; --ink-dim:#B0B0B0; --ink-faint:#8C8C8C;
  --input-bg:#0A0A0A;
}
.map-fullscreen-target:fullscreen .graph-box,
.map-fullscreen-target:-webkit-full-screen .graph-box,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .graph-box{
  position:absolute; inset:0; padding:0; border:none; border-radius:0; background:none;
}
/* Matched by every map's own *MapCanvasHolder id naming convention, rather than listing each one
   by id here. !important on width/height is required here (unlike NovelEarth's own equivalent
   #novelEarthMapHolder, which has no inline style at all) -- every one of these holders carries its
   own inline style="width:100%; height:520px" for its normal-view fixed height, and an inline style
   always wins over a stylesheet rule for the same property regardless of selector specificity, so
   without !important the holder stays visibly pinned at 520px tall while everything else around it
   goes fullscreen (confirmed directly: computed height stayed "520px" post-fullscreen without this). */
.map-fullscreen-target:fullscreen .graph-box > div[id$="CanvasHolder"],
.map-fullscreen-target:-webkit-full-screen .graph-box > div[id$="CanvasHolder"],
.map-fullscreen-target.maplibregl-pseudo-fullscreen .graph-box > div[id$="CanvasHolder"]{
  position:absolute !important; inset:0 !important; width:100% !important; height:100% !important; border-radius:0;
}
/* The badge's default top-left corner is exactly where the controls overlay floats in full screen
   (see its own rule below) -- moved to the one corner nothing else claims there (top-right is
   MapLibre's own zoom/full-screen controls, bottom-center is .map-fs-bottom-stack) so it stays
   reachable instead of sitting hidden underneath the controls panel. */
.map-fullscreen-target:fullscreen .novelearth-link-badge,
.map-fullscreen-target:-webkit-full-screen .novelearth-link-badge,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .novelearth-link-badge{
  top:auto; left:10px; bottom:10px;
}
/* Below ~600px the centered .map-fs-bottom-stack (status pill + legend) can grow wide/tall enough
   -- a wrapped multi-item legend, or a wide gradient bar like Dark Skies' Bortle scale -- to reach
   into this same bottom-left corner and sit on top of the badge, sometimes hiding it completely.
   There's no corner left to move it to instead (top-right is MapLibre's own zoom/fullscreen
   controls, top-left is .map-fs-controls-overlay, bottom-center is the stack this collides with) --
   so rather than a link that's sometimes unreachable and sometimes invisible depending on which
   map/legend is open, it's hidden here. Normal (non-fullscreen) view is unaffected -- the badge
   sits top-left there instead, with nothing to collide with. */
@media (max-width:600px){
  .map-fullscreen-target:fullscreen .novelearth-link-badge,
  .map-fullscreen-target:-webkit-full-screen .novelearth-link-badge,
  .map-fullscreen-target.maplibregl-pseudo-fullscreen .novelearth-link-badge{
    display:none;
  }
}
/* The distance scale (shared/js/base-map.js's own maplibregl.ScaleControl, bottom-left on every
   map) only collides with the badge above once fullscreen moves that badge down into the SAME
   bottom-left corner (its own rule just above) -- normal view never has this conflict, since the
   badge sits top-left there instead. Pushed up above the badge rather than the reverse, since the
   badge already has an established, deliberate claim on the plain bottom-left corner. */
.map-fullscreen-target:fullscreen .maplibregl-ctrl-bottom-left,
.map-fullscreen-target:-webkit-full-screen .maplibregl-ctrl-bottom-left,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .maplibregl-ctrl-bottom-left{
  bottom:44px;
}

.map-fullscreen-target:fullscreen .map-fs-controls-overlay,
.map-fullscreen-target:-webkit-full-screen .map-fs-controls-overlay,

.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-controls-overlay{
  display:block; position:absolute; top:12px; left:12px; z-index:10;
  width:min(360px, calc(100% - 24px)); max-height:calc(100% - 24px); overflow:visible;
  background:rgba(15,16,22,0.8); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  border:1px solid var(--line-soft); border-radius:var(--radius); padding:12px;
}
.map-fullscreen-target:fullscreen .map-fs-controls-overlay .graph-controls,
.map-fullscreen-target:-webkit-full-screen .map-fs-controls-overlay .graph-controls,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-controls-overlay .graph-controls{
  margin-bottom:0;
}
.map-fullscreen-target:fullscreen .map-fs-controls-overlay .graph-controls + .graph-controls,
.map-fullscreen-target:-webkit-full-screen .map-fs-controls-overlay .graph-controls + .graph-controls,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-controls-overlay .graph-controls + .graph-controls{
  margin-top:10px;
}

/* The hover status and the legend are two SEPARATE floating boxes (not one shared panel) so the
   hover box can come and go on its own without the legend panel resizing/repositioning around it
   -- stacked with a small gap via this shared flex column, which is what's actually
   bottom-center-anchored; each child box below just supplies its own look. */
.map-fullscreen-target:fullscreen .map-fs-bottom-stack,
.map-fullscreen-target:-webkit-full-screen .map-fs-bottom-stack,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-bottom-stack{
  display:flex; flex-direction:column; align-items:center; gap:8px;
  position:absolute; bottom:12px; left:50%; transform:translateX(-50%); z-index:10;
  max-width:calc(100% - 24px);
}
.map-fullscreen-target:fullscreen .map-fs-bottom-stack .status-line,
.map-fullscreen-target:-webkit-full-screen .map-fs-bottom-stack .status-line,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-bottom-stack .status-line{
  background:rgba(15,16,22,0.8); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  border:1px solid var(--line-soft); border-radius:999px; padding:5px 14px;
  margin:0; min-height:0; white-space:nowrap;
}

/* An idle hover-status line has nothing to say, and in fullscreen its pill styling (background,
   border, blur) would otherwise draw an empty dark box floating above the legend. Blank it out
   WITHOUT collapsing it: same padding and min-height, just nothing visible. Collapsing instead
   would make the legend jump up and down every time the pointer entered or left the map.
   Relies on the JS setting textContent to '' (not ' ' or '\u00A0') when there's nothing to show --
   :empty counts a whitespace text node as content. Aurora's "data unavailable" and Meteor's "no
   active showers" idle messages are real content, so they keep their pill. */
.map-fullscreen-target:fullscreen .map-fs-bottom-stack .status-line:empty,
.map-fullscreen-target:-webkit-full-screen .map-fs-bottom-stack .status-line:empty,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-bottom-stack .status-line:empty{
  background:none; border-color:transparent;
  backdrop-filter:none; -webkit-backdrop-filter:none;
}
/* An empty div has no line box, so blanking the pill alone would shrink it (measured 27px -> 12px)
   and bounce the legend up and down every time the pointer entered or left the map. An EMPTY
   inline-block restores exactly one line box (any inline-level box creates one, and the line's
   height then comes from the block's own strut), keeping the invisible pill the same height a
   filled one would be -- font-independent, unlike hardcoding a min-height.
   content:"" and NOT a zero-width space: U+200B is missing from this pill's font and Chrome renders
   it as a visible "tofu" box, which is exactly the stray glyph a ZWSP version of this rule shipped.
   An empty inline-block has no character at all, so nothing can fall back to tofu.
   ::before content does not stop :empty from matching. */
.map-fullscreen-target:fullscreen .map-fs-bottom-stack .status-line:empty::before,
.map-fullscreen-target:-webkit-full-screen .map-fs-bottom-stack .status-line:empty::before,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-bottom-stack .status-line:empty::before{
  content:""; display:inline-block;
}
.map-fullscreen-target:fullscreen .map-fs-legend-overlay,
.map-fullscreen-target:-webkit-full-screen .map-fs-legend-overlay,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-legend-overlay{
  display:block; max-width:100%;
  background:rgba(15,16,22,0.8); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  border:1px solid var(--line-soft); border-radius:var(--radius); padding:10px 18px;
}
.map-fullscreen-target:fullscreen .map-fs-legend-overlay .graph-legend,
.map-fullscreen-target:-webkit-full-screen .map-fs-legend-overlay .graph-legend,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-legend-overlay .graph-legend{
  margin:0;
}
.map-fullscreen-target:fullscreen .map-fs-legend-overlay .gradient-legend,
.map-fullscreen-target:-webkit-full-screen .map-fs-legend-overlay .gradient-legend,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-legend-overlay .gradient-legend{
  margin:8px auto 0;
}
/* Matches the normal-view 420px cap (tuned down from an earlier 2.5x-wider attempt that read as
   too large in fullscreen). FIXED width (not max-width) is still required even at this size,
   though -- this box is a flex item of .map-fs-bottom-stack, which uses align-items:center (so its
   children shrink-wrap to their own content's width instead of filling available space); the
   swatch bar itself has no intrinsic content width (empty colored squares), so a mere max-width cap
   shrink-wraps down to the ticks/title text's much narrower width instead of actually holding 420px. */
.map-fullscreen-target:fullscreen .map-fs-legend-overlay .bortle-legend,
.map-fullscreen-target:-webkit-full-screen .map-fs-legend-overlay .bortle-legend,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .map-fs-legend-overlay .bortle-legend{
  margin:8px auto 0; width:420px; max-width:100%;
}

/* ---------- Chart fullscreen -- non-map graphs (24-hour/year graphs, the shared metric-chart
   component's charts, Aurora's own custom chart, Sky Path) reusing the exact same
   .map-fullscreen-target/.map-fs-* mechanics maps use above, wrapped the same way (a
   .map-fullscreen-target div containing the chart's own box). A chart has no MapLibre control to
   supply its own fullscreen button, so this adds a small hand-rolled one instead -- always visible
   (not fullscreen-only, unlike .map-fs-controls-overlay) since it's both the entry AND exit
   control, swapping its icon on click. ---------- */
.chart-fullscreen-btn{
  position:absolute; top:12px; right:12px; z-index:6;
  width:28px; height:28px; display:flex; align-items:center; justify-content:center;
  background:var(--bg-panel); border:1px solid var(--line-soft); border-radius:6px;
  color:var(--ink-dim); cursor:pointer; padding:0;
}
.chart-fullscreen-btn:hover, .chart-fullscreen-btn:focus-visible{ color:var(--gold-text); border-color:var(--gold-text); }
.chart-fullscreen-btn svg{ width:14px; height:14px; display:block; }
.map-fullscreen-target:fullscreen .chart-fullscreen-btn,
.map-fullscreen-target:-webkit-full-screen .chart-fullscreen-btn,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .chart-fullscreen-btn{
  position:fixed; top:12px; right:12px; z-index:20;
}
/* Extends the map-only .graph-box fullscreen rule above to the shared metric-chart component's own
   wrapper (.moon-chart-box, used by Sun/Moon/Meteor Activity/Aurora) and Sky Path's polar-diagram
   wrapper (.skypath-box) -- same full-bleed treatment, flex column so the chart holder itself can
   grow to fill the extra vertical space (charts render taller in fullscreen, not just wider -- see
   shared/js/metric-chart.js's own fullscreen height handling). */
.map-fullscreen-target:fullscreen .moon-chart-box,
.map-fullscreen-target:-webkit-full-screen .moon-chart-box,
.map-fullscreen-target:fullscreen .skypath-box,
.map-fullscreen-target:-webkit-full-screen .skypath-box,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .moon-chart-box,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .skypath-box{
  position:absolute; inset:0; padding:16px 16px 8px; border:none; border-radius:0; margin:0;
  display:flex; flex-direction:column; background:var(--bg-deep); max-width:none;
}
/* Matched by every chart holder's own *ChartHolder/*SvgHolder id naming convention, the same
   suffix-matching approach the map rules above use for *CanvasHolder. */
.map-fullscreen-target:fullscreen .moon-chart-box > div[id$="ChartHolder"],
.map-fullscreen-target:-webkit-full-screen .moon-chart-box > div[id$="ChartHolder"],
.map-fullscreen-target:fullscreen .graph-box > div[id$="ChartHolder"],
.map-fullscreen-target:-webkit-full-screen .graph-box > div[id$="ChartHolder"],
.map-fullscreen-target:fullscreen .graph-box > div[id$="SvgHolder"],
.map-fullscreen-target:-webkit-full-screen .graph-box > div[id$="SvgHolder"],
.map-fullscreen-target:fullscreen .skypath-box > div[id$="SvgHolder"],
.map-fullscreen-target:-webkit-full-screen .skypath-box > div[id$="SvgHolder"],
.map-fullscreen-target.maplibregl-pseudo-fullscreen .moon-chart-box > div[id$="ChartHolder"],
.map-fullscreen-target.maplibregl-pseudo-fullscreen .graph-box > div[id$="ChartHolder"],
.map-fullscreen-target.maplibregl-pseudo-fullscreen .graph-box > div[id$="SvgHolder"],
.map-fullscreen-target.maplibregl-pseudo-fullscreen .skypath-box > div[id$="SvgHolder"]{
  flex:1; min-height:0;
}
/* The chart's own controls row, at the top-left of its box in BOTH normal and fullscreen view:
   fullscreen-only title, then the Week/Month/Year toggle, then the two metric dropdowns
   immediately to its right, with the range label pushed to the far right.

   Each dropdown is a shared/js/combo-select.js custom control rather than a row of toggle chips (a
   registry with many entries, e.g. Meteor Activity's one card per active shower, made a chip row
   wrap across several lines) or a native <select> (its open option list can't be themed in any
   browser, breaking the dark UI the instant it opens -- see that file's own header).

   These used to sit in a floating .map-fs-controls-overlay panel, fullscreen-only, stacked
   vertically at full width under "Primary"/"Secondary" labels. That panel covered the chart's
   top-left corner and was mostly dead space; the dot colour on each trigger already says which
   series is which, so the labels were redundant too. */
.chart-controls-row{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding-right:40px;
}
.chart-metric-selector{ display:flex; align-items:center; gap:8px; }
/* Narrow, and side-by-side rather than stacked. The trigger already ellipsizes, so a long metric
   name shortens instead of stretching the row. */
.chart-metric-selector .combo-select{ width:150px; }
.chart-metric-selector .combo-select-trigger{ padding:6px 9px; font-size:12px; }
/* The title is display:none outside fullscreen (see .map-fs-title above), so in normal view this
   row simply starts with the range toggle. Its default bottom margin is for the old stacked panel
   -- inline in this row it needs none. */
.chart-controls-row .map-fs-title{ margin:0; }
/* Pushed to the far right of the row, opposite the toggle and selectors. */
.chart-controls-row .chart-range-label{ margin-left:auto; }

/* ---------- shared/js/combo-select.js's own component ---------- */
.combo-select{ position:relative; }
.combo-select-trigger{
  width:100%; display:flex; align-items:center; gap:8px; text-align:left;
  background:var(--input-bg); border:1px solid var(--line); color:var(--ink);
  padding:8px 10px; border-radius:8px; font-family:var(--font-body); font-size:13px; cursor:pointer;
}
.combo-select-trigger:hover{ border-color:var(--ink-dim); }
.combo-select-trigger[aria-expanded="true"]{ border-color:var(--gold-text); }
.combo-select-dot{ width:9px; height:9px; border-radius:50%; flex:none; }
.combo-select-label{ flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.combo-select-caret{ color:var(--ink-faint); font-size:10px; flex:none; transition:transform 0.15s ease; }
.combo-select-trigger[aria-expanded="true"] .combo-select-caret{ transform:rotate(180deg); }
/* Same floating-panel look as shared/css/date-picker-popup.css's own .date-picker-popup --
   background/border/shadow match exactly, for one consistent "custom popup" language site-wide. */
.combo-select-popup{
  position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:60;
  max-height:240px; overflow-y:auto; padding:6px;
  background:var(--bg-raised); border:1px solid var(--line-soft); border-radius:var(--radius);
  box-shadow:0 12px 32px rgba(0,0,0,0.4);
}
.combo-select-option{
  display:flex; align-items:center; width:100%; text-align:left;
  padding:7px 8px; border-radius:6px; border:none; background:transparent;
  color:var(--ink-dim); font-family:var(--font-body); font-size:12.5px; cursor:pointer;
}
/* No outline:none override here -- the global button:focus-visible gold ring (shared/css/base.css)
   already applies to these since they're real <button> elements, and stays on top of this. */
.combo-select-option:hover, .combo-select-option:focus-visible{ background:var(--bg-panel-2); color:var(--ink); }
.combo-select-option[aria-selected="true"]{ color:var(--ink); font-weight:600; }
.combo-select-option[aria-selected="true"]::after{ content:'✓'; margin-left:auto; color:var(--gold-text); }
/* ---------- SkyView ----------
   The all-sky canvas is square by nature -- a disc of sky -- so the holder centres it rather than
   letting it stretch. Sized in JS from the holder's own width (23-skyview-view.js), because the
   canvas backing store has to be set in device pixels and cannot be driven by CSS alone. */
.skyview-holder{
  display:flex; justify-content:center; align-items:center;
  width:100%; padding:4px 0;
  /* The exposure column is positioned against this. */
  position:relative;
}
.skyview-holder canvas{
  display:block; border-radius:50%;
  background:var(--night);
  cursor:crosshair;
}
/* Look-around mode is a window on the sky rather than a disc of it, so it is rectangular and drags.
   touch-action:none is required, not cosmetic: without it a drag on a phone scrolls the page
   instead of turning the view, and pointermove stops arriving mid-gesture. */
.skyview-holder canvas.skyview-look{
  border-radius:10px;
  cursor:grab;
  touch-action:none;
}
.skyview-holder canvas.skyview-look:active{ cursor:grabbing; }
/* In fullscreen the canvas is the whole point, so let it use the height available rather than the
   width -- otherwise a wide screen gives a disc sized for a column it is no longer in. The disc is
   then sized in JS to the SMALLER of the two dimensions, matching Sky Path's own fullscreen rule in
   sun-and-moon/js/03-skypath-view.js, so both polar diagrams fill the space the same way. */
.map-fullscreen-target:fullscreen .skyview-holder,
.map-fullscreen-target:-webkit-full-screen .skyview-holder,
.map-fullscreen-target.maplibregl-pseudo-fullscreen .skyview-holder{
  height:100%; min-height:0;
  /* Room for the status pill that floats over the bottom of the canvas in fullscreen, and enough at
     the top that the N label is not clipped by the edge. renderInner() reads this back off the
     computed style, so changing it here is enough. The disc then lands at very close to the same
     fraction of the height as Sun & Moon's Sky Path does in its own fullscreen. */
  padding:6px 0 46px;
}

/* ---------- SkyView exposure column ----------
   Vertical, in the gutter the disc leaves at the right of its own holder. It is absolutely placed
   rather than being a flex sibling so that the disc stays CENTRED in the holder rather than being
   pushed off-centre by the column's width; renderInner() reserves the same gutter on both sides
   when it sizes the canvas, so the two never overlap at any width.

   The slider is vertical via writing-mode, which is the standard route now that
   `appearance:slider-vertical` is deprecated -- direction:rtl puts the maximum at the TOP, so up
   reads as brighter. The -webkit-appearance line is kept for older WebKit, which ignores the
   writing-mode form. */
.skyview-exposure{
  position:absolute; right:0; top:0; bottom:0;
  width:var(--skyview-gutter, 56px);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:6px; padding:8px 0; pointer-events:none;
}
.skyview-exposure > *{ pointer-events:auto; }
.skyview-exposure-cap{
  writing-mode:vertical-rl; transform:rotate(180deg);
  font-size:11px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink-faint); white-space:nowrap;
}
.skyview-exposure input[type="range"]{
  writing-mode:vertical-rl; direction:rtl;
  -webkit-appearance:slider-vertical;
  width:24px;                 /* 2.5.8: the touch target, not the track */
  flex:1 1 auto; min-height:90px; max-height:340px;
  margin:0; padding:0; background:transparent; cursor:ns-resize;
}
.skyview-exposure-val{
  font-family:var(--font-mono, ui-monospace, monospace);
  font-size:11px; color:var(--ink-faint); white-space:nowrap;
}
.skyview-exposure-reset{
  min-width:24px; min-height:24px;
  padding:2px 6px; font-size:13px; line-height:1;
}
/* Below this the holder has no gutter worth the name -- the caption and the readout would crowd the
   disc -- so only the slider and its reset survive. */
@media (max-width:560px){
  .skyview-exposure{ width:var(--skyview-gutter-narrow, 34px); }
  .skyview-exposure-cap, .skyview-exposure-val{ display:none; }
}
