/* theme.css — base typography + layout primitives.  Every page in
   Burning Swell loads tokens.css then theme.css; components apply
   BEM-style classes that key off the variables defined there.

   Aesthetic: "Dawn Patrol" refined-minimal — warm paper/ink, one
   sodium-amber accent, generous air, type doing the work of borders.
   Motion is reserved for one orchestrated page-load reveal plus
   honest hover/focus feedback; all of it yields to
   `prefers-reduced-motion'. */

@import url("/tokens.css");

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--fg);
    font-family: var(--font-sans);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* Atmosphere: a low warm wash from the top — the page reads as a lit
   surface at golden hour, not a flat fill.  Fixed so it doesn't
   scroll; tokenised so it inverts cleanly with the theme. */
body {
    min-height: 100vh;
    background-image:
        radial-gradient(120% 80% at 50% -20%,
                         var(--atmo-1) 0%, var(--atmo-2) 60%);
    background-attachment: fixed;
}

a {
    color: var(--accent);
    text-decoration: none;
}
a:hover { text-decoration: underline; }

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 560;
    line-height: 1.15;
    letter-spacing: -0.012em;
}

h1 { font-size: var(--text-2xl); margin: var(--space-6) 0 var(--space-4); }
h2 { font-size: var(--text-xl);  margin: var(--space-6) 0 var(--space-3); }
h3 { font-size: var(--text-lg);  margin: var(--space-4) 0 var(--space-2); }

.bs-page {
    max-width: 1080px;
    margin: 0 auto;
    padding: var(--space-8) var(--space-4);
}

/* ---- One orchestrated load reveal ------------------------------- *
 * The dashboard's major blocks fade-up in sequence so the eye lands
 * on the now-cast first.  Subtle (8px / 0.5s), and entirely off under
 * reduced-motion.
 * ---------------------------------------------------------------- */
@keyframes bs-rise {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

.bs-page > *,
.bs-home, .bs-sessions, .bs-stats, .bs-map {
    animation: bs-rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
.bs-page > *:nth-child(1) { animation-delay: 0.02s; }
.bs-page > *:nth-child(2) { animation-delay: 0.09s; }
.bs-page > *:nth-child(3) { animation-delay: 0.16s; }
.bs-page > *:nth-child(4) { animation-delay: 0.23s; }
.bs-page > *:nth-child(n+5) { animation-delay: 0.30s; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
}

/* Magic-link sign-in (bs-avk / Phase-2 C1). */
.bs-auth {
    max-width: 24rem;
    margin: 4rem auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.bs-auth__title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 600;
}

.bs-auth__form {
    display: flex;
    gap: var(--space-2);
}

.bs-auth__input {
    flex: 1;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
    color: var(--fg);
    font: inherit;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.bs-auth__input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.bs-auth__submit {
    padding: 0.5rem 1rem;
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-fg);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: filter 0.15s ease, transform 0.06s ease;
}
.bs-auth__submit:hover  { filter: brightness(1.06); }
.bs-auth__submit:active { transform: translateY(1px); }
.bs-auth__submit:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.bs-auth__status {
    min-height: 1.2em;
    color: var(--fg-muted);
    font-size: var(--text-sm);
}

/* Account hub — multi-email manager (bs-yp3 Phase 3). */
.bs-account {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.bs-account__heading {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    margin: var(--space-2) 0 0;
}

.bs-account__section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
}

.bs-account__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.bs-account__row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.bs-account__addr {
    flex: 1;
    overflow-wrap: anywhere;
}

.bs-account__badge {
    font-size: var(--text-sm);
    padding: 0.1rem 0.4rem;
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
    color: var(--fg-muted);
    border: 1px solid var(--border);
}
.bs-account__badge--primary {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
}
.bs-account__badge--unverified {
    color: var(--fg-muted);
    font-style: italic;
}

.bs-account__action {
    padding: 0.25rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
    color: var(--fg);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
    transition: filter 0.15s ease, transform 0.06s ease;
}
.bs-account__action:hover  { filter: brightness(1.06); }
.bs-account__action:active { transform: translateY(1px); }
.bs-account__action--danger { color: var(--danger, #c0392b); }

/* ---- Spot header ------------------------------------------------ */

.bs-spot-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    border-bottom: 1px solid var(--border);
    padding-bottom: var(--space-3);
    margin-bottom: var(--space-8);
}

.bs-spot-header__name {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 640;
    letter-spacing: -0.02em;
}
.bs-spot-header__meta { color: var(--fg-muted); font-size: 0.95rem; }

/* ---- Forecast table — 3-hourly columns, energy heatmap ---------- */

.bs-forecast {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.bs-forecast th,
.bs-forecast td {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
    text-align: center;
}

.bs-forecast tbody tr { transition: background 0.12s ease; }
.bs-forecast tbody tr:hover { background: var(--accent-soft); }

.bs-forecast__cell-energy {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    border-radius: var(--radius-sm);
}

.bs-tide__bar {
    width: 60%;
    min-height: 1px;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    background: var(--accent);
}

.bs-tide--ebb { background: var(--fg-subtle); }

.bs-tide__val {
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    color: var(--fg-muted);
}

/* Forecast-column → tide-point cross-highlight (bs-cc2 B2 / bs-gwj):
   hovering any cell in a column adds `--tide-hot' to that column's
   tide td, which lights its bar and value. */
.bs-forecast__cell--tide-hot {
    background: var(--accent-soft);
    border-radius: var(--radius-sm);
}

.bs-forecast__cell--tide-hot .bs-tide__bar {
    background: var(--accent);
    outline: 2px solid var(--accent);
    transform: scaleX(1.25);
}

.bs-forecast__cell--tide-hot .bs-tide__val {
    color: var(--fg);
    font-weight: 700;
}

/* ---- Tide curve (bs-2q0g) — daily sparkline panel --------------- *
 * A server-rendered SVG of the day's predicted tide; the curve + area
 * stretch to the panel width (preserveAspectRatio=none), strokes kept
 * constant with non-scaling-stroke.  High/low detail is a wrapping chip
 * row, mobile-first (no wide numeric column — the bs-yg45 overflow fix). */
.bs-tide-curve {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    padding: var(--space-4);
    margin-bottom: var(--space-8);
}

.bs-tide-curve__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    margin-bottom: var(--space-3);
}

.bs-tide-curve__title { font-weight: 700; font-size: 0.9rem; }

.bs-tide-curve__caveat { font-size: 0.72rem; color: var(--fg-subtle); }

.bs-tide-curve__svg {
    display: block;
    width: 100%;
    height: 96px;
}

.bs-tide-curve__area { fill: var(--accent-soft); }

.bs-tide-curve__line {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
}

.bs-tide-curve__now {
    stroke: var(--fg-muted);
    stroke-width: 1;
    stroke-dasharray: 3 3;
    vector-effect: non-scaling-stroke;
}

/* bs-pajo.2: the OBSERVED water-level overlay — a cool-teal line over the
 * amber prediction, so their gap reads as the surge residual. */
.bs-tide-curve__observed {
    fill: none;
    stroke: var(--tide-observed);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
}

.bs-tide-curve__dot { fill: var(--accent); }
.bs-tide-curve__dot--low { fill: var(--fg-subtle); }

/* bs-pajo.2: predicted-vs-observed legend + surge readout — a wrapping
 * chip row so it never overflows at phone width (bs-yg45). */
.bs-tide-curve__legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.9rem;
    margin-top: var(--space-3);
    font-size: 0.74rem;
    color: var(--fg-muted);
}

.bs-tide-curve__key {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.bs-tide-curve__swatch {
    display: inline-block;
    width: 1.1rem;
    height: 0;
    border-top-width: 3px;
    border-top-style: solid;
    border-radius: 2px;
}

.bs-tide-curve__swatch--predicted { border-top-color: var(--accent); }
.bs-tide-curve__swatch--observed  { border-top-color: var(--tide-observed); }

.bs-tide-curve__residual {
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    margin-left: auto;
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius-sm);
    background: var(--bg-subtle);
    font-variant-numeric: tabular-nums;
}

.bs-tide-curve__residual-label {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.66rem;
    font-weight: 700;
    color: var(--tide-observed);
}

.bs-tide-curve__residual-val { color: var(--fg); font-weight: 600; }

.bs-tide-curve__marks {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: var(--space-3);
}

.bs-tide-curve__chip {
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius-sm);
    background: var(--bg-subtle);
    font-size: 0.74rem;
    font-variant-numeric: tabular-nums;
}

.bs-tide-curve__chip-kind {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.66rem;
    color: var(--fg-muted);
}

.bs-tide-curve__chip--high .bs-tide-curve__chip-kind { color: var(--accent); }

.bs-tide-curve__chip-h { color: var(--fg-muted); }

.bs-tide-curve__credit {
    margin-top: var(--space-2);
    font-size: 0.66rem;
    color: var(--fg-subtle);
}

/* ---------------------------------------------------------------- *
 * Consumer weather-condition card (bs-lwjd) — the everyday "Partly
 * cloudy 18°C" card beside the surf now-cast.  Card-first (flex/grid
 * of chips), so it cannot produce the bs-yg45 table-overflow class:
 * a first-party inline-SVG glyph + a headline line + a wrapping
 * metric row, mobile-safe by construction.
 * ---------------------------------------------------------------- */
.bs-wx-card {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    padding: var(--space-4);
    margin-bottom: var(--space-8);
}

.bs-wx-card__main {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.bs-wx-card__icon {
    flex: 0 0 auto;
    width: 2.75rem;
    height: 2.75rem;
    color: var(--fg-muted);   /* default glyph hue; families override below */
}

.bs-wx-glyph { display: block; width: 100%; height: 100%; }

/* Conventional weather hues, independent of the brand --accent so the
 * sky reads right in either theme (icon-set hardening is a follow-up). */
.bs-wx-card__icon--clear-day,
.bs-wx-card__icon--partly-day  { color: #f0a830; }
.bs-wx-card__icon--clear-night,
.bs-wx-card__icon--partly-night { color: #8a93a6; }
.bs-wx-card__icon--rain,
.bs-wx-card__icon--thunderstorm { color: #5b8fb0; }
.bs-wx-card__icon--snow        { color: #79a7c2; }

.bs-wx-card__headline {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-3);
}

.bs-wx-card__label { font-weight: 700; font-size: 1rem; }

.bs-wx-card__temp {
    font-size: 1.4rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.bs-wx-card__feels { font-size: 0.78rem; color: var(--fg-subtle); }

.bs-wx-card__detail {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.9rem;
    margin-top: var(--space-3);
    font-size: 0.8rem;
    color: var(--fg-muted);
    font-variant-numeric: tabular-nums;
}

.bs-wx-card__metric { white-space: nowrap; }

.bs-wx-card__note {
    margin-top: var(--space-2);
    font-size: 0.66rem;
    color: var(--fg-subtle);
}

/* ---------------------------------------------------------------- *
 * Global chrome — a sticky, hairline-ruled header carrying the
 * wordmark, the spot search, primary nav and the theme toggle.
 * ---------------------------------------------------------------- */

.bs-header {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: var(--space-6);
    height: var(--header-h);
    padding: 0 var(--space-6);
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    -webkit-backdrop-filter: saturate(1.5) blur(12px);
    backdrop-filter: saturate(1.5) blur(12px);
    border-bottom: 1px solid var(--border);
}

.bs-header__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    font-family: var(--font-display);
    font-weight: 640;
    font-size: 1.18rem;
    letter-spacing: -0.02em;
    color: var(--fg);
    white-space: nowrap;
}
.bs-header__brand:hover { text-decoration: none; }

/* CSS-drawn swell mark — a rising crescent, no extra DOM. */
.bs-header__brand::before {
    content: "";
    width: 0.95rem;
    height: 0.95rem;
    border-radius: 50%;
    border: 2px solid var(--accent);
    border-bottom-color: transparent;
    border-left-color: transparent;
    transform: rotate(-45deg);
}

.bs-header__search { flex: 1 1 auto; max-width: 30rem; }

.bs-header__nav {
    display: flex;
    align-items: center;
    gap: var(--space-6);
    margin-left: auto;
}

.bs-header__link {
    position: relative;
    color: var(--fg-muted);
    font-size: 0.9rem;
    letter-spacing: 0.01em;
    transition: color 0.15s ease;
}
.bs-header__link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 100%;
    bottom: -0.35rem;
    height: 1.5px;
    background: var(--accent);
    transition: right 0.22s ease;
}
.bs-header__link:hover {
    color: var(--fg);
    text-decoration: none;
}
.bs-header__link:hover::after { right: 0; }

/* ---- Theme toggle (System → Light → Dark, app.js-driven) -------- */

.bs-theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--fg-muted);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease,
                background 0.15s ease;
}
.bs-theme-toggle:hover {
    color: var(--fg);
    border-color: var(--accent);
}
.bs-theme-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.bs-theme-toggle__glyph { font-size: 1rem; line-height: 1; }

/* ---- Units toggle (Metric → Imperial → UK, app.js-driven) ------- */
/* Same visual language as the theme toggle, sat beside it in the nav. */

.bs-units-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--fg-muted);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease,
                background 0.15s ease;
}
.bs-units-toggle:hover {
    color: var(--fg);
    border-color: var(--accent);
}
.bs-units-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.bs-units-toggle__glyph {
    font-size: 0.8rem;
    line-height: 1;
    font-weight: 600;
    opacity: 0.85;
}

/* ---- spot search ------------------------------------------------ */

.bs-search { position: relative; display: flex; align-items: center; }

.bs-search__icon {
    position: absolute;
    left: 0.1rem;
    color: var(--fg-subtle);
    font-size: 1.05rem;
    pointer-events: none;
    line-height: 1;
}

.bs-search__input {
    width: 100%;
    padding: 0.5rem 0.4rem 0.5rem 1.6rem;
    border: 0;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    background: transparent;
    color: var(--fg);
    font: inherit;
    transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.bs-search__input::placeholder {
    color: var(--fg-subtle);
    letter-spacing: 0.01em;
}
.bs-search__input:focus {
    outline: none;
    border-bottom-color: var(--accent);
    box-shadow: 0 1px 0 0 var(--accent);
}

.bs-search__panel {
    /* Visibility is owned by Datastar `data-show' via the inline
       style.display (initial `display:none' is set inline in
       render-spot-search); a CSS `display:none' here would be
       un-overridable when shown. */
    position: absolute;
    top: calc(100% + 0.5rem);
    left: 0;
    right: 0;
    z-index: 60;
    overflow: hidden;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 18px 40px -22px var(--shadow-color);
    animation: bs-panel-in 0.15s cubic-bezier(0.2, 0.7, 0.3, 1);
}

@keyframes bs-panel-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
}

.bs-search__hits {
    display: flex;
    flex-direction: column;
    max-height: min(60vh, 22rem);
    overflow-y: auto;
}

.bs-search__hit {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    padding: 0.6rem var(--space-4);
    color: var(--fg);
    border-bottom: 1px solid var(--border);
    transition: background 0.12s ease;
}
.bs-search__hit:last-child { border-bottom: 0; }
.bs-search__hit:hover {
    background: var(--bg-subtle);
    text-decoration: none;
}
.bs-search__hit:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

.bs-search__hit-name {
    font-weight: 600;
    letter-spacing: -0.01em;
}

.bs-search__hit-slug {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-subtle);
}

.bs-search__empty {
    padding: 0.85rem var(--space-4);
    color: var(--fg-subtle);
    font-size: 0.9rem;
}

@media (max-width: 640px) {
    .bs-header {
        flex-wrap: wrap;
        height: auto;
        gap: var(--space-3);
        padding: var(--space-2) var(--space-4);
    }
    .bs-header__nav { gap: var(--space-4); }
    .bs-header__search {
        order: 3;
        flex-basis: 100%;
        max-width: none;
    }

    /* bs-ppyb — phone nav: the bottom tab bar carries the primary
       destinations, so drop the public header's text links (the theme
       toggle, not a `__link', stays).  The weather console keeps its
       own sub-nav. */
    .bs-header:not(.bs-header--weather) .bs-header__link { display: none; }

    /* Touch ergonomics (≥44px): the theme toggle and the search field
       grew from ~30/41px; each remaining header link gets a 44px hit
       area via an overlay, leaving its visual box (and underline)
       untouched. */
    .bs-theme-toggle { min-height: 44px; }
    .bs-units-toggle { min-height: 44px; }
    .bs-search__input { min-height: 44px; }
    .bs-header__link::before {
        content: "";
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 100%;
        min-width: 44px;
        height: 44px;
    }

    /* Reveal the fixed bottom tab bar and clear page-bottom space so it
       never covers the last of the content/footer. */
    .bs-tabbar { display: flex; }
    body { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
}

/* ---- Source toggle --------------------------------------------- */

.bs-source-toggle__tabs {
    display: flex;
    gap: var(--space-1);
    margin: var(--space-6) 0 var(--space-2);
}

.bs-source-toggle__tab {
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--fg-muted);
    cursor: pointer;
    font: inherit;
    font-size: 0.85rem;
    transition: color 0.15s ease, border-color 0.15s ease,
                background 0.15s ease;
}
.bs-source-toggle__tab:hover:not(:disabled) {
    color: var(--fg);
    border-color: var(--accent);
}
.bs-source-toggle__tab:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.bs-source-toggle__tab--active {
    background: var(--accent);
    color: var(--accent-fg);
    border-color: var(--accent);
    font-weight: 600;
}

/* E3: a source whose ingest failed for the current cycle. */
.bs-source-toggle__tab--unavailable {
    opacity: 0.45;
    cursor: not-allowed;
    text-decoration: line-through;
}

.bs-source-toggle__note {
    font-size: 0.8rem;
    color: var(--fg-muted);
    margin: var(--space-1) 0;
}
.bs-source-toggle__note:empty { display: none; }

/* E2: observed NDBC buoy conditions under the model now-cast. */
.bs-now-panel__buoy {
    font-size: var(--text-sm);
    color: var(--fg-muted);
    margin-top: var(--space-2);
}

/* ---- Home — distance-ordered spot list -------------------------- */

.bs-home__title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 640;
    letter-spacing: -0.02em;
    margin: var(--space-8) 0 var(--space-6);
}

.bs-home__row {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--border);
    transition: padding-left 0.15s ease;
}
.bs-home__row:hover { padding-left: var(--space-2); }

/* Top line of a row: the spot name (link) and, when geolocated, the
   distance — the historical baseline-aligned, space-between layout. */
.bs-home__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.bs-home__link {
    color: var(--fg);
    font-weight: 600;
    text-decoration: none;
}
.bs-home__row:hover .bs-home__link { color: var(--accent); }

.bs-home__dist {
    color: var(--fg-muted);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Current-conditions chip (bs-2yv6): a compact triage line under the spot
   name — Hs · period · direction arrow, then a coarse wind-quality pill.
   Wraps on narrow phones; absent on rows with no ingested forecast (the
   row then stays name-only — never an empty shell, bs-foy). */
.bs-home__chip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-size: 0.85rem;
    color: var(--fg-muted);
}
.bs-home__cond {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
}
.bs-home__wind {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem var(--space-2);
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    background: var(--wind-default-bg);
    color: var(--wind-default-fg);
}
.bs-home__wind--offshore { background: var(--wind-offshore-bg); color: var(--wind-offshore-fg); }
.bs-home__wind--cross    { background: var(--wind-cross-bg);    color: var(--wind-cross-fg); }
.bs-home__wind--onshore  { background: var(--wind-onshore-bg);  color: var(--wind-onshore-fg); }
.bs-home__wind--glassy   { background: var(--wind-glassy-bg);   color: var(--wind-glassy-fg); }

/* ---- "I surfed here" log form ----------------------------------- */

.bs-logform {
    margin: var(--space-8) 0;
    padding: var(--space-6) 0 0;
    border-top: 1px solid var(--border);
}

.bs-logform__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--text-lg);
    margin-bottom: var(--space-3);
}

.bs-logform__rating,
.bs-logform__notes {
    padding: var(--space-2) var(--space-3);
    margin-right: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
    color: var(--fg);
    font: inherit;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.bs-logform__rating:focus,
.bs-logform__notes:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.bs-logform__submit {
    padding: var(--space-2) var(--space-4);
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--accent-fg);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    transition: filter 0.15s ease, transform 0.06s ease;
}
.bs-logform__submit:hover  { filter: brightness(1.06); }
.bs-logform__submit:active { transform: translateY(1px); }
.bs-logform__submit:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.bs-logform__status {
    margin-top: var(--space-3);
    font-size: var(--text-sm);
    color: var(--fg-muted);
}

/* ---- Observed wave height (bs-j1g4.2 ★) ------------------------- */

.bs-obs {
    margin: var(--space-4) 0;
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
}

.bs-obs__head {
    font-weight: 600;
    margin-bottom: var(--space-2);
}

.bs-obs__forecast {
    font-size: var(--text-sm);
    color: var(--fg-muted);
    margin-bottom: var(--space-3);
}
.bs-obs__phs { color: var(--accent); }

.bs-obs__buckets {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.bs-obs__bucket {
    /* ≥44px tap target (Kai's one-tap log, Diego's 390px) — bs-yg45. */
    min-height: 44px;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--fg);
    font: inherit;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.bs-obs__bucket:hover { border-color: var(--accent); }
.bs-obs__bucket--on {
    border-color: var(--accent);
    background: var(--accent-soft);
    font-weight: 600;
}

.bs-obs__numeric {
    margin-top: var(--space-3);
    font-size: var(--text-sm);
    color: var(--fg-muted);
}

.bs-obs__num {
    width: 5rem;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--fg);
    font: inherit;
}
.bs-obs__num:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ---- Sessions --------------------------------------------------- */

.bs-sessions__title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 640;
    letter-spacing: -0.02em;
    margin: var(--space-8) 0 var(--space-6);
}

.bs-session-card {
    padding: var(--space-4) 0;
    border-bottom: 1px solid var(--border);
}

.bs-session-card__spot {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--text-lg);
}

.bs-session-card__meta {
    color: var(--fg-muted);
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
}

.bs-session-card__summary {
    margin-top: var(--space-1);
    font-size: 0.9rem;
}

.bs-sessions__empty {
    color: var(--fg-muted);
    padding: var(--space-6) 0;
}

/* ---- Stats ------------------------------------------------------ */

.bs-stats__title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 640;
    letter-spacing: -0.02em;
    margin: var(--space-8) 0 var(--space-4);
}

.bs-stats__summary {
    font-size: var(--text-lg);
    color: var(--fg-muted);
    margin-bottom: var(--space-6);
}

.bs-stats__spot-row,
.bs-stats__pt {
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
    font-variant-numeric: tabular-nums;
}

.bs-stats__scatter { margin-top: var(--space-6); }

/* ---- "Surf Life" lifetime stats — Surface B (bs-j1g4.4 Phase 3) -
   A single-column stack of cards: chip-grid totals, the spots-you-surf
   bar list (WebGL-less fallback, bs-7fx), block-glyph sparklines, the
   streak/heatmap strip, the per-spot accuracy, and records/badges.
   Everything wraps at ~390px — no wide table, no horizontal scroll
   (bs-yg45). */

.bs-surflife { max-width: 56rem; }

.bs-surflife__bar {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin: var(--space-8) 0 var(--space-6);
}

.bs-surflife__title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 640;
    letter-spacing: -0.02em;
}

.bs-surflife__sessions { font-size: var(--text-sm); white-space: nowrap; }

.bs-surflife__card {
    padding: var(--space-5) 0;
    border-top: 1px solid var(--border);
}

.bs-surflife__h {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    margin: 0 0 var(--space-3);
}

.bs-surflife__muted { color: var(--fg-muted); font-size: 0.9rem; }

/* Lifetime totals — a wrapping chip grid, never a wide table. */
.bs-surflife__totals {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.bs-chip {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    padding: var(--space-3) var(--space-4);
}

.bs-chip__n {
    font-family: var(--font-display);
    font-size: var(--text-xl, 1.5rem);
    font-weight: 660;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.bs-chip__label {
    color: var(--fg-muted);
    font-size: var(--text-sm);
    margin-top: var(--space-1);
}

/* Where you surf — count-ranked bars (doubles as the per-spot pivot). */
.bs-spotbars { list-style: none; margin: 0; padding: 0; }

.bs-spotbar {
    display: grid;
    grid-template-columns: minmax(6rem, 10rem) 1fr auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
}

.bs-spotbar__name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bs-spotbar__track {
    height: 0.5rem;
    background: var(--bg-elevated);
    border-radius: 999px;
    overflow: hidden;
}

.bs-spotbar__fill {
    display: block;
    height: 100%;
    background: var(--accent);
    border-radius: 999px;
}

.bs-spotbar__n {
    color: var(--fg-muted);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-sm);
}

/* Streak / heatmap / seasonality. */
.bs-streak {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-variant-numeric: tabular-nums;
    margin-bottom: var(--space-3);
}

.bs-streak__sep { color: var(--fg-muted); }

.bs-heatmap {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
    margin-bottom: var(--space-3);
}

.bs-heatmap__cell {
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 3px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
}

.bs-heatmap__cell.is-1 { background: var(--accent-soft, #cfe8ff); }
.bs-heatmap__cell.is-2 { background: var(--accent); opacity: 0.7; }
.bs-heatmap__cell.is-3 { background: var(--accent); }

.bs-season { display: flex; flex-direction: column; gap: 2px; }

.bs-season__spark {
    font-size: 1.4rem;
    line-height: 1;
    letter-spacing: 0.15em;
    color: var(--accent);
}

.bs-season__labels {
    color: var(--fg-muted);
    font-size: var(--text-sm);
    letter-spacing: 0.32em;
    font-variant-numeric: tabular-nums;
}

/* Conditions histograms — full-width block-glyph sparklines. */
.bs-histogram {
    display: grid;
    grid-template-columns: minmax(4.5rem, 7rem) 1fr auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
}

.bs-histogram__label { font-weight: 600; }

.bs-histogram__spark {
    font-size: 1.5rem;
    line-height: 1;
    letter-spacing: 0.06em;
    color: var(--accent);
    overflow: hidden;
}

.bs-histogram__range {
    color: var(--fg-muted);
    font-size: var(--text-sm);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Accuracy for you. */
.bs-accuracy__lead { font-size: var(--text-lg); }

.bs-accuracy__meta {
    color: var(--fg-muted);
    font-size: var(--text-sm);
    margin-top: var(--space-1);
    font-variant-numeric: tabular-nums;
}

.bs-accuracy__spots {
    list-style: none;
    margin: var(--space-3) 0 0;
    padding: 0;
}

.bs-accuracy__spot {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    font-variant-numeric: tabular-nums;
}

.bs-accuracy__spot-name { flex: 1 1 auto; font-weight: 600; }
.bs-accuracy__spot-n { color: var(--fg-muted); font-size: var(--text-sm); }

/* Records & badges. */
.bs-records { list-style: none; margin: 0; padding: 0; }

.bs-records__item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
}

.bs-records__k { color: var(--fg-muted); }
.bs-records__v { font-weight: 600; text-align: right; }

.bs-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

.bs-badge {
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: var(--space-1) var(--space-3);
    font-size: var(--text-sm);
    background: var(--bg-elevated);
}

.bs-surflife__empty { color: var(--fg-muted); padding: var(--space-6) 0; }

.bs-surflife__empty-head {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--fg);
    margin-bottom: var(--space-2);
}

.bs-surflife__cta {
    display: inline-block;
    margin-top: var(--space-4);
    font-weight: 600;
}

/* ---- Manage recordings — Surface A (bs-j1g4.3 Phase 2) ---------- */

.bs-sessions__bar {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.bs-sessions__log {
    flex: none;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--accent);
    color: var(--accent-fg);
    font-weight: 600;
    text-decoration: none;
}
.bs-sessions__log:hover { filter: brightness(1.06); }

/* Filter / sort / search bar — wraps, never a horizontal scroll (bs-yg45). */
.bs-sessions__filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    margin: var(--space-4) 0 var(--space-6);
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
}
.bs-sessions__filters input,
.bs-sessions__filters select {
    min-width: 0;
    max-width: 100%;
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg, transparent);
    color: inherit;
    font-size: var(--text-sm);
}
.bs-filter__q { flex: 1 1 12rem; }
.bs-filter__spot { flex: 0 1 9rem; }
.bs-sessions__filters .bs-filter__range {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-sm);
    color: var(--fg-muted);
}
.bs-filter__go {
    flex: none;
    padding: var(--space-1) var(--space-4);
    border: none;
    border-radius: var(--radius-sm, 6px);
    background: var(--accent);
    color: var(--accent-fg);
    font-weight: 600;
    cursor: pointer;
}

/* Enriched list card. */
.bs-session-card__head {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.bs-session-card__stars { color: var(--accent); letter-spacing: 0.05em; }
.bs-session-card__lock { font-size: var(--text-sm); }
.bs-session-card__title { font-weight: 600; margin-top: var(--space-1); }
.bs-session-card__obs {
    margin-top: var(--space-1);
    font-size: 0.9rem;
    color: var(--fg-muted);
}
.bs-session-card__obs-you { color: var(--fg); }
.bs-session-card__actions {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-2);
}
.bs-session-card__view,
.bs-session-card__edit {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
}
.bs-session-card__view:hover,
.bs-session-card__edit:hover { text-decoration: underline; }

.bs-sessions__empty-head {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    margin-bottom: var(--space-2);
}
.bs-sessions__cta {
    display: inline-block;
    margin-top: var(--space-4);
    color: var(--accent);
    font-weight: 600;
    text-decoration: none;
}
.bs-sessions__more { margin-top: var(--space-6); text-align: center; }
.bs-sessions__next {
    display: inline-block;
    padding: var(--space-2) var(--space-6);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--accent);
    font-weight: 600;
    text-decoration: none;
}

/* Single-session detail / edit. */
.bs-session-detail { max-width: 56rem; }
.bs-detail__back {
    display: inline-block;
    margin: var(--space-6) 0 var(--space-2);
    color: var(--fg-muted);
    text-decoration: none;
    font-size: var(--text-sm);
}
.bs-detail__title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 640;
    letter-spacing: -0.02em;
}
.bs-detail__when {
    color: var(--fg-muted);
    font-variant-numeric: tabular-nums;
    margin-bottom: var(--space-4);
}
.bs-detail__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}
.bs-detail__actions button {
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg-elevated);
    color: inherit;
    cursor: pointer;
    font-size: var(--text-sm);
}
.bs-detail__delete-open { color: var(--danger, #c0392b); }
.bs-detail__confirm {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3);
    margin-bottom: var(--space-4);
    border: 1px solid var(--danger, #c0392b);
    border-radius: var(--radius-md);
}
.bs-detail__confirm-yes {
    background: var(--danger, #c0392b) !important;
    color: #fff !important;
    border: none !important;
}
.bs-detail__rating { font-size: var(--text-lg); margin-bottom: var(--space-4); }
.bs-detail__stars { color: var(--accent); }
.bs-obs-pred,
.bs-detail__snapshot,
.bs-detail__notes,
.bs-detail__media {
    padding: var(--space-4) 0;
    border-top: 1px solid var(--border);
}
.bs-detail__section-head {
    font-weight: 600;
    margin-bottom: var(--space-2);
    color: var(--fg-muted);
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.bs-obs-pred__head { font-weight: 600; margin-bottom: var(--space-1); }
.bs-obs-pred__delta { color: var(--accent); margin-top: var(--space-1); }
.bs-detail__facts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
    color: var(--fg-muted);
}
.bs-detail__snapshot-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    font-variant-numeric: tabular-nums;
}
.bs-detail__media-strip { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.bs-detail__media-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    max-width: 8rem;
}
.bs-detail__media-thumb {
    font-size: 2rem;
    width: 5rem; height: 5rem;
    display: flex; align-items: center; justify-content: center;
    background: var(--bg-elevated);
    border-radius: var(--radius-md);
}
.bs-detail__media-key {
    font-size: 0.75rem;
    color: var(--fg-muted);
    word-break: break-all;
}
.bs-detail__media-reveal {
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    color: inherit;
    cursor: pointer;
}
.bs-detail__deleted { padding: var(--space-8) 0; color: var(--fg-muted); }

/* Edit form — a single column of labelled rows. */
.bs-edit { display: flex; flex-direction: column; gap: var(--space-3); }
.bs-edit__row { display: flex; flex-direction: column; gap: var(--space-1); }
.bs-edit__row input,
.bs-edit textarea {
    max-width: 100%;
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 6px);
    background: var(--bg, transparent);
    color: inherit;
    font: inherit;
}
.bs-edit textarea { min-height: 4rem; resize: vertical; }
.bs-edit__num { max-width: 8rem; }
.bs-edit__buttons { display: flex; gap: var(--space-3); margin-top: var(--space-2); }
.bs-edit__save {
    padding: var(--space-2) var(--space-6);
    border: none;
    border-radius: var(--radius-md);
    background: var(--accent);
    color: var(--accent-fg);
    font-weight: 600;
    cursor: pointer;
}
.bs-edit__cancel {
    padding: var(--space-2) var(--space-6);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    color: inherit;
    cursor: pointer;
}

@media (max-width: 640px) {
    /* No horizontal page scroll at phone width (bs-yg45): the filter bar
       and detail facts stack/wrap, full-width controls. */
    .bs-sessions__filters { gap: var(--space-2); }
    .bs-filter__q,
    .bs-filter__spot { flex: 1 1 100%; }
    .bs-detail__facts { gap: var(--space-2); }
    /* Surf Life (bs-j1g4.4): tighter chip grid; the bar / histogram rows
       keep their 3-col grid but with a narrower label track so nothing
       overflows 390px. */
    .bs-surflife__totals {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--space-2);
    }
    .bs-spotbar { grid-template-columns: minmax(4.5rem, 8rem) 1fr auto; }
    .bs-histogram { grid-template-columns: minmax(3.5rem, 5rem) 1fr auto; }
    .bs-histogram__spark, .bs-season__spark { font-size: 1.25rem; }
}

/* ---- Map -------------------------------------------------------- */

.bs-map-widget {
    position: relative;            /* containing block for the fallback */
    width: 100%;
    height: 460px;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
}

/* bs-4zt/bs-x13: WebGL fail-safe.  Server-rendered and visible by
   default — no-JS, no-WebGL, or a lost context all leave it showing.
   map.js sets `data-bs-map-mode="interactive"' on .bs-map-widget once a
   live WebGL context is confirmed, and the rule below hides it then.
   bs-x13: it carries a dismissible banner (browser-aware "enable WebGL"
   hint + help link) and a persistent spot-link list; top-aligned and
   scrollable so the list never clips. */
.bs-map-widget__fallback {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-4);
    text-align: center;
    color: var(--fg-muted);
    background: var(--bg-elevated);
    overflow-y: auto;
}

.bs-map-widget[data-bs-map-mode="interactive"] .bs-map-widget__fallback {
    display: none;
}

.bs-map-widget__fallback-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--fg);
}

/* bs-x13: the dismissible banner.  Pure-CSS checkbox hack — the
   visually-hidden toggle, when checked, hides its banner sibling; needs
   no JS, so it works on the no-JS path too.  The spot list is a SEPARATE
   sibling, so dismissing the banner leaves spot navigation intact. */
.bs-map-widget__dismiss-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

.bs-map-widget__banner {
    position: relative;
    max-width: 32rem;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
}

.bs-map-widget__dismiss-toggle:checked ~ .bs-map-widget__banner {
    display: none;
}

.bs-map-widget__dismiss {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    cursor: pointer;
    line-height: 1;
    font-size: var(--text-lg);
    color: var(--fg-muted);
    padding: 0 var(--space-1);
}

.bs-map-widget__dismiss:hover {
    color: var(--fg);
}

.bs-map-widget__hint {
    font-size: var(--text-sm);
}

.bs-map-widget__help-link {
    color: var(--accent);
}

.bs-map-widget__spots {
    width: 100%;
    max-width: 32rem;
}

.bs-map-widget__spots-heading {
    margin: 0 0 var(--space-2);
    font-weight: 600;
    color: var(--fg);
}

.bs-map-widget__spot-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    justify-content: center;
}

.bs-map-widget__spot-list a {
    display: inline-flex;
    padding: var(--space-1) var(--space-3);
    border-radius: 999px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--fg);
    text-decoration: none;
    font-size: var(--text-sm);
}

.bs-map-widget__spot-list a:hover {
    border-color: var(--accent);
    color: var(--accent);
}

/* bs-x13: the /help/webgl page reached from the fallback. */
.bs-webgl-help {
    max-width: 44rem;
    margin: 0 auto;
    padding: var(--space-6) var(--space-4);
}

.bs-webgl-help__title {
    font-family: var(--font-display);
    margin: 0 0 var(--space-2);
}

.bs-webgl-help__intro {
    color: var(--fg-muted);
    margin: 0 0 var(--space-4);
}

.bs-webgl-help__list dt {
    font-weight: 600;
    margin-top: var(--space-4);
}

.bs-webgl-help__list dd {
    margin: var(--space-1) 0 0;
    color: var(--fg-muted);
}

.bs-webgl-help__back {
    display: inline-block;
    margin-top: var(--space-6);
    color: var(--accent);
}

.bs-map-widget__time {
    width: 100%;
    margin: var(--space-3) 0;
    accent-color: var(--accent);
}

/* D4: clickable spot-pin overlay (DOM anchors, WebGL-independent). */
.bs-map-pins {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

/* bs-x13: in the no-WebGL fallback the server-rendered spot list is the
   single source of spot navigation, so hide map.js's redundant pin
   overlay until the map is actually interactive.  The server render
   never sets data-bs-map-mode, so this also keeps a no-JS page tidy.
   bs-1wqz: the pins now live in the bottom sheet's chips slot, so reach
   them through `.bs-map-sheet'. */
.bs-map-widget:not([data-bs-map-mode="interactive"]) ~ .bs-map-sheet .bs-map-pins {
    display: none;
}

.bs-map-pin {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--fg);
    text-decoration: none;
    font-size: var(--text-sm);
    border: 1px solid var(--border);
    transition: color 0.15s ease, border-color 0.15s ease;
}

.bs-map-pin:hover {
    border-color: var(--accent);
    color: var(--accent);
    text-decoration: none;
}

/* ---- Map bottom sheet (bs-1wqz) -------------------------------- *
 * The /map controls — time scrubber, spot chips and the overlay key.
 * Desktop: a plain stacked block below the map (the grip + the pure-CSS
 * toggle are inert here, the drawer is always open).  The `@640' block
 * below re-homes this as a fixed, frosted sheet that overlays the
 * full-bleed map and collapses to a peek.
 * ---------------------------------------------------------------- */

.bs-map-sheet { margin-top: var(--space-4); }

/* The expand toggle is a visually-hidden checkbox (the same hack as the
   fallback dismiss); the grip <label> drives it with no JS. */
.bs-map-sheet__toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

/* The grip is a phone affordance — hidden on wider screens, where the
   drawer is simply always open. */
.bs-map-sheet__handle { display: none; }

.bs-map-sheet__grip {
    width: 2.25rem;
    height: 0.3rem;
    border-radius: 999px;
    background: var(--border);
}

.bs-map-sheet__scrubber {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.bs-map-sheet .bs-map-widget__time {
    flex: 1 1 auto;
    width: auto;
    margin: 0;
    min-height: 44px;              /* a comfortable thumb target */
}

.bs-map-sheet__time-label {
    flex: 0 0 auto;
    min-width: 5.5rem;             /* reserve width so the slider does not
                                      jump when JS fills the label in */
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--fg-muted);
    white-space: nowrap;
}

.bs-map-sheet__drawer { margin-top: var(--space-3); }

.bs-map-sheet__legend { margin-top: var(--space-3); }

.bs-map-sheet__legend-title {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-subtle);
}

.bs-map-sheet__legend-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--text-sm);
    color: var(--fg-muted);
}

.bs-map-sheet__legend-term { font-weight: 600; color: var(--fg); }

/* The wind particles are omitted under reduced-motion (map.js / D5), so
   drop their key line too — the legend must not promise motion the map
   will not show. */
@media (prefers-reduced-motion: reduce) {
    .bs-map-sheet__legend-item--wind { display: none; }
}

/* ---- /map mobile: full-bleed map + the sheet as a true bottom sheet
 *      (bs-1wqz) -------------------------------------------------- */
@media (max-width: 640px) {
    /* Fill the gap between the (wrapping, variable-height) header and the
       fixed tab bar.  A flex column on the map page lets the map grow
       however many rows the header wraps to — more robust than a
       `100dvh - <fixed header>' calc when the header height is auto. */
    body:has(.bs-map-page) {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
        min-height: 100dvh;
    }
    .bs-map-page {
        flex: 1 1 auto;
        display: flex;
        min-height: 0;             /* let the flex child shrink */
        animation: none;           /* a transform here would re-anchor the
                                      fixed sheet to .bs-map, not the
                                      viewport — drop the load reveal */
    }
    .bs-map-page .bs-map-widget {
        flex: 1 1 auto;
        height: auto;              /* override the 460px desktop box */
        min-height: 0;
        border-radius: 0;
        border-left: 0;
        border-right: 0;
    }

    /* Overlaid controls raised to >=44px (maplibre-gl.css ships 29px). */
    .bs-map-widget .maplibregl-ctrl-top-right {
        top: var(--space-2);
        right: var(--space-2);
    }
    .bs-map-widget .maplibregl-ctrl-group button {
        width: 44px;
        height: 44px;
    }

    /* The sheet becomes a fixed, frosted panel docked above the tab bar,
       overlaying the bottom of the map.  The grip collapses it to a peek
       (scrubber only) and expands it to reveal the chips + key. */
    .bs-map-sheet {
        position: fixed;
        left: 0;
        right: 0;
        bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
        z-index: 55;               /* above the map, below the tab bar (60) */
        margin: 0;
        padding: var(--space-1) var(--space-4) var(--space-3);
        max-height: 60vh;
        max-height: 60dvh;
        overflow-y: auto;
        background: color-mix(in srgb, var(--bg) 92%, transparent);
        -webkit-backdrop-filter: saturate(1.5) blur(12px);
        backdrop-filter: saturate(1.5) blur(12px);
        border-top: 1px solid var(--border);
        border-top-left-radius: var(--radius-lg);
        border-top-right-radius: var(--radius-lg);
        box-shadow: 0 -10px 30px -22px var(--shadow-color);
    }
    .bs-map-sheet__handle {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 44px;          /* the grip is a >=44px touch target */
        cursor: pointer;
    }
    /* Peek: the drawer (chips + key) is collapsed; the scrubber stays one
       thumb away.  Tapping the grip reveals the drawer. */
    .bs-map-sheet__drawer { display: none; }
    .bs-map-sheet__toggle:checked ~ .bs-map-sheet__drawer { display: block; }
}

/* ---- Wind-state pill — semantic, theme-aware (all six states) --- */

.bs-wind-state {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.1rem var(--space-2);
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    background: var(--wind-default-bg);
    color: var(--wind-default-fg);
}

.bs-wind-state--offshore {
    background: var(--wind-offshore-bg); color: var(--wind-offshore-fg);
}
.bs-wind-state--cross {
    background: var(--wind-cross-bg);    color: var(--wind-cross-fg);
}
.bs-wind-state--onshore {
    background: var(--wind-onshore-bg);  color: var(--wind-onshore-fg);
}
.bs-wind-state--glassy {
    background: var(--wind-glassy-bg);   color: var(--wind-glassy-fg);
}

/* ---- Rating stars (MSW split-bar) ------------------------------- */

.bs-rating {
    display: inline-flex;
    gap: 2px;
    font-size: 0.9rem;
}

.bs-rating__star { color: var(--rating-off); }
.bs-rating__star--on { color: var(--rating-on); }
.bs-rating__star--faded { color: var(--rating-faded); }

/* F4: MSW / Personal rating chip. */
.bs-rating-chip { display: inline-flex; flex-direction: column; gap: 2px; }
.bs-rating-chip__tabs { display: inline-flex; gap: var(--space-1); }
.bs-rating-chip__tab {
    padding: 0 var(--space-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--fg-muted);
    cursor: pointer;
    font: inherit;
    font-size: 0.72rem;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.bs-rating-chip__tab:hover { color: var(--fg); border-color: var(--accent); }
.bs-rating-chip__tab:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.bs-rating-chip__tab--active {
    background: var(--accent);
    color: var(--accent-fg);
    border-color: var(--accent);
    font-weight: 600;
}
.bs-rating-chip--hidden { display: none; }

/* ---- Plan-your-trip affiliate panel (bs-hvg7) ------------------- *
 * A clearly-secondary, geo-gated travel garnish BELOW the forecast —
 * never co-equal with it (§10).  Subdued surface, the Flights/Hotels
 * micro-toggle reuses the rating-chip token vocabulary.
 * ---------------------------------------------------------------- */

.bs-plan-trip {
    margin-top: var(--space-6);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-subtle);
}
.bs-plan-trip__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}
.bs-plan-trip__title {
    font-weight: 600;
    font-size: var(--text-sm);
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--fg-muted);
}
.bs-plan-trip__hint {
    font-size: 0.78rem;
    color: var(--fg-subtle);
}
.bs-plan-trip__tabs {
    display: inline-flex;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}
.bs-plan-trip__tab {
    padding: 0 var(--space-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--fg-muted);
    cursor: pointer;
    font: inherit;
    font-size: 0.72rem;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.bs-plan-trip__tab:hover { color: var(--fg); border-color: var(--accent); }
.bs-plan-trip__tab:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.bs-plan-trip__tab--active {
    background: var(--accent);
    color: var(--accent-fg);
    border-color: var(--accent);
    font-weight: 600;
}
.bs-plan-trip__cta {
    display: inline-block;
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 600;
    text-decoration: none;
}
.bs-plan-trip__cta:hover { background: var(--accent); color: var(--accent-fg); }
.bs-plan-trip__cta:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.bs-plan-trip__disclosure {
    margin: var(--space-3) 0 0;
    font-size: 0.72rem;
    color: var(--fg-subtle);
}

/* ---- Footer ----------------------------------------------------- */

.bs-footer {
    margin-top: var(--space-12);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
    color: var(--fg-subtle);
    font-size: var(--text-sm);
    text-align: center;
}
.bs-footer__line + .bs-footer__line { margin-top: var(--space-1); }
.bs-footer__affiliate { font-size: 0.72rem; color: var(--fg-subtle); }

/* ---- Mobile bottom tab bar (bs-ppyb) ---------------------------- *
 * Phone-width primary nav: a fixed, thumb-reachable row of ≥44px tabs.
 * Hidden above 640px (the top-bar nav serves there); the `@640' block
 * flips `display' and clears space for it under the page content.
 * ---------------------------------------------------------------- */

.bs-tabbar {
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;                       /* above the sticky header (50) */
    justify-content: space-around;
    align-items: stretch;
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    -webkit-backdrop-filter: saturate(1.5) blur(12px);
    backdrop-filter: saturate(1.5) blur(12px);
    border-top: 1px solid var(--border);
}

/* Each tab — and the `More' summary — is an icon over a label, the
   whole control a ≥44px square-ish touch target. */
.bs-tabbar__tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 44px;
    padding: var(--space-1) var(--space-2);
    color: var(--fg-muted);
    font-size: 0.66rem;
    letter-spacing: 0.01em;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.15s ease;
}
.bs-tabbar__tab:hover { color: var(--fg); text-decoration: none; }
.bs-tabbar__tab:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--accent-soft);
}
.bs-tabbar__svg { width: 22px; height: 22px; display: block; }
.bs-tabbar__label { line-height: 1; }

/* `More' — a native <details>; the menu pops above the bar, no JS. */
.bs-tabbar__more { position: relative; flex: 1 1 0; display: flex; }
.bs-tabbar__more > summary { list-style: none; }
.bs-tabbar__more > summary::-webkit-details-marker { display: none; }

.bs-tabbar__menu {
    position: absolute;
    right: var(--space-2);
    bottom: calc(100% + var(--space-2));
    min-width: 11rem;
    display: flex;
    flex-direction: column;
    padding: var(--space-1);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
}
.bs-tabbar__menu-link {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: var(--space-2) var(--space-3);
    color: var(--fg);
    border-radius: var(--radius-sm);
    font-size: 0.95rem;
}
.bs-tabbar__menu-link:hover {
    background: var(--bg-subtle);
    text-decoration: none;
}

/* ---- Now-panel — the hero current-conditions read --------------- *
 * This is THE glance-value of the product.  De-boxed: no card border,
 * generous air, a large Fraunces number, the rating prominent.
 * ---------------------------------------------------------------- */

.bs-now-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4) 0 var(--space-8);
    margin-bottom: var(--space-8);
    border-bottom: 1px solid var(--border);
}

.bs-now-panel__title {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--fg-subtle);
}

.bs-now-panel__body {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-6);
}

.bs-now-panel__primary {
    font-family: var(--font-display);
    font-size: var(--text-hero);
    font-weight: 640;
    line-height: 1;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--fg);
}

.bs-now-panel__wind,
.bs-now-panel__energy {
    color: var(--fg-muted);
    font-size: var(--text-lg);
    font-variant-numeric: tabular-nums;
}

.bs-now-panel__energy-swatch {
    display: inline-block;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    vertical-align: middle;
}

/* ---- Wide-table scroll container -------------------------------- */

/* Reusable horizontal-scroll wrapper for any table too wide for a phone:
   the table scrolls WITHIN its own box instead of pushing the whole page
   sideways (bs-9lug — /weather had 227px of page-level overflow at 390px).
   Behaviour only — no border/background — so it never double-skins a table
   that already sits in a bordered panel.  The forecast table composes this
   with .bs-forecast-wrap below, which adds its panel skin. */
.bs-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* ---- Forecast table — 10-day × 3-hourly grid -------------------- */

.bs-forecast-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-8);
    background: var(--bg-elevated);
}

.bs-forecast__row-label {
    text-align: left;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--fg-muted);
    background: var(--bg-subtle);
    position: sticky;
    left: 0;
    min-width: 8rem;
}

.bs-forecast__th-row {
    background: var(--bg-subtle);
    position: sticky;
    left: 0;
}

.bs-forecast__th {
    font-weight: 600;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--fg-subtle);
}

.bs-forecast__cell {
    min-width: 3.5rem;
}

.bs-forecast__cell-swell,
.bs-forecast__cell-wind {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.1rem;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
}

.bs-swell__arrow,
.bs-wind__arrow {
    font-size: 1.1rem;
    color: var(--fg-muted);
}

.bs-swell__hs,
.bs-wind__speed {
    font-weight: 600;
}

.bs-swell__period {
    color: var(--fg-subtle);
    font-size: 0.8rem;
}

.bs-forecast__cell-tide {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    height: 2.5rem;
    color: var(--fg-subtle);
    font-size: 0.8rem;
}

/* ---- Locator card + spot-meta sidebar --------------------------- */

.bs-aside {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
    margin-bottom: var(--space-8);
}

.bs-locator-map {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background:
        linear-gradient(180deg,
            var(--bg-subtle) 0%,
            color-mix(in srgb, var(--accent) 10%, var(--bg-subtle)) 100%);
}

/* Real MapLibre mini-map (bs-vcv): map.js binds the OSM basemap +
   a centre marker to .bs-locator-map__map.  MapLibre fills its
   container, so the container MUST carry an explicit height. */
.bs-locator-map__map {
    height: 14rem;
    width: 100%;
}

/* Fallback shown only where map.js can't init (no WebGL/network):
   the empty container would otherwise collapse to a bare strip. */
.bs-locator-map__map:empty::after {
    content: "≈≈≈";
    display: flex;
    height: 100%;
    align-items: center;
    justify-content: center;
    color: var(--fg-subtle);
    font-family: var(--font-display);
    font-size: 1.5rem;
    letter-spacing: 0.02em;
}

.bs-locator-map__coords {
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: 0.8rem;
    color: var(--fg-muted);
    background: var(--bg-elevated);
}

.bs-spot-meta {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    padding: var(--space-4) var(--space-6);
}

.bs-spot-meta__row {
    padding: var(--space-2) 0;
    font-size: 0.9rem;
    color: var(--fg-muted);
}

.bs-spot-meta__row + .bs-spot-meta__row {
    border-top: 1px solid var(--border);
}

@media (max-width: 720px) {
    .bs-aside {
        grid-template-columns: 1fr;
    }
}

/* Absent (un-ingested) datum — rendered as a muted "n/a", never a
   fabricated 0.  No heatmap colour; this is the honest empty cell. */
.bs-cell--na {
    color: var(--fg-subtle);
    font-style: italic;
    font-size: 0.8rem;
    background: none !important;
}

/* Dashboard empty-state: no forecast ingested for this spot. */
.bs-no-forecast {
    margin: var(--space-6) 0;
    padding: var(--space-8) var(--space-4);
    border: 1px dashed var(--border);
    border-radius: var(--radius-md);
    text-align: center;
    color: var(--fg-muted);
}

.bs-no-forecast__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--text-lg);
    color: var(--fg);
    margin-bottom: var(--space-2);
}

.bs-no-forecast__body {
    font-size: 0.9rem;
}

/* ---- Mobile-first day-card strip + hourly disclosure (bs-s7to) ---- */

/* The horizontal strip of per-day summary cards sits ABOVE the hourly
   table and is the lead "what's it doing today / this week" read on a
   phone.  Desktop keeps the full table as the primary surface, so the
   strip is phone-only: hidden by default, revealed at <=640px below. */
.bs-day-strip {
    display: none;
    gap: var(--space-3);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    margin: 0 0 var(--space-6);
    padding-bottom: var(--space-2);
}

.bs-day-card {
    flex: 0 0 auto;
    min-width: 7rem;
    scroll-snap-align: start;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
}

/* Today reads first — a soft accent frame, not a loud fill. */
.bs-day-card--today {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.bs-day-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.bs-day-card__label {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--fg);
}

/* Reuses the now-panel energy-swatch idiom (theme.css) at card scale. */
.bs-day-card__swatch {
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    flex: 0 0 auto;
}

.bs-day-card__hs {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 640;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--fg);
}

.bs-day-card__sub {
    font-size: var(--text-sm);
    color: var(--fg-muted);
    font-variant-numeric: tabular-nums;
}

/* The day card's quality stars are a compact glance — trim the table/now
   scale a touch so five stars sit on one line in a 7rem card. */
.bs-day-card .bs-rating { font-size: 0.85rem; }

/* The "Full hourly table" disclosure.  The toggle is phone-only (desktop
   shows the table outright); the collapse class only takes effect at
   phone width, so desktop and JS-off both keep the table visible. */
.bs-forecast-disclosure__toggle {
    display: none;
    width: 100%;
    min-height: 44px;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    color: var(--fg);
    font: inherit;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}
.bs-forecast-disclosure__toggle:hover { border-color: var(--accent); }
.bs-forecast-disclosure__toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.bs-forecast-disclosure__caret {
    display: inline-block;
    color: var(--fg-muted);
    transition: transform 0.15s ease;
}
.bs-forecast-disclosure__caret--open { transform: rotate(90deg); }

@media (max-width: 640px) {
    .bs-day-strip { display: flex; }
    .bs-forecast-disclosure__toggle { display: flex; }
    /* On a phone the table collapses behind the disclosure; the class is
       toggled by the Datastar `$hourly' signal (data-class on the body).
       Scoped to phone width so desktop is never affected. */
    .bs-forecast-disclosure__body--collapsed { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .bs-forecast-disclosure__caret { transition: none; }
}
