:root {
    --color-hot: #c62828;
    --color-cold: #1565c0;
    --color-hot-bg: rgba(229, 57, 53, 0.12);
    --color-cold-bg: rgba(30, 136, 229, 0.12);
    --color-hot-border: rgba(229, 57, 53, 0.3);
    --color-cold-border: rgba(30, 136, 229, 0.3);
    --breadcrumb-color: #495866;
    --psychro-color-leaving: #00796b;
    --result-card-text: #fff;
}

/* Mobile list version of the weather-station results. Hidden by default;
   mobile.css swaps which view is visible. */
.station-results-list {
    display: none;
}

/* === Sidebar footer rows ===
   Used by SidebarNav (desktop) and the MobileHomePage nav (which replicates
   the sidebar as the mobile home screen). */
.sidebar-footer {
    margin-top: auto;
    display: flex;
    flex-direction: column;
}

.sidebar-footer-row {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 40px;
    padding: 0 16px;
    gap: 8px;
}

.sidebar-link-primary,
.sidebar-link-secondary,
.sidebar-link-tertiary {
    text-decoration: none;
    font-size: 1rem;
    letter-spacing: 0.03em;
}

.sidebar-link-primary,
.sidebar-link-secondary {
    color: #fff !important;
}

.sidebar-link-primary .mud-icon-root,
.sidebar-link-secondary .mud-icon-root {
    color: #fff !important;
}

.sidebar-link-primary {
    background: color-mix(in srgb, var(--mud-palette-primary) 90%, white);
}

.sidebar-link-secondary {
    background: color-mix(in srgb, var(--mud-palette-secondary) 90%, white);
}

.sidebar-link-tertiary {
    background: color-mix(in srgb, var(--mud-palette-tertiary) 90%, white);
    justify-content: space-evenly;
    padding: 0 !important;
    gap: 0;
}

.sidebar-link-tertiary .mud-icon-button {
    color: #495866 !important;
    padding: 0 !important;
}

.sidebar-footer-copyright {
    min-height: 40px;
}

.sidebar-weather-station {
    background: transparent;
    border: none;
    color: var(--mud-palette-text-secondary);
    text-align: left;
    width: 100%;
    font-size: 0.9rem;
    cursor: pointer;
    font-family: inherit;
    letter-spacing: 0.02em;
    border-top: 1px solid var(--mud-palette-divider);
    border-bottom: 1px solid var(--mud-palette-divider);
}

.sidebar-weather-station:hover {
    background: color-mix(in srgb, var(--mud-palette-action-default) 8%, transparent);
    color: var(--mud-palette-text-primary);
}

.sidebar-weather-station .mud-icon-root {
    color: var(--mud-palette-text-secondary);
    flex-shrink: 0;
}

.sidebar-weather-station:hover .mud-icon-root {
    color: var(--mud-palette-primary);
}

.sidebar-weather-station--set {
    padding: 0;
    gap: 0;
    justify-content: flex-start;
    min-height: 52px;
    align-items: stretch;
}

/* Unset state: draw attention so users know to set their location.
   Both the row background and the icon pulse in sync. */
.sidebar-weather-station--unset {
    color: var(--mud-palette-text-primary);
    font-weight: 500;
    border-top: 1px solid color-mix(in srgb, var(--mud-palette-info) 40%, transparent);
    border-bottom: none;
    animation: sidebar-weather-station-bg-pulse 3s ease-in-out infinite;
}

.sidebar-weather-station--unset:hover {
    color: var(--mud-palette-text-primary);
    animation-play-state: paused;
    background: color-mix(in srgb, var(--mud-palette-info) 22%, transparent);
}

.sidebar-weather-station--unset .mud-icon-root {
    color: var(--mud-palette-info);
    animation: sidebar-weather-station-icon-pulse 3s ease-in-out infinite;
}

.sidebar-weather-station--unset:hover .mud-icon-root {
    color: var(--mud-palette-info);
    animation-play-state: paused;
}

@keyframes sidebar-weather-station-bg-pulse {
    0%, 100% { background: color-mix(in srgb, var(--mud-palette-info) 8%, transparent); }
    50%      { background: color-mix(in srgb, var(--mud-palette-info) 22%, transparent); }
}

@keyframes sidebar-weather-station-icon-pulse {
    0%, 100% { transform: scale(1); opacity: 1; }
    50%      { transform: scale(1.15); opacity: 0.9; }
}

@media (prefers-reduced-motion: reduce) {
    .sidebar-weather-station--unset,
    .sidebar-weather-station--unset .mud-icon-root {
        animation: none;
    }
    .sidebar-weather-station--unset {
        background: color-mix(in srgb, var(--mud-palette-info) 15%, transparent);
    }
}

.sidebar-weather-station-main {
    background: transparent;
    border: none;
    color: inherit;
    text-decoration: none;
    font: inherit;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1 1 auto;
    min-width: 0;
    padding: 6px 8px 6px 16px;
    text-align: left;
}

.sidebar-weather-station-info {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
    line-height: 1.2;
}

.sidebar-weather-station-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--mud-palette-text-secondary);
    opacity: 0.8;
}

.sidebar-weather-station-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
}

.sidebar-weather-station-edit {
    background: transparent;
    border: none;
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    flex-shrink: 0;
}

.sidebar-weather-station-edit:hover {
    color: var(--mud-palette-primary);
}

/* === Page Header (used by PageHeader.razor) === */
.page-header {
    flex-wrap: nowrap !important;
    background: var(--mud-palette-secondary);
    color: #fff;
}

.page-header h1 {
    /* Scale the title down on narrow screens so it stays on one line; ellipsis is the
       last-resort fallback for an unusually long title. Caps at 1.25rem on wide screens. */
    font-size: clamp(0.9rem, 3.2vw, 1.25rem);
    font-weight: 500;
    line-height: 1.35;
    margin: 0;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.page-header h1:focus-visible {
    outline: none;
}

.page-header-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
}

.page-header-subtitle {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: rgba(255, 255, 255, 0.85);
}

/* Right-align trailing actions without a flex-growing spacer, so an empty actions slot
   takes zero width and the title keeps the full row. */
.page-header-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}

/* Drop the subtitle on small screens so the header stays one compact row (the title
   itself scales via clamp() above). */
@media (max-width: 600px) {
    .page-header-subtitle {
        display: none;
    }
}

/* === Card Grids (Home + Category Pages) === */
/* min() keeps the 350px track on roomy viewports but lets it shrink to the container
   once there is less than that to give — a bare minmax(350px, ...) overflows to the
   right on narrow screens (~380px and under, or any width with page zoom / large
   fonts) instead of reflowing. */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(350px, 100%), 1fr));
    gap: 16px;
    padding: 16px;
}

/* Grid and flex children default to min-width:auto, which lets long unbroken content
   push a track wider than its own column. */
.card-grid > * {
    min-width: 0;
}

.card-link {
    text-decoration: none;
    color: inherit;
    display: flex;
}

.card-link > .mud-card {
    flex: 1;
    transition: box-shadow 0.2s ease;
}

.card-grid-header {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

.card-grid-text {
    flex: 1;
    min-width: 0;
}

.card-link:hover > .mud-card {
    box-shadow: var(--card-hover-shadow);
    background-color: var(--card-hover-bg);
}

/* === Favorites === */
/* Wrapper lets the favorite star sit over the card corner without nesting a
   button inside the card's anchor (which would hijack navigation clicks). */
.card-item-wrap {
    position: relative;
    display: flex;
}

.card-item-wrap > .card-link {
    flex: 1;
}

.card-fav-btn {
    position: absolute !important;
    top: 4px;
    right: 4px;
}

/* Keep the title/external icon clear of the overlaid star */
.card-item-wrap.has-fav .card-grid-header {
    padding-right: 28px;
}

.favorites-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 16px 16px 0;
}

.favorites-grid {
    padding-top: 8px;
    padding-bottom: 0;
}

/* Favorites UI renders conditionally once localStorage is read after the circuit
   connects — ease it in instead of flashing. The wrapper grid-row animates 0fr→1fr
   so the height grows to fit content (no hardcoded max-height) while fading in;
   content below slides down smoothly instead of jumping. */
@keyframes favorites-fade-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

@keyframes favorites-expand {
    from { grid-template-rows: 0fr; }
    to   { grid-template-rows: 1fr; }
}

.favorites-reveal {
    display: grid;
    animation: favorites-expand 0.35s ease-out,
               favorites-fade-in 0.35s ease-out;
}

.favorites-reveal > * {
    overflow: hidden;
    min-height: 0;
}

/* === Tool Page === */

.tool-detail-row {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    margin-bottom: 12px;
}

.tool-detail-row .detail-icon {
    color: var(--mud-palette-info);
    margin-top: 2px;
    flex-shrink: 0;
}

/* The label+content column beside the icon. A flex item's automatic minimum size is its
   min-content width, so without this the column refuses to shrink and the whole row —
   variables grid, tables, everything in the details card — hangs off the right edge of a
   narrow card. This was the actual cause of the tool-page spill, not the grid inside it. */
.tool-detail-row > div {
    min-width: 0;
}

.tool-detail-row .detail-label {
    display: block;
}

.tool-detail-row .detail-value {
    display: block;
    font-size: 14px;
    padding-right: 16px;
    color: var(--mud-palette-text-primary);
}

.variables-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 6px 16px;
    margin-top: 4px;
    padding-left: 16px;
    align-items: baseline;
}

.variable-name {
}

.meta-label {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--mud-palette-text-secondary);
}
.meta-label--bold {
    font-weight: 600;
}

.variable-def {
    font-size: 13px;
    color: var(--mud-palette-text-primary);
}

/* Phone-width: the term/definition pair stacks, name above its own definition.
   Two columns can't survive here — the name column's max-content ("TARGET SPACE DB TEMP /
   HUMIDITY") plus the definition's min-content is wider than the card, and squeezing both
   shreds the name one word per line. minmax(0, 1fr) so a long unbroken token can't
   re-inflate the track. Only the web app renders this section (MobileToolPage has no
   details card), so in practice this is the mobile-web layout. */
@media (max-width: 600px) {
    .variables-list {
        grid-template-columns: minmax(0, 1fr);
        gap: 2px;
        padding-left: 0;
        align-items: start;
    }

    /* Separate one pair from the next, never a name from its own definition — so this
       skips the very first name. */
    .variables-list > .meta-label:not(:first-child) {
        margin-top: 14px;
    }

    .variables-list > .variable-def {
        overflow-wrap: break-word;
    }
}

.calculator-layout {
    display: flex;
    gap: 32px;
    align-items: flex-start;
}

.calculator-results-panel {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 16px;
    min-width: min(var(--results-panel-min-width, 255px), 100%);
    align-items: stretch;
    align-content: stretch;
    flex: 1;
    align-self: stretch;
}

.calculator-results-panel--stacked {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 16px;
}

/* === Calculator === */
.calculator-form {
    display: flex;
    flex-direction: column;
    gap: 24px;
    flex: 1 0 50%;
    min-width: 0;
}

.calculator-form-paired {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 24px 12px;
}

/* Two-up on roomy containers, one-up when the container is narrower than a column.
   `min(<floor>, 100%)` — never a bare px floor: a flex item whose min-width exceeds its
   container cannot shrink, so it spills out of the card and clips its helper text. That
   is what broke every config-driven calculator on narrow/zoomed web windows; the MAUI app
   never showed it because mobile.css already forces min-width: 0 here. 100% resolves
   against the flex container's content box, so the clamp follows the card, not the
   viewport, and needs no breakpoint. Same pattern as the .card-grid minmax() fix.
   Apply it to every fixed min-width below that sits inside a calculator card. */
.calculator-form-paired > * {
    flex: 1 1 calc(50% - 6px);
    min-width: min(300px, 100%);
}

.section-label {
    margin: 4px 0 -16px 0;
    font-size: 13px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--mud-palette-text-secondary);
    border-bottom: 1px solid var(--mud-palette-divider);
    padding-bottom: 6px;
}

.section-label:first-child {
    margin-top: 0;
}

.field-hint-row {
    display: flex;
    align-items: center;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin-top: 3px;
    padding-left: 14px;
}

/* === Result Display === */
.result-display {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px 32px;
    background: var(--mud-palette-background);
    border-radius: 8px;
    border: 1px solid var(--mud-palette-info);
    text-align: center;
    flex: 1 1 calc(50% - 8px);
    min-width: 150px;
}

.result-label {
}

.result-value {
    font-size: 24px;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
}

.result-display.highlight .result-value {
    color: var(--mud-palette-text-primary);
}

/* Grouped result card (CalcResult.Group): several label/value rows in one card. The row that
   governs (CalcResult.HighlightWhen) gets the success tint; colours are mixed from the
   palette variables so light and dark mode both work without a theme class. */
.result-display--group {
    gap: 14px;
}

/* Beside the form (the two-column layout, above the 768px stack breakpoint) grouped cards
   stack one per row: two side by side there are tall, thin slivers stretched to the form's
   height. Once the panel drops under the form it is wide and short, so they sit in a row. */
@media (min-width: 769px) {
    .result-display--group {
        flex-basis: 100%;
    }
}

.result-row {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.result-display--group.highlight {
    border-color: var(--mud-palette-success);
    background: color-mix(in srgb, var(--mud-palette-success) 12%, var(--mud-palette-background));
}

.result-display--group .result-row.is-governing .meta-label,
.result-display--group .result-row.is-governing .result-value {
    color: color-mix(in srgb, var(--mud-palette-success) 70%, var(--mud-palette-text-primary));
}

.result-display--group .result-row.is-governing .result-value {
    font-weight: 700;
}

.calculator-results-panel > .result-note,
.calculator-results-panel > .result-footnote {
    flex: 1 1 100%;
    align-self: flex-start;
}

/* Asterisked caption under the result cards — same mark as the Fan Affinity Laws footnote,
   but full-strength text: it states the answer rather than annotating it. */
.result-footnote {
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--mud-palette-text-primary);
}

.result-asterisk {
    color: var(--mud-palette-primary);
    font-weight: 700;
}

.result-value .result-asterisk {
    margin-left: 2px;
}

.results {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
}

/* === Explain Tooltip Icon === */
.explain-icon {
    font-size: 16px !important;
    width: 16px !important;
    height: 16px !important;
    margin-left: 4px;
    cursor: help;
    color: var(--mud-palette-text-secondary);
    vertical-align: middle;
}

/* === Elevation Lookup Adornment === */
.elevation-lookup-field .mud-input-adornment-end {
    cursor: pointer;
}

/* === Select dropdown arrow: keep it out of hit testing === */
/* MudBlazor renders MudSelect's arrow as a decorative <svg> carrying BOTH aria-hidden="true"
   and tabindex="-1". tabindex="-1" is click-focusable, so clicking the arrow focuses an
   aria-hidden element and Chrome logs "Blocked aria-hidden on an element because its
   descendant retained focus". Dropping the icon from hit testing sends the click to its
   ancestor div.mud-select, which is where MudBlazor's own open/close handler lives, and
   leaves focus to the real combobox — the sibling div.mud-input-slot[tabindex="0"].

   pointer-events: none is MudBlazor's own remedy for inert adornments: it ships
   .mud-input-adornment-disable-pointerevents with exactly this declaration and just never
   applies it to the select arrow. Not fixable by upgrading — 9.10.0's ARIA work (#13772,
   #13785) does not touch icon tabindex.

   Clickable adornments are untouched. With OnAdornmentClick set, MudBlazor renders a real
   <button class="mud-input-adornment-icon-button"> whose inner svg carries neither
   .mud-input-adornment-icon nor a tabindex, so the elevation-lookup search button above
   still gets its clicks. MudBlazor declares no rule of its own for .mud-input-adornment-icon,
   so this needs no !important despite MudBlazor being linked after us (see the app.css
   header for that load order). */
.mud-select .mud-input-adornment-icon {
    pointer-events: none;
}

/* === Utility Classes === */

/* 1. Card with info border */
.info-card { border: 1px solid var(--mud-palette-info); }

/* 2. Card icon (primary color, 2.5rem) */
.card-icon { color: var(--mud-palette-primary); font-size: 2.75rem !important; }

/* 3. Card title */
.card-title { font-weight: 500 !important; line-height: 1.3 !important; align-self: baseline !important; margin-bottom: 4px !important; }

/* 4. Muted text */
.text-muted { opacity: 0.6; }

/* 5. External link indicator */
.text-faint { opacity: 0.3; }

/* 10. Close button positioning */
.close-btn-float { position: absolute !important; top: 8px; right: 8px; opacity: 0.5; }

/* 11. Card content relative */
.card-content-relative { position: relative !important; }

/* 12. Show details button */
.btn-show-details { text-transform: none !important; opacity: 0.6; margin-top: 8px !important; }

/* 13. No padding card content */
.card-content-flush { padding: 0 !important; }

/* 14. Dialog icon vertical align */
.icon-valign { vertical-align: middle; }

/* === Cooling Load Calculator === */
.cooling-load-layout .calculator-form-paired > * {
    flex: 1 1 calc(33.333% - 8px);
    min-width: min(200px, 100%);
}

.cooling-load-layout .section-label--spaced,
.psych-chart-results .section-label--spaced {
    margin-top: 40px !important;
}

/* Grid instead of flex-wrap so the value tiles align on both edges (uniform columns)
   rather than sizing to their text. Rows pack to the top; the column count adapts to
   the panel width. */
.cooling-load-layout .calculator-results-panel,
.psych-chart-results .calculator-results-panel {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    align-content: start;
}

/* Non-tile children (headers, hints, placeholders, errors, footnotes) span all columns. */
.cooling-load-layout .calculator-results-panel .section-label,
.psych-chart-results .calculator-results-panel .section-label,
.cooling-load-layout .calculator-results-panel .psych-edit-hint,
.psych-chart-results .calculator-results-panel .psych-edit-hint,
.cooling-load-layout .calculator-results-panel .psych-results-placeholder,
.psych-chart-results .calculator-results-panel .psych-results-placeholder,
.cooling-load-layout .calculator-results-panel .psych-side-error,
.psych-chart-results .calculator-results-panel .psych-side-error,
.cooling-load-layout .calculator-results-panel .psych-reheat-note,
.psych-chart-results .calculator-results-panel .psych-reheat-note {
    grid-column: 1 / -1;
}

/* Section headers sized up to match the tile values — they were half the size. */
.cooling-load-layout .calculator-results-panel .section-label,
.psych-chart-results .calculator-results-panel .section-label {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
}

.psych-chart-results-card {
    border: 1px solid var(--mud-palette-info);
    height: 100%;
    display: flex;
    flex-direction: column;
}

.psych-chart-results-card > .mud-card-content {
    flex: 1;
}

.psych-chip-edit-dialog .mud-dialog-content {
    padding: 8px !important;
}

/* === Psychrometric Chart Layout === */
.psychro-hover-tooltip {
    position: absolute;
    background: var(--mud-palette-info);
    color: var(--mud-palette-info-text);
    border-radius: 6px;
    padding: 6px 14px;
    font-size: 14px;
    pointer-events: none;
    display: flex;
    gap: 16px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

.psychro-layout {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Read-only inputs summary shown only when printing (see @media print). */
.psychro-print-inputs {
    display: none;
}

.psychro-chart {
    width: 100%;
    min-width: 0;
}

.psychrometric-chart-svg {
    width: 100%;
    display: block;
    cursor: crosshair;
    border: 1px solid var(--mud-palette-info);
    border-radius: 4px;
}

/* The chart-picker dialog's chart box. Must be positioned: both the hover tooltip
   and the fullscreen button are absolutely placed against it, and without this they
   fall back to .mud-dialog-content (which scrolls, and is the wrong origin). */
.picker-chart-wrapper {
    position: relative;
}

/* ── Fullscreen chart button (mobile / narrow only) ── */
/* MudBlazor's .mud-button-root rules load AFTER shared.css (see App.razor) and set
   position/display on the button, so the positioning + desktop-hide here must be
   !important to win the cascade and float over the chart instead of taking layout space. */
.psychro-fullscreen-btn {
    position: absolute !important;
    right: 10px !important;
    bottom: 10px !important;
    z-index: 3;
    background: var(--mud-palette-surface) !important;
    opacity: 0.9;
    border: 1px solid var(--mud-palette-divider) !important;
}
@media (min-width: 960px) {
    .psychro-fullscreen-btn { display: none !important; }   /* desktop already has room */
}

/* ── Fullscreen overlay ── */
.psychro-fs-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: var(--mud-palette-surface);
    padding: env(safe-area-inset-top) env(safe-area-inset-right)
             env(safe-area-inset-bottom) env(safe-area-inset-left);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

/* Also a MudIconButton — needs !important positioning to escape the overlay's
   centered flex flow and pin to the viewport corner (see note above). */
.psychro-fs-close {
    position: fixed !important;
    top: calc(8px + env(safe-area-inset-top)) !important;
    right: calc(8px + env(safe-area-inset-right)) !important;
    z-index: 2002;
    background: var(--mud-palette-surface) !important;
    opacity: 0.9;
}

.psychro-fs-readout {
    position: fixed;
    top: calc(8px + env(safe-area-inset-top));
    left: calc(8px + env(safe-area-inset-left));
    z-index: 2002;
    display: flex;
    gap: 10px;
    padding: 6px 10px;
    border-radius: 6px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-divider);
    font-size: 13px;
    white-space: nowrap;
}

/* The chart wrapper fills the viewport; rotation depends on DOM orientation. */
.psychro-fs-chart {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Make the component root + SVG fill the rotated box; meet-fit avoids clipping. */
.psychro-fs-chart > div {
    width: 100%;
    height: 100%;
}
/* Full drag-read in fullscreen (no page to scroll here); flatten the SVG's own border. */
.psychro-fs-chart .psychrometric-chart-svg {
    touch-action: none;
    border: none;
    width: 100%;
    height: 100%;
}

/* Portrait DOM: rotate the wide chart to fill the tall screen. Turning the phone
   sideways -> upright & huge. Works with OS rotation lock ON (DOM stays portrait ->
   we rotate) or OFF (landscape rule below un-rotates). */
@media (orientation: portrait) {
    .psychro-fs-chart {
        width: 100vh;
        height: 100vw;
        transform: rotate(90deg);
    }
}
/* Landscape DOM (rotation lock OFF, browser reflowed): no rotation needed. */
@media (orientation: landscape) {
    .psychro-fs-chart {
        width: 100vw;
        height: 100vh;
        transform: none;
    }
}

/* === Airflow Comparison calculator layout === */

.airflow-comparison-layout .calculator-results-panel {
    min-width: 500px;
}

.airflow-comparison-layout .comparison-note,
.airflow-comparison-layout .sweep-caption,
.airflow-comparison-layout .empty-state {
    margin: 0.5rem 0;
}

.airflow-comparison-layout .sweep-block {
    margin-top: 1rem;
}

@media (max-width: 1500px) {
    .calculator-layout.airflow-comparison-layout {
        flex-direction: column;
    }
    .calculator-layout.airflow-comparison-layout > .mud-divider {
        display: none;
    }
    /* Once stacked, both panes should span the full container width instead of
       keeping their side-by-side column widths. */
    .airflow-comparison-layout .calculator-form,
    .airflow-comparison-layout .calculator-results-panel {
        min-width: 0;
        max-width: 100%;
        flex-basis: auto;
        width: 100%;
    }
}

.cooling-condition-section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    width: 100%;
    border-bottom: 1px solid var(--mud-palette-divider);
    margin: 4px 0 -16px 0;
    padding-bottom: 4px;
}

.cooling-condition-section-title {
    font-size: 13px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--mud-palette-text-secondary);
    flex: 1 1 auto;
    min-width: 0;
}

/* Soft discharge warning rendered between the Dry Bulb and Known Property fields. */
.cooling-condition-warning {
    display: block;
    margin: 4px 0 -8px 0;
    line-height: 1.3;
}

.psychro-sidebar {
    width: 100%;
}

/* 6. Psychrometric result chip */
/* Outlined like .result-display on the other calculators (info border, page background,
   normal text colors) — the old solid info fill couldn't hold contrast in dark mode.
   Same padding/radius as before so the tiles keep their size. */
.psychro-result-chip {
    background: var(--mud-palette-background) !important;
    color: var(--mud-palette-text-primary) !important;
    border: 1px solid var(--mud-palette-info);
    padding: 4px 10px;
    border-radius: 4px;
}
.psychro-result-chip--selectable { cursor: pointer; }
.psychro-result-chip--selectable:hover { background: var(--mud-palette-action-default-hover) !important; }

/* 10. Process line leaving marker */
.psychro-leaving-marker { fill: var(--psychro-color-leaving); stroke: white; stroke-width: 1.5; }

/* 11. Process line section labels */
.psychro-process-label { display: block; }
.psychro-process-label--leaving { color: var(--psychro-color-leaving); }
.psychro-process-header { display: flex; justify-content: space-between; align-items: center; }

/* 7. Psychrometric result caption */
.psychro-result-caption { color: var(--mud-palette-text-secondary); }

/* 8. Psychrometric result value */
.psychro-result-value { font-weight: 600; }

/* 9. Result unit span */
.psychro-result-unit { font-size: 0.65em; font-weight: 400; opacity: 0.85; }

/* === Detail tables === */
.table-wrapper {
    border: 1px solid var(--mud-palette-divider);
    border-radius: 8px;
    overflow-x: auto;
}

/* Chrome-less sibling of .table-wrapper, for tables that already draw their own cell
   borders (.rtu-table, .cost-summary-table) and so must not gain a second outline.
   A raw <table> is at least as wide as the sum of its columns' min-content, which on a
   phone-width card exceeds the card — it then spills out the right edge instead of
   scrolling. Every raw <table> belongs in one of these two wrappers. */
.table-scroll {
    overflow-x: auto;
    /* Without this the scroller inherits the table's min-content width from any flex or
       grid ancestor and spills anyway, scrollbar and all. */
    min-width: 0;
    max-width: 100%;
}

.detail-table {
    width: 100%;
    border-collapse: collapse;
    white-space: nowrap;
    font-size: 13px;
}

.detail-table th,
.detail-table td {
    padding: 8px 12px;
    text-align: center;
    border: 1px solid var(--mud-palette-divider);
}

.detail-table thead th {
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
}

.detail-table tbody td {
    color: var(--mud-palette-text-primary);
}

.detail-table .row-label {
    text-align: center;
    font-weight: 600;
    color: var(--mud-palette-text-secondary);
}

.monthly-table td,
.monthly-table th {
    min-width: 52px;
}

/* === Weather Station === */
.search-container {
    max-width: 900px;
}

.detail-container {
    padding: 32px;
    display: flex;
    flex-direction: column;
    gap: 32px;
}

.detail-section {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.detail-section-title {
    font-size: 18px;
    font-weight: 500;
    margin: 0;
    color: var(--mud-palette-text-primary);
}

.detail-section-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.data-groups {
    display: flex;
    justify-content: space-between;
    gap: 48px;
    flex-wrap: wrap;
}

.data-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.data-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 24px 48px;
}

.data-card {
    display: flex;
    flex-direction: column;
}

.data-card .data-label {
}

.data-card .data-value {
    font-size: 20px;
    font-weight: 500;
    margin: 2px 0;
    color: var(--mud-palette-text-primary);
}

.data-card .data-sublabel {
    font-size: 11px;
    color: var(--mud-palette-text-disabled);
}

.data-card.accent-hot .data-value {
    color: var(--color-hot);
}

.data-card.accent-cold .data-value {
    color: var(--color-cold);
}

.col-hot {
    background-color: var(--color-hot-bg);
}

.col-cold {
    background-color: var(--color-cold-bg);
}

thead .col-hot {
    color: var(--color-hot);
    font-weight: 600;
}

thead .col-cold {
    color: var(--color-cold);
    font-weight: 600;
}

/* Legend */
.table-legend {
    display: flex;
    gap: 16px;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 6px;
}

.legend-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 2px;
}

.legend-hot .legend-swatch {
    background-color: var(--color-hot-bg);
    border: 1px solid var(--color-hot-border);
}

.legend-cold .legend-swatch {
    background-color: var(--color-cold-bg);
    border: 1px solid var(--color-cold-border);
}

/* === Calculator layout divider === */
.calculator-layout > .mud-divider-vertical {
    border-color: var(--mud-palette-info) !important;
}

/* === Responsive === */
@media (min-width: 1600px) {
    .psychro-layout {
        flex-direction: row;
        gap: 24px;
    }

    .psychro-chart {
        flex: 3;
        min-width: 0;
    }

    .psychro-sidebar {
        flex: 1;
    }

    .psychro-sidebar .psychro-results > .mud-paper {
        width: 100%;
    }
}

@media (min-width: 1920px) {
    .psychro-sidebar .psychro-results > .mud-paper {
        width: calc(50% - 6px);
    }
}

@media (min-width: 2560px) {
    .psychro-sidebar .psychro-results > .mud-paper {
        width: calc(33.33% - 8px);
    }
}

@media (max-width: 960px) {
    .card-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 768px) {
    .calculator-layout {
        flex-direction: column;
    }
    .calculator-layout > .mud-divider-vertical {
        display: none;
    }
    .calculator-form {
        max-width: 100%;
        flex-basis: auto;
        width: 100%;
    }
    .calculator-results-panel {
        width: 100%;
        position: static;
    }
}

@media (max-width: 600px) {
    .result-display {
        width: 100%;
        min-width: unset;
    }
    .results {
        grid-template-columns: 1fr;
    }
}

/* === Expandable Section ===
   Animates open/close of info cards and their "Show..." button rows.
   Pair two siblings with opposite data-show values to cross-fade. */
.expandable-section {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    visibility: hidden;
    /* No transition by default — only active under body[data-ui-ready]. */
}

.expandable-section[data-show="true"] {
    grid-template-rows: 1fr;
    opacity: 1;
    visibility: visible;
}

/* === Required Airflow Calculator — RTU/Paragon output sheet ===
   Ported from the Load Calculator's rtu-comparison component. Kept global (this app
   does not bundle component-scoped .razor.css) and namespaced under .rtu-comparison. */

.rtu-comparison {
    display: block;
}

/* Tables */
.rtu-comparison .rtu-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 0.75rem;
}

.rtu-comparison .rtu-table th,
.rtu-comparison .rtu-table td {
    padding: 0.5rem;
    border: 1px solid var(--mud-palette-divider);
    text-align: center;
    font-size: 12px;
    line-height: 16px;
    color: var(--mud-palette-text-primary);
}

.rtu-comparison .rtu-table th {
    font-weight: 500;
    background-color: var(--mud-palette-background-grey);
}

.rtu-comparison .rtu-table .name-cell {
    text-align: left;
}

.rtu-comparison .rtu-table .unit-label {
    font-size: 0.8em;
    color: var(--mud-palette-text-secondary);
}

.rtu-comparison .overage-pct {
    font-size: 0.8em;
    color: var(--mud-palette-error);
    margin-left: 0.4rem;
    white-space: nowrap;
}

.rtu-comparison .na-value {
    color: var(--mud-palette-error);
    font-weight: 600;
}

/* Captions */
.rtu-comparison .rtu-caption {
    font-size: 0.8rem;
    font-style: italic;
    color: var(--mud-palette-text-secondary);
    margin: 0 0 0.75rem;
    padding: 0 1.5rem;
    line-height: 1.4;
}

.rtu-comparison .rtu-caption::before {
    content: "* ";
    color: var(--mud-palette-error);
    font-weight: bold;
    font-style: normal;
}

.rtu-comparison .chart-section-title {
    text-align: center;
    font-size: 1.1rem;
    padding-bottom: 0.75rem;
    margin-top: 1.5rem;
    color: var(--mud-palette-text-primary);
}

/* Charts */
.rtu-comparison .rtu-chart {
    width: 100%;
    margin: 0.5rem 0 1rem;
}

.rtu-comparison .rtu-chart-svg {
    width: 100%;
    height: 280px;
    display: block;
}

.rtu-comparison .chart-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary);
}

.rtu-comparison .chart-legend .legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.rtu-comparison .legend-line {
    display: inline-block;
    width: 18px;
    height: 3px;
    border-radius: 2px;
}

.rtu-comparison .legend-dash {
    -webkit-mask: repeating-linear-gradient(90deg, #000 0 5px, transparent 5px 9px);
    mask: repeating-linear-gradient(90deg, #000 0 5px, transparent 5px 9px);
}

.rtu-comparison .legend-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

/* Blower savings cards */
.rtu-comparison .blower-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin: 0.5rem 0 0.6rem;
}

.rtu-comparison .blower-card {
    flex: 1 1 0;
    min-width: min(130px, 100%);
    padding: 1rem 1.1rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 12px;
    background: var(--mud-palette-surface);
    text-align: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.rtu-comparison .blower-card .card-label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

.rtu-comparison .blower-card .card-value {
    margin: 0.3rem 0 0.2rem;
    font-size: 2rem;
    font-weight: 800;
    line-height: 1.05;
    color: var(--mud-palette-text-primary);
}

.rtu-comparison .blower-card .card-sub {
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
    line-height: 1.3;
}

.rtu-comparison .blower-card.is-highlight {
    border: 1px solid #b7e0c6;
    background: #eef9f2;
}

.rtu-comparison .blower-card.is-highlight .card-label {
    color: #2e8b57;
}

.rtu-comparison .blower-card.is-highlight .card-value {
    color: #1e7d46;
}

/* The highlight card has a fixed light-green background, so its sub-label must use a
   fixed dark colour too — otherwise it inherits the theme's (light) secondary text
   colour and disappears on the green in dark mode. */
.rtu-comparison .blower-card.is-highlight .card-sub {
    color: rgba(0, 0, 0, 0.55);
}

/* Dark mode: the light-green highlight card looks harsh on a dark surface. Give it a
   dark green-tinted background with lighter green text instead. */
.rtu-comparison.rtu-dark .blower-card.is-highlight {
    background: color-mix(in srgb, var(--mud-palette-success) 14%, var(--mud-palette-surface));
    border-color: color-mix(in srgb, var(--mud-palette-success) 45%, transparent);
}

.rtu-comparison.rtu-dark .blower-card.is-highlight .card-label {
    color: color-mix(in srgb, var(--mud-palette-success) 75%, #fff);
}

.rtu-comparison.rtu-dark .blower-card.is-highlight .card-value {
    color: color-mix(in srgb, var(--mud-palette-success) 60%, #fff);
}

.rtu-comparison.rtu-dark .blower-card.is-highlight .card-sub {
    color: var(--mud-palette-text-secondary);
}

/* RTU Applied Capacity readout colours by % band: red when undersized (negative), orange
   when more than 5% oversized. The acceptable 0–5% band carries no extra class and keeps the
   base .blower-card look (white box / black text in light + print). Dark-mode + print
   variants follow the .is-highlight pattern. */
.rtu-comparison .blower-card.applied-cap--neg {
    border: 1px solid #f3c0bb;
    background: #fdecea;
}
.rtu-comparison .blower-card.applied-cap--neg .card-label { color: #c0392b; }
.rtu-comparison .blower-card.applied-cap--neg .card-value { color: #b71c1c; }
.rtu-comparison .blower-card.applied-cap--neg .card-sub   { color: rgba(0, 0, 0, 0.55); }

.rtu-comparison .blower-card.applied-cap--over {
    border: 1px solid #ffd9a8;
    background: #fff4e5;
}
.rtu-comparison .blower-card.applied-cap--over .card-label { color: #b35f00; }
.rtu-comparison .blower-card.applied-cap--over .card-value { color: #a85400; }
.rtu-comparison .blower-card.applied-cap--over .card-sub   { color: rgba(0, 0, 0, 0.55); }

.rtu-comparison.rtu-dark .blower-card.applied-cap--neg {
    background: color-mix(in srgb, var(--mud-palette-error) 14%, var(--mud-palette-surface));
    border-color: color-mix(in srgb, var(--mud-palette-error) 45%, transparent);
}
.rtu-comparison.rtu-dark .blower-card.applied-cap--neg .card-label { color: color-mix(in srgb, var(--mud-palette-error) 78%, #fff); }
.rtu-comparison.rtu-dark .blower-card.applied-cap--neg .card-value { color: color-mix(in srgb, var(--mud-palette-error) 62%, #fff); }
.rtu-comparison.rtu-dark .blower-card.applied-cap--neg .card-sub   { color: var(--mud-palette-text-secondary); }

.rtu-comparison.rtu-dark .blower-card.applied-cap--over {
    background: color-mix(in srgb, var(--mud-palette-warning) 16%, var(--mud-palette-surface));
    border-color: color-mix(in srgb, var(--mud-palette-warning) 45%, transparent);
}
.rtu-comparison.rtu-dark .blower-card.applied-cap--over .card-label { color: color-mix(in srgb, var(--mud-palette-warning) 80%, #fff); }
.rtu-comparison.rtu-dark .blower-card.applied-cap--over .card-value { color: color-mix(in srgb, var(--mud-palette-warning) 65%, #fff); }
.rtu-comparison.rtu-dark .blower-card.applied-cap--over .card-sub   { color: var(--mud-palette-text-secondary); }

/* Required-airflow driver tint on the comparison table: blue = sensible-driven CFM,
   green = latent-driven. Matches the legend swatches below the table. */
.rtu-comparison .rtu-table td.cfm-sensible {
    background: #e8f1fb;
    color: #1f5fa6;
    font-weight: 700;
}
/* .savings-row tr shares the green treatment for the bottom savings row of each cost
   section (whole row, name cell included; its .unit-label inherits the green too). */
.rtu-comparison .rtu-table td.cfm-latent,
.rtu-comparison .rtu-table tr.savings-row td {
    background: #eef9f2;
    color: #1e7d46;
    font-weight: 700;
}

.rtu-comparison .rtu-table tr.savings-row .unit-label {
    color: inherit;
    opacity: 0.7;
}

/* Labels on the green rows read in the normal text colour; only the value is green. */
.rtu-comparison .rtu-table tr.savings-row td.name-cell {
    color: var(--mud-palette-text-primary);
}

/* No divider between the label and its value on the green rows — they read as one strip. */
.rtu-comparison .rtu-table tr.savings-row td.name-cell {
    border-right: none;
}

.rtu-comparison .rtu-table tr.savings-row td.name-cell + td {
    border-left: none;
}
.rtu-comparison.rtu-dark .rtu-table td.cfm-sensible {
    background: color-mix(in srgb, #3f86d6 22%, var(--mud-palette-surface));
    color: color-mix(in srgb, #3f86d6 65%, #fff);
}
.rtu-comparison.rtu-dark .rtu-table td.cfm-latent,
.rtu-comparison.rtu-dark .rtu-table tr.savings-row td {
    background: color-mix(in srgb, var(--mud-palette-success) 18%, var(--mud-palette-surface));
    color: color-mix(in srgb, var(--mud-palette-success) 62%, #fff);
}

.rtu-comparison.rtu-dark .rtu-table tr.savings-row td.name-cell {
    color: var(--mud-palette-text-primary);
}

/* Compact legend under the comparison table explaining the driver tints. */
.rtu-comparison .cfm-driver-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
    margin: 0 0 0.75rem;
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
}
.rtu-comparison .cfm-driver-legend .legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.rtu-comparison .cfm-driver-legend .legend-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
}
.rtu-comparison .cfm-driver-legend .cfm-sensible-swatch { background: #2f6fb3; }
.rtu-comparison .cfm-driver-legend .cfm-latent-swatch   { background: #2e8b57; }

.rtu-comparison .blower-basis {
    font-size: 0.75rem;
    font-style: italic;
    text-align: center;
    color: var(--mud-palette-text-secondary);
    margin: 0 0 1rem;
    line-height: 1.4;
}

/* Input-form divider above the "RTU Spec/RTU Replacement Comparison Tool" section,
   delineating it from the Airflow Design inputs above. Clearly visible (lines-inputs)
   and theme-aware. */
.airflow-comparison-layout .calculator-form .form-section-divider {
    border-top: 2px solid var(--mud-palette-lines-inputs);
    margin: 1.5rem 0 1.25rem;
}

/* RTU Spec / RTU Replacement applied-capacity block — spaced from the Modern HVAC
   output above it. No divider line (the section is delineated by its own header). */
.rtu-comparison .rtu-applied-section {
    margin-top: 1.25rem;
}

.rtu-comparison .applied-note {
    margin: 0.5rem 0 0;
    font-size: 0.8rem;
    font-weight: 600;
    line-height: 1.4;
    text-align: center;
    color: var(--mud-palette-text-primary);
}

.rtu-comparison .applied-note--undersized {
    color: var(--mud-palette-error);
}

/* The all-N/A dehumidification warning leads the asterisked caption block, so it needs
   its own bottom gap (the base .applied-note has none — it normally hugs the cards above). */
.rtu-comparison .applied-note--spaced {
    margin-bottom: 1rem;
}

/* The in-sheet section label (e.g. "Required Airflow vs. Unit Discharge Temperature")
   normally has a negative bottom margin to pull form inputs up; here a chart follows,
   so give it a little breathing room instead. */
.rtu-comparison .section-label {
    margin-bottom: 0.75rem;
}

/* Results header: the first section label plus a right-aligned print icon, sharing
   one row. Mirrors the .section-label look but carries the underline on the row. */
.results-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border-bottom: 1px solid var(--mud-palette-divider);
    padding-bottom: 6px;
    margin: 0 0 4px 0;
}

.results-header-title {
    font-size: 13px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--mud-palette-text-secondary);
}

/* The optional project name on the printed header row (print-only). Kept full-strength
   black rather than secondary grey so it reads as the sheet's label, not a caption. */
.results-header-name {
    color: var(--mud-palette-text-primary);
    font-weight: 600;
}

.results-header .results-print-btn {
    flex: 0 0 auto;
    color: var(--mud-palette-text-secondary);
}

/* === Cost Analysis (optional Required-Airflow second section) === */

/* Form: checkbox-gated sub-sections. */
.cost-hint {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin: 0 0 0.75rem 0;
}

/* Single shared efficiency-metric selector row (EER / IEER / SEER), indented to line up
   with the sub-section's inputs. */
.cost-metric-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0 0.75rem;
    padding-left: 2rem;
    margin: 0.5rem 0 0.25rem;
}

.cost-metric-label {
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
}

.cost-metric-radios {
    display: flex;
    flex-wrap: wrap;
    gap: 0 0.25rem;
}

/* Closing "Additional Long Term Savings" bullet list. */
.rtu-comparison .cost-longterm-list {
    margin: 0.25rem 0 0;
    padding-left: 1.5rem;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--mud-palette-text-primary);
}

.rtu-comparison .cost-longterm-list li {
    margin-bottom: 0.15rem;
}

/* Header delineating the cost section from the airflow outputs. */
.rtu-comparison .cost-ownership-header {
    font-size: 1rem;
    font-weight: 500;
    text-align: center;
    color: var(--mud-palette-text-primary);
    padding-bottom: 6px;
    margin: 0 0 0.75rem;
    border-bottom: 2px solid var(--mud-palette-divider);
}

.cost-hint--indent {
    margin-left: 2rem;
}

.cost-subsection {
    margin-top: 0.5rem;
}

/* MudCheckBox's root (.mud-input-control) is a column flex container whose default
   align-items:stretch makes the <label> span the whole row, so a click far to the right
   of the text still toggles. Shrink the label to its content. */
.cost-subsection .mud-input-control-boolean-input .mud-checkbox {
    align-self: flex-start;
}

/* Indent a sub-section's inputs so they sit under the checkbox label, not flush left
   with the checkbox itself. Matches the .cost-hint--indent used by the Duct note. */
.cost-subsection .calculator-form-paired {
    padding-left: 2rem;
}

/* The 2rem indent eats into the row width; drop the per-field min-width by more than
   that so a pair still fits two-up wherever it did before the indent. */
.cost-subsection .calculator-form-paired > * {
    min-width: min(260px, 100%);
}

/* Cost Analysis accordion header: keeps the .section-label look, lays the title and a
   collapse caret on one row, and reads as clickable. */
.cost-analysis-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    cursor: pointer;
    user-select: none;
}

.cost-analysis-caret {
    color: var(--mud-palette-text-secondary);
    flex: 0 0 auto;
    transition: transform 250ms ease;
}

.cost-analysis-caret.is-open {
    transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .cost-analysis-caret {
        transition: none;
    }
}

/* Output: second results section, printed on its own page. */
.cost-analysis-page {
    break-before: page;
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 2px solid var(--mud-palette-divider);
}

.cost-analysis-title {
    font-size: 15px;
}

.cost-block {
    margin-bottom: 1.25rem;
}

/* Total Estimated Savings: one summary line per enabled sub-section (duct listed as a
   one-time %, excluded from the total) above a heavy Total Annual Savings row. Fixed
   light-green like .is-highlight, so text colours are fixed-dark; the .rtu-dark variants
   below swap to the success-tinted dark treatment the highlight cards use. */
.cost-analysis-page .cost-summary-card {
    border: 2px solid #8fd0a8;
    border-radius: 12px;
    background: #eef9f2;
    padding: 0.8rem 1.25rem 0.9rem;
}

.cost-analysis-page .cost-summary-table {
    width: 100%;
    border-collapse: collapse;
}

.cost-analysis-page .cost-summary-table th {
    padding: 0 0 0.3rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    text-align: right;
    color: rgba(0, 0, 0, 0.72);
}

.cost-analysis-page .cost-summary-table td {
    padding: 0.28rem 0;
    font-size: 0.9rem;
    color: rgba(0, 0, 0, 0.72);
}

.cost-analysis-page .cost-summary-table td:not(:first-child) {
    padding-left: 1.5rem;
    text-align: right;
    font-weight: 700;
    color: #1e7d46;
    white-space: nowrap;
}

/* Fixed grey dividers — the theme divider (12% black) vanishes on the green card. */
.cost-analysis-page .cost-summary-table tbody tr + tr td {
    border-top: 1px solid rgba(0, 0, 0, 0.22);
}

.cost-analysis-page .cost-summary-table .cost-summary-total-row td {
    border-top: 2px solid rgba(0, 0, 0, 0.22);
    padding-top: 0.45rem;
    font-weight: 800;
}

.cost-analysis-page .cost-summary-table .cost-summary-total-row td:first-child {
    font-size: 0.78rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.cost-analysis-page .cost-summary-table .cost-summary-total-row td:not(:first-child) {
    font-size: 1.35rem;
    line-height: 1.1;
}

.rtu-comparison.rtu-dark .cost-summary-card {
    background: color-mix(in srgb, var(--mud-palette-success) 14%, var(--mud-palette-surface));
    border-color: color-mix(in srgb, var(--mud-palette-success) 55%, transparent);
}

.rtu-comparison.rtu-dark .cost-summary-table td {
    color: var(--mud-palette-text-primary);
}

.rtu-comparison.rtu-dark .cost-summary-table td:not(:first-child) {
    color: color-mix(in srgb, var(--mud-palette-success) 60%, #fff);
}

.rtu-comparison.rtu-dark .cost-summary-table th {
    color: var(--mud-palette-text-primary);
}

.rtu-comparison.rtu-dark .cost-summary-table tbody tr + tr td,
.rtu-comparison.rtu-dark .cost-summary-table .cost-summary-total-row td {
    border-top-color: rgba(255, 255, 255, 0.25);
}

/* Breathing room between the summary card and its inflation note. */
.cost-analysis-page .cost-summary-block .rtu-caption {
    margin-top: 0.6rem;
}

/* Consecutive assumption notes under one table read as a tight pair, not a list. */
.cost-analysis-page .rtu-caption + .rtu-caption {
    margin-top: -0.55rem;
}

/* Page-wide estimate disclaimer at the very bottom of the cost page: the preceding
   cost-block's own bottom margin supplies the gap. */
.cost-analysis-page .cost-disclaimer {
    margin-top: 0;
}

.cost-analysis-page .cost-total-row td {
    font-weight: 600;
    border-top: 2px solid var(--mud-palette-divider);
}

.cost-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding: 6px 0;
    font-size: 14px;
}

.cost-line-value {
    font-weight: 600;
}

/* === Print: Required Airflow Calculator — results only ===
   Scoped with :has() so ONLY this page is affected; every other page prints normally.
   Tuned to fit the whole report on a single page (Load Calculator parity). */
/* Counterpart to .no-print: content that belongs only on the printed sheet. Hidden on
   screen, revealed by the @media print rule below. */
.print-only {
    display: none;
}

@media print {
    @page {
        margin: 0.4in;
    }

    .no-print {
        display: none !important;
    }

    .print-only {
        display: revert !important;
    }

    body:has(.airflow-comparison-layout) * {
        visibility: hidden;
    }

    /* Scoped to the panel INSIDE the calculator: the Related Calculators column in the
       description card reuses .calculator-results-panel for layout, and an unscoped
       selector made it print as a white box over the page-1 report. */
    body:has(.airflow-comparison-layout) .airflow-comparison-layout .calculator-results-panel,
    body:has(.airflow-comparison-layout) .airflow-comparison-layout .calculator-results-panel * {
        visibility: visible;
    }

    body:has(.airflow-comparison-layout) .airflow-comparison-layout .calculator-results-panel {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        margin: 0;
        padding: 0;
        background: #fff !important;   /* clean white report — drop the grey panel */
        box-shadow: none !important;

        /* Force background colours to render in the PDF. Browsers strip backgrounds
           when printing unless this opts in; without it the legend swatches, the
           blue/green driver-tinted table cells, and the colour summary cards all wash
           out (the swatches are pure background, so they vanish entirely). Inherited,
           so setting it on the panel covers every descendant. */
        print-color-adjust: exact;
        -webkit-print-color-adjust: exact;

        /* Force light-theme palette so printing from dark mode comes out readable.
           The SVG charts bake in var(--mud-palette-*), so overriding the variables
           here fixes chart text/gridlines, tables, and captions all at once. */
        --mud-palette-text-primary: rgba(0, 0, 0, 0.87);
        --mud-palette-text-secondary: rgba(0, 0, 0, 0.54);
        --mud-palette-divider: rgba(0, 0, 0, 0.12);
        --mud-palette-lines-default: rgba(0, 0, 0, 0.12);
        --mud-palette-background-grey: #f5f5f5;
        --mud-palette-surface: #ffffff;
        --mud-palette-error: #f44336;
        color: rgba(0, 0, 0, 0.87) !important;
    }

    /* Pin both cards to their light appearance regardless of the dark-mode overrides. */
    body:has(.airflow-comparison-layout) .blower-card {
        background: #fff !important;
        border-color: #e2e8f0 !important;
    }
    body:has(.airflow-comparison-layout) .blower-card.is-highlight {
        background: #eef9f2 !important;
        border-color: #b7e0c6 !important;
    }
    body:has(.airflow-comparison-layout) .blower-card.is-highlight .card-label {
        color: #2e8b57 !important;
    }
    body:has(.airflow-comparison-layout) .blower-card.is-highlight .card-value {
        color: #1e7d46 !important;
    }
    body:has(.airflow-comparison-layout) .blower-card.is-highlight .card-sub {
        color: rgba(0, 0, 0, 0.55) !important;
    }

    /* Pin the applied-capacity colour states + driver tints to their light appearance
       so they print correctly from dark mode (overrides both screen and .rtu-dark rules). */
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--neg {
        background: #fdecea !important;
        border-color: #f3c0bb !important;
    }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--neg .card-label { color: #c0392b !important; }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--neg .card-value { color: #b71c1c !important; }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--neg .card-sub   { color: rgba(0, 0, 0, 0.55) !important; }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--over {
        background: #fff4e5 !important;
        border-color: #ffd9a8 !important;
    }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--over .card-label { color: #b35f00 !important; }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--over .card-value { color: #a85400 !important; }
    body:has(.airflow-comparison-layout) .blower-card.applied-cap--over .card-sub   { color: rgba(0, 0, 0, 0.55) !important; }
    body:has(.airflow-comparison-layout) .rtu-table td.cfm-sensible {
        background: #e8f1fb !important;
        color: #1f5fa6 !important;
    }
    body:has(.airflow-comparison-layout) .rtu-table td.cfm-latent,
    body:has(.airflow-comparison-layout) .rtu-table tr.savings-row td {
        background: #eef9f2 !important;
        color: #1e7d46 !important;
    }
    body:has(.airflow-comparison-layout) .rtu-table tr.savings-row td.name-cell {
        color: rgba(0, 0, 0, 0.87) !important;
    }
    body:has(.airflow-comparison-layout) .cfm-driver-legend .cfm-sensible-swatch { background: #2f6fb3 !important; }
    body:has(.airflow-comparison-layout) .cfm-driver-legend .cfm-latent-swatch   { background: #2e8b57 !important; }

    /* Compress vertical rhythm so it fits one page. The SVG charts scale with their
       CSS height (unlike a Chart.js canvas), so shrink them here. */
    body:has(.airflow-comparison-layout) .rtu-chart-svg {
        height: 185px;
    }
    body:has(.airflow-comparison-layout) .rtu-chart {
        margin: 0.15rem 0 0.4rem;
    }
    body:has(.airflow-comparison-layout) .chart-legend {
        margin-top: 0.15rem;
    }
    body:has(.airflow-comparison-layout) .blower-cards {
        margin: 0.25rem 0 0.3rem;
    }
    body:has(.airflow-comparison-layout) .blower-card {
        padding: 0.5rem 0.8rem;
        box-shadow: none !important;
    }
    body:has(.airflow-comparison-layout) .blower-card .card-value {
        font-size: 1.5rem;
    }
    body:has(.airflow-comparison-layout) .blower-basis {
        margin: 0 0 0.4rem;
    }
    body:has(.airflow-comparison-layout) .rtu-table {
        margin-bottom: 0.4rem;
    }
    /* Tighten cell vertical padding so the single-line rows don't push the
       report onto a second page. Horizontal padding is kept for legibility. */
    body:has(.airflow-comparison-layout) .rtu-table th,
    body:has(.airflow-comparison-layout) .rtu-table td {
        padding: 0.2rem 0.5rem;
    }
    body:has(.airflow-comparison-layout) .rtu-caption {
        margin-bottom: 0.3rem;
        font-size: 0.72rem;
    }
    body:has(.airflow-comparison-layout) .rtu-comparison .section-label,
    body:has(.airflow-comparison-layout) .results-header {
        margin-top: 0.35rem;
        padding-bottom: 4px;
    }

    /* Cost of Ownership Analysis: extra breathing room below the section header and above
       each comparison table so they don't crowd the header / savings cards in print — but
       kept just tight enough (with slimmer between-block margins) that the page doesn't
       spill onto a second sheet now that the belt table + modeled-inputs note exist. */
    body:has(.airflow-comparison-layout) .cost-ownership-header {
        margin-bottom: 1.1rem;
    }
    body:has(.airflow-comparison-layout) .cost-analysis-page .rtu-compare-table {
        margin-top: calc(0.75rem - 3px);
    }
    body:has(.airflow-comparison-layout) .cost-analysis-page .cost-block {
        margin-bottom: 1rem;
    }
    /* Tighten the long-term-savings bullets — the last few px that keep the page on one sheet. */
    body:has(.airflow-comparison-layout) .cost-longterm-list {
        line-height: 1.35;
    }
    body:has(.airflow-comparison-layout) .cost-longterm-list li {
        margin-bottom: 0;
    }

    /* Total Estimated Savings: pin the light-green treatment (as with .is-highlight above)
       and compress it a touch so the summary + disclaimer keep the page on one sheet. */
    body:has(.airflow-comparison-layout) .cost-summary-card {
        background: #eef9f2 !important;
        border-color: #8fd0a8 !important;
        padding: 0.5rem 1rem 0.6rem;
    }
    body:has(.airflow-comparison-layout) .cost-summary-table td {
        color: rgba(0, 0, 0, 0.72) !important;
        padding-top: 0.2rem;
        padding-bottom: 0.2rem;
    }
    body:has(.airflow-comparison-layout) .cost-summary-table td:not(:first-child) {
        color: #1e7d46 !important;
    }
    body:has(.airflow-comparison-layout) .cost-summary-table th {
        color: rgba(0, 0, 0, 0.72) !important;
    }
    body:has(.airflow-comparison-layout) .cost-summary-table tbody tr + tr td,
    body:has(.airflow-comparison-layout) .cost-summary-table .cost-summary-total-row td {
        border-top-color: rgba(0, 0, 0, 0.22) !important;
    }
    body:has(.airflow-comparison-layout) .cost-summary-table .cost-summary-total-row td:not(:first-child) {
        font-size: 1.2rem;
    }

    /* Match the gap above the two in-sheet section headers ("Required Airflow vs. Unit
       Discharge Temperature" and "RTU Spec / RTU Replacement Comparison"): give both the
       same top margin, and strip the screen-only divider + padding the applied-capacity
       block carries so its header doesn't float far below the discharge-temp notes. */
    body:has(.airflow-comparison-layout) .rtu-comparison .section-label--spaced {
        margin-top: 1.1rem;
    }
    body:has(.airflow-comparison-layout) .rtu-comparison .rtu-applied-section {
        margin-top: 0;
        padding-top: 0;
        border-top: none;
    }

    /* Remove page chrome and container outlines that otherwise print as a left edge
       line (fixed drawer) and a thick bottom bar (dark app bar / wrapping card). */
    body:has(.airflow-comparison-layout) .mud-appbar,
    body:has(.airflow-comparison-layout) .mud-drawer,
    body:has(.airflow-comparison-layout) .mud-drawer-overlay,
    body:has(.airflow-comparison-layout) .mud-overlay,
    body:has(.airflow-comparison-layout) .breadcrumb-bar,
    body:has(.airflow-comparison-layout) .mud-breadcrumbs {
        display: none !important;
    }

    body:has(.airflow-comparison-layout) .mud-paper,
    body:has(.airflow-comparison-layout) .mud-card,
    body:has(.airflow-comparison-layout) .mud-main-content,
    body:has(.airflow-comparison-layout) main,
    body:has(.airflow-comparison-layout) .layout-content {
        border: none !important;
        box-shadow: none !important;
        background: transparent !important;
    }

    /* The lines were the page/layout background (grey in light, near-black in dark)
       printing in the margins around the absolutely-positioned report. Force white. */
    html:has(.airflow-comparison-layout),
    body:has(.airflow-comparison-layout),
    body:has(.airflow-comparison-layout) .mud-layout {
        background: #ffffff !important;
    }

    /* Cost Analysis prints as its own page after the airflow report. Drop the screen-only
       top divider/spacing so the new page starts clean. */
    body:has(.airflow-comparison-layout) .cost-analysis-page {
        break-before: page;
        margin-top: 0;
        padding-top: 0;
        border-top: none;
    }

    /* ============================================================
       Psychrometric Chart print report (body:has(.psychro-print-page))
       Goal: one clean portrait page — chart on top, results + read-only
       inputs below — in light-mode colors regardless of screen theme.
       ============================================================ */

    /* Force the light palette so the chart's baked-in var(--mud-palette-*)
       gridlines/labels, the coloured load chips, and all text print readable
       even from dark mode. print-color-adjust keeps browsers from stripping
       backgrounds (chip colours are backgrounds). Inherited to all descendants. */
    body:has(.psychro-print-page) .psychro-print-page {
        print-color-adjust: exact;
        -webkit-print-color-adjust: exact;
        --mud-palette-text-primary: rgba(0, 0, 0, 0.87);
        --mud-palette-text-secondary: rgba(0, 0, 0, 0.54);
        --mud-palette-divider: rgba(0, 0, 0, 0.12);
        --mud-palette-lines-default: rgba(0, 0, 0, 0.12);
        --mud-palette-background-grey: #f5f5f5;
        --mud-palette-surface: #ffffff;
        --mud-palette-error: #f44336;
        color: rgba(0, 0, 0, 0.87) !important;
    }

    /* Force white page/layout background so no dark theme bleeds into margins. */
    html:has(.psychro-print-page),
    body:has(.psychro-print-page),
    body:has(.psychro-print-page) .mud-layout {
        background: #ffffff !important;
    }

    /* Remove app chrome that would otherwise print as edge lines / bars, plus the
       teal page-header toolbar and the "Show details" toggle button row. */
    body:has(.psychro-print-page) .mud-appbar,
    body:has(.psychro-print-page) .mud-drawer,
    body:has(.psychro-print-page) .mud-drawer-overlay,
    body:has(.psychro-print-page) .mud-overlay,
    body:has(.psychro-print-page) .breadcrumb-bar,
    body:has(.psychro-print-page) .mud-breadcrumbs,
    body:has(.psychro-print-page) .page-header,
    body:has(.psychro-print-page) .details-button-row {
        display: none !important;
    }

    /* Drop help/marketing text (both info cards), the weather-station banner, and
       the interactive input card — the inputs print via the read-only summary. */
    body:has(.psychro-print-page) .oa-station-cta,
    body:has(.psychro-print-page) .info-card,
    body:has(.psychro-print-page) .psychro-top-card {
        display: none !important;
    }

    /* Hide interactive-only affordances inside the results panel + the live
       hover tooltip so they never appear on paper. */
    body:has(.psychro-print-page) .psych-clear-btn,
    body:has(.psychro-print-page) .psych-edit-hint,
    body:has(.psychro-print-page) .psychro-hover-tooltip {
        display: none !important;
    }

    /* Show the read-only inputs summary (hidden on screen). */
    body:has(.psychro-print-page) .psychro-print-inputs {
        display: flex;
        gap: 24px;
        flex-wrap: wrap;
        padding: 0 16px;
        margin: 0 0 12px;
        font-size: 0.9rem;
    }

    /* Strip card chrome so the report is flat white. */
    body:has(.psychro-print-page) .mud-paper,
    body:has(.psychro-print-page) .mud-card,
    body:has(.psychro-print-page) .mud-main-content,
    body:has(.psychro-print-page) main,
    body:has(.psychro-print-page) .layout-content {
        border: none !important;
        box-shadow: none !important;
        background: transparent !important;
    }

    /* Kill the app-shell scroll container (was printing a scrollbar and clipping
       content to one screen) and the top padding the main content reserves for the
       now-hidden app bar (was pushing the report far down the page). */
    html:has(.psychro-print-page),
    body:has(.psychro-print-page),
    body:has(.psychro-print-page) .mud-layout,
    body:has(.psychro-print-page) .mud-main-content,
    body:has(.psychro-print-page) main,
    body:has(.psychro-print-page) .layout-content {
        overflow: visible !important;
        height: auto !important;
        min-height: 0 !important;
        max-height: none !important;
        padding-top: 0 !important;
        margin-top: 0 !important;
    }

    /* Result chips render white text on a var(--mud-palette-info) background; the
       card-chrome reset above strips that background, leaving white-on-white. Give
       them a light report style with dark text (accent swatches keep their colour). */
    body:has(.psychro-print-page) .psychro-result-chip {
        background: #f5f5f5 !important;
        color: rgba(0, 0, 0, 0.87) !important;
        border: 1px solid rgba(0, 0, 0, 0.15) !important;
        box-shadow: none !important;
    }
    body:has(.psychro-print-page) .psychro-result-caption {
        color: rgba(0, 0, 0, 0.6) !important;
    }

    /* Force chart-on-top / results-below on one column, overriding the >=1600px
       side-by-side rule so it prints the same at any browser width. */
    body:has(.psychro-print-page) .psychro-layout {
        flex-direction: column !important;
        gap: 12px;
    }

    /* Neutralise the scroll container that clips the chart top on screen, so the
       whole chart renders, and cap its height so the results still fit page 1.
       max-width override lets the chart use the full page width in print. */
    body:has(.psychro-print-page) .psychro-chart {
        max-width: 100% !important;
        overflow: visible !important;
        height: auto !important;
    }
    body:has(.psychro-print-page) .psychrometric-chart-svg {
        /* 4.7in fit before the results grid gained larger headers; 4.2in keeps
           chart + loads + both condition blocks on one portrait page. */
        max-height: 4.2in;
        height: auto;
        width: 100%;
        border-color: rgba(0, 0, 0, 0.2) !important;
    }

    /* ---- Compaction: tighten vertical rhythm so chart + loads + BOTH condition
       blocks fit one portrait page. ---- */

    /* The screen keeps a 40px gap above each "…Conditions" heading; too much on paper. */
    body:has(.psychro-print-page) .section-label--spaced {
        margin-top: 14px !important;
    }

    /* Trim card padding around the results panel. */
    body:has(.psychro-print-page) .psych-chart-results-card > .mud-card-content,
    body:has(.psychro-print-page) .mud-card-content {
        padding: 8px 12px !important;
    }

    /* Slightly denser chips + tighter grid gaps between them. */
    body:has(.psychro-print-page) .psychro-result-chip {
        padding: 3px 8px !important;
    }
    body:has(.psychro-print-page) .calculator-results-panel {
        gap: 8px !important;
    }

    /* Shrink the reheat footnote's whitespace. */
    body:has(.psychro-print-page) .calculator-results-panel .section-label {
        margin: 0 !important;
    }
}

body[data-ui-ready] .expandable-section {
    transition: grid-template-rows 250ms ease, opacity 250ms ease, visibility 0ms 250ms;
}

body[data-ui-ready] .expandable-section[data-show="true"] {
    transition: grid-template-rows 250ms ease, opacity 250ms ease, visibility 0ms 0ms;
}

.expandable-section__inner {
    overflow: hidden;
    min-height: 0;
}

@media (prefers-reduced-motion: reduce) {
    body[data-ui-ready] .expandable-section,
    body[data-ui-ready] .expandable-section[data-show="true"] {
        transition: none;
    }
}

.details-button-row {
    display: flex;
    justify-content: flex-end;
    padding: 4px 16px;
}

/* === Outdoor Air calculator layout === */
.oa-outdoor-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    margin-top: 8px;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.oa-outdoor-title {
    font-size: 13px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--mud-palette-text-secondary);
    flex: 1 1 auto;
    min-width: 0;
}

/* Both chip strips are grids rather than flex rows. 1fr columns give every chip in a row
   the same width and the default stretch gives them the same height, so a short "Pressure"
   tile can no longer end up half the width of the "Summer Wet Bulb" beside it. auto-fit
   re-flows 2 -> 3 -> 4 columns as the results panel widens instead of leaving a ragged
   trailing row. 140px is the narrowest a chip can be and still fit its value line (value
   and percentile designation side by side); min(..., 100%) keeps the track from spilling a
   card narrower than one chip. */
.oa-summary-chips,
.oa-result-chips {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
    gap: 8px;
    align-items: stretch;
}

.oa-summary-chips {
    margin: 0 0 12px 0;
}

/* Past phone width the design-condition chips stop growing. They are reference values
   sitting beside the inputs, not results — stretched across a wide form they read as the
   calculator's primary output. A fixed track keeps them uniform and left-aligned; only
   .oa-result-chips keeps its 1fr tracks and fills the results panel. Below this they do
   fill the row, because at phone width there is no spare space to leave and two ragged
   half-width tiles is the thing being fixed. */
@media (min-width: 600px) {
    .oa-summary-chips {
        grid-template-columns: repeat(auto-fill, 150px);
        justify-content: start;
    }
}

.oa-result-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: stretch;
}

.oa-result-group > .section-label {
    margin-bottom: 0;
}

/* space-between, not center: the caption pins to the top and the value line to the bottom,
   so value lines stay on one baseline across a row even when one caption wraps to two
   lines and its neighbour's does not. */
.oa-result-chips .psychro-result-chip,
.oa-summary-chips .psychro-result-chip {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 2px;
    min-width: 0;
}

.oa-chip-value-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.75rem;
    width: 100%;
}

.oa-chip-designation {
    font-size: 0.7em;
    font-weight: 400;
    opacity: 0.75;
    white-space: nowrap;
    flex-shrink: 0;
}

.oa-station-cta {
    margin: 0 0 12px 0;
    align-items: center;
}

.oa-station-cta .mud-alert-message {
    width: 100%;
    flex: 1 1 auto;
    align-self: center;
}

.oa-station-cta .mud-alert-icon {
    align-self: center;
}

.oa-station-cta-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Small gap so a wrapped button sits close under the text (not a 1rem
       vertical gap). With space-between, inline spacing is unaffected. */
    gap: 0.25rem;
    width: 100%;
    flex-wrap: wrap;
}

.oa-chip {
    min-width: 0;
}

/* === Psychrometric chart process loads (top inputs row) === */
.psychro-top-inputs {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px;
}

@media (min-width: 600px) {
    .psychro-top-inputs {
        gap: 16px;
    }

    .psychro-top-inputs > .mud-input-control {
        flex: 1;
        min-width: 180px;
    }
}

.psychro-process-loads {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 8px;
    flex-wrap: wrap;
}

.psychro-results {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* === Field hint row (for NumericInputField with Hint + Explain) === */
.field-hint-row {
    display: flex;
    align-items: center;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin-top: 3px;
    padding-left: 14px;
}

.field-hint-row .explain-icon {
    margin-left: 6px;
    opacity: 0.5;
}

.explain-icon-wrap {
    display: inline-flex;
    align-items: center;
    cursor: help;
    user-select: none;
    padding: 2px;
}

.field-explain-inline {
    position: relative;
    font-size: 12px;
    line-height: 1.4;
    color: var(--mud-palette-text-secondary);
    margin-top: 4px;
    padding: 8px 36px 8px 12px;
    background: color-mix(in srgb, var(--mud-palette-info) 6%, transparent);
    border-left: 2px solid var(--mud-palette-info);
    border-radius: 0 4px 4px 0;
}

.field-explain-text {
    display: block;
}

.field-explain-close {
    position: absolute !important;
    top: 2px;
    right: 2px;
    opacity: 0.45;
}

.field-explain-close:hover {
    opacity: 0.85;
}


.detail-value--multiline {
    white-space: pre-line;
}

.description-body {
    line-height: 1.7;
    white-space: pre-line;
}

.related-card-row {
    display: flex;
    gap: 12px;
    align-items: center;
}

/* === Psych results panel: section heads, edit hint, per-side Clear === */
.psych-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.psych-clear-btn {
    min-width: 0;
}

.psych-edit-hint {
    flex-basis: 100%;
    width: 100%;
    font-size: 0.75rem;
    color: var(--mud-palette-text-secondary);
    /* Negative margins offset the results grid's 16px row gap on both sides:
       ~5px below the title divider, ~8px above the tiles. */
    margin: -11px 0 -8px;
}

.psych-side-error {
    flex-basis: 100%;
    width: 100%;
    display: block;
    margin-top: 4px;
}

/* === Fan Affinity Law Calculator === */
/* One grid drives the whole table so a property's baseline and final inputs always share a
   row box. Cells hold nothing variable-height, so entering values can never knock the two
   columns out of alignment. */
.fan-law-grid {
    display: grid;
    grid-template-columns: minmax(130px, auto) 1fr 1fr minmax(76px, auto);
    gap: 16px 12px;
    align-items: center;
}

/* Inputs pin to the top of their row rather than centring in it, so that a validation
   message under one field grows its own cell without shifting the field opposite. The
   label and comparison cells still centre against the input. */
.fan-law-cell {
    align-self: start;
}

.fan-law-head {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
}

.fan-law-head--pct {
    text-align: right;
}

.fan-law-row-label {
    font-weight: 600;
    line-height: 1.25;
}

.fan-law-unit {
    margin-left: 6px;
    font-size: 0.8em;
    font-weight: 400;
    color: var(--mud-palette-text-secondary);
}

.fan-law-pct {
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--mud-palette-text-secondary);
}

/* Reset on the left, footnote pushed to the right edge of the same row. margin-left:auto
   rather than space-between so Reset stays put when there is no footnote to show. */
.fan-law-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 16px;
}

.fan-law-footnote {
    margin-left: auto;
    text-align: right;
    font-size: 0.78rem;
    line-height: 1.4;
    color: var(--mud-palette-text-secondary);
}

.fan-law-asterisk {
    color: var(--mud-palette-primary);
    font-weight: 700;
}

/* Narrow screens: keep the two input columns paired under their headers, and let the
   property label and its comparison span the full width above and below them. */
@media (max-width: 720px) {
    .fan-law-grid {
        grid-template-columns: 1fr 1fr;
        gap: 4px 12px;
    }

    .fan-law-head--spacer,
    .fan-law-head--pct {
        display: none;
    }

    .fan-law-row-label {
        grid-column: 1 / -1;
        margin-top: 14px;
    }

    .fan-law-pct {
        grid-column: 1 / -1;
    }
}

