/* ============================================================
   Calculators hub + Psychrometric calculator
   ------------------------------------------------------------
   Two views share this sheet:
     .calc-*  the Calculators landing page (card grid)
     .psy-*   the Psychrometric calculator (form panel + chart)
   The SVG chart is styled here too (.psy-chart and its curve
   classes) so the drawing code sets geometry only.
   ============================================================ */

/* ---------- Landing page ---------- */

.calc-page {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
    padding: var(--space-lg) var(--space-xl);
}

.calc-title {
    font-size: var(--font-size-xxl);
    color: var(--color-text);
    margin: 0 0 var(--space-xs) 0;
}

.calc-sub {
    color: var(--color-text-muted);
    font-size: var(--font-size-base);
    max-width: 800px;
}

.calc-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 380px));
    gap: var(--space-lg);
}

.calc-card {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
    text-align: left;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    box-shadow: var(--shadow-sm);
    transition: transform var(--transition-fast),
                box-shadow var(--transition-fast),
                border-color var(--transition-fast);
}

.calc-card:hover {
    transform: translateY(-2px);
    border-color: var(--color-primary-light);
    box-shadow: var(--shadow-md);
}

.calc-card:active {
    transform: translateY(0) scale(0.99);
}

.calc-card-icon {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    background: linear-gradient(135deg, var(--color-primary) 0%, #0d3a5a 100%);
    color: var(--color-text-inverse);
    font-size: 24px;
}

.calc-card-name {
    font-size: var(--font-size-lg);
    font-weight: 600;
    color: var(--color-text);
    margin: 0 0 var(--space-xs) 0;
}

.calc-card-desc {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

.calc-empty {
    color: var(--color-text-muted);
    font-style: italic;
}

/* ---------- Psychrometric page layout ---------- */

/* Fixed-height page like Design Search: the form panel scrolls on
   its own and the chart takes whatever height remains. */
.psy-page {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: var(--space-md) var(--space-xl);
    gap: var(--space-md);
    overflow: hidden;
    min-height: 0;
}

.psy-topbar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-lg);
    flex-wrap: wrap;
    flex-shrink: 0;
}

.psy-topbar-links {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    align-self: flex-start;
}

.psy-ext-link {
    text-decoration: none;
    white-space: nowrap;
}

.psy-ext-link svg {
    width: 14px;
    height: 14px;
}

.psy-title {
    font-size: var(--font-size-xl);
    color: var(--color-text);
    margin: 0 0 2px 0;
}

.psy-sub {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    max-width: 760px;
}

.psy-settings {
    flex-shrink: 0;
    background-color: var(--color-bg-dark);
    border-bottom: 1px solid var(--color-border);
}

.psy-altitude {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md) var(--space-xs);
}

.psy-pressure {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    white-space: nowrap;
    padding-left: var(--space-sm);
    border-left: 1px solid var(--color-border);
}

.psy-work {
    flex: 1;
    display: flex;
    gap: var(--space-md);
    min-height: 0;
    overflow: hidden;
}

@media (max-width: 1000px) {
    .psy-page {
        overflow: auto;
    }
    .psy-work {
        flex-direction: column;
        overflow: visible;
    }
    .psy-panel {
        width: auto !important;
        max-height: none !important;
    }
    .psy-chart-wrap {
        min-height: 420px;
    }
}

/* ---------- Left panel ---------- */

.psy-panel {
    width: 500px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.psy-tabs {
    display: flex;
    flex-shrink: 0;
    border-bottom: 1px solid var(--color-border);
    background-color: var(--color-bg-dark);
}

.psy-tab {
    flex: 1;
    padding: 10px var(--space-md);
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--color-text-muted);
    border-bottom: 2px solid transparent;
    transition: color var(--transition-fast),
                border-color var(--transition-fast),
                background-color var(--transition-fast);
}

.psy-tab:hover {
    color: var(--color-text);
    background-color: var(--color-row-hover);
}

.psy-tab.is-active {
    color: var(--color-text);
    border-bottom-color: var(--color-primary-light);
}

.psy-panel-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-md);
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
}

.psy-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.psy-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.psy-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
}

.psy-section-head .psy-swatch {
    margin-right: var(--space-xs);
}

.psy-section-head .psy-section-title {
    flex: 1;
}

.psy-section-title {
    font-size: var(--font-size-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    margin: 0;
}

.psy-hint {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    line-height: 1.4;
}

.psy-fields {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-md);
}

.psy-field {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
}

.psy-field-label {
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--color-text);
    white-space: nowrap;
}

.psy-input {
    width: 66px;
    padding: 6px 8px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background-color: var(--color-bg);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    text-align: right;
    box-sizing: border-box;
    -moz-appearance: textfield;
    appearance: textfield;
    transition: border-color var(--transition-fast);
}

.psy-input::-webkit-outer-spin-button,
.psy-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.psy-input:focus {
    outline: none;
    border-color: var(--color-primary-light);
}

.psy-input:disabled,
.psy-select:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.psy-input-alt,
.psy-input-power {
    width: 88px;
}

.psy-point-name {
    flex: 1;
    text-align: left;
    width: auto;
    min-width: 0;
}

.psy-select {
    min-height: 32px;
    padding: 4px 8px;
    font-size: var(--font-size-sm);
    width: 150px;
}

/* Cooling coil capacity pair: "Sensible heat ratio" needs the room. */
.psy-select-cap {
    width: 170px;
}

.psy-unit {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.psy-field-error {
    color: var(--color-error-light);
    font-size: var(--font-size-xs);
    min-height: 0;
    margin: 0;
}

.psy-field-error:empty {
    display: none;
}

.psy-state-fields {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.psy-state-fields.is-disabled {
    opacity: 0.6;
}

.psy-radio-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs) var(--space-md);
}

/* A choice row that cannot fit on one line stacks instead of wrapping
   mid-row: the label keeps the first line and every option starts at
   the left edge on its own line. layoutRadioRows() in psychrometrics.js
   decides which rows need it. */
.psy-radio-row.is-stacked .psy-radio {
    flex-basis: 100%;
}

.psy-inline-label {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.psy-flow-fields {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.psy-range {
    margin-left: auto;
}

.psy-range-select {
    width: auto;
    min-height: 28px;
    padding: 2px 6px;
    font-size: var(--font-size-xs);
}

.psy-radio,
.psy-check {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-sm);
    color: var(--color-text);
    cursor: pointer;
    white-space: nowrap;
}

.psy-actions {
    display: flex;
    gap: var(--space-sm);
}

.psy-add-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.psy-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.psy-icon-btn:hover:not(:disabled) {
    background-color: var(--color-row-hover);
    color: var(--color-error-light);
}

.psy-icon-btn:disabled {
    opacity: 0.3;
    cursor: not-allowed;
}

/* Point rows (State Points tab) */
.psy-point-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.psy-point-row {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-sm) var(--space-sm);
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--psy-color, var(--color-primary-light));
    border-radius: var(--radius-sm);
    background-color: var(--color-bg);
}

.psy-point-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.psy-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: var(--psy-color, var(--color-primary-light));
    flex-shrink: 0;
}

/* ---------- Results ---------- */

.psy-results {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding-top: var(--space-md);
    border-top: 1px solid var(--color-border);
}

/* Breathing room between stacked result blocks (mixing, coil load,
   property table) without touching the first heading. */
.psy-results .psy-section-title + .psy-kv,
.psy-results .psy-section-title + .psy-table-wrap {
    margin-bottom: var(--space-sm);
}

.psy-table-wrap {
    overflow: hidden;
}

/* Fixed layout so the column count, not the content, sets the widths;
   the property column takes what is left after the value columns. */
.psy-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-size: var(--font-size-xs);
}

.psy-table th,
.psy-table td {
    padding: 3px 5px;
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Header cells may wrap so unit labels are never clipped. */
.psy-table th {
    white-space: normal;
    line-height: 1.15;
    vertical-align: bottom;
}

.psy-table th.psy-table-col,
.psy-table td.psy-table-val {
    width: 66px;
}

.psy-table-cols-5 th.psy-table-col,
.psy-table-cols-5 td.psy-table-val {
    width: 62px;
}

.psy-table th {
    text-align: right;
    font-weight: 600;
    color: var(--color-text);
    background-color: var(--color-bg-dark);
}

.psy-table th.psy-table-col .psy-swatch {
    margin-right: 4px;
    width: 8px;
    height: 8px;
}

.psy-table-prop {
    text-align: left !important;
    color: var(--color-text-muted);
    font-weight: 500;
}

.psy-table-unit {
    margin-left: 5px;
    font-size: 10px;
    opacity: 0.8;
}

.psy-table-val {
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--color-text);
}

.psy-table tbody tr:hover td {
    background-color: var(--color-row-hover);
}

.psy-kv {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 4px var(--space-md);
    margin: 0;
    font-size: var(--font-size-sm);
}

.psy-kv dt {
    color: var(--color-text-muted);
}

.psy-kv dd {
    margin: 0;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* ---------- Chart area ---------- */

.psy-chart-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    gap: var(--space-sm);
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: var(--space-sm) var(--space-md);
}

.psy-chart-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm) var(--space-md);
    flex-shrink: 0;
}

.psy-toolbar-label {
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.psy-chart-wrap {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.psy-chart {
    width: 100%;
    height: 100%;
    display: block;
    font-family: var(--font-family);
    user-select: none;
}

.psy-readout {
    flex-shrink: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-md);
    min-height: 24px;
    align-items: center;
    font-size: var(--font-size-sm);
    padding-top: var(--space-xs);
    border-top: 1px solid var(--color-border);
}

.psy-readout-hint {
    color: var(--color-text-muted);
    font-style: italic;
    font-size: var(--font-size-xs);
}

.psy-readout-item {
    display: inline-flex;
    gap: 6px;
    font-variant-numeric: tabular-nums;
}

.psy-readout-key {
    color: var(--color-text-muted);
    font-weight: 600;
}

.psy-readout-val {
    color: var(--color-text);
}

/* ---------- Chart drawing ---------- */

.psy-frame {
    fill: var(--color-bg);
    stroke: none;
}

.psy-frame-outline {
    fill: none;
    stroke: var(--color-border-strong);
    stroke-width: 1;
    pointer-events: none;
}

.psy-grid-line {
    stroke: var(--color-border);
    stroke-width: 0.6;
    opacity: 0.6;
}

.psy-grid-major {
    stroke: var(--color-border-strong);
    stroke-width: 0.8;
    opacity: 0.55;
}

.psy-tick {
    stroke: var(--color-border-strong);
    stroke-width: 1;
}

.psy-axis-label {
    fill: var(--color-text-muted);
    font-size: 11px;
}

.psy-axis-title {
    fill: var(--color-text);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.03em;
}

.psy-pressure-label {
    fill: var(--color-text-muted);
    font-size: 11px;
}

.psy-sat {
    fill: none;
    stroke: var(--color-text);
    stroke-width: 1.8;
}

.psy-rh {
    fill: none;
    stroke: #5ba9d8;
    stroke-width: 0.9;
    opacity: 0.75;
}

.psy-wb {
    fill: none;
    stroke: #6ee7b7;
    stroke-width: 0.7;
    opacity: 0.6;
}

.psy-h {
    fill: none;
    stroke: #fbbf24;
    stroke-width: 0.7;
    stroke-dasharray: 5 4;
    opacity: 0.6;
}

.psy-v {
    fill: none;
    stroke: #c4b5fd;
    stroke-width: 0.7;
    stroke-dasharray: 2 3;
    opacity: 0.7;
}

.psy-label {
    font-size: 10px;
    paint-order: stroke;
    stroke: var(--color-bg);
    stroke-width: 3px;
    stroke-linejoin: round;
}

.psy-label-rh { fill: #8fc7ea; }
.psy-label-wb { fill: #9ef0cc; }
.psy-label-h  { fill: #fcd34d; }
.psy-label-v  { fill: #d6ccff; }

.psy-label-caption {
    font-size: 10px;
    font-style: italic;
}

/* Enthalpy detail: fine lines and the ruler outside saturation */
.psy-h-fine {
    stroke-width: 0.5;
    stroke-dasharray: none;
    opacity: 0.28;
}

.psy-h-tick {
    stroke: #fbbf24;
    stroke-width: 0.9;
    opacity: 0.9;
}

.psy-h-edge-label { font-size: 10px; }

/* Optional protractor (sensible heat / total heat and enthalpy /
   humidity ratio) in the top-left corner */
.psy-prot-bg {
    fill: var(--color-bg);
    stroke: var(--color-border);
    stroke-width: 0.8;
    opacity: 0.92;
}

.psy-prot-line {
    fill: none;
    stroke: var(--color-text);
    stroke-width: 1;
}

.psy-prot-tick {
    stroke: var(--color-text-muted);
    stroke-width: 0.8;
}

.psy-prot-label {
    font-size: 7px;
    fill: var(--color-text-muted);
}

.psy-prot-label-shr { fill: var(--color-text); }

.psy-prot-caption {
    font-size: 7px;
    font-weight: 600;
    letter-spacing: 0.04em;
    fill: var(--color-text);
}

/* Optional scales to the right of the plot: dew point, vapor pressure,
   enthalpy and the sensible heat factor */
.psy-rscale-box {
    fill: rgba(148, 163, 184, 0.06);
    stroke: var(--color-border);
    stroke-width: 0.8;
}

.psy-rscale-bar {
    stroke: var(--color-text-muted);
    stroke-width: 1;
}

.psy-rscale-tick {
    stroke: var(--color-text-muted);
    stroke-width: 0.8;
}

.psy-rscale-label {
    font-size: 9px;
    fill: var(--color-text-muted);
}

.psy-rscale-caption {
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.03em;
    fill: var(--color-text);
}

.psy-shr-ref {
    fill: none;
    stroke: var(--color-text);
    stroke-width: 1.2;
}

/* Hover crosshair */
.psy-crosshair {
    fill: none;   /* the enthalpy guide is a path */
    stroke: var(--color-text-muted);
    stroke-width: 0.8;
    stroke-dasharray: 3 3;
    pointer-events: none;
}

.psy-crosshair-dot {
    fill: none;
    stroke: var(--color-text);
    stroke-width: 1;
    pointer-events: none;
}

/* Plotted points and lines. Each point carries a color class that
   sets --psy-color; the same classes color the form swatches and
   result-table headers so everything matches. */
.psy-line {
    stroke: var(--color-text);
    stroke-width: 2;
    fill: none;
}

.psy-line-mix {
    stroke: #94a3b8;
    stroke-dasharray: 6 4;
}

.psy-line-process {
    stroke: #f8fafc;
}

.psy-arrow {
    fill: #f8fafc;
}

.psy-point-halo {
    fill: var(--psy-color, var(--color-primary-light));
    opacity: 0.3;
}

.psy-point-dot {
    fill: var(--psy-color, var(--color-primary-light));
    stroke: var(--color-bg);
    stroke-width: 1.5;
}

.psy-point-label {
    fill: var(--psy-color, var(--color-primary-light));
    font-size: 12px;
    font-weight: 700;
    paint-order: stroke;
    stroke: var(--color-bg);
    stroke-width: 3px;
    stroke-linejoin: round;
}

.psy-point-offchart .psy-point-dot {
    stroke-dasharray: 2 2;
}

.psy-point-oa { --psy-color: #f97316; }
.psy-point-ra { --psy-color: #38bdf8; }
.psy-point-ma { --psy-color: #a3e635; }
.psy-point-sa { --psy-color: #e879f9; }
.psy-point-rh { --psy-color: #fb7185; }

.psy-line-reheat {
    stroke: #fda4af;
}

.psy-point-c0 { --psy-color: #38bdf8; }
.psy-point-c1 { --psy-color: #f97316; }
.psy-point-c2 { --psy-color: #a3e635; }
.psy-point-c3 { --psy-color: #e879f9; }
.psy-point-c4 { --psy-color: #facc15; }
.psy-point-c5 { --psy-color: #f87171; }

/* Reduced motion: the landing cards still lift on hover elsewhere;
   here we simply drop the transform. */
@media (prefers-reduced-motion: reduce) {
    .calc-card:hover,
    .calc-card:active {
        transform: none;
    }
}

/* ---------- Settings strip: units, save, export ---------- */

.psy-seg {
    display: inline-flex;
    margin-left: auto;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.psy-seg-btn {
    padding: 3px 10px;
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--color-text-muted);
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.psy-seg-btn + .psy-seg-btn {
    border-left: 1px solid var(--color-border-strong);
}

.psy-seg-btn:hover {
    color: var(--color-text);
}

.psy-seg-btn.is-active {
    background-color: var(--color-primary);
    color: var(--color-text-inverse);
}

.psy-actions-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    padding: 0 var(--space-md) var(--space-sm);
}

.psy-small-btn {
    padding: 5px 10px;
    font-size: var(--font-size-xs);
}

.psy-save-status {
    font-size: var(--font-size-xs);
    color: var(--color-success);
}

.psy-save-form {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    width: 100%;
}

.psy-save-name {
    flex: 1;
    text-align: left;
    width: auto;
}

/* ---------- Chain stages ---------- */

.psy-stage {
    padding: var(--space-xs) 0 var(--space-xs) var(--space-sm);
    border-left: 3px solid var(--psy-color, var(--color-border));
}

.psy-stage.is-off {
    border-left-color: var(--color-border);
}

.psy-stage.is-off .psy-swatch {
    opacity: 0.35;
}

.psy-stage-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.psy-stage-body.is-disabled {
    display: none;
}

/* ---------- System chooser + component chips ---------- */

.psy-system-select {
    width: 100%;
}

.psy-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.psy-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px 3px 8px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background-color: var(--color-bg-dark);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    line-height: 1.4;
    white-space: nowrap;
    cursor: pointer;
    transition: color var(--transition-fast),
                border-color var(--transition-fast),
                background-color var(--transition-fast);
}

.psy-chip::before {
    content: '+';
    font-weight: 700;
    opacity: 0.6;
}

.psy-chip:hover:not(:disabled) {
    color: var(--color-text);
    border-color: var(--color-border-strong);
}

.psy-chip.is-on {
    color: var(--color-text);
    border-color: var(--color-primary-light);
    background-color: rgba(91, 169, 216, 0.14);
}

.psy-chip.is-on::before {
    content: '\2713';
    color: var(--color-primary-light);
    opacity: 1;
}

.psy-chip:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.psy-stage-remove {
    width: 22px;
    height: 22px;
    opacity: 0.55;
}

.psy-stage-remove:hover:not(:disabled) {
    opacity: 1;
}

.psy-stage-remove svg {
    width: 13px;
    height: 13px;
}

/* ---------- Chart controls ---------- */

.psy-chart-controls {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-left: auto;
}

.psy-zoom-group {
    display: inline-flex;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.psy-zoom-btn {
    min-width: 28px;
    padding: 3px 8px;
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--color-text);
    background-color: var(--color-surface);
    transition: background-color var(--transition-fast);
}

.psy-zoom-btn + .psy-zoom-btn {
    border-left: 1px solid var(--color-border-strong);
}

.psy-zoom-btn:hover {
    background-color: var(--color-row-hover);
}

/* "Save chart preferences": a stand-alone button, not inside a group. */
.psy-zoom-btn.psy-save-prefs {
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
}

.psy-zoom-btn.psy-save-prefs:disabled {
    opacity: 0.6;
    cursor: progress;
}

/* ---------- Extra chart styling ---------- */

.psy-path {
    fill: none;
    stroke: var(--color-text);
    stroke-width: 1.4;
}

.psy-line-room {
    stroke: #c4b5fd;
    stroke-dasharray: 5 3;
}

.psy-point-er { --psy-color: #fb923c; }
.psy-point-ph { --psy-color: #fbbf24; }
.psy-point-f1 { --psy-color: #94a3b8; }
.psy-point-f2 { --psy-color: #94a3b8; }
.psy-point-hu { --psy-color: #22d3ee; }
.psy-point-ec { --psy-color: #34d399; }
.psy-point-rm { --psy-color: #c4b5fd; }
.psy-point-rq { --psy-color: #a78bfa; }
.psy-point-dp { --psy-color: #67e8f9; }
.psy-point-econ { --psy-color: #94a3b8; }

.psy-point-rq .psy-point-dot {
    fill: var(--color-bg);
    stroke: var(--psy-color);
    stroke-width: 2;
}

/* ---------- Results ---------- */

.psy-kv dd.is-ok {
    color: var(--color-success);
}

.psy-kv dd.is-warn {
    color: var(--color-warning);
}

.psy-table-cols-8 th.psy-table-col,
.psy-table-cols-8 td.psy-table-val {
    width: 50px;
}

/* Air properties with the airflow column: eight value columns. At the
   default 66px they overran the panel and squeezed the point column to
   nothing. The airflow ("10,000") and specific volume ("14.728")
   columns need a little more than the rest; the point keeps ~48px. */
.psy-table-cols-9 th.psy-table-col,
.psy-table-cols-9 td.psy-table-val {
    width: 50px;
}

.psy-table-cols-9 th.psy-table-col:nth-child(2),
.psy-table-cols-9 td.psy-table-val:nth-child(2),
.psy-table-cols-9 th.psy-table-col:last-child,
.psy-table-cols-9 td.psy-table-val:last-child {
    width: 54px;
}

.psy-table-cols-4 th.psy-table-col,
.psy-table-cols-4 td.psy-table-val {
    width: 100px;
}

.psy-table td.psy-table-prop .psy-swatch {
    width: 8px;
    height: 8px;
    margin-right: 5px;
}

/* ---------- Saved calculations (View Project tab) ---------- */

.calc-saved-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding: var(--space-md) var(--space-xl);
    max-width: 900px;
}

.calc-saved-empty {
    color: var(--color-text-muted);
    padding: var(--space-xl);
    text-align: center;
}

.calc-saved-card {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-sm) var(--space-md);
}

.calc-saved-icon {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: linear-gradient(135deg, var(--color-primary) 0%, #0d3a5a 100%);
    color: var(--color-text-inverse);
    font-size: 18px;
}

.calc-saved-body {
    flex: 1;
    min-width: 0;
}

.calc-saved-name {
    font-weight: 600;
    color: var(--color-text);
    margin: 0;
}

.calc-saved-meta {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.calc-saved-actions {
    display: flex;
    gap: var(--space-xs);
    flex-shrink: 0;
}

/* ---------- Economizer boundary on the chart ---------- */

.psy-region {
    stroke: none;
}

.psy-econ-region {
    fill: rgba(52, 211, 153, 0.12);
}

.psy-line-econ {
    stroke: #34d399;
    stroke-width: 1.3;
    stroke-dasharray: 6 4;
}

.psy-line-limit {
    stroke: #f59e0b;
    stroke-width: 1.1;
    stroke-dasharray: 2 3;
}

.psy-line-dplimit {
    stroke: #67e8f9;
    stroke-width: 1.2;
    stroke-dasharray: 7 3 2 3;
}

.psy-dp-region {
    fill: rgba(103, 232, 249, 0.07);
}

.psy-path-label {
    font-size: 10px;
    font-weight: 600;
    paint-order: stroke;
    stroke: var(--color-bg);
    stroke-width: 3px;
    stroke-linejoin: round;
}

.psy-label-econ { fill: #6ee7b7; }
.psy-label-limit { fill: #fcd34d; }
.psy-label-dplimit { fill: #a5f3fc; }

/* ---------- On-chart explainer box (economizer) ---------- */

.psy-callout-bg {
    fill: rgba(15, 23, 42, 0.82);
    stroke: var(--color-border-strong);
    stroke-width: 0.8;
}

.psy-callout-title {
    fill: var(--color-text);
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.03em;
}

.psy-callout-text {
    fill: var(--color-text);
    font-size: 9px;
}

.psy-callout-req {
    fill: var(--color-bg);
    stroke: #a78bfa;
    stroke-width: 1.5;
}

/* Mouse-driven chart: grab cursor while panning */
.psy-chart {
    cursor: crosshair;
}

.psy-chart.is-dragging {
    cursor: grabbing;
}

.psy-mouse-hint {
    text-transform: none;
    letter-spacing: 0;
}

.psy-callout-dot.is-ok {
    fill: var(--color-success);
}

.psy-callout-dot.is-no {
    fill: var(--color-error);
}

.psy-callout-swatch-box {
    stroke: #34d399;
    stroke-width: 0.8;
}

.psy-point-sf { --psy-color: #94a3b8; }

/* ---------- "?" help icons and popover ---------- */

.psy-help {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    margin-left: 2px;
    border-radius: 50%;
    border: 1px solid var(--color-border-strong);
    color: var(--color-text-muted);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
    cursor: help;
    transition: color var(--transition-fast), border-color var(--transition-fast), background-color var(--transition-fast);
}

.psy-help:hover,
.psy-help:focus-visible {
    color: var(--color-text-inverse);
    background-color: var(--color-primary);
    border-color: var(--color-primary-light);
    outline: none;
}

.psy-section-head .psy-help {
    margin-right: auto;
}

.psy-help-pop {
    position: fixed;
    z-index: 1200;
    max-width: 340px;
    padding: var(--space-sm) var(--space-md);
    background-color: var(--color-bg-dark);
    color: var(--color-text);
    border: 1px solid var(--color-primary-light);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    font-size: var(--font-size-xs);
    line-height: 1.45;
    pointer-events: auto;
}

/* ---------- Supply air dew point calculator ---------- */

.dp-side {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
    padding: var(--space-lg);
    overflow-y: auto;
}

.dp-hero {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-lg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-bg-dark);
}

.dp-hero-value {
    font-size: 2.6rem;
    font-weight: 700;
    line-height: 1.1;
    color: #a5f3fc;
    letter-spacing: -0.01em;
}

.dp-hero-caption {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    max-width: 640px;
}

.dp-hero-caption.is-warn {
    color: var(--color-error-light);
}

.dp-hero-line {
    font-size: var(--font-size-sm);
    font-weight: 600;
}

.dp-hero-line.is-ok { color: #6ee7b7; }
.dp-hero-line.is-warn { color: var(--color-error-light); }

.dp-explain {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    max-width: 720px;
}

.dp-explain-p {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    line-height: 1.55;
    margin: 0;
}

.dp-solve-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-xs);
}

/* ---------------------------------------------------------------
   Ductulator calculator
   --------------------------------------------------------------- */

.dt-side {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    overflow-y: auto;
}

.dt-hero {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md) var(--space-xl);
    padding: var(--space-md) var(--space-lg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-bg-dark);
}

.dt-hero-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 120px;
}

.dt-hero-value {
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1.1;
    color: #a5f3fc;
    letter-spacing: -0.01em;
}

.dt-hero-value.is-warn { color: var(--color-error-light); }

.dt-hero-caption {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Chart and duct drawing side by side; they stack on narrow panels. */
.dt-visuals {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md);
    align-items: flex-start;
    justify-content: center;
}

.dt-chart-wrap {
    flex: 1 1 460px;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    min-width: 0;
}

.dt-chart {
    width: 100%;
    max-width: 900px;
    aspect-ratio: 760 / 560;
    height: auto;
    display: block;
    font-family: var(--font-family);
    user-select: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: crosshair;
}

.dt-chart-bg { fill: var(--color-bg-dark); }
.dt-plot-frame { fill: none; stroke: var(--color-border-strong); stroke-width: 1; }
.dt-design-band { fill: #1d3557; stroke: none; }
.dt-band-label { fill: #93c5fd; font-size: 10px; font-style: italic; }
.dt-grid { stroke: #24334a; stroke-width: 0.6; }
.dt-grid-major { stroke: #3b4d68; stroke-width: 0.9; }
.dt-axis-label { fill: #cbd5e1; font-size: 10.5px; }
.dt-axis-title { fill: #e6edf3; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; }
.dt-line-d { fill: none; stroke: #5ba9d8; stroke-width: 1.1; }
.dt-line-v { fill: none; stroke: #6ee7b7; stroke-width: 0.9; stroke-dasharray: 5 4; }
.dt-line-label-d { fill: #9cd3f5; font-size: 9.5px; }
.dt-line-label-v { fill: #a7f3d0; font-size: 9.5px; }
.dt-legend { fill: #94a3b8; font-size: 10px; }
.dt-point { transition: transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1); }
.dt-cross { stroke: #fbbf24; stroke-width: 1; stroke-dasharray: 3 3; }
.dt-point-dot { fill: #fbbf24; stroke: #78350f; stroke-width: 1.5; }
.dt-point-label { fill: #fde68a; font-size: 12.5px; font-weight: 600; }
.dt-point-note { fill: var(--color-warning); font-size: 10px; }
.dt-readout { border-top: none; padding-top: 0; }

.dt-duct-wrap {
    flex: 0 1 300px;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    min-width: 0;
}

.dt-duct {
    width: min(100%, 320px, calc(100vh - 330px));
    aspect-ratio: 1 / 1;
    height: auto;
    display: block;
    font-family: var(--font-family);
    user-select: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-bg-dark);
}

.dt-duct-face { fill: #1d3557; stroke: #cbd5e1; stroke-width: 1.6; }
.dt-duct-back { fill: #16243a; stroke: #94a3b8; stroke-width: 1; }
.dt-duct-edge { stroke: #94a3b8; stroke-width: 1; }
.dt-flow { stroke: #fbbf24; stroke-width: 2.5; }
.dt-flow-head { fill: #fbbf24; stroke: none; }
.dt-dim { stroke: #a5f3fc; stroke-width: 1; }
.dt-dim-label { fill: #a5f3fc; font-size: 12px; font-weight: 600; }
.dt-duct-title { fill: #e6edf3; font-size: 11px; font-weight: 600; letter-spacing: 0.08em; }
.dt-duct-sub { fill: #94a3b8; font-size: 10.5px; }

.dt-shape-seg { align-self: flex-start; margin-left: 0; }

/* Material dropdown: as wide as its longest entry so the whole name reads
   without opening the list. */
.dt-material-field { display: block; }
.dt-material-select { width: 100%; max-width: 100%; }

.dt-note {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    line-height: 1.5;
    margin: 0;
}

.dt-solve-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-xs);
}

.dt-rect-table td.psy-table-val { text-align: right; }
.dt-rect-table .is-warn { color: var(--color-warning); }

/* ---------- Check results under a panel section ----------
   The rows that used to be explainer boxes on the chart. Swatches are
   tiny SVGs using the chart's own line / dot classes, so each row also
   works as the key for the line it describes. */

.psy-verdict {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: var(--space-xs);
    padding: var(--space-sm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background-color: var(--color-bg);
}

.psy-verdict[hidden] { display: none; }

.psy-verdict-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    font-size: var(--font-size-xs);
    line-height: 1.4;
    color: var(--color-text);
}

.psy-verdict-row.is-no { color: var(--color-error-light); }

.psy-verdict-row strong { font-weight: 600; }

/* ---------- Space section: the two checks ---------- */

.psy-subcheck {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    margin-top: var(--space-xs);
    padding: 2px 0 2px var(--space-sm);
    border-left: 2px solid var(--color-border);
}

.psy-subcheck.is-on { border-left-color: var(--color-text-muted); }

.psy-subcheck-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs) var(--space-sm);
}

.psy-subcheck-head .psy-check { font-weight: 600; }

.psy-subcheck-head .psy-verdict-swatch { margin-top: 0; }

.psy-subcheck-sub {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

.psy-subcheck-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.psy-subcheck-body:empty { display: none; }

.psy-verdict-swatch {
    flex-shrink: 0;
    width: 22px;
    height: 10px;
    margin-top: 3px;
    overflow: visible;
}

.psy-label-room { fill: #c4b5fd; }
