/* ─────────────────────────────────────────────────────────────────────────────
   Design system — PARTS. Requires tokens.css. Prefix: .ds-
   A small vocabulary, phone-first. Apps compose screens from these; they add
   layout (where a part sits) but never restyle a part's colours or type.
   Pulse equivalents (unprefixed): .panel ≈ .ds-panel, .tabs ≈ .ds-tabs,
   .dot ≈ .ds-dot, .kpi ≈ .ds-stat, .chip ≈ .ds-chip, .pill ≈ .ds-pill.
   ───────────────────────────────────────────────────────────────────────────── */

/* ── Base (opt-in on <body class="ds">) ─────────────────────────────────── */
body.ds { margin: 0; background: var(--bg); color: var(--ink); font: var(--fs)/var(--lh) var(--sans); -webkit-font-smoothing: antialiased; }
body.ds *, body.ds *::before, body.ds *::after { box-sizing: border-box; }
/* Zero-specificity defaults (:where), so every .ds- part wins over them */
:where(body.ds a) { color: var(--accent-2); text-decoration: none; }
:where(body.ds a:hover) { text-decoration: underline; }
:where(body.ds button, body.ds select, body.ds input) { font: inherit; color: inherit; }
body.ds :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Type utilities ─────────────────────────────────────────────────────── */
.ds-h1 { font-size: var(--fs-lg); font-weight: 600; margin: 0; }
.ds-h2 { font-size: var(--fs); font-weight: 600; margin: 0; letter-spacing: .01em; }
.ds-label { color: var(--muted); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-label); }
.ds-unit { text-transform: none; letter-spacing: 0; }   /* "km/h", "°C" inside a label or a stat */
.ds-meta { color: var(--muted); font-size: var(--fs-sm); }
.ds-muted { color: var(--muted); }
.ds-mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.ds-num { font-variant-numeric: tabular-nums; }
.ds-truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.ds-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ── Layout helpers ─────────────────────────────────────────────────────── */
.ds-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.ds-stack { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.ds-spacer { margin-left: auto; }

/* ── App header (sticky, glass) ─────────────────────────────────────────── */
.ds-top { position: sticky; top: 0; z-index: var(--z-bar); display: flex; align-items: center; gap: var(--sp-2);
  height: calc(var(--top-h) + var(--safe-top)); padding: var(--safe-top) var(--sp-3) 0;
  background: var(--glass); backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  border-bottom: 1px solid var(--line); }
.ds-brand { display: flex; align-items: center; gap: var(--sp-2); color: var(--ink); font-weight: 600; letter-spacing: .02em; white-space: nowrap; }
.ds-brand img, .ds-brand .ds-mark { width: 28px; height: 28px; border-radius: var(--r-sm); display: block; }
.ds-brand .ds-mark { background: linear-gradient(135deg, var(--accent), var(--accent-2)); }   /* placeholder until an app sets its logo */
.ds-top .ds-right { margin-left: auto; display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-sm); color: var(--ink-2); }

/* ── Tabs ───────────────────────────────────────────────────────────────── */
.ds-tabs { display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none; min-width: 0; }
.ds-tabs::-webkit-scrollbar { display: none; }
.ds-tab { position: relative; display: inline-flex; align-items: center; gap: 7px; padding: 6px 8px; min-height: 32px; border: 0; background: none; border-radius: var(--r-sm);
  color: var(--ink-2); font-size: var(--fs-sm); font-weight: 500; white-space: nowrap; cursor: pointer; text-decoration: none; user-select: none; transition: background var(--t-fast), color var(--t-fast); }
.ds-tab:hover { color: var(--ink); background: var(--panel-2); text-decoration: none; }
.ds-tab.on { color: var(--ink); background: var(--panel-2); box-shadow: var(--ring); }

/* ── Panels ─────────────────────────────────────────────────────────────── */
.ds-panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); padding: var(--sp-3) var(--sp-4); min-width: 0; }
.ds-panel-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); flex-wrap: wrap; }
.ds-panel-head .ds-meta, .ds-panel-head .ds-more { margin-left: auto; }

/* Floating panel over the map: glass + blur + shadow. The app positions it. */
.ds-float { position: absolute; z-index: var(--z-float); background: var(--glass); backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow); min-width: 0; transition: border-color var(--t), box-shadow var(--t); }
.ds-float.on, .ds-float.active { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow), var(--shadow); }
.ds-float.clickable { cursor: pointer; }

/* Bottom sheet surface: timeline bar, AtmoSlice (the app stacks them) */
.ds-sheet { position: absolute; left: 0; right: 0; bottom: 0; z-index: var(--z-bar); background: var(--glass); backdrop-filter: blur(var(--glass-blur)); -webkit-backdrop-filter: blur(var(--glass-blur));
  border-top: 1px solid var(--line); padding: var(--sp-2) var(--gutter) calc(var(--sp-2) + var(--safe-bottom)); touch-action: pan-x; }

/* ── Controls bar (under the header; selects, icon buttons, status text) ── */
.ds-bar { display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-1) var(--gutter); background: var(--panel); border-bottom: 1px solid var(--line); flex-wrap: wrap; min-width: 0; }
.ds-bar .ds-meta { margin-left: auto; white-space: nowrap; }

/* ── Controls ───────────────────────────────────────────────────────────── */
.ds-select { -webkit-appearance: none; appearance: none; min-height: var(--ctl-h); padding: 0 28px 0 10px; font-size: var(--fs-sm); color: var(--ink); background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%), linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: calc(100% - 15px) 55%, calc(100% - 10px) 55%; background-size: 5px 5px; background-repeat: no-repeat; max-width: 100%; }
.ds-select:hover { border-color: var(--line-2); }
.ds-select.primary { font-weight: 600; }

.ds-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: var(--ctl-h); padding: 0 12px; font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2);
  background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer; white-space: nowrap; user-select: none; position: relative;
  transition: border-color var(--t-fast), color var(--t-fast), background var(--t-fast); }
.ds-btn:hover { border-color: var(--line-2); color: var(--ink); }
.ds-btn.on { color: var(--ink); border-color: var(--accent); }
.ds-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.ds-btn.primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.ds-btn.ghost { background: transparent; border-color: transparent; }
.ds-btn.danger { background: transparent; color: var(--bad); }
.ds-btn.danger:hover { border-color: var(--bad); background: color-mix(in srgb, var(--bad) 10%, transparent); }
.ds-btn.small { min-height: 28px; padding: 0 9px; font-size: var(--fs-xs); }
.ds-btn.icon { width: calc(var(--ctl-h) + 2px); min-height: calc(var(--ctl-h) + 2px); padding: 0; font-size: 16px; }
.ds-btn:disabled { opacity: .5; cursor: default; }

.ds-toggle { display: inline-flex; border: 1px solid var(--line); border-radius: var(--r-sm); }   /* no overflow:hidden — it would clip the 44px hit areas */
.ds-toggle .ds-btn { border: 0; border-radius: 0; min-height: 30px; }
.ds-toggle .ds-btn:first-child { border-radius: calc(var(--r-sm) - 1px) 0 0 calc(var(--r-sm) - 1px); }
.ds-toggle .ds-btn:last-child { border-radius: 0 calc(var(--r-sm) - 1px) calc(var(--r-sm) - 1px) 0; }
.ds-toggle .ds-btn + .ds-btn { border-left: 1px solid var(--line); }
.ds-toggle .ds-btn.on { background: var(--panel-2); color: var(--ink); }

.ds-chip { position: relative; display: inline-flex; align-items: center; gap: 5px; min-height: 26px; padding: 0 9px; font-size: var(--fs-xs); color: var(--ink-2); background: transparent; border: 1px solid var(--line); border-radius: var(--r-pill); cursor: pointer; white-space: nowrap; }
.ds-chip:hover { border-color: var(--line-2); color: var(--ink); }
.ds-chip.on { background: var(--panel-2); color: var(--ink); border-color: var(--accent); }

.ds-input { min-height: var(--ctl-h); padding: 0 10px; font-size: var(--fs-sm); color: var(--ink); background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r-sm); width: 100%; }
.ds-input:focus { border-color: var(--accent); outline: none; }
.ds-field { display: flex; flex-direction: column; gap: var(--sp-1); }
.ds-field > .ds-label { margin-bottom: 2px; }

/* ── Status ─────────────────────────────────────────────────────────────── */
.ds-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); display: inline-block; flex: none; }
.ds-dot.up, .ds-dot.good { background: var(--good); box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 22%, transparent); }
.ds-dot.down, .ds-dot.bad { background: var(--bad); box-shadow: 0 0 0 3px color-mix(in srgb, var(--bad) 22%, transparent); }
.ds-dot.warn { background: var(--warn); }
.ds-dot.stale { background: var(--stale); }
.ds-dot.big { width: 10px; height: 10px; }
.ds-live { display: inline-flex; align-items: center; gap: 6px; }
.ds-live .ds-dot.up { animation: ds-pulse 2.4s ease-in-out infinite; }
@keyframes ds-pulse { 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 22%, transparent); } 50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--good) 8%, transparent); } }

.ds-pill { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-xs); padding: 1px 7px; border-radius: var(--r-pill); border: 1px solid var(--line-2); color: var(--ink-2); white-space: nowrap; }
.ds-pill.good { color: var(--good-ink); border-color: color-mix(in srgb, var(--good) 50%, transparent); }
.ds-pill.warn { color: var(--warn-ink); border-color: color-mix(in srgb, var(--warn) 50%, transparent); }
.ds-pill.bad { color: var(--bad-ink); border-color: color-mix(in srgb, var(--bad) 55%, transparent); }
.ds-pill.stale { color: var(--stale-ink); border-color: color-mix(in srgb, var(--stale) 55%, transparent); }
.ds-pill.muted { color: var(--muted); }

/* ── Stat tile ("a number is the chart"); corner boxes are floating stats ── */
.ds-stat { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px 9px; min-width: 0; }
.ds-stat .k { color: var(--muted); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-label); }
.ds-stat .v { font-size: var(--fs-lg); line-height: 1.15; font-weight: 500; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ds-stat .v small { font-size: var(--fs-sm); font-weight: 400; color: var(--ink-2); margin-left: 2px; }
.ds-stat .s { color: var(--ink-2); font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-stat .v.warn { color: var(--warn); } .ds-stat .v.bad { color: var(--bad); } .ds-stat .v.good { color: var(--good); } .ds-stat .v.muted { color: var(--muted); }
.ds-stat.center { text-align: center; align-items: center; }
.ds-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-3); }

/* ── Banner (floating pill: a name and a time) ──────────────────────────── */
.ds-banner { display: inline-flex; flex-direction: column; align-items: center; gap: 1px; padding: 6px 18px; border-radius: var(--r-pill); white-space: nowrap; }
.ds-banner .name { font-size: var(--fs-md); font-weight: 600; letter-spacing: .01em; }
.ds-banner .time { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); letter-spacing: .02em; }

/* ── Legend (colour ramp for a map layer) ───────────────────────────────── */
.ds-legend { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-xs); line-height: 1.6; min-width: 120px; }
.ds-legend .ds-label { display: block; margin-bottom: 4px; }
.ds-legend-bar { height: 8px; border-radius: 4px; margin: 4px 0; background: var(--ramp, linear-gradient(to right, var(--s1), var(--s3), var(--s4), var(--s2), var(--s8))); }
/* Data ramps (wind, rain, temperature…) are the app's palettes, not tokens: set `--ramp` on the legend, e.g. style="--ramp: linear-gradient(…)" */
.ds-legend-labels { display: flex; justify-content: space-between; color: var(--muted); font-variant-numeric: tabular-nums; }
.ds-legend-row { display: flex; align-items: center; gap: 6px; }
.ds-legend-row i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; flex: none; }

/* ── Popup card (also skins Leaflet popups inside body.ds) ──────────────── */
.ds-popup { background: var(--panel); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-lg); padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm); }
.ds-popup h3 { font-size: var(--fs); font-weight: 600; margin: 0 0 var(--sp-1); }
body.ds .leaflet-popup-content-wrapper { background: var(--panel); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-lg); font: var(--fs-sm)/var(--lh) var(--sans); }
body.ds .leaflet-popup-tip { background: var(--panel); border: 1px solid var(--line); border-top: 0; border-left: 0; }
body.ds .leaflet-popup-close-button { color: var(--muted); }
body.ds .leaflet-control-attribution { background: var(--glass); color: var(--muted); font-size: 10px; border-top-left-radius: var(--r-sm); }
body.ds .leaflet-control-attribution a { color: var(--ink-2); }

/* ── Overlays ───────────────────────────────────────────────────────────── */
.ds-overlay { position: absolute; inset: 0; z-index: var(--z-overlay); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-3); background: color-mix(in srgb, var(--bg) 60%, transparent); color: var(--ink-2); font-size: var(--fs-sm); }
.ds-spinner { width: 28px; height: 28px; border: 3px solid var(--line-2); border-top-color: var(--accent); border-radius: 50%; animation: ds-spin .8s linear infinite; }
@keyframes ds-spin { to { transform: rotate(360deg); } }

.ds-modal { position: fixed; inset: 0; z-index: var(--z-modal); display: flex; align-items: flex-end; justify-content: center; background: var(--scrim); padding: var(--gutter); padding-bottom: calc(var(--gutter) + var(--safe-bottom)); }
.ds-modal-card { width: 100%; max-width: 440px; max-height: 85vh; overflow: auto; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-lg); padding: var(--sp-4); }
.ds-modal-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; margin-top: var(--sp-4); }

/* "Stale" marker for data shown past its refresh interval (PWA offline) */
.ds-stale-note { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--stale-ink); }
.ds-stale-note::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--stale); }

/* ── Hit areas: a control smaller than --tap gets an invisible pseudo-element
   that grows it to --tap on whichever axis is short (percentages resolve
   against the control's own box, min() keeps larger controls unchanged).
   Tabs and toggle buttons live inside clipping containers, so they get taller
   instead (touch rule below). ── */
.ds-btn::before, .ds-chip::before { content: ""; position: absolute; inset: min(0px, calc((100% - var(--tap)) / 2)); }

/* ── Touch screens: taller visible controls ── */
@media (pointer: coarse) {
  :root { --ctl-h: 40px; }
  .ds-tab { min-height: 44px; }
  .ds-toggle .ds-btn { min-height: 40px; }
  .ds-btn.small { min-height: 36px; }
  .ds-chip { min-height: 32px; }
}

/* ── Desktop (phone is the default above) ───────────────────────────────── */
@media (min-width: 769px) {
  .ds-top { gap: var(--sp-4); padding-left: var(--gutter); padding-right: var(--gutter); }
  .ds-tab { padding: 6px 10px; font-size: var(--fs); }
  .ds-bar { gap: var(--sp-2); padding: var(--sp-2) var(--gutter); }
  .ds-stat .v { font-size: var(--fs-xl); }
  .ds-modal { align-items: center; }
}

/* ── Reduced motion: no decorative animation; the spinner still turns, slower ── */
@media (prefers-reduced-motion: reduce) {
  .ds-live .ds-dot.up { animation: none; }
  .ds-spinner { animation-duration: 1.6s; }
}
