/* Self-hosted so the fonts are one same-origin hop, discoverable from index.html's preload
   rather than through a chained @import. `optional` is the point: it gives the browser a
   ~100ms block period and then, if the font missed it, keeps the fallback for the rest of
   the page view and caches the font for the next one. No mid-view swap means no reflow,
   which is what was moving .lede and .hero-note under the re-wrapping hero h1.
   Subsets and unicode-ranges are copied verbatim from Google's own CSS; filenames keep
   Google's content hash so the immutable caching in public/_headers stays truthful. */

/* latin */
@font-face {
    font-family: 'Manrope';
    font-style: normal;
    /* Variable: this one file covers the 400-800 the stylesheet asks for. */
    font-weight: 400 800;
    font-display: optional;
    src: url('/fonts/manrope-latin-xn7gYHE41ni1AdIRggexSg.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext — Estonian š/ž and the other analyte-label diacritics live here. */
@font-face {
    font-family: 'Manrope';
    font-style: normal;
    font-weight: 400 800;
    font-display: optional;
    src: url('/fonts/manrope-latin-ext-xn7gYHE41ni1AdIRggmxSuXd.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 400;
    font-display: optional;
    src: url('/fonts/dm-mono-400-latin-aFTU7PB1QTsUX8KYthqQBA.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 400;
    font-display: optional;
    src: url('/fonts/dm-mono-400-latin-ext-aFTU7PB1QTsUX8KYthSQBLyM.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* latin */
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 500;
    font-display: optional;
    src: url('/fonts/dm-mono-500-latin-aFTR7PB1QTsUX8KYvumzEYOtbQ.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* latin-ext */
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 500;
    font-display: optional;
    src: url('/fonts/dm-mono-500-latin-ext-aFTR7PB1QTsUX8KYvumzEY2tbZX9.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    color-scheme: light;
    --ink: #17221f;
    --muted: #687572;
    --paper: #f6f5ef;
    --panel: #fffef9;
    --line: #d9ded7;
    --teal: #0d766d;
    --teal-dark: #07574f;
    --coral: #dc735a;
    --yellow: #e8c85b;
    --shadow: 0 18px 50px rgba(29, 53, 48, .09);
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    color: var(--ink);
    background: var(--paper);
    font-family: Manrope, sans-serif;
}

button,
input,
select {
    font: inherit;
}

button {
    cursor: pointer;
}

.shell {
    min-height: 100vh;
}

.topbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 22px clamp(20px, 5vw, 72px);
    border-bottom: 1px solid var(--line);
    background: rgba(246, 245, 239, .9);
}

.brand {
    display: flex;
    align-items: center;
    gap: 12px;
    font-weight: 800;
    letter-spacing: -.03em;
}

.brand-mark {
    width: 35px;
    height: 35px;
    display: grid;
    place-items: center;
    color: white;
    background: var(--teal);
    border-radius: 10px 10px 10px 3px;
}

.top-actions {
    position: relative;
    display: flex;
    align-items: center;
}

.top-menu {
    display: flex;
    align-items: center;
    gap: 16px;
    color: var(--muted);
    font-size: 13px;
}

/* Compound selector on purpose: .btn below sets display too, and a bare .menu-toggle ties with
   it on specificity, so the later .btn would win and leave a dead Menu button on desktop. */
.btn.menu-toggle {
    display: none;
}

/* Used on <a> as much as on <button> — the two anchor-only declarations keep a link from
   rendering as underlined inline text with its padding spilling out of the line box. */
.btn {
    display: inline-block;
    border: 0;
    border-radius: 7px;
    text-decoration: none;
    padding: 11px 16px;
    font-weight: 700;
    color: var(--panel);
    background: var(--teal);
}

.btn:hover {
    background: var(--teal-dark);
}

.btn.secondary {
    color: var(--teal-dark);
    background: #e4eeea;
}

.btn.ghost {
    color: var(--teal-dark);
    background: transparent;
    border: 1px solid var(--line);
}

main {
    width: min(1220px, calc(100% - 40px));
    margin: 0 auto;
    padding: 54px 0 80px;
}

.hero {
    display: flex;
    justify-content: space-between;
    gap: 30px;
    align-items: end;
    margin-bottom: 38px;
}

.eyebrow {
    color: var(--coral);
    font-family: 'DM Mono', monospace;
    font-size: 12px;
    letter-spacing: .12em;
    text-transform: uppercase;
}

h1 {
    margin: 10px 0 10px;
    max-width: 670px;
    font-size: clamp(34px, 5vw, 64px);
    line-height: 1.02;
    letter-spacing: -.06em;
}

/* The landing headline sits right at its wrap point, so a font with different advance widths
   can flip it between two and three lines — a ~65px jump that carries .lede and the
   bottom-aligned .hero-note with it. Reserving two lines pins the box whichever font wins.
   Scoped to the landing hero: renderApp()'s headline is one line and would gain dead space.
   2 x 1.02 line-height = 2.04em; the lh unit says the same thing where it is supported. */
.hero-landing h1 {
    min-height: 2.04em;
    min-height: 2lh;
}

.lede {
    max-width: 590px;
    color: var(--muted);
    line-height: 1.7;
}

.hero-note {
    max-width: 230px;
    padding: 18px;
    border-top: 3px solid var(--yellow);
    color: var(--muted);
    font-size: 12px;
    line-height: 1.6;
}

.layout {
    display: grid;
    grid-template-columns: 245px 1fr;
    gap: 22px;
}

.panel {
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--panel);
    box-shadow: var(--shadow);
}

.sidebar {
    padding: 18px;
    align-self: start;
}

.section-label {
    margin: 10px 0 12px;
    color: var(--muted);
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .08em;
}

.metric-list {
    display: grid;
    gap: 5px;
}

.metric-button {
    width: 100%;
    display: flex;
    justify-content: space-between;
    border: 0;
    border-radius: 6px;
    padding: 10px;
    text-align: left;
    color: var(--ink);
    background: transparent;
}

.metric-button:hover,
.metric-button.active {
    color: var(--teal-dark);
    background: #e7f0ec;
}

.metric-button small {
    color: var(--muted);
}

/* Both metric pickers are always rendered; the media query below swaps which one shows. */
.metric-select {
    display: none;
    width: 100%;
}

.link-button {
    margin-top: 12px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--teal-dark);
    font-size: 12px;
    font-weight: 700;
}

.link-button:hover {
    text-decoration: underline;
}

.sidebar-note {
    margin: 12px 0 0;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.6;
}

.content {
    min-width: 0;
}

.toolbar {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 12px;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--line);
}

.toolbar-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

select,
input,
textarea {
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 9px 10px;
    color: var(--ink);
    background: #fff;
}

textarea {
    min-height: 62px;
    font: inherit;
    line-height: 1.5;
    resize: vertical;
}

/* iOS Safari zooms the whole page when a focused control's text is under 16px, and .field sets
   12px for its label, which the control inherits through `font: inherit`. openModal() autofocuses
   [data-autofocus], so that zoom fired the moment a dialog opened and left it clipped. Pin the
   control itself on touch screens; the label keeps its size, and desktop keeps its compact fields. */
@media (pointer: coarse) {
    select,
    input,
    textarea {
        font-size: 16px;
    }
}

.chart-panel {
    overflow: hidden;
}

.chart-wrap {
    position: relative;
    min-height: 360px;
    padding: 24px;
}

.chart-wrap svg {
    width: 100%;
    height: 310px;
    overflow: visible;
}

.chart-grid {
    stroke: #e2e7e0;
    stroke-width: 1;
}

.axis-label {
    fill: var(--muted);
    font-family: 'DM Mono', monospace;
    font-size: 10px;
}

.point-label {
    fill: var(--ink);
    font-size: 11px;
    font-weight: 700;
    stroke: var(--panel);
    stroke-width: 3px;
    paint-order: stroke;
}

.chart-line {
    fill: none;
    stroke: var(--teal);
    stroke-width: 3;
}

.chart-point {
    fill: var(--panel);
    stroke: var(--teal);
    stroke-width: 3;
}

.chart-band {
    fill: #dceee7;
    opacity: .8;
}

.threshold-a {
    stroke: var(--coral);
}

.threshold-b {
    stroke: var(--yellow);
}

.threshold-c {
    stroke: #7899a3;
}

.legend {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    padding: 15px 24px 19px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 12px;
}

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

.swatch {
    width: 22px;
    height: 3px;
}

.swatch.band {
    height: 10px;
    background: #dceee7;
}

/* The .threshold-* rules above set `stroke` for the dashed SVG lines, which does nothing to an
   <i>; the legend chips need the same colours as a background. Kept in step with those strokes. */
.swatch.line {
    background: var(--teal);
}

.swatch.threshold-a {
    background: var(--coral);
}

.swatch.threshold-b {
    background: var(--yellow);
}

.swatch.threshold-c {
    background: #7899a3;
}

.empty {
    display: grid;
    place-items: center;
    min-height: 320px;
    padding: 30px;
    text-align: center;
    color: var(--muted);
}

.empty strong {
    display: block;
    color: var(--ink);
    font-size: 20px;
    margin-bottom: 8px;
}

.history {
    border-top: 1px solid var(--line);
}

.history-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 10px 24px;
    border-bottom: 1px solid var(--line);
    font-size: 13px;
}

.history-row:last-child {
    border-bottom: 0;
}

.history-date {
    color: var(--muted);
    font-family: 'DM Mono', monospace;
    font-size: 12px;
}

.history-value {
    flex: 1;
    font-weight: 700;
}

.history-delete {
    border: 0;
    background: transparent;
    padding: 4px 0;
    color: var(--coral);
    font-size: 12px;
    font-weight: 700;
}

.history-delete:hover {
    text-decoration: underline;
}

.modal-backdrop {
    position: fixed;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 20px;
    background: rgba(23, 34, 31, .45);
    z-index: 50;
}

.modal {
    width: min(560px, 100%);
    max-height: 90vh;
    overflow: auto;
    padding: 26px;
}

.modal h2 {
    margin: 8px 0 18px;
    font-size: 22px;
}

.form-panel {
    margin-top: 22px;
    padding: 22px;
}

/* The metric background that replaced the always-on entry form under the chart. */
.about-panel {
    margin-top: 22px;
    padding: 22px;
}

.about-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--line);
}

.about-head h2 {
    margin: 6px 0 0;
    font-size: 22px;
    letter-spacing: -.03em;
}

.about-meta {
    color: var(--muted);
    font-family: 'DM Mono', monospace;
    font-size: 12px;
}

/* Label column + body column. The .section-label margin is tuned for the sidebar, so it is reset
   here to sit on the same baseline as the first line of its paragraph. */
.about-grid {
    display: grid;
    gap: 16px;
    margin-top: 18px;
}

.about-row {
    display: grid;
    grid-template-columns: 148px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}

.about-row .section-label {
    margin: 2px 0 0;
}

.about-body p {
    margin: 0;
    max-width: 62ch;
    color: var(--ink);
    font-size: 14px;
    line-height: 1.65;
}

.about-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
}

.about-footer {
    margin: 20px 0 0;
    padding-top: 14px;
    border-top: 3px solid var(--yellow);
    color: var(--muted);
    font-size: 12px;
    line-height: 1.6;
}

/* Shown when a metric has no long-form copy yet: what the catalog does know, rather than a
   panel of empty headings. */
.about-thin {
    display: grid;
    gap: 8px;
    margin-top: 16px;
}

.about-thin p {
    margin: 0;
    max-width: 62ch;
    font-size: 14px;
    line-height: 1.65;
}

.about-pending {
    color: var(--muted);
    font-size: 12px;
}

/* Sits under the metric name in the chart toolbar: a real sentence, so it gets sentence-case body
   type rather than the uppercase mono .eyebrow treatment this slot used to carry. */
.metric-tagline {
    display: block;
    margin-top: 3px;
    max-width: 64ch;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.5;
}

.about-editor {
    margin-top: 16px;
}

.about-editor summary {
    cursor: pointer;
    color: var(--teal-dark);
    font-size: 12px;
    font-weight: 700;
}

.about-editor summary span {
    color: var(--muted);
    font-weight: 400;
}

.about-editor .form-grid {
    margin-top: 14px;
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}

.field {
    display: grid;
    gap: 6px;
    color: var(--muted);
    font-size: 12px;
}

.field.full {
    grid-column: 1/-1;
}

.field input,
.field select {
    width: 100%;
}

.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 18px;
}

.settings {
    display: grid;
    gap: 22px;
    max-width: 720px;
}

.settings .form-panel {
    margin-top: 0;
}

.settings h2 {
    margin: 8px 0 10px;
    font-size: 22px;
}

.dropzone {
    display: grid;
    justify-items: center;
    gap: 6px;
    padding: 38px 20px;
    border: 1.5px dashed #c3ccc3;
    border-radius: 8px;
    background: #fbfaf5;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.dropzone:hover,
.dropzone.dragover {
    border-color: var(--teal);
    background: #eef4f0;
}

.dropzone strong {
    font-size: 16px;
}

.dropzone span {
    color: var(--muted);
    font-size: 12px;
}

.files-panel {
    margin-top: 22px;
    overflow: hidden;
}

.file-row {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 18px 22px;
    border-bottom: 1px solid var(--line);
}

.file-row:last-child {
    border-bottom: 0;
}

.file-row:hover {
    background: #fbfaf5;
}

.file-icon {
    flex: none;
    width: 42px;
    height: 42px;
    display: grid;
    place-items: center;
    border-radius: 10px 10px 10px 3px;
    background: #e7f0ec;
    color: var(--teal-dark);
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    font-weight: 500;
}

.file-meta {
    flex: 1;
    min-width: 0;
    display: grid;
    gap: 7px;
    justify-items: start;
}

.file-meta strong {
    overflow-wrap: anywhere;
}

.file-sub {
    color: var(--muted);
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    letter-spacing: .04em;
}

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

.chip {
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid var(--line);
    color: var(--muted);
    background: #fff;
    font-size: 11px;
    font-weight: 600;
}

.chip.ok {
    color: var(--teal-dark);
    background: #e7f0ec;
    border-color: transparent;
}

/* Related metrics are the one chip you can press, so they borrow the filled .chip.ok treatment
   rather than sitting in the same outline as the read-only "what moves it" chips. Written as
   .chip.chip-link so it outranks the .chip base rule above it. */
.chip.chip-link {
    cursor: pointer;
    color: var(--teal-dark);
    background: #e7f0ec;
    border-color: transparent;
    font-family: inherit;
    font-weight: 700;
}

.chip.chip-link:hover {
    background: #d7e7df;
}

.chip.warn {
    color: #a1512d;
    background: #f9e9e0;
    border-color: transparent;
}

.file-actions {
    display: flex;
    gap: 6px;
    flex: none;
}

.btn.small {
    padding: 7px 11px;
    border-radius: 6px;
    font-size: 12px;
}

.btn.danger {
    color: var(--coral);
}

.ignored-details summary {
    cursor: pointer;
    color: var(--teal-dark);
    font-size: 12px;
    font-weight: 700;
}

.ignored-details ul {
    margin: 8px 0 0;
    padding-left: 18px;
    display: grid;
    gap: 5px;
    color: var(--muted);
    font-size: 12px;
}

.ignored-raw {
    display: block;
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    color: var(--muted);
    opacity: .8;
    overflow-wrap: anywhere;
}

.empty-note {
    padding: 28px 22px;
    margin: 0;
    color: var(--muted);
}

/* Indeterminate progress for the report parse. The server reports no progress, so the bar
   shows liveness only — the elapsed counter next to it is the honest number. */
.progress-track {
    position: relative;
    overflow: hidden;
    height: 6px;
    border-radius: 999px;
    background: var(--line);
}

.progress-bar {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 38%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--teal), var(--teal-dark));
    animation: progress-slide 1.5s cubic-bezier(.65, .05, .36, 1) infinite;
}

@keyframes progress-slide {
    from { left: -38%; }
    to { left: 100%; }
}

.parsing-meta {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 16px;
}

.parsing-elapsed {
    font-family: 'DM Mono', monospace;
    font-size: 22px;
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    /* Still reads as "working" — the elapsed seconds keep ticking without any motion. */
    .progress-bar {
        left: 0;
        width: 100%;
        animation: none;
        opacity: .4;
    }
}

/* A value outside the range printed on that row of the report — worth a second look before
   importing, but never blocked: an out-of-range result is often the real finding. */
.review-outside {
    color: var(--coral);
    font-weight: 600;
}

/* The line each imported value was read from, so it can be checked against the report. */
.review-source {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    color: var(--muted);
    max-width: 320px;
    overflow-wrap: anywhere;
}

/* Keeps a wide table inside the panel instead of stretching the page. Below the mobile
   breakpoint the rows stack instead (see the media query), so this only bites above it. */
.table-scroll {
    margin-top: 16px;
    overflow-x: auto;
}

.review-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

.review-table th {
    text-align: left;
    padding: 8px 10px;
    color: var(--muted);
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .08em;
    border-bottom: 1px solid var(--line);
}

.review-table td {
    padding: 9px 10px;
    border-bottom: 1px solid var(--line);
}

.checkbox {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--ink);
    font-size: 14px;
}

.checkbox input {
    width: auto;
}

.ignored-group {
    margin-top: 14px;
    color: var(--muted);
    font-size: 13px;
}

.ignored-group ul {
    margin: 6px 0 0;
    padding-left: 18px;
    display: grid;
    gap: 4px;
}

.ignored-name {
    margin-right: 6px;
    color: var(--ink);
    font-weight: 600;
}

/* Bottom-left on purpose: .toast is pinned bottom-right and would land on top of it. The
   z-index sits under .modal-backdrop's 50 so the dialog covers the button that opened it. */
.feedback-fab {
    position: fixed;
    left: 22px;
    bottom: 22px;
    z-index: 40;
    cursor: pointer;
    box-shadow: var(--shadow);
}

.toast {
    position: fixed;
    right: 22px;
    bottom: 22px;
    padding: 13px 16px;
    border-radius: 7px;
    color: white;
    background: var(--ink);
    box-shadow: var(--shadow);
}

/* ─── Landing ────────────────────────────────────────────────────────────────────────────────
   The landing markup lives in public/index.html so it paints before app.js runs and so a
   crawler sees something; the app replaces #app whole on its first render, so nothing below is
   ever on screen at the same time as a rendered screen. Everything here is built from the
   components above — .panel, .chip, .review-table, the .chart-* classes — so the page cannot
   drift away from the product it is describing. */

/* Set pre-paint by the inline hint in index.html when this browser has signed in before, so a
   returning user gets the header and then their timeline rather than a frame of the pitch.
   Only the sections hide: the top bar is the same one renderApp() paints, so leaving it up
   makes the boot an insertion under a fixed header instead of a flash of empty paper. */
.returning #landing {
    display: none;
}

.landing-cta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 22px;
}

/* A still of the real timeline view, assembled from .layout/.sidebar/.chart-panel so it stays
   truthful for free. The sidebar rows are spans rather than buttons — nothing here is live. */
.landing-preview .metric-button {
    cursor: default;
}

.landing-section {
    margin-top: 76px;
    padding-top: 38px;
    border-top: 1px solid var(--line);
}

.landing-section h2,
.landing-footer h2 {
    margin: 10px 0 12px;
    max-width: 720px;
    font-size: clamp(24px, 3vw, 36px);
    line-height: 1.15;
    letter-spacing: -.03em;
}

.landing-note {
    max-width: 760px;
    margin-top: 26px;
    color: var(--muted);
    font-size: 14px;
    line-height: 1.7;
}

.landing-note strong {
    color: var(--ink);
}

/* The only prose link on the site. Keeps the underline — it is a link out to someone else's
   policy and should look like one — but in the hairline colour rather than browser blue. */
.landing-note a {
    color: var(--teal-dark);
    text-decoration-color: var(--line);
    text-underline-offset: 3px;
}

.landing-note a:hover {
    text-decoration-color: var(--teal);
}

.steps {
    display: grid;
    gap: 30px;
    margin: 32px 0 0;
    padding: 0;
    list-style: none;
}

/* Absolute rather than a grid column: step 2 carries a figure and the others don't, so the
   number would otherwise have to span a row count that differs per item. Child combinator
   throughout: step 2's figure contains its own <li> list, which takes none of this. */
.steps > li {
    position: relative;
    padding-left: 62px;
}

.step-mark {
    position: absolute;
    left: 0;
    top: 1px;
    width: 42px;
    height: 42px;
    display: grid;
    place-items: center;
    /* The same asymmetric corner as .brand-mark and .file-icon. */
    border-radius: 10px 10px 10px 3px;
    color: var(--panel);
    background: var(--teal);
    font-family: 'DM Mono', monospace;
    font-size: 15px;
    font-weight: 500;
}

.steps > li > h3 {
    margin: 0 0 6px;
    font-size: 20px;
    letter-spacing: -.02em;
}

.steps > li > p {
    max-width: 640px;
    margin: 0;
    color: var(--muted);
    line-height: 1.7;
}

/* Reads as a still of a screen rather than a live panel, so it takes the dropzone's tint and
   skips the shadow — a shadowed card inside body copy looks like something to click. */
.landing-figure {
    margin-top: 20px;
    padding: 4px 20px 18px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fbfaf5;
}

.landing-figure .ignored-group {
    margin-top: 18px;
}

.track-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 26px 30px;
    margin-top: 32px;
}

.track-group .section-label {
    margin-top: 0;
}

.fact-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(235px, 1fr));
    gap: 18px;
    margin-top: 32px;
}

.fact {
    padding: 20px;
}

.fact .section-label {
    margin-top: 0;
}

.fact p {
    margin: 0;
    color: var(--muted);
    font-size: 14px;
    line-height: 1.7;
}

.landing-footer {
    display: flex;
    justify-content: space-between;
    align-items: end;
    gap: 30px;
    margin-top: 76px;
    padding-top: 38px;
    border-top: 1px solid var(--line);
}

.landing-footer .btn {
    margin-top: 20px;
}

@media (max-width:800px) {
    .feedback-fab {
        left: 14px;
        bottom: 14px;
    }

    /* The on-screen keyboard covers the lower half of the viewport, but .modal-backdrop is fixed
       to the layout viewport, which does not shrink — so a vertically centred dialog puts its
       field and its buttons behind the keyboard with no way to scroll to them. Anchor the dialog
       to the top and let the backdrop scroll instead of centring it into the covered area. */
    .modal-backdrop {
        align-items: start;
        overflow-y: auto;
    }

    .modal {
        max-height: none;
    }

    /* A textarea sized by `rows` for desktop costs height that is scarce once the keyboard is up. */
    .modal textarea {
        height: 100px;
    }

    .topbar {
        padding: 17px 20px;
    }

    .btn.menu-toggle {
        display: block;
    }

    /* Scoped to .has-menu: a header with a single action keeps the base inline row instead. */
    .has-menu .top-menu {
        position: absolute;
        right: 0;
        top: calc(100% + 10px);
        z-index: 40;
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
        min-width: 200px;
        padding: 12px;
        border: 1px solid var(--line);
        border-radius: 8px;
        background: var(--panel);
        box-shadow: var(--shadow);
    }

    .top-actions.open .top-menu {
        display: flex;
    }

    .has-menu .top-menu .btn {
        display: block;
        width: 100%;
        text-align: left;
    }

    .top-menu > span {
        display: none;
    }

    main {
        padding-top: 34px;
    }

    .hero {
        display: block;
    }

    .hero-note {
        margin-top: 24px;
        max-width: none;
    }

    .layout {
        grid-template-columns: 1fr;
    }

    .metric-select {
        display: block;
    }

    .metric-list {
        display: none;
    }

    /* The mobile viewBox is near-square, so a fixed height would letterbox it inside the panel;
       height:auto lets the SVG take exactly its own aspect ratio. */
    .chart-wrap {
        min-height: 0;
        padding: 12px;
    }

    .chart-wrap svg {
        height: auto;
    }

    .form-grid {
        grid-template-columns: 1fr;
    }

    .about-row {
        grid-template-columns: 1fr;
        gap: 6px;
    }

    .field.full {
        grid-column: auto;
    }

    /* Each row stacks into a block. Four columns cannot give the source line a usable width at
       this size, and it is the column that matters — it is the verbatim report text a value is
       checked against, so it gets the full width here rather than a few characters per line. */
    .review-table thead {
        display: none;
    }

    .review-table,
    .review-table tbody,
    .review-table tr,
    .review-table td {
        display: block;
    }

    .review-table tr {
        padding: 12px 0;
        border-bottom: 1px solid var(--line);
    }

    .review-table tr:last-child {
        border-bottom: 0;
    }

    .review-table td {
        padding: 0;
        border: 0;
    }

    .review-table td[data-label] {
        display: inline-block;
        margin: 7px 16px 0 0;
    }

    .review-table td[data-label]::before {
        content: attr(data-label) " ";
        color: var(--muted);
        font-family: 'DM Mono', monospace;
        font-size: 10px;
        text-transform: uppercase;
        letter-spacing: .08em;
    }

    .review-source {
        max-width: none;
        margin-top: 7px;
    }

    .file-row {
        flex-wrap: wrap;
    }

    .file-actions {
        width: 100%;
        justify-content: flex-end;
    }

    /* Landing. The sidebar still is dropped rather than stacked: on a phone the app itself swaps
       the metric list for a select, so a column of rows above the chart would be showing a
       control that isn't there, and the chart wants the width more. */
    .landing-preview .sidebar {
        display: none;
    }

    .landing-section,
    .landing-footer {
        margin-top: 48px;
        padding-top: 28px;
    }

    .steps > li {
        padding-left: 0;
    }

    .step-mark {
        position: static;
        margin-bottom: 12px;
    }

    .landing-figure {
        padding: 4px 14px 14px;
    }

    .landing-footer {
        display: block;
    }
}