/*  pupillometry.css — pupillary evaluation view
 *
 *  On the portal palette (see DESIGN.md). The component paints NO ground of its own: the page's
 *  --newton-blue-1 shows through, and structure comes from cards sitting on it, exactly as
 *  MeasurementComponent's .lsiCard does. That is why there is no --pup-paper any more.
 *
 *  Card recipe, lifted from .lsiCard so the two components read as one family:
 *      background var(--newton-blue-2) · border 1px solid rgba(20,53,80,.14)
 *      border-radius 12px · box-shadow var(--box-shadow-1)
 *  Recessed blocks INSIDE a card drop to --newton-blue-1 with a --newton-blue-4 hairline.
 *
 *  Width is Bootstrap's .container-md on the root element, the same one MeasurementComponent
 *  uses, so the two cap and centre identically when the visit rail switches between them.
 *
 *  ⚠ Bootstrap's text-muted (#6c757d), btn-link and btn-secondary are built for white grounds
 *    and are close to invisible here. Every colour below comes from the palette instead.
 *
 *  Every rule is scoped under .pup-exam and every class is pup-prefixed: Bootstrap is loaded
 *  globally and styles bare elements this file also styles.
 */

.pup-exam,
.pup-page {
    /* Ground and cards */
    --pup-card: var(--newton-blue-2);
    --pup-card-edge: rgba(20, 53, 80, .14);
    --pup-recess: var(--newton-blue-1);
    --pup-band: var(--newton-blue-3);
    --pup-rule: var(--newton-blue-4);
    --pup-rule-soft: rgba(46, 46, 77, .55);
    /*  Ink — mostly white, as on the binocular exam, where MainLayout's `body { color: white }`
        carries almost every string and grey is the exception rather than the rule. Each tier here
        is one step brighter than the mockup's, and grey now only marks genuinely secondary text:
        units, sub-labels, and values that do not apply.  */
    --pup-ink: #fff;
    --pup-ink-strong: #fff;
    --pup-ink-2: #d7d7e4;
    --pup-ink-3: #b6bacd;
    --pup-ink-4: #8f8fa8;
    /* Eyes. OD is green, OS is blue, everywhere, without exception. */
    --pup-od: #70CB46;
    --pup-os: #4DA3E8;
    --pup-near: #9E86D8;
    /* State. Text tones and fill tones are NOT interchangeable: #DB1623 is the palette's error
       fill and is too dark to read as text on --newton-blue-2, so text uses #ff8a8a — the same
       pair PendingResultPlaceholder uses in this very column. */
    --pup-alert: #ff8a8a;
    --pup-alert-fill: #DB1623;
    --pup-alert-bg: rgba(219, 22, 35, .13);
    --pup-watch: #dfa03a;
    --pup-watch-bg: rgba(223, 160, 58, .13);
    --pup-ok: #3fc06d;
    --pup-ok-bg: rgba(63, 192, 109, .11);
    --pup-accent: #008fdb;
    --pup-spark: #8f8fa8;
    --pup-spark-threshold: #dfa03a;
    /* The waveform field — a recess inside its card, not an inverted surface any more */
    --pup-field: var(--newton-blue-1);
    --pup-field-grid: var(--newton-blue-4);
    --pup-field-tick: #8f8fa8;
    --pup-field-lab: #6f6f88;
    --pup-field-line: #d7d7e4;
    --pup-field-chrome: var(--newton-blue-3);
    --pup-field-edge: var(--newton-blue-4);
    --pup-field-dim: #8f8fa8;
    --pup-t75: #7a6336;
    --pup-t75-label: #dfa03a;
    --pup-lost: #dfa03a;
    --pup-sans: var(--font-primary, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);

    color: var(--pup-ink);
    font-family: var(--pup-sans);
    font-size: 1rem;
    line-height: 1.5;
    font-feature-settings: "tnum" 1;
    -webkit-font-smoothing: antialiased;
}

.pup-exam {
    padding-bottom: 2.5rem;
}

.pup-exam *,
.pup-page * {
    box-sizing: border-box;
}

/*  ── the card ────────────────────────────────────────────────────────────────────────────
    Matches .lsiCard in MeasurementComponent. Change one, change the other.

    ⚠ NO HORIZONTAL OFFSET HERE, DELIBERATELY. Matching the binocular card's edge is done in
    the markup, by putting these inside the same .row > .px-0 wrapper MeasurementComponent uses
    — see the comment there. An earlier attempt computed the offset that wrapper produces and
    hardcoded it as margin-inline: -12px; that is only correct while --bs-gutter-x resolves to
    1.5rem, which .container-md inherits from whatever ancestor sets it. Reproducing the chain
    is exact at any gutter; arithmetic against one is exact at one.

    Padding is 1rem to match the .p-3 inside .lsiCard, so the card contents line up too, not
    just the edges.  */
.pup-card {
    background: var(--pup-card);
    border: 1px solid var(--pup-card-edge);
    border-radius: 12px;
    box-shadow: var(--box-shadow-1);
    padding: 1rem;
    margin: 1.5rem 0 0;
    overflow: hidden;
}

/*  ── banner ──────────────────────────────────────────────────────────────────────────────
    Mirrors MeasurementComponent's opening row: a grow-to-fill title slot and the Actions menu
    on the right, in a wrapper with the same 10px inset. The slot is empty because this
    component has no title — which is also what the binocular exam renders on the visit page,
    where its h3 is hidden. Same structure, so the button lands on the same pixel in both.  */
.pup-banner {
    display: flex;
}

.pup-banner-main {
    flex-grow: 1;
    min-width: 0;
}

.pup-banner-actions {
    flex: none;
    padding-right: 10px;
}

/*  The measurement date, as the binocular exam states it: a <p> carrying Bootstrap's 1rem
    margin-bottom, a light-weight label, then the value. */
/*  ⚠ NO font-size, so this inherits the 1rem body size the binocular exam's date <p> gets —
    .pup-exam's own 14.5px base would render it two points smaller than the line it is supposed
    to match. Weight is left to the cascade for the same reason: the value takes body's
    --fw-regular and only the label goes light, which is exactly what .thin-text does over
    there.  */
.pup-date {
    margin: 0 0 1rem;
    color: var(--pup-ink);
    font-size: 1rem;
}

/*  Mirrors .thin-text in MeasurementComponent — weight only. ⚠ Do not add a colour: the label
    is the same ink as the value on the binocular exam, and greying it here is what made this
    line read as a different weight when the weights were already identical.  */
.pup-thin {
    font-weight: var(--fw-light);
}

/* ── provenance bar ───────────────────────────────────────────────────────────────────────── */

.pup-idbar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    align-items: center;
    justify-content: space-between;
    padding: 0 0 .75rem;
}

.pup-meta {
    font-size: .88rem;
    color: var(--pup-ink-3);
}

    .pup-meta span {
        margin-right: 14px;
        white-space: nowrap;
    }

.pup-qual {
    font-size: .83rem;
    font-weight: var(--fw-bold);
    border: 1px solid var(--pup-rule);
    background: var(--pup-recess);
    border-radius: 999px;
    padding: 3px 12px 4px;
    display: inline-block;
    color: var(--pup-ink-2);
    white-space: nowrap;
}

    .pup-qual.pup-good {
        color: var(--pup-ok);
        border-color: rgba(63, 192, 109, .4);
        background: var(--pup-ok-bg);
    }

    .pup-qual.pup-warn {
        color: var(--pup-watch);
        border-color: rgba(223, 160, 58, .4);
        background: var(--pup-watch-bg);
    }

/* ── the answer card ──────────────────────────────────────────────────────────────────────── */

/*  ── the answer card's grid ──────────────────────────────────────────────────────────────
    Five children, no wrappers: chips, findings bar, summary matrix, resting stills, impression.

    ⚠ A GRID SPECIFICALLY SO THE STILLS CAN CHANGE PARTNERS. Wide, they sit beside the matrix;
    below 1200 they pair with the chips instead. Those are two different rows, and a flex wrapper
    would have to reparent the element to do it — grid-template-areas moves it without touching
    the DOM.

    ⚠ DOM order is the reading order (chips → findings → matrix → stills → impression) and does
    NOT follow the visual order below 1200, where the stills move up beside the chips. That is the
    accepted cost of the reflow; the stills carry their own captions, so nothing is orphaned.  */
.pup-top {
    display: grid;
    gap: 14px 20px;
    align-items: start;
    grid-template-columns: minmax(0, 800px) minmax(242px, 1fr);
    grid-template-areas:
        "chips chips"
        "find  find"
        "sum   iris"
        "imp   imp";
}

.pup-perrla  { grid-area: chips; }
.pup-findbar { grid-area: find; }
.pup-sumcard { grid-area: sum; }
.pup-irispair { grid-area: iris; }
.pup-imp     { grid-area: imp; }

.pup-perrla {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}

.pup-pchip {
    display: flex;
    align-items: baseline;
    gap: 6px;
    border: 1px solid var(--pup-rule);
    background: var(--pup-recess);
    border-radius: 8px;
    padding: 6px 10px 7px;
    font-size: .85rem;
    min-width: 0;
    overflow: hidden;
}

    /*  Telerik's CheckCircle, matching the patient-merge dialog. .k-icon carries its own
        font-size, so the glyph has to be sized here or it ignores the chip's type scale.  */
    .pup-pchip .pup-tick {
        color: var(--pup-ok);
        flex: 0 0 auto;
        display: inline-flex;
        align-items: center;
        align-self: center;
    }

        .pup-pchip .pup-tick .k-icon {
            font-size: 1rem;
        }

        .pup-pchip .pup-tick.pup-off {
            visibility: hidden;
        }

    .pup-pchip b {
        font-weight: var(--fw-bold);
        color: var(--pup-ink);
        white-space: nowrap;
    }

    .pup-pchip .pup-chipval {
        color: var(--pup-ink-3);
        font-size: .83rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        margin-left: auto;
    }

    .pup-pchip.pup-bad {
        border-color: rgba(219, 22, 35, .45);
        background: var(--pup-alert-bg);
    }

        .pup-pchip.pup-bad b,
        .pup-pchip.pup-bad .pup-chipval {
            color: var(--pup-alert);
        }

/*  Findings bar. Renders even when empty — a clean exam and a section that failed to load must
    not look the same. */
.pup-findbar {
    background: var(--pup-recess);
    border: 1px solid var(--pup-rule);
    border-radius: 8px;
    overflow: hidden;
}

    .pup-findbar table {
        width: 100%;
        border-collapse: collapse;
        table-layout: fixed;
    }

    .pup-findbar th {
        text-align: left;
        font-size: .72rem;
        font-weight: var(--fw-bold);
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--pup-ink-4);
        padding: 7px 12px 6px;
        background: var(--pup-band);
        border-bottom: 1px solid var(--pup-rule);
    }

    .pup-findbar td {
        padding: 0 12px;
        height: 40px;
        font-size: .875rem;
        border-bottom: 1px solid var(--pup-rule-soft);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .pup-findbar tr:last-child td {
        border-bottom: none;
    }

    .pup-findbar col.pup-c1 { width: 31%; }
    .pup-findbar col.pup-c2 { width: 8%; }
    .pup-findbar col.pup-c3 { width: 19%; }
    .pup-findbar col.pup-c4 { width: 17%; }
    .pup-findbar col.pup-c5 { width: 25%; }

    .pup-findbar td.pup-f-name {
        font-weight: var(--fw-bold);
        color: var(--pup-ink-strong);
    }

    .pup-findbar td.pup-f-side {
        font-weight: var(--fw-bold);
        color: var(--pup-alert);
    }

    .pup-findbar td.pup-f-val { font-variant-numeric: tabular-nums; }

    .pup-findbar td.pup-f-thr {
        color: var(--pup-ink-3);
        font-variant-numeric: tabular-nums;
    }

    .pup-findbar td.pup-f-act {
        font-weight: var(--fw-bold);
        color: var(--pup-alert);
    }

    .pup-findbar td.pup-f-none { color: var(--pup-ink-2); }

        .pup-findbar td.pup-f-none b {
            color: var(--pup-ok);
            margin-right: 7px;
        }

            .pup-findbar td.pup-f-none b .k-icon {
                font-size: 1rem;
                vertical-align: -3px;
            }

/*  Summary — an OD/OS matrix, not composed prose. */
.pup-sumcard {
    flex: 1 1 auto;
    min-width: 0;

    /*  Capped so the matrix stops growing on a wide screen. Two eye columns of 104px against a
        label column that has nothing left to say past this width — the rest of the row is better
        spent on the stills.  */
    background: var(--pup-recess);
    border: 1px solid var(--pup-rule);
    border-radius: 8px;
    overflow: hidden;
}

    .pup-sumcard table {
        width: 100%;
        border-collapse: collapse;
        table-layout: fixed;
    }

    .pup-sumcard col.pup-s1 { width: auto; }
    .pup-sumcard col.pup-s2,
    .pup-sumcard col.pup-s3 { width: 104px; }

    .pup-sumcard thead th {
        background: var(--pup-band);
        border-bottom: 1px solid var(--pup-rule);
        font-size: .72rem;
        font-weight: var(--fw-bold);
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--pup-ink-4);
        padding: 7px 12px 6px;
        text-align: right;
    }

        .pup-sumcard thead th.pup-lft { text-align: left; }

        .pup-sumcard thead th span {
            display: inline-block;
            padding-bottom: 2px;
            border-bottom: 2px solid transparent;
            font-size: .78rem;
            letter-spacing: .02em;
            color: var(--pup-ink);
            font-weight: var(--fw-bold);
        }

        .pup-sumcard thead th.pup-od span { border-bottom-color: var(--pup-od); }
        .pup-sumcard thead th.pup-os span { border-bottom-color: var(--pup-os); }

    .pup-sumcard td {
        padding: 0 12px;
        height: 34px;
        font-size: .875rem;
        text-align: right;
        color: var(--pup-ink);
        border-bottom: 1px solid var(--pup-rule-soft);
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

        /*  White, like .pup-mname in the measure tables and like every table label on the
            binocular exam. This is a row label, not secondary text — greying it made the summary
            matrix the one table on the page whose left column receded.  */
        .pup-sumcard td.pup-lft {
            text-align: left;
            color: var(--pup-ink);
        }

        .pup-sumcard td.pup-pair {
            text-align: left;
            color: var(--pup-ink);
        }

        .pup-sumcard td.pup-bad {
            color: var(--pup-alert);
            font-weight: var(--fw-bold);
        }

        .pup-sumcard td.pup-na { color: var(--pup-ink-4); }

    .pup-sumcard tr:last-child td { border-bottom: none; }

    .pup-sumcard tr.pup-rule td { border-bottom: 1px solid var(--pup-rule); }

/*  The impression. Full card width, below everything it is drawn from. */
.pup-imp {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 11px 14px 12px;
    border: 1px solid rgba(63, 192, 109, .3);
    border-radius: 8px;
    background: var(--pup-ok-bg);
}

    .pup-imp .pup-k {
        font-size: .72rem;
        font-weight: var(--fw-bold);
        letter-spacing: .06em;
        color: var(--pup-ink-4);
        flex: 0 0 auto;
    }

    .pup-imp .pup-v {
        font-size: 1.05rem;
        font-weight: var(--fw-bold);
        color: var(--pup-ok);
    }

    .pup-imp.pup-bad {
        border-color: rgba(219, 22, 35, .42);
        background: var(--pup-alert-bg);
    }

        .pup-imp.pup-bad .pup-v { color: var(--pup-alert); }

/*  Resting stills. Centres a 242px column in whatever its grid track is — 242 is the two 116px
    frames plus their 10px gap, so the stills, their captions and the note stay a single aligned
    block rather than spreading as the track grows.  */
.pup-irispair {
    display: flex;
    flex-direction: column;
    align-items: center;
}

    /*  width, not max-width: the heading and the note keep their left edge on the frames' left
        edge, and it is the whole column that centres — not each line within it.  */
    .pup-irispair > * {
        width: 242px;
    }

    .pup-irispair .pup-pairhd {
        font-size: .72rem;
        font-weight: var(--fw-bold);
        letter-spacing: .04em;
        color: var(--pup-ink-4);
        margin: 0 0 6px;
    }

    .pup-irispair .pup-frames {
        display: flex;
        gap: 10px;
    }

    .pup-irispair .pup-th {
        flex: 0 0 116px;
        width: 116px;
    }

        .pup-irispair .pup-th svg {
            display: block;
            width: 116px;
            height: 116px;
            border-radius: 8px;
        }

    .pup-irispair .pup-cap {
        display: flex;
        justify-content: space-between;
        font-size: .78rem;
        color: var(--pup-ink-3);
        margin-top: 5px;
    }

        .pup-irispair .pup-cap b {
            font-weight: var(--fw-bold);
            color: var(--pup-ink);
            font-variant-numeric: tabular-nums;
        }

    .pup-irispair .pup-note {
        font-size: .78rem;
        color: var(--pup-ink-4);
        margin: 8px 0 0;
        line-height: 1.45;
    }

/* ── waveform card ────────────────────────────────────────────────────────────────────────── */

.pup-viewbar {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px 6px;
    margin-bottom: 10px;
}

    .pup-viewbar .pup-lead {
        font-size: .83rem;
        color: var(--pup-ink-4);
        margin-right: 4px;
    }

.pup-vbtn {
    appearance: none;
    background: none;
    border: 1px solid transparent;
    font: inherit;
    font-size: .85rem;
    color: var(--pup-ink-2);
    padding: 4px 11px 5px;
    border-radius: 999px;
    cursor: pointer;
}

    .pup-vbtn:hover {
        color: var(--pup-ink-strong);
        border-color: var(--pup-rule);
    }

    /*  Selected uses the app's one accent, the same #008FDB that marks a selected toggle
        everywhere else in the portal. */
    .pup-vbtn[aria-pressed="true"] {
        background: var(--pup-accent);
        color: #fff;
        font-weight: var(--fw-bold);
        border-color: var(--pup-accent);
    }

    .pup-vbtn .pup-dot {
        display: inline-block;
        width: 5px;
        height: 5px;
        border-radius: 50%;
        background: var(--pup-alert-fill);
        margin-left: 6px;
        vertical-align: 2px;
    }

    .pup-vbtn[aria-pressed="true"] .pup-dot { background: #fff; }

    .pup-vbtn .pup-dot.pup-off { visibility: hidden; }

.pup-field {
    background: var(--pup-field);
    border: 1px solid var(--pup-rule);
    border-radius: 8px 8px 0 0;
    border-bottom: none;
    padding: 12px 14px 8px;
    min-height: 300px;
}

.pup-fieldrow {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 20px;
}

.pup-rail {
    flex: 0 0 254px;
    width: 254px;
}

.pup-railhd {
    color: var(--pup-ink-2);
    font-size: .8rem;
    font-weight: var(--fw-bold);
    margin: 0 0 2px;
}

.pup-railsub {
    color: var(--pup-field-lab);
    font-size: .78rem;
    margin: 0 0 8px;
    min-height: 15px;
}

.pup-railframes {
    display: flex;
    gap: 10px;
    justify-content: flex-start;
}

.pup-trialslot {
    display: flex;
    justify-content: center;
    width: 242px;
}

.pup-trialtog {
    display: inline-flex;
    border: 1px solid var(--pup-field-edge);
    border-radius: 6px;
    overflow: hidden;
    background: var(--pup-field-chrome);
    margin: 0 0 9px;
}

    .pup-trialtog button {
        appearance: none;
        border: none;
        background: none;
        font: inherit;
        font-size: .78rem;
        color: var(--pup-field-dim);
        padding: 5px 0 6px;
        width: 104px;
        cursor: pointer;
        border-right: 1px solid var(--pup-field-edge);
    }

        .pup-trialtog button:last-child { border-right: none; }

        .pup-trialtog button[aria-pressed="true"] {
            color: var(--newton-blue-1);
            font-weight: var(--fw-bold);
        }

        .pup-trialtog button[data-eye="od"][aria-pressed="true"] { background: var(--pup-od); }
        .pup-trialtog button[data-eye="os"][aria-pressed="true"] { background: var(--pup-os); }

        .pup-trialtog button:focus-visible {
            outline: 2px solid var(--pup-ink);
            outline-offset: -2px;
        }

.pup-frame {
    flex: 0 0 116px;
    width: 116px;
}

    .pup-frame svg {
        display: block;
        width: 116px;
        height: 116px;
        border-radius: 6px;
        outline: 2px solid transparent;
        outline-offset: 0;
    }

    /*  The lit eye is outlined in its own colour, so "which eye is the light on" is answerable
        from the video alone, without reading the band under the trace. Keyed off data-eye rather
        than the id, because the id is instance-scoped and pupillometry.js rewrites the class. */
    .pup-frame.pup-lit[data-eye="od"] svg { outline-color: var(--pup-od); }
    .pup-frame.pup-lit[data-eye="os"] svg { outline-color: var(--pup-os); }

.pup-frameftr {
    display: flex;
    justify-content: space-between;
    gap: 5px;
    font-size: .7rem;
    color: var(--pup-field-dim);
    margin-top: 4px;
    font-variant-numeric: tabular-nums;
}

    .pup-frameftr b {
        color: var(--pup-ink);
        font-weight: var(--fw-bold);
    }

    .pup-frameftr .pup-lost {
        color: var(--pup-lost);
        font-weight: var(--fw-bold);
    }

.pup-scrub {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 11px;
}

    .pup-scrub button {
        appearance: none;
        cursor: pointer;
        background: var(--pup-field-chrome);
        border: 1px solid var(--pup-field-edge);
        color: var(--pup-ink);
        border-radius: 6px;
        width: 30px;
        height: 26px;
        font-size: .75rem;
        line-height: 1;
        padding: 0;
        flex: 0 0 auto;
    }

        .pup-scrub button:hover {
            background: var(--pup-rule);
            color: var(--pup-ink-strong);
        }

    .pup-scrub input[type=range] {
        flex: 1 1 auto;
        min-width: 0;
        accent-color: var(--pup-accent);
        height: 18px;
    }

    .pup-scrub .pup-tval {
        color: var(--pup-ink-2);
        font-size: .78rem;
        font-variant-numeric: tabular-nums;
        flex: 0 0 52px;
        text-align: right;
    }

.pup-panels {
    display: flex;
    flex-direction: column;
    gap: 18px;
    flex: 1 1 auto;
    min-width: 0;
}

.pup-pan {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
}

.pup-panlabels {
    width: 100%;
    text-align: center;
}

.pup-panchart {
    width: 100%;
    min-width: 0;
}

    .pup-panchart svg {
        display: block;
        width: 100%;
        height: auto;
    }

.pup-pantitle {
    color: var(--pup-ink-2);
    font-size: .85rem;
    font-weight: var(--fw-bold);
    margin: 0;
    display: inline;
}

.pup-pansub {
    color: var(--pup-field-lab);
    font-size: .78rem;
    margin: 0 0 0 6px;
    line-height: 1.4;
    display: inline;
}

    .pup-pansub::before {
        content: "· ";
        color: var(--pup-rule);
        margin-right: 2px;
    }

    .pup-pansub.pup-bad { color: var(--pup-alert); }

.pup-fieldnote {
    color: var(--pup-field-lab);
    font-size: .78rem;
    margin: 12px auto 0;
    max-width: 96ch;
    line-height: 1.5;
    min-height: 30px;
    text-align: center;
}

/*  Retention. Inside the field because it is a fact about the VIDEO specifically — the waveforms
    and metrics outlive it by years, and saying so here is what stops "deletes in 89 days" from
    reading as "the exam disappears". */
.pup-retain {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    margin-top: 12px;
    padding-top: 11px;
    border-top: 1px solid var(--pup-field-grid);
    color: var(--pup-field-lab);
    font-size: .78rem;
    line-height: 1.45;
}

    .pup-retain .pup-rtxt { min-width: 0; }

        .pup-retain .pup-rtxt b {
            color: var(--pup-ink-2);
            font-weight: var(--fw-bold);
        }

        .pup-retain .pup-rtxt .pup-ext {
            color: var(--pup-watch);
            font-weight: var(--fw-bold);
        }

.pup-rbtn {
    appearance: none;
    cursor: pointer;
    font: inherit;
    font-size: .78rem;
    font-weight: var(--fw-bold);
    background: var(--pup-field-chrome);
    border: 1px solid var(--pup-field-edge);
    color: var(--pup-ink);
    padding: 5px 11px 6px;
    border-radius: 6px;
    flex: 0 0 auto;
    white-space: nowrap;
}

    .pup-rbtn:hover {
        background: var(--pup-rule);
        color: var(--pup-ink-strong);
    }

    .pup-rbtn:focus-visible {
        outline: 2px solid var(--pup-accent);
        outline-offset: 1px;
    }

    .pup-rbtn.pup-done {
        background: none;
        color: var(--pup-ink-3);
    }

        .pup-rbtn.pup-done:hover {
            background: var(--pup-field-chrome);
            color: var(--pup-ink);
        }

/* ── conditions ───────────────────────────────────────────────────────────────────────────── */

.pup-cond {
    background: var(--pup-band);
    border: 1px solid var(--pup-rule);
    border-radius: 0 0 8px 8px;
}

    .pup-cond summary {
        padding: 9px 14px 10px;
        font-size: .83rem;
        color: var(--pup-ink-3);
        cursor: pointer;
    }

        .pup-cond summary b {
            font-weight: var(--fw-bold);
            color: var(--pup-ink);
        }

.pup-condgrid {
    display: flex;
    flex-wrap: wrap;
    border-top: 1px solid var(--pup-rule);
}

.pup-cbi {
    flex: 1 1 148px;
    padding: 9px 14px 10px;
    border-right: 1px solid var(--pup-rule);
}

    .pup-cbi:last-child { border-right: none; }

    .pup-cbi .pup-k {
        font-size: .7rem;
        color: var(--pup-ink-4);
    }

    .pup-cbi .pup-v {
        font-size: .83rem;
        color: var(--pup-ink);
    }

        .pup-cbi .pup-v.pup-warn {
            color: var(--pup-watch);
            font-weight: var(--fw-bold);
        }

/* ── groups ───────────────────────────────────────────────────────────────────────────────── */

.pup-exam h2.pup-sec {
    font-family: var(--pup-sans);
    font-size: .72rem;
    font-weight: var(--fw-bold);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--pup-ink-4);
    margin: 0 0 4px;
}

.pup-grp { border-bottom: 1px solid var(--pup-rule-soft); }

    .pup-grp:first-of-type { border-top: 1px solid var(--pup-rule-soft); }

    .pup-grp > summary {
        display: flex;
        align-items: baseline;
        gap: 10px;
        padding: 12px 2px;
        cursor: pointer;
        list-style: none;
        font-size: .95rem;
    }

        .pup-grp > summary::-webkit-details-marker { display: none; }

        .pup-grp > summary::before {
            content: "";
            width: 6px;
            height: 6px;
            flex: 0 0 auto;
            align-self: center;
            border-right: 1.5px solid var(--pup-ink-3);
            border-bottom: 1.5px solid var(--pup-ink-3);
            transform: rotate(-45deg);
            transition: transform .15s;
        }

    .pup-grp[open] > summary::before { transform: rotate(45deg); }

.pup-gname {
    font-weight: var(--fw-bold);
    color: var(--pup-ink-strong);
}

.pup-gstat {
    color: var(--pup-ink-3);
    font-size: .85rem;
}

    .pup-gstat.pup-bad {
        color: var(--pup-alert);
        font-weight: var(--fw-bold);
    }

/*  A skipped group is one flat line, not a collapsed section: there is nothing inside to open,
    and a chevron would promise otherwise. */
.pup-skipline {
    padding: 12px 2px;
    font-size: .92rem;
    color: var(--pup-ink-2);
    border-bottom: 1px solid var(--pup-rule-soft);
    display: flex;
    gap: 10px;
    align-items: baseline;
}

    .pup-skipline .pup-why {
        color: var(--pup-ink-4);
        font-size: .85rem;
    }

.pup-exam summary:focus-visible,
.pup-vbtn:focus-visible {
    outline: 2px solid var(--pup-accent);
    outline-offset: 2px;
}

/* ── measure tables ───────────────────────────────────────────────────────────────────────── */

.pup-exam table.pup-m {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 10px;
    table-layout: fixed;
}

    .pup-exam table.pup-m th:nth-child(2),
    .pup-exam table.pup-m th:nth-child(3),
    .pup-exam table.pup-m td:nth-child(2),
    .pup-exam table.pup-m td:nth-child(3) { width: 108px; }

    .pup-exam table.pup-m th {
        text-align: right;
        font-size: .72rem;
        font-weight: var(--fw-bold);
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--pup-ink-4);
        padding: 0 0 6px;
        border-bottom: 1px solid var(--pup-rule-soft);
        background: none;
    }

        .pup-exam table.pup-m th.pup-lft { text-align: left; }

    .pup-exam table.pup-m td {
        padding: 8px 0;
        height: 48px;
        color: var(--pup-ink);
        font-size: .875rem;
        border-bottom: 1px solid var(--pup-rule-soft);
        text-align: right;
        font-variant-numeric: tabular-nums;
        background: none;
    }

    .pup-exam table.pup-m tr:last-child td { border-bottom: none; }

    .pup-exam table.pup-m td.pup-lft { text-align: left; }

.pup-mname {
    color: var(--pup-ink);
}

.pup-msub {
    display: block;
    font-size: .78rem;
    color: var(--pup-ink-4);
    font-weight: var(--fw-regular);
    margin-top: 1px;
}

.pup-val.pup-dim { color: var(--pup-ink-4); }

/*  Width has to land on the header cell too — the table is `table-layout: fixed`, so the first
    row is what sizes the columns. */
.pup-exam table.pup-m .pup-trendcell {
    width: 72px;
    padding-left: 10px;
}

.pup-trendcell svg {
    display: block;
    width: 64px;
    height: 19px;
    margin-left: auto;
}

.pup-exam table.pup-m .pup-flagcell { width: 92px; }

.pup-flag {
    display: inline-block;
    font-size: .75rem;
    font-weight: var(--fw-bold);
    padding: 3px 8px 4px;
    border-radius: 999px;
    white-space: nowrap;
}

    .pup-flag.pup-watch {
        color: var(--pup-watch);
        background: var(--pup-watch-bg);
    }

    .pup-flag.pup-refer {
        color: var(--pup-alert);
        background: var(--pup-alert-bg);
    }

.pup-exam table.pup-m tr.pup-hit td { background: var(--pup-alert-bg); }

/* ── investigational / all measures / footer ──────────────────────────────────────────────── */

/*  Dashed rather than the solid card border. The whole point of this block is that it is NOT
    the same kind of thing as the cards above it. */
.pup-invest {
    border-style: dashed;
    border-color: var(--pup-rule);
    background: none;
    box-shadow: none;
    padding: 0;
}

    .pup-invest > summary {
        padding: 12px 14px;
        cursor: pointer;
        list-style: none;
        font-size: .92rem;
        display: flex;
        gap: 10px;
        align-items: baseline;
    }

        .pup-invest > summary::-webkit-details-marker { display: none; }

    .pup-invest .pup-tagres {
        font-size: .72rem;
        font-weight: var(--fw-bold);
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--pup-ink-3);
        border: 1px solid var(--pup-rule);
        border-radius: 999px;
        padding: 2px 8px 3px;
    }

    .pup-invest .pup-investbody { padding: 0 14px 6px; }

    .pup-invest .pup-investlead {
        margin: 0 0 8px;
        font-size: .83rem;
        color: var(--pup-ink-3);
        max-width: 82ch;
    }

.pup-all {
    padding: 0 1rem;
}

    .pup-all > summary {
        cursor: pointer;
        font-size: .92rem;
        color: var(--pup-ink-2);
        padding: 12px 0;
        list-style: none;
        display: flex;
        align-items: center;
        gap: 8px;
    }

        .pup-all > summary::-webkit-details-marker { display: none; }

        .pup-all > summary::before {
            content: "";
            width: 6px;
            height: 6px;
            border-right: 1.5px solid var(--pup-ink-3);
            border-bottom: 1.5px solid var(--pup-ink-3);
            transform: rotate(-45deg);
            transition: transform .15s;
        }

    .pup-all[open] > summary::before { transform: rotate(45deg); }

.pup-caveat {
    font-size: .83rem;
    color: var(--pup-ink-3);
    margin: 2px 0 12px;
    max-width: 84ch;
    padding-left: 12px;
    border-left: 2px solid var(--pup-rule);
    line-height: 1.55;
}

.pup-foot {
    margin-top: 1.25rem;
    display: flex;
    flex-wrap: wrap;
    gap: 8px 22px;
    align-items: center;
    font-size: .78rem;
    color: var(--pup-ink-4);
}

.pup-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--pup-ink-3);
}

    .pup-chip i {
        width: 6px;
        height: 6px;
        border-radius: 50%;
        background: var(--pup-ok);
    }

    .pup-chip.pup-pend i { background: var(--pup-ink-4); }

/* ── preview chrome (host page only, not part of the component) ───────────────────────────── */

.pup-preview {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 0 4px;
    font-size: .83rem;
    color: var(--pup-ink-4);
}

.pup-segs {
    display: inline-flex;
    border: 1px solid var(--pup-rule);
    border-radius: 999px;
    overflow: hidden;
    background: var(--pup-card);
}

    .pup-segs button {
        appearance: none;
        border: none;
        background: none;
        font: inherit;
        font-size: .83rem;
        color: var(--pup-ink-2);
        padding: 5px 14px 6px;
        cursor: pointer;
    }

        .pup-segs button[aria-pressed="true"] {
            background: var(--pup-accent);
            color: #fff;
            font-weight: var(--fw-bold);
        }

        .pup-segs button:focus-visible {
            outline: 2px solid var(--pup-accent);
            outline-offset: -2px;
        }

.pup-preview .pup-hint {
    margin-left: auto;
    font-size: .8rem;
}

.pup-mockline {
    margin-top: 1rem;
    font-size: .78rem;
    color: var(--pup-ink-4);
    max-width: 82ch;
    line-height: 1.6;
}

/* ── narrow ───────────────────────────────────────────────────────────────────────────────── */

/*  ── stills below the summary ─────────────────────────────────────────────────────────────
    The matrix caps at 800px and the stills need 242px beside it, so a row needs ~1060px of card
    before the two stop competing. Below 1200 the stills drop underneath instead of squeezing the
    matrix's label column, which is the one that loses first — "Resting diameter — scotopic" has
    nowhere to go.

    ⚠ Ahead of the 900px block in source order, at equal specificity, so the narrower rules below
    still win where both apply.  */
/*  ── stills move up beside the chips ──────────────────────────────────────────────────────
    The matrix wants 800px and the stills 242px, so a side-by-side row needs ~1060px of card
    before the two stop competing. Rather than drop the stills to a row of their own — which
    leaves a 242px block alone against dead space — they pair with the chips, which stack into a
    single column and fill the height beside them.  */
@media (max-width: 1200px) {
    .pup-top {
        grid-template-columns: minmax(0, 1fr) 242px;
        grid-template-areas:
            "chips iris"
            "find  find"
            "sum   sum"
            "imp   imp";
    }

    /*  One per row. Four stacked chips is close to the stills' own height, so the pair reads as
        one band rather than a short column beside a tall one.  */
    .pup-perrla { grid-template-columns: 1fr; }
}

@media (max-width: 900px) {
    /*  Single column: 242px beside anything is too tight here, and the chips go back to two
        across now that they have the full width to themselves.  */
    .pup-top {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas: "chips" "iris" "find" "sum" "imp";
    }

    .pup-perrla { grid-template-columns: repeat(2, 1fr); }

    .pup-irispair { align-items: flex-start; }

    .pup-fieldrow {
        flex-direction: column;
        align-items: stretch;
    }

    .pup-rail {
        flex: 0 0 auto;
        width: 100%;
    }

    .pup-railframes { justify-content: center; }

    .pup-trialslot { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .pup-exam * { transition: none !important; }
}

/*  ── loading skeleton ────────────────────────────────────────────────────────────────────
    The same treatment as MeasurementComponent's, with its own class names and keyframes on
    purpose: that component's <style> block is only in the DOM while IT renders, so borrowing
    .skeleton-block would leave this unstyled on a visit whose only test is a pupillometry one.

    ⚠ Blocks are sized from the LOADED view, not estimated, so the pane does not resize when
    content replaces them. Re-measure if the cards change.

    ⚠ The sweep is a translateX on an ::after overlay, NOT an animated background-position.
    Transform runs on the compositor, so a full-page skeleton costs no layout and no repaint
    per frame.  */
.pup-skel {
    position: relative;
    overflow: hidden;
    background: var(--pup-card);
    border-radius: 6px;
}

    .pup-skel::after {
        content: "";
        position: absolute;
        inset: 0;
        transform: translateX(-100%);
        background: linear-gradient(90deg,
                    transparent 0%,
                    rgba(89, 89, 139, .28) 50%,
                    transparent 100%);
        animation: pup-skeleton-sweep 1.4s ease-in-out infinite;
    }

@keyframes pup-skeleton-sweep {
    to { transform: translateX(100%); }
}

/*  The Telerik Actions button: k-button-md, k-rounded-full, in a wrapper with padding-right
    10px. Height is an observation of the rendered control, not a value from this repo. */
.pup-skel-actions {
    height: 2.25rem;
    width: 7rem;
    border-radius: 999px;
}

/*  Heights are the real LINE BOXES, not the visible text — these stack, and their sum is what
    positions the first card. */
.pup-skel-line-date {
    height: 1.5rem;
    width: min(18rem, 45%);
    margin: 0 0 1rem;
}

.pup-skel-line-meta {
    height: 1.2rem;
    width: min(24rem, 55%);
}

.pup-skel-pill {
    height: 1.6rem;
    width: 11rem;
    border-radius: 999px;
}

/*  Card blocks carry the card's own geometry, so the skeleton and the loaded view sit on the
    same grid. */
/*  Geometry matches .pup-card, and the skeleton sits in the same .row / .px-0 wrapper, so the
    blocks and the cards replacing them share an edge.  */
.pup-skel-card {
    border-radius: 12px;
    margin: 1.5rem 0 0;
}

/*  ── card floors ─────────────────────────────────────────────────────────────────────────
    ⚠ EVERY ONE IS min-height AND EVERY ONE IS THE SMALLEST THE REAL CARD CAN BE. Those are two
    separate rules and both matter:

      · Under the floor, the card GROWS when content lands and everything below it jumps down.
        That is the bug these numbers replace — the answer card was set to 268px against its
        floor, so it moved on every load.
      · Over the floor, the card SHRINKS on the one exam that is smallest, which jumps the same
        distance in the other direction and is harder to notice in testing because it only
        happens on sparse content.

    min-height rather than height so a bigger exam settles downward instead of clipping.

    ⚠ DERIVED FROM THE BOX MODEL IN THIS FILE, NOT MEASURED IN A BROWSER — unlike
    MeasurementComponent's skeleton, whose comments claim measurement. Root is 16px (app.css
    sets no html font-size), .pup-exam is 14.5px/1.5. Each figure below is padding + borders +
    line boxes summed down the card's own child stack, taking the smallest legal content at
    every variable point: one findings row, one summary row, one collapsed group, the
    single-panel view. Text-wrap counts (the iris note, the field note, the retention line) are
    estimated at ~0.5em per character and are the softest part of each sum. Worth one pass with
    devtools to confirm; if any is off, it is off by a line box, not by a card.  */

/*  440 = 32 card padding + 35 chip row + 73 findings bar + 207 stills (taller than the matrix)
    The head row's floor is the iris pair, not the summary table: two 116px stills plus caption
    and note are fixed, where the table can be a single row.  */
.pup-skel-card-answer { min-height: 440px; }

/*  489 = 32 + 41 view bar + 375 field + 41 conditions, for the SINGLE-panel view (swinging
    flashlight, near response) where the 254px rail is taller than the one chart beside it.
    ⚠ A two-panel view — direct/consensual, afferent/efferent — is ~760px, and a normal exam
    opens on one. The skeleton cannot know which, so it reserves the smaller and accepts the
    settle: the alternative shrinks by 266px on every abnormal exam.  */
.pup-skel-card-field { min-height: 489px; }

/*  102 = 32 + 21 heading + 48 for one collapsed group. Both mock exams carry three, but
    the group list is protocol-driven and one is what the markup can legally render.  */
.pup-skel-card-groups { min-height: 102px; }

/*  Both are a single collapsed summary row, and they differ: the investigational block's height
    is set by its "Investigational" pill (padding + border round a .62rem line), the all-measures
    block by a plain .85rem line.  */
.pup-skel-card-invest { min-height: 50px; }
.pup-skel-card-all    { min-height: 48px; }

/*  Below 900px the PERRLA grid halves to two rows, the head row stacks, and the field's rail
    goes above the panels instead of beside them — so both floors roughly double. Re-derived,
    not scaled.  */
/*  ⚠ THESE MUST STAY BELOW THE BASE RULES ABOVE. A media query adds no specificity, so at equal
    specificity the later declaration wins — an override placed earlier in the file than the value
    it overrides is simply dead. The layout breakpoints live in their own section further up; the
    skeleton's have to live here.  */

/*  471 = the stills (207, taller than four stacked chips) + findings bar + matrix + impression
    + the grid's gaps. The stills have moved up beside the chips.  */
@media (max-width: 1200px) {
    .pup-skel-card-answer { min-height: 471px; }
}

@media (max-width: 900px) {
    .pup-skel-card-answer { min-height: 564px; }
    .pup-skel-card-field  { min-height: 849px; }
}

/*  ⚠ REQUIRED at this project's AA bar: an infinite animation has to be stoppable by
    preference. The blocks stay — they are the useful part — and only the sweep goes, so a
    reduced-motion user still sees the layout reserved rather than a blank pane.  */
@media (prefers-reduced-motion: reduce) {
    .pup-skel::after { animation: none; }
}

