@layer modules {
    /* Recent-activity stream on route_item_detail — compact "row per run".
       Each row carries --card-color from the response status; data-state
       drives a subtle background tint per warning/critical/running. */
    .activity-stream {
        display: flex;
        flex-direction: column;
        gap: 0.4rem;
    }

    .activity-row {
        align-items: baseline;
        background: var(--surface);
        border: 1px solid var(--rule-soft);
        box-shadow: inset 3px 0 0 var(--card-color, var(--rule));
        color: inherit;
        column-gap: 0.75ch;
        display: grid;
        grid-template-columns: auto 1fr auto;
        padding: 0.55rem 0.85rem 0.55rem 1.05rem;
        text-decoration: none;
        transition: border-color 120ms ease-out;
    }

    .activity-row[data-state="check"]  {
        background: var(--surface-check);
        --card-color: var(--status-check-fg);
    }
    .activity-row[data-state="warning"]  {
        background: var(--surface-warn);
        --card-color: var(--status-warn-fg);
    }
    .activity-row[data-state="critical"] {
        background: var(--surface-crit);
        --card-color: var(--status-crit-fg);
    }

    @media (any-hover: hover) {
        .activity-row:hover { border-color: var(--primary); }
    }

    .activity-row__byline {
        align-items: baseline;
        color: var(--ink-soft);
        display: inline-flex;
        flex-wrap: wrap;
        font-family: var(--font-data);
        font-size: 0.6875rem;
        gap: 0 0.75ch;
        letter-spacing: 0.04em;
    }

    .activity-row__byline strong { color: var(--ink); font-weight: 600; }
    .activity-row__byline time   { text-transform: uppercase; letter-spacing: 0.08em; }

    /* "READING ▸" cue on measurement runs — signals the row expands the
       captured reading in place, not the run report. Flips to ▾ when open. */
    .activity-row__data-cue {
        color: var(--primary);
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;

        &::after { content: " ▸"; }
    }

    .activity-row[aria-expanded="true"] .activity-row__data-cue::after { content: " ▾"; }

    /* Measurement run rows are <button>s (they toggle the reading below), so
       undo the UA button chrome to match the <a> rows exactly. */
    button.activity-row {
        cursor: pointer;
        font: inherit;
        inline-size: 100%;
        text-align: start;
    }

    .activity-row[aria-expanded="true"] { border-color: var(--primary); }

    /* Expanded reading: hangs under its row, indented to the stripe, and
       carries its own way out to the full run report. */
    .activity-item__reading {
        border: 1px solid var(--rule-soft);
        border-block-start: 0;
        display: grid;
        gap: 0.5rem;
        padding: 0.5rem 0.65rem 0.65rem;

        &[hidden] { display: none; }

        .measurement-inspect { margin-block-end: 0; }
    }

    .activity-item__report-link {
        color: var(--primary);
        font-family: var(--font-data);
        font-size: 0.6875rem;
        font-weight: 700;
        justify-self: end;
        letter-spacing: 0.08em;
        text-decoration: none;
        text-transform: uppercase;
    }

    .datasheet-wrapper:has(.datasheet__detail-row) { container-type: inline-size; }

    /* Way through to the check itself, under the expanded reading. */
    .datasheet__detail-link {
        color: var(--primary);
        font-weight: 700;
        margin-block-start: 0.5rem;
        text-align: end;
        text-decoration: none;
        text-transform: uppercase;
    }

    /* Run report datasheet: a measurement check's label is a <button> that
       expands its reading in the full-width detail row beneath it. Reset the
       UA button chrome so it reads exactly like the <a> labels; the caret is
       the only tell. */
    .datasheet__link--toggle {
        background: none;
        border: 0;
        cursor: pointer;
        font: inherit;
        letter-spacing: inherit;
        padding: 0;
        text-align: start;

        &::after {
            color: var(--ink-mute);
            content: " ▸";
        }
        &[aria-expanded="true"]::after { content: " ▾"; }
    }

    .datasheet__detail-row > td {
        background: var(--color-canvas);
        padding: 0.5rem;

        /* On phones the datasheet is wider than its wrapper and scrolls
           sideways. Size the reading to the visible wrapper (cqi) and pin it
           left so the charts sit in view instead of past the scroll edge. */
        > turbo-frame,
        > .datasheet__detail-link {
            display: block;
        }
        > .report-detail,
        > turbo-frame,
        > .datasheet__detail-link {
            box-sizing: border-box;
            inline-size: calc(100cqi - 1rem - 2px);
            inset-inline-start: 0.5rem;
            position: sticky;
        }

        .measurement-inspect { margin-block-end: 0; }
    }

    .activity-row__notes {
        color: var(--ink-soft);
        font-size: 0.8125rem;
        grid-column: 2 / 3;
        margin: 0.15rem 0 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .activity-row__chip { align-self: center; }

    /* Amend a completed run (execution_amend.html). Rows reuse the
       activity-row toggle; each opens a panel of small single-purpose forms. */
    .amend-subgroup { margin: 0.4rem 0 0; }

    /* No id column: titles + response, not activity-row's three tracks. */
    .amend-row { grid-template-columns: 1fr auto; }

    .amend-row__titles {
        display: grid;
        font-size: 0.8125rem;
        gap: 0.1rem;
    }

    .amend-row__sub {
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.625rem;
        letter-spacing: 0.04em;
    }

    .amend-row__missing {
        border-style: dashed;
        color: var(--ink-mute);
    }

    .amend-panel {
        display: grid;
        gap: 1rem;
    }

    .amend-panel__block,
    .amend-panel__form {
        border-block-end: 1px solid var(--rule-soft);
        display: grid;
        gap: 0.5rem;
        padding-block-end: 0.85rem;
    }

    .amend-panel__form .form-field { display: grid; gap: 0.25rem; }

    .amend-panel__severity { margin-block-start: 0.35rem; }

    .amend-verdict:not(:has(input[value="fail"]:checked)) .amend-panel__severity { display: none; }

    .amend-panel__inline {
        align-items: center;
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .amend-panel__checks { margin: 0; padding-inline-start: 1.1rem; }

    .amend-panel__link {
        color: var(--primary);
        font-family: var(--font-data);
        font-size: 0.6875rem;
        font-weight: 700;
        letter-spacing: 0.08em;
        text-decoration: none;
        text-transform: uppercase;
    }

    .amend-panel__photos {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .amend-photo {
        display: grid;
        gap: 0.25rem;
        inline-size: var(--attachment-md);
        margin: 0;

        img {
            aspect-ratio: 1;
            border: 1px solid var(--rule);
            inline-size: 100%;
            object-fit: cover;
        }
    }

    .amend-photo__remove {
        --btn-padding: 0.05rem 0.4rem;

        font-size: 0.6875rem;
        inline-size: 100%;
        justify-content: center;
    }

    .amend-log {
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.6875rem;
        letter-spacing: 0.04em;
        margin: 0;
        padding-inline-start: 1.1rem;
    }

    /* Single-column stacks for zone / unzoned / executions detail pages. */
    .execution-card-stack {
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
        margin-inline: auto;
        max-inline-size: 80ch;
    }

    /* "+ Add a check" affordance — sits alongside the cards in the stack
       on the unzoned column, full-width like an empty-zone CTA. */
    /* Control Room execution card — mirrors .check-card / .zone-card.
    /* ------------------------------------------------------------------------
    /* Used in the executions column on route_detail (collapsed in the kanban
    /* mobile flow) and on route_executions_list (full single-column view).
    /* ----------------------------------------------------------------------- */

    .execution-card {
        background: var(--surface);
        border: 1px solid var(--rule);
        box-shadow: inset 3px 0 0 var(--card-color, var(--rule));
        color: var(--ink);
        display: grid;
        gap: 0.35rem;
        padding: 0.75rem 0.9rem 0.75rem 1.05rem;
        position: relative;
        transition: border-color 120ms ease-out, box-shadow 120ms ease-out;
    }

    /* Full-card overlay link to the execution detail (the run result). The card
       body is non-interactive text, so the link sits on top and makes the whole
       card a click target. The previous `.route-card__link` class had no CSS,
       so the card was inert. */
    .execution-card__link {
        inset: 0;
        position: absolute;
        z-index: 1;

        &:focus-visible {
            outline: 2px solid var(--primary);
            outline-offset: -2px;
        }
    }

    .execution-card[data-state="check"] {
        background: var(--surface-check);
        border-color: color-mix(in oklch, var(--rule) 40%, var(--status-check));
        --card-color: var(--status-check-fg);
    }

    .execution-card[data-state="warning"] {
        background: var(--surface-warn);
        border-color: color-mix(in oklch, var(--rule) 40%, var(--status-warning));
        --card-color: var(--status-warn-fg);
    }

    .execution-card[data-state="critical"] {
        background: var(--surface-crit);
        border-color: color-mix(in oklch, var(--rule) 40%, var(--status-critical));
        --card-color: var(--status-crit-fg);
    }

    .execution-card[data-state="running"] {
        background: var(--color-considering-bg);
        border-color: color-mix(in srgb, var(--rule) 40%, var(--color-considering));
        --card-color: var(--color-considering);
    }

    @media (any-hover: hover) {
        .execution-card:hover {
            border-color: var(--primary);
            box-shadow: inset 3px 0 0 var(--card-color), 0 0 0 1px var(--primary);
        }
    }

    .execution-card__header {
        align-items: baseline;
        display: flex;
        flex-wrap: wrap;
        gap: 0 0.6ch;
    }

    .execution-card__header .status-chip {
        margin-inline-start: auto;
    }

    .execution-card__header .status-chip[data-state="running"] {
        color: var(--color-considering);
    }

    .execution-card__title {
        color: var(--ink);
        font-family: var(--font-body);
        font-size: 0.9375rem;
        font-weight: 600;
        letter-spacing: -0.005em;
        line-height: 1.25;
        margin: 0;
    }

    .execution-card__byline {
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.6875rem;
        letter-spacing: 0.04em;
        margin: 0;
    }

    .execution-card__byline strong {
        color: var(--ink);
        font-weight: 600;
    }

    .execution-card__meta {
        align-items: baseline;
        color: var(--ink-soft);
        display: flex;
        flex-wrap: wrap;
        font-family: var(--font-data);
        font-size: 0.625rem;
        gap: 0 0.75ch;
        letter-spacing: 0.08em;
        margin-block-start: 0.15rem;
        text-transform: uppercase;
    }

    .execution-card__result strong {
        color: var(--ink);
        font-weight: 700;
        margin-inline-start: 0.3ch;
    }

    .execution-card[data-state="warning"] .execution-card__result strong  { color: var(--status-warn-fg); }
    .execution-card[data-state="critical"] .execution-card__result strong { color: var(--status-crit-fg); }

    .execution-card__updated {
        color: var(--ink-faint);
        margin-inline-start: auto;
    }

    .execution-card__updated--check { color: var(--status-check-fg); font-weight: 700; }
    .execution-card__updated--minor { color: var(--status-warn-fg); font-weight: 700; }
    .execution-card__updated--major { color: var(--status-crit-fg); font-weight: 700; }

    /* Routes container — width constraints */
    .routes {
        --routes-item-padding-inline: 0;

        margin: 0 auto;
        max-inline-size: min(80ch, 100%);
    }

    /* Routes — group picker list */
    .routes__asset-list {
        list-style: none;
        margin: 0;
        padding: 0;
        padding-inline-start: var(--routes-item-padding-inline);

        /* Keyboard selection in the group picker: the same selected fill the
           nav drawer and the points section picker use, so arrows + Enter
           read the same in every combobox. */
        > [role="option"][aria-selected].list-row,
        > [role="option"][aria-selected] > .list-row {
            background-color: var(--color-selected);
        }
    }

    /* Route editor — turbo-frame layout (measurement-point select row) */
    .route-edit__item-row > turbo-frame {
        display: contents;
    }

    /* Route editor — group card (create mode only).
     *
     * Each checklist group is a card: breadcrumb header on top, stack of
     * item cards beneath. In edit mode the group is a <tbody> so these
     * card styles intentionally do not apply there. */
    div > .route-edit__group {
        --group-border: var(--rule);

        display: flex;
        flex-direction: column;
        gap: var(--space-half, 0.6em);
        padding: var(--space-half, 0.6em);
        background: var(--surface);
        border: 1px solid var(--group-border);
        border-radius: 0.5em;
        box-shadow: 0 1px 2px oklch(0% 0 0 / 0.03);
    }

    .route-edit__group-head {
        display: flex;
        align-items: center;
        gap: 0.5ch;
        min-inline-size: 0;
    }

    .route-edit__group-title {
        flex: 1 1 auto;
        min-inline-size: 0;
        margin: 0;
        font-family: var(--font-body, system-ui);
        font-size: 1em;
        line-height: 1.2;
        text-transform: none;
        letter-spacing: normal;
        overflow: hidden;

        /* Last crumb (the asset/zone name) in bold — this is the current segment */
        & .breadcrumb__item--current {
            font-weight: 700;
        }

        /* Let the breadcrumb wrap on very narrow containers rather than
           clipping the asset name. */
        flex-wrap: wrap;
    }

    .route-edit__group-actions {
        display: flex;
        gap: 0.5ch;
        flex-shrink: 0;
    }

    .route-edit__group-actions > .btn--circle {
        --btn-size: 2.75rem;
    }

    /* Stack of item cards inside a group. */
    .route-edit__item-list {
        display: flex;
        flex-direction: column;
        gap: 0.4em;
    }

    /* Item card — drag handle on the left edge + row of controls + optional photo gallery. */
    .route-edit__item {
        display: grid;
        grid-template-columns: auto 1fr;
        gap: 0 0.25em;
        padding: 0.5em 0.6em;
        padding-inline-start: 0;
        background: color-mix(in oklch, var(--rule-soft) 40%, var(--surface));
        border: 1px solid var(--rule);
        border-radius: 0.35em;
    }

    /* Drag handle sits in its own narrow column, spanning both rows. */
    .route-edit__item > .drag-handle {
        grid-row: 1 / -1;
        align-self: stretch;
        display: flex;
        align-items: center;
        padding: 0.25em 0.3em;
        border-inline-end: 1px solid var(--rule);
        margin-inline-end: 0.25em;
    }

    .route-edit__item-row {
        display: flex;
        align-items: center;
        gap: 0.5ch;
        min-inline-size: 0;
    }

    .route-edit__item-row > input[name="item_label"],
    .route-edit__item-row > turbo-frame > select[name="measurement_point"] {
        flex: 1 1 auto;
        min-inline-size: 0;
    }

    .route-edit__item-row > .btn--circle {
        --btn-size: 2.75rem;
    }

    .route-edit__item-row > .btn--negative,
    .route-edit__group-actions > .btn--negative {
        --btn-background: transparent;
        --btn-color: var(--status-crit-fg);
        --btn-border-color: var(--rule);

        @media (any-hover: hover) {
            &:hover {
                --btn-background: var(--status-crit-fg);
                --btn-color: var(--color-ink-inverted);
                --btn-border-color: var(--status-crit-fg);
            }
        }
    }

    /* Photo gallery under the item row. Inherits .attachments base styling
       from measurement_form.css; this just tightens the thumbnail size and
       hides the gallery when empty via the [hidden] attribute.
       Grid column 2 so it sits next to the drag handle, not under it. */
    .route-edit__photos {
        --attachment-height: var(--attachment-md);
        grid-column: 2;
        margin: 0;
    }

    /* Empty-state upload placeholder inside the photos strip. */
    .attachment--upload {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 0.25rem;
        block-size: var(--attachment-height, var(--attachment-md));
        aspect-ratio: 1;
        border: 2px dashed var(--rule);
        border-radius: var(--radius-s, 6px);
        cursor: pointer;

        &:hover {
            border-color: var(--primary);
            color: var(--primary);
        }
    }

    /* Route editor — item row reflow on narrow containers.
     *
     * The row packs label + type + optional camera + move + remove.
     * The drag handle is outside the row (in its own grid column), so
     * the row only needs to worry about its own controls. On narrow
     * viewports the row wraps onto two lines:
     *
     * Narrow layout:
     *   row 1: [label — full width]
     *   row 2: [type select — grows] [camera?] [move] [remove]
     */
    [data-route-editor-target="itemList"] {
        container-type: inline-size;
        container-name: route-item-list;
    }

    @container route-item-list (max-width: 55ch) {
        .route-edit__item-row {
            flex-wrap: wrap;
        }

        /* Label input OR measurement-point select (inside display:contents
           turbo-frame) takes the full row width,
           pushing the action cluster onto row 2. */
        .route-edit__item-row > input[name="item_label"],
        .route-edit__item-row > turbo-frame > select[name="measurement_point"] {
            flex: 1 1 100%;
            min-inline-size: 0;
        }

        /* Type select grows to fill the action row. */
        .route-edit__item-row > select[name="item_type"] {
            flex: 1 1 auto;
            min-inline-size: 0;
        }
    }

    /* Route editor — drag-and-drop affordances */
    .drag-handle {
        display: inline-flex;
        cursor: grab;
        padding: 0.25em;
    }

    .drag-handle:active {
        cursor: grabbing;
    }

    .sortable-ghost {
        opacity: 0.3;
    }

    .sortable-chosen {
        box-shadow: 0 2px 8px oklch(0% 0 0 / 0.15);
    }

    [data-route-editor-target="itemList"]:empty {
        min-block-size: 2em;
        border: 1px dashed var(--color-ink-lighter);
        border-radius: 0.5em;
    }

    /* Route editor — datasheet table variant (edit mode).
     * Groups are <tbody> rows, items are <tr> within each group.
     * The drag handle sits in the first narrow column; actions in the last. */

    .route-edit__table {
        margin-block-start: 0.25rem;

        /* Override standard datasheet thead padding — no triangle gutter needed here */
        & thead th:first-child {
            padding-inline-start: 0.55rem;
        }

        /* Grip column — fixed narrow width for drag handles */
        & thead th:first-child,
        & td:first-child {
            inline-size: 2rem;
            padding-inline: 0.3rem;
            text-align: center;
        }

        /* Actions column — narrow padding, no wrap */
        & thead th:last-child,
        & td:last-child {
            padding-inline: 0.3rem;
            white-space: nowrap;
        }

        /* Group-delete th — padding only; flex lives on the inner div */
        & .route-edit__group-delete {
            padding-inline: 0.3rem;
        }

        & .route-edit__group-delete__inner,
        & .route-edit__item-actions-cell__inner {
            display: flex;
            align-items: center;
            justify-content: flex-end;
            gap: 0.25rem;
        }

        & .datasheet__group-head th:not(.route-edit__group-delete) {
            padding-block: 0.5rem;
            padding-inline: 0.55rem;
        }
    }

    .route-edit__group-delete__inner > .btn--circle,
    .route-edit__item-actions-cell__inner > .btn--circle {
        --btn-size: 1.75rem;

        &:not(.btn--negative) {
            --btn-background: transparent;
            --btn-color: var(--ink-faint);
            @media (any-hover: hover) {
                &:hover {
                    --btn-background: var(--surface-sunken);
                    --btn-color: var(--ink);
                }
            }
        }

        &.btn--negative {
            --btn-background: transparent;
            --btn-color: var(--status-crit-fg);
            @media (any-hover: hover) {
                &:hover {
                    --btn-background: var(--status-crit-fg);
                    --btn-color: var(--color-ink-inverted);
                    --btn-border-color: var(--status-crit-fg);
                }
            }
        }
    }

    /* Empty tbody drop-target when all items have been moved out */
    .route-edit__table tbody[data-route-editor-target="itemList"]:not(:has([data-item])) {
        & > tr:not(.datasheet__group-head) {
            display: none;
        }
    }

    /* Sortable ghost / chosen inside the table */
    .route-edit__table .sortable-ghost td,
    .route-edit__table .sortable-ghost th {
        opacity: 0.35;
    }

    /* Execution UI */

    /* In normal execute mode the parent .form-sheet provides the page-width
       cap and inline padding; capture mode overrides via .routes--execute-capture. */
    .routes--execute {
        max-inline-size: 100%;
    }

    .routes--execute .exec-list {
        gap: 0.75rem;
    }

    .routes--execute .exec-list__group {
        gap: 0.25rem;
    }

    .routes--execute .exec-list__heading {
        border-block-end: 1px solid var(--rule-soft);
        min-block-size: 2.1rem;
        padding-block-end: 0.35rem;
    }

    .routes--execute .exec-row {
        gap: 0.2rem 0.75rem;
        grid-template-columns: minmax(7rem, 0.75fr) minmax(0, 1.35fr) auto auto;
        min-block-size: 3rem;
        padding: 0.55rem 0.65rem 0.55rem 0.8rem;
    }

    .routes--execute .exec-row__kind,
    .routes--execute .exec-row__loc {
        grid-column: 1 / 2;
    }

    .routes--execute .exec-row__label {
        align-self: center;
        font-size: 0.95rem;
        grid-column: 2 / 3;
        grid-row: 1 / 3;
        min-inline-size: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .routes--execute .exec-row__chip {
        grid-column: 3 / 4;
    }

    .routes--execute .exec-row__chev {
        grid-column: 4 / 5;
    }

    /* Wide screens: cards fill their column. State is conveyed by color and
       the pass/fail toggle; the old left/right slide layout is gone now that
       cards live inside zone columns on the execute board. */

    /* Severity pill — independent of pass/fail; thumb colored per level
       (yellow=minor, red=major). Driven by its own data-severity attr. */
    .execution__toggle--severity {
        --toggle-w: 9ch;
    }

    /* Card footer — photo upload + rich-text note.
       Uses the same building blocks as the measurement form so every card,
       regardless of item_type, shares the same note/photo affordances. */

    /* Measurement form when embedded inline inside an execution card —
       tighter gaps, no oversized page margins, subtle auto-save hint. */
    .measurement-form--inline {
        gap: var(--space-half, 0.75em);
    }

    /* Saved measurement partial — compact embedded card that mirrors the
       measurement detail view's layout (numbered .card__board, status
       badge, .card__meta readouts, notes, thermogram gallery) while
       sitting inside the route-execution wizard card. The `.card` base
       already supplies the --card-color chrome; these rules just tighten
       spacing so the embedded card doesn't feel cavernous and wire up the
       actions footer.

       The outer <turbo-frame> gets display:contents from base.css, so
       .measurement-saved__card IS the visible container. */
    .measurement-saved__card {
        --card-padding-block: var(--space-half, 0.6em);
        --card-padding-inline: 1ch;
        gap: 0.5em;
        box-shadow: none;
        border: 1px solid color-mix(in srgb, var(--card-color) 28%, transparent);
    }

    .measurement-saved__card[data-severity="check"] { --card-color: oklch(var(--lch-aqua-medium)); }
    .measurement-saved__card[data-severity="minor"] { --card-color: oklch(var(--lch-yellow-medium)); }
    .measurement-saved__card[data-severity="major"] { --card-color: oklch(var(--lch-red-medium)); }

    .measurement-saved__body {
        display: flex;
        flex-direction: column;
        gap: 0.6em;
    }

    .measurement-saved__body > .card__meta {
        gap: 0.5ch 1.25ch;
    }

    .measurement-saved__attachments {
        --attachment-size: var(--attachment-sm);
        gap: 0.4em;
    }

    /* Empty grid is kept in the DOM purely as an append-target for the
       inline uploader; collapse it so it doesn't leave a visual gap
       above the "Add another thermograph" button. */
    .measurement-saved__attachments--empty:empty {
        display: none;
    }

    /* Inline thermograph upload-row on the saved measurement — uses the
       same .measurement-form__upload-btn chrome as the capture form, just
       tightened for the compact saved-card context. */
    .measurement-saved__upload-row .measurement-form__upload-btn {
        min-block-size: 2.8em;
        padding-block: 0.5em;
        padding-inline: 1em;
        font-size: var(--text-small, 0.9em);
    }

    .measurement-saved__upload-row [data-controller*="thermogram-upload"].is-uploading {
        opacity: 0.55;
        pointer-events: none;
    }

    .measurement-saved__actions {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.25ch;
        margin-block-start: 0.25em;
        padding-block-start: 0.4em;
        border-block-start: 1px dashed color-mix(in srgb, var(--card-color) 20%, var(--color-ink-lighter));
    }

    .measurement-saved__detail-link {
        margin-inline-start: auto;
    }

    /* Bare comment wrap (no avatar, compact Trix) — applied to every note
       inside a route execution, on both measurement and non-measurement
       cards, so the Trix editor + toolbar render identically everywhere. */
    .measurement-form__comments-wrap--bare {
        --comment-padding-inline: 0;

        & .comment {
            padding: 0;
            gap: 0;
        }

        & .django-prose-editor-container {
            inline-size: 100%;
        }

        & trix-editor {
            min-block-size: 3.1em;
            padding: 0.4em 0.6em;
            border-radius: 0.35em;
            border: 1px solid var(--color-ink-lighter);
            background: var(--color-canvas);
            font-size: var(--text-small, 1em);
        }

        & trix-toolbar {
            margin-block-end: 0.25em;
        }
    }

    @media (max-width: 99.99ch) {
        .measurement-form__comments-wrap--bare {
            & trix-editor {
                min-block-size: 5em;
                font-size: 1.15em;
                padding: 0.75em 0.95em;
            }
        }
    }

    /* ------------------------------------------------------------------------ */
    /* Read-only execution detail                                                */
    /* ------------------------------------------------------------------------ */

    /* Readonly cards inherit the capture-flow's left/right anchoring so pass
       reads as "left, accepted" and fail as "right, flagged" — keeps the same
       spatial grammar between capture and report. */

    /* Steps — checklist items inside multi-check cards
    /* ---------------------------------------------------------------- */
    .steps {
        display: flex;
        flex-direction: column;
        gap: 0;
        list-style: none;
        margin: 0;
        padding: 0;
    }

    .step {
        display: grid;
        grid-template-columns: 1em 1fr auto;
        gap: calc(var(--inline-space, 0.5rem) * 2 / 3);
        align-items: baseline;
        padding-block: 0.15em;
    }

    .step__checkbox {
        accent-color: var(--card-color, currentColor);
    }

    .step__content {
        border-bottom: 1px solid transparent;
        font-weight: 500;

        .step:has(:checked) & {
            opacity: 0.7;
            text-decoration: line-through;
        }
    }

    input.step__content {
        background: transparent;
        border: 0;
        border-bottom: 1px solid transparent;
        color: inherit;
        font: inherit;
        outline: none;
        padding: 0;

        &:hover { border-bottom-color: var(--rule-soft); }
        &:focus { border-bottom-color: var(--ink-soft); }
    }

    .step__delete {
        background: transparent;
        border: 0;
        color: var(--ink-faint);
        cursor: pointer;
        font-size: 1.1em;
        line-height: 1;
        padding: 0 0.4ch;

        &:hover { color: var(--status-crit-fg, var(--ink)); }
    }

    .step__content:is(a) {
        color: inherit;
    }

    .step__new {
        opacity: 0.5;

        .input {
            background: transparent;
            border: none;
            font: inherit;
            outline: none;
            padding: 0;

            &::placeholder {
                color: currentColor;
                opacity: 0.5;
            }
        }
    }

    /* Card detail (card-perma) — route item detail screen

    /* ── Phase 7b — execution list + detail (server-rendered) ─────────
       `.exec-list`: flat list of checks, grouped by heading. Each row
       is a hyperlink to `?item=<uuid>` — no client-side wizard state.
       `.exec-nav`: prev / all / next bar on the detail page. */
    .exec-list {
        display: flex;
        flex-direction: column;
        gap: 1rem;
        list-style: none;
        margin: 0;
        padding: 0;
    }

    .exec-list__group {
        display: flex;
        flex-direction: column;
        gap: 0.4rem;
    }

    .exec-list__heading {
        align-items: baseline;
        color: var(--ink);
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem 0.75rem;
        margin: 0 0 0.2rem;
    }

    .exec-list__heading-name {
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.8125rem;
        font-weight: 700;
        letter-spacing: 0.14em;
        text-transform: uppercase;
    }

    .exec-list__count {
        color: var(--ink-faint);
        font-family: var(--font-data);
        font-size: 0.625rem;
        letter-spacing: 0.12em;
        margin-inline-start: auto;
        text-transform: uppercase;
    }

    .exec-row {
        align-items: center;
        background: var(--surface);
        border: 1px solid var(--rule);
        box-shadow: inset 3px 0 0 var(--card-color, var(--rule-soft));
        color: var(--ink);
        cursor: pointer;
        display: grid;
        gap: 0.2rem 0.85rem;
        grid-template-columns: 1fr auto auto;
        min-block-size: 4.25rem;
        padding: 0.75rem 0.85rem 0.75rem 1rem;
        /* Breathing room above the row when the resume scroll targets it
           (scrollIntoView block:start) — keeps the group heading visible. */
        scroll-margin-block-start: 6rem;
        text-decoration: none;
        transition: border-color 120ms ease-out, box-shadow 120ms ease-out;

        @media (any-hover: hover) {
            &:hover {
                border-color: var(--primary);
                box-shadow: inset 3px 0 0 var(--card-color, var(--primary)), 0 0 0 1px var(--primary);
                color: var(--primary);
            }
        }
    }

    .exec-row[data-done-status="pass"] {
        --card-color: var(--status-nominal);
    }

    .exec-row[data-done-status="fail"] {
        --card-color: var(--status-critical);
        background: var(--surface-warn);
    }

    .exec-row[data-done-status="measured"] {
        --card-color: var(--primary);
    }

    /* Transient highlight applied by execution_controller on resume so the */
    /* first incomplete check is visible once scrolled into view. */
    .exec-row--resume-target {
        animation: exec-row-resume 2.4s ease-out;
    }

    @keyframes exec-row-resume {
        0%,
        65% {
            border-color: var(--primary);
            box-shadow: inset 3px 0 0 var(--card-color, var(--primary)), 0 0 0 2px var(--primary);
        }

        100% {
            border-color: var(--rule);
            box-shadow: inset 3px 0 0 var(--card-color, var(--rule-soft));
        }
    }

    .exec-row__kind {
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.625rem;
        font-weight: 700;
        grid-column: 1 / 2;
        letter-spacing: 0.14em;
        text-transform: uppercase;
    }

    .exec-row__loc {
        color: var(--ink-faint);
        font-family: var(--font-data);
        font-size: 0.625rem;
        font-weight: 500;
        grid-column: 1 / 2;
        letter-spacing: 0.1em;
        text-transform: uppercase;
    }

    .exec-row__label {
        color: var(--ink);
        font-size: 1rem;
        font-weight: 600;
        grid-column: 1 / 2;
        grid-row: 2;
        letter-spacing: -0.01em;
        line-height: 1.2;
    }

    .exec-row__chip {
        align-self: center;
        color: var(--ink-faint);
        font-family: var(--font-data);
        font-size: 0.6875rem;
        font-weight: 700;
        grid-column: 2 / 3;
        grid-row: 1 / 3;
        letter-spacing: 0.14em;
        padding: 0.2rem 0.5rem;
    }

    .exec-row__chip--pass {
        background: var(--status-nominal);
        color: var(--color-ink-inverted);
    }

    .exec-row__chip--fail {
        background: var(--status-critical);
        color: var(--color-ink-inverted);
    }

    .exec-row__chip--measured {
        background: var(--primary);
        color: var(--color-ink-inverted);
    }

    .exec-row__chip--pending {
        color: var(--ink-faint);
    }

    .exec-row__chev {
        align-self: center;
        color: var(--ink-soft);
        grid-column: 3 / 4;
        grid-row: 1 / 3;
    }

    @media (max-width: 52ch) {
        .exec-row {
            grid-template-columns: 1fr auto auto;
        }

        .exec-row__kind {
            grid-column: 1 / 2;
            grid-row: 1;
        }

        .exec-row__label {
            grid-column: 1 / 2;
            grid-row: 2;
        }

        .exec-row__loc {
            grid-column: 1 / 2;
            grid-row: 3;
        }

        .exec-row__chip {
            grid-column: 2 / 3;
            grid-row: 1 / 4;
        }

        .exec-row__chev {
            grid-column: 3 / 4;
            grid-row: 1 / 4;
        }

        .exec-list__count {
            margin-inline-start: 0;
        }
    }
}

/* ── Capture viewport — full-screen, no-scroll single-item execution UI ──
   Separate @layer modules block to avoid Chrome CSS-nesting parse context
   from the hover rule above treating these as nested rules.              */
@layer modules {
    body:has(.capture-viewport) {
        overflow: hidden;
    }

    body:has(.capture-viewport) #global-container {
        display: flex;
        flex-direction: column;
        height: 100dvh;
        overflow: hidden;
    }

    body:has(.capture-viewport) #main {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-block-size: 0;
        overflow: hidden;
        padding-inline: 0;
    }

    body:has(.capture-viewport) .routes--execute-capture {
        display: flex;
        flex: 1;
        flex-direction: column;
        inline-size: 100%;
        margin-inline: 0;
        max-inline-size: 100%;
        min-block-size: 0;
        overflow: hidden;
        padding: 0;
    }

    .capture-viewport {
        display: flex;
        flex-direction: column;
        flex: 1;
        overflow: hidden;
    }

    .capture-strip {
        background: var(--surface-sunken);
        border-block: 1px solid var(--rule-soft);
        display: flex;
        justify-content: space-between;
        align-items: center;
        flex-shrink: 0;
        gap: 0.5rem;
        padding: 0.35rem 1rem;
    }

    .capture-strip__asset {
        color: var(--ink-faint);
        font-family: var(--font-data);
        font-size: 0.5625rem;
        letter-spacing: 0.1em;
        text-align: right;
        text-transform: uppercase;
    }

    .point-stepper {
        display: flex;
        flex-shrink: 0;
        gap: 0.2rem;
        padding: 0.5rem 1rem 0;
    }

    .point-stepper__seg {
        background: var(--rule-soft);
        block-size: 0.25rem;
        border: 0;
        cursor: pointer;
        flex: 1;
        padding: 0;
        text-decoration: none;
        transition: background 120ms ease-out;
    }

    /* State fills mirror the severity palette: minor fails amber, major
       fails red. The current position is an outline layered over whatever
       state fill the segment has — a solid accent fill read as "major red". */
    .point-stepper__seg--pass       { background: var(--status-nominal); }
    .point-stepper__seg--fail       { background: var(--status-warning); }
    .point-stepper__seg--fail-major { background: var(--status-critical); }
    .point-stepper__seg--done       { background: var(--ink-soft); }

    .point-stepper__seg--active {
        outline: 2px solid var(--primary);
        outline-offset: 1px;
    }

    .point-stepper__labels {
        color: var(--ink-faint);
        display: flex;
        flex-shrink: 0;
        font-family: var(--font-data);
        font-size: 0.5625rem;
        font-weight: 700;
        justify-content: space-between;
        letter-spacing: 0.14em;
        padding: 0.25rem 1rem 0.35rem;
        text-transform: uppercase;
    }

    .capture-body {
        -webkit-overflow-scrolling: touch;
        flex: 1;
        min-block-size: 0;
        overflow-y: auto;
        padding: 0.5rem 1rem;
    }

    .capture-body .capture {
        background: transparent;
        border: 0;
        padding: 0;
    }

    .capture-body .capture,
    .capture-body form {
        display: flex;
        flex-direction: column;
        min-block-size: 100%;
    }

    .capture-nav {
        display: grid;
        flex-shrink: 0;
        grid-template-columns: repeat(3, 1fr);
        gap: 0.5rem;
        padding: 0.5rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
    }

    .capture-nav .thumb-action {
        align-items: center;
        border: 1px solid var(--rule);
        color: var(--ink);
        display: flex;
        gap: 0.4rem;
        inline-size: auto;
        justify-content: center;
        min-block-size: 3rem;
        padding-inline: 0.5rem;
        text-decoration: none;
        transition: background 120ms ease-out, border-color 120ms ease-out, color 120ms ease-out;
    }

    .capture-nav .thumb-action[aria-disabled="true"] {
        border-color: var(--rule-soft);
        color: var(--ink-faint);
        cursor: default;
        pointer-events: none;
    }

    .capture-nav__clear {
        background: var(--surface-sunken);
        border-color: transparent;
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.625rem;
        font-weight: 700;
        letter-spacing: 0.12em;
        text-transform: uppercase;
    }

    .capture-nav__clear:hover,
    .capture-nav__clear:focus-visible {
        color: var(--status-critical);
    }

    /* Middle cell stacks Clear over a one-line mono save caption. The     */
    /* caption keeps its line reserved so the first save does not shift  */
    /* the bar; uppercase comes from CSS so screen readers get plain text. */
    .capture-nav__middle {
        display: flex;
        flex-direction: column;
        gap: 0.25rem;
        min-inline-size: 0;

        > .capture-nav__clear {
            flex: 1;
        }
    }

    .capture-nav__status {
        color: var(--ink-soft);
        font-family: var(--font-data);
        font-size: 0.5625rem;
        letter-spacing: 0.1em;
        line-height: 1;
        min-block-size: 1em;
        overflow: hidden;
        text-align: center;
        text-overflow: ellipsis;
        text-transform: uppercase;
        white-space: nowrap;

        &[data-save-state="failed"] {
            color: var(--status-crit-fg);
            font-weight: 700;
        }
    }

    .capture-nav__next {
        background: var(--surface);
    }

    .capture-viewport:has([data-execution-card]:not([data-state="pending"])) .capture-nav__next {
        background: var(--primary);
        border-color: var(--primary);
        color: var(--on-primary);
    }

    /* ── Filter strip ─────────────────────────────────────────────────── */

    .rl-filter-strip {
        align-items: center;
        border-block-end: 1px solid var(--rule-soft);
        display: flex;
        flex-wrap: nowrap;
        gap: 0.375rem;
        margin-block-end: 0.75rem;
        overflow-x: auto;
        padding-block: 0.75rem;
    }

    .rl-pill {
        align-items: center;
        border: 1px solid var(--rule);
        border-radius: 2px;
        color: var(--ink-soft);
        cursor: pointer;
        display: inline-flex;
        flex-shrink: 0;
        font-family: var(--font-data);
        font-size: 0.6875rem;
        font-weight: 700;
        gap: 0;
        letter-spacing: 0.012em;
        padding: 0.3125rem 0.625rem;
        text-decoration: none;
        transition: background 80ms, color 80ms, border-color 80ms;

        &:hover { background: var(--surface-sunken); color: var(--ink); }
    }

    .rl-pill--active {
        background: var(--ink);
        border-color: var(--ink);
        color: var(--surface);
    }

    .rl-pill__count {
        margin-inline-start: 0.25rem;
        opacity: 0.55;
    }

    .rl-pill--active .rl-pill__count { opacity: 0.65; }

    /* Route-list datasheet: hide secondary columns on narrow screens */
    @media (max-width: 99.99ch) {
        .rl-datasheet th[data-col="checks"],
        .rl-datasheet td[data-col="checks"],
        .rl-datasheet th[data-col="date"],
        .rl-datasheet td[data-col="date"] {
            display: none;
        }
    }

    /* ── Flat stops table (route_detail checklist) ───────────────────── */

    .rd-stops-section {
        margin-inline: auto;
        max-inline-size: var(--main-width);
        padding-block-end: var(--block-space);
        text-align: start;
    }

    .rd-stops-stage {
        border-block-end: 1px solid var(--rule-soft);
        padding-block-start: 1.25rem;
    }

    .rd-stops-stage__head {
        padding-inline: 2.5rem;

        @media (max-width: 100ch) {
            padding-inline: 1rem;
        }
    }

    .rd-stops-stage .datasheet-wrapper {
        padding-inline: 2.5rem;

        @media (max-width: 100ch) {
            padding-inline: 0;
        }
    }

    /* Route report — trend/finding content in the results detail row */
    .datasheet__limit {
        color: var(--color-ink-dark);
        font-size: 0.8em;
        white-space: nowrap;
    }

    /* minmax(0, …): a plain 1fr track grows to the chart's pre-fit 700px
       Plotly default and overflows the phone viewport. */
    .report-detail {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        gap: 0.75rem;
        padding: 0.75rem 1rem;
    }
    .report-detail__trend {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        gap: 0.5rem;
    }
    .report-detail__chart {
        inline-size: 100%;
        block-size: 140px;
    }
    .report-detail__stats {
        display: flex;
        flex-wrap: wrap;
        gap: 1.25rem;
        margin: 0;
    }
    .report-detail__stat {
        display: flex;
        flex-direction: column;
        gap: 0.1rem;
    }
    .report-detail__stat dt {
        font-size: 0.75em;
        text-transform: uppercase;
        color: var(--color-ink-dark);
    }
    .report-detail__breakdown {
        display: flex;
        flex-wrap: wrap;
        gap: 0.75rem;
    }
    .trend--up { color: oklch(var(--lch-red-medium)); }
    .trend--down { color: oklch(var(--lch-green-medium)); }

    @media (min-width: 100ch) {
        .report-detail__trend {
            grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
            align-items: center;
        }
    }
}
