/*
 * Sensortech V2 — design tokens + components.
 * Lifted from claude/design_handoff_meter_overview/design/styles.css
 * (cool greys, brand blue, Inter / JetBrains Mono). The .st-* class names
 * are the canonical primitives. A short alias section at the bottom keeps
 * older class names (.card, .kpi, .tabs, .severity, .tag-chip) working
 * until every view has been migrated.
 */

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap");

:root {
    --st-bg: #fafaf9;
    --st-card: #ffffff;
    --st-topbar: #dad7d1;
    --st-card-soft: #f3f2ee;
    --st-border: #e6e3dd;
    --st-border-strong: #dbd6ca;
    --st-text: #1f2630;
    --st-text-muted: #6b7480;
    --st-text-soft: #8a8f99;
    --st-accent: #2c5fb3;
    --st-accent-soft: #bad0ee;
    --st-accent-bg: #eaf1fb;
    --st-good: #1f7a4d;
    --st-good-bg: #e6f3ec;
    --st-warn: #b56a00;
    --st-warn-bg: #fbf0db;
    --st-bad: #b3261e;
    --st-bad-bg: #fbe5e3;
    /* Chart accent: hue-rotated equivalents of --st-accent / --st-accent-soft
       for paired series (e.g. humidity bars next to temperature bars). Same
       saturation + lightness as the corresponding blue tokens so they read
       at the same visual weight. */
    --st-warm: #b3782c;
    --st-warm-soft: #eed8b9;
    --st-shadow-sm: 0 1px 2px rgba(20, 25, 35, 0.04);
    --st-shadow-md:
        0 1px 3px rgba(20, 25, 35, 0.05), 0 8px 24px rgba(20, 25, 35, 0.04);
    --st-radius: 10px;
    --st-radius-lg: 14px;
    --st-font:
        "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui,
        sans-serif;
    --st-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
}

* {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
    font-family: var(--st-font);
    font-size: 14px;
    line-height: 1.45;
    color: var(--st-text);
    background: var(--st-bg);
    -webkit-font-smoothing: antialiased;
}

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

code,
pre {
    font-family: var(--st-mono);
}
code {
    font-size: 0.92em;
    color: var(--st-text);
    background: var(--st-card-soft);
    padding: 1px 5px;
    border-radius: 3px;
}

h1 {
    font-size: 24px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0 0 4px;
}
h2 {
    font-size: 16px;
    font-weight: 600;
    margin: 24px 0 10px;
}
h3 {
    font-size: 13px;
    font-weight: 600;
    margin: 20px 0 8px;
    color: var(--st-text);
}

.st-mono {
    font-family: var(--st-mono);
}
.st-muted {
    color: var(--st-text-muted);
}
.st-soft {
    color: var(--st-text-soft);
}

/* ── Topbar ── */
.st-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 24px;
    background: var(--st-topbar);
    box-shadow: 0 1px 2px rgba(20, 25, 35, 0.06);
    position: sticky;
    top: 0;
    /* Above Leaflet's default control z-index (.leaflet-control is 800) so
     the dropdown menu doesn't get covered by map tiles/controls. */
    z-index: 1000;
}
.st-logo {
    display: flex;
    align-items: center;
    color: var(--st-text);
}
.st-logo:hover {
    text-decoration: none;
}
.st-logo-mark {
    height: 28px;
    width: auto;
    flex: 0 0 auto;
    display: block;
}
.st-topbar-right {
    display: flex;
    align-items: center;
    gap: 12px;
}
/* Topbar search — rounded pill (white card, soft border) with the
   search icon and the input inside it. position: relative also anchors
   the dropdown panel below. */
.st-search {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border: 1px solid var(--st-border-strong);
    border-radius: 999px;
    background: #fff;
    color: var(--st-text-muted);
    font-size: 13px;
    min-width: 220px;
    margin: 0;
}
.st-search input,
.st-search input[type="text"],
.st-search input[type="search"] {
    /* Strip the browser's native search-field decoration (inset rounded
       pill, built-in padding, cancel button) so the input sits flush
       inside our pill instead of double-bordering it. */
    -webkit-appearance: none;
    appearance: none;
    border: none;
    outline: none;
    background: transparent;
    box-shadow: none;
    font: inherit;
    color: var(--st-text);
    flex: 1;
    min-width: 0;
    padding: 0;
    margin: 0;
    border-radius: 0;
    height: auto;
}
.st-search input[type="search"]::-webkit-search-decoration,
.st-search input[type="search"]::-webkit-search-cancel-button,
.st-search input[type="search"]::-webkit-search-results-button,
.st-search input[type="search"]::-webkit-search-results-decoration {
    -webkit-appearance: none;
    appearance: none;
}
.st-search input:focus {
    box-shadow: none;
    outline: none;
}
.st-search input::placeholder {
    color: var(--st-text-soft);
}

/* Mobile search: an icon button replaces the inline pill (which otherwise
   widens the topbar). Tapping it opens the input as an overlay below the bar
   — JS toggles `.search-open` on .st-topbar. Hidden on desktop. */
.st-search-toggle {
    display: none;
}
@media (max-width: 600px) {
    .st-search-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        padding: 0;
        border: 1px solid var(--st-border-strong);
        border-radius: 8px;
        background: #fff;
        color: var(--st-text-muted);
        cursor: pointer;
    }
    .st-search {
        display: none;
    }
    .st-topbar.search-open .st-search {
        display: flex;
        position: absolute;
        top: 100%;
        left: 12px;
        right: 12px;
        margin-top: 8px;
        min-width: 0;
        z-index: 40;
        box-shadow: var(--st-shadow-sm);
    }
    /* ≥16px so iOS Safari doesn't auto-zoom the page when the input focuses.
       Must match the [type="search"] selector below — the base rule sets
       `font: inherit` (13px) at higher specificity and would otherwise win. */
    .st-search input,
    .st-search input[type="text"],
    .st-search input[type="search"] {
        font-size: 16px;
    }
}

/* Dropdown panel below the topbar input. Light-themed (white card) to
   distinguish from the dark .st-menu-panel — system controls are dark,
   content surfaces are light. The dropdown HTML is server-rendered by
   /search/quick and swapped in by app/javascript/search.js. */
.st-search-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow: var(--st-shadow-md);
    z-index: 30; /* above .st-menu-panel's 20 if both ever open together */
    max-height: 70vh;
    overflow-y: auto;
    padding: 6px;
    color: var(--st-text);
    font-size: 13px;
}
.st-search-dropdown[hidden] {
    display: none;
}
.st-search-section {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--st-text-muted);
    padding: 8px 10px 4px;
}
.st-search-result {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 7px 10px;
    border-radius: 6px;
    color: var(--st-text);
    line-height: 1.3;
}
.st-search-result:hover,
.st-search-result:focus-visible {
    background: var(--st-card-soft);
    color: var(--st-text);
    text-decoration: none;
    outline: none;
}
.st-search-result-title {
    font-weight: 500;
}
.st-search-result-meta {
    color: var(--st-text-muted);
    font-size: 12px;
}
.st-search-empty {
    padding: 16px 12px;
    color: var(--st-text-muted);
    text-align: center;
}
.st-search-foot {
    border-top: 1px solid var(--st-border);
    margin-top: 6px;
    padding: 8px 10px 4px;
    text-align: center;
}
.st-search-foot a {
    font-size: 12px;
    color: var(--st-accent);
}

/* On the full results page, each card holds a vertical list of rows. */
.st-search-result-list {
    display: flex;
    flex-direction: column;
}
.st-search-result-list .st-search-result {
    border-bottom: 1px solid var(--st-border);
    border-radius: 0;
}
.st-search-result-list .st-search-result:last-child {
    border-bottom: none;
}
.st-iconbtn {
    width: 34px;
    height: 34px;
    border: 1px solid var(--st-border-strong);
    border-radius: 8px;
    background: #fff;
    color: var(--st-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    font: inherit;
    cursor: pointer;
    padding: 0;
}
.st-iconbtn:hover {
    color: var(--st-text);
    border-color: var(--st-text-muted);
}

/* Inline row-edit pen — borderless, faded, sized in em so it never grows the
   table row height. */
.st-rowedit {
    display: inline-flex;
    line-height: 0;
    color: var(--st-text-muted);
    opacity: 0.5;
}
.st-rowedit:hover {
    color: var(--st-accent);
    opacity: 1;
}
.st-rowedit svg {
    width: 1em;
    height: 1em;
}

/* Topbar menu (details/summary popover) */
.st-menu {
    position: relative;
}
.st-menu > summary {
    list-style: none;
    width: 34px;
    height: 34px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--st-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.st-menu > summary::-webkit-details-marker {
    display: none;
}
.st-menu > summary:hover {
    color: var(--st-text);
}
.st-menu[open] > summary {
    background: transparent;
    color: var(--st-text);
}
.st-menu-panel {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    background: #1f2630;
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: var(--st-radius);
    box-shadow:
        0 4px 6px rgba(0, 0, 0, 0.2),
        0 12px 32px rgba(0, 0, 0, 0.25);
    min-width: 240px;
    padding: 6px;
    z-index: 20;
    color: #f3f2ee;
}
.st-menu-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 7px 10px;
    border-radius: 6px;
    color: #f3f2ee;
    font-size: 13px;
}
.st-menu-item:hover {
    background: rgba(255, 255, 255, 0.07);
    color: #ffffff;
    text-decoration: none;
}
.st-menu-item.active {
    background: rgba(44, 95, 179, 0.32);
    color: #d6e4f7;
    font-weight: 500;
}
.st-menu-item .badge {
    font-family: var(--st-mono);
    font-size: 11px;
    padding: 1px 7px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
    color: rgba(243, 242, 238, 0.75);
}
.st-menu-item.active .badge {
    background: rgba(44, 95, 179, 0.45);
    color: #ffffff;
}
.st-menu-separator {
    height: 2px;
    background: rgba(255, 255, 255, 0.06);
    margin: 8px 4px;
    border-radius: 1px;
}
/* "Log ud" — a button_to wrapped form whose <button> we restyle to match
   the surrounding menu items. The selector is scoped tightly enough to
   outrank the generic `form.button_to button` rule (~1690) without
   resorting to !important. */
.st-menu-panel form.button_to {
    margin: 0;
    padding: 0;
}
.st-menu-panel form.button_to button.st-menu-item-button {
    display: flex;
    align-items: center;
    justify-content: flex-end; /* right-align the label */
    width: 100%;
    padding: 7px 10px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: #f3f2ee;
    font: inherit;
    font-size: 13px;
    font-weight: 400;
    cursor: pointer;
}
.st-menu-panel form.button_to button.st-menu-item-button:hover {
    background: rgba(255, 255, 255, 0.07);
    color: #ffffff;
}

/* ── Page heading ── */
.st-page {
    padding: 24px;
}
.st-page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 20px;
    gap: 16px;
    flex-wrap: wrap;
}
.st-h1 {
    font-size: 24px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0 0 4px;
}
.st-h1.big {
    font-size: 32px;
}
.st-sub {
    color: var(--st-text-muted);
    font-size: 14px;
    margin: 0;
}

/* ── Cards ── */
.st-card {
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow: var(--st-shadow-sm);
}
.st-card.soft {
    background: var(--st-card-soft);
}
.st-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--st-border);
    gap: 12px;
}
.st-card-title {
    font-size: 1em;
    font-weight: 600;
    color: var(--st-text);
    margin: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}
.st-card-body {
    padding: 18px;
}
.st-card-body.flush {
    padding: 0;
}

/* ── KPI tile ── */
.st-kpi {
    position: relative; /* anchor for .st-kpi-icon */
    background: var(--st-card-soft);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.st-kpi-icon {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 28px; /* 22px × 1.25 */
    height: 28px;
    stroke-width: 2.1; /* CSS wins over the SVG presentation attribute */
    pointer-events: none;
}
/* Type-tinted icons. Water + sensor + humidity share the accent blue;
   alarm + thermometer get warmer tones so they stand apart from the
   consumption tiles at a glance. */
.st-kpi-icon-sensor {
    color: var(--st-accent);
}
.st-kpi-icon-water {
    color: var(--st-accent);
}
.st-kpi-icon-humidity {
    color: var(--st-accent);
}
.st-kpi-icon-alarm {
    color: var(--st-warn);
}
.st-kpi-icon-thermometer {
    color: var(--st-warm);
}
.st-kpi-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--st-text-muted);
}
.st-kpi-value {
    font-size: 30px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--st-text);
    line-height: 1.1;
}
.st-kpi-value.huge {
    font-size: 44px;
}
.st-kpi-value.bad {
    color: var(--st-bad);
}
.st-kpi-unit {
    font-size: 18px;
    color: var(--st-text-muted);
    margin-left: 4px;
    font-weight: 400;
}
.st-kpi-foot {
    font-size: 12px;
    color: var(--st-text-muted);
}
.st-kpi-foot.good {
    color: var(--st-good);
}
.st-kpi-foot.warn {
    color: var(--st-warn);
}
.st-kpi-foot.bad {
    color: var(--st-bad);
}

/* ── Tabs (segmented) ── */
.st-tabs {
    display: inline-flex;
    background: var(--st-card-soft);
    border: 1px solid var(--st-border);
    border-radius: 8px;
    padding: 3px;
    gap: 2px;
}
.st-tab {
    padding: 5px 12px;
    font-size: 12px;
    font-weight: 500;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: var(--st-text-muted);
    font: inherit;
    cursor: pointer;
    text-decoration: none;
}
.st-tab:hover {
    color: var(--st-text);
    text-decoration: none;
}
.st-tab.active {
    background: var(--st-text);
    color: #fff;
}
.st-tab.active:hover {
    color: #fff;
}
/* Period tabs ship both a long and a short label; CSS picks one. Default
   = long, mobile = short (see <540px media block). */
.st-tab-long {
    display: inline;
}
.st-tab-short {
    display: none;
}
/* Same trick for table column headers (and a few cell values like
   timestamps) where the long form is too wide on phones. */
.st-th-long {
    display: inline;
}
.st-th-short {
    display: none;
}

/* ── Date-range picker (.dr) ──
   Canonical period control for chart cards (replaces chart_period_tabs).
   Trigger pill shows the selected preset name in bold; once the user steps
   with ← →, the label switches to a monospace date range. UX reference:
   claude/design_charts/08_date_picker.html. See docs/charts.md. */
.dr {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    background: var(--st-card-soft);
    border: 1px solid var(--st-border);
    border-radius: 8px;
    padding: 0;
    gap: 0;
}
.dr-step {
    width: 32px;
    min-height: 32px;
    background: transparent;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--st-text-muted);
    font: inherit;
    padding: 0;
    border-radius: 7px;
    transition:
        background 120ms ease,
        color 120ms ease;
}
.dr-step:hover:not(:disabled) {
    color: var(--st-text);
    background: rgba(20, 25, 35, 0.04);
}
.dr-step:disabled {
    color: var(--st-text-soft);
    opacity: 0.45;
    cursor: not-allowed;
}
.dr-step:focus-visible {
    outline: 2px solid var(--st-accent);
    outline-offset: 2px;
}
.dr-step svg {
    width: 14px;
    height: 14px;
    display: block;
}
.dr-trigger {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 6px 12px;
    font: inherit;
    color: var(--st-text);
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 32px;
    border-radius: 7px;
    min-width: 150px;
    justify-content: center;
    transition: background 120ms ease;
}
.dr-trigger:hover {
    background: rgba(20, 25, 35, 0.04);
}
.dr-trigger:focus-visible {
    outline: 2px solid var(--st-accent);
    outline-offset: 2px;
}
/* Calendar glyph in the trigger — hidden on desktop (text label shows there),
   revealed on mobile where the trigger collapses to an icon. */
.dr-cal {
    display: none;
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
    color: var(--st-text-muted);
}
.dr-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--st-text);
    letter-spacing: -0.005em;
}
.dr-label.range {
    font-family: var(--st-mono);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0;
}
.dr-chevron {
    width: 12px;
    height: 12px;
    flex: 0 0 auto;
    color: var(--st-text-muted);
    transition: transform 160ms ease;
}
.dr.open .dr-chevron {
    transform: rotate(180deg);
}

/* Popover */
.dr .pop {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    min-width: 260px;
    max-width: 320px;
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow:
        0 8px 28px rgba(20, 25, 35, 0.12),
        0 2px 6px rgba(20, 25, 35, 0.06);
    padding: 6px;
    opacity: 0;
    transform: translateY(-4px) scale(0.99);
    pointer-events: none;
    transition:
        opacity 140ms ease,
        transform 140ms ease;
    z-index: 1100; /* above topbar (1000) so it doesn't get covered */
}
.dr.open .pop {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}
.pop-label {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--st-text-muted);
    padding: 8px 10px 4px;
}
.pop-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: 7px 10px;
    border: none;
    background: transparent;
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    color: var(--st-text);
    border-radius: 6px;
    text-align: left;
    transition: background 100ms ease;
}
.pop-item:hover {
    background: var(--st-card-soft);
}
.pop-item:focus-visible {
    outline: 2px solid var(--st-accent);
    outline-offset: -2px;
}
.pop-item.selected {
    background: var(--st-accent-bg);
    color: var(--st-accent);
    font-weight: 600;
}
.pop-item-check {
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    opacity: 0;
    color: var(--st-accent);
}
.pop-item.selected .pop-item-check {
    opacity: 1;
}
.pop-divider {
    height: 1px;
    background: var(--st-border);
    margin: 4px 6px;
}

.pop-custom {
    padding: 8px 10px 6px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.pop-custom-row {
    display: flex;
    gap: 6px;
    align-items: center;
}
.pop-custom-row input {
    flex: 1;
    font: inherit;
    font-size: 12px;
    font-family: var(--st-mono);
    padding: 6px 8px;
    border: 1px solid var(--st-border-strong);
    border-radius: 6px;
    background: var(--st-card);
    color: var(--st-text);
    min-width: 0;
}
.pop-custom-row input:focus {
    outline: 2px solid var(--st-accent);
    outline-offset: -1px;
    border-color: var(--st-accent);
}
.pop-custom-row .dash {
    color: var(--st-text-muted);
    font-size: 12px;
}
.pop-custom-apply {
    align-self: flex-end;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    padding: 6px 12px;
    border-radius: 6px;
    border: none;
    cursor: pointer;
    background: var(--st-accent);
    color: #fff;
    transition: background 120ms ease;
}
.pop-custom-apply:hover {
    background: #234a8c;
}

/* Muted total appended after a chart-card title:
 *   <h2 class="st-card-title">Vandforbrug <span class="st-card-title-sub">5,1 m³</span></h2>
 * Same font-size as the heading, regular weight, muted color. */
.st-card-title-sub {
    font-weight: 400;
    color: var(--st-text-muted);
    margin-left: 6px;
    font-variant-numeric: tabular-nums;
}

/* Chart-card legend that sits under the comparison line chart. */
.st-chart-legend {
    display: flex;
    gap: 18px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 10px;
    font-size: 12px;
    color: var(--st-text-muted);
}
.st-chart-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
/* Comparison-chart legend: filled box for the current-period bars, dotted
 * line for the previous-period overlay drawn behind them. */
.st-chart-legend-swatch {
    display: inline-block;
    width: 14px;
    height: 10px;
    border-radius: 2px;
    background: var(--st-accent-soft);
}
.st-chart-legend-swatch.dotted {
    width: 22px;
    height: 0;
    background: transparent;
    border-radius: 0;
    border-top: 2px dotted rgba(138, 143, 153, 0.85);
    align-self: center;
}

@media (max-width: 600px) {
    /* Picker stays compact and right-aligned: steppers kept, trigger shows just
       the calendar icon (label + chevron hidden). flex:0 0 auto + margin-left
       guard against the box stretching to full header width. */
    .dr {
        flex: 0 0 auto;
        margin-left: auto;
        align-self: center;
    }
    .dr-cal {
        display: inline-block;
    }
    .dr-trigger .dr-label,
    .dr-trigger .dr-chevron {
        display: none;
    }
    .dr-trigger {
        flex: 0 0 auto;
        padding: 7px 9px;
    }
    /* Popover: a usable fixed-width panel anchored to the trigger's right edge,
       capped to the viewport — so the date inputs never spill outside it. */
    .dr .pop {
        right: 0;
        left: auto;
        min-width: 240px;
        max-width: calc(100vw - 24px);
    }
    /* Stack the from/to date inputs so they can't overflow the popover. */
    .pop-custom-row {
        flex-direction: column;
        align-items: stretch;
    }
    .pop-custom-row .dash {
        display: none;
    }
    .pop-custom-row input {
        font-size: 16px; /* avoid iOS focus-zoom on the date fields */
    }
    .st-chart-legend {
        gap: 12px;
        font-size: 11px;
    }
    /* Chart card header stays one line (title left, compact picker right);
       shorten the plot so it fits a phone. */
    .st-card-header {
        padding: 12px 14px;
    }
    .st-chart-wrap {
        height: 240px;
    }
    /* Forms: tighter card + comfortable but not oversized fields on phones. */
    .st-form {
        padding: 14px 16px;
    }
    .st-form > div {
        margin-bottom: 12px;
    }
}
@media (prefers-reduced-motion: reduce) {
    .dr-step,
    .dr-trigger,
    .dr-chevron,
    .dr .pop,
    .pop-item,
    .pop-custom-apply {
        transition: none !important;
    }
}

/* ── Pills / badges ── */
.st-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.st-pill.good {
    background: var(--st-good-bg);
    color: var(--st-good);
}
.st-pill.warn {
    background: var(--st-warn-bg);
    color: var(--st-warn);
}
.st-pill.bad {
    background: var(--st-bad-bg);
    color: var(--st-bad);
}
.st-pill.neutral {
    background: var(--st-card-soft);
    color: var(--st-text-muted);
}
.st-pill.accent {
    background: var(--st-accent-bg);
    color: var(--st-accent);
}

.st-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    display: inline-block;
    flex: 0 0 auto;
}
.st-dot.good {
    background: var(--st-good);
}
.st-dot.warn {
    background: var(--st-warn);
}
.st-dot.bad {
    background: var(--st-bad);
}
.st-dot.neutral {
    background: var(--st-text-soft);
}

/* ── Buttons ── */
.st-btn {
    display: inline-block;
    padding: 8px 14px;
    border-radius: 8px;
    border: 1px solid var(--st-border-strong);
    background: #fff;
    color: var(--st-text);
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
}
.st-btn:hover {
    text-decoration: none;
    border-color: var(--st-text-muted);
}
.st-btn.primary {
    background: var(--st-accent);
    color: #fff;
    border-color: var(--st-accent);
}
.st-btn.primary:hover {
    background: #244e94;
    border-color: #244e94;
    color: #fff;
}
.st-btn.danger {
    background: var(--st-bad);
    color: #fff;
    border-color: var(--st-bad);
}
.st-btn.danger:hover {
    background: #951e18;
    border-color: #951e18;
    color: #fff;
}
.st-btn.large {
    padding: 14px 22px;
    font-size: 16px;
}
.st-btn.small {
    padding: 4px 10px;
    font-size: 12px;
}

/* ── Tables ── */
.st-table {
    width: 100%;
    border-collapse: collapse;
}
.st-table th,
.st-table td {
    text-align: left;
    padding: 12px 16px;
    font-size: 13px;
    border-bottom: 1px solid var(--st-border);
    vertical-align: middle;
}
.st-table th {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--st-text-muted);
    font-weight: 600;
    background: transparent;
}
.st-table tr:last-child td {
    border-bottom: none;
}
.st-table tbody tr:hover td {
    background: rgba(0, 0, 0, 0.015);
}
/* Sortable columns: clickable headers with an asc/desc affordance. JS
   (sortable_table.js) toggles aria-sort; everything visual keys off it. */
.st-table.st-sortable th[data-sort-col] {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.st-table.st-sortable th[data-sort-col]::after {
    content: "↕";
    margin-left: 5px;
    opacity: 0.3;
    font-size: 0.9em;
}
.st-table.st-sortable th[aria-sort="ascending"]::after { content: "↑"; opacity: 1; }
.st-table.st-sortable th[aria-sort="descending"]::after { content: "↓"; opacity: 1; }
.st-table.st-sortable th[data-sort-col]:hover { color: var(--st-text); }
.st-table.st-sortable th[data-sort-col]:focus-visible {
    outline: 2px solid var(--st-accent);
    outline-offset: -2px;
}
.st-link {
    color: var(--st-accent);
    font-weight: 500;
}

.st-empty {
    padding: 32px 18px;
    text-align: center;
    color: var(--st-text-muted);
    font-size: 13px;
}

/* Card title — h2-sized variant used when the title should command more
   weight (e.g. the unit dashboard's map/foto card). Matches .st-h1's
   structure at a notch smaller font-size. */
.st-card-title-lg {
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0;
    color: var(--st-text);
}

/* ── Photo gallery (unit dashboard map/foto toggle) ── */
.st-photo-frame {
    position: relative;
    width: 100%;
    /* Matches .st-leaflet height so toggling Kort/Foto doesn't reflow
       the card and the dashboard layout stays stable. */
    height: 360px;
    background: var(--st-card-soft);
    border-radius: var(--st-radius);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
.st-photo {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.st-photo-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    border-radius: 999px;
    background: rgba(20, 25, 35, 0.55);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    line-height: 1;
    text-decoration: none;
}
.st-photo-arrow:hover {
    background: rgba(20, 25, 35, 0.78);
    text-decoration: none;
    color: #fff;
}
.st-photo-arrow-prev {
    left: 10px;
}
.st-photo-arrow-next {
    right: 10px;
}
.st-photo-counter {
    position: absolute;
    bottom: 10px;
    right: 10px;
    background: rgba(20, 25, 35, 0.55);
    color: #fff;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-family: var(--st-mono);
}
.st-photo-upload {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
    padding: 8px 10px;
    border: 1px dashed var(--st-border-strong);
    border-radius: var(--st-radius);
    background: var(--st-card-soft);
    flex-wrap: wrap;
}
.st-photo-upload-label {
    font-size: 12px;
    color: var(--st-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
}
.st-photo-upload input[type="file"] {
    flex: 1;
    min-width: 200px;
    font-size: 13px;
}

/* ── Chart wrappers ── */
/* Slim positioning container for Chart.js canvases. Chart.js draws into the
   canvas and handles all rendering; this wrap just gives it a sized
   parent so `responsive: true + maintainAspectRatio: false` can work. */
.st-chart-wrap {
    position: relative;
    width: 100%;
    height: 360px; /* matches .st-leaflet so chart card + map card line up */
}
.st-chart-wrap-combo {
    /* height set inline by the helper — varies per chart */
}
.st-chart-wrap > canvas {
    max-width: 100%;
}

/* ── Map placeholder ── */
.st-map {
    height: 100%;
    min-height: 240px;
    background:
        repeating-linear-gradient(
            135deg,
            rgba(60, 90, 140, 0.04) 0 8px,
            transparent 8px 18px
        ),
        linear-gradient(180deg, #f3efe6 0%, #ece6d6 100%);
    border-radius: 8px;
    position: relative;
    overflow: hidden;
}
.st-map.mini {
    min-height: 160px;
}
.st-map-pin {
    position: absolute;
    width: 22px;
    height: 22px;
    margin-left: -11px;
    margin-top: -11px;
    border-radius: 50%;
    background: var(--st-accent);
    border: 3px solid #fff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
    font-size: 10px;
    font-weight: 700;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
}
.st-map-pin.good {
    background: var(--st-good);
}
.st-map-pin.warn {
    background: var(--st-warn);
}
.st-map-pin.bad {
    background: var(--st-bad);
}
.st-map-attribution {
    position: absolute;
    bottom: 4px;
    right: 8px;
    font-size: 9px;
    color: var(--st-text-soft);
    background: rgba(255, 255, 255, 0.7);
    padding: 1px 5px;
    border-radius: 3px;
}

/* Leaflet container — same chrome as the placeholder map.
   isolation:isolate creates a fresh stacking context so Leaflet's internal
   z-index ladder (panes 200–700, controls up to 1000) can never escape
   above the topbar / dropdown menu. */
.st-leaflet {
    height: 360px;
    border-radius: 8px;
    overflow: hidden;
    position: relative;
    isolation: isolate;
    z-index: 0;
}
/* Desaturated tile variant — used on the signal-diagnostics map so colored
 * status pins and RSSI link polylines pop against a quiet basemap. Filter
 * lives on .leaflet-tile (the individual tile <img>) instead of the pane
 * so it survives Leaflet's pane re-creation on zoom. */
.st-leaflet--muted .leaflet-tile {
    filter: grayscale(1) brightness(1.04) contrast(0.9);
}
.st-map-legend {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    margin-top: 10px;
    padding: 0 4px;
    font-size: 12px;
    color: var(--st-text-muted);
}
.st-map-legend > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.st-legend-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    display: inline-block;
    border: 1.5px solid #fff;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12);
}
.st-legend-dot.good {
    background: var(--st-good);
}
.st-legend-dot.warn {
    background: var(--st-warn);
}
.st-legend-dot.bad {
    background: var(--st-bad);
}

.st-leaflet-pin-wrap {
    background: transparent;
    border: none;
}
.st-leaflet-pin {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 3px solid #fff;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
    font-size: 10px;
    font-weight: 700;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--st-mono);
}

/* ── Forms ── */
.st-form {
    background: var(--st-card);
    padding: 18px 20px;
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow: var(--st-shadow-sm);
    max-width: 560px;
}
.st-form > div {
    margin-bottom: 14px;
}
.st-form label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--st-text-muted);
    margin-bottom: 6px;
}
.st-form input[type="text"],
.st-form input[type="email"],
.st-form input[type="password"],
.st-form input[type="number"],
.st-form input[type="search"],
.st-form select,
.st-form textarea {
    width: 100%;
    padding: 8px 12px;
    font: inherit;
    font-size: 14px;
    color: var(--st-text);
    border: 1px solid var(--st-border-strong);
    border-radius: 8px;
    background: #fff;
}
.st-form input:focus,
.st-form select:focus,
.st-form textarea:focus {
    outline: none;
    border-color: var(--st-accent);
    box-shadow: 0 0 0 3px var(--st-accent-bg);
}
.st-form textarea {
    min-height: 100px;
    resize: vertical;
}
.st-form .st-form-help {
    font-size: 12px;
    color: var(--st-text-muted);
    margin-top: 4px;
}

/* ── Devise unauthenticated screens ──
   The Devise views use .st-form like everything else; these classes
   replace the inline style attributes that previously decorated the
   logo, the heading, the remember-me checkbox row, and the full-width
   submit button. Class-based so a future CSP (`style-src 'self'`)
   doesn't break the screens. */
.st-devise-brand {
    text-align: center;
    margin-bottom: 24px;
}
.st-devise-logo {
    height: 32px;
    width: auto;
}
.st-form-heading {
    font-size: 18px;
    font-weight: 600;
    margin: 0 0 18px;
    letter-spacing: -0.01em;
}
/* When a help paragraph follows the heading, tighten the gap and
   leave the standard 18px before the first field. */
.st-form-heading + .st-form-help {
    margin-top: -12px;
    margin-bottom: 18px;
}
.st-form-checkbox-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.st-form-checkbox-row input[type="checkbox"] {
    width: auto;
    margin: 0;
}
.st-form-checkbox-row label {
    margin: 0;
    font-size: 13px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    color: var(--st-text);
}
.st-form-actions {
    margin-top: 18px;
    margin-bottom: 0;
}
.st-btn-block {
    width: 100%;
}
.st-devise-links {
    margin-top: 18px;
    text-align: center;
    font-size: 13px;
    color: var(--st-text-muted);
}

/* ── Top navigation progress bar ── */
/* Driven by app/javascript/nav_progress.js. The element is appended on
   link click and removed when the next page replaces the document, so
   the animation always reads as "started, doing work, gone" regardless
   of how long the request actually takes. */
#st-nav-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--st-accent);
    transform: scaleX(0);
    transform-origin: left center;
    z-index: 9999;
    pointer-events: none;
    box-shadow: 0 0 8px rgba(44, 95, 179, 0.5);
}
#st-nav-progress.active {
    animation: st-nav-progress 12s cubic-bezier(0.1, 0.9, 0.3, 1) forwards;
}
@keyframes st-nav-progress {
    0% {
        transform: scaleX(0);
    }
    20% {
        transform: scaleX(0.4);
    }
    50% {
        transform: scaleX(0.75);
    }
    80% {
        transform: scaleX(0.92);
    }
    100% {
        transform: scaleX(0.97);
    }
}
@media (prefers-reduced-motion: reduce) {
    #st-nav-progress {
        display: none;
    }
}

/* ── Flash ── */
.st-flash {
    padding: 10px 14px;
    border-radius: var(--st-radius);
    border: 1px solid transparent;
    font-size: 13px;
    margin: 0 0 16px;
}
.st-flash.notice {
    background: var(--st-good-bg);
    border-color: var(--st-good-bg);
    color: var(--st-good);
}
.st-flash.alert {
    background: var(--st-bad-bg);
    border-color: var(--st-bad-bg);
    color: var(--st-bad);
}
.st-errors {
    background: var(--st-bad-bg);
    border: 1px solid var(--st-bad-bg);
    padding: 10px 14px;
    border-radius: var(--st-radius);
    color: var(--st-bad);
}
.st-errors li {
    margin-left: 16px;
}

/* ── Definition lists (kv pairs on detail pages) ── */
.st-kv {
    display: grid;
    grid-template-columns: 160px 1fr;
    gap: 8px 16px;
    margin: 0 0 16px;
}
.st-kv dt {
    color: var(--st-text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
}
.st-kv dd {
    margin: 0;
    font-size: 14px;
}

/* ── Heatmap (legacy chart helper renders cells) ── */
.heatmap-grid {
    display: grid;
    grid-template-columns: 32px repeat(24, 1fr);
    gap: 2px;
    font-family: var(--st-mono);
    font-size: 10px;
}
.heatmap-grid .hm-row-label,
.heatmap-grid .hm-col-label {
    color: var(--st-text-muted);
    padding: 2px 4px;
}
.heatmap-grid .hm-cell {
    height: 22px;
    border-radius: 3px;
    background: var(--st-accent-soft);
}

/* ── Sparkline / inline chart ── */
.spark {
    display: block;
    width: 100%;
    height: 36px;
}

/* ── Page-level utilities ── */
.st-row {
    display: flex;
    gap: 16px;
}
.st-col {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.st-grow {
    flex: 1;
    min-width: 0;
}
.st-grid-2 {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 14px;
}
.st-grid-4 {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
}
/* Full HD and wider: spread 6 KPI tiles across one row instead of wrapping. */
@media (min-width: 1600px) {
    .st-grid-4 {
        grid-template-columns: repeat(6, 1fr);
    }
}
.st-divider {
    height: 1px;
    background: var(--st-border);
    margin: 12px 0;
}
.st-stack-sm > * + * {
    margin-top: 8px;
}
.st-stack-md > * + * {
    margin-top: 14px;
}
.st-stack-lg > * + * {
    margin-top: 18px;
}

/* Stack 2-col rows on tablets and small laptops up to ~1200px. iPad
   landscape (1024–1194) was getting a cramped 2fr/1fr split where a chart
   + map shared a row; full-width cards read better at that range. KPI
   strip stays 4-across down to 900px since the cards are tiny. */
@media (max-width: 1200px) {
    .st-grid-2 {
        grid-template-columns: 1fr;
    }
}
@media (max-width: 900px) {
    .st-grid-4 {
        grid-template-columns: 1fr 1fr;
    }
    .st-page {
        padding: 16px;
        padding-bottom: calc(80px + env(safe-area-inset-bottom));
    }
    /* Tables: allow horizontal scroll inside cards on narrow screens. */
    .st-card {
        overflow-x: auto;
    }
    .st-card .st-table {
        min-width: 480px;
    }
    /* Compact tables (3 short columns: timestamp + value + delta) fit on a
     phone without scrolling — the 480px floor only stretches them. */
    .st-card .st-table.compact {
        min-width: 0;
    }
    /* Touch targets — bump tab height on mobile for easier tapping. */
    .st-tab {
        padding: 9px 12px;
        min-height: 44px;
    }
    /* Hide page-header action buttons (e.g. "Rediger") on tablet/phone — frees
     up horizontal room for the entity name (h1). The action is reachable
     from the burger menu / direct URL. */
    .st-page-header .st-btn {
        display: none;
    }
}
@media (max-width: 540px) {
    .st-page {
        padding: 12px;
        padding-bottom: calc(80px + env(safe-area-inset-bottom));
    }
    .st-logo-mark {
        height: 22px;
    }
    .st-topbar {
        padding: 12px 14px;
    }
    .st-grid-4 {
        grid-template-columns: 1fr 1fr;
        gap: 10px;
    }
    .st-kpi {
        padding: 12px 14px;
        gap: 4px;
    }
    .st-kpi-label {
        font-size: 9.5px;
        letter-spacing: 0.06em;
    }
    .st-kpi-value {
        font-size: 24px;
    }
    .st-kpi-value.huge {
        font-size: 32px;
    }
    .st-kpi-unit {
        font-size: 14px;
    }
    .st-h1 {
        font-size: 22px;
    }
    .st-page-header {
        gap: 10px;
        margin-bottom: 14px;
    }
    /* Visually-collapse the page-header text block on phones (h1 +
     breadcrumb sub take vertical room above the KPI strip), but keep it
     in the accessibility tree so screen-reader users still hear the
     entity name. `display: none` would have removed it from AT entirely.
     The sr-only-style clip leaves zero visual footprint while preserving
     announcement on focus / page-load. */
    .st-page-header > div:first-child {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }
    .st-card-header {
        padding: 12px 14px;
    }
    .st-card-body {
        padding: 14px;
    }
    /* Period tabs swap to compact labels on phones so "1 dag / 7 dage /
     30 dage / 1 år" doesn't wrap onto two lines. */
    .st-tab-long {
        display: none;
    }
    .st-tab-short {
        display: inline;
    }
    /* Same swap for table headers / timestamp cells. */
    .st-th-long {
        display: none;
    }
    .st-th-short {
        display: inline;
    }
    /* Drop the "↑ 25% vs. i går" sub-line under usage cells on phones —
     too narrow to render usefully and clutters the row height. */
    .st-compare-line {
        display: none;
    }
}

/* ── Bottom tab bar (mobile only) ── */
.st-bottom-tabs {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    display: none;
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-top: 1px solid var(--st-border);
    padding-bottom: env(safe-area-inset-bottom);
    z-index: 30;
}
.st-bottom-tab {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 10px 4px 8px;
    min-height: 56px;
    color: var(--st-text-muted);
    font-size: 10px;
    font-weight: 500;
    text-decoration: none;
}
.st-bottom-tab:hover {
    text-decoration: none;
    color: var(--st-text);
}
.st-bottom-tab.active {
    color: var(--st-accent);
}
.st-bottom-tab svg {
    width: 22px;
    height: 22px;
}

@media (max-width: 900px) {
    .st-bottom-tabs {
        display: flex;
    }
}

/* ──────────────────────────────────────────────────────────────────────
   Legacy aliases — keep older view markup readable while pages migrate.
   Each rule below maps an old class name onto the equivalent st-* primitive.
   Remove once every view uses the st-* names directly.
   ────────────────────────────────────────────────────────────────────── */

.card {
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow: var(--st-shadow-sm);
    padding: 18px;
}
.kpi {
    background: var(--st-card-soft);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.kpi-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--st-text-muted);
    display: flex;
    align-items: center;
    gap: 8px;
}
.kpi-label::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 999px;
    background: var(--st-accent);
}
.kpi-label.water::before {
    background: var(--st-accent);
}
.kpi-label.elec::before {
    background: var(--st-warn);
}
.kpi-label.heat::before {
    background: var(--st-bad);
}
.kpi-label.health::before {
    background: var(--st-good);
}
.kpi-value {
    font-size: 30px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--st-text);
    line-height: 1.1;
    margin-top: 4px;
}
.kpi-unit {
    color: var(--st-text-muted);
    font-size: 18px;
    margin-left: 4px;
    font-weight: 400;
}
.kpi-delta {
    font-family: var(--st-mono);
    font-size: 12px;
}
.kpi-delta.up {
    color: var(--st-bad);
}
.kpi-delta.down {
    color: var(--st-good);
}
.kpi-delta.flat {
    color: var(--st-text-muted);
}
.kpi-foot {
    font-size: 12px;
    color: var(--st-text-muted);
}
.kpi-spark {
    margin-top: auto;
    padding-top: 6px;
}

.tabs {
    display: flex;
    gap: 18px;
    padding: 0;
    border-bottom: 1px solid var(--st-border);
    margin: 6px 0 18px;
}
.tabs a {
    padding: 8px 0;
    color: var(--st-text-muted);
    font-size: 13px;
    border-bottom: 2px solid transparent;
}
.tabs a:hover {
    color: var(--st-text);
    text-decoration: none;
}
.tabs a.active {
    color: var(--st-text);
    border-bottom-color: var(--st-accent);
    font-weight: 500;
}
.tabs .tab-count {
    color: var(--st-text-muted);
    margin-left: 4px;
}

.eyebrow {
    font-family: var(--st-mono);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--st-text-muted);
    margin-bottom: 6px;
}
.meta-line {
    color: var(--st-text-muted);
    font-size: 13px;
}
.meta-line span + span::before {
    content: " · ";
    color: var(--st-text-muted);
}
.mono {
    font-family: var(--st-mono);
}

table:not(.st-table) {
    width: 100%;
    border-collapse: collapse;
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    overflow: hidden;
    box-shadow: var(--st-shadow-sm);
}
table:not(.st-table) th,
table:not(.st-table) td {
    padding: 12px 16px;
    font-size: 13px;
    text-align: left;
    vertical-align: middle;
}
table:not(.st-table) thead th {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--st-text-muted);
    border-bottom: 1px solid var(--st-border);
    font-weight: 600;
    background: transparent;
}
table:not(.st-table) tbody tr + tr td {
    border-top: 1px solid var(--st-border);
}
table:not(.st-table) tbody tr:hover td {
    background: rgba(0, 0, 0, 0.015);
}

form:not(.st-form):not(.button_to):not(.st-search-host) {
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow: var(--st-shadow-sm);
    max-width: 560px;
    padding: 24px;
}
form:not(.st-form):not(.button_to):not(.st-search-host) > div {
    margin-bottom: 14px;
}
form:not(.st-form):not(.button_to):not(.st-search-host) label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--st-text-muted);
    margin-bottom: 6px;
}
form:not(.st-form):not(.button_to):not(.st-search-host) input[type="text"],
form:not(.st-form):not(.button_to):not(.st-search-host) input[type="email"],
form:not(.st-form):not(.button_to):not(.st-search-host) input[type="password"],
form:not(.st-form):not(.button_to):not(.st-search-host) input[type="number"],
form:not(.st-form):not(.button_to):not(.st-search-host) input[type="search"],
form:not(.st-form):not(.button_to):not(.st-search-host) select,
form:not(.st-form):not(.button_to):not(.st-search-host) textarea {
    width: 100%;
    padding: 8px 12px;
    font: inherit;
    font-size: 14px;
    color: var(--st-text);
    border: 1px solid var(--st-border-strong);
    border-radius: 8px;
    background: #fff;
}
form:not(.st-form):not(.button_to):not(.st-search-host) input:focus,
form:not(.st-form):not(.button_to):not(.st-search-host) select:focus,
form:not(.st-form):not(.button_to):not(.st-search-host) textarea:focus {
    outline: none;
    border-color: var(--st-accent);
    box-shadow: 0 0 0 3px var(--st-accent-bg);
}
form:not(.st-form):not(.button_to):not(.st-search-host) input[type="submit"],
form:not(.st-form):not(.button_to):not(.st-search-host)
    button:not(.st-iconbtn):not(.st-btn) {
    display: inline-block;
    padding: 8px 14px;
    border-radius: 8px;
    border: 1px solid var(--st-accent);
    background: var(--st-accent);
    color: #fff;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}
form.button_to {
    display: inline-block;
    padding: 0;
    border: none;
    background: transparent;
    max-width: none;
}
form.button_to button {
    display: inline-block;
    padding: 6px 12px;
    border-radius: 8px;
    border: 1px solid var(--st-border-strong);
    background: #fff;
    color: var(--st-text);
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}

.btn {
    display: inline-block;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 500;
    background: var(--st-accent);
    color: #fff;
    border: 1px solid var(--st-accent);
    border-radius: 8px;
    font-family: inherit;
    cursor: pointer;
    text-decoration: none;
}
.btn:hover {
    background: #244e94;
    border-color: #244e94;
    color: #fff;
    text-decoration: none;
}
.btn-soft {
    background: #fff;
    color: var(--st-text);
    border-color: var(--st-border-strong);
}
.btn-soft:hover {
    background: var(--st-card-soft);
    color: var(--st-text);
    border-color: var(--st-text-muted);
}

.flash {
    padding: 10px 14px;
    border-radius: var(--st-radius);
    border: 1px solid transparent;
    font-size: 13px;
    margin-bottom: 16px;
}
.flash-notice {
    background: var(--st-good-bg);
    border-color: var(--st-good-bg);
    color: var(--st-good);
}
.flash-alert {
    background: var(--st-bad-bg);
    border-color: var(--st-bad-bg);
    color: var(--st-bad);
}
.errors {
    background: var(--st-bad-bg);
    border: 1px solid var(--st-bad-bg);
    padding: 10px 14px;
    border-radius: var(--st-radius);
    color: var(--st-bad);
}
.errors li {
    margin-left: 16px;
}

dl:not(.st-kv) {
    display: grid;
    grid-template-columns: 160px 1fr;
    gap: 8px 16px;
    margin: 0 0 16px;
}
dl:not(.st-kv) dt {
    color: var(--st-text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
}
dl:not(.st-kv) dd {
    margin: 0;
}

.severity {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.severity-info {
    background: var(--st-accent-bg);
    color: var(--st-accent);
}
.severity-warning {
    background: var(--st-warn-bg);
    color: var(--st-warn);
}
.severity-critical {
    background: var(--st-bad-bg);
    color: var(--st-bad);
}
.has-open-alarms {
    color: var(--st-bad);
    font-weight: 600;
}

.tag-chip {
    display: inline-block;
    font-family: var(--st-mono);
    font-size: 11px;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--st-card-soft);
    color: var(--st-text-muted);
    margin-right: 4px;
}
.tag-chip.tag-water {
    background: var(--st-accent-bg);
    color: var(--st-accent);
}
.tag-chip.tag-elec {
    background: var(--st-warn-bg);
    color: var(--st-warn);
}
.tag-chip.tag-heat {
    background: var(--st-bad-bg);
    color: var(--st-bad);
}
.tag-chip.tag-temp {
    background: var(--st-card-soft);
    color: var(--st-text-soft);
}
.tag-chip.tag-ok {
    background: var(--st-good-bg);
    color: var(--st-good);
}
.tag-chip.tag-warn {
    background: var(--st-warn-bg);
    color: var(--st-warn);
}
.tag-chip.tag-crit {
    background: var(--st-bad-bg);
    color: var(--st-bad);
}
.tag-chip.tag-info {
    background: var(--st-accent-bg);
    color: var(--st-accent);
}

.alerts-panel {
    display: flex;
    flex-direction: column;
    gap: 0;
}
.alerts-panel-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 0;
    border-top: 1px solid var(--st-border);
}
.alerts-panel-row:first-child {
    border-top: 0;
    padding-top: 0;
}
.alerts-panel-row .dot {
    width: 8px;
    height: 8px;
    border-radius: 999px;
    margin-top: 6px;
    flex: 0 0 auto;
}
.alerts-panel-row .dot.critical {
    background: var(--st-bad);
}
.alerts-panel-row .dot.warning {
    background: var(--st-warn);
}
.alerts-panel-row .dot.info {
    background: var(--st-accent);
}
.alerts-panel-row .body {
    flex: 1;
    min-width: 0;
}
.alerts-panel-row .body .title {
    font-size: 14px;
    color: var(--st-text);
    font-weight: 500;
}
.alerts-panel-row .body .meta {
    font-family: var(--st-mono);
    font-size: 11px;
    color: var(--st-text-muted);
}

.kpi-health .kpi-label.health::before {
    background: var(--st-warn);
}
.kpi-health-line {
    font-size: 22px;
    font-weight: 500;
    color: var(--st-text);
    letter-spacing: -0.01em;
    margin: 6px 0 8px;
}
.kpi-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 8px;
}
.chip {
    display: inline-flex;
    align-items: center;
    font-family: var(--st-mono);
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 4px;
}
.chip-crit {
    background: var(--st-bad-bg);
    color: var(--st-bad);
}
.chip-warn {
    background: var(--st-warn-bg);
    color: var(--st-warn);
}
.chip-ok {
    background: var(--st-good-bg);
    color: var(--st-good);
}
.chip-info {
    background: var(--st-accent-bg);
    color: var(--st-accent);
}

figure.chart {
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
}
figure.chart figcaption {
    font-size: 13px;
    color: var(--st-text);
    margin-bottom: 8px;
    display: flex;
    align-items: baseline;
    gap: 8px;
}
figure.chart figcaption .chart-meta {
    font-family: var(--st-mono);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--st-text-muted);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.st-skip-link {
    position: absolute;
    left: -9999px;
    top: 8px;
    padding: 8px 12px;
    background: var(--st-accent);
    color: #fff;
    font-weight: 500;
    border-radius: 6px;
    z-index: 1000;
}
.st-skip-link:focus {
    left: 8px;
}

/* ── Field-assignment ("Felt-montering") — mobile, big touch targets ── */
.st-field-search {
    width: 100%;
    padding: 14px 16px;
    margin-bottom: 14px;
    font: inherit;
    font-size: 16px; /* ≥16px so iOS doesn't zoom the viewport on focus */
    color: var(--st-text);
    border: 1px solid var(--st-border-strong);
    border-radius: var(--st-radius);
    background: #fff;
}
.st-field-search:focus {
    outline: none;
    border-color: var(--st-accent);
    box-shadow: 0 0 0 3px var(--st-accent-bg);
}

.st-tap-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.st-tap-link {
    display: block;
    min-height: 56px;
    padding: 14px 16px;
    background: var(--st-card);
    border: 1px solid var(--st-border);
    border-radius: var(--st-radius);
    box-shadow: var(--st-shadow-sm);
    text-decoration: none;
    color: var(--st-text);
}
.st-tap-link:hover {
    border-color: var(--st-accent-soft);
    text-decoration: none;
}
.st-tap-main {
    display: block;
    font-size: 18px;
    font-weight: 600;
}
.st-tap-sub {
    display: block;
    font-size: 14px;
    color: var(--st-text);
    margin-top: 2px;
}
.st-tap-meta {
    display: block;
    font-size: 12px;
    color: var(--st-text-muted);
    margin-top: 4px;
}

/* Panel labels: section-level, not the uppercase .st-form label treatment. */
.st-field-form .st-field-label {
    display: block;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    color: var(--st-text);
    margin-bottom: 8px;
}
.st-field-select {
    width: 100%;
}
.st-field-select option {
    padding: 10px 8px;
    font-size: 15px;
}

.st-kind-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.st-kind-button {
    /* Reset the inherited .st-form label styling for these chips. */
    display: inline-flex;
    align-items: center;
    margin: 0;
    padding: 0;
    text-transform: none;
    letter-spacing: 0;
}
.st-kind-button input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.st-kind-button span {
    display: inline-block;
    padding: 12px 18px;
    font-size: 16px;
    font-weight: 600;
    border: 1px solid var(--st-border-strong);
    border-radius: var(--st-radius);
    background: #fff;
    color: var(--st-text);
    cursor: pointer;
}
.st-kind-button input:checked + span {
    background: var(--st-accent);
    color: #fff;
    border-color: var(--st-accent);
}
.st-kind-button input:focus-visible + span {
    outline: 2px solid var(--st-accent);
    outline-offset: 2px;
}

.st-capture-btn {
    /* A big, friendly camera button (the real file input is .sr-only). */
    display: block;
    text-align: center;
    padding: 16px;
    font-size: 16px;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0;
    color: var(--st-accent);
    background: var(--st-accent-bg);
    border: 1px dashed var(--st-accent-soft);
    border-radius: var(--st-radius);
    cursor: pointer;
}
.st-field-hint {
    display: block;
    margin-top: 8px;
    font-size: 13px;
    color: var(--st-text-muted);
}
.st-field-coords {
    display: flex;
    gap: 8px;
    margin-top: 10px;
}
.st-field-coords input {
    flex: 1;
    min-width: 0;
}
.st-field-actions {
    margin-top: 4px;
}
.st-btn-block {
    display: block;
    width: 100%;
    text-align: center;
}
