/* box-sizing: border-box everywhere, so a percentage width plus padding
   (e.g. .history-panel, .validation-panel: width: 100% inside a padded
   .panel) sizes to the specified width instead of adding padding on top
   of it. Without this, those two panels rendered 64px wider than their
   container on every screen - invisible on a wide viewport where the
   extra width just ate into .app-wrapper's margin, but real horizontal
   overflow at a narrow one. The per-input box-sizing declarations further
   down predate this and are now redundant, but are left in place rather
   than pulled out in the same change that added the reset. */
*, *::before, *::after {
    box-sizing: border-box;
}

:root {
    --primary-emerald: #064E3B;
    --primary-emerald-hover: #043a2b;
    --bg-champagne: #F8E7C9;
    --accent-champagne: #efe0bb;
    --text-main: #1a2e26;
    /* Darkened from #5a6d65, which fell to 4.21:1 on --accent-champagne (the
       nav bar, stat tiles and study status) - under the 4.5:1 AA floor for
       body text. Now 4.81:1 there and 6.29:1 on white. */
    --text-muted: #52645c;
    --panel-bg: #ffffff;
    --border-color: #d1c7b3;
    /* The boundary of a form control has to reach 3:1 (SC 1.4.11); the
       decorative --border-color above is 1.68:1 on white. Only controls use
       this, so panel edges and table rules keep their light hairlines - 1.4.11
       does not apply to those. */
    --border-control: #968871;
    --shadow: 0 8px 30px rgba(0,0,0,0.08);
    --radius: 12px;
}

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background-color: var(--bg-champagne);
    color: var(--text-main);
    margin: 0;
    padding: 0;
    line-height: 1.5;
}

.app-wrapper {
    max-width: 1200px;
    margin: 0 auto;
    padding: 40px 20px;
}

.main-header {
    text-align: center;
    margin-bottom: 40px;
}

.main-header h1 {
    font-size: 2.5rem;
    color: var(--primary-emerald);
    margin: 0 0 10px 0;
    font-weight: 800;
    letter-spacing: -0.02em;
}

.main-header p {
    color: var(--text-muted);
    font-size: 1.1rem;
}

.nav-tabs {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-bottom: 30px;
    background: var(--accent-champagne);
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
    padding: 6px;
    border-radius: 16px;
}

.tab-btn {
    padding: 10px 24px;
    border: none;
    border-radius: 10px;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.95rem;
    transition: all 0.2s ease;
    background: transparent;
    color: var(--text-muted);
}

.tab-btn.active {
    background: var(--primary-emerald);
    color: white;
    box-shadow: 0 4px 12px rgba(6, 78, 59, 0.2);
}

.dashboard-container {
    width: 100%;
}

.main-layout {
    display: grid;
    grid-template-columns: 380px 1fr;
    gap: 30px;
    align-items: start;
}

.hidden {
    display: none !important;
}

.panel {
    background: var(--panel-bg);
    padding: 32px;
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    border: 1px solid var(--border-color);
    /* .history-panel/.validation-panel set width: 100% to fill their
       container; without border-box that 100% is the content box alone, and
       this panel's own padding+border then add on top of it, overflowing the
       container by ~66px. Invisible on a wide desktop layout's slack, fatal
       at phone width. */
    box-sizing: border-box;
}

.panel-title {
    margin: 0 0 24px 0;
    font-size: 1.25rem;
    color: var(--primary-emerald);
    font-weight: 700;
    border-bottom: 2px solid var(--bg-champagne);
    padding-bottom: 12px;
}

.input-group {
    margin-bottom: 24px;
}

.input-group label {
    display: block;
    font-weight: 600;
    margin-bottom: 10px;
    font-size: 0.9rem;
    color: var(--text-main);
}

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

.row-input input {
    width: 80px;
    text-align: center;
}

.separator {
    font-weight: bold;
    color: var(--text-muted);
}

.temp-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 16px;
    width: 100%;
}

.temp-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.temp-field label {
    font-weight: 500;
    font-size: 0.8rem;
    color: var(--text-muted);
}

input[type="number"] {
    padding: 10px;
    border: 1px solid var(--border-control);
    border-radius: 8px;
    font-size: 1rem;
    transition: border-color 0.2s;
    background: #fafafa;
    width: 100%;
    box-sizing: border-box;
}

/* A border-colour change alone was the only focus signal here, and it is easy
   to miss; every other control in the app keeps the browser's default ring. */
input[type="number"]:focus {
    outline: 2px solid var(--primary-emerald);
    outline-offset: 1px;
    border-color: var(--primary-emerald);
    background: white;
}

.primary-btn {
    width: 100%;
    padding: 14px;
    background-color: var(--primary-emerald);
    color: white;
    border: none;
    border-radius: 8px;
    font-size: 1rem;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.2s ease;
    margin-top: 10px;
}

.primary-btn:hover {
    background-color: var(--primary-emerald-hover);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(6, 78, 59, 0.15);
}

.primary-btn:active {
    transform: translateY(0);
}

.primary-btn:disabled {
    /* Darkened from #a0b0a8, which left the white label at 2.27:1 while a run
       was in flight. Disabled controls are exempt from SC 1.4.3, but the label
       still has to be readable; 3.85:1 reads clearly and still looks inert. */
    background-color: #78857f;
    cursor: not-allowed;
    transform: none;
}

.secondary-btn {
    width: 100%;
    padding: 12px;
    background-color: transparent;
    color: #c0392b;
    border: 1px solid #f5c6cb;
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    margin-top: 20px;
}

.secondary-btn:hover {
    background-color: #f8d7da;
    border-color: #f5c6cb;
}

.status-display {
    margin-top: 20px;
    font-size: 0.85rem;
    text-align: center;
    color: var(--text-muted);
    padding: 10px;
    border-radius: 8px;
    background: var(--bg-champagne);
}

.visualization-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    /* As a grid item this defaults to min-width: auto, so the widest child
       sizes the panel: the value table stretched it (and the page) past the
       viewport instead of scrolling in its own box. */
    min-width: 0;
}

/* The parameter column is much taller than the plate. Pinning the
   visualisation keeps the field, the key and the timeline together on screen
   no matter how far down the controls are scrolled. */
@media (min-width: 901px) {
    .visualization-panel {
        position: sticky;
        top: 20px;
    }
}

.canvas-stage {
    position: relative;
    /* Square, but never so tall that the key and timeline below it are pushed
       off a short screen. */
    width: min(500px, calc(100vh - 330px));
    height: min(500px, calc(100vh - 330px));
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 22px;
    background: #000;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 0 20px rgba(0,0,0,0.1);
}

canvas {
    width: 100%;
    height: 100%;
    /* A 20x300 grid is not square. `contain` letterboxes it inside the stage
       instead of stretching it; the hover readout does the same arithmetic. */
    object-fit: contain;
    image-rendering: pixelated;
}

.legend-container {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    width: 100%;
    max-width: 500px;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-main);
}

/* Filled in by script.js from the active colour map, so the key always shows
   the colours actually painted on the plate. */
.gradient-bar {
    /* Shrinks on a narrow screen instead of pushing the key off the side. */
    flex: 1 1 120px;
    max-width: 240px;
    height: 12px;
    border-radius: 6px;
    border: 1px solid var(--border-color);
}

.legend-label {
    flex: 0 0 auto;
    min-width: 62px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.legend-options {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 10px 16px;
    margin-top: 12px;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.mini-select {
    padding: 5px 8px;
    border: 1px solid var(--border-control);
    border-radius: 7px;
    background: #fafafa;
    font-size: 0.8rem;
    color: var(--text-main);
}

.scale-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}

.scale-toggle input { margin: 0; }

/* Visually hidden, still read by screen readers. */
.sr-inline {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* ---------- Timeline ---------- */

.time-ctrl {
    width: 100%;
    max-width: 500px;
    margin-top: 20px;
}

.time-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
}

.play-btn {
    width: 38px;
    height: 38px;
    flex: 0 0 auto;
    border: none;
    border-radius: 50%;
    background: var(--primary-emerald);
    color: #fff;
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.2s, transform 0.1s;
}

.play-btn:hover { background: var(--primary-emerald-hover); }
.play-btn:active { transform: scale(0.95); }

.time-readout {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-main);
    font-variant-numeric: tabular-nums;
    margin: 0 !important;
}

.frame-count {
    font-weight: 500;
    color: var(--text-muted);
    margin-left: 8px;
}

.slider {
    width: 100%;
    accent-color: var(--primary-emerald);
    cursor: pointer;
}

.slider-labels {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}

/* Sized like the timeline above it. min-width: 0 matters: as a flex item of
   .visualization-panel it defaults to min-width: auto, so a wide value table
   stretched the panel (and the page) instead of scrolling inside its own box. */
.field-table {
    width: 100%;
    max-width: 500px;
    min-width: 0;
    margin-top: 16px;
}

.status-display.is-error {
    background: #fbe9e7;
    color: #b3261e;
    font-weight: 600;
}

/* Sticks to the bottom of the viewport while the (very tall) parameter column
   is on screen, then settles into place at its end. The negative offset and
   the padding cancel the panel's own 32px bottom padding so nothing shows
   through underneath it. */
.run-dock {
    position: sticky;
    bottom: -32px;
    margin: 4px -32px -32px -32px;
    padding: 12px 32px 32px 32px;
    background: var(--panel-bg);
    border-top: 1px solid var(--bg-champagne);
    border-radius: 0 0 var(--radius) var(--radius);
}

.run-dock .primary-btn { margin-top: 0; }
.run-dock .status-display { margin-top: 12px; margin-bottom: 0; }

.history-panel {
    width: 100%;
}

/* ---------- 404 ---------- */

.error-panel {
    max-width: 560px;
    margin: 8vh auto 0 auto;
    text-align: center;
}

.error-code {
    font-size: 3.5rem;
    font-weight: 800;
    line-height: 1;
    color: var(--primary-emerald);
    margin: 0 0 8px 0;
    font-variant-numeric: tabular-nums;
}

.error-panel .panel-title {
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: 12px;
}

.error-panel .panel-note {
    margin: 0 auto 24px auto;
}

/* The same thermal ramp the plate and the key are painted with. */
.error-rule {
    background: linear-gradient(to right, #0000ff, #00ff00, #ff0000);
    margin: 0 auto 24px auto;
    max-width: 220px;
}

.error-home {
    display: inline-block;
    width: auto;
    padding: 14px 28px;
    text-decoration: none;
}

.table-responsive {
    overflow-x: auto;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

th, td {
    text-align: left;
    padding: 16px;
    border-bottom: 1px solid var(--bg-champagne);
}

th {
    background-color: var(--bg-champagne);
    color: var(--primary-emerald);
    font-weight: 700;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.view-btn {
    width: auto;
    padding: 6px 14px;
    font-size: 0.8rem;
    background: var(--primary-emerald);
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-weight: 600;
    transition: opacity 0.2s;
}

.view-btn:hover {
    opacity: 0.9;
}

@media (max-width: 900px) {
    .main-layout {
        grid-template-columns: 1fr;
    }

    /* Finger-sized targets on touch layouts: 38px and 37px tall on a phone is
       under the 44px guideline. Desktop keeps the tighter sizing. */
    .play-btn {
        width: 44px;
        height: 44px;
    }

    .tab-btn {
        padding: 14px 24px;
    }

    /* The checkbox itself stays 13px, but the label wrapping it is the target,
       so giving the label the height gives the tap area without resizing any
       control. Adds a little vertical space to the parameter column. */
    .ins-toggle,
    .scale-toggle {
        min-height: 44px;
    }

    /* Taller hit area for the thumb; the track is drawn centred, so the
       slider looks the same. */
    .slider {
        height: 44px;
    }

    /* One column, so the visualisation panel comes first - otherwise the
       plate sits below a screen and a half of inputs. */
    .visualization-panel { order: -1; }

    /* Sized against the panel, not the viewport: 90vw ignored the panel's own
       padding, so the stage was 64px wider than the column that holds it and
       pushed the whole page sideways. */
    .canvas-stage {
        width: 100%;
        max-width: 500px;
        height: auto;
        aspect-ratio: 1 / 1;
    }
}

/* Small phones. The three tabs, at the 44px-target padding above, add up to
   more than a 360px screen and pushed the page sideways; they wrap instead,
   which keeps the tap targets. */
@media (max-width: 480px) {
    .nav-tabs {
        flex-wrap: wrap;
        max-width: 100%;
    }

    .tab-btn {
        padding: 14px 16px;
    }

    .app-wrapper {
        padding: 24px 14px;
    }

    .panel {
        padding: 22px 18px;
    }
}

/* The simulation tab is a 380px control sidebar + canvas grid. The history and
   validation tabs are single full-width panels, so they opt out of that
   template - otherwise their content is squeezed into the 380px column. */
#history-tab,
#validation-tab {
    display: block;
}

/* ---------- Validation tab ---------- */

.validation-panel {
    width: 100%;
}

.panel-note {
    color: var(--text-muted);
    font-size: 0.92rem;
    margin: -6px 0 22px 0;
    max-width: 70ch;
}

.panel-note code,
.study-status code {
    background: var(--accent-champagne);
    padding: 1px 6px;
    border-radius: 5px;
    font-size: 0.88em;
}

.study-status {
    padding: 28px;
    text-align: center;
    color: var(--text-muted);
    background: var(--accent-champagne);
    border-radius: var(--radius);
}

.study-status .muted { color: var(--text-muted); }

/* KPI row: headline numbers read as tiles, not as a chart */
.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 14px;
    margin-bottom: 28px;
}

.stat-tile {
    background: var(--accent-champagne);
    border-radius: var(--radius);
    padding: 16px 18px;
}

.stat-value {
    font-size: 1.7rem;
    font-weight: 700;
    color: var(--text-main);
    line-height: 1.1;
}

.stat-value.good { color: var(--primary-emerald); }
.stat-value.bad  { color: #b3261e; }

.stat-label {
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--text-main);
    margin-top: 6px;
}

.stat-note {
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-top: 2px;
}

.chart-card {
    background: var(--panel-bg);
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    padding: 18px 18px 6px 18px;
    margin: 0 0 22px 0;
}

.chart-caption {
    color: var(--text-muted);
    font-size: 0.85rem;
    line-height: 1.5;
    margin-bottom: 10px;
    max-width: 80ch;
}

.chart-tip {
    position: absolute;
    z-index: 50;
    pointer-events: none;
    background: #1a2e26;
    color: #fff;
    font-size: 0.78rem;
    line-height: 1.45;
    padding: 7px 10px;
    border-radius: 8px;
    box-shadow: 0 6px 18px rgba(0,0,0,0.22);
    white-space: nowrap;
}

.data-details {
    margin-top: 6px;
}

.data-details summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--primary-emerald);
    padding: 8px 0;
}

.data-details h4 {
    margin: 18px 0 8px 0;
    color: var(--text-main);
    font-size: 0.95rem;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.84rem;
    font-variant-numeric: tabular-nums;
}

.data-table th,
.data-table td {
    text-align: left;
    padding: 7px 10px;
    border-bottom: 1px solid var(--border-color);
}

.data-table th {
    color: var(--text-muted);
    font-weight: 600;
}

/* ---------- Heat source list ---------- */

.ps-hint {
    font-size: 0.8rem;
    color: var(--text-muted);
    line-height: 1.45;
    margin: 4px 0 12px 0;
}

.src-head,
.src-row {
    display: grid;
    grid-template-columns: 1fr 1fr 1.3fr 32px;
    gap: 8px;
    align-items: center;
}

.src-head {
    margin-bottom: 4px;
}

.src-head span {
    font-size: 0.74rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.src-row {
    margin-bottom: 8px;
}

.src-row input {
    width: 100%;
    box-sizing: border-box;
}

.src-del {
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
    border-radius: 8px;
    padding: 4px;
    transition: all 0.15s ease;
}

.src-del:hover {
    background: #f3d9d9;
    color: #b3261e;
}

.src-empty {
    font-size: 0.82rem;
    color: var(--text-muted);
    font-style: italic;
    margin: 4px 0 10px 0;
}

.src-add {
    width: 100%;
    margin-bottom: 14px;
}

.src-quick-label {
    display: block;
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.src-quick-label code {
    background: var(--accent-champagne);
    padding: 1px 5px;
    border-radius: 4px;
}

.src-quick-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
}

.src-quick-row input {
    width: 100%;
    box-sizing: border-box;
}

.src-quick-msg {
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-top: 6px;
    min-height: 1em;
}

.src-quick-msg.is-error {
    color: #b3261e;
}

/* Neutral action button. .secondary-btn is the red destructive style used by
   Clear History; adding a heat spot is not destructive. */
.ghost-btn {
    padding: 11px 16px;
    background-color: transparent;
    color: var(--primary-emerald);
    border: 1px solid var(--border-control);
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
}

.ghost-btn:hover {
    background-color: var(--accent-champagne);
    border-color: var(--primary-emerald);
}

/* Keep the enable checkbox on one line with its label. */
.ps-toggle {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 4px;
}

.ps-toggle input[type="checkbox"] {
    width: auto;
    margin: 0;
    flex: 0 0 auto;
}

.ps-toggle label {
    margin: 0;
    font-weight: 600;
    cursor: pointer;
}

/* The heatmap responds to hover, so signal that it is inspectable. */
#heatCanvas {
    cursor: crosshair;
}

/* Cost comparison bars */
.cost-row {
    display: grid;
    grid-template-columns: 210px 1fr 190px;
    gap: 12px;
    align-items: center;
    margin-bottom: 10px;
}

.cost-label { font-size: 0.85rem; color: var(--text-main); }

.cost-track {
    background: var(--accent-champagne);
    border-radius: 6px;
    height: 20px;
    overflow: hidden;
}

.cost-fill {
    background: #2a78d6;
    height: 100%;
    border-radius: 6px;
}

.cost-value {
    font-size: 0.82rem;
    color: var(--text-secondary, #52514e);
    font-variant-numeric: tabular-nums;
}

.cost-ms { color: var(--text-muted); margin-left: 6px; }

/* .cost-row's three columns are fixed pixel widths (210px label + 190px
   value either side of the bar) that add up to more than a narrow phone
   screen before the middle 1fr track gets anything, pushing the whole page
   sideways. Stack them instead: label, then bar, then value, each at the
   full column width. This has to come after the base .cost-row rule above -
   an earlier @media block does not out-rank a later unconditional rule of
   equal specificity, it just loses the cascade once both apply. */
@media (max-width: 900px) {
    .cost-row {
        grid-template-columns: 1fr;
        gap: 4px;
        margin-bottom: 14px;
    }

    .cost-value {
        justify-self: start;
    }
}

/* Reaction-diffusion parameter grid */
.rd-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 10px 0 4px 0;
}

.rd-grid label {
    display: block;
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-bottom: 4px;
}

.rd-grid input { width: 100%; box-sizing: border-box; }

/* Material regions */
.mat-head, .mat-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr) 1.2fr 30px;
    gap: 6px;
    align-items: center;
}

.mat-head span {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
}

.mat-row { margin-bottom: 8px; }
.mat-row input { width: 100%; box-sizing: border-box; padding: 8px 6px; font-size: 0.85rem; }

.ins-toggle {
    display: flex !important;
    align-items: center;
    gap: 5px;
    font-size: 0.72rem !important;
    color: var(--text-muted) !important;
    font-weight: 500 !important;
    margin-top: 4px !important;
    cursor: pointer;
}

.ins-toggle input[type="checkbox"] { width: auto; margin: 0; }

/* ---------- Legal pages and footer ---------- */

.legal-panel {
    max-width: 720px;
    margin: 0 auto;
}

.legal-panel h2 {
    font-size: 1.05rem;
    color: var(--primary-emerald);
    margin: 26px 0 8px 0;
}

.legal-panel p,
.legal-panel dd {
    color: var(--text-muted);
    font-size: 0.92rem;
    line-height: 1.6;
    margin: 0 0 12px 0;
}

.legal-list dt {
    font-weight: 700;
    color: var(--text-main);
    font-size: 0.92rem;
    margin-top: 14px;
}

.legal-list dd {
    margin-left: 0;
}

.legal-panel a {
    color: var(--primary-emerald);
}

.site-footer {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    margin-top: 28px;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.site-footer a {
    color: var(--primary-emerald);
    /* 44px tall so it is a real target on a phone, without looking padded. */
    padding: 12px 6px;
}
