/* M3.2.1 · Unified Product Design System v17 ------------------------------
 *
 * Scope: all main product pages
 *   Dashboard / Devices / Device Detail / Notifications / Operations
 *   Data Center / Sensor Settings / Pending Channels / Accounts / Account
 *
 * Principle:
 *   page background  -> open page header
 *   primary panel    -> calm glass surface
 *   secondary card   -> lighter translucent surface
 *   controls         -> compact white glass
 *   status           -> semantic colour only where meaning exists
 *
 * v17 intentionally does NOT change business layout or data rendering.
 */

/* ========================================================================
   1. Shared design tokens
   ======================================================================== */


/* ========================================================================
   2. Page headers: one common language everywhere
   ======================================================================== */
.product-page-header,
.dashboard-hero,
.devices-header,
.detail-header,
.notification-hero,
.operations-hero,
.data-center-header,
.settings-header,
.pending-header {
    min-height: 76px;
    margin-bottom: 18px;
    padding: 4px 2px 6px;
    background: transparent;
    border: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.product-page-header h1,
.dashboard-hero h1,
.devices-title-row h1,
.detail-header h1,
.notification-hero h1,
.operations-hero h1,
.data-center-title-row h1,
.settings-title-row h1,
.pending-header h1 {
    color: var(--ds-text-strong);
    letter-spacing: -.028em;
}

.product-page-header p,
.dashboard-hero p,
.devices-header p,
.detail-header p,
.notification-hero p,
.operations-hero p,
.data-center-header-meta,
.settings-header p,
.pending-header p {
    color: var(--ds-text-secondary);
}

/* Header action controls use the same quiet-glass treatment. */
.product-page-header button,
.product-page-header a[class*="btn"],
.dashboard-hero button,
.devices-header button,
.detail-header button,
.notification-hero button,
.operations-hero button,
.data-center-header button,
.settings-header button,
.pending-header button {
    min-height: 38px;
    border-radius: var(--ds-radius-control);
}

/* ========================================================================
   3. Primary panels: consistent surface / border / radius / spacing
   ======================================================================== */
.panel,
.devices-panel,
.detail-panel,
.detail-channels-panel,
.notification-panel,
.operations-panel,
.data-section-panel,
.settings-panel,
.pending-panel,
.accounts-panel,
.device-ops-overview,
.overview-health-card,
.overview-attention-panel,
.notification-focus-card,
.trend-spotlight-panel,
.simple-threshold-panel,
.template-panel {
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-panel);
    background: var(--ds-surface-panel);
    box-shadow: var(--ds-panel-shadow);
    -webkit-backdrop-filter: blur(var(--ds-panel-blur)) saturate(112%);
    backdrop-filter: blur(var(--ds-panel-blur)) saturate(112%);
}

/* Shared spacing for panel content without touching grid templates. */
.panel,
.devices-panel,
.detail-panel,
.detail-channels-panel,
.notification-panel,
.operations-panel,
.data-section-panel,
.settings-panel,
.pending-panel,
.accounts-panel {
    padding-top: max(16px, var(--ds-space-4));
    padding-bottom: max(16px, var(--ds-space-4));
}

/* ========================================================================
   4. Section headers
   ======================================================================== */
.section-head,
.panel-head,
.panel-title-row,
.detail-section-head,
.settings-panel-head,
.data-section-heading,
.results-heading,
.device-ops-overview-head,
.notification-history-head,
.rules-head {
    min-height: 42px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--ds-line);
}

.section-head h2,
.panel-head h2,
.panel-title-row h2,
.detail-section-head h2,
.settings-panel-head h2,
.data-section-heading h2,
.results-heading h2,
.device-ops-overview-head h2,
.notification-history-head h2,
.rules-head h2 {
    color: var(--ds-text-strong);
    letter-spacing: -.016em;
}

/* ========================================================================
   5. Secondary cards: unify repeated data/setting/device tiles
   ======================================================================== */
.summary-card,
.fleet-summary-card,
.device-stat-card,
.detail-stat-card,
.settings-overview-card,
.notification-stat,
.ops-stat,
.admin-summary-card,
.device-card,
.channel-card,
.quick-link-card,
.pending-card,
.config-card,
.device-ops-card,
.rule-template-row,
.quality-rule,
.alert-item,
.notification-item,
.notification-alert-card,
.activity-item,
.event-card,
.health-metric {
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-card);
    box-shadow: var(--ds-card-shadow);
}

.summary-card,
.fleet-summary-card,
.device-stat-card,
.settings-overview-card,
.notification-stat,
.ops-stat,
.admin-summary-card,
.device-card,
.channel-card,
.quick-link-card,
.pending-card,
.config-card,
.device-ops-card,
.rule-template-row,
.quality-rule,
.activity-item,
.health-metric {
    background: var(--ds-surface-card);
    -webkit-backdrop-filter: blur(var(--ds-card-blur)) saturate(108%);
    backdrop-filter: blur(var(--ds-card-blur)) saturate(108%);
}

@media (hover: hover) and (pointer: fine) {
    .device-card:hover,
    .channel-card:hover,
    .quick-link-card:hover,
    .pending-card:hover,
    .config-card:hover,
    .rule-template-row:hover,
    .quality-rule:hover,
    .activity-item:hover {
        background: var(--ds-surface-card-hover);
        border-color: var(--glass-white-72);
    }
}

/* Semantic alert/event cards retain meaning but use the same material. */
.alert-item,
.notification-item,
.notification-alert-card,
.event-card.warning,
.event-card.critical,
.event-card.info {
    background: var(--glass-white-46);
}

/* ========================================================================
   6. Stats: same metric hierarchy on every page
   ======================================================================== */
.fleet-summary-label,
.device-stat-label,
.detail-stat-label,
.settings-overview-label,
.notification-stat span,
.ops-stat span,
.admin-summary-title {
    color: var(--ds-text-secondary);
    font-weight: 680;
}

.fleet-summary-value,
.device-stat-value,
.detail-stat-value,
.settings-overview-value,
.notification-stat strong,
.ops-stat strong,
.admin-summary-main strong {
    color: var(--ds-text-strong);
    font-variant-numeric: tabular-nums;
    letter-spacing: -.018em;
}

.fleet-summary-meta,
.devices-summary,
.detail-stat-sub,
.settings-overview-meta,
.notification-section-summary,
.updated-at,
.data-center-header-meta,
.device-ops-updated {
    color: var(--ds-text-muted);
}

/* ========================================================================
   7. Toolbars / filters / workbenches
   ======================================================================== */
.devices-toolbar,
.notification-filter-bar,
.data-query-workbench,
.trend-primary-controls,
.filters,
.backup-toolbar,
.sensor-dialog-toolbar,
.template-form,
.template-apply-panel,
.simple-threshold-form,
.alert-rule-form {
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-card);
    background: var(--ds-surface-muted);
    box-shadow:
        inset 0 1px 0 var(--glass-white-50);
}

/* ========================================================================
   8. Tabs / segmented / range selection
   ======================================================================== */
.data-tabs,
.notification-segmented,
.range-presets {
    padding: 5px;
    gap: 5px;
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-card);
    background: var(--surface-segmented);
    box-shadow: inset 0 1px 0 var(--glass-white-46);
}

.data-tab,
.notification-segmented button,
.range-btn {
    border-radius: var(--radius-compact);
}

.data-tab.active,
.notification-segmented button.active,
.range-btn.active {
    background: var(--surface-selected);
    border-color: var(--border-selected);
    color: var(--text-success-strong);
    box-shadow:
        inset 0 1px 0 var(--glass-white-72),
        var(--shadow-selection);
}

/* ========================================================================
   9. Controls / inputs / buttons — canonical v31
   ======================================================================== */

input,
select,
textarea {
    min-height: 38px;
    border: 1px solid var(--border-control);
    border-radius: var(--ds-radius-control);
    background: var(--surface-control);
    color: var(--text-body);
    box-shadow: var(--ds-control-shadow);
}

input:hover,
select:hover,
textarea:hover {
    background: var(--surface-control-hover);
    border-color: var(--border-control-hover);
}

input:focus,
select:focus,
textarea:focus,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: none;
    border-color: var(--control-focus-border);
    box-shadow:
        0 0 0 3px var(--control-focus-ring),
        inset 0 1px 0 var(--glass-white-58);
}

button,
.button-like,
.button-link,
.primary-btn,
.secondary-btn,
.danger-btn,
.table-btn,
.notification-action-button {
    border-radius: var(--ds-radius-control);
    font-weight: 680;
}

/* Primary action */
button.primary,
.primary-btn,
.button-like.primary,
.notification-hero-actions .primary,
.notification-action-button.primary,
.notification-dialog-actions .primary {
    border-color: var(--control-primary-border);
    background: var(--control-primary-bg);
    color: var(--control-primary-fg);
}

button.primary:hover,
.primary-btn:hover,
.button-like.primary:hover,
.notification-hero-actions .primary:hover,
.notification-action-button.primary:hover,
.notification-dialog-actions .primary:hover {
    border-color: var(--control-primary-border-hover);
    background: var(--control-primary-bg-hover);
    color: var(--control-primary-fg);
}

/* Secondary / neutral action */
button:not(.primary):not(.danger),
.secondary-btn,
.table-btn,
.notification-action-button:not(.primary) {
    border-color: var(--control-secondary-border);
    background: var(--control-secondary-bg);
    color: var(--control-secondary-fg);
}

button:not(.primary):not(.danger):hover,
.secondary-btn:hover,
.table-btn:hover,
.notification-action-button:not(.primary):hover {
    background: var(--control-secondary-bg-hover);
}

/* Destructive action */
button.danger,
.danger-btn,
.notification-hero-actions .danger {
    border-color: var(--control-danger-border);
    background: var(--control-danger-bg);
    color: var(--control-danger-fg);
}

button.danger:hover,
.danger-btn:hover,
.notification-hero-actions .danger:hover {
    background: var(--control-danger-bg-hover);
}

/* Disabled */
button:disabled,
.primary-btn:disabled,
.secondary-btn:disabled,
.danger-btn:disabled,
.table-btn:disabled,
.notification-action-button:disabled,
input:disabled,
select:disabled,
textarea:disabled {
    cursor: default;
    opacity: var(--control-disabled-opacity);
}

/* Keyboard focus is shared by buttons, links and interactive cards. */
button:focus-visible,
.button-like:focus-visible,
.button-link:focus-visible,
.primary-btn:focus-visible,
.secondary-btn:focus-visible,
.danger-btn:focus-visible,
.table-btn:focus-visible,
.notification-action-button:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--control-focus-ring);
}

/* ========================================================================
   10. Pills / chips / state system — canonical v31
   ======================================================================== */

.refresh-chip,
.live-chip,
.range-status-chip,
.device-refresh-chip,
.detail-live-chip,
.settings-save-state,
.guest-preview-chip,
.status-pill,
.role-pill,
.password-pill,
.state-pill,
.severity-pill,
.rule-chip,
.count-badge,
.pending-chip,
.device-id-chip,
.sensor-key-chip,
.record-sensor-chip,
.notification-chip,
.result-count-chip,
.selection-chip,
.account-state-chip,
.account-role-chip,
.template-type-chip,
.backup-status,
.sensor-status-pill {
    border-radius: var(--ds-radius-pill);
    box-shadow: inset 0 1px 0 var(--glass-white-50);
}

/* Device / runtime state */
.device-status.online,
.device-state.online,
.state-pill.online,
.status-pill.enabled,
.sensor-status-pill.normal,
.backup-status.ok,
.notification-chip.resolved,
.notification-chip.unread-chip,
.notification-chip.status-已恢复 {
    background: var(--state-success-bg);
    color: var(--state-success-fg);
}

.device-status.delayed,
.device-state.delayed,
.state-pill.delayed,
.severity-pill.warning,
.sensor-status-pill.attention,
.pending-chip,
.notification-chip.warning,
.notification-chip.opened,
.notification-chip.status-活动中 {
    background: var(--state-warning-bg);
    color: var(--state-warning-fg);
}

.device-status.offline,
.device-state.offline,
.state-pill.offline,
.severity-pill.critical,
.notification-chip.critical,
.backup-status.bad {
    background: var(--state-danger-bg);
    color: var(--state-danger-fg);
}

.notification-chip.acknowledged {
    background: var(--state-info-bg);
    color: var(--state-info-fg);
}

.state-pill.never_online,
.state-pill.disabled,
.state-pill.unknown,
.status-pill.disabled,
.sensor-status-pill.muted,
.notification-chip.status-已确认 {
    background: var(--state-neutral-bg);
    color: var(--state-neutral-fg);
}

.severity-pill.resolved,
.pending-chip-group {
    background: var(--state-success-bg);
    color: var(--state-success-fg);
}

/* State dots */
.device-status.online::before,
.device-state.online::before {
    background: var(--state-success-dot);
}

.device-status.delayed::before,
.device-state.delayed::before {
    background: var(--state-warning-dot);
}

.device-status.offline::before,
.device-state.offline::before {
    background: var(--state-danger-dot);
}

/* Table action semantic variants */
.table-btn.success {
    color: var(--state-success-fg);
    border-color: var(--state-success-border);
}

.table-btn.warn {
    color: var(--state-danger-fg);
    border-color: var(--state-danger-border);
}

/* Message state */
.message.ok,
.accounts-message.ok,
.notification-message.ok,
.account-message.ok,
.form-message.ok,
.template-message.ok,
.simple-threshold-message.ok,
.quality-event-message.ok {
    color: var(--state-success-fg);
}

.message.error,
.accounts-message.error,
.notification-message.error,
.account-message.error,
.form-message.error,
.template-message.error,
.simple-threshold-message.error,
.quality-event-message.error {
    color: var(--state-danger-fg);
}

/* ========================================================================
   11. Tables: one table language
   ======================================================================== */
.record-table-shell,
.accounts-table-wrap,
.detail-table-wrap,
.history-table-shell,
.backup-table-shell,
.recent-table-shell,
.table-wrap {
    overflow: auto;
    border: 1px solid var(--ds-border-soft);
    border-radius: var(--ds-radius-card);
    background: var(--glass-white-42);
    box-shadow:
        inset 0 1px 0 var(--glass-white-48);
}

table {
    background: transparent;
}

table thead th,
.accounts-table th,
.detail-table th {
    background: var(--surface-table-head);
    color: var(--text-table-head);
    border-bottom-color: var(--border-table);
}

table tbody td,
.accounts-table td,
.detail-table td {
    border-bottom-color: var(--border-table-soft);
}

table tbody tr {
    background: var(--surface-table-row);
    transition:
        background-color var(--motion-fast) ease,
        box-shadow var(--motion-fast) ease;
}

table tbody tr:hover {
    background: var(--glass-white-35);
}

/* ========================================================================
   12. Empty / loading / message states
   ======================================================================== */
.empty-state,
.settings-empty,
.ops-empty,
.notification-empty,
.activity-empty,
.detail-loading,
.detail-empty,
.devices-empty,
.template-target-empty,
.app-state {
    border: 1px dashed var(--border-empty);
    border-radius: var(--ds-radius-card);
    background: var(--glass-white-22);
    color: var(--ds-text-secondary);
}

.message,
.accounts-message,
.notification-message,
.account-message,
.form-message,
.template-message,
.simple-threshold-message,
.quality-event-message {
    border-radius: var(--radius-compact);
    color: var(--ds-text-secondary);
}



/* ========================================================================
   13. Page-specific reconciliation
   ======================================================================== */

/* Dashboard */
.filter-panel,
.recent-panel,
.system-health-panel,
.activity-panel {
    border-radius: var(--ds-radius-panel);
}

/* Devices */
.devices-panel .device-card {
    min-width: 0;
}

/* Device detail */
.detail-panel .quick-link-card {
    min-height: 86px;
}

/* Notifications */
.notification-focus-card,
.notification-panel {
    overflow: hidden;
}

/* Operations */
.advanced-operations {
    border-radius: var(--ds-radius-panel);
}

.advanced-operations > summary {
    border-radius: var(--ds-radius-card);
}

/* Data center */
.data-policy-card,
.admin-summary-card {
    border-radius: var(--ds-radius-card);
}

/* Sensor settings */
.settings-policy-card {
    border-radius: var(--ds-radius-card);
}

/* Pending sensor channels */
.pending-card {
    overflow: hidden;
}

/* Accounts */
.accounts-panel {
    overflow: hidden;
}

/* ========================================================================
   14. Responsive consistency
   ======================================================================== */
@media (max-width: 980px) {
    :root {
        --ds-radius-page: 18px;
        --ds-radius-panel: 16px;
        --ds-radius-card: 13px;
        --ds-radius-control: 10px;
        --ds-panel-blur: 11px;
        --ds-card-blur: 8px;
    }

    .product-page-header,
    .dashboard-hero,
    .devices-header,
    .detail-header,
    .notification-hero,
    .operations-hero,
    .data-center-header,
    .settings-header,
    .pending-header {
        min-height: auto;
        margin-bottom: 14px;
    }
}

/* Accessibility: material remains clear without animation. */
@media (prefers-reduced-motion: reduce) {
    table tbody tr,
    input,
    select,
    textarea {
        transition: none;
    }
}

/* M3.2.1 · Canonical operational typography v24 ------------------------
 * Shared readable type scale for controls, status, tables and metadata.
 */
/* Canonical typography rules ------------------------------------
 * Goal:
 * - preserve v11 glass hierarchy exactly
 * - stop using 9/10px text for normal operational information
 * - establish a consistent readable scale without making the UI bulky
 *
 * Desktop scale:
 *   micro metadata       11px
 *   secondary / caption  11.5-12px
 *   control label        12px
 *   normal body          14px
 *
 * The selectors below intentionally target semantic secondary text instead
 * of globally scaling every element, so card geometry and dense data views
 * remain stable.
 */

:root {
    --type-micro: 11px;
    --type-caption: 11.5px;
    --type-secondary: 12px;
    --type-body: 14px;
    --type-secondary-line: 1.45;
}

/* Shared form / helper typography. */
label,
.control-label {
    font-size: var(--type-secondary);
    line-height: 1.35;
}

.field-hint,
.template-form-hint,
.dialog-note,
.account-hint,
.notification-note-field small {
    font-size: var(--type-caption);
    line-height: var(--type-secondary-line);
}

/* Status chips should read like controls/status, not footnotes. */
.refresh-chip,
.live-chip,
.range-status-chip,
.device-refresh-chip,
.detail-live-chip,
.settings-save-state,
.guest-preview-chip {
    font-size: var(--type-secondary);
    line-height: 1.3;
}

/* Dashboard trend controls ---------------------------------------------- */

.trend-spotlight-panel .control-label {
    color: var(--text-control);
    font-size: 12px;
    font-weight: 760;
}

.trend-spotlight-panel .device-select-shell::before {
    color: var(--text-muted);
    font-size: 11px;
    font-weight: 600;
}

.trend-spotlight-panel .range-btn,
.trend-spotlight-panel select,
.trend-spotlight-panel input {
    font-size: 12px;
}

.trend-spotlight-panel .metric-filter-title {
    color: var(--text-control);
    font-size: 12px;
    font-weight: 780;
}

.trend-spotlight-panel .metric-filter-help {
    color: var(--text-muted);
    font-size: 11.5px;
    line-height: 1.45;
}

.trend-spotlight-panel .compact-btn {
    font-size: 11.5px;
    font-weight: 700;
}

/* Sensor filter pills: 10px was unnecessarily small on desktop. */
.trend-spotlight-panel .sensor-toggle {
    font-size: 11.5px;
    font-weight: 680;
}

.trend-spotlight-panel .sensor-toggle-group-title {
    color: var(--text-secondary);
    font-size: 11px;
    font-weight: 760;
}

/* Health / freshness strip. */
.trend-spotlight-panel .trend-health-label {
    color: var(--text-muted);
    font-size: 11.5px;
    font-weight: 650;
}

.trend-spotlight-panel .trend-health-item strong {
    font-size: 12.5px;
    font-weight: 760;
}

.trend-spotlight-panel .range-summary {
    color: var(--text-secondary);
    font-size: 11.5px;
    line-height: 1.45;
}

.trend-spotlight-panel .metric-filter-subhelp {
    color: var(--text-muted);
    font-size: 11.5px;
    line-height: 1.5;
}

/* Actual class names used by dashboard.js for the type-group header.
 * Earlier polish rules used generic aliases; these selectors make the
 * hierarchy explicit and reliable.
 */
.trend-sensor-group-kicker {
    color: var(--text-accent-control);
    font-size: 11.5px;
    font-weight: 720;
    letter-spacing: .045em;
}

.trend-sensor-group-count {
    color: var(--text-secondary);
    font-size: 11.5px;
    font-weight: 650;
}

.group-toggle-label {
    color: var(--text-accent-control);
    font-size: 11.5px;
    font-weight: 720;
}

/* Individual chart secondary information. */
.chart-box .trend-marker-legend {
    font-size: 13px;
    line-height: 1.5;
}

.chart-box .trend-stat-label {
    font-size: 12px;
}

.chart-box .trend-stat-value {
    font-size: 13px;
}

.chart-box .trend-stat-value .stat-unit {
    font-size: 11.5px;
}

/* Shared summary cards --------------------------------------------------- */

.fleet-summary-label,
.settings-overview-label,
.detail-stat-label,
.device-stat-label,
.notification-stat span,
.ops-stat span,
.admin-summary-title,
.health-metric-label,
.profile-label {
    font-size: 12px;
    line-height: 1.35;
}

.fleet-summary-meta,
.settings-overview-meta,
.detail-stat-sub,
.profile-description,
.notification-section-summary,
.devices-summary,
.updated-at,
.data-center-header-meta,
.device-ops-updated {
    font-size: 11.5px;
    line-height: 1.45;
}

/* Tables: 10px headers looked visibly softer/smaller than surrounding UI.
 * 11.5px is still dense enough for the data-center tables.
 */
table thead th,
.accounts-table th {
    font-size: 11.5px;
    line-height: 1.35;
    letter-spacing: .015em;
}

/* Empty/loading/helper copy across pages. */
.empty-state,
.settings-empty,
.ops-empty,
.notification-empty,
.activity-empty,
.app-state,
.detail-loading {
    font-size: 12px;
    line-height: 1.5;
}

/* Device/status metadata used throughout overview/detail pages. */
.device-label,
.device-state,
.device-meta,
.meta-row,
.overview-health-label,
.overview-health-text {
    line-height: 1.45;
}

.device-label {
    font-size: 11.5px;
}

.device-state {
    font-size: 11.5px;
}

/* Mobile: avoid shrinking operational copy below a comfortable floor. */
@media (max-width: 720px) {
    :root {
        --type-micro: 11px;
        --type-caption: 11.5px;
        --type-secondary: 12px;
    }

    .trend-spotlight-panel .sensor-toggle,
    .trend-spotlight-panel .metric-filter-help,
    .trend-spotlight-panel .metric-filter-subhelp,
    .trend-sensor-group-kicker,
    .trend-sensor-group-count,
    .group-toggle-label {
        font-size: 11.5px;
    }

    table thead th,
    .accounts-table th {
        font-size: 11px;
    }
}

/* M3.2.1 · Canonical rounded shadow system v24 -------------------------
 * Shared contact-shadow and clipping rules for rounded glass surfaces.
 */
/* Canonical rounded shadow rules -------------------------------------
 * Fixes the square/rectangular "shadow sheet" seen around rounded glass cards.
 *
 * Root cause in the previous visual system:
 * - large blur-radius external box shadows;
 * - backdrop-filter compositing over nested translucent surfaces.
 *
 * v14 rule:
 * - backdrop glass is clipped to the rounded card contour;
 * - external shadows are short "contact shadows";
 * - nested cards do not cast another broad halo;
 * - separation comes from glass rim + local shadow, not a large grey field.
 */

:root {
    --rounded-shadow-panel:
        0 4px 11px rgba(37, 51, 44, .027),
        0 1px 3px var(--shadow-ink-014),
        inset 0 1px 0 var(--glass-white-62);
    --rounded-shadow-card:
        0 3px 8px rgba(37, 51, 44, .025),
        0 1px 2px var(--shadow-ink-012),
        inset 0 1px 0 var(--glass-white-66);
}

/* These surfaces are safe to clip: they do not own dropdown popovers.
 * Clipping forces the backdrop-filter compositor to obey the same rounded
 * silhouette as the visible card.
 */
.overview-attention-panel,
.notification-focus-card,
.detail-stat-card,
.chart-box,
.alert-item,
.notification-item,
.activity-item,
.device-card,
.pending-card {
    background-clip: padding-box;
    overflow: hidden;
}

/* Large rounded glass panels: short contact shadow only. */
.overview-attention-panel,
.notification-focus-card,
.overview-health-card,
.device-ops-overview {
    border-radius: var(--radius-glass-lg);
    box-shadow: var(--rounded-shadow-panel);
}

/* The screenshot example: "待关注事项".
 * No broad 20-30px grey halo under the whole panel.
 */
.overview-attention-panel {
    box-shadow:
        0 4px 10px var(--shadow-ink-024),
        0 1px 3px var(--shadow-ink-012),
        inset 0 1px 0 var(--glass-white-66);
}

/* Alert rows already have a red/neutral outline. A second external shadow
 * creates stacked rectangular haze, so keep only a tiny internal highlight.
 */
.overview-attention-panel .alert-item,
.notification-focus-card .notification-item {
    border-radius: 13px;
    box-shadow:
        inset 0 1px 0 var(--glass-white-58);
}

/* Repeated glass cards use the same rounded contact-shadow language. */
.detail-stat-card,
.chart-box,
.device-card,
.pending-card {
    box-shadow: var(--rounded-shadow-card);
}

/* Preserve the v13 detail-card material, but make its external shadow even
 * closer to the card so row gaps remain clean.
 */
.detail-stat-card {
    box-shadow:
        0 4px 10px rgba(36, 51, 43, .028),
        0 1px 3px rgba(36, 51, 43, .014),
        inset 0 1px 0 var(--glass-white-82),
        inset 1px 0 0 rgba(255, 255, 255, .20);
}

/* Trend cards: retain glass depth without a rectangular fog field. */
.chart-box {
    box-shadow:
        0 4px 11px rgba(37, 51, 45, .027),
        0 1px 3px rgba(37, 51, 45, .013),
        inset 0 1px 0 var(--glass-white-80),
        inset 1px 0 0 rgba(255, 255, 255, .21);
}

/* Hover never expands into a large blurred rectangle. */
.overview-attention-panel:hover,
.notification-focus-card:hover,
.detail-stat-card:hover,
.chart-box:hover,
.device-card:hover,
.pending-card:hover {
    box-shadow:
        0 6px 13px rgba(37, 51, 44, .032),
        0 1px 3px var(--shadow-ink-014),
        inset 0 1px 0 var(--glass-white-72);
}

/* Full-width generic panels still had the v6 24px blur shadow. Reduce it
 * globally, but do not clip them because some panels can own dropdowns.
 */
.panel,
.devices-toolbar,
.notification-filter-bar,
.data-query-workbench,
.trend-primary-controls,
.trend-spotlight-panel,
.settings-panel,
.pending-panel,
.record-table-shell,
.accounts-table-wrap,
.detail-table-wrap,
.history-table-shell,
.backup-table-shell {
    box-shadow:
        0 4px 12px rgba(36, 50, 43, .026),
        0 1px 3px rgba(36, 50, 43, .013),
        inset 0 1px 0 var(--glass-white-50);
}

/* Keep compact KPI tiles clean as well. */
.summary-card,
.fleet-summary-card,
.device-stat-card,
.settings-overview-card,
.notification-stat,
.ops-stat {
    box-shadow:
        0 3px 8px rgba(37, 52, 44, .022),
        0 1px 2px rgba(37, 52, 44, .011),
        inset 0 1px 0 var(--glass-highlight-52);
}

/* Mobile: even shorter shadows to avoid GPU/compositor halos. */
@media (max-width: 760px) {
    .overview-attention-panel,
    .notification-focus-card,
    .detail-stat-card,
    .chart-box,
    .device-card,
    .pending-card {
        box-shadow:
            0 3px 8px var(--shadow-ink-024),
            0 1px 2px var(--shadow-ink-012),
            inset 0 1px 0 var(--glass-white-66);
    }
}

/* M3.2.1 · Page-specific canonical refinements v26 ------------------------
 * Surviving selectors from the retired visual-polish core.
 * Generic hierarchy/surface/control/table rules were removed because their
 * canonical equivalents already live above in the v17/v24 design system.
 */
/* Page-specific refinements --------------------------------------------- */

.dashboard-hero,
.notification-hero,
.operations-hero,
.devices-header,
.data-center-header,
.settings-header,
.detail-header,
.pending-header {
    margin-bottom: 4px;
}

.dashboard-activity-grid,
.overview-grid,
.recent-layout,
.detail-top-grid,
.detail-middle-grid,
.detail-bottom-grid,
.operations-grid,
.account-grid {
    gap: var(--layout-section-gap);
}

.sensor-grid,
.fleet-summary-grid,
.device-stats,
.notification-stats,
.settings-overview,
.detail-stat-grid,
.communication-health-grid {
    gap: var(--layout-card-gap);
}

.device-ops-card,
.health-metric,
.trend-health-item,
.range-summary > *,
.selection-chip {
    border-color: var(--utility-card-border);
    background: var(--utility-card-bg);
}

.device-ops-card strong,
.health-metric-value,
.trend-health-item strong,
.range-summary strong {
    font-variant-numeric: tabular-nums;
}

.notification-focus-card {
    box-shadow: var(--utility-focus-shadow);
}

.notification-focus-icon,
.overview-health-icon {
    box-shadow: var(--utility-icon-shadow);
}

.data-guidance summary,
.advanced-operations > summary {
    color: var(--utility-heading);
    font-weight: 760;
}

.restore-warning,
.pending-note,
.notice,
.danger-notice {
    border-radius: 12px;
}

.account-dialog::backdrop,
.device-modal::before,
.restore-modal::before,
.notification-modal::before {
    backdrop-filter: blur(var(--blur-glass-xs));
}

/* M3.2.1 · Environment trend composition v32 -----------------------------
 * Fixes the visual imbalance of the trend control panel:
 * - control shelf no longer stretches into a large empty rectangle;
 * - device + range controls form a compact left-aligned workbench;
 * - metric controls use a stable sidebar/content ratio;
 * - sensor groups start earlier and read as one coherent block;
 * - vertical rhythm uses the shared spacing system.
 */

.trend-spotlight-panel {
    padding: var(--space-xl) var(--space-xl) var(--space-lg);
}

.trend-spotlight-panel .trend-control-head {
    min-height: 48px;
    padding-bottom: var(--space-sm);
}

.trend-spotlight-panel .trend-control-head h2 {
    line-height: 1.18;
}

.trend-spotlight-panel .range-status-chip {
    min-height: var(--control-height-compact);
    padding-inline: 14px;
}

/* Compact workbench instead of a full-width empty shelf. */
.trend-spotlight-panel .trend-primary-controls {
    width: fit-content;
    max-width: 100%;
    grid-template-columns:
        minmax(240px, var(--trend-device-width))
        minmax(500px, var(--trend-range-width));
    justify-content: start;
    align-items: end;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
    padding: var(--space-sm);
    border-radius: var(--radius-glass-md);
}

.trend-spotlight-panel .trend-primary-controls .control-block {
    min-width: 0;
}

.trend-spotlight-panel .control-label {
    margin-bottom: 6px;
}

.trend-spotlight-panel .device-select-shell select,
.trend-spotlight-panel .range-btn {
    min-height: var(--control-height);
}

.trend-spotlight-panel .range-presets {
    grid-template-columns: repeat(4, minmax(112px, 1fr));
    gap: var(--control-gap);
}

/* Metrics: stable left rail + flexible sensor groups. */
.trend-spotlight-panel .metric-filter {
    grid-template-columns:
        minmax(260px, var(--metric-sidebar-width))
        minmax(0, 1fr);
    column-gap: var(--space-xl);
    row-gap: var(--space-sm);
    align-items: start;
    margin-top: var(--space-md);
    padding-top: var(--space-md);
}

.trend-spotlight-panel .metric-filter-head {
    display: grid;
    grid-template-columns: 1fr;
    align-content: start;
    gap: var(--space-xs);
    min-width: 0;
}

.trend-spotlight-panel .metric-filter-title {
    font-size: 12px;
}

.trend-spotlight-panel .metric-filter-help {
    display: block;
    max-width: 28em;
    margin-top: 2px;
    line-height: 1.55;
}

.trend-spotlight-panel .metric-filter-actions {
    justify-content: flex-start;
    gap: var(--control-gap);
    margin-top: 2px;
}

.trend-spotlight-panel .legend-row {
    align-items: start;
    align-content: start;
    gap: var(--space-sm) var(--space-lg);
    margin: 0;
    padding-top: 1px;
}

.trend-spotlight-panel .sensor-toggle-group {
    gap: var(--space-xs);
}

.trend-spotlight-panel .sensor-toggle-group-title {
    font-size: 11px;
    line-height: 1.3;
}

.trend-spotlight-panel .sensor-toggle-group-items {
    gap: var(--control-gap);
}

.trend-spotlight-panel .sensor-toggle {
    min-height: 31px;
    padding-inline: 11px;
}

/* Quality strip gets breathing room but remains subordinate. */
.trend-spotlight-panel .trend-health-bar {
    margin-top: var(--space-md);
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-compact);
}

.trend-spotlight-panel .trend-health-item {
    min-height: 28px;
    padding: 4px 8px;
}

.trend-spotlight-panel .range-summary {
    margin-top: var(--space-xs);
}

.trend-spotlight-panel .metric-filter-subhelp {
    margin-top: var(--space-xs);
    font-size: 10px;
    line-height: 1.5;
}

/* Medium screens still keep the two controls together while using full width. */
@media (max-width: 1120px) {
    .trend-spotlight-panel .trend-primary-controls {
        width: 100%;
        grid-template-columns:
            minmax(220px, .72fr)
            minmax(0, 1.55fr);
    }

    .trend-spotlight-panel .range-presets {
        grid-template-columns: repeat(4, minmax(96px, 1fr));
    }

    .trend-spotlight-panel .metric-filter {
        grid-template-columns:
            minmax(240px, 280px)
            minmax(0, 1fr);
        column-gap: var(--space-lg);
    }
}

/* Tablet: stack the control families and move metrics into one reading flow. */
@media (max-width: 860px) {
    .trend-spotlight-panel {
        padding: var(--panel-padding-compact);
    }

    .trend-spotlight-panel .trend-primary-controls {
        grid-template-columns: 1fr;
        width: 100%;
    }

    .trend-spotlight-panel .range-presets {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .trend-spotlight-panel .metric-filter {
        grid-template-columns: 1fr;
        gap: var(--space-sm);
    }

    .trend-spotlight-panel .metric-filter-head {
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
    }

    .trend-spotlight-panel .metric-filter-actions {
        margin-top: 0;
    }

    .trend-spotlight-panel .legend-row {
        gap: var(--space-sm);
    }
}

/* Phone: keep controls comfortable and prevent action wrapping from feeling cramped. */
@media (max-width: 560px) {
    .trend-spotlight-panel .metric-filter-head {
        grid-template-columns: 1fr;
        align-items: start;
    }

    .trend-spotlight-panel .metric-filter-actions {
        justify-content: flex-start;
    }

    .trend-spotlight-panel .range-presets {
        grid-template-columns: 1fr 1fr;
    }
}

/* M3.2.1 · Smooth sensor-group collapse v33 ------------------------------
 * Exact-height animation is driven by dashboard.js.
 * CSS owns the visual continuity around that motion.
 */

.trend-sensor-group {
    contain: layout style;
}

.trend-sensor-group-body {
    display: grid;
    overflow: clip;
    height: auto;
    max-height: none;
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transform-origin: top center;
    will-change: height, opacity, transform;

    /*
     * Disable the old max-height transition from motion.css.
     * Web Animations API now owns height/opacity/transform.
     */
    transition: none;
}

.trend-sensor-group:not(.is-open) .trend-sensor-group-body {
    display: grid;
    height: 0;
    max-height: none;
    margin-top: 0;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    pointer-events: none;
    transition: none;
}

/* Header feedback stays synchronized with body motion. */
.trend-sensor-group-head {
    position: relative;
    overflow: hidden;
    transition:
        background-color 180ms ease,
        border-color 180ms ease,
        box-shadow 220ms ease,
        transform 220ms cubic-bezier(.22,.78,.24,1);
}

.trend-sensor-group-head:active {
    transform: scale(.998);
}

.group-toggle-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 44px;
    justify-content: flex-end;
    transition:
        color 180ms ease,
        opacity 180ms ease,
        transform 240ms cubic-bezier(.22,.78,.24,1);
}

/* Tiny directional cue without changing the existing HTML. */
.group-toggle-label::after {
    content: "⌄";
    display: inline-block;
    font-size: 12px;
    line-height: 1;
    opacity: .68;
    transform: rotate(0deg) translateY(-1px);
    transform-origin: center;
    transition:
        transform 260ms cubic-bezier(.22,.78,.24,1),
        opacity 180ms ease;
}

.trend-sensor-group.is-open .group-toggle-label {
    transform: translateY(-1px);
}

.trend-sensor-group.is-open .group-toggle-label::after {
    transform: rotate(180deg) translateY(1px);
    opacity: .82;
}

/* Expand/collapse-all controls should feel related to the group motion. */
#expandAllGroupsBtn,
#collapseAllGroupsBtn {
    transition:
        transform 180ms cubic-bezier(.22,.78,.24,1),
        background-color 180ms ease,
        border-color 180ms ease,
        box-shadow 180ms ease;
}

#expandAllGroupsBtn:active,
#collapseAllGroupsBtn:active {
    transform: translateY(1px) scale(.985);
}

@media (prefers-reduced-motion: reduce) {
    .trend-sensor-group {
        contain: none;
    }

    .trend-sensor-group-body,
    .trend-sensor-group-head,
    .group-toggle-label,
    .group-toggle-label::after,
    #expandAllGroupsBtn,
    #collapseAllGroupsBtn {
        transition: none;
        animation: none;
    }
}

/* M3.2.1 · Canonical layout skeleton v34 ---------------------------------
 * Shared page geometry for Dashboard / Devices / Detail / Notifications /
 * Operations / Data Center / Settings / Pending / Accounts.
 */

/* Main page shells */
.container,
.product-page,
.dashboard-page,
.devices-page,
.detail-page,
.notification-page,
.operations-page,
.data-center-page,
.settings-page,
.pending-page,
.accounts-page,
.account-page {
    width: min(
        calc(100% - (var(--page-gutter) * 2)),
        var(--page-max-width)
    );
    margin-inline: auto;
}

/* Open page headers */
.ui-page-header,
.dashboard-hero,
.devices-header,
.detail-header,
.notification-hero,
.operations-hero,
.data-center-header,
.settings-header,
.pending-header,
.accounts-header,
.account-header {
    min-height: var(--page-header-min-height);
    margin-bottom: var(--page-header-gap);
}

/* Primary sections share one vertical rhythm. */
.panel,
.devices-panel,
.detail-panel,
.detail-channels-panel,
.notification-panel,
.operations-panel,
.data-section-panel,
.settings-panel,
.pending-panel,
.accounts-panel,
.device-ops-overview,
.overview-health-card,
.overview-attention-panel,
.notification-focus-card,
.trend-spotlight-panel,
.simple-threshold-panel,
.template-panel {
    margin-bottom: var(--page-section-gap);
}

/* Canonical panel breathing room. */
.panel,
.devices-panel,
.detail-panel,
.detail-channels-panel,
.notification-panel,
.operations-panel,
.data-section-panel,
.settings-panel,
.pending-panel,
.accounts-panel {
    padding-left: var(--panel-padding-normal);
    padding-right: var(--panel-padding-normal);
}

/* Section headers keep consistent baseline height. */
.ui-section-header,
.section-head,
.panel-head,
.panel-title-row,
.detail-section-head,
.settings-panel-head,
.data-section-heading,
.results-heading,
.device-ops-overview-head,
.notification-history-head,
.rules-head {
    min-height: var(--section-header-min-height);
}

/* Core grids */
.device-stats,
.notification-stats,
.operations-stats,
.settings-overview,
.accounts-summary,
.detail-stat-grid,
.device-grid,
.channel-grid,
.quick-links,
.pending-grid,
.config-grid,
.device-ops-grid,
.trend-spotlight-grid {
    gap: var(--grid-gap-normal);
}

/* Toolbars and filter benches align to one control rhythm. */
.devices-toolbar,
.notification-filter-bar,
.data-query-workbench,
.trend-primary-controls,
.filters,
.backup-toolbar,
.sensor-dialog-toolbar,
.template-form,
.template-apply-panel,
.simple-threshold-form,
.alert-rule-form,
.ui-filter-bar {
    min-height: var(--toolbar-min-height);
    gap: var(--layout-control-gap);
}

/* Preserve the intentionally compact Environment Trend composition. */
.trend-spotlight-panel {
    margin-bottom: var(--page-section-gap);
}

.trend-spotlight-panel .metric-filter {
    margin-top: var(--space-md);
}

.trend-spotlight-panel .trend-health-bar {
    margin-top: var(--space-md);
}

/* Large displays get slightly more breathing room, not wider content. */
@media (min-width: 1680px) {
    .container,
    .product-page,
    .dashboard-page,
    .devices-page,
    .detail-page,
    .notification-page,
    .operations-page,
    .data-center-page,
    .settings-page,
    .pending-page,
    .accounts-page,
    .account-page {
        width: min(
            calc(100% - (var(--page-gutter-wide) * 2)),
            var(--page-max-width)
        );
    }

    .panel,
    .devices-panel,
    .detail-panel,
    .detail-channels-panel,
    .notification-panel,
    .operations-panel,
    .data-section-panel,
    .settings-panel,
    .pending-panel,
    .accounts-panel {
        padding-left: var(--panel-padding-wide);
        padding-right: var(--panel-padding-wide);
    }

    .device-grid,
    .channel-grid,
    .pending-grid,
    .config-grid,
    .device-ops-grid,
    .trend-spotlight-grid {
        gap: var(--grid-gap-wide);
    }
}

/* Tablet */
@media (max-width: 980px) {
    .container,
    .product-page,
    .dashboard-page,
    .devices-page,
    .detail-page,
    .notification-page,
    .operations-page,
    .data-center-page,
    .settings-page,
    .pending-page,
    .accounts-page,
    .account-page {
        width: calc(100% - 32px);
    }

    .ui-page-header,
    .dashboard-hero,
    .devices-header,
    .detail-header,
    .notification-hero,
    .operations-hero,
    .data-center-header,
    .settings-header,
    .pending-header,
    .accounts-header,
    .account-header {
        min-height: auto;
        margin-bottom: 14px;
    }

    .panel,
    .devices-panel,
    .detail-panel,
    .detail-channels-panel,
    .notification-panel,
    .operations-panel,
    .data-section-panel,
    .settings-panel,
    .pending-panel,
    .accounts-panel {
        padding-left: var(--panel-padding-compact);
        padding-right: var(--panel-padding-compact);
    }
}

/* Phone */
@media (max-width: 620px) {
    .container,
    .product-page,
    .dashboard-page,
    .devices-page,
    .detail-page,
    .notification-page,
    .operations-page,
    .data-center-page,
    .settings-page,
    .pending-page,
    .accounts-page,
    .account-page {
        width: calc(100% - (var(--page-gutter-mobile) * 2));
    }

    .panel,
    .devices-panel,
    .detail-panel,
    .detail-channels-panel,
    .notification-panel,
    .operations-panel,
    .data-section-panel,
    .settings-panel,
    .pending-panel,
    .accounts-panel {
        padding-left: var(--panel-padding-mobile);
        padding-right: var(--panel-padding-mobile);
    }

    .device-stats,
    .notification-stats,
    .operations-stats,
    .settings-overview,
    .accounts-summary,
    .detail-stat-grid,
    .device-grid,
    .channel-grid,
    .quick-links,
    .pending-grid,
    .config-grid,
    .device-ops-grid,
    .trend-spotlight-grid {
        gap: var(--grid-gap-compact);
    }
}

/* M3.2.1 · Product-wide typography hierarchy v35 ------------------------ */

/* Default reading texture */
body,
button,
input,
select,
textarea {
    color: var(--text-primary);
    font-size: var(--type-body);
    font-weight: var(--weight-body);
    letter-spacing: var(--tracking-body);
    text-rendering: geometricPrecision;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Page titles */
.ui-page-header h1,
.dashboard-hero h1,
.devices-header h1,
.detail-header h1,
.notification-hero h1,
.operations-hero h1,
.data-center-header h1,
.settings-header h1,
.pending-header h1,
.accounts-header h1,
.account-header h1,
.page-title {
    font-size: var(--type-page-title);
    line-height: var(--leading-tight);
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
    color: var(--text-primary);
}

/* Primary section titles */
.ui-section-header h2,
.section-head h2,
.panel-head h2,
.panel-title-row h2,
.detail-section-head h2,
.settings-panel-head h2,
.data-section-heading h2,
.results-heading h2,
.device-ops-overview-head h2,
.notification-history-head h2,
.rules-head h2,
.trend-spotlight-panel > h2,
.panel > h2 {
    font-size: var(--type-section-title);
    line-height: var(--leading-title);
    font-weight: var(--weight-title);
    letter-spacing: var(--tracking-title);
    color: var(--text-primary);
}

/* Card titles */
.metric-card h3,
.sensor-card h3,
.device-card h3,
.channel-card h3,
.notification-card h3,
.attention-item h3,
.quick-link-card h3,
.settings-card h3,
.pending-card h3,
.account-card h3,
.card-title,
.metric-title,
.sensor-title,
.device-title {
    font-size: var(--type-card-title);
    line-height: var(--leading-title);
    font-weight: var(--weight-card-title);
    letter-spacing: var(--tracking-card);
    color: var(--text-primary);
}

/* Body copy */
.panel p,
.card p,
.detail-panel p,
.notification-panel p,
.operations-panel p,
.data-section-panel p,
.settings-panel p,
.pending-panel p,
.accounts-panel p,
.help-text,
.description,
.summary-text {
    line-height: var(--leading-body);
}

/* Secondary copy */
.ui-page-header p,
.ui-section-header p,
.page-subtitle,
.section-subtitle,
.card-subtitle,
.device-meta,
.channel-meta,
.notification-meta,
.settings-description,
.empty-description,
.hint,
.helper-text {
    color: var(--text-secondary);
    font-size: var(--type-label);
    line-height: var(--leading-caption);
    font-weight: var(--weight-muted);
}

/* Labels: readable, but never compete with content. */
label,
.label,
.field-label,
.form-label,
.filter-label,
.stat-label,
.metric-label,
.kicker,
.eyebrow,
.group-label,
.sensor-group-label,
.legend-label {
    color: var(--text-secondary);
    font-size: var(--type-label);
    line-height: var(--leading-caption);
    font-weight: var(--weight-strong);
    letter-spacing: var(--tracking-label);
}

/* Small operational metadata */
.timestamp,
.updated-at,
.meta,
.caption,
.table-note,
.footnote,
.data-footnote,
.status-note,
.freshness-note {
    color: var(--text-muted);
    font-size: var(--type-caption);
    line-height: var(--leading-caption);
    font-weight: var(--weight-muted);
}

/* Buttons and pills share one typographic voice. */
button,
.button,
.btn,
.ui-button,
.pill,
.badge,
.status-pill,
.chip,
.metric-chip,
.sensor-chip,
.segmented-control button,
.time-range-button {
    font-size: var(--type-label);
    line-height: 1.2;
    font-weight: var(--weight-strong);
    letter-spacing: 0;
}

/* Inputs should never look visually weaker than surrounding labels. */
input,
select,
textarea,
.ui-input,
.ui-select {
    font-size: var(--type-body);
    line-height: 1.35;
    font-weight: var(--weight-body);
}

/* Tables: compact but readable. */
table {
    font-size: var(--type-label);
    line-height: 1.45;
}
th {
    color: var(--text-secondary);
    font-weight: var(--weight-strong);
}
td {
    color: var(--text-primary);
    font-weight: var(--weight-body);
}

/* Empty states were previously too faint/small in several panels. */
.empty-state,
.chart-empty,
.no-data,
.no-data-text,
.empty-text,
.chart-placeholder {
    color: var(--text-secondary);
    font-size: 14px;
    line-height: 1.5;
    font-weight: var(--weight-strong);
}

/* Alert trigger / warning microcopy: preserve hierarchy but improve legibility. */
.alert-trigger,
.alert-trigger-count,
.warning-count,
.threshold-count,
.alarm-count {
    font-size: 13px;
    line-height: 1.35;
    font-weight: var(--weight-strong);
}

/* Numbers remain visually crisp. */
.stat-value,
.metric-value,
.current-value,
.summary-value,
.kpi-value,
.value {
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.015em;
}

/* Phone: retain hierarchy without oversized headings. */
@media (max-width: 620px) {
    :root {
        --type-page-title: 27px;
        --type-section-title: 21px;
        --type-card-title: 18px;
        --type-body: 14px;
        --type-label: 13px;
        --type-caption: 12px;
    }
}

/* M3.2.1 · Canonical control language v36 ------------------------------- */

/* Shared control geometry */
body .container :where(
    button,
    input,
    select,
    textarea,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button
) {
    border-radius: var(--control-radius);
    transition: var(--control-transition);
}

/* Inputs / selects */
body .container :where(input, select, textarea) {
    min-height: var(--control-height-md);
    padding-inline: var(--control-pad-x-md);
    border: 1px solid var(--control-border);
    background: var(--control-surface);
    color: var(--text-primary);
    box-shadow: var(--control-shadow);
}

body .container :where(input, select, textarea):hover:not(:disabled) {
    border-color: var(--control-border-hover);
    background: var(--control-surface-hover);
    box-shadow: var(--control-shadow-hover);
}

body .container :where(input, select, textarea):focus,
body .container :where(input, select, textarea):focus-visible {
    outline: none;
    border-color: var(--control-border-active);
    background: var(--control-surface-hover);
    box-shadow: var(--focus-ring);
}

/* Neutral buttons */
body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .notification-action-button
):not(.primary):not(.danger):not(.active):not(:disabled) {
    min-height: var(--control-height-md);
    padding-inline: var(--control-pad-x-md);
    border: 1px solid var(--control-border);
    background: var(--control-surface);
    color: var(--text-secondary);
    box-shadow: var(--control-shadow);
}

body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .notification-action-button
):not(.primary):not(.danger):not(.active):hover:not(:disabled) {
    border-color: var(--control-border-hover);
    background: var(--control-surface-hover);
    color: var(--text-primary);
    box-shadow: var(--control-shadow-hover);
    transform: translateY(-1px);
}

/* Primary actions */
body .container :where(
    button.primary,
    .primary-btn,
    .button.primary,
    .notification-action-button.primary
) {
    min-height: var(--control-height-md);
    padding-inline: var(--control-pad-x-lg);
    border: 1px solid var(--control-primary-border);
    background: var(--control-primary-bg);
    color: var(--control-primary-fg);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.18),
        0 3px 9px rgba(35,112,60,.09);
}

body .container :where(
    button.primary,
    .primary-btn,
    .button.primary,
    .notification-action-button.primary
):hover:not(:disabled) {
    border-color: var(--control-primary-border-hover);
    background: var(--control-primary-bg-hover);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.21),
        0 5px 12px rgba(35,112,60,.12);
    transform: translateY(-1px);
}

/* Destructive actions */
body .container :where(button.danger, .danger-btn, .button.danger) {
    min-height: var(--control-height-md);
    padding-inline: var(--control-pad-x-lg);
    border: 1px solid var(--control-danger-border);
    background: var(--control-danger-bg);
    color: var(--control-danger-fg);
}

/* Active / selected controls */
body .container :where(
    .range-btn.active,
    .data-tab.active,
    .notification-segmented button.active,
    .segmented-control button.active,
    button[aria-pressed="true"]
) {
    border-color: var(--control-border-active);
    background: var(--control-surface-active);
    color: var(--state-success-fg);
    box-shadow: var(--control-shadow-active);
}

/* Tabs / segmented ranges should read as a family. */
body .container :where(
    .range-presets,
    .data-tabs,
    .notification-segmented,
    .segmented-control
) {
    gap: 6px;
    padding: 5px;
    border: 1px solid rgba(255,255,255,.52);
    border-radius: 14px;
    background: rgba(255,255,255,.28);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.48);
}

body .container :where(
    .range-btn,
    .data-tab,
    .notification-segmented button,
    .segmented-control button
) {
    min-height: var(--control-height-md);
    padding-inline: var(--control-pad-x-md);
}

/* Pill / status family */
body .container :where(
    .pill,
    .badge,
    .chip,
    .status-pill,
    .state-pill,
    .severity-pill,
    .rule-chip,
    .pending-chip,
    .notification-chip,
    .range-status-chip,
    .selection-chip,
    .result-count-chip
) {
    min-height: 30px;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding-inline: 11px;
    border-radius: var(--control-radius-pill);
    line-height: 1;
}

/* Common operation rows / toolbars */
body .container :where(
    .devices-toolbar,
    .notification-filter-bar,
    .data-query-workbench,
    .filters,
    .backup-toolbar,
    .ui-filter-bar
) {
    align-items: center;
    gap: var(--layout-control-gap);
}

/* Press feedback */
body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button
):active:not(:disabled) {
    transform: translateY(0) scale(.985);
}

/* Keyboard accessibility */
body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button
):focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* Disabled state */
body .container :where(
    button,
    input,
    select,
    textarea,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button
):disabled {
    opacity: .48;
    cursor: default;
    transform: none;
    box-shadow: none;
}

/* Small utility controls remain compact. */
body .container :where(
    .table-btn,
    .group-toggle,
    .group-toggle-label,
    .compact-btn
) {
    min-height: var(--control-height-sm);
}

/* Mobile: preserve touch target without inflating density. */
@media (max-width: 620px) {
    body .container :where(
        button,
        input,
        select,
        .button,
        .btn,
        .range-btn,
        .data-tab
    ) {
        min-height: 42px;
    }

    body .container :where(
        .range-presets,
        .data-tabs,
        .notification-segmented,
        .segmented-control
    ) {
        gap: 5px;
        padding: 4px;
    }
}

/* M3.2.1 · Canonical data surfaces v37 ---------------------------------- */

/* -----------------------------------------------------------------------
   1. Table shells
   ----------------------------------------------------------------------- */
body .container :where(
    .record-table-shell,
    .accounts-table-wrap,
    .detail-table-wrap,
    .history-table-shell,
    .backup-table-shell,
    .recent-table-shell,
    .table-wrap,
    .table-shell,
    .ui-table-shell
) {
    position: relative;
    overflow: auto;
    border: 1px solid var(--data-border);
    border-radius: var(--ds-radius-card);
    background: var(--data-surface);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.56),
        0 3px 10px rgba(36,51,43,.018);
    scrollbar-gutter: stable;
}

/* Tables */
body .container :where(
    table,
    .accounts-table,
    .detail-table
) {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: transparent;
    font-variant-numeric: tabular-nums;
}

/* Header */
body .container :where(
    table,
    .accounts-table,
    .detail-table
) thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    min-height: var(--data-row-height-compact);
    padding: var(--data-cell-y) var(--data-cell-x);
    border-bottom: 1px solid var(--data-border-strong);
    background: var(--data-header-surface);
    color: var(--text-secondary);
    font-size: var(--type-caption);
    font-weight: var(--weight-strong);
    line-height: 1.35;
    text-align: left;
    white-space: nowrap;
    -webkit-backdrop-filter: blur(9px) saturate(108%);
    backdrop-filter: blur(9px) saturate(108%);
}

/* Body cells */
body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody td {
    min-height: var(--data-row-height);
    padding: var(--data-cell-y) var(--data-cell-x);
    border-bottom: 1px solid var(--data-border);
    color: var(--text-primary);
    vertical-align: middle;
}

/* Last row does not need a hanging divider. */
body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr:last-child td {
    border-bottom-color: transparent;
}

/* Row interaction */
body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr {
    background: transparent;
    transition:
        background-color 160ms ease,
        box-shadow 160ms ease;
}

body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr:hover {
    background: var(--data-row-hover);
}

body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr.selected,
body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr[aria-selected="true"] {
    background: var(--data-row-selected);
}

/* Numeric cells */
body .container :where(
    td.numeric,
    td.number,
    td.value,
    .table-number,
    .numeric-cell
) {
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* Keep actions visually compact. */
body .container :where(
    td.actions,
    .table-actions,
    .row-actions
) {
    white-space: nowrap;
}

/* -----------------------------------------------------------------------
   2. Lists / event rows
   ----------------------------------------------------------------------- */
body .container :where(
    .alert-item,
    .notification-item,
    .activity-item,
    .event-card,
    .rule-template-row,
    .quality-rule,
    .history-item,
    .list-row
) {
    position: relative;
    border: 1px solid var(--data-border);
    border-radius: var(--ds-radius-card);
    background: rgba(255,255,255,.34);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.52),
        0 2px 7px rgba(36,51,43,.014);
    transition:
        background-color 180ms ease,
        border-color 180ms ease,
        box-shadow 190ms ease,
        transform 190ms cubic-bezier(.22,.78,.24,1);
}

body .container :where(
    .alert-item,
    .notification-item,
    .activity-item,
    .event-card,
    .rule-template-row,
    .quality-rule,
    .history-item,
    .list-row
):hover {
    border-color: var(--data-border-strong);
    background: rgba(255,255,255,.44);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.62),
        0 4px 11px rgba(36,51,43,.024);
    transform: translateY(-1px);
}

/* -----------------------------------------------------------------------
   3. Empty states
   ----------------------------------------------------------------------- */
body .container :where(
    .empty-state,
    .settings-empty,
    .ops-empty,
    .notification-empty,
    .activity-empty,
    .devices-empty,
    .detail-empty,
    .template-target-empty,
    .app-state
) {
    min-height: var(--empty-min-height);
    display: grid;
    place-items: center;
    align-content: center;
    gap: 8px;
    padding: var(--space-xl);
    border: 1px dashed var(--empty-border);
    border-radius: var(--ds-radius-card);
    background: var(--empty-surface);
    color: var(--text-secondary);
    text-align: center;
}

/* Empty states inside tables should stay compact. */
body .container td:where(
    .empty-state,
    .detail-empty-cell,
    .empty-cell
) {
    height: 84px;
    padding: var(--space-md);
    border: 0;
    background: transparent;
    text-align: center;
    vertical-align: middle;
}

/* Empty title / description if present */
body .container :where(
    .empty-state-title,
    .empty-title
) {
    color: var(--text-primary);
    font-size: 15px;
    font-weight: var(--weight-strong);
}

body .container :where(
    .empty-state-description,
    .empty-description,
    .empty-hint
) {
    max-width: 38em;
    color: var(--text-muted);
    font-size: var(--type-caption);
    line-height: 1.55;
}

/* -----------------------------------------------------------------------
   4. Loading / skeleton states
   ----------------------------------------------------------------------- */
@keyframes m321-v37-skeleton {
    0%   { transform: translateX(-125%); opacity: 0; }
    28%  { opacity: .38; }
    68%  { opacity: .24; }
    100% { transform: translateX(125%); opacity: 0; }
}

body .container :where(
    .loading,
    .is-loading,
    .detail-loading,
    .app-state-loading,
    .skeleton
) {
    position: relative;
    overflow: hidden;
}

body .container :where(
    .loading,
    .is-loading,
    .detail-loading,
    .app-state-loading,
    .skeleton
)::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        linear-gradient(
            105deg,
            transparent 28%,
            var(--skeleton-highlight) 48%,
            transparent 68%
        );
    animation: m321-v37-skeleton 1.75s ease-in-out infinite;
}

/* Generic skeleton blocks, if present. */
body .container :where(
    .skeleton-line,
    .skeleton-block,
    .skeleton-cell
) {
    border-radius: 8px;
    background: var(--skeleton-base);
}

/* -----------------------------------------------------------------------
   5. Messages / banners
   ----------------------------------------------------------------------- */
body .container :where(
    .message,
    .accounts-message,
    .notification-message,
    .account-message,
    .form-message,
    .template-message,
    .simple-threshold-message,
    .quality-event-message,
    .toast,
    .flash-message,
    .app-toast
) {
    min-height: 38px;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 12px;
    border: 1px solid var(--data-border);
    border-radius: var(--control-radius);
    background: rgba(255,255,255,.48);
    color: var(--text-secondary);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.56);
}

body .container :where(
    .message.ok,
    .accounts-message.ok,
    .notification-message.ok,
    .account-message.ok,
    .form-message.ok,
    .template-message.ok,
    .simple-threshold-message.ok,
    .quality-event-message.ok,
    .toast.success,
    .flash-message.success
) {
    border-color: var(--message-success-border);
    background: var(--message-success-bg);
    color: var(--state-success-fg);
}

body .container :where(
    .message.error,
    .accounts-message.error,
    .notification-message.error,
    .account-message.error,
    .form-message.error,
    .template-message.error,
    .simple-threshold-message.error,
    .quality-event-message.error,
    .toast.error,
    .flash-message.error
) {
    border-color: var(--message-danger-border);
    background: var(--message-danger-bg);
    color: var(--state-danger-fg);
}

body .container :where(
    .message.warning,
    .toast.warning,
    .flash-message.warning
) {
    border-color: var(--message-warning-border);
    background: var(--message-warning-bg);
    color: var(--state-warning-fg);
}

body .container :where(
    .message.info,
    .toast.info,
    .flash-message.info
) {
    border-color: var(--message-info-border);
    background: var(--message-info-bg);
    color: var(--state-info-fg);
}

/* -----------------------------------------------------------------------
   6. Pagination
   ----------------------------------------------------------------------- */
body .container :where(
    .pagination,
    .pager,
    .pagination-controls,
    .table-pagination
) {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--pager-gap);
    min-height: 48px;
    padding-top: var(--space-sm);
}

body .container :where(
    .page-btn,
    .pager button,
    .pagination button,
    .pagination-btn
) {
    min-width: var(--pager-height);
    min-height: var(--pager-height);
    padding-inline: 10px;
}

body .container :where(
    .page-btn.active,
    .pagination button.active,
    .pagination-btn.active,
    .pager button[aria-current="page"]
) {
    border-color: var(--control-border-active);
    background: var(--control-surface-active);
    color: var(--state-success-fg);
}

/* -----------------------------------------------------------------------
   7. Dialogs / modals
   ----------------------------------------------------------------------- */
body .container :where(
    .account-dialog,
    .device-dialog,
    .notification-dialog,
    .restore-dialog,
    .ui-dialog-surface
) {
    width: min(calc(100vw - 32px), var(--dialog-width-md));
    max-height: min(84vh, 780px);
    overflow: auto;
    border: 1px solid rgba(255,255,255,.72);
    border-radius: var(--ds-radius-panel);
    background:
        linear-gradient(
            150deg,
            rgba(255,255,255,.88),
            var(--dialog-surface-end)
        );
    box-shadow: var(--dialog-shadow);
    -webkit-backdrop-filter: blur(var(--blur-glass-panel)) saturate(112%);
    backdrop-filter: blur(var(--blur-glass-panel)) saturate(112%);
}

body .container :where(
    .dialog-head,
    .device-dialog-head,
    .notification-dialog-head,
    .restore-dialog-head
) {
    position: sticky;
    top: 0;
    z-index: 3;
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--border-line);
    background: linear-gradient(
        180deg,
        rgba(255,255,255,.62),
        rgba(255,255,255,.20)
    );
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
}

body .container :where(
    .dialog-actions,
    .device-dialog-actions,
    .notification-dialog-actions,
    .restore-dialog-actions
) {
    position: sticky;
    bottom: 0;
    z-index: 3;
    display: flex;
    justify-content: flex-end;
    gap: var(--layout-control-gap);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--border-line);
    background: linear-gradient(
        0deg,
        rgba(255,255,255,.66),
        rgba(255,255,255,.22)
    );
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
}

/* -----------------------------------------------------------------------
   8. Data toolbars / counts
   ----------------------------------------------------------------------- */
body .container :where(
    .results-heading,
    .record-toolbar,
    .table-toolbar,
    .data-toolbar,
    .history-toolbar
) {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--layout-control-gap);
    min-height: 48px;
}

body .container :where(
    .result-count,
    .record-count,
    .table-count,
    .selection-count
) {
    color: var(--text-muted);
    font-size: var(--type-caption);
    font-variant-numeric: tabular-nums;
}

/* Responsive data density */
@media (max-width: 760px) {
    :root {
        --data-cell-x: var(--data-cell-x-compact);
        --data-row-height: var(--data-row-height-compact);
        --empty-min-height: 112px;
    }

    body .container :where(
        .record-table-shell,
        .accounts-table-wrap,
        .detail-table-wrap,
        .history-table-shell,
        .backup-table-shell,
        .recent-table-shell,
        .table-wrap,
        .table-shell,
        .ui-table-shell
    ) {
        border-radius: 12px;
    }

    body .container :where(
        .results-heading,
        .record-toolbar,
        .table-toolbar,
        .data-toolbar,
        .history-toolbar
    ) {
        align-items: flex-start;
        flex-wrap: wrap;
    }

    body .container :where(
        .dialog-actions,
        .device-dialog-actions,
        .notification-dialog-actions,
        .restore-dialog-actions
    ) {
        flex-wrap: wrap;
    }
}

@media (prefers-reduced-motion: reduce) {
    body .container :where(
        .loading,
        .is-loading,
        .detail-loading,
        .app-state-loading,
        .skeleton
    )::after {
        animation: none;
        display: none;
    }

    body .container :where(
        .alert-item,
        .notification-item,
        .activity-item,
        .event-card,
        .rule-template-row,
        .quality-rule,
        .history-item,
        .list-row
    ) {
        transition: none;
    }
}

/* M3.2.1 · Microinteraction polish v38 -----------------------------------
 * Motion is deliberately restrained:
 * - one page entrance;
 * - material lift only on interactive cards;
 * - consistent control press/focus feedback;
 * - dialog entrance;
 * - disclosure/details motion cues;
 * - no perpetual decorative animation.
 */

/* -----------------------------------------------------------------------
   1. Page entrance
   ----------------------------------------------------------------------- */
@keyframes m321-v38-page-enter {
    from {
        opacity: 0;
        transform: translateY(7px);
        filter: saturate(.96);
    }
    to {
        opacity: 1;
        transform: translateY(0);
        filter: saturate(1);
    }
}


/* -----------------------------------------------------------------------
   2. Interactive card material
   ----------------------------------------------------------------------- */
body .container :where(
    a.device-card,
    a.quick-link-card,
    button.metric-card,
    button.sensor-card,
    .device-card[role="button"],
    .sensor-card[role="button"],
    .channel-card[role="button"],
    .notification-item[role="button"],
    .activity-item[role="button"],
    .clickable-card,
    .interactive-card
) {
    transform: translateY(0);
    transform-origin: center;
    transition:
        transform var(--motion-normal) var(--ease-standard),
        border-color var(--motion-fast) ease,
        background-color var(--motion-fast) ease,
        box-shadow var(--motion-normal) ease;
}

body .container :where(
    a.device-card,
    a.quick-link-card,
    button.metric-card,
    button.sensor-card,
    .device-card[role="button"],
    .sensor-card[role="button"],
    .channel-card[role="button"],
    .notification-item[role="button"],
    .activity-item[role="button"],
    .clickable-card,
    .interactive-card
):hover {
    transform: translateY(var(--lift-card));
    box-shadow: var(--motion-shadow-card-hover);
}

body .container :where(
    a.device-card,
    a.quick-link-card,
    button.metric-card,
    button.sensor-card,
    .device-card[role="button"],
    .sensor-card[role="button"],
    .channel-card[role="button"],
    .notification-item[role="button"],
    .activity-item[role="button"],
    .clickable-card,
    .interactive-card
):active {
    transform: translateY(0) scale(.992);
}

/* -----------------------------------------------------------------------
   3. Controls: one tactile language
   ----------------------------------------------------------------------- */
body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button,
    input,
    select,
    textarea
) {
    transition:
        background-color var(--motion-fast) ease,
        border-color var(--motion-fast) ease,
        box-shadow var(--motion-normal) ease,
        color var(--motion-fast) ease,
        opacity var(--motion-fast) ease,
        transform var(--motion-normal) var(--ease-standard);
}

body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button
):hover:not(:disabled) {
    transform: translateY(var(--lift-control));
}

body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button
):active:not(:disabled) {
    transform: translateY(0) scale(var(--press-scale));
    transition-duration: var(--motion-instant);
}

/* Focus ring enters smoothly rather than flashing. */
body .container :where(
    button,
    .button,
    .btn,
    .table-btn,
    .range-btn,
    .data-tab,
    .notification-action-button,
    input,
    select,
    textarea
):focus-visible {
    transition-duration: var(--motion-fast);
}

/* -----------------------------------------------------------------------
   4. Tabs / segmented selection
   ----------------------------------------------------------------------- */
body .container :where(
    .range-btn,
    .data-tab,
    .notification-segmented button,
    .segmented-control button
) {
    position: relative;
    overflow: hidden;
}

body .container :where(
    .range-btn.active,
    .data-tab.active,
    .notification-segmented button.active,
    .segmented-control button.active,
    button[aria-pressed="true"]
) {
    transform: translateY(0);
}

/* Tiny inner highlight makes state changes legible without a moving slider. */
body .container :where(
    .range-btn.active,
    .data-tab.active,
    .notification-segmented button.active,
    .segmented-control button.active
)::after {
    content: "";
    position: absolute;
    inset: 3px;
    border-radius: calc(var(--control-radius) - 4px);
    pointer-events: none;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.52);
    opacity: .72;
}

/* -----------------------------------------------------------------------
   5. Status / pill changes
   ----------------------------------------------------------------------- */
body .container :where(
    .pill,
    .badge,
    .chip,
    .status-pill,
    .state-pill,
    .severity-pill,
    .range-status-chip,
    .result-count-chip
) {
    transition:
        background-color var(--motion-normal) ease,
        border-color var(--motion-normal) ease,
        color var(--motion-normal) ease,
        box-shadow var(--motion-normal) ease,
        opacity var(--motion-fast) ease,
        transform var(--motion-normal) var(--ease-standard);
}

/* -----------------------------------------------------------------------
   6. Table/list interaction
   ----------------------------------------------------------------------- */
body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr {
    transition:
        background-color var(--motion-fast) ease,
        box-shadow var(--motion-fast) ease;
}

body .container :where(
    table,
    .accounts-table,
    .detail-table
) tbody tr:hover {
    box-shadow: inset 3px 0 0 rgba(84,145,101,.14);
}

body .container :where(
    .alert-item,
    .notification-item,
    .activity-item,
    .event-card,
    .rule-template-row,
    .quality-rule,
    .history-item,
    .list-row
) {
    transition:
        background-color var(--motion-fast) ease,
        border-color var(--motion-fast) ease,
        box-shadow var(--motion-normal) ease,
        transform var(--motion-normal) var(--ease-standard);
}

/* -----------------------------------------------------------------------
   7. Dialog / modal entrance
   ----------------------------------------------------------------------- */
@keyframes m321-v38-dialog-enter {
    from {
        opacity: 0;
        transform: translateY(10px) scale(.985);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes m321-v38-backdrop-enter {
    from { opacity: 0; }
    to   { opacity: 1; }
}

body .container :where(
    dialog[open],
    .account-dialog[open],
    .device-dialog[open],
    .notification-dialog[open],
    .restore-dialog[open]
) {
    animation:
        m321-v38-dialog-enter
        var(--motion-slow)
        var(--ease-enter)
        both;
}

body :where(dialog[open])::backdrop {
    animation:
        m321-v38-backdrop-enter
        var(--motion-normal)
        ease
        both;
}

/* Non-dialog modal surfaces used by older pages. */
body .container :where(
    .device-modal.is-open,
    .restore-modal.is-open,
    .notification-modal.is-open,
    .modal.is-open
) > :where(
    .modal-content,
    .modal-card,
    .device-modal-card,
    .restore-modal-card,
    .notification-modal-card
) {
    animation:
        m321-v38-dialog-enter
        var(--motion-slow)
        var(--ease-enter)
        both;
}

/* -----------------------------------------------------------------------
   8. Native disclosure / accordion cues
   ----------------------------------------------------------------------- */
body .container details > summary {
    cursor: pointer;
    transition:
        color var(--motion-fast) ease,
        background-color var(--motion-fast) ease,
        border-color var(--motion-fast) ease;
}

body .container details > summary::marker {
    transition: transform var(--motion-normal) var(--ease-standard);
}

/* Existing sensor-group animation from v33 remains the authoritative
   height animation. We only synchronize the header's material response. */
body .container .trend-sensor-group-head {
    transition:
        background-color var(--motion-fast) ease,
        border-color var(--motion-fast) ease,
        box-shadow var(--motion-normal) ease,
        transform var(--motion-normal) var(--ease-standard);
}

/* -----------------------------------------------------------------------
   9. Message appearance
   ----------------------------------------------------------------------- */
@keyframes m321-v38-message-enter {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

body .container :where(
    .message,
    .accounts-message,
    .notification-message,
    .account-message,
    .form-message,
    .template-message,
    .simple-threshold-message,
    .quality-event-message,
    .toast,
    .flash-message,
    .app-toast
):not(:empty) {
    animation:
        m321-v38-message-enter
        var(--motion-normal)
        var(--ease-enter)
        both;
}

/* -----------------------------------------------------------------------
   10. Accessibility / motion budget
   ----------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    body .container,
    body .container :where(
        dialog[open],
        .account-dialog[open],
        .device-dialog[open],
        .notification-dialog[open],
        .restore-dialog[open],
        .message,
        .accounts-message,
        .notification-message,
        .account-message,
        .form-message,
        .template-message,
        .simple-threshold-message,
        .quality-event-message,
        .toast,
        .flash-message,
        .app-toast
    ):not(:empty) {
        animation: none;
    }

    body :where(dialog[open])::backdrop {
        animation: none;
    }

    body .container :where(
        a.device-card,
        a.quick-link-card,
        button.metric-card,
        button.sensor-card,
        .device-card[role="button"],
        .sensor-card[role="button"],
        .channel-card[role="button"],
        .notification-item[role="button"],
        .activity-item[role="button"],
        .clickable-card,
        .interactive-card,
        button,
        .button,
        .btn,
        .table-btn,
        .range-btn,
        .data-tab,
        input,
        select,
        textarea
    ) {
        transition: none;
        transform: none;
    }
}

/* Touch devices do not need hover lift. */
@media (hover: none) {
    body .container :where(
        a.device-card,
        a.quick-link-card,
        button.metric-card,
        button.sensor-card,
        .device-card[role="button"],
        .sensor-card[role="button"],
        .channel-card[role="button"],
        .notification-item[role="button"],
        .activity-item[role="button"],
        .clickable-card,
        .interactive-card,
        button,
        .button,
        .btn,
        .table-btn,
        .range-btn,
        .data-tab
    ):hover {
        transform: none;
    }
}

/* M3.2.1 · Navigation, page state & visualization polish v39 ------------ */

/* -----------------------------------------------------------------------
   2. Page state: every major page starts with the same visual anchor
   ----------------------------------------------------------------------- */
body .container :where(
    .ui-page-header,
    .dashboard-hero,
    .devices-header,
    .detail-header,
    .notification-hero,
    .operations-hero,
    .data-center-header,
    .settings-header,
    .pending-header,
    .accounts-header,
    .account-header
) {
    position: relative;
}

/* A restrained lower state line ties title/meta/actions together. */
body .container :where(
    .ui-page-header,
    .dashboard-hero,
    .devices-header,
    .detail-header,
    .notification-hero,
    .operations-hero,
    .data-center-header,
    .settings-header,
    .pending-header,
    .accounts-header,
    .account-header
)::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background:
        linear-gradient(
            90deg,
            var(--page-state-accent) 0 52px,
            var(--page-state-line) 52px 58%,
            transparent 92%
        );
    opacity: .78;
    pointer-events: none;
}

/* Status/action area remains visually subordinate to the page title. */
body .container :where(
    .devices-title-actions,
    .detail-header-actions,
    .notification-hero-actions,
    .operations-hero-actions,
    .data-center-header-actions,
    .settings-title-actions,
    .accounts-header-actions,
    .page-header-actions
) {
    align-items: center;
    gap: var(--layout-control-gap);
}

/* -----------------------------------------------------------------------
   3. KPI / status hierarchy
   ----------------------------------------------------------------------- */
body .container :where(
    .summary-card,
    .fleet-summary-card,
    .device-stat-card,
    .settings-overview-card,
    .notification-stat,
    .ops-stat,
    .detail-stat-card,
    .health-metric
) {
    position: relative;
}

/* Large values are easier to scan across overview/detail pages. */
body .container :where(
    .fleet-summary-value,
    .settings-overview-value,
    .detail-stat-value,
    .device-stat-value,
    .notification-stat strong,
    .ops-stat strong,
    .health-metric-value,
    .stat-value,
    .kpi-value
) {
    font-variant-numeric: tabular-nums;
    letter-spacing: -.025em;
    line-height: 1.08;
}

/* -----------------------------------------------------------------------
   4. Chart frames / legend / secondary chart information
   ----------------------------------------------------------------------- */
body .container :where(
    .chart-box,
    .trend-chart,
    .chart-container,
    .chart-frame
) {
    position: relative;
}

/* Canvas receives a calm plotting field without changing chart JS. */
body .container :where(
    .chart-box,
    .trend-chart,
    .chart-container,
    .chart-frame
) canvas {
    border-radius: 12px;
}

/* Known trend chart secondary information. */
body .container .chart-box .trend-marker-legend,
body .container .trend-spotlight-panel .legend-row,
body .container :where(.chart-legend, .legend-row) {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 7px 12px;
    padding: 7px 10px;
    border: 1px solid var(--chart-legend-border);
    border-radius: 10px;
    background: var(--chart-legend-bg);
    color: var(--text-secondary);
    font-size: var(--type-caption);
    line-height: 1.35;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.48);
}

/* Legend swatches, regardless of whether the page uses span/i/b elements. */
body .container :where(
    .trend-marker-legend,
    .legend-row,
    .chart-legend
) :where(
    .legend-dot,
    .legend-swatch,
    i[class*="dot"],
    span[class*="dot"]
) {
    flex: 0 0 auto;
    box-shadow: 0 0 0 2px rgba(255,255,255,.52);
}

/* Chart statistic hierarchy */
body .container .chart-box .trend-stat-label {
    color: var(--text-muted);
    font-size: var(--type-caption);
    font-weight: var(--weight-strong);
}

body .container .chart-box .trend-stat-value {
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-weight: var(--weight-title);
    letter-spacing: -.02em;
}

/* Chart empty state should look intentional, not like a failed canvas. */
body .container :where(
    .chart-empty,
    .chart-placeholder,
    .no-data
) {
    min-height: 150px;
    border: 1px dashed var(--empty-border);
    border-radius: 12px;
    background:
        linear-gradient(
            180deg,
            rgba(255,255,255,.22),
            rgba(255,255,255,.10)
        );
}

/* -----------------------------------------------------------------------
   5. Alert / notification priority
   ----------------------------------------------------------------------- */
body .container :where(
    .alert-item,
    .notification-item,
    .notification-alert-card,
    .event-card
) {
    overflow: hidden;
}

/* Priority is expressed by a narrow edge, not a large saturated card. */
body .container :where(
    .alert-item.critical,
    .notification-item.critical,
    .notification-alert-card.critical,
    .event-card.critical,
    [data-severity="critical"]
)::before {
    content: "";
    position: absolute;
    inset: 10px auto 10px 0;
    width: 3px;
    border-radius: 0 999px 999px 0;
    background: var(--severity-critical-accent);
}

body .container :where(
    .alert-item.warning,
    .notification-item.warning,
    .notification-alert-card.warning,
    .event-card.warning,
    [data-severity="warning"]
)::before {
    content: "";
    position: absolute;
    inset: 10px auto 10px 0;
    width: 3px;
    border-radius: 0 999px 999px 0;
    background: var(--severity-warning-accent);
}

body .container :where(
    .alert-item.info,
    .notification-item.info,
    .notification-alert-card.info,
    .event-card.info,
    [data-severity="info"]
)::before {
    content: "";
    position: absolute;
    inset: 10px auto 10px 0;
    width: 3px;
    border-radius: 0 999px 999px 0;
    background: var(--severity-info-accent);
}

body .container :where(
    .alert-item.resolved,
    .notification-item.resolved,
    .event-card.resolved,
    [data-severity="resolved"]
)::before {
    content: "";
    position: absolute;
    inset: 10px auto 10px 0;
    width: 3px;
    border-radius: 0 999px 999px 0;
    background: var(--severity-success-accent);
}

/* Critical information gets stronger text hierarchy without flooding red. */
body .container :where(
    .alert-item.critical,
    .notification-item.critical,
    .notification-alert-card.critical,
    .event-card.critical,
    [data-severity="critical"]
) :where(
    h3,
    .title,
    .notification-title,
    .alert-title
) {
    font-weight: var(--weight-title);
}

/* -----------------------------------------------------------------------
   6. Live / freshness indicators
   ----------------------------------------------------------------------- */
body .container :where(
    .refresh-chip,
    .live-chip,
    .range-status-chip,
    .device-refresh-chip,
    .detail-live-chip,
    .settings-save-state
) {
    border: 1px solid rgba(91,116,100,.12);
    background: rgba(255,255,255,.34);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.46);
}

/* -----------------------------------------------------------------------
   7. Mobile
   ----------------------------------------------------------------------- */
@media (max-width: 620px) {
    body .container :where(
        .ui-page-header,
        .dashboard-hero,
        .devices-header,
        .detail-header,
        .notification-hero,
        .operations-hero,
        .data-center-header,
        .settings-header,
        .pending-header,
        .accounts-header,
        .account-header
    )::after {
        background:
            linear-gradient(
                90deg,
                var(--page-state-accent) 0 36px,
                var(--page-state-line) 36px 76%,
                transparent 100%
            );
    }

    body .container .chart-box .trend-marker-legend,
    body .container .trend-spotlight-panel .legend-row,
    body .container :where(.chart-legend, .legend-row) {
        padding: 6px 8px;
        gap: 6px 9px;
    }
}

/* M3.2.1 · Core page composition v40 -------------------------------------
 * Page-specific composition without taking ownership of route transitions.
 * No opacity/transform animation is applied to .container or page shells.
 */

/* =======================================================================
   1. Dashboard / overview
   ======================================================================= */

/* Overview numbers form a compact first scan layer. */
body .container .fleet-summary-grid {
    grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
    gap: clamp(10px, 1vw, 14px);
    margin-bottom: clamp(18px, 1.6vw, 24px);
}

body .container :where(
    .fleet-summary-card,
    .summary-card
) {
    min-height: 112px;
    padding: clamp(14px, 1.2vw, 18px);
}

/* Values dominate, metadata recedes. */
body .container .fleet-summary-value {
    margin-top: 5px;
    font-size: clamp(25px, 2vw, 31px);
}

body .container .fleet-summary-meta {
    margin-top: 7px;
}

/* Health is the calm operational surface; attention is the exception layer. */
body .container .overview-health-card {
    background:
        linear-gradient(
            145deg,
            rgba(255,255,255,.64),
            rgba(245,250,246,.42)
        );
}

body .container .overview-attention-panel {
    border-color: rgba(145,112,81,.16);
    background:
        linear-gradient(
            145deg,
            rgba(255,255,255,.68),
            rgba(251,247,241,.40)
        );
}

/* Alerts should have internal separation rather than stacked shadows. */
body .container .overview-attention-panel :where(
    .alert-item,
    .attention-item
) + :where(
    .alert-item,
    .attention-item
) {
    margin-top: 9px;
}

/* =======================================================================
   2. Device detail
   ======================================================================= */

/* Device identity/header is followed by a dense operational snapshot. */
body .container .detail-stat-grid {
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: clamp(10px, 1vw, 14px);
}

body .container .detail-stat-card {
    min-height: 108px;
    padding: clamp(14px, 1.15vw, 17px);
}

body .container .detail-stat-value {
    margin-top: 5px;
    font-size: clamp(24px, 1.85vw, 30px);
}

body .container .detail-stat-sub {
    margin-top: 7px;
}

/* Communication health is visually grouped but not made heavier than
   sensor data. */
body .container .communication-health-grid {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 11px;
}

body .container .health-metric {
    min-height: 94px;
    padding: 14px 15px;
    border-color: rgba(93,121,103,.11);
    background: rgba(255,255,255,.34);
}

body .container .health-metric-value {
    margin-top: 5px;
}

/* Device operations read as controls, not another wall of sensor cards. */
body .container .device-ops-overview {
    background:
        linear-gradient(
            145deg,
            rgba(250,252,250,.66),
            rgba(240,246,242,.44)
        );
}

body .container .device-ops-grid {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}

body .container .device-ops-card {
    min-height: 96px;
    padding: 14px 15px;
}

/* =======================================================================
   3. Notification center
   ======================================================================= */

body .container .notification-stats {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 11px;
    margin-bottom: clamp(18px, 1.5vw, 23px);
}

body .container .notification-stat {
    min-height: 100px;
    padding: 14px 16px;
}

body .container .notification-stat strong {
    display: block;
    margin-top: 6px;
    font-size: clamp(24px, 1.8vw, 29px);
}

/* The focus area should be visibly more important than history/rules,
   without becoming an opaque white slab. */
body .container .notification-focus-card {
    border-color: rgba(132,105,82,.17);
    background:
        linear-gradient(
            145deg,
            rgba(255,255,255,.70),
            rgba(250,246,240,.42)
        );
}

body .container .notification-filter-bar {
    padding: 10px 12px;
    background: rgba(255,255,255,.42);
}

/* Notification rows: more breathing room for title + metadata + actions. */
body .container :where(
    .notification-item,
    .notification-alert-card
) {
    padding: clamp(13px, 1vw, 16px);
}

body .container :where(
    .notification-item,
    .notification-alert-card
) + :where(
    .notification-item,
    .notification-alert-card
) {
    margin-top: 8px;
}

/* History/rule sections intentionally flatter than the focus area. */
body .container :where(
    .notification-panel,
    .simple-threshold-panel,
    .template-panel
) {
    background:
        linear-gradient(
            145deg,
            rgba(255,255,255,.52),
            rgba(248,250,248,.32)
        );
}

/* =======================================================================
   4. Data center
   ======================================================================= */

/* Query workbench is the primary action surface. */
body .container .data-query-workbench {
    padding: clamp(14px, 1.3vw, 18px);
    border-color: rgba(94,128,105,.15);
    background:
        linear-gradient(
            145deg,
            rgba(255,255,255,.66),
            rgba(242,248,244,.42)
        );
}

/* Tabs are a navigation aid, not another panel. */
body .container .data-tabs {
    width: fit-content;
    max-width: 100%;
    margin-bottom: 14px;
    background: rgba(255,255,255,.34);
}

/* Result sections become quieter so the data itself wins. */
body .container .data-section-panel {
    background:
        linear-gradient(
            145deg,
            rgba(255,255,255,.48),
            rgba(248,250,248,.29)
        );
}

/* Table shell is intentionally flatter than the workbench. */
body .container :where(
    .record-table-shell,
    .history-table-shell
) {
    background: rgba(255,255,255,.30);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.50),
        0 2px 8px rgba(36,50,43,.016);
}

/* Result heading gets a stable visual baseline. */
body .container .results-heading {
    padding-bottom: 8px;
    border-bottom: 1px solid rgba(91,116,100,.09);
}

/* Guidance / advanced operations should not compete with normal querying. */
body .container :where(
    .data-guidance,
    .advanced-operations
) {
    border-color: rgba(91,116,100,.10);
    background: rgba(255,255,255,.25);
}

/* =======================================================================
   5. Cross-page composition rules
   ======================================================================= */

/* The first information layer after a page header starts slightly closer,
   while later sections retain the established v34 breathing rhythm. */
body .container :where(
    .dashboard-hero,
    .detail-header,
    .notification-hero,
    .data-center-header
) + :where(
    .fleet-summary-grid,
    .detail-stat-grid,
    .notification-stats,
    .data-tabs,
    .data-query-workbench,
    .panel,
    .detail-panel,
    .notification-panel,
    .data-section-panel
) {
    margin-top: clamp(15px, 1.4vw, 21px);
}

/* Long operational metadata should wrap instead of stretching cards. */
body .container :where(
    .fleet-summary-meta,
    .detail-stat-sub,
    .notification-meta,
    .data-center-header-meta,
    .device-ops-updated
) {
    overflow-wrap: anywhere;
}

/* =======================================================================
   6. Responsive composition
   ======================================================================= */

@media (max-width: 980px) {
    body .container :where(
        .fleet-summary-grid,
        .detail-stat-grid,
        .notification-stats,
        .communication-health-grid
    ) {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    body .container .device-ops-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 620px) {
    body .container :where(
        .fleet-summary-grid,
        .detail-stat-grid,
        .notification-stats,
        .communication-health-grid,
        .device-ops-grid
    ) {
        grid-template-columns: 1fr;
        gap: 9px;
    }

    body .container :where(
        .fleet-summary-card,
        .detail-stat-card,
        .notification-stat,
        .health-metric,
        .device-ops-card
    ) {
        min-height: 0;
    }

    body .container .data-tabs {
        width: 100%;
        overflow-x: auto;
        scrollbar-width: thin;
    }

    body .container .data-query-workbench {
        padding: 12px;
    }
}

/* M3.2.1 · Smooth trend visualization v41 ------------------------------- */

/* Plot area: keep the chart visually quiet so the data line is dominant. */
body .container .trend-card .chart-wrap {
    margin-top: 5px;
    padding-top: 10px;
    border-top-color: rgba(91,116,100,.075);
}

body .container .trend-card .chart-wrap::before {
    content: "";
    position: absolute;
    inset: 10px 0 0 46px;
    border-radius: 12px;
    background:
        linear-gradient(
            180deg,
            rgba(255,255,255,.16),
            rgba(255,255,255,.045)
        );
    pointer-events: none;
}

body .container .trend-card .chart-wrap canvas {
    position: relative;
    z-index: 1;
    cursor: crosshair;
}

/* Tooltip is deliberately crisp rather than heavily blurred: it follows the
   pointer, so a large blur/shadow makes motion feel muddy. */
body .container .trend-card .chart-tooltip {
    min-width: 146px;
    padding: 10px 12px;
    border-color: rgba(88,118,99,.16);
    border-radius: 12px;
    background: rgba(255,255,255,.94);
    backdrop-filter: blur(10px) saturate(1.04);
    box-shadow:
        0 7px 18px rgba(31,54,41,.085),
        inset 0 1px 0 rgba(255,255,255,.72);
    transition: opacity 90ms ease;
}

body .container .trend-card .tooltip-title {
    font-size: 10.5px;
    letter-spacing: .01em;
}

body .container .trend-card .tooltip-value {
    margin-top: 5px;
    font-size: 17px;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}

body .container .trend-card .tooltip-time {
    margin-top: 5px;
    font-size: 10px;
    font-variant-numeric: tabular-nums;
}

/* Stats stay compact and clearly secondary to the line itself. */
body .container .trend-card .trend-stats {
    gap: 7px;
}

body .container .trend-card .trend-stat {
    border-color: rgba(91,116,100,.10);
    background: rgba(255,255,255,.34);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.48);
}

body .container .trend-card .trend-stat-value {
    font-variant-numeric: tabular-nums;
}

/* Alert marker legend is quieter; actual alert markers remain visible. */
body .container .trend-card .trend-marker-legend {
    color: rgba(77,94,83,.66);
}

body .container .trend-card .marker-legend-line {
    border-top-color: rgba(177,67,59,.46);
}

/* A little more chart height on wide screens gives the smooth curve room
   without increasing card density on mobile. */
@media (min-width: 1180px) {
    body .container .trend-card .chart-wrap canvas {
        min-height: 278px;
    }
}

@media (max-width: 620px) {
    body .container .trend-card .chart-wrap::before {
        left: 42px;
    }

    body .container .trend-card .chart-tooltip {
        min-width: 132px;
        padding: 9px 10px;
        backdrop-filter: blur(8px) saturate(1.03);
    }
}

@media (prefers-reduced-motion: reduce) {
    body .container .trend-card .chart-tooltip {
        transition: none;
    }
}



/* M3.2.1 · Trend signal cleanup v42 --------------------------------------
 * Dense sensor streams are rendered as a calm display trend in dashboard.js.
 * These rules remove the redundant in-field device label that could collide
 * with the native select text and clarify raw-vs-trend tooltip values.
 */
body .container .trend-spotlight-panel .device-select-shell::before {
    content: none;
    display: none;
}
body .container .trend-spotlight-panel .device-select-shell::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 15px;
    width: 7px;
    height: 7px;
    border-right: 1.5px solid rgba(65,83,71,.72);
    border-bottom: 1.5px solid rgba(65,83,71,.72);
    transform: translateY(-65%) rotate(45deg);
    pointer-events: none;
}
body .container .trend-spotlight-panel .device-select-shell select {
    width: 100%;
    min-width: 0;
    padding-left: 14px;
    padding-right: 40px;
    appearance: none;
    -webkit-appearance: none;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body .container .trend-card .tooltip-value { margin-top: 6px; }
body .container .trend-card .tooltip-trend {
    margin-top: 3px;
    color: rgba(72,91,79,.72);
    font-size: 10px;
    font-weight: 680;
    font-variant-numeric: tabular-nums;
    line-height: 1.35;
}
body .container .trend-card .tooltip-time {
    padding-top: 5px;
    border-top: 1px solid rgba(88,118,99,.08);
}


/* M3.2.1 · v61 · state-driven save actions ----------------------------- */
body .container :where(
    button.save-state-control,
    .save-state-control.primary-btn,
    .save-state-control.button
):disabled {
    opacity: 1;
    border-color: rgba(143, 163, 149, .24);
    background: rgba(239, 244, 240, .78);
    color: rgba(76, 94, 82, .52);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.64);
    cursor: default;
    transform: none;
}

body .container :where(
    button.save-state-control,
    .save-state-control.primary-btn,
    .save-state-control.button
).is-dirty:not(:disabled) {
    border-color: var(--control-primary-border);
    background: var(--control-primary-bg);
    color: var(--control-primary-fg);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,.18),
        0 3px 9px rgba(35,112,60,.09);
}

body .container :where(
    button.save-state-control,
    .save-state-control.primary-btn,
    .save-state-control.button
).is-dirty:hover:not(:disabled) {
    border-color: var(--control-primary-border-hover);
    background: var(--control-primary-bg-hover);
    color: var(--control-primary-fg);
}

body .container :where(
    button.save-state-control,
    .save-state-control.primary-btn,
    .save-state-control.button
).is-saving:disabled {
    border-color: rgba(91, 139, 103, .22);
    background: rgba(232, 240, 234, .86);
    color: rgba(54, 101, 67, .72);
}
