@font-face {
    font-family: "Archivo";
    src: url("/assets/vendors/archivo/archivo-latin-var.woff2") format("woff2");
    font-weight: 100 900;
    font-display: swap;
}

@font-face {
    font-family: "Martian Mono";
    src: url("/assets/vendors/martian-mono/martian-mono-latin-var.woff2") format("woff2");
    font-weight: 100 800;
    font-display: swap;
}

:root {
    /* The neutrals are the mark's own: --surface-2 is the icon tile exactly, --text its
       bone, and the ramp around them keeps that warmth rather than the cool grey a dark
       UI defaults to. */
    --ground: #191917;
    --surface: #212120;
    --surface-2: #2c2c2a;
    --rule: #383835;
    --text: #f1efe8;
    --text-2: #9a968c;
    /* The one step past --text, for the element that is already wearing it and still has
       to answer a hover. */
    --text-hi: #ffffff;

    /* The mark is four bars and only the leading one is orange, so orange means moving
       here too: it is the running colour, the focus ring, and nothing else. Buttons and
       headings stay bone, which is what keeps it worth noticing. */
    --brand: #ef9f27;
    /* The running lane's second stripe: --brand carried most of the way to --text. Spelled
       out rather than mixed, because the two palettes reach their paler orange from
       opposite directions and a single mix cannot say both. */
    --brand-2: #f0b965;

    --fail: #ff5d6c;
    /* Olive rather than a fresh green: success is most of the table and the stylesheet
       already says it stays quiet, so it sits a step off the neutrals and lets the
       running rows be the ones that carry colour. */
    --ok: #7f8a6b;
    /* Not red: an invalid row is flowlite losing track of the work, not the command
       failing, and painting it as a failure sends the reader to their own script. */
    --invalid: #b17ae8;

    /* Darker than --ground in both palettes: a scrim is the room's lights going down, so
       it stays a shadow over a light page rather than inverting into a haze. */
    --scrim: rgba(12, 12, 10, 0.72);

    --scheme: dark;

    --sans: "Archivo", system-ui, sans-serif;
    --display: "Martian Mono", ui-monospace, monospace;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

    --gutter: 2rem;
    --shell: 90rem;
}

/* The light palette, and the only block that restates a colour. `[ui] theme = "auto"`
   never reaches this selector: root.html resolves it to "light" or "dark" before the first
   paint, so the OS preference and a configured theme arrive here as the same attribute and
   this palette can be written once.

   Not an inversion of the dark one. The neutrals mirror, warmth and all - --surface is the
   bone that is --text above - but the four accents darken instead of holding still: each
   is text at five sites as well as a fill at fifteen, and #ef9f27 on a near-white ground
   is about 2:1. Darkening satisfies both uses at once, so each accent stays one token. */
:root[data-theme="light"] {
    --ground: #faf9f5;
    --surface: #f1efe8;
    --surface-2: #e5e2d8;
    --rule: #d5d1c4;
    /* The ink of logo-light.png, so the wordmark sits in the palette here too. */
    --text: #2e2e2c;
    --text-2: #6b675e;
    --text-hi: #0f0f0e;

    /* Deep amber: still the only colour that means moving, and 4.5:1 as a word. */
    --brand: #a3640b;
    --brand-2: #d7a55a;

    --fail: #c22c3a;
    --ok: #5e6a4a;
    --invalid: #7b4fc4;

    --scrim: rgba(30, 29, 26, 0.45);

    --scheme: light;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { color-scheme: var(--scheme); }

body {
    background: var(--ground);
    color: var(--text);
    font-family: var(--sans);
    font-size: 0.875rem;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

::selection { background: var(--brand); color: var(--ground); }

:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: 1px;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--ground); }
::-webkit-scrollbar-thumb { background: var(--rule); border: 2px solid var(--ground); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-2); }

a {
    color: inherit;
    text-decoration: underline;
    text-decoration-color: var(--rule);
    text-underline-offset: 3px;
}
a:hover { text-decoration-color: var(--text-2); }

/* ---------- Shell ---------- */

.shell {
    width: 100%;
    max-width: var(--shell);
    margin: 0 auto;
    padding: 0 var(--gutter);
}

main { flex: 1; padding: 2.5rem 0 5rem; }

.rule { border: 0; border-top: 1px solid var(--rule); }

/* ---------- Masthead ---------- */

.masthead {
    border-bottom: 1px solid var(--rule);
    background: var(--ground);
    position: sticky;
    top: 0;
    z-index: 10;
}

.masthead__inner {
    display: flex;
    align-items: center;
    gap: 2.5rem;
    height: 3.5rem;
}

/* The wordmark itself, rather than the display face standing in for it. Its own bone and
   orange are the page's --text and --brand, so it sits on the masthead as part of the
   palette instead of as a pasted-in image. */
.masthead__brand {
    display: flex;
    align-items: center;
    flex: none;
    text-decoration: none;
}

/* Both marks are in the page and the palette hides one. A <picture> would be the obvious
   way to carry two, but its media queries see only prefers-color-scheme and would ignore a
   configured theme. */
.masthead__brand img {
    display: block;
    height: 1.375rem;
    width: auto;
}

.masthead__brand .brand-mark--light { display: none; }
:root[data-theme="light"] .masthead__brand .brand-mark--dark { display: none; }
:root[data-theme="light"] .masthead__brand .brand-mark--light { display: block; }

.masthead__brand:hover img { opacity: 0.82; }

.masthead__nav {
    display: flex;
    gap: 1.5rem;
    margin-right: auto;
}

.masthead__link {
    color: var(--text-2);
    text-decoration: none;
    padding: 0.25rem 0;
    border-bottom: 1px solid transparent;
}
.masthead__link:hover { color: var(--text); }
.masthead__link[aria-current="page"] {
    color: var(--text);
    border-bottom-color: var(--text);
}

.masthead__live {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
}

/* Who is signed in, and the way out - only rendered when [auth] is configured. */
.masthead__user {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: var(--text-2);
}

/* ---------- Login ---------- */

.login {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 22rem;
    margin: 4rem auto;
}

.login .view-title { margin-bottom: 1rem; }
.login .meta__label { margin-top: 0.5rem; }
.login .btn { margin-top: 1rem; }

.login__error { color: var(--fail); }

/* ---------- Status marks ---------- */

.mark {
    display: block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: none;
    background: var(--text-2);
}
.mark--queued, .mark--waiting { background: none; box-shadow: inset 0 0 0 1px var(--text-2); }
.mark--scheduled, .mark--planned { background: none; box-shadow: inset 0 0 0 1px var(--text-2); opacity: .55; }
.mark--running { background: var(--brand); animation: breathe 1.6s ease-in-out infinite; }
.mark--succeeded { background: var(--ok); }
.mark--failed, .mark--timedout { background: var(--fail); }
.mark--skipped, .mark--aborted, .mark--deleted { background: none; box-shadow: inset 0 0 0 1px var(--rule); }
.mark--invalid { background: var(--invalid); }

@keyframes breathe {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 50%, transparent); }
    50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 0%, transparent); }
}

/* Only anomalies get a word and a colour; success stays quiet. */
.state { font-size: 0.75rem; color: var(--text-2); }
.state--running { color: var(--brand); }
.state--failed, .state--timedout { color: var(--fail); }
.state--invalid { color: var(--invalid); }

/* ---------- View header ---------- */

.view-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 2rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.view-head > * { min-width: 0; }

.view-title {
    font-family: var(--display);
    font-size: 1.75rem;
    font-weight: 600;
    letter-spacing: -0.05em;
    line-height: 1.1;
}

.view-sub {
    color: var(--text-2);
    margin-top: 0.5rem;
    max-width: 68ch;
}

.eyebrow {
    display: inline-block;
    font-family: var(--mono);
    font-size: 0.75rem;
    color: var(--text-2);
    margin-bottom: 0.625rem;
}

.back {
    display: inline-block;
    color: var(--text-2);
    text-decoration: none;
    margin-bottom: 2rem;
}
.back:hover { color: var(--text); }

/* ---------- Controls ---------- */

.controls {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

/* The job page stacks its action over the CLI line that does the same thing, rather than
   sitting them side by side as peers. */
.controls--stack {
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

.field, .btn {
    font-family: inherit;
    font-size: 0.8125rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 0.375rem 0.625rem;
}

.field { min-width: 11rem; }
.field:hover { border-color: var(--text-2); }
.field::placeholder { color: var(--text-2); }

.btn { cursor: pointer; }
.btn:hover { border-color: var(--text-2); }
.btn--primary { background: var(--text); color: var(--ground); border-color: var(--text); font-weight: 600; }
.btn--primary:hover { background: var(--text-hi); border-color: var(--text-hi); }
.btn--danger { color: var(--fail); border-color: var(--fail); background: none; }
.btn--danger:hover { background: var(--fail); color: var(--ground); }
.btn--quiet { background: none; color: var(--text-2); }
.btn--quiet:hover { color: var(--text); }
.btn:disabled { opacity: 0.35; cursor: default; }
.btn:disabled:hover { border-color: var(--rule); }

.btn--icon {
    padding: 0.25rem;
    min-width: 1.625rem;
    line-height: 0;
    color: var(--text-2);
}
.btn--icon:hover { color: var(--text); }

.icon {
    width: 14px;
    height: 14px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.25;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.chips { display: flex; gap: 0.375rem; flex-wrap: wrap; }

.chip {
    font-size: 0.8125rem;
    color: var(--text-2);
    text-decoration: none;
    padding: 0.25rem 0.625rem;
    border: 1px solid transparent;
    border-radius: 999px;
    cursor: pointer;
    background: none;
    font-family: inherit;
    display: inline-flex;
    align-items: center;
    gap: 0.4375rem;
}
.chip:hover { color: var(--text); border-color: var(--rule); }
.chip[aria-pressed="true"], .chip[aria-current="page"] {
    color: var(--text);
    background: var(--surface);
    border-color: var(--rule);
}

/* ---------- Run list ---------- */

.scroller { overflow-x: auto; }

.runs { width: 100%; border-collapse: collapse; }

/* The head stays put while the body scrolls under it. Its rule is an inset shadow, not a
   border: a collapsed border belongs to the table grid and would be left behind. */
.runs thead th {
    text-align: left;
    font-size: 0.6875rem;
    font-weight: 500;
    color: var(--text-2);
    padding: 0 0.75rem 0.5rem;
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--ground);
    box-shadow: inset 0 -1px 0 var(--rule);
}
.runs thead th:first-child { padding-left: 0; }
.runs thead th:last-child { padding-right: 0; }

.runs tbody td {
    padding: 0.625rem 0.75rem;
    border-bottom: 1px solid var(--rule);
    vertical-align: middle;
}
.runs tbody td:first-child { padding-left: 0; }
.runs tbody td:last-child { padding-right: 0; }
.runs tbody tr:hover td { background: var(--surface); }

.runs__mark { width: 1.5rem; }
.runs__state { width: 5.5rem; }
.runs__id { width: 4.5rem; font-family: var(--mono); color: var(--text-2); }
.runs__when { width: 7rem; color: var(--text-2); font-variant-numeric: tabular-nums; }
.runs__bar { width: 34%; min-width: 6rem; }
.runs__dur {
    width: 6rem;
    text-align: right;
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

.runs__go { width: 2.25rem; text-align: right; }

.runs__job { font-weight: 500; }
.runs__job a { text-decoration: none; }
.runs__job a:hover { text-decoration: underline; text-decoration-color: var(--text-2); }

/* Duration drawn against the slowest run on the page. */
.bar {
    height: 4px;
    background: var(--rule);
    border-radius: 2px;
    width: var(--span, 0%);
    min-width: 2px;
}
.bar--running { background: var(--brand); }
.bar--failed, .bar--timedout { background: var(--fail); }
.bar--succeeded { background: var(--ok); }
.bar--invalid { background: var(--invalid); }
.bar--scheduled { background: none; box-shadow: inset 0 0 0 1px var(--rule); }

/* ---------- Table footer / pagination ---------- */

.table-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding-top: 1rem;
    color: var(--text-2);
    font-size: 0.8125rem;
}

.table-foot--end { justify-content: flex-end; }

.pager { display: flex; align-items: center; gap: 0.5rem; }
.pager .btn { min-width: 2rem; text-align: center; text-decoration: none; }
.pager__at { font-variant-numeric: tabular-nums; }

.rows-per-page { display: flex; align-items: center; gap: 0.5rem; }
.rows-per-page .field { min-width: 0; padding: 0.1875rem 0.375rem; }

/* ---------- Metadata rows ---------- */

.meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0 3rem;
}

.meta__item { padding: 0.5rem 0; }

.meta__label {
    font-size: 0.6875rem;
    color: var(--text-2);
    margin-bottom: 0.125rem;
}

.meta__value { font-variant-numeric: tabular-nums; }
.meta__value--mono { font-family: var(--mono); font-size: 0.8125rem; }

.none { color: var(--text-2); }

/* ---------- Section ---------- */

.section { margin-top: 3rem; }

.section__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    padding-bottom: 0.625rem;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 1.25rem;
}

.section__title {
    font-family: var(--display);
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: -0.03em;
}

.section__note { color: var(--text-2); font-size: 0.8125rem; }

/* A section that opens on click. `details` draws its own marker and its own `display`,
   both of which fight `.section__head`, so the marker is dropped and the caret redrawn
   here - from the same rule colour as everything else, turning with the state. */
.collapse > summary {
    cursor: pointer;
    list-style: none;
}

.collapse > summary::-webkit-details-marker { display: none; }

/* Closed, the head's rule is the only thing under it, so the space it reserves for a body
   would read as a gap the panel forgot to fill. */
.collapse:not([open]) > summary { margin-bottom: 0; }

.collapse__title {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.collapse__caret {
    width: 0.375rem;
    height: 0.375rem;
    border-right: 1.5px solid var(--text-2);
    border-bottom: 1.5px solid var(--text-2);
    transform: rotate(-45deg);
    transition: transform 120ms ease;
}

.collapse[open] .collapse__caret { transform: rotate(45deg); }

.collapse > summary:hover .collapse__caret { border-color: var(--text); }

/* ---------- Timeline (job run detail) ---------- */

.timeline {
    display: grid;
    gap: 0;
    --lane-label: 14rem;
    --lane-dur: 5.5rem;
}

.timeline__axis {
    display: grid;
    grid-template-columns: var(--lane-label) 1fr var(--lane-dur) auto;
    align-items: end;
    color: var(--text-2);
    font-size: 0.6875rem;
    padding-bottom: 0.375rem;
}

.timeline__ticks {
    position: relative;
    height: 1.25rem;
    border-bottom: 1px solid var(--rule);
}

.timeline__tick {
    position: absolute;
    bottom: 0;
    left: var(--at);
    padding-left: 0.25rem;
    border-left: 1px solid var(--rule);
    line-height: 1;
    padding-bottom: 0.25rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.timeline__tick:last-child { border-left: 0; border-right: 1px solid var(--rule); padding-left: 0; padding-right: 0.25rem; transform: translateX(-100%); }

.lane {
    display: grid;
    grid-template-columns: var(--lane-label) 1fr var(--lane-dur) auto;
    align-items: center;
    gap: 0;
    min-height: 2rem;
    border-bottom: 1px solid var(--rule);
}
.lane:hover { background: var(--surface); }

.lane__name {
    font-family: var(--mono);
    font-size: 0.8125rem;
    padding-right: 1rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lane__track { position: relative; height: 2rem; }

.lane__span {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    left: var(--start, 0%);
    width: var(--span, 0%);
    min-width: 3px;
    height: 0.625rem;
    border-radius: 2px;
    background: var(--text-2);
}
/* Both stripes are light: orange against a paler orange reads as a sheen travelling along
   the bar, where orange alternating with the dark ground underneath it reads as hazard
   tape. Running is the normal case and should not look like a warning. */
.lane__span--running {
    background: repeating-linear-gradient(
        115deg,
        var(--brand) 0 9px,
        var(--brand-2) 9px 18px
    );
    animation: crawl 1.4s linear infinite;
}
.lane__span--succeeded { background: var(--ok); }
.lane__span--failed, .lane__span--timedout { background: var(--fail); }
.lane__span--queued { background: none; box-shadow: inset 0 0 0 1px var(--rule); }
.lane__span--scheduled { background: none; box-shadow: inset 0 0 0 1px var(--rule); opacity: .55; }
.lane__span--invalid { background: var(--invalid); }

/* One full stripe period along x, so the loop has no seam: the 18px period divided by
   sin(115deg), the stripe angle above. */
@keyframes crawl {
    to { background-position: 19.86px 0; }
}

.lane__idle {
    position: absolute;
    top: 50%;
    left: var(--start, 0%);
    transform: translateY(-50%);
    color: var(--text-2);
    font-size: 0.75rem;
    padding-left: 0.5rem;
    white-space: nowrap;
}

.lane__acts {
    display: flex;
    gap: 0.25rem;
    padding-left: 0.5rem;
}

.lane__dur {
    text-align: right;
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
    padding-left: 1rem;
}

.lane__deps {
    grid-column: 1;
    font-size: 0.6875rem;
    color: var(--text-2);
    padding-right: 1rem;
    padding-bottom: 0.375rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------- DAG (job detail) ---------- */

.dag {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 1.5rem;
    overflow-x: auto;
}

.dag svg { display: block; }
.dag__edge { fill: none; stroke: var(--rule); stroke-width: 1.5; }
.dag__node { fill: var(--surface-2); stroke: var(--rule); }
.dag__label {
    fill: var(--text);
    font-family: var(--mono);
    font-size: 12px;
}

/* ---------- Definition table ---------- */

.deftable { width: 100%; border-collapse: collapse; }

.deftable th {
    text-align: left;
    font-size: 0.6875rem;
    font-weight: 500;
    color: var(--text-2);
    padding: 0 1rem 0.5rem 0;
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--ground);
    box-shadow: inset 0 -1px 0 var(--rule);
}

.deftable td {
    padding: 0.625rem 1rem 0.625rem 0;
    border-bottom: 1px solid var(--rule);
    vertical-align: top;
}
.deftable th:last-child, .deftable td:last-child { padding-right: 0; }
.deftable tbody tr:hover td { background: var(--surface); }

.deftable__id { font-family: var(--mono); font-size: 0.8125rem; white-space: nowrap; }

.deftable__go { width: 1%; text-align: right; white-space: nowrap; }

.cmd {
    font-family: var(--mono);
    font-size: 0.8125rem;
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 0.25rem 0.5rem;
    display: inline-block;
    max-width: 100%;
    overflow-x: auto;
    white-space: pre;
    vertical-align: middle;
}

.deps { display: flex; flex-wrap: wrap; gap: 0.25rem 0.5rem; }

.dep {
    font-family: var(--mono);
    font-size: 0.75rem;
    color: var(--text-2);
    border-bottom: 1px dashed var(--rule);
}

/* ---------- Index list (jobs, schedules) ---------- */

.index { border-top: 1px solid var(--rule); }

.entry {
    display: grid;
    grid-template-columns: minmax(12rem, 1fr) minmax(0, 2fr) auto;
    gap: 1.5rem;
    align-items: baseline;
    padding: 1rem 0.75rem;
    margin: 0 -0.75rem;
    border-bottom: 1px solid var(--rule);
    text-decoration: none;
}
.entry:hover { background: var(--surface); }

.entry__name { font-weight: 500; }

.entry__id {
    font-family: var(--mono);
    font-size: 0.75rem;
    color: var(--text-2);
    margin-top: 0.125rem;
}

.entry__desc {
    color: var(--text-2);
    max-width: 68ch;
}

.entry__aside {
    text-align: right;
    font-size: 0.8125rem;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.entry__cron { font-family: var(--mono); color: var(--text); }

.entry__off {
    font-size: 0.75rem;
    color: var(--text-2);
    border: 1px solid var(--rule);
    border-radius: 999px;
    padding: 0.0625rem 0.5rem;
}

/* ---------- Empty state ---------- */

.empty {
    padding: 4rem 0;
    text-align: center;
    color: var(--text-2);
}

.empty__do { margin-top: 0.5rem; }

.empty__cmd {
    font-family: var(--mono);
    font-size: 0.8125rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 0.1875rem 0.5rem;
}

/* ---------- Loading ---------- */

.loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
    padding: 4rem 0;
    color: var(--text-2);
}

.spinner {
    width: 0.75rem;
    height: 0.75rem;
    border: 1.5px solid var(--rule);
    border-top-color: var(--text-2);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Dialog ---------- */

dialog {
    /* The reset above strips the UA's margin: auto, which is what centres an open modal. */
    margin: auto;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 1.5rem;
    max-width: 26rem;
    width: calc(100% - 2rem);
}
dialog::backdrop { background: var(--scrim); }

.dialog__title {
    font-family: var(--display);
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    margin-bottom: 0.5rem;
}

.dialog__body { color: var(--text-2); margin-bottom: 1.5rem; }

.dialog__actions { display: flex; justify-content: flex-end; gap: 0.5rem; }

/* Wide enough for a name/value listing, where the confirmation dialogs are a sentence wide. */
.dialog--data { max-width: 34rem; }

.dialog__scroll {
    max-height: 60vh;
    overflow-y: auto;
    margin-bottom: 1.5rem;
}

.dialog__scroll .meta__item { width: 100%; }
.dialog__scroll .meta__value { overflow-wrap: anywhere; }
/* A parameter row in the submit dialog is a label over a full-width input. */
.dialog__scroll .field { width: 100%; margin-top: 0.25rem; }

/* ---------- Attempt output (task run detail) ---------- */

.attempt {
    border-top: 1px solid var(--rule);
    padding: 1rem 0 1.25rem;
}

.attempt:first-of-type { border-top: 0; }

.attempt__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.attempt__name {
    font-family: var(--display);
    font-size: 0.8125rem;
}

.attempt__at, .attempt__dur {
    font-size: 0.75rem;
    color: var(--text-2);
}

.attempt__at { margin-left: auto; }

.stream { margin-top: 0.75rem; }

/* The label is the stream's own head: the name at the left, what is inside at the right,
   which is the whole of what a closed one tells the reader. */
.stream__label {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    font-family: var(--mono);
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-2);
    margin-bottom: 0.375rem;
}

/* A count reads as prose, not as another label, so it drops the head's tracking and caps. */
.stream__note {
    letter-spacing: normal;
    text-transform: none;
}

/* Long lines scroll inside the block rather than widening the page. */
.stream__body {
    font-family: var(--mono);
    font-size: 0.8125rem;
    line-height: 1.5;
    margin: 0;
    padding: 0.75rem 1rem;
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: 3px;
    max-height: 30rem;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.stream__body--err { color: var(--fail); }

/* ---------- Fit to window ---------- */

/* A page that opts in with `fit-viewport` ends at the bottom of the window: one section
   (`section--fill`) absorbs whatever height is left over and scrolls inside itself, so the
   sections after it stay on screen no matter how many rows the reader asked for.

   Only worth doing when there is height to divide up — below that the page scrolls the
   ordinary way, which beats squeezing a table into four rows. */
@media (min-height: 44rem) {
    .fit-viewport { height: 100svh; overflow: hidden; }

    /* Content that still will not fit (a very long limits panel, say) scrolls here rather
       than being cut off at the window's edge. */
    .fit-viewport main {
        display: flex;
        min-height: 0;
        overflow: auto;
        padding-bottom: 2.5rem;
    }

    .fit-viewport main > .shell {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-height: 0;
    }

    .fit-viewport .section--fill {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-height: 0;
    }

    /* The htmx target between the section and the table it swaps in. */
    .fit-viewport .section--fill > [hx-trigger] {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-height: 0;
    }

    .fit-viewport .section--fill .scroller {
        flex: 1;
        min-height: 8rem;
        overflow: auto;
    }

    .fit-viewport .section--fill .table-foot { flex: none; }

    /* Sized by config, so it has no natural ceiling: cap it before it crowds out the runs. */
    .fit-viewport .section--cap .scroller { max-height: 30vh; }
}

/* ---------- Responsive ---------- */

@media (max-width: 60rem) {
    :root { --gutter: 1.25rem; }

    .runs__when, .runs__bar { display: none; }

    .entry {
        grid-template-columns: 1fr;
        gap: 0.375rem;
    }
    .entry__aside { text-align: left; }
}

@media (max-width: 40rem) {
    .timeline { --lane-label: 7rem; --lane-dur: 4rem; }
    .masthead__live { display: none; }
    .masthead__inner { gap: 1.25rem; }
    .masthead__brand img { height: 1.125rem; }
    .masthead__nav { gap: 1rem; }
    .view-title { font-size: 1.375rem; }
    .runs__state { display: none; }
    .meta { gap: 0 1.5rem; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
    .mark--running { box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 25%, transparent); }
    .lane__span--running { background: var(--brand); }
}
