/* /Components/Controls/AdpDisplaySettingsPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-a4krqosqw9] { font-size:.78rem; color:#64748b; }
.projects-side-panel .muted[b-a4krqosqw9] { color:#94a3b8; }
.projects-side-panel .small[b-a4krqosqw9] { font-size:.78rem; }
.img-warn[b-a4krqosqw9] { background:#fef3c7; color:#92400e; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
/* Same contract as the image legend dot, against ADP_POINT_FILL / _RING / _RADIUS —
       and drawn a shade smaller for the same reason the marker is. */
.adp-legend-dot[b-a4krqosqw9] { display:inline-block; width:8px; height:8px; border-radius:50%; background:#22c55e; border:1.5px solid #0f172a; margin-right:.35rem; vertical-align:baseline; }
.qc-flight-top .btn[b-a4krqosqw9] { margin-left:auto; }
/* The swath toggle. A row rather than an inline control so its counts wrap under the label on
       a narrow rail instead of pushing the checkbox off the edge. */
/* One row per drawable layer in the bar's SCANNER popover: checkbox, legend mark matching how
       that layer actually draws, name, then its count pushed to the right so two rows' numbers
       line up and can be compared at a glance. */
.qc-layer-toggle[b-a4krqosqw9] { display:flex; align-items:center; gap:.4rem; margin:0 0 .35rem; cursor:pointer; font-size:.82rem; }
.qc-layer-name[b-a4krqosqw9] { font-weight:600; color:#1e293b; }
.qc-layer-meta[b-a4krqosqw9] { margin-left:auto; font-size:.78rem; text-align:right; }
/* The coverage check, under the scanner display toggles it shares a scope with. Separated by
       a rule rather than a heading: the toggles say how the sweeps DRAW and this says what they
       covered, which are different questions about one selection. */
.qc-scan-check[b-a4krqosqw9] { margin-top:.6rem; padding-top:.55rem; border-top:1px solid #e2e8f0; }
.qc-scan-check-head[b-a4krqosqw9] { display:flex; align-items:center; gap:.5rem; margin-bottom:.35rem; }
.qc-scan-check-head .btn[b-a4krqosqw9] { margin-left:auto; }
/* One card per gap layer: the tick that draws it, the share it accounts for, and the walk
       through it. Boxed rather than left as flat rows because each card is a piece of WORK — a
       stretch somebody has to fly again — and the two of them mean opposite things: fly it again
       versus fly it differently. */
.qc-issue[b-a4krqosqw9] { border:1px solid #e2e8f0; border-radius:7px; padding:.35rem .45rem .3rem; margin:0 0 .4rem; }
.qc-issue-main[b-a4krqosqw9] { display:flex; align-items:center; gap:.4rem; margin:0; cursor:pointer; font-size:.82rem; }
.qc-issue-meta[b-a4krqosqw9] { margin-left:auto; font-size:.72rem; text-align:right; white-space:nowrap; font-variant-numeric:tabular-nums; }
/* The walk, indented to the layer NAME above it — past the tick and its legend mark — so it
       reads as that layer's control rather than as a second row in a list. */
.qc-issue-go[b-a4krqosqw9] { display:flex; align-items:center; gap:.45rem; margin-top:.3rem; padding-left:1.55rem; }
.qc-issue-warn[b-a4krqosqw9] { margin:.35rem 0 0; }
.qc-scan-stamp[b-a4krqosqw9] { margin:.4rem 0 0; }
/* One block per rig in the probe check: a project with three aircraft lists three, and they
       must not read as one running paragraph. */
.qc-adp-system[b-a4krqosqw9] { margin:.45rem 0 0; padding-top:.35rem; border-top:1px dashed #e2e8f0; }
.qc-adp-system:first-of-type[b-a4krqosqw9] { border-top:0; padding-top:0; }
.qc-adp-head[b-a4krqosqw9] { display:flex; align-items:baseline; gap:.4rem; }
.qc-adp-scene[b-a4krqosqw9] { padding-left:.6rem; }
/* Same red as the ortho gap swatch — they mean the same thing, and two reds would invite
       reading a difference into them that is not there. */
.scan-gap-legend[b-a4krqosqw9] { display:inline-block; width:14px; height:0; border-top:2.5px solid #dc2626; vertical-align:middle; }
/* The two questions as two dials, side by side and never merged into one: a project reading
       100% along its lines and 60% across its corridors is the case a single figure hides. */
.qc-dials[b-a4krqosqw9] { display:grid; grid-template-columns:1fr 1fr; gap:.5rem; margin:.45rem 0 .5rem; }
/* One question, so one column — a lone dial in a two-column grid sits hard left of a gap the
       eye reads as a second figure that failed to load. */
.qc-dials-solo[b-a4krqosqw9] { grid-template-columns:1fr; }
.qc-dial[b-a4krqosqw9] { display:flex; flex-direction:column; align-items:center; text-align:center; min-width:0; }
.qc-dial-cap[b-a4krqosqw9] { font-size:.7rem; font-weight:600; text-transform:uppercase; letter-spacing:.04em; color:#475569; }
.qc-dial-sub[b-a4krqosqw9] { font-size:.66rem; color:#94a3b8; line-height:1.25; }
.qc-dial-val .muted[b-a4krqosqw9] { font-size:.62rem; }
/* What the figure above is a percentage OF. Under the dial rather than beside it: a
       denominator that moved silently is worse than the wrong denominator. */
.qc-dial-scope[b-a4krqosqw9] { font-size:.68rem; line-height:1.25; }
.qc-scanner-scope[b-a4krqosqw9] { display:flex; align-items:baseline; gap:.35rem; margin:0 0 .3rem; }
.qc-scanner-scope-label[b-a4krqosqw9] { text-transform:uppercase; letter-spacing:.04em; font-size:.7rem; }
.qc-help[b-a4krqosqw9] { margin:0 0 .5rem; padding:.4rem .55rem; border-left:2px solid #cbd5e1; border-radius:0 4px 4px 0; background:#f8fafc; }
/* A measured figure belonging to the toggle row above it, aligned with that row's NAME — past
       the checkbox and its legend mark — so it reads as part of that row and not as another layer. */
.qc-layer-sub[b-a4krqosqw9] { margin:-.2rem 0 .45rem; padding-left:1.55rem; }
/* The endpoint pager, indented like the Go-to walk and for the same reason: it belongs to the
       row above it. Tight arrow buttons, because the range beside them is the part being read. */
.qc-page-row[b-a4krqosqw9] { display:flex; align-items:center; gap:.25rem; margin:-.15rem 0 .5rem; padding-left:1.55rem; }
.qc-page-row .btn[b-a4krqosqw9] { min-width:1.4rem; padding:0 .3rem; line-height:1.35; font-size:.85rem; }
.qc-page-row .btn:disabled[b-a4krqosqw9] { opacity:.45; cursor:default; }
.qc-page-row .muted[b-a4krqosqw9] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
/* Informational, not a warning: nothing is wrong, the ticks are simply out of view. */
.img-note[b-a4krqosqw9] { background:#e0e7ff; color:#3730a3; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
.qc-onmap .adp-legend-dot[b-a4krqosqw9] { margin-left:.35rem; }
.adp-readout-head .muted[b-a4krqosqw9] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-a4krqosqw9] { color:#94a3b8; }
.adp-readout-table .muted[b-a4krqosqw9] { color:#94a3b8; }
.pole-review .img-note[b-a4krqosqw9] { background:#fff7ed; border:1px solid #fed7aa; color:#9a3412; border-radius:6px; margin:0; padding:.35rem .6rem; font-size:.76rem; }
.qc-bar-scope .muted[b-a4krqosqw9] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-a4krqosqw9] { font-size:.78rem; color:#64748b; }
/* /Components/Controls/CoverageDial.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-acjwjzxxw3] { font-size:.78rem; color:#64748b; }
.projects-side-panel .muted[b-acjwjzxxw3] { color:#94a3b8; }
.qc-dial-fig[b-acjwjzxxw3] { position:relative; display:inline-block; margin:.3rem 0 .2rem; }
/* The arc is the covered share; the TRACK behind it is what is missing, in the colour that
       stretch draws on the map — so the ring and the legend below it cannot disagree about what a
       hole is. The arc's own colour is one green at every value: nothing on this page has a pass
       threshold, and only the arc's LENGTH says how much was covered. */
.qc-dial-arc[b-acjwjzxxw3] { stroke:#16a34a; }
.qc-dial-track-line[b-acjwjzxxw3] { stroke:#fecaca; }
.qc-dial-track-swath[b-acjwjzxxw3] { stroke:#fde68a; }
.qc-dial-val[b-acjwjzxxw3] { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; line-height:1.15; }
.qc-dial-val .muted[b-acjwjzxxw3] { font-size:.62rem; }
.qc-page-row .muted[b-acjwjzxxw3] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
.adp-readout-head .muted[b-acjwjzxxw3] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-acjwjzxxw3] { color:#94a3b8; }
.adp-readout-table .muted[b-acjwjzxxw3] { color:#94a3b8; }
.qc-bar-scope .muted[b-acjwjzxxw3] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-acjwjzxxw3] { font-size:.78rem; color:#64748b; }
/* /Components/Controls/FieldLanes.razor.rz.scp.css */
/* Isolated on purpose. The names in here (.lane, .band, .chip, .field) are exactly the
   kind of generic selectors that have twice leaked out of a page <style> block in this
   repo and restyled the sidebar. */

.lanes-root[b-m5ceyqjgaf] {
    --gutter: 13rem;
    --grid: #e2e8f0;
    --ink: #0f172a;
    --ink-2: #475569;
    --muted: #94a3b8;
    --series: #2563eb;
    font-size: .88rem;
}

/* ---- toolbar ---- */

.toolbar[b-m5ceyqjgaf] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1rem;
    align-items: center;
    margin-bottom: .6rem;
}

.picker[b-m5ceyqjgaf] {
    display: flex;
    align-items: center;
    gap: .6rem;
}

.picker input[type=search][b-m5ceyqjgaf] {
    padding: .35rem .55rem;
    border: 1px solid #cbd5e1;
    border-radius: 6px;
    min-width: 14rem;
}

.chk[b-m5ceyqjgaf] {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    color: var(--ink-2);
    font-size: .82rem;
    white-space: nowrap;
}

.chosen[b-m5ceyqjgaf] {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
    align-items: center;
}

.chip[b-m5ceyqjgaf] {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    background: #eff6ff;
    color: #1e40af;
    border: 1px solid #bfdbfe;
    border-radius: 999px;
    padding: .1rem .25rem .1rem .55rem;
    font-size: .78rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.chip button[b-m5ceyqjgaf] {
    border: 0;
    background: transparent;
    color: #1e40af;
    cursor: pointer;
    font-size: .95rem;
    line-height: 1;
    padding: 0 .25rem;
}

.chip button:hover[b-m5ceyqjgaf] { color: #b91c1c; }

/* ---- lanes ---- */

.lanes[b-m5ceyqjgaf] {
    position: relative;
    border: 1px solid var(--grid);
    border-radius: 8px;
    overflow: hidden;
    background: #fff;
}

.lane[b-m5ceyqjgaf] {
    display: grid;
    grid-template-columns: var(--gutter) 1fr;
    border-top: 1px solid var(--grid);
}

.lane:first-child[b-m5ceyqjgaf] { border-top: 0; }

.lane-label[b-m5ceyqjgaf] {
    padding: .3rem .55rem;
    border-right: 1px solid var(--grid);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .05rem;
    min-width: 0;
    background: #f8fafc;
}

.lane-label .name[b-m5ceyqjgaf] {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .78rem;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lane-label .scale[b-m5ceyqjgaf] {
    font-size: .68rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* The hover readout. JS writes into this; it must not reflow the gutter as values
   change width, hence the fixed line and tabular figures. */
.lane-label .readout[b-m5ceyqjgaf] {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .8rem;
    font-weight: 700;
    color: var(--series);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.lane-plot[b-m5ceyqjgaf] {
    position: relative;
    min-width: 0;
}

.lane.num .lane-plot[b-m5ceyqjgaf] { height: 52px; }
.lane.state .lane-plot[b-m5ceyqjgaf] { height: 26px; }

.lane.num svg[b-m5ceyqjgaf] {
    display: block;
    width: 100%;
    height: 100%;
}

.env[b-m5ceyqjgaf] {
    fill: none;
    stroke: var(--series);
    stroke-width: 1.5;
    stroke-linejoin: round;
}

/* ---- state ribbons ---- */

.bands[b-m5ceyqjgaf] {
    display: flex;
    height: 100%;
    width: 100%;
}

.band[b-m5ceyqjgaf] {
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    font-size: .7rem;
    letter-spacing: .01em;
    white-space: nowrap;
    /* A 2px surface gap between adjacent fills, so two similar ramp steps still read as
       two bands rather than one long one. */
    box-shadow: inset -2px 0 0 #fff;
}

.band span[b-m5ceyqjgaf] {
    padding: 0 .3rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- axis ---- */

.lane.axis .lane-plot[b-m5ceyqjgaf] { height: 20px; }
.lane.axis .lane-label[b-m5ceyqjgaf] { background: #f8fafc; }

.ticks[b-m5ceyqjgaf] {
    position: relative;
    height: 100%;
}

.ticks span[b-m5ceyqjgaf] {
    position: absolute;
    top: 2px;
    transform: translateX(-50%);
    font-size: .68rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ticks span:first-child[b-m5ceyqjgaf] { transform: none; }
.ticks span:last-child[b-m5ceyqjgaf] { transform: translateX(-100%); }

/* ---- crosshair ---- */

.crosshair-host[b-m5ceyqjgaf] {
    position: absolute;
    top: 0;
    /* 20px axis plot + its 1px border-top. At a flat 20px the crosshair bled a pixel
       into the tick row and read as a stray mark under the last lane. */
    bottom: 21px;
    left: var(--gutter);
    right: 0;
    cursor: crosshair;
}

.crosshair[b-m5ceyqjgaf] {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: #0f172a;
    opacity: 0;
    pointer-events: none;
}

.crosshair-host:hover .crosshair[b-m5ceyqjgaf] { opacity: .55; }

/* Where the player currently sits, so the lanes and the transport agree. */
.cursor-mark[b-m5ceyqjgaf] {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: #ea580c;
    pointer-events: none;
}

.foot[b-m5ceyqjgaf] {
    margin: .4rem 0 .7rem;
    font-size: .78rem;
}

/* ---- field list ---- */

.field-list[b-m5ceyqjgaf] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem .9rem;
    max-height: 15rem;
    overflow: auto;
    border: 1px solid var(--grid);
    border-radius: 8px;
    padding: .5rem .6rem;
    background: #fcfcfb;
}

.family[b-m5ceyqjgaf] { min-width: 9rem; }

.family-name[b-m5ceyqjgaf] {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--muted);
    margin-bottom: .15rem;
}

.field[b-m5ceyqjgaf] {
    display: flex;
    align-items: baseline;
    gap: .35rem;
    width: 100%;
    text-align: left;
    border: 1px solid transparent;
    background: transparent;
    border-radius: 5px;
    padding: .1rem .3rem;
    cursor: pointer;
    font-size: .76rem;
    color: var(--ink-2);
}

.field:hover[b-m5ceyqjgaf] { background: #eef2ff; }

.field.on[b-m5ceyqjgaf] {
    background: #dbeafe;
    border-color: #93c5fd;
    color: #1e3a8a;
    font-weight: 600;
}

.field.flat[b-m5ceyqjgaf] { opacity: .5; }

.field .fk[b-m5ceyqjgaf] {
    font-size: .6rem;
    color: var(--muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    width: 1.6rem;
    flex: none;
}

.field .fn[b-m5ceyqjgaf] {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.field .fv[b-m5ceyqjgaf] {
    margin-left: auto;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    font-size: .68rem;
    white-space: nowrap;
}

.muted[b-m5ceyqjgaf] { color: var(--muted); font-style: italic; }
/* /Components/Controls/FlightTrackSettingsPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-vwlea0n5hq] { font-size:.78rem; color:#64748b; }
.projects-side-panel .muted[b-vwlea0n5hq] { color:#94a3b8; }
.projects-side-panel .small[b-vwlea0n5hq] { font-size:.78rem; }
.img-warn[b-vwlea0n5hq] { background:#fef3c7; color:#92400e; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
/* The track's marks are DASHES and the pins' are DOTS, each drawn the way the map draws it. The
       hues are the trail read's (MessagesController.MapTrails) and the pins' (RtQc.FilterBar.cs),
       which are the Live Map's, and must be kept in step with them: a legend that disagrees with
       the map is worse than no legend. */
.flight-legend-dash[b-vwlea0n5hq] { display:inline-block; width:14px; border-top:3px solid #16a34a; margin-right:.35rem; vertical-align:middle; }
.flight-legend-key[b-vwlea0n5hq] { display:flex; flex-wrap:wrap; gap:.15rem .7rem; margin:-.1rem 0 .45rem; padding-left:1.55rem; font-size:.74rem; }
.flight-key-dash[b-vwlea0n5hq] { display:inline-block; width:12px; border-top:3px solid; margin-right:.25rem; vertical-align:middle; }
.flight-key-scene[b-vwlea0n5hq] { border-top-color:#16a34a; }
.flight-key-between[b-vwlea0n5hq] { border-top-color:#3388ff; }
.flight-key-pin[b-vwlea0n5hq] { display:inline-block; width:10px; height:10px; border-radius:50%; border:2px solid #fff; box-shadow:0 0 0 1px #94a3b8; margin-right:.25rem; vertical-align:middle; }
.flight-key-start[b-vwlea0n5hq] { background:#16a34a; }
.flight-key-end[b-vwlea0n5hq] { background:#dc2626; }
/* One row per flight in scope: when it flew, then Go to pushed right, with the miles under
       both. Two lines rather than one because the times and the mileage each read as a column of
       their own when several flights are listed, and a 20rem popover cannot hold them side by
       side without one of them wrapping mid-number. */
.qc-flight-list[b-vwlea0n5hq] { margin:.1rem 0 .4rem; }
.qc-flight-row[b-vwlea0n5hq] { padding:.28rem 0 .3rem 1.55rem; border-top:1px solid #f1f5f9; }
.qc-flight-row:first-child[b-vwlea0n5hq] { border-top:none; }
.qc-flight-top[b-vwlea0n5hq] { display:flex; align-items:baseline; gap:.4rem; }
.qc-flight-when[b-vwlea0n5hq] { font-weight:600; color:#1e293b; font-size:.82rem; font-variant-numeric:tabular-nums; }
.qc-flight-top .btn[b-vwlea0n5hq],
.qc-flight-top .qc-flight-undrawn[b-vwlea0n5hq] { margin-left:auto; }
.qc-flight-meta[b-vwlea0n5hq] { display:block; font-size:.76rem; font-variant-numeric:tabular-nums; }
/* The swath toggle. A row rather than an inline control so its counts wrap under the label on
       a narrow rail instead of pushing the checkbox off the edge. */
/* One row per drawable layer in the bar's SCANNER popover: checkbox, legend mark matching how
       that layer actually draws, name, then its count pushed to the right so two rows' numbers
       line up and can be compared at a glance. */
.qc-layer-toggle[b-vwlea0n5hq] { display:flex; align-items:center; gap:.4rem; margin:0 0 .35rem; cursor:pointer; font-size:.82rem; }
.qc-layer-name[b-vwlea0n5hq] { font-weight:600; color:#1e293b; }
.qc-layer-meta[b-vwlea0n5hq] { margin-left:auto; font-size:.78rem; text-align:right; }
.qc-scan-check-head .btn[b-vwlea0n5hq] { margin-left:auto; }
.qc-dial-val .muted[b-vwlea0n5hq] { font-size:.62rem; }
.qc-scanner-scope[b-vwlea0n5hq] { display:flex; align-items:baseline; gap:.35rem; margin:0 0 .3rem; }
.qc-scanner-scope-label[b-vwlea0n5hq] { text-transform:uppercase; letter-spacing:.04em; font-size:.7rem; }
.qc-help[b-vwlea0n5hq] { margin:0 0 .5rem; padding:.4rem .55rem; border-left:2px solid #cbd5e1; border-radius:0 4px 4px 0; background:#f8fafc; }
.qc-page-row .btn[b-vwlea0n5hq] { min-width:1.4rem; padding:0 .3rem; line-height:1.35; font-size:.85rem; }
.qc-page-row .btn:disabled[b-vwlea0n5hq] { opacity:.45; cursor:default; }
.qc-page-row .muted[b-vwlea0n5hq] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
/* Informational, not a warning: nothing is wrong, the ticks are simply out of view. */
.img-note[b-vwlea0n5hq] { background:#e0e7ff; color:#3730a3; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
.adp-readout-head .muted[b-vwlea0n5hq] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-vwlea0n5hq] { color:#94a3b8; }
.adp-readout-table .muted[b-vwlea0n5hq] { color:#94a3b8; }
.pole-review .img-note[b-vwlea0n5hq] { background:#fff7ed; border:1px solid #fed7aa; color:#9a3412; border-radius:6px; margin:0; padding:.35rem .6rem; font-size:.76rem; }
.qc-bar-scope .muted[b-vwlea0n5hq] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-vwlea0n5hq] { font-size:.78rem; color:#64748b; }
/* /Components/Controls/MapFeatureCard.razor.rz.scp.css */
/* Bottom-CENTRE of the map stage, which is the one docking spot free on both
   hosts: Leaflet's zoom + basemap controls own the top-left, the systems /
   projects rails own the right edge, and RT QC's ADP readout owns the bottom-left.

   Centred by auto margins between left/right insets rather than by translateX(-50%):
   RT QC's bottom-left readout is a peer, not a no-go zone, and at 1366px a card
   centred in the whole stage starts ~30px inside its right edge. The host declares how
   much of its left edge is spoken for (--feature-card-inset-left) and the card centres
   in what is left; the 0px default leaves the Live Map as it was. */
.feature-card[b-wvkzdjnke0] {
    position: absolute;
    left: var(--feature-card-inset-left, 0px);
    right: 0;
    margin-left: auto;
    margin-right: auto;
    bottom: .75rem;
    /* One above the peer panels: they no longer overlap, but the card is always the
       thing the operator just clicked, so ties resolve in its favour. */
    z-index: 1101;
    width: 26rem;
    /* Measured against the inset region, not the whole stage — otherwise a narrow
       remainder over-constrains left/right/width and the card spills off the right
       edge instead of shrinking. */
    max-width: calc(100% - var(--feature-card-inset-left, 0px) - 1.5rem);
    /* The body is a fixed handful of rows, with one exception: a KML <name> is
       producer-supplied and can be arbitrarily long, and the name row wraps rather
       than truncating (an operator needs the whole line id). Bounded so a pathological
       name can't grow the card up the map. Matches the ADP readout's guard. */
    max-height: 18rem;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #cbd5e1;
    border-radius: 6px;
    padding: .5rem .7rem .6rem;
    box-shadow: 0 2px 10px rgba(15, 23, 42, .18);
    font-size: .78rem;
    color: #0f172a;
}

.feature-card-head[b-wvkzdjnke0] {
    display: flex;
    align-items: center;
    gap: .45rem;
    padding-bottom: .35rem;
    border-bottom: 1px solid #e2e8f0;
}

.feature-card-head strong[b-wvkzdjnke0] {
    flex: 1;
    min-width: 0;
    font-size: .86rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.feature-card-kind[b-wvkzdjnke0] {
    flex: none;
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    padding: .1rem .35rem;
    border-radius: 3px;
}

.feature-card-kind.is-project[b-wvkzdjnke0] { background: #ede9fe; color: #5b21b6; }
.feature-card-kind.is-flight[b-wvkzdjnke0] { background: #e0f2fe; color: #075985; }

.feature-card-close[b-wvkzdjnke0] {
    flex: none;
    background: #f1f5f9;
    border: 1px solid #cbd5e1;
    border-radius: 4px;
    color: #334155;
    font-size: .7rem;
    padding: .12rem .45rem;
    cursor: pointer;
}

.feature-card-close:hover[b-wvkzdjnke0] { background: #e2e8f0; }

.feature-card-name[b-wvkzdjnke0] {
    padding-top: .35rem;
    font-size: .82rem;
    font-weight: 600;
    word-break: break-word;
}

.feature-card-tags[b-wvkzdjnke0] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    padding-top: .2rem;
}

.feature-card-folder[b-wvkzdjnke0] {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .7rem;
    color: #475569;
    background: #f1f5f9;
    border-radius: 3px;
    padding: .05rem .3rem;
}

.feature-card-status[b-wvkzdjnke0] {
    font-size: .68rem;
    font-weight: 700;
    border-radius: 3px;
    padding: .05rem .35rem;
}

/* Tinted to the hues FlightKmzExporter actually strokes the track with — blue
   #3388ff ferry, green #16a34a collect, amber #f59e0b reposition — so a chip reads
   as the stroke it sits a few pixels from.

   The collect and ferry pairs are the shared .status-* values the Flights / Home /
   SystemFlights tables use, so the same word is the same swatch wherever it is a
   chip. Reposition is the one that deliberately differs: amber here because that is
   what the map draws, violet in those tables because amber already means REFLIGHT
   there. The text tone is a step darker than .status-reflight's so the two aren't
   pixel-identical even out of context. */
.feature-card-status.is-collecting[b-wvkzdjnke0] { background: #dcfce7; color: #166534; }
.feature-card-status.is-ferrying[b-wvkzdjnke0] { background: #dbeafe; color: #1d4ed8; }
.feature-card-status.is-repositioning[b-wvkzdjnke0] { background: #fef3c7; color: #92400e; }

.feature-card-facts[b-wvkzdjnke0] {
    display: flex;
    flex-wrap: wrap;
    gap: .15rem 1.1rem;
    margin: .4rem 0 0;
}

.feature-card-facts > div[b-wvkzdjnke0] { display: flex; align-items: baseline; gap: .3rem; }

.feature-card-facts dt[b-wvkzdjnke0] {
    font-size: .64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: #64748b;
}

.feature-card-facts dd[b-wvkzdjnke0] {
    margin: 0;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.feature-card-ends[b-wvkzdjnke0] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .35rem;
    margin-top: .35rem;
    padding-top: .3rem;
    border-top: 1px solid #f1f5f9;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .68rem;
    color: #475569;
}

.feature-card-arrow[b-wvkzdjnke0] { color: #94a3b8; }

/* "Flown by", in the slot the endpoint coordinates used to occupy. */
.feature-card-flown[b-wvkzdjnke0] {
    margin-top: .35rem;
    padding-top: .3rem;
    border-top: 1px solid #f1f5f9;
    font-size: .72rem;
}

.feature-card-flight[b-wvkzdjnke0] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .4rem;
    padding: .1rem 0;
}

.feature-card-flight-sys[b-wvkzdjnke0] {
    font-weight: 700;
    color: #0f172a;
}

.feature-card-flight-when[b-wvkzdjnke0] {
    /* Tabular so the dates line up when the list is expanded — an unaligned column of
       timestamps is the thing that makes a stack of passes hard to scan. */
    font-variant-numeric: tabular-nums;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: #475569;
}

/* Amber, matching REFLIGHT everywhere else in the dashboard tables. */
.feature-card-flight-tag[b-wvkzdjnke0] {
    font-size: .62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    background: #fef3c7;
    color: #b45309;
    border-radius: 3px;
    padding: .02rem .25rem;
}

.feature-card-more[b-wvkzdjnke0] {
    margin-top: .15rem;
    background: none;
    border: none;
    padding: 0;
    color: #4f46e5;
    font-size: .7rem;
    font-weight: 600;
    cursor: pointer;
}

.feature-card-more:hover[b-wvkzdjnke0] { text-decoration: underline; }

.feature-card .muted[b-wvkzdjnke0] { color: #94a3b8; font-weight: 400; }
/* /Components/Controls/MapLayerPanel.razor.rz.scp.css */
/* Scoped to this component, which is why the shared-looking names are restated rather than
   borrowed: Blazor rewrites every selector here with this component's own attribute, so a rule
   living in a sibling's stylesheet does not reach these rows. Same reason ScanLineLayerPanel
   carries its own copy. */

.qc-layer-intro[b-lo5ibf5ysr] { margin: 0 0 .45rem; }
.qc-help[b-lo5ibf5ysr] { margin: 0 0 .5rem; padding: .4rem .55rem; border-left: 2px solid #cbd5e1; border-radius: 0 4px 4px 0; background: #f8fafc; }
.qc-help p[b-lo5ibf5ysr] { margin: 0 0 .35rem; font-size: .76rem; line-height: 1.35; }
.qc-help p:last-child[b-lo5ibf5ysr] { margin-bottom: 0; }
.muted[b-lo5ibf5ysr] { color: #94a3b8; }
.small[b-lo5ibf5ysr] { font-size: .78rem; }

/* One row per family: the switch takes the width it needs and Only is pinned to the right, so
   the counts stay in a column that can be read down. */
.qc-layer-row[b-lo5ibf5ysr] { display: flex; align-items: center; gap: .4rem; margin: 0 0 .3rem; }
.qc-layer-toggle[b-lo5ibf5ysr] { display: flex; align-items: center; gap: .4rem; flex: 1; min-width: 0; cursor: pointer; font-size: .82rem; }
.qc-layer-name[b-lo5ibf5ysr] { font-weight: 600; color: #1e293b; }
.qc-layer-meta[b-lo5ibf5ysr] { margin-left: auto; font-size: .78rem; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.qc-layer-only[b-lo5ibf5ysr] { flex: none; }
/* A row with nothing to switch. The default cursor is the whole of what says so before the
   hover is read — a pointer over a row that cannot be pressed is the lie. Indented to where a
   checkbox would have put the name, so the column of labels still reads down. */
.qc-layer-toggle.is-fixed[b-lo5ibf5ysr] { cursor: default; padding-left: 1.4rem; }

/* The corridor row's source and hint lines. Indented to the checkbox's label so they read as
   belonging to the row above rather than as a paragraph of their own, and kept out of the help
   block on purpose: which corridor was drawn is a measurement, not prose. */
.qc-layer-src[b-lo5ibf5ysr] { margin: -.15rem 0 .35rem 1.4rem; }
/* A row whose box cannot be ticked yet. The cursor is what says so before the title is read. */
.qc-layer-toggle.is-off[b-lo5ibf5ysr] { cursor: default; }

.qc-layer-foot[b-lo5ibf5ysr] { display: flex; align-items: flex-start; gap: .4rem; margin-top: .5rem; }
.qc-layer-foot .img-note[b-lo5ibf5ysr] { flex: 1; }
.img-note[b-lo5ibf5ysr] { background: #e0e7ff; color: #3730a3; border-radius: 6px; padding: .4rem .55rem; font-size: .76rem; margin: 0; }
.img-warn[b-lo5ibf5ysr] { background: #fef3c7; color: #92400e; border-radius: 6px; padding: .4rem .55rem; font-size: .76rem; margin: 0; }
/* The corridor's own notes are paragraphs in the flow; the foot's is a flex child that supplies
   its own spacing. Only the paragraphs take a margin, or the foot gains a gap nothing asked for. */
p.img-note[b-lo5ibf5ysr], p.img-warn[b-lo5ibf5ysr] { margin: 0 0 .35rem; }
/* /Components/Controls/OrthoCheckPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-osdrzrouvy] { font-size:.78rem; color:#64748b; }
.projects-coverage-row[b-osdrzrouvy] { display:flex; align-items:center; gap:.4rem; margin:0 0 .55rem; padding-bottom:.45rem; border-bottom:1px solid #e2e8f0; cursor:pointer; }
.projects-coverage-text[b-osdrzrouvy] { color:#475569; font-size:.8rem; }
/* Ortho coverage check. Sits under the flown-coverage toggle it is the strict
       counterpart of: that one shows what WAS collected from stored flight rows, this
       shows what the ortho frames failed to cover, recomputed on demand. Red throughout,
       matching the "no coverage" pole verdict — one colour for one meaning across both
       halves of QC. */
.ortho-check[b-osdrzrouvy] { margin:0 0 .55rem; padding-bottom:.5rem; border-bottom:1px solid #e2e8f0; }
.ortho-check-head[b-osdrzrouvy] { display:flex; align-items:center; gap:.4rem; }
.ortho-check-title[b-osdrzrouvy] { color:#475569; font-size:.8rem; }
.ortho-gap-swatch[b-osdrzrouvy] { flex:0 0 auto; width:1.5rem; height:0; border-top:3px solid #dc2626; }
.ortho-run-btn[b-osdrzrouvy] { margin-left:auto; padding:.15rem .55rem; background:#fff; border:1px solid #cbd5e1; border-radius:6px; cursor:pointer; font-size:.74rem; color:#475569; }
.ortho-run-btn:hover:not(:disabled)[b-osdrzrouvy] { background:#fee2e2; border-color:#fca5a5; color:#991b1b; }
.ortho-run-btn:disabled[b-osdrzrouvy] { cursor:default; color:#94a3b8; background:#f8fafc; }
.ortho-summary[b-osdrzrouvy] { margin-top:.4rem; }
.ortho-bar[b-osdrzrouvy] { height:.4rem; border-radius:999px; background:#fecaca; overflow:hidden; margin-bottom:.3rem; }
.ortho-bar-fill[b-osdrzrouvy] { display:block; height:100%; background:#16a34a; }
.ortho-stat-row[b-osdrzrouvy] { display:flex; align-items:baseline; gap:.35rem; font-size:.78rem; color:#334155; }
.ortho-ok[b-osdrzrouvy] { color:#15803d; font-weight:600; }
.ortho-bad[b-osdrzrouvy] { color:#b91c1c; font-weight:600; }
.ortho-cam-row[b-osdrzrouvy] { display:flex; align-items:baseline; gap:.35rem; font-size:.74rem; color:#64748b; }
.ortho-cam-name[b-osdrzrouvy] { color:#334155; font-weight:600; min-width:3.4rem; }
/* Per-camera footprint swath toggle. Indented under its camera row so the swatch reads
       as belonging to that camera rather than to the project. */
.ortho-swath-row[b-osdrzrouvy] { display:flex; align-items:center; gap:.35rem; margin:.1rem 0 .25rem 3.75rem; cursor:pointer; font-size:.72rem; color:#64748b; }
.ortho-swath-row.is-on[b-osdrzrouvy] { color:#334155; }
.ortho-swath-swatch[b-osdrzrouvy] { flex:0 0 auto; width:.7rem; height:.7rem; border-radius:2px; border:1px solid; opacity:.45; }
.ortho-swath-text[b-osdrzrouvy] { white-space:nowrap; }
/* What is actually drawn, plus the one control that changes it. Wraps rather than
       ellipsising: this line is the difference between "all 575 frames" and "a raster at 12 m
       detail", which is exactly the sentence that must not be cut off. */
.ortho-swath-note[b-osdrzrouvy] { display:flex; flex-wrap:wrap; align-items:baseline; gap:.3rem .4rem; margin:-.15rem 0 .3rem 3.75rem; line-height:1.3; }
.ortho-swath-link[b-osdrzrouvy] { padding:0; border:0; background:none; color:#2563eb; font:inherit; cursor:pointer; text-decoration:underline; }
.ortho-swath-link:disabled[b-osdrzrouvy] { color:#94a3b8; cursor:default; text-decoration:none; }
.ortho-warning[b-osdrzrouvy] { margin:.35rem 0 0; padding:.3rem .45rem; background:#fff7ed; border:1px solid #fed7aa; border-radius:5px; color:#9a3412; font-size:.72rem; line-height:1.35; }
.ortho-note[b-osdrzrouvy] { margin:.3rem 0 0; }
.ortho-lines[b-osdrzrouvy] { margin-top:.35rem; max-height:14rem; overflow-y:auto; }
.ortho-line-row[b-osdrzrouvy] { display:flex; align-items:baseline; gap:.35rem; padding:.18rem .3rem; border-radius:4px; cursor:pointer; font-size:.76rem; }
.ortho-line-row:hover[b-osdrzrouvy] { background:#fef2f2; }
.ortho-line-name[b-osdrzrouvy] { flex:1; min-width:0; color:#0f172a; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ortho-line-pct[b-osdrzrouvy] { flex:0 0 auto; }
.projects-side-panel .muted[b-osdrzrouvy] { color:#94a3b8; }
.projects-side-panel .small[b-osdrzrouvy] { font-size:.78rem; }
.projects-side-panel .error[b-osdrzrouvy] { color:#b91c1c; font-weight:600; }
.qc-dial-val .muted[b-osdrzrouvy] { font-size:.62rem; }
.qc-page-row .muted[b-osdrzrouvy] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
.adp-readout-head .muted[b-osdrzrouvy] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-osdrzrouvy] { color:#94a3b8; }
.adp-readout-table .muted[b-osdrzrouvy] { color:#94a3b8; }
.qc-bar-scope .muted[b-osdrzrouvy] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-osdrzrouvy] { font-size:.78rem; color:#64748b; }
/* /Components/Controls/OrthoMosaicSection.razor.rz.scp.css */
.ortho-mosaic[b-407okdtfaj] { margin:.35rem 0 .3rem; padding:.3rem .45rem; border:1px solid #e2e8f0; border-radius:6px; background:#f8fafc; }

.om-head[b-407okdtfaj] { font-size:.7rem; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:#475569; margin-bottom:.15rem; }

.om-cam[b-407okdtfaj] { margin:.2rem 0; }

.om-name[b-407okdtfaj] { font-size:.72rem; color:#334155; margin-right:.3rem; }

.om-state[b-407okdtfaj] { font-size:.7rem; color:#64748b; }

.om-state.good[b-407okdtfaj] { color:#15803d; }

.om-state.bad[b-407okdtfaj] { color:#b91c1c; }

.om-state.busy[b-407okdtfaj] { color:#a16207; }

.om-note[b-407okdtfaj] { margin:.15rem 0 0; font-size:.72rem; color:#64748b; line-height:1.3; }

.om-note.warn[b-407okdtfaj] { color:#9a3412; }

.om-actions[b-407okdtfaj] { display:flex; gap:.3rem; margin-top:.3rem; }

.om-btn[b-407okdtfaj] { padding:.15rem .5rem; background:#fff; border:1px solid #cbd5e1; border-radius:6px; cursor:pointer; font-size:.74rem; color:#475569; }

.om-btn:hover:not(:disabled)[b-407okdtfaj] { border-color:#94a3b8; color:#0f172a; }

.om-btn:disabled[b-407okdtfaj] { opacity:.6; cursor:default; }
/* /Components/Controls/PoleHeightControlsPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.rtqc-viewer-meta .dim[b-xemgrjqbpe] { color:#64748b; }
.adp-readout-sub .dim[b-xemgrjqbpe] { color:#64748b; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.sensor-card-figure .dim[b-xemgrjqbpe] { font-size:.72rem; color:#64748b; }
.sensor-verdict .dim[b-xemgrjqbpe] { color:#94a3b8; }
.pole-range[b-xemgrjqbpe] { display:flex; align-items:center; gap:.4rem; }
.pole-num[b-xemgrjqbpe] { display:flex; align-items:center; gap:.3rem; }
.pole-num .dim[b-xemgrjqbpe] { color:#94a3b8; font-size:.68rem; }
.pole-mounts .dim[b-xemgrjqbpe] { color:#94a3b8; }
.pole-derived-agl[b-xemgrjqbpe] { color:#1e40af; font-size:.66rem; font-weight:700; text-transform:none; letter-spacing:normal; font-variant-numeric:tabular-nums; }
.pole-derived-agl.bad[b-xemgrjqbpe] { color:#b91c1c; }
.pole-review-head .dim[b-xemgrjqbpe] { color:#64748b; }
/* The fragment needs a single root; the rail needs none. display:contents gives both,
       so extracting it changed the rail's layout by nothing at all. It also has to stay:
       .pole-cone-body is a flex column with a gap, so an unstyled wrapper would fold the
       three height controls into ONE flex item and lose the spacing between them. */
.rtqc-stage .pole-height-controls[b-xemgrjqbpe] { display:contents; }
/* /Components/Controls/PoleReviewSettingsPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-goaf8o4lay] { font-size:.78rem; color:#64748b; }
.project-goto-btn[b-goaf8o4lay] { padding:.15rem .5rem; background:#fff; border:1px solid #cbd5e1; border-radius:6px; cursor:pointer; font-size:.74rem; color:#475569; }
.project-goto-btn:hover[b-goaf8o4lay] { background:#dbeafe; border-color:#93c5fd; color:#1e40af; }
.project-goto-btn.is-hiding[b-goaf8o4lay] { background:#eff6ff; border-color:#93c5fd; color:#1e40af; }
.projects-side-panel .muted[b-goaf8o4lay] { color:#94a3b8; }
.projects-side-panel .small[b-goaf8o4lay] { font-size:.78rem; }
/* Tree vocabulary for the QC rail's rows. Badge and name colors are lifted from the
       /images page (JDay in the same blue, monospace identifiers, the same pill badges)
       so the tree is recognizable as the same tree. Rows are tighter than the page's
       because the levels have to fit a 22rem rail rather than a full-width page. */
/* Wraps because the pole rail carries a picker per camera slot: three of them across a
       22rem rail leave a select too narrow to read a camera name out of. */
.img-toolbar[b-goaf8o4lay] { display:flex; flex-wrap:wrap; gap:.6rem; margin:.1rem 0 .5rem; }
/* Captionless, unlike every other .img-toolbar label — the gap and the uppercase run
       above the control have nothing left to space or letter. */
.img-toolbar label.pole-cam-slot[b-goaf8o4lay] { gap:0; }
.img-actions[b-goaf8o4lay] { display:flex; gap:.3rem; margin:0 0 .5rem; padding-bottom:.45rem; border-bottom:1px solid #e2e8f0; flex-wrap:wrap; }
.img-actions .project-goto-btn:disabled[b-goaf8o4lay] { opacity:.45; cursor:default; background:#f8fafc; }
.qc-dial-val .muted[b-goaf8o4lay] { font-size:.62rem; }
.qc-page-row .muted[b-goaf8o4lay] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
/* Informational, not a warning: nothing is wrong, the ticks are simply out of view. */
.img-note[b-goaf8o4lay] { background:#e0e7ff; color:#3730a3; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
/* ---- QC rail ---- Reuses the generic row/tree classes above throughout; these are only
       what that vocabulary has no equivalent of: the artifact rows under a day, and the
       presence chips that let a day be read without expanding it. */
.qc-note[b-goaf8o4lay] { margin:.1rem 0 .4rem; line-height:1.35; }
.rtqc-viewer-meta .dim[b-goaf8o4lay] { color:#64748b; }
.adp-readout-head .muted[b-goaf8o4lay] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .dim[b-goaf8o4lay] { color:#64748b; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.adp-readout-sub .muted[b-goaf8o4lay] { color:#94a3b8; }
.adp-readout-table .muted[b-goaf8o4lay] { color:#94a3b8; }
/* Two stacked bars over one track: covered grows from the left, no-coverage after it,
       and whatever is left of the track is pending. One bar per status rather than a
       single "reviewed" bar, because "we looked and there is nothing" is a different
       outcome from "we looked and it's fine" and the point of the review is the split. */
.pole-progress[b-goaf8o4lay] { padding:.15rem .3rem .35rem; }
.pole-progress-bar[b-goaf8o4lay] { display:flex; height:.5rem; border-radius:999px; overflow:hidden; background:#e2e8f0; }
.pole-bar-covered[b-goaf8o4lay] { background:#16a34a; }
.pole-bar-none[b-goaf8o4lay] { background:#dc2626; }
/* Same blue as the map dot in PoleFillOf - the segment and the dots it measures cannot
       be allowed to drift apart. */
.pole-bar-ready[b-goaf8o4lay] { background:#3b82f6; }
/* One row, always. Measured, the five standard chips want 365px against the 342px the
       rail gives them, so the compression on .pole-chip below is what makes the ordinary
       case fit rather than merely not wrap. nowrap + overflow-x is the backstop for the
       cases that still cannot: a six-figure pole count, or the two extra chips a scene
       scope adds. Scrolling a filter row is recoverable; a second row is what was asked
       against, and clipping would hide a filter with no way to reach it. */
.pole-progress-legend[b-goaf8o4lay] { display:flex; flex-wrap:nowrap; overflow-x:auto; scrollbar-width:thin; gap:.2rem; margin-top:.35rem; padding-bottom:.1rem; }
/* flex:0 0 auto so a tight row scrolls rather than squeezing every chip until its
       label ellipsises — an unreadable filter is worse than one off the right edge. */
.pole-chip[b-goaf8o4lay] { flex:0 0 auto; border:1px solid #e2e8f0; background:#f8fafc; color:#475569; border-radius:999px; padding:.1rem .32rem; font-size:.67rem; cursor:pointer; display:inline-flex; gap:.2rem; align-items:center; white-space:nowrap; }
.pole-chip:hover[b-goaf8o4lay] { border-color:#94a3b8; }
.pole-chip.is-on[b-goaf8o4lay] { border-color:#1d4ed8; background:#eff6ff; color:#1e40af; }
/* Re-flown poles. Violet rather than another warm tone: gold/green/red are already spoken
       for by the three verdicts, and this is not a fourth verdict — it is a pole that has one
       and needs looking at again. */
.pole-chip.requeued[b-goaf8o4lay] { border-color:#ddd6fe; background:#f5f3ff; }
.sensor-card-figure .dim[b-goaf8o4lay] { font-size:.72rem; color:#64748b; }
.sensor-verdict .dim[b-goaf8o4lay] { color:#94a3b8; }
.sensor-card-actions .project-goto-btn:disabled[b-goaf8o4lay] { opacity:.45; cursor:default; background:#f8fafc; }
/* The ORTHO panel's own notes, which predate the scene cards and are not on the rail. Same
       three variants as .scene-note; kept separate rather than merged because that one is scoped
       to a card's padding and this one to a popover's. */
.queue-item-note[b-goaf8o4lay] { margin:.3rem 0 0; font-size:.72rem; color:#64748b; line-height:1.3; }
.queue-item-note.warn[b-goaf8o4lay] { color:#9a3412; }
.pole-cone[b-goaf8o4lay] { margin:.2rem .3rem .35rem; border:1px solid #e2e8f0; border-radius:6px; background:#f8fafc; }
.pole-cone-body[b-goaf8o4lay] { padding:.15rem .45rem .4rem; display:flex; flex-direction:column; gap:.3rem; }
.pole-range[b-goaf8o4lay] { display:flex; align-items:center; gap:.4rem; }
.pole-num .dim[b-goaf8o4lay] { color:#94a3b8; font-size:.68rem; }
.pole-cone-note[b-goaf8o4lay] { margin:.15rem 0 0; color:#64748b; font-size:.66rem; line-height:1.35; text-transform:none; letter-spacing:normal; font-weight:400; }
/* What the rig is understood to be, and where that puts each frame's centre. The line
       that makes a wrong flying height or a wrong mount obvious before anything is marked. */
.pole-mounts[b-goaf8o4lay] { display:flex; flex-direction:column; gap:.15rem; padding:.2rem 0; border-top:1px solid #e2e8f0; }
.pole-mount-row[b-goaf8o4lay] { display:flex; flex-wrap:wrap; gap:.35rem; align-items:baseline; font-size:.68rem; color:#475569; font-variant-numeric:tabular-nums; }
.pole-mount-cam[b-goaf8o4lay] { font-weight:700; color:#0f172a; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.pole-mount-geom[b-goaf8o4lay] { color:#0f172a; }
.pole-mount-aim[b-goaf8o4lay] { background:#eff6ff; color:#1e40af; border-radius:999px; padding:.02rem .35rem; font-weight:700; }
.pole-mount-warn[b-goaf8o4lay] { background:#fef9c3; color:#a16207; border-radius:999px; padding:.02rem .35rem; }
.pole-mounts .dim[b-goaf8o4lay] { color:#94a3b8; }
.pole-mount-override[b-goaf8o4lay] { background:#eff6ff; color:#1e40af; border-radius:999px; padding:.02rem .35rem; font-size:.62rem; font-weight:700; text-transform:uppercase; letter-spacing:.04em; }
/* The escape hatch for a rig whose camera names don't resolve to a configured mount. Kept
       compact and directly under the readout it corrects, so the fix is where the problem is
       reported rather than in appsettings.json and a restart away. */
.pole-mount-edit[b-goaf8o4lay] { display:flex; flex-wrap:wrap; gap:.4rem; align-items:center; padding:0 0 .25rem .6rem; }
.pole-mount-clear[b-goaf8o4lay] { border:1px solid #cbd5e1; background:#f8fafc; color:#475569; border-radius:5px; padding:.05rem .35rem; font-size:.62rem; cursor:pointer; }
.pole-mount-clear:hover[b-goaf8o4lay] { background:#e2e8f0; }
.pole-review-head .dim[b-goaf8o4lay] { color:#64748b; }
.pole-scene-bar .pole-bar-covered[b-goaf8o4lay] { background:#16a34a; }
.pole-scene-bar .pole-bar-none[b-goaf8o4lay] { background:#dc2626; }
.pole-review .img-note[b-goaf8o4lay] { background:#fff7ed; border:1px solid #fed7aa; color:#9a3412; border-radius:6px; margin:0; padding:.35rem .6rem; font-size:.76rem; }
.qc-bar-scope .muted[b-goaf8o4lay] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-goaf8o4lay] { font-size:.78rem; color:#64748b; }
/* The fragment needs a single root; the rail needs none. display:contents gives both,
       so extracting it changed the rail's layout by nothing at all. */
.pole-settings[b-goaf8o4lay] { display:contents; }
/* /Components/Controls/ScanCheckPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-o6rvigtuk4] { font-size:.78rem; color:#64748b; }
.projects-side-panel .muted[b-o6rvigtuk4] { color:#94a3b8; }
.projects-side-panel .small[b-o6rvigtuk4] { font-size:.78rem; }
.img-warn[b-o6rvigtuk4] { background:#fef3c7; color:#92400e; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
.qc-flight-top .btn[b-o6rvigtuk4] { margin-left:auto; }
.qc-layer-name[b-o6rvigtuk4] { font-weight:600; color:#1e293b; }
/* The coverage check, under the scanner display toggles it shares a scope with. Separated by
       a rule rather than a heading: the toggles say how the sweeps DRAW and this says what they
       covered, which are different questions about one selection. */
.qc-scan-check[b-o6rvigtuk4] { margin-top:.6rem; padding-top:.55rem; border-top:1px solid #e2e8f0; }
.qc-scan-check-head[b-o6rvigtuk4] { display:flex; align-items:center; gap:.5rem; margin-bottom:.35rem; }
.qc-scan-check-head .btn[b-o6rvigtuk4] { margin-left:auto; }
/* One card per gap layer: the tick that draws it, the share it accounts for, and the walk
       through it. Boxed rather than left as flat rows because each card is a piece of WORK — a
       stretch somebody has to fly again — and the two of them mean opposite things: fly it again
       versus fly it differently. */
.qc-issue[b-o6rvigtuk4] { border:1px solid #e2e8f0; border-radius:7px; padding:.35rem .45rem .3rem; margin:0 0 .4rem; }
.qc-issue-main[b-o6rvigtuk4] { display:flex; align-items:center; gap:.4rem; margin:0; cursor:pointer; font-size:.82rem; }
.qc-issue-meta[b-o6rvigtuk4] { margin-left:auto; font-size:.72rem; text-align:right; white-space:nowrap; font-variant-numeric:tabular-nums; }
/* The walk, indented to the layer NAME above it — past the tick and its legend mark — so it
       reads as that layer's control rather than as a second row in a list. */
.qc-issue-go[b-o6rvigtuk4] { display:flex; align-items:center; gap:.45rem; margin-top:.3rem; padding-left:1.55rem; }
.qc-issue-warn[b-o6rvigtuk4] { margin:.35rem 0 0; }
/* Which run the cards below came from, needed only once the dials can be showing a different
       scope from the layers. */
.qc-issue-head[b-o6rvigtuk4] { font-size:.7rem; text-transform:uppercase; letter-spacing:.04em; margin:.1rem 0 .3rem; }
/* The resolution of the corridor figure. The fold hides the explanation and never the
       invisible-hole SIZE, which stays in the summary. */
.qc-fold[b-o6rvigtuk4] { margin:.15rem 0 .45rem; }
/* The run is the panel's one filled control — everything else here is a tick or a walk. */
.qc-run-btn[b-o6rvigtuk4] { border-radius:999px; border-color:#4f46e5; background:#4f46e5; color:#fff; font-weight:600; }
.qc-run-btn:hover:not(:disabled)[b-o6rvigtuk4] { border-color:#4338ca; background:#4338ca; color:#fff; }
.qc-run-btn:disabled[b-o6rvigtuk4] { border-color:#e2e8f0; background:#e2e8f0; color:#94a3b8; }
.qc-scan-stamp[b-o6rvigtuk4] { margin:.4rem 0 0; }
/* Same red as the ortho gap swatch — they mean the same thing, and two reds would invite
       reading a difference into them that is not there. */
.scan-gap-legend[b-o6rvigtuk4] { display:inline-block; width:14px; height:0; border-top:2.5px solid #dc2626; vertical-align:middle; }
/* Amber and DASHED, matching what is drawn on the map. Both halves of that matter: the
       corridor layer sits on top of the red one wherever a stretch is missing from both, so the
       dash is what says which is which where the two overlap. */
.scan-corridor-legend[b-o6rvigtuk4] { display:inline-block; width:14px; height:0; border-top:2.5px dashed #f59e0b; vertical-align:middle; }
/* The corridor WIDTH row: an input, so it sits above the run and stays put after it — a
       corridor percentage with no width beside it cannot be checked or quoted. */
.qc-corridor[b-o6rvigtuk4] { display:flex; flex-wrap:wrap; align-items:baseline; gap:.4rem; margin:.1rem 0 .5rem; }
.qc-corridor-label[b-o6rvigtuk4] { text-transform:uppercase; letter-spacing:.04em; font-size:.7rem; }
/* The width the swath dial is measured against, as a chip. It is an INPUT to the answer and
       not one of its figures, and the pill is what keeps it from reading as a third measurement
       over the two below it. */
.qc-corridor-chip[b-o6rvigtuk4] { display:inline-flex; align-items:baseline; gap:.35rem; padding:.1rem .55rem .15rem; border-radius:999px; background:#eef2ff; color:#3730a3; }
.qc-corridor-chip .qc-corridor-label[b-o6rvigtuk4] { color:#6366f1; }
/* Where the number came from, on its own line under the chip: at 20rem a KMZ folder name and
       a chip do not share one, and a source that wraps on its own reads as a stray label. */
.qc-corridor-src[b-o6rvigtuk4] { flex-basis:100%; }
.qc-corridor-input[b-o6rvigtuk4] { width:5.5rem; }
/* The field and its unit move together. "ft across" alone on a line reads as a stray label,
       and it is the word that says the figure is the full span rather than either side of it. */
.qc-corridor-entry[b-o6rvigtuk4] { display:inline-flex; align-items:baseline; gap:.3rem; white-space:nowrap; }
.qc-corridor-note[b-o6rvigtuk4] { flex-basis:100%; line-height:1.35; }
/* WHICH FLYING the dials below describe. A tab pair rather than a second row of figures: at
       20rem two dials already fill the panel, and the scoped answer and the project answer are
       the same two questions asked of different flying rather than four numbers to read at once.
       Each tab names its own scope and each dial carries its own denominator, which is what stops
       a figure being read against the other tab's mileage. */
.qc-scope-tabs[b-o6rvigtuk4] { display:flex; gap:.3rem; margin:.45rem 0 .1rem; }
.qc-dial-val .muted[b-o6rvigtuk4] { font-size:.62rem; }
.qc-dial-empty[b-o6rvigtuk4] { display:flex; align-items:center; gap:.45rem; margin:.45rem 0 .5rem; line-height:1.3; }
.qc-help[b-o6rvigtuk4] { margin:0 0 .5rem; padding:.4rem .55rem; border-left:2px solid #cbd5e1; border-radius:0 4px 4px 0; background:#f8fafc; }
.qc-page-row .btn[b-o6rvigtuk4] { min-width:1.4rem; padding:0 .3rem; line-height:1.35; font-size:.85rem; }
.qc-page-row .btn:disabled[b-o6rvigtuk4] { opacity:.45; cursor:default; }
.qc-page-row .muted[b-o6rvigtuk4] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
/* Informational, not a warning: nothing is wrong, the ticks are simply out of view. */
.img-note[b-o6rvigtuk4] { background:#e0e7ff; color:#3730a3; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
.adp-readout-head .muted[b-o6rvigtuk4] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-o6rvigtuk4] { color:#94a3b8; }
.adp-readout-table .muted[b-o6rvigtuk4] { color:#94a3b8; }
.pole-review .img-note[b-o6rvigtuk4] { background:#fff7ed; border:1px solid #fed7aa; color:#9a3412; border-radius:6px; margin:0; padding:.35rem .6rem; font-size:.76rem; }
.qc-bar-input[b-o6rvigtuk4] { border:1px solid #cbd5e1; border-radius:6px; background:#f8fafc; color:#0f172a; padding:.3rem .45rem; font-size:.85rem; min-width:11rem; }
.qc-bar-input:focus[b-o6rvigtuk4] { outline:2px solid #93c5fd; outline-offset:1px; }
.qc-bar-scope .muted[b-o6rvigtuk4] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-o6rvigtuk4] { font-size:.78rem; color:#64748b; }

@media (max-width: 900px) {
    .qc-bar-input[b-o6rvigtuk4] { min-width:8rem; }
}
/* /Components/Controls/ScanCoverageDials.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-d5istp2iw9] { font-size:.78rem; color:#64748b; }
.projects-side-panel .muted[b-d5istp2iw9] { color:#94a3b8; }
.projects-side-panel .small[b-d5istp2iw9] { font-size:.78rem; }
/* The two questions as two dials, side by side and never merged into one: a project reading
       100% along its lines and 60% across its corridors is the case a single figure hides. */
.qc-dials[b-d5istp2iw9] { display:grid; grid-template-columns:1fr 1fr; gap:.5rem; margin:.45rem 0 .5rem; }
.qc-dial[b-d5istp2iw9] { display:flex; flex-direction:column; align-items:center; text-align:center; min-width:0; }
.qc-dial-cap[b-d5istp2iw9] { font-size:.7rem; font-weight:600; text-transform:uppercase; letter-spacing:.04em; color:#475569; }
.qc-dial-sub[b-d5istp2iw9] { font-size:.66rem; color:#94a3b8; line-height:1.25; }
.qc-dial-val .muted[b-d5istp2iw9] { font-size:.62rem; }
/* What the figure above is a percentage OF. Under the dial rather than beside it: a
       denominator that moved silently is worse than the wrong denominator. */
.qc-dial-scope[b-d5istp2iw9] { font-size:.68rem; line-height:1.25; }
/* "Not measured" and "width changed" keep the dial's column but not its ring — an absent
       answer drawn as an empty dial is a 0% somebody quotes. */
.qc-dial-none[b-d5istp2iw9] { display:flex; align-items:center; min-height:4.5rem; line-height:1.3; }
.qc-page-row .muted[b-d5istp2iw9] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
.adp-readout-head .muted[b-d5istp2iw9] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-d5istp2iw9] { color:#94a3b8; }
.adp-readout-table .muted[b-d5istp2iw9] { color:#94a3b8; }
.qc-bar-scope .muted[b-d5istp2iw9] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-d5istp2iw9] { font-size:.78rem; color:#64748b; }
/* /Components/Controls/ScanLineLayerPanel.razor.rz.scp.css */
/* Extracted from RtQc's page <style> block when this component's styles were
   still living there. It rendered correctly only inside RtQc until then, because the
   page's global block was the only thing styling it. */

.projects-side-panel-header .muted[b-oat8suordw] { font-size:.78rem; color:#64748b; }
.projects-side-panel .muted[b-oat8suordw] { color:#94a3b8; }
.projects-side-panel .small[b-oat8suordw] { font-size:.78rem; }
.img-warn[b-oat8suordw] { background:#fef3c7; color:#92400e; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
/* Same contract again, against SCANLINE_POINT_FILL / _RING / _RADIUS — smallest of the
       three, for the reason its marker is: two dots per sweep at scanner line rate makes this
       the densest layer on the map. */
.scan-legend-dot[b-oat8suordw] { display:inline-block; width:7px; height:7px; border-radius:50%; background:#f59e0b; border:1.5px solid #0f172a; margin-right:.35rem; vertical-align:baseline; }
.qc-flight-top .btn[b-oat8suordw] { margin-left:auto; }
/* The swath toggle. A row rather than an inline control so its counts wrap under the label on
       a narrow rail instead of pushing the checkbox off the edge. */
/* One row per drawable layer in the bar's SCANNER popover: checkbox, legend mark matching how
       that layer actually draws, name, then its count pushed to the right so two rows' numbers
       line up and can be compared at a glance. */
.qc-layer-toggle[b-oat8suordw] { display:flex; align-items:center; gap:.4rem; margin:0 0 .35rem; cursor:pointer; font-size:.82rem; }
.qc-layer-name[b-oat8suordw] { font-weight:600; color:#1e293b; }
.qc-layer-meta[b-oat8suordw] { margin-left:auto; font-size:.78rem; text-align:right; }
.qc-scan-check-head .btn[b-oat8suordw] { margin-left:auto; }
.qc-dial-val .muted[b-oat8suordw] { font-size:.62rem; }
.qc-scanner-scope[b-oat8suordw] { display:flex; align-items:baseline; gap:.35rem; margin:0 0 .3rem; }
.qc-scanner-scope-label[b-oat8suordw] { text-transform:uppercase; letter-spacing:.04em; font-size:.7rem; }
.qc-help[b-oat8suordw] { margin:0 0 .5rem; padding:.4rem .55rem; border-left:2px solid #cbd5e1; border-radius:0 4px 4px 0; background:#f8fafc; }
/* A measured figure belonging to the toggle row above it, aligned with that row's NAME — past
       the checkbox and its legend mark — so it reads as part of that row and not as another layer. */
.qc-layer-sub[b-oat8suordw] { margin:-.2rem 0 .45rem; padding-left:1.55rem; }
/* The endpoint pager, indented like the Go-to walk and for the same reason: it belongs to the
       row above it. Tight arrow buttons, because the range beside them is the part being read. */
.qc-page-row[b-oat8suordw] { display:flex; align-items:center; gap:.25rem; margin:-.15rem 0 .5rem; padding-left:1.55rem; }
.qc-page-row .btn[b-oat8suordw] { min-width:1.4rem; padding:0 .3rem; line-height:1.35; font-size:.85rem; }
.qc-page-row .btn:disabled[b-oat8suordw] { opacity:.45; cursor:default; }
.qc-page-row .muted[b-oat8suordw] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
/* A dashed light-blue block, matching how the ribbon actually draws — filled and dashed-edged.
       Broken out from the sweep-end dots' amber because a translucent amber fill read as
       terrain/road color on satellite basemaps and disappeared; the dots keep amber since they
       are small enough that contrast isn't the problem. */
/* Two solid rules rather than a dashed box: the layer is a pair of edges at full
       resolution now, not an averaged fill, and the mark has to say which. */
.scan-swath-legend[b-oat8suordw] { display:inline-block; width:14px; height:8px; border-top:2px solid #38bdf8; border-bottom:2px solid #38bdf8; vertical-align:baseline; }
/* Informational, not a warning: nothing is wrong, the ticks are simply out of view. */
.img-note[b-oat8suordw] { background:#e0e7ff; color:#3730a3; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
.qc-onmap .scan-legend-dot[b-oat8suordw] { margin-left:.35rem; }
.adp-readout-head .muted[b-oat8suordw] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub .muted[b-oat8suordw] { color:#94a3b8; }
.adp-readout-table .muted[b-oat8suordw] { color:#94a3b8; }
.pole-review .img-note[b-oat8suordw] { background:#fff7ed; border:1px solid #fed7aa; color:#9a3412; border-radius:6px; margin:0; padding:.35rem .6rem; font-size:.76rem; }
.qc-bar-scope .muted[b-oat8suordw] { color:#64748b; font-style:italic; }
.qc-popover-head .muted[b-oat8suordw] { font-size:.78rem; color:#64748b; }
/* /Components/Controls/SessionGuard.razor.rz.scp.css */
.session-unavailable[b-dctgrlp54j] {
    position: fixed;
    top: 0.75rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2000;
    max-width: calc(100vw - 2rem);
    padding: 0.5rem 0.9rem;
    border: 1px solid #f59e0b;
    border-radius: 6px;
    background: #fffbeb;
    color: #9a3412;
    font-size: 0.85rem;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.session-unavailable a[b-dctgrlp54j] {
    margin-left: 0.5rem;
    color: inherit;
    font-weight: 600;
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
#blazor-error-ui[b-p3ytkk4pib] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-p3ytkk4pib] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-m0gbzxqqxi],
.components-reconnect-repeated-attempt-visible[b-m0gbzxqqxi],
.components-reconnect-failed-visible[b-m0gbzxqqxi],
.components-pause-visible[b-m0gbzxqqxi],
.components-resume-failed-visible[b-m0gbzxqqxi],
.components-rejoining-animation[b-m0gbzxqqxi] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-retrying[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-failed[b-m0gbzxqqxi],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-m0gbzxqqxi] {
    display: block;
}


#components-reconnect-modal[b-m0gbzxqqxi] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-m0gbzxqqxi 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-m0gbzxqqxi 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-m0gbzxqqxi 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-m0gbzxqqxi]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-m0gbzxqqxi 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-m0gbzxqqxi {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-m0gbzxqqxi {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-m0gbzxqqxi {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-m0gbzxqqxi] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-m0gbzxqqxi] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-m0gbzxqqxi] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-m0gbzxqqxi] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-m0gbzxqqxi] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-m0gbzxqqxi] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-m0gbzxqqxi] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-m0gbzxqqxi 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-m0gbzxqqxi] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-m0gbzxqqxi {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Pages/RtQc.razor.rz.scp.css */
/* RT QC's page styles. Isolated rather than a page <style> block, which is plain
   global CSS: the generic names in here (.qc-note, .img-row, .dim, .muted) are exactly
   the kind that have leaked out of a block in this repo and restyled the sidebar, which
   is what the hand-written `.rtqc-stage` prefix on 384 rules used to be holding back.
   Isolation does that scoping properly, so the prefix is gone.

   Specificity did not move when it went: dropping one class and gaining one attribute
   selector is a wash, so the override order inside this file is what it always was.

   `.rtqc-stage.has-readout` sets --feature-card-inset-left for MapFeatureCard's OWN
   scoped rules to read. That still works across the scope boundary because custom
   properties inherit down the DOM and know nothing about scope attributes. */

/* Pin the map to the viewport right of the sidebar so it fills the window
       without affecting main's scroll-overflow calculation — margins here would
       push main into showing a scrollbar. Same trick as .live-map-stage. */
.rtqc-stage[b-a93jw9iay3] { position:fixed; top:var(--shell-top, 0px); left:var(--shell-left, 220px); right:0; bottom:0; display:flex; flex-direction:column; }
/* The containing block for every map overlay, and the reason the filter bar needs no
       inset anywhere: it is a flex item that gives up exactly the bar's height, whatever
       that turns out to be at this width and with this content. min-height:0 because a
       flex item's default min-height:auto would let the map refuse to shrink. */
.rtqc-map-area[b-a93jw9iay3] { position:relative; flex:1 1 auto; min-height:0; }
/* Open rails SHARE the column rather than shrinking from their content height. `flex:0 1 auto`
       shrinks in proportion to content, so a 67-scene queue left QC by day a 60px strip of
       header. Basis 0 splits the height evenly; max-content hands what a short rail does not
       need to the others. Basis 0 needs a column of definite height to split, hence
       top + bottom, which costs nothing because the column itself takes no pointer. The
       bottom clears Leaflet's attribution (~17px, bottom-right), which the imagery terms
       require to stay readable and a full rail used to sit over. */
.right-rail-panels[b-a93jw9iay3] { position:absolute; top:.75rem; bottom:1.75rem; right:0; z-index:1100; display:flex; flex-direction:column; align-items:flex-end; gap:.55rem; min-height:0; pointer-events:none; }
.projects-side-panel[b-a93jw9iay3] { display:flex; align-items:stretch; min-height:0; flex:0 0 auto; pointer-events:auto; }
.projects-side-panel.open[b-a93jw9iay3] { flex:1 1 0; max-height:max-content; }
.projects-side-panel-handle[b-a93jw9iay3] { display:flex; flex-direction:column; align-items:center; gap:.35rem; background:#475569; color:white; border:none; padding:.55rem .35rem; cursor:pointer; border-radius:6px 0 0 6px; font-weight:700; letter-spacing:.12em; font-size:.95rem; box-shadow:-2px 0 6px rgba(15,23,42,.18); height:fit-content; align-self:flex-start; }
.projects-side-panel-handle:hover[b-a93jw9iay3] { background:#334155; }
.projects-side-panel-arrow[b-a93jw9iay3] { font-size:.7rem; }
.projects-side-panel-label[b-a93jw9iay3] { writing-mode:vertical-rl; transform:rotate(180deg); }
.projects-side-panel-body[b-a93jw9iay3] { width:22rem; min-height:0; overflow-y:auto; background:#fff; border:1px solid #cbd5e1; border-right:none; border-radius:6px 0 0 6px; padding:.7rem .8rem; box-shadow:-3px 0 10px rgba(15,23,42,.1); }
.projects-side-panel-header[b-a93jw9iay3] { display:flex; justify-content:space-between; align-items:baseline; gap:.5rem; margin-bottom:.45rem; padding-bottom:.35rem; border-bottom:1px solid #e2e8f0; }
.projects-side-panel-header .muted[b-a93jw9iay3] { font-size:.78rem; color:#64748b; }
.projects-color-row[b-a93jw9iay3] { display:flex; align-items:center; gap:.35rem; margin:.1rem 0 .55rem; padding-bottom:.45rem; border-bottom:1px solid #e2e8f0; flex-wrap:wrap; }
.project-color-swatch[b-a93jw9iay3] { width:1.15rem; height:1.15rem; border-radius:50%; border:2px solid #e2e8f0; cursor:pointer; padding:0; transition:transform .1s ease; }
.project-color-swatch:hover[b-a93jw9iay3] { transform:scale(1.12); }
.project-color-swatch.is-selected[b-a93jw9iay3] { border-color:#0f172a; box-shadow:0 0 0 2px rgba(15,23,42,.12); }
.project-color-original[b-a93jw9iay3] { background:#fff; display:inline-flex; align-items:center; justify-content:center; }
.swatch-x[b-a93jw9iay3] { color:#64748b; font-size:.95rem; line-height:1; font-weight:700; }
.projects-coverage-row[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; margin:0 0 .55rem; padding-bottom:.45rem; border-bottom:1px solid #e2e8f0; cursor:pointer; }
.projects-coverage-row input[b-a93jw9iay3] { cursor:pointer; flex:0 0 auto; }
.projects-coverage-text[b-a93jw9iay3] { color:#475569; font-size:.8rem; }
.coverage-legend-swatch[b-a93jw9iay3] { flex:0 0 auto; width:1.5rem; height:0; border-top:3px dashed #0f172a; margin-left:auto; }
/* Not-flown gaps: the swatch is the map's own orange, solid, so it is told apart from the red
   sensor gaps and the dashed flown coverage above it. */
.plan-gaps[b-a93jw9iay3] { margin:0 0 .55rem; padding-bottom:.45rem; border-bottom:1px solid #e2e8f0; }
.plan-gaps-row[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; cursor:pointer; }
.plan-gaps-row input[b-a93jw9iay3] { cursor:pointer; flex:0 0 auto; }
.plan-gap-swatch[b-a93jw9iay3] { flex:0 0 auto; width:1.5rem; height:0; border-top:3px solid #ea580c; margin-left:auto; }
.plan-gap-kind[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; cursor:pointer; }
.plan-gap-kind input[b-a93jw9iay3] { cursor:pointer; flex:0 0 auto; margin:0; }
.plan-gap-kind-swatch[b-a93jw9iay3] { flex:0 0 auto; width:1.4rem; height:0; border-top-width:3px; }
.plan-gaps-status[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.2rem; margin-top:.3rem; color:#334155; font-size:.76rem; line-height:1.35; }
.plan-gaps-note[b-a93jw9iay3] { color:#92400e; }
.plan-gaps-actions[b-a93jw9iay3] { display:flex; gap:.3rem; flex-wrap:wrap; }
.plan-gaps-btn[b-a93jw9iay3] { padding:.12rem .5rem; background:#fff; border:1px solid #cbd5e1; border-radius:6px; cursor:pointer; font-size:.72rem; color:#475569; }
.plan-gaps-btn:hover[b-a93jw9iay3] { background:#fff7ed; border-color:#fdba74; color:#9a3412; }
/* Ortho coverage check. Sits under the flown-coverage toggle it is the strict
       counterpart of: that one shows what WAS collected from stored flight rows, this
       shows what the ortho frames failed to cover, recomputed on demand. Red throughout,
       matching the "no coverage" pole verdict — one colour for one meaning across both
       halves of QC. */
.ortho-check[b-a93jw9iay3] { margin:0 0 .55rem; padding-bottom:.5rem; border-bottom:1px solid #e2e8f0; }
.ortho-check-head[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; }
.ortho-check-title[b-a93jw9iay3] { color:#475569; font-size:.8rem; }
.ortho-gap-swatch[b-a93jw9iay3] { flex:0 0 auto; width:1.5rem; height:0; border-top:3px solid #dc2626; }
.ortho-run-btn[b-a93jw9iay3] { margin-left:auto; padding:.15rem .55rem; background:#fff; border:1px solid #cbd5e1; border-radius:6px; cursor:pointer; font-size:.74rem; color:#475569; }
.ortho-run-btn:hover:not(:disabled)[b-a93jw9iay3] { background:#fee2e2; border-color:#fca5a5; color:#991b1b; }
.ortho-run-btn:disabled[b-a93jw9iay3] { cursor:default; color:#94a3b8; background:#f8fafc; }
.ortho-stat-row[b-a93jw9iay3] { display:flex; align-items:baseline; gap:.35rem; font-size:.78rem; color:#334155; }
.ortho-ok[b-a93jw9iay3] { color:#15803d; font-weight:600; }
.ortho-bad[b-a93jw9iay3] { color:#b91c1c; font-weight:600; }
.ortho-swath-row input[b-a93jw9iay3] { cursor:pointer; flex:0 0 auto; margin:0; }
.ortho-swath-link[b-a93jw9iay3] { padding:0; border:0; background:none; color:#2563eb; font:inherit; cursor:pointer; text-decoration:underline; }
.ortho-swath-link:disabled[b-a93jw9iay3] { color:#94a3b8; cursor:default; text-decoration:none; }
/* The view-mode pair, inline at the end of the sentence that explains why they are offered.
       Wrapped in its own span so the buttons stay together when the note wraps. */
.qc-view-actions[b-a93jw9iay3] { display:inline-flex; gap:.55rem; margin-left:.35rem; white-space:nowrap; }
.ortho-note[b-a93jw9iay3] { margin:.3rem 0 0; }
.projects-side-row[b-a93jw9iay3] { padding:.35rem 0; border-bottom:1px solid #f1f5f9; }
.projects-side-row:last-child[b-a93jw9iay3] { border-bottom:none; }
.projects-side-row-main[b-a93jw9iay3] { display:flex; align-items:center; gap:.45rem; cursor:pointer; padding:.2rem .35rem; border-radius:4px; user-select:none; }
.projects-side-row-main:hover[b-a93jw9iay3] { background:#f1f5f9; }
.projects-side-row-main.open[b-a93jw9iay3] { background:#eef2ff; }
.projects-side-row-text[b-a93jw9iay3] { display:flex; flex-direction:column; flex:1; min-width:0; }
.projects-side-row-name[b-a93jw9iay3] { color:#0f172a; font-weight:600; font-size:.88rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.projects-side-row-sys[b-a93jw9iay3] { color:#64748b; font-size:.74rem; }
.projects-side-row-chevron[b-a93jw9iay3] { color:#475569; font-size:1rem; width:1rem; text-align:center; line-height:1; }
.project-goto-btn[b-a93jw9iay3] { padding:.15rem .5rem; background:#fff; border:1px solid #cbd5e1; border-radius:6px; cursor:pointer; font-size:.74rem; color:#475569; }
.project-goto-btn:hover[b-a93jw9iay3] { background:#dbeafe; border-color:#93c5fd; color:#1e40af; }
.project-goto-btn.is-hiding[b-a93jw9iay3] { background:#eff6ff; border-color:#93c5fd; color:#1e40af; }
.projects-side-layers[b-a93jw9iay3] { margin:.25rem 0 .35rem 1.4rem; padding:0; }
.projects-side-panel .muted[b-a93jw9iay3] { color:#94a3b8; }
.projects-side-panel .small[b-a93jw9iay3] { font-size:.78rem; }
.projects-side-panel .error[b-a93jw9iay3] { color:#b91c1c; font-weight:600; }
.project-folder[b-a93jw9iay3] { border-bottom:1px solid #f1f5f9; }
.project-folder:last-child[b-a93jw9iay3] { border-bottom:none; }
.project-folder-header[b-a93jw9iay3] { display:flex; align-items:center; gap:.45rem; cursor:pointer; padding:.3rem .35rem; border-radius:4px; user-select:none; }
.project-folder-header:hover[b-a93jw9iay3] { background:#f1f5f9; }
.project-folder-header.open[b-a93jw9iay3] { background:#eef2ff; }
.project-folder-name[b-a93jw9iay3] { flex:1; min-width:0; color:#0f172a; font-size:.88rem; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.project-folder-count[b-a93jw9iay3] { flex:0 0 auto; color:#64748b; font-size:.74rem; font-variant-numeric:tabular-nums; }
.project-folder-rows[b-a93jw9iay3] { margin:.1rem 0 .35rem 1.4rem; }
/* Tree vocabulary for the QC rail's rows. Badge and name colors are lifted from the
       /images page (JDay in the same blue, monospace identifiers, the same pill badges)
       so the tree is recognizable as the same tree. Rows are tighter than the page's
       because the levels have to fit a 22rem rail rather than a full-width page. */
/* Wraps because the pole rail carries a picker per camera slot: three of them across a
       22rem rail leave a select too narrow to read a camera name out of. */
.img-toolbar[b-a93jw9iay3] { display:flex; flex-wrap:wrap; gap:.6rem; margin:.1rem 0 .5rem; }
.img-toolbar label[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.15rem; font-size:.66rem; text-transform:uppercase; letter-spacing:.06em; color:#64748b; font-weight:700; flex:1 1 6.5rem; min-width:0; }
.img-toolbar select[b-a93jw9iay3] { padding:.25rem .35rem; border:1px solid #cbd5e1; border-radius:6px; font-size:.82rem; background:white; color:#0f172a; min-width:0; }
.img-actions[b-a93jw9iay3] { display:flex; gap:.3rem; margin:0 0 .5rem; padding-bottom:.45rem; border-bottom:1px solid #e2e8f0; flex-wrap:wrap; }
.img-actions .project-goto-btn:disabled[b-a93jw9iay3] { opacity:.45; cursor:default; background:#f8fafc; }
.img-warn[b-a93jw9iay3] { background:#fef3c7; color:#92400e; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
.img-empty[b-a93jw9iay3] { margin:.15rem 0 .3rem; }
/* Keep these three in step with IMAGE_POINT_FILL / _RING / _RADIUS in
       leaflet-points.js — a legend that has drifted from the mark it explains is
       worse than no legend. */
.img-legend-dot[b-a93jw9iay3] { display:inline-block; width:10px; height:10px; border-radius:50%; background:#06b6d4; border:1.5px solid #0f172a; margin-right:.35rem; vertical-align:baseline; }
/* Same contract as the image legend dot, against ADP_POINT_FILL / _RING / _RADIUS —
       and drawn a shade smaller for the same reason the marker is. */
.adp-legend-dot[b-a93jw9iay3] { display:inline-block; width:8px; height:8px; border-radius:50%; background:#22c55e; border:1.5px solid #0f172a; margin-right:.35rem; vertical-align:baseline; }
/* Same contract again, against SCANLINE_POINT_FILL / _RING / _RADIUS — smallest of the
       three, for the reason its marker is: two dots per sweep at scanner line rate makes this
       the densest layer on the map. */
.scan-legend-dot[b-a93jw9iay3] { display:inline-block; width:7px; height:7px; border-radius:50%; background:#f59e0b; border:1.5px solid #0f172a; margin-right:.35rem; vertical-align:baseline; }
/* The flown track's mark is a DASH, not a dot, because that layer draws lines. Green is the
       trail read's in-scene colour; the full legend is in FlightTrackSettingsPanel. */
.flight-legend-dash[b-a93jw9iay3] { display:inline-block; width:14px; border-top:3px solid #16a34a; margin-right:.35rem; vertical-align:middle; }
.qc-layer-toggle input[b-a93jw9iay3] { margin:0; }
.qc-scan-figure strong[b-a93jw9iay3] { font-size:1.15rem; }
.qc-issue-main input[b-a93jw9iay3] { margin:0; }
.qc-fold > summary[b-a93jw9iay3] { cursor:pointer; font-size:.72rem; color:#64748b; }
.qc-fold > p[b-a93jw9iay3] { margin:.3rem 0 0; padding-left:.9rem; line-height:1.35; }
.qc-corridor-chip strong[b-a93jw9iay3] { font-size:.95rem; font-variant-numeric:tabular-nums; }
.qc-scope-tabs button[b-a93jw9iay3] { flex:1 1 0; min-width:0; padding:.2rem .35rem; font-size:.72rem; line-height:1.35; color:#64748b; background:#fff; border:1px solid #e2e8f0; border-radius:5px; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.qc-scope-tabs button:hover[b-a93jw9iay3] { border-color:#cbd5e1; color:#334155; }
.qc-scope-tabs button.on[b-a93jw9iay3] { background:#eef2ff; border-color:#c7d2fe; color:#3730a3; font-weight:600; }
/* Twelve o'clock, or the arc cannot be read as a share of the ring. */
.qc-dial-fig svg[b-a93jw9iay3] { display:block; transform:rotate(-90deg); }
.qc-dial-val strong[b-a93jw9iay3] { font-size:.95rem; font-variant-numeric:tabular-nums; }
.qc-dial-val .muted[b-a93jw9iay3] { font-size:.62rem; }
/* The ? beside a section heading, and the prose behind it. Small and quiet by design: the
       explanation is read once and the counts beside it are read every sortie, so this panel's
       resting state is numbers only. Only prose hides here — warnings, truncation notes and every
       "nothing was measured" line stay in the body always. */
.qc-help-btn[b-a93jw9iay3] { flex:0 0 auto; align-self:center; width:1.05rem; height:1.05rem; padding:0; line-height:1; border:1px solid #cbd5e1; border-radius:50%; background:#fff; color:#64748b; font-size:.7rem; font-weight:700; cursor:pointer; }
.qc-help-btn:hover[b-a93jw9iay3] { border-color:#94a3b8; color:#334155; }
.qc-help-btn.on[b-a93jw9iay3] { background:#1d4ed8; border-color:#1d4ed8; color:#fff; }
/* Pushed to the far edge on the scope row only. In the check's head the run button already
       holds that edge, and a second auto margin would split the row and float the ? mid-way. */
.qc-scanner-scope .qc-help-btn[b-a93jw9iay3] { margin-left:auto; }
.qc-help p[b-a93jw9iay3] { margin:0 0 .4rem; font-size:.76rem; line-height:1.4; color:#475569; }
.qc-help p:last-child[b-a93jw9iay3] { margin:0; }
.qc-page-row .muted[b-a93jw9iay3] { margin-left:.2rem; font-variant-numeric:tabular-nums; }
/* Holds the column a checkbox occupies on the sibling artifact rows, so the Scanner row's
       legend dot and name stay aligned with theirs instead of shifting left where its tick was.
       Sized from the tri-state control rather than guessed. */
.qc-row-nocheck[b-a93jw9iay3] { display:inline-block; width:13px; flex:0 0 13px; }
/* A dashed light-blue block, matching how the ribbon actually draws — filled and dashed-edged.
       Broken out from the sweep-end dots' amber because a translucent amber fill read as
       terrain/road color on satellite basemaps and disappeared; the dots keep amber since they
       are small enough that contrast isn't the problem. */
/* Two solid rules rather than a dashed box: the layer is a pair of edges at full
       resolution now, not an averaged fill, and the mark has to say which. */
.scan-swath-legend[b-a93jw9iay3] { display:inline-block; width:14px; height:8px; border-top:2px solid #38bdf8; border-bottom:2px solid #38bdf8; vertical-align:baseline; }
/* Informational, not a warning: nothing is wrong, the ticks are simply out of view. */
.img-note[b-a93jw9iay3] { background:#e0e7ff; color:#3730a3; border-radius:6px; padding:.4rem .55rem; font-size:.76rem; margin:0 0 .5rem; }
/* ---- QC rail ---- Reuses the generic row/tree classes above throughout; these are only
       what that vocabulary has no equivalent of: the artifact rows under a day, and the
       presence chips that let a day be read without expanding it. */
.qc-note[b-a93jw9iay3] { margin:.1rem 0 .4rem; line-height:1.35; }
/* Both layers' point counts on one line, each behind its own legend dot. Sits directly
       under the actions so "Go to points" and "Clear all" have a number beside them saying
       what they would act on. */
.qc-onmap[b-a93jw9iay3] { display:flex; align-items:center; gap:.25rem; flex-wrap:wrap; margin:0 0 .45rem; font-variant-numeric:tabular-nums; }
.qc-onmap .adp-legend-dot[b-a93jw9iay3],
.qc-onmap .scan-legend-dot[b-a93jw9iay3] { margin-left:.35rem; }
.qc-kinds[b-a93jw9iay3] { display:flex; gap:.2rem; flex:0 0 auto; margin-left:auto; }
/* Present is a filled chip, absent is an outline of the same size — never a missing one.
       "No probe data today" IS the finding, and a chip that simply isn't drawn reads as the
       rail not tracking that artifact at all. */
.qc-chip[b-a93jw9iay3] { display:inline-flex; align-items:center; justify-content:center; width:1.05rem; height:1.05rem; border-radius:3px; font-size:.66rem; font-weight:700; background:#1d4ed8; color:white; }
.qc-chip.off[b-a93jw9iay3] { background:transparent; color:#cbd5e1; box-shadow:inset 0 0 0 1px #e2e8f0; }
/* Indented under the Scanner row it explains, and dimmer than a warning: no calibration
       deployed is a configuration state, not a fault in the collection. */
.qc-scan-note[b-a93jw9iay3] { margin:.1rem 0 .35rem 2.1rem; line-height:1.35; }
.qc-row-kind[b-a93jw9iay3] { cursor:pointer; }
.qc-row-kind .img-name[b-a93jw9iay3] { font-weight:700; font-size:.8rem; color:#334155; flex:0 0 auto; }
.qc-row-absent[b-a93jw9iay3] { cursor:default; }
.qc-row-absent:hover[b-a93jw9iay3] { background:transparent; }
.qc-row-absent .img-name[b-a93jw9iay3] { color:#94a3b8; font-weight:600; }
/* Keeps an unticked artifact's label aligned with a ticked one's, rather than sliding left
       into the space a checkbox would have occupied. */
.qc-tick-gap[b-a93jw9iay3] { display:inline-block; width:13px; flex:0 0 auto; }
.qc-row-file[b-a93jw9iay3] { cursor:default; }
.qc-row-file:hover[b-a93jw9iay3] { background:#f8fafc; }
.qc-file-name[b-a93jw9iay3] { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.72rem; color:#1d4ed8; text-decoration:none; }
.qc-row-file:hover .qc-file-name[b-a93jw9iay3] { text-decoration:underline; }
.qc-project-row[b-a93jw9iay3] { display:flex; align-items:center; gap:.35rem; padding:.2rem .3rem .35rem; min-width:0; }
.qc-project-row select[b-a93jw9iay3] { flex:1; min-width:0; padding:.2rem .3rem; border:1px solid #cbd5e1; border-radius:6px; font-size:.76rem; background:white; color:#0f172a; }
.qc-project-name[b-a93jw9iay3] { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-weight:700; font-size:.78rem; color:#0f172a; }
/* Says the selection came from the imagery rather than from a person. Deliberately quiet —
       it marks a preselection an operator may override, not a verdict. */
.qc-project-auto[b-a93jw9iay3] { flex:0 0 auto; font-size:.66rem; font-weight:700; text-transform:uppercase; letter-spacing:.02em; color:#3730a3; background:#eef2ff; border-radius:3px; padding:.1rem .25rem; }
.qc-cam-actions[b-a93jw9iay3] { padding-bottom:.25rem; }
.qc-cam-check[b-a93jw9iay3] { margin:.1rem 0 .3rem; }
.img-node[b-a93jw9iay3] { min-width:0; }
.img-row[b-a93jw9iay3] { display:flex; align-items:center; gap:.35rem; padding:.2rem .3rem; border-radius:4px; cursor:pointer; user-select:none; }
.img-row:hover[b-a93jw9iay3] { background:#f1f5f9; }
.img-row.open[b-a93jw9iay3] { background:#eef2ff; }
.img-row-cam[b-a93jw9iay3] { cursor:default; }
.img-row-cam:hover[b-a93jw9iay3] { background:#f8fafc; }
.img-row input[type=checkbox][b-a93jw9iay3] { margin:0; flex:0 0 auto; cursor:pointer; }
.img-caret[b-a93jw9iay3] { color:#475569; font-size:.9rem; width:.85rem; text-align:center; line-height:1; flex:0 0 auto; }
.img-caret-leaf[b-a93jw9iay3] { visibility:hidden; }
.img-name[b-a93jw9iay3] { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.img-name-sys[b-a93jw9iay3] { font-weight:700; color:#0f172a; font-size:.86rem; }
.img-name-day[b-a93jw9iay3] { font-weight:700; color:#1d4ed8; font-size:.82rem; font-variant-numeric:tabular-nums; flex:0 0 auto; }
.img-name-cam[b-a93jw9iay3] { color:#0f172a; font-size:.78rem; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
/* When, on the rows that otherwise only say what. flex:0 0 auto so it keeps its width and
       the NAME is what ellipsises — a truncated time is worse than a truncated name, since the
       name is recoverable from the tree position and the time is not. */
.img-clock[b-a93jw9iay3] { flex:0 0 auto; color:#64748b; font-size:.68rem; font-variant-numeric:tabular-nums; }
.img-sub[b-a93jw9iay3] { color:#64748b; font-size:.74rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; }
.img-meta[b-a93jw9iay3] { margin-left:auto; display:flex; align-items:center; gap:.25rem; flex:0 0 auto; }
.img-meta .badge[b-a93jw9iay3] { background:#f1f5f9; color:#475569; font-size:.68rem; padding:.05rem .35rem; border-radius:999px; font-variant-numeric:tabular-nums; }
.img-kids[b-a93jw9iay3] { margin-left:.85rem; padding-left:.25rem; border-left:1px solid #e2e8f0; }
/* Station viewer. Same shape as the /images page's viewer so an operator who has
       used one recognizes the other; the camera strip is the addition, since a dot
       here stands for every camera that fired at that station. */
.rtqc-viewer[b-a93jw9iay3] { position:fixed; inset:0; background:rgba(15,23,42,.86); display:flex; align-items:center; justify-content:center; z-index:2000; padding:1.5rem; }
.rtqc-viewer:focus[b-a93jw9iay3] { outline:none; }
.rtqc-viewer-inner[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.6rem; max-width:96vw; max-height:92vh; }
.rtqc-viewer-stage[b-a93jw9iay3] { align-self:center; display:flex; align-items:center; gap:.55rem; }
/* Leaves room for both arrows, so the frame shrinks rather than pushing them off
       the overlay. Keep in step with .rtqc-viewer-nav's width. */
.rtqc-viewer-stage > img[b-a93jw9iay3] { max-width:calc(96vw - 6.5rem); max-height:70vh; object-fit:contain; border-radius:6px; background:#0f172a; }
.rtqc-viewer-nav[b-a93jw9iay3] { flex:0 0 auto; width:2.4rem; height:3.6rem; display:flex; align-items:center; justify-content:center; font-size:1.9rem; line-height:1; color:white; background:rgba(15,23,42,.55); border:1px solid rgba(255,255,255,.28); border-radius:8px; cursor:pointer; padding:0; }
.rtqc-viewer-nav:hover:enabled[b-a93jw9iay3] { background:rgba(29,78,216,.9); border-color:#1d4ed8; }
.rtqc-viewer-nav:disabled[b-a93jw9iay3] { opacity:.22; cursor:default; }
.rtqc-viewer-pos[b-a93jw9iay3] { color:#475569; font-size:.78rem; font-variant-numeric:tabular-nums; white-space:nowrap; margin-right:.2rem; }
.rtqc-viewer-cam[b-a93jw9iay3] { display:flex; align-items:center; gap:.3rem; font-size:.72rem; text-transform:uppercase; letter-spacing:.05em; color:#64748b; font-weight:600; }
.rtqc-viewer-cam select[b-a93jw9iay3] { padding:.15rem .3rem; border:1px solid #cbd5e1; border-radius:6px; font-size:.8rem; text-transform:none; letter-spacing:normal; font-weight:400; background:white; color:#0f172a; }
/* The arrows own ← / →, so nothing behind the overlay should be scrolling. */
body:has(.rtqc-viewer)[b-a93jw9iay3] { overflow:hidden; }
.rtqc-viewer-bar[b-a93jw9iay3] { display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap; background:white; border-radius:6px; padding:.5rem .7rem; }
.rtqc-viewer-meta[b-a93jw9iay3] { display:flex; gap:.7rem; flex-wrap:wrap; align-items:center; font-size:.78rem; color:#475569; font-variant-numeric:tabular-nums; }
.rtqc-viewer-meta strong[b-a93jw9iay3] { color:#0f172a; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.78rem; }
.rtqc-viewer-meta .dim[b-a93jw9iay3] { color:#64748b; }
.rtqc-viewer-actions[b-a93jw9iay3] { display:flex; gap:.4rem; align-items:center; }
.rtqc-btn[b-a93jw9iay3] { display:inline-block; border:1px solid #cbd5e1; background:#f8fafc; color:#0f172a; border-radius:6px; padding:.2rem .55rem; font-size:.8rem; text-decoration:none; white-space:nowrap; cursor:pointer; }
.rtqc-btn:hover[b-a93jw9iay3] { background:#e2e8f0; }
/* Scrolls within itself: a rig with many cameras would otherwise widen the modal
       past the viewport. */
.rtqc-viewer-strip[b-a93jw9iay3] { display:flex; gap:.35rem; overflow-x:auto; background:white; border-radius:6px; padding:.35rem; }
.rtqc-strip-item[b-a93jw9iay3] { display:flex; flex-direction:column; align-items:center; gap:.15rem; padding:.15rem; background:#f8fafc; border:2px solid #e2e8f0; border-radius:5px; cursor:pointer; font-size:.66rem; color:#475569; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.rtqc-strip-item:hover[b-a93jw9iay3] { border-color:#93c5fd; }
.rtqc-strip-item.is-selected[b-a93jw9iay3] { border-color:#1d4ed8; color:#1e40af; }
.rtqc-strip-item img[b-a93jw9iay3] { width:72px; height:54px; object-fit:cover; display:block; border-radius:3px; }
.rtqc-strip-time[b-a93jw9iay3] { color:#64748b; font-variant-numeric:tabular-nums; }
.rtqc-strip-more[b-a93jw9iay3] { display:flex; flex-direction:column; align-items:center; justify-content:center; min-width:72px; padding:.15rem .35rem; color:#64748b; font-size:.66rem; text-align:center; font-variant-numeric:tabular-nums; }
/* ADP readout. Docked bottom-left of the stage rather than centered with a backdrop:
       it holds a handful of numbers, and it has to be able to sit open at the same time as
       the image viewer without either one blocking the other. Bottom-LEFT specifically —
       the rails are on the right and Leaflet's zoom/layers controls are top-left. */
/* .75rem gutter + 24rem readout + .5rem gap — keep in step with .rtqc-readouts below. */
.rtqc-stage.has-readout[b-a93jw9iay3] { --feature-card-inset-left: 25.25rem; }
/* The docked-readout column. Positioned ONCE here so each card inside it is a plain
       block that stacks — see the markup note for why neither card can know the other's
       height. column-reverse so a newly opened card appears at the BOTTOM of the stack,
       nearest the map, rather than shoving the open one down; pointer-events:none lets the
       gap between cards pass clicks through to the map, which a full-height positioned
       container would otherwise swallow. */
.rtqc-readouts[b-a93jw9iay3] { position:absolute; left:.75rem; bottom:.75rem; z-index:1100; display:flex; flex-direction:column-reverse; gap:.5rem; max-width:calc(100% - 1.5rem); pointer-events:none; }
.rtqc-readouts > *[b-a93jw9iay3] { pointer-events:auto; }
.adp-readout[b-a93jw9iay3] { width:24rem; max-width:100%; max-height:22rem; overflow-y:auto; background:#fff; border:1px solid #cbd5e1; border-radius:6px; padding:.55rem .7rem; box-shadow:0 2px 10px rgba(15,23,42,.18); }
/* No cap at all, unlike the probe card: this one is a fixed handful of fields rather than a
       list that grows with a dwell, so it cannot outgrow the space and never needs to scroll. */
.adp-readout.scan-readout[b-a93jw9iay3] { max-height:none; }
.adp-readout-head[b-a93jw9iay3] { display:flex; align-items:center; gap:.5rem; padding-bottom:.35rem; border-bottom:1px solid #e2e8f0; }
.adp-readout-head strong[b-a93jw9iay3] { color:#0f172a; font-size:.86rem; }
.adp-readout-head .muted[b-a93jw9iay3] { color:#64748b; font-size:.78rem; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.adp-readout-sub[b-a93jw9iay3] { display:flex; flex-wrap:wrap; gap:.55rem; padding:.35rem 0; color:#475569; font-size:.74rem; font-variant-numeric:tabular-nums; }
.adp-readout-sub .dim[b-a93jw9iay3] { color:#64748b; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.adp-readout-sub .muted[b-a93jw9iay3] { color:#94a3b8; }
.adp-readout-table[b-a93jw9iay3] { width:100%; border-collapse:collapse; font-size:.74rem; font-variant-numeric:tabular-nums; }
.adp-readout-table th[b-a93jw9iay3] { text-align:left; color:#64748b; font-size:.66rem; text-transform:uppercase; letter-spacing:.05em; font-weight:700; padding:.2rem .3rem; border-bottom:1px solid #e2e8f0; }
.adp-readout-table td[b-a93jw9iay3] { padding:.18rem .3rem; color:#0f172a; border-bottom:1px solid #f1f5f9; }
.adp-readout-table .num[b-a93jw9iay3] { text-align:right; }
.adp-readout-table .muted[b-a93jw9iay3] { color:#94a3b8; }
.adp-status[b-a93jw9iay3] { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.7rem; color:#475569; }
.adp-readout-more[b-a93jw9iay3] { margin:.35rem 0 0; color:#64748b; font-size:.72rem; font-variant-numeric:tabular-nums; }
/* Poles rail. The legend dot matches the gold KmlPoles gives the placemarks in the
       KMZ, and the three status colours below are the same three the map paints — a rail
       count and a dot on the map have to be the same colour or the tally means nothing.
       Hollow, for the same reason POLE_POINT_WEIGHT is: the marker is a ring so the image
       stations under it stay visible, and a filled swatch here would explain a mark that
       is no longer on the map. */
.pole-legend-dot[b-a93jw9iay3] { display:inline-block; width:.6rem; height:.6rem; border-radius:50%; background:transparent; border:2px solid #ffd700; margin-right:.3rem; vertical-align:middle; }
.pole-bar-covered[b-a93jw9iay3] { background:#16a34a; }
.pole-bar-none[b-a93jw9iay3] { background:#dc2626; }
/* flex:0 0 auto so a tight row scrolls rather than squeezing every chip until its
       label ellipsises — an unreadable filter is worse than one off the right edge. */
.pole-chip[b-a93jw9iay3] { flex:0 0 auto; border:1px solid #e2e8f0; background:#f8fafc; color:#475569; border-radius:999px; padding:.1rem .32rem; font-size:.67rem; cursor:pointer; display:inline-flex; gap:.2rem; align-items:center; white-space:nowrap; }
.pole-chip b[b-a93jw9iay3] { font-variant-numeric:tabular-nums; color:#0f172a; }
.pole-chip:hover[b-a93jw9iay3] { border-color:#94a3b8; }
.pole-chip.is-on[b-a93jw9iay3] { border-color:#1d4ed8; background:#eff6ff; color:#1e40af; }
.pole-chip.pending b[b-a93jw9iay3] { color:#a16207; }
/* The darkened, readable form of the map's #3b82f6, matching how .pending tints the gold
       and .covered the green. Note .is-on is itself blue chrome (border + background), so the
       selected state stays legible on this chip: only the count carries the hue. */
.pole-chip.ready b[b-a93jw9iay3] { color:#1d4ed8; }
.pole-chip.covered b[b-a93jw9iay3] { color:#15803d; }
.pole-chip.none b[b-a93jw9iay3] { color:#b91c1c; }
/* Re-flown poles. Violet rather than another warm tone: gold/green/red are already spoken
       for by the three verdicts, and this is not a fourth verdict — it is a pole that has one
       and needs looking at again. */
.pole-chip.requeued[b-a93jw9iay3] { border-color:#ddd6fe; background:#f5f3ff; }
.pole-chip.requeued b[b-a93jw9iay3] { color:#6d28d9; }
/* Deliberately the dimmest chip on the row: it describes work that is NOT here. */
.pole-chip.elsewhere[b-a93jw9iay3] { border-color:#e2e8f0; background:#f8fafc; color:#94a3b8; }
.pole-chip.elsewhere b[b-a93jw9iay3] { color:#64748b; }
/* ---- QUEUE rail: one scene, four sensors ----
       The scene is the outer card and each sensor an inner one, because that is the shape of the
       work: an operator clears a pass, and a pass is four decisions of three different kinds. The
       nesting is one level deep and stops there — a third would be per camera, and the cameras are
       a line of text on the sensor card rather than rows of their own. */
.scene-card[b-a93jw9iay3] { border:1px solid #e2e8f0; border-radius:8px; margin-bottom:.45rem; background:#fff; overflow:hidden; }
/* The folder wears the SAME four states as the cards inside it, rolled up — see
       SceneCardState for the priority and why flagged outranks unmeasured. It replaced a flat grey
       "is-done": with forty scenes in the window, "which of these is finished" was a question that
       could only be answered by opening them, and one grey tone answered half of it. On an OPEN
       card the fill survives only in the head strip, because each sensor card paints its own over
       the rest — which is the picture that was wanted: the rollup, then its four parts. */
.scene-card.is-unchecked[b-a93jw9iay3] { background:#fffbeb; border-color:#fcd34d; }
.scene-card.is-checked[b-a93jw9iay3] { background:#f0fdf4; border-color:#a7f3d0; }
.scene-card.is-accepted[b-a93jw9iay3] { background:#dcfce7; border-color:#6ee7b7; }
.scene-card.is-flagged[b-a93jw9iay3] { background:#fef2f2; border-color:#fca5a5; }
/* A left edge rather than a fill for the open card, and LAST so its border beats the state's:
       the same split the sensor cards make — an edge says which one you are inside, a fill says
       how far along it is, and the two must be able to be true at once. */
.scene-card.is-open[b-a93jw9iay3] { border-color:#93c5fd; box-shadow:inset 3px 0 0 #2563eb; }
/* The pass a /qc-reports link named. An OUTLINE around the whole card, outside the border, so it
       reads over every state fill and over the open card's own left edge — the question it answers,
       "which of these sixty is the one I clicked", is asked once and has to be answerable at a
       glance. It survives until the operator touches the rail themselves. */
.scene-card.is-linked[b-a93jw9iay3] { outline:2px solid #a855f7; outline-offset:1px; }
/* Focus target only: focusing is what scrolls the card into view, and the browser's own focus
       ring on a zero-size element would be a stray dot beside a card that is already outlined. */
.scene-link-anchor[b-a93jw9iay3] { display:block; width:0; height:0; outline:none; scroll-margin-top:.4rem; }
/* The whole head is the button. Reset to look like the row it replaced rather than like a
       control, since a rail of forty of these lined with button chrome is unreadable. */
.scene-card-head[b-a93jw9iay3] { display:flex; justify-content:space-between; align-items:baseline; gap:.5rem; width:100%; padding:.45rem .55rem .1rem; border:0; background:none; font:inherit; text-align:left; cursor:pointer; }
.scene-card-head:hover .scene-card-title[b-a93jw9iay3] { color:#1d4ed8; }
/* The caret is the only thing on this head that says it opens. Without it the row reads as a
       heading — bold text over a card — and operators worked the whole rail without discovering
       that the four sensor cards, which are its entire content, were one click away. It leads the
       row rather than trailing it, where a disclosure is looked for, and turns with the state so
       the affordance is also the indicator. */
.scene-card-caret[b-a93jw9iay3] { flex:0 0 auto; color:#475569; font-size:.8rem; line-height:1; width:.7rem; }
.scene-card-head:hover .scene-card-caret[b-a93jw9iay3] { color:#1d4ed8; }
/* Grows, so the time stays pinned right once the caret makes this a three-child flex row —
       space-between alone would strand the title in the middle. */
.scene-card-title[b-a93jw9iay3] { flex:1 1 auto; font-weight:700; font-size:.82rem; color:#0f172a; }
.scene-card-when[b-a93jw9iay3] { font-size:.74rem; color:#475569; font-variant-numeric:tabular-nums; white-space:nowrap; }
/* A flex row now that it carries the pass's own press. Wrapping rather than shrinking, because
       the rail is read on a narrow panel and a project name long enough to squeeze the button is
       ordinary — a control clipped to three letters is worse than one on its own line. */
.scene-card-sub[b-a93jw9iay3] { display:flex; flex-wrap:wrap; align-items:center; gap:.25rem; font-size:.72rem; color:#94a3b8; padding:0 .55rem .35rem; }
.scene-card-left[b-a93jw9iay3] { color:#b45309; font-weight:700; }
/* Pushed to the far end of the sub row, so the line reads as facts first and the control last —
       and grouped rather than each pushed on its own, or the two auto margins would share the free
       space and leave the button stranded mid-row. */
.scene-card-sub-actions[b-a93jw9iay3] { display:flex; align-items:center; gap:.3rem; margin-left:auto; }
/* The head's press sits among grey text rather than in a row of buttons, so it carries its own
       outline — without it the only thing saying it is a control is the cursor. */
.scene-show-btn[b-a93jw9iay3] { font-size:.7rem; padding:.1rem .4rem; }
/* The head's notes, which have no card to sit inside. Indented to the sub row's own gutter. */
.scene-card-notes[b-a93jw9iay3] { padding:0 .55rem .3rem; }
.sensor-card[b-a93jw9iay3] { border-top:1px solid #eef2f6; padding:.4rem .55rem; }
/* ---- The four review states, as a fill ----
       A fill rather than a chip because the question these answer — "which of these forty cards
       still needs me" — is asked of the whole rail at once, and a chip has to be read card by
       card. Amber for unmeasured, light green for measured with no verdict, green for accepted,
       red for flagged. The two greens are deliberately far apart in weight: they differ by
       whether a human has signed anything, which is the one distinction on this rail that must
       not be a subtle one. Backgrounds only, plus a left edge that repeats the state at the
       card's border — the figures inside stay on the .sensor-pct bands, which are about a
       PERCENTAGE and not about a verdict, and tinting text with both would collide. */
.sensor-card.is-unchecked[b-a93jw9iay3] { background:#fffbeb; box-shadow:inset 2px 0 0 #f59e0b; }
.sensor-card.is-checked[b-a93jw9iay3] { background:#f0fdf4; box-shadow:inset 2px 0 0 #86efac; }
.sensor-card.is-accepted[b-a93jw9iay3] { background:#dcfce7; box-shadow:inset 2px 0 0 #16a34a; }
.sensor-card.is-flagged[b-a93jw9iay3] { background:#fef2f2; box-shadow:inset 2px 0 0 #dc2626; }
/* The card whose data is on the map, and now the LEFT EDGE only — last so its bar wins over
       the state bars above, while the state keeps the fill. It used to own the fill too, which is
       no longer a colour it can spend: "which card am I looking at" is asked of the one card
       being shown, and "which cards are done" is asked of all four at once. The edge answers the
       first without taking the fill the second needs, and it is the light purple of the scene
       track the press draws — the tint and the line on the map name each other. A shade darker
       than the line itself, which at 2px on a white card would barely show. */
.sensor-card.is-shown[b-a93jw9iay3] { box-shadow:inset 2px 0 0 #c084fc; }
/* A sensor the pass did not collect. Dimmed rather than hidden: a rig whose scanner produced
       nothing is a finding, and a card that vanishes reads as a rig that has no scanner. */
.sensor-card.is-absent[b-a93jw9iay3] { opacity:.6; }
.sensor-card-head[b-a93jw9iay3] { display:flex; justify-content:space-between; align-items:baseline; gap:.5rem; }
.sensor-card-name[b-a93jw9iay3] { font-size:.7rem; font-weight:700; letter-spacing:.06em; color:#334155; }
.sensor-card-count[b-a93jw9iay3] { font-size:.74rem; color:#0f172a; font-variant-numeric:tabular-nums; }
.sensor-card-count.dim[b-a93jw9iay3] { color:#94a3b8; font-variant-numeric:normal; }
.sensor-card-units[b-a93jw9iay3] { font-size:.72rem; color:#64748b; margin:.1rem 0 .25rem; }
/* A unit name on a card is a CONTROL — a camera, a scanner head or the probe alike —
       and it is drawn as a small sibling of the Show on map / Check / Accept row below it — the shape that already means "pressable" on
       this card. It started as underlined text on the argument that the unit line is read far
       more often than it is pressed; that argument was right about the reading and wrong about
       the discovery, because a dotted underline reads as emphasis and nobody found the toggle. A
       control nobody can see is not a lighter-weight control, it is an absent one. */
.unit-fp[b-a93jw9iay3] {
        display:inline-flex; align-items:center; gap:.25rem;
        border:1px solid #cbd5e1; background:#f8fafc; color:#334155;
        border-radius:6px; padding:.1rem .35rem; margin:.1rem .25rem .1rem 0;
        font:inherit; font-size:.7rem; line-height:1.3; cursor:pointer; white-space:nowrap;
    }
.unit-fp:hover[b-a93jw9iay3] { border-color:#94a3b8; background:#e2e8f0; color:#0f172a; }
/* Drawn. Dark edge and a filled swatch, so the one unit whose geometry is on the map is the
       one thing in the row that is not grey. */
.unit-fp.is-on[b-a93jw9iay3] { border-color:#0f172a; background:#fff; color:#0f172a; font-weight:600; }
.unit-fp.is-busy[b-a93jw9iay3] { opacity:.55; cursor:progress; }
/* Hollow until it draws. The empty square says this button is about a layer; only the FILL
       names a colour, and a colour named for a unit drawing nothing claims geometry that is not
       there — and on a camera it would claim the wrong hue anyway, since the palette index is
       not resolved until the calibration has answered. */
.unit-fp-swatch[b-a93jw9iay3] {
        display:inline-block; width:8px; height:8px; border-radius:2px; flex:none;
        border:1px solid #94a3b8; background:transparent;
    }
.unit-fp.is-on .unit-fp-swatch[b-a93jw9iay3] { border-color:#0f172a; }
/* A mosaic is a picture with no colour of its own, so a drawn one fills grey. */
.unit-fp.is-on .unit-fp-swatch.is-mosaic[b-a93jw9iay3] { background:#cbd5e1; }
/* A mosaic waiting to be drawn again after its rebuild. Pressable, so not dimmed like busy. */
.unit-fp.is-pending[b-a93jw9iay3] { border-style:dashed; border-color:#0f172a; background:#fff; color:#0f172a; }
.unit-fp-note[b-a93jw9iay3] { font-weight:400; color:#64748b; }
/* A mosaic that is not ready yet: present, so the row lists every camera, but not pressable. */
.unit-fp:disabled:not(.is-busy)[b-a93jw9iay3] { opacity:.5; cursor:default; background:#f8fafc; border-color:#cbd5e1; color:#64748b; }
/* One drawn unit's account of itself. Indented under the unit line it belongs to, because a
       card can have three of these open at once and they are otherwise four chip rows with
       nothing saying which unit each describes. The chips inside come from whichever of the three
       stats components the sensor uses — each carries its own copy, scoped CSS following its
       own markup. */
.unit-fp-readout[b-a93jw9iay3] { margin:.15rem 0 .3rem .4rem; padding-left:.45rem; border-left:2px solid #e2e8f0; }
.unit-fp-title[b-a93jw9iay3] { display:inline-flex; align-items:center; font-size:.7rem; font-weight:600; color:#334155; }
.sensor-card-figure[b-a93jw9iay3] { display:flex; align-items:baseline; gap:.4rem; margin:.15rem 0 .3rem; }
/* Three bands, matching how the day-level report tints its coverage cells — the same numbers
       read on two pages must not be banded differently. */
.sensor-pct[b-a93jw9iay3] { font-size:.9rem; font-weight:700; font-variant-numeric:tabular-nums; }
.sensor-pct.good[b-a93jw9iay3] { color:#15803d; }
.sensor-pct.fair[b-a93jw9iay3] { color:#b45309; }
.sensor-pct.bad[b-a93jw9iay3] { color:#b91c1c; }
.sensor-card-figure .dim[b-a93jw9iay3] { font-size:.72rem; color:#64748b; }
.scene-gaps-btn[b-a93jw9iay3] {
        margin-left:auto; font-size:.66rem; padding:.05rem .4rem; white-space:nowrap;
        border:1px solid #fcd34d; border-radius:.6rem; background:#fffbeb; color:#92400e; cursor:pointer;
    }
.scene-gaps-btn.is-on[b-a93jw9iay3] { background:#f59e0b; border-color:#f59e0b; color:#fff; }
/* Reads as a label rather than as more numbers — the figures beside it are already two
       shades of grey, and a third would leave the one word that says WHICH question was
       answered looking like the least important thing in the row. */
.sensor-measure[b-a93jw9iay3] {
        font-size:.64rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
        color:#475569; background:#e2e8f0; border-radius:.6rem; padding:.05rem .35rem;
        white-space:nowrap;
    }
.sensor-verdict[b-a93jw9iay3] { display:flex; flex-wrap:wrap; align-items:baseline; gap:.3rem; font-size:.72rem; margin:.15rem 0 .25rem; }
.sensor-verdict-word[b-a93jw9iay3] { font-weight:700; }
.sensor-verdict.is-accepted .sensor-verdict-word[b-a93jw9iay3] { color:#15803d; }
.sensor-verdict.is-flagged .sensor-verdict-word[b-a93jw9iay3] { color:#b91c1c; }
.sensor-verdict .dim[b-a93jw9iay3] { color:#94a3b8; }
.sensor-note-box[b-a93jw9iay3] { width:100%; box-sizing:border-box; margin:.2rem 0 .3rem; padding:.25rem .35rem; font-size:.74rem; border:1px solid #cbd5e1; border-radius:5px; }
.sensor-card-actions[b-a93jw9iay3] { display:flex; gap:.3rem; flex-wrap:wrap; }
.sensor-card-actions .project-goto-btn:disabled[b-a93jw9iay3] { opacity:.45; cursor:default; background:#f8fafc; }
/* The two verdicts are the only coloured buttons on the rail, because they are the only ones
       that WRITE. Everything else here reads. */
.sensor-card-actions .project-goto-btn.accept[b-a93jw9iay3] { border-color:#86efac; color:#15803d; }
.sensor-card-actions .project-goto-btn.flag[b-a93jw9iay3] { border-color:#fca5a5; color:#b91c1c; }
/* Stands where the Check button would be when no plan exists for this rig-day. Deliberately
       NOT styled as a disabled button: a dark button says "not yet" and invites a hunt for the
       control that would light it, and there is no such control — the fix is a project that does
       not exist. A flat statement in the button's place is what says that. Dashed to read as an
       absence rather than as a verdict chip; it is neither good news nor bad. */
.sensor-noplan[b-a93jw9iay3] {
        display:inline-flex; align-items:center; padding:.12rem .4rem;
        border:1px dashed #cbd5e1; border-radius:6px; background:#f8fafc;
        color:#64748b; font-size:.7rem; font-weight:600; white-space:nowrap; cursor:help;
    }
.scene-note[b-a93jw9iay3] { margin:.25rem 0 0; font-size:.72rem; color:#64748b; line-height:1.3; }
.scene-note.warn[b-a93jw9iay3] { color:#9a3412; }
.scene-note.dim[b-a93jw9iay3] { color:#94a3b8; }
/* Where a card's narration lives now. Grey and quiet on purpose: everything under it is true
       of a HEALTHY pass, so it must not compete with the one line on a card that is not. It still
       has to be VISIBLE — the count is the whole affordance, and it is what keeps "nothing was
       said" and "nothing had to be said" apart without spending a line on either. */
.sensor-info-btn[b-a93jw9iay3] {
        margin-left:auto; border:1px solid #e2e8f0; background:#f8fafc; color:#64748b;
        border-radius:999px; padding:.1rem .4rem; font-size:.68rem; cursor:pointer;
        font-variant-numeric:tabular-nums; white-space:nowrap;
    }
.sensor-info-btn:hover[b-a93jw9iay3] { border-color:#94a3b8; color:#334155; }
.sensor-info-btn.is-on[b-a93jw9iay3] { border-color:#93c5fd; background:#eff6ff; color:#1e40af; }
/* The ORTHO card's ℹ while its closed mosaic block holds a failure or a stale mosaic. */
.sensor-info-btn.is-warn[b-a93jw9iay3] { border-color:#fdba74; background:#fff7ed; color:#9a3412; }
.sensor-info[b-a93jw9iay3] { border-top:1px dashed #e2e8f0; margin-top:.3rem; padding-top:.15rem; }
/* Rides on the unit line, because it qualifies the count and nothing else. */
.sensor-live[b-a93jw9iay3] {
        margin-left:.3rem; background:#fef9c3; color:#a16207; border-radius:999px;
        padding:.02rem .35rem; font-size:.62rem; font-weight:700; text-transform:uppercase;
        letter-spacing:.04em; white-space:nowrap;
    }
.queue-toggle[b-a93jw9iay3] { display:inline-flex; align-items:center; gap:.3rem; font-size:.74rem; color:#475569; cursor:pointer; }
/* The pole chip row, which the OBLIQUE card carries. Kept under its old name because the
       chips themselves are the pole rail's and are styled there — see .pole-chip. */
.queue-item-counts[b-a93jw9iay3] { display:flex; flex-wrap:wrap; gap:.25rem; margin-bottom:.35rem; }
.pole-cone[b-a93jw9iay3] { margin:.2rem .3rem .35rem; border:1px solid #e2e8f0; border-radius:6px; background:#f8fafc; }
.pole-cone > summary[b-a93jw9iay3] { cursor:pointer; padding:.25rem .45rem; font-size:.72rem; font-weight:700; color:#475569; text-transform:uppercase; letter-spacing:.04em; }
.pole-cone-body[b-a93jw9iay3] { padding:.15rem .45rem .4rem; display:flex; flex-direction:column; gap:.3rem; }
.pole-cone-body label[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.1rem; font-size:.68rem; color:#64748b; text-transform:uppercase; letter-spacing:.04em; font-weight:600; }
.pole-range input[type=range][b-a93jw9iay3] { flex:1; min-width:0; }
.pole-range b[b-a93jw9iay3] { font-size:.74rem; color:#0f172a; text-transform:none; letter-spacing:normal; font-variant-numeric:tabular-nums; min-width:3.4rem; text-align:right; }
.pole-num input[b-a93jw9iay3] { width:5rem; padding:.15rem .3rem; border:1px solid #cbd5e1; border-radius:6px; font-size:.78rem; text-transform:none; letter-spacing:normal; font-weight:400; }
.pole-num .dim[b-a93jw9iay3] { color:#94a3b8; font-size:.68rem; }
.pole-cone-note[b-a93jw9iay3] { margin:.15rem 0 0; color:#64748b; font-size:.66rem; line-height:1.35; text-transform:none; letter-spacing:normal; font-weight:400; }
.pole-mounts .dim[b-a93jw9iay3] { color:#94a3b8; }
.pole-mount-edit label[b-a93jw9iay3] { flex-direction:row; align-items:center; gap:.2rem; font-size:.62rem; }
.pole-mount-edit input[b-a93jw9iay3] { width:3.6rem; padding:.1rem .25rem; border:1px solid #cbd5e1; border-radius:5px; font-size:.72rem; text-transform:none; letter-spacing:normal; font-weight:400; }
/* Pole review overlay. Modal, and sized so the two frames are the page: a pole is a
       thin vertical thing a few pixels wide in a wide-angle survey frame, so anything that
       shrinks the imagery to make room for chrome defeats the review. */
.pole-review[b-a93jw9iay3] { position:fixed; inset:0; background:rgba(15,23,42,.9); display:flex; align-items:center; justify-content:center; z-index:2100; padding:.5rem; }
.pole-review:focus[b-a93jw9iay3] { outline:none; }
.pole-review-inner[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.5rem; width:100%; max-width:min(150rem, 99vw); max-height:98vh; }
body:has(.pole-review)[b-a93jw9iay3] { overflow:hidden; }
.pole-review-head[b-a93jw9iay3] { display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; background:white; border-radius:6px; padding:.4rem .7rem; font-size:.78rem; color:#475569; font-variant-numeric:tabular-nums; }
.pole-review-head strong[b-a93jw9iay3] { color:#0f172a; font-size:.9rem; }
.pole-review-head .dim[b-a93jw9iay3] { color:#64748b; }
.pole-review-head .pole-review-spacer[b-a93jw9iay3] { flex:1; }
.pole-review-pos[b-a93jw9iay3] { color:#1d4ed8; font-weight:700; }
/* The scene's own position and progress, ahead of the project one. Violet rather than the
       project position's blue, matching the "Scene NNNNN" chip in the POLES rail — the two name
       the same scope and an operator should not have to work that out twice. The bar reuses
       .pole-bar-covered / .pole-bar-none so the scene's colours cannot drift from the rail's. */
.pole-review-pos.scene[b-a93jw9iay3] { color:#6d28d9; }
.pole-scene-bar[b-a93jw9iay3] { display:inline-flex; width:6rem; height:.45rem; border-radius:999px; overflow:hidden; background:#e2e8f0; vertical-align:middle; }
.pole-scene-bar .pole-bar-covered[b-a93jw9iay3] { background:#16a34a; }
.pole-scene-bar .pole-bar-none[b-a93jw9iay3] { background:#dc2626; }
.pole-verdict-tag[b-a93jw9iay3] { border-radius:999px; padding:.05rem .45rem; font-size:.7rem; font-weight:700; text-transform:uppercase; letter-spacing:.04em; }
.pole-verdict-tag.pending[b-a93jw9iay3] { background:#fef9c3; color:#a16207; }
.pole-verdict-tag.covered[b-a93jw9iay3] { background:#dcfce7; color:#15803d; }
.pole-verdict-tag.none[b-a93jw9iay3] { background:#fee2e2; color:#b91c1c; }
/* Side by side at desktop width, stacked below it. The panes share the width evenly
       rather than one leading, and how many there are comes from --pole-panes, set on the
       element: only the slots with a camera get a pane, so a two-camera rig keeps the full
       width for its two pictures instead of holding a third of it open for nothing.
       minmax(0,1fr) rather than 1fr, because a grid track's default min-content floor is the
       image's intrinsic width and a wide frame would push the panes past the row. */
.pole-review-panes[b-a93jw9iay3] { display:grid; grid-template-columns:repeat(var(--pole-panes,2), minmax(0,1fr)); gap:.5rem; min-height:0; align-items:start; }
/* The inset map takes a fixed column and the panes share what's left, so turning it on
       narrows the pictures rather than covering them. Narrower at three panes: the map's job
       is placing the pole, and past two panes the pictures are what is short of room. */
.pole-review-panes.with-map[b-a93jw9iay3] { grid-template-columns:repeat(var(--pole-panes,2), minmax(0,1fr)) 28rem; }
/* One tall column for the portrait frame, the landscape ones STACKED beside it — see
       RtQc.PoleStackedLayout for when this applies and why. Equal columns squeeze the landscape
       frames into a third of the row while the portrait one beside them runs out of height long
       before it runs out of width; stacking gives them a column half again as wide and half the
       height each, which is more picture in both directions on the rig's ~5:3 frames.

       The row heights come from a DEFINITE container height with `1fr` rows, not from a
       per-image `max-height` in vh. A vh cap is a magic number that is right on one screen and
       wrong on the next, and getting it too large overflows the modal; this way each picture
       simply fills the box its row gives it. 86vh leaves room for the header, the keyboard bar
       and a header that has wrapped. */
.pole-review-panes.stacked[b-a93jw9iay3] { grid-template-columns:minmax(0,1fr) minmax(0,1.35fr); grid-template-rows:repeat(var(--pole-rows,2), minmax(0,1fr)); height:86vh; }
.pole-review-panes.stacked.with-map[b-a93jw9iay3] { grid-template-columns:minmax(0,1fr) minmax(0,1.35fr) 28rem; }
/* Placement comes in as custom properties rather than as inline grid-column/grid-row, so the
       narrow-screen rule below can still collapse the row — an inline placement would win over
       it and leave three panes side by side on a phone. */
.pole-review-panes.stacked > .pole-pane[b-a93jw9iay3],
.pole-review-panes.stacked > .pole-mini[b-a93jw9iay3] { grid-column:var(--pane-col, auto); grid-row:var(--pane-row, auto) / span var(--pane-span, 1); min-height:0; }
/* STRETCH, overriding the row's align-items:start, and this is what makes the whole
       definite-height scheme work rather than quietly do nothing. Left at `start` a pane is
       sized by its content, so its stage never receives the row's leftover height, `max-height:
       100%` on the picture resolves against an auto-height parent (i.e. no cap at all), and each
       frame renders at whatever its pane's WIDTH implies — two ~5:3 frames stacked then run
       about 1 140 px against an 82vh box, overflowing the modal. The equal-column layout still
       wants `start`: there the panes are independent and a short one should not pad itself out
       to match a tall neighbour. */
.pole-review-panes.stacked > .pole-pane[b-a93jw9iay3] { align-self:stretch; }
.pole-review-panes.stacked .pole-pane-stage[b-a93jw9iay3] { flex:1; min-height:0; }
.pole-review-panes.stacked .pole-pane-stage > img[b-a93jw9iay3] { max-height:100%; }
.pole-pane[b-a93jw9iay3] { background:white; border:2px solid transparent; border-radius:6px; padding:.4rem; display:flex; flex-direction:column; gap:.35rem; min-width:0; cursor:pointer; position:relative; }
/* The picture takes the height the pane has; the text never eats into it. */
.pole-pane.has-frame .pole-pane-stage[b-a93jw9iay3] { flex:1; min-height:0; position:relative; }
/* The step arrows ride the frame's own edges rather than sitting in the row beside it,
       which is worth ~3rem of picture width in every pane. They keep their size — they are the
       primary control now — and gain a scrim, because a bare chevron disappears over pale
       ground. Anchored to the stage, so they follow the picture and not the pane. */
.pole-pane.has-frame .rtqc-viewer-nav[b-a93jw9iay3] { position:absolute; top:50%; transform:translateY(-50%); z-index:3; background:rgba(15,23,42,.5); color:#f1f5f9; border-color:transparent; }
.pole-pane.has-frame .rtqc-viewer-nav:hover:enabled[b-a93jw9iay3] { background:rgba(15,23,42,.78); }
.pole-pane.has-frame .rtqc-viewer-nav:first-of-type[b-a93jw9iay3] { left:.25rem; }
.pole-pane.has-frame .rtqc-viewer-nav:last-of-type[b-a93jw9iay3] { right:.25rem; }
/* Which pane the arrow keys drive. Without a visible marker the keyboard silently
       steps whichever pane was clicked last, which reads as the arrows being broken. */
.pole-pane.is-active[b-a93jw9iay3] { border-color:#1d4ed8; }
/* Wraps: the header carries the camera, the scene, the pass ordinal and the frame counter,
       and a third pane makes each column narrow enough for that to overflow. */
.pole-pane-head[b-a93jw9iay3] { display:flex; flex-wrap:wrap; align-items:center; gap:.45rem; font-size:.74rem; color:#64748b; }
.pole-pane-cam[b-a93jw9iay3] { font-weight:700; color:#0f172a; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
/* The picture's own name, beside the scene. Bounded and truncated rather than wrapping: it
       shares a line with the counters, and a long name that wraps pushes them onto a second row
       and costs the panes a line of height each.
       `min-width:0` is what lets it shrink at all: a flex item's automatic minimum size is its
       MIN-CONTENT width, which for nowrap text is the whole string, and that minimum beats
       max-width in the clamp — so without it a long name overflows the header and
       `text-overflow` never fires. */
/* Same ink as the facts, not the pale grey it inherited from being a throwaway line at the
       bottom of the old list. It identifies the picture — it is read, and copied out — so it
       has to be legible rather than merely present. */
.pole-pane-file[b-a93jw9iay3] { min-width:0; max-width:12rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#475569; }
.pole-pane-pos[b-a93jw9iay3] { color:#1d4ed8; font-weight:700; font-variant-numeric:tabular-nums; }
/* The header's own two notes — "no mount", "recorded", "recorded frame missing" — get the
       same colour-only treatment as the facts below. Left as filled pills they were the last
       chips in the panel, which is the mixed formatting one level up from where it was fixed. */
.pole-pane-warn[b-a93jw9iay3] { color:#b45309; }
.pole-pane-stage[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; justify-content:center; min-width:0; }
/* The frame at its OWN aspect ratio, never stretched to the pane's width.
       `flex:1` here made every picture fill the column and `object-fit:contain` then filled
       the difference with the dark background — which on the portrait oblique meant a third
       of the pane was black bars, on the pane whose pictures are already the tallest and
       narrowest. Sized by whichever of width or height runs out first, so a portrait frame
       comes out narrow and tall and a landscape one fills the column: no letterboxing either
       way, and no per-camera rule about which is which.
       width:100% rather than auto, because auto never scales UP: a frame smaller than its pane
       sat at its own pixel size in a sea of white. It now fills the width and, when that makes it
       too tall, is capped and contained — the leftover box is transparent, so the capped case
       costs nothing visible where the old dark background drew bars. */
.pole-pane-stage > img[b-a93jw9iay3] { flex:0 1 auto; min-width:0; max-width:100%; max-height:72vh; width:100%; height:auto; object-fit:contain; border-radius:4px; background:transparent; }
.pole-pane-meta[b-a93jw9iay3] { display:flex; flex-wrap:wrap; gap:.2rem .75rem; align-items:center; font-size:.72rem; color:#475569; font-variant-numeric:tabular-nums; }
/* ONE format for every fact in the panel. There were four — a filled pill for a metric, an
       amber pill for a warning, a plain span for the time and distance, and a dim monospace
       filename — which made a set of peer measurements look like four kinds of thing. Colour is
       the only thing that still varies, and only where it carries meaning: a warning argues
       against the picture, and the pick tags say which frame the machine chose. No pills, no
       uppercase, no letter-spacing, nothing that changes the shape of one line against another. */
.pole-fact[b-a93jw9iay3] { font-size:.72rem; font-weight:400; color:#475569; background:none; border-radius:0; padding:0; text-transform:none; letter-spacing:normal; white-space:nowrap; }
.pole-fact.warn[b-a93jw9iay3] { color:#b45309; }
.pole-fact.best[b-a93jw9iay3] { color:#15803d; }
.pole-fact.closest[b-a93jw9iay3] { color:#b91c1c; }
.pole-fact.rec[b-a93jw9iay3] { color:#a16207; }
.pole-pane-empty[b-a93jw9iay3] { flex:1; display:flex; align-items:center; justify-content:center; text-align:center; min-height:14rem; padding:1rem; color:#64748b; font-size:.8rem; line-height:1.45; background:#f8fafc; border-radius:4px; }
.pole-pane-note[b-a93jw9iay3] { margin:0; color:#64748b; font-size:.68rem; }
.pole-pane-sub[b-a93jw9iay3] { color:#64748b; font-variant-numeric:tabular-nums; }
/* Moving through a pass's frames. A drag target rather than a row of dots: this is the
       most-used action in the review — the operator is hunting a better frame — and a 9-pixel
       circle repeated a dozen times is the wrong control for it. Thumbnails would be worse
       still: exposures a second apart mostly look alike at thumbnail size, so a preview strip
       would be a row of near-identical images taking the space the actual frame needs. */
.pole-frame-scrub[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; justify-content:center; }
.pole-frame-scrub input[type=range][b-a93jw9iay3] { flex:1; max-width:22rem; min-width:6rem; cursor:pointer; accent-color:#1d4ed8; }
/* The pass stepper in the header: its arrows sit inline with the counter they move. */
.pole-pass-step[b-a93jw9iay3] { display:inline-flex; align-items:center; gap:.25rem; }
.pole-pass-step .pole-frame-step[b-a93jw9iay3] { width:1.15rem; height:1.15rem; font-size:.8rem; }
.pole-frame-step[b-a93jw9iay3] { width:1.5rem; height:1.5rem; flex:0 0 auto; display:flex; align-items:center; justify-content:center; border:1px solid #cbd5e1; background:#f8fafc; color:#0f172a; border-radius:5px; font-size:1rem; line-height:1; cursor:pointer; padding:0; }
.pole-frame-step:hover:enabled[b-a93jw9iay3] { background:#e2e8f0; }
.pole-frame-step:disabled[b-a93jw9iay3] { opacity:.3; cursor:default; }
/* The pick tags are `.pole-fact` like everything else now; only their colour differs.
       `closest` is deliberately NOT green: it is the least-bad frame of a set none of which
       contains the pole, and green would read as a recommendation the geometry does not
       support. `rec` is the frame the verdict was recorded against, which is usually not the
       algorithm's pick — the whole reason the recorded one is honoured. */
.pole-pane-recorded[b-a93jw9iay3] { color:#a16207; }
/* The inset map card. Same white panel as a pane so the three read as one row. */
.pole-mini[b-a93jw9iay3] { background:white; border:2px solid transparent; border-radius:6px; padding:.4rem; display:flex; flex-direction:column; gap:.35rem; min-width:0; align-self:start; }
.pole-mini-head[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; font-size:.74rem; color:#64748b; }
.pole-mini-title[b-a93jw9iay3] { font-weight:700; color:#0f172a; }
.pole-mini-head .pole-mini-spacer[b-a93jw9iay3] { flex:1; }
.pole-mini-legend[b-a93jw9iay3] { display:flex; flex-wrap:wrap; gap:.5rem; align-items:center; font-size:.68rem; color:#475569; }
/* A dot's tooltip has to say which pane it belongs to AND how far off its centre landed,
       which does not fit across 300 pixels on Leaflet's default nowrap — it ran off the edge of
       the map instead. Wrapped rather than shortened, because both facts are the reason to hover
       it. The WIDTH has to be explicit: a Leaflet tooltip is absolutely positioned inside a pane
       with no intrinsic width, so a max-width alone shrink-to-fits and breaks every word onto its
       own line. */
.pole-mini[b-a93jw9iay3]  .leaflet-tooltip { white-space:normal; width:9.5rem; text-align:center; }
.pole-mini-note[b-a93jw9iay3] { margin:0; color:#64748b; font-size:.66rem; line-height:1.35; }
.pole-mini-note.warn[b-a93jw9iay3] { color:#a16207; }
/* Also used in each pane's header to tie a pane to its colour on the map. */
.pole-swatch[b-a93jw9iay3] { display:inline-block; width:.6rem; height:.6rem; border-radius:50%; border:1px solid #0f172a; vertical-align:middle; flex:0 0 auto; }
/* The pole under review, as the map draws it: a white ring with nothing in it — hollow
       so the stations whose imagery is being judged stay visible through the one pole they
       are being judged against. Empty rather than white-filled is also what tells it apart
       from .pick below, which is a pane colour wearing a white ring. The box-shadow does
       the same job here as it does there: carry a white ring on a white card. */
.pole-swatch.ring[b-a93jw9iay3] { background:transparent; border:2px solid #ffffff; box-shadow:0 0 0 1px #94a3b8; width:.7rem; height:.7rem; }
/* A picked frame, as the map draws it: white ring, one size up. The outer box-shadow is what
       keeps that white ring visible on this white card — on the map the basemap does that job. */
.pole-swatch.pick[b-a93jw9iay3] { width:.7rem; height:.7rem; border:2px solid #ffffff; box-shadow:0 0 0 1px #94a3b8; }
.pole-review-bar[b-a93jw9iay3] { display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap; background:white; border-radius:6px; padding:.4rem .7rem; }
.pole-review-keys[b-a93jw9iay3] { display:flex; gap:.7rem; flex-wrap:wrap; color:#64748b; font-size:.7rem; }
.pole-review-keys kbd[b-a93jw9iay3] { background:#f1f5f9; border:1px solid #cbd5e1; border-bottom-width:2px; border-radius:3px; padding:0 .25rem; font-size:.66rem; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; margin-right:.1rem; }
.pole-review-actions[b-a93jw9iay3] { display:flex; gap:.4rem; align-items:center; flex-wrap:wrap; }
.pole-btn[b-a93jw9iay3] { border:1px solid transparent; border-radius:6px; padding:.25rem .7rem; font-size:.82rem; font-weight:700; cursor:pointer; white-space:nowrap; }
.pole-btn.good[b-a93jw9iay3] { background:#16a34a; border-color:#15803d; color:white; }
.pole-btn.good:hover:enabled[b-a93jw9iay3] { background:#15803d; }
.pole-btn.bad[b-a93jw9iay3] { background:#dc2626; border-color:#b91c1c; color:white; }
.pole-btn.bad:hover:enabled[b-a93jw9iay3] { background:#b91c1c; }
.pole-btn:disabled[b-a93jw9iay3] { opacity:.4; cursor:default; }
.pole-review .img-note[b-a93jw9iay3] { background:#fff7ed; border:1px solid #fed7aa; color:#9a3412; border-radius:6px; margin:0; padding:.35rem .6rem; font-size:.76rem; }
/* ---- QC filter bar ----
       A flex item at the foot of the stage rather than an overlay on it, so it takes its
       own height off the map and nothing else on the page has to know what that height
       is. It wraps to two and then three rows as the viewport narrows, and the map simply
       gets shorter — which is what makes the wrapping harmless. */
.qc-filter-bar[b-a93jw9iay3] {
        flex:0 0 auto;
        /* Positioned only so the shadow it casts up over the map is not painted under the
           map's own tiles. Nothing is positioned against it. */
        position:relative; z-index:1102;
        display:flex; align-items:center; gap:1rem; flex-wrap:wrap;
        background:#fff; border-top:1px solid #cbd5e1;
        padding:.55rem .9rem; box-shadow:0 -2px 10px rgba(15,23,42,.12);
    }
.qc-bar-filters[b-a93jw9iay3] { display:flex; align-items:flex-end; gap:.85rem; flex-wrap:wrap; }
/* Pushed to the far edge so the two halves read as what they are: what you are
       looking at, and what you can do with it. */
.qc-bar-data[b-a93jw9iay3] { display:flex; align-items:center; gap:.7rem; margin-left:auto; flex-wrap:wrap; }
.qc-bar-field[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.2rem; }
/* The label and its note share one row so the note costs no height. Below the control
       it overhung the bar's bottom padding, and reserving a row for it made the bar taller
       for the sake of two words that are absent most of the time. */
.qc-bar-labelrow[b-a93jw9iay3] { display:flex; align-items:baseline; gap:.4rem; min-height:.95rem; }
/* Matches the rail handles' lettering, which is the page's existing vocabulary for
       "this names a section" rather than a new one invented for the bar. */
.qc-bar-label[b-a93jw9iay3] { font-size:.68rem; font-weight:700; letter-spacing:.12em; color:#475569; }
.qc-bar-input[b-a93jw9iay3] { border:1px solid #cbd5e1; border-radius:6px; background:#f8fafc; color:#0f172a; padding:.3rem .45rem; font-size:.85rem; min-width:11rem; }
.qc-bar-input:focus[b-a93jw9iay3] { outline:2px solid #93c5fd; outline-offset:1px; }
.qc-bar-date[b-a93jw9iay3] { min-width:9.5rem; }
/* Narrower than the control it annotates at every width the bar is used at, so it
       cannot drag the select widths around as it appears and disappears. */
.qc-bar-note[b-a93jw9iay3] { font-size:.66rem; font-weight:400; letter-spacing:.02em; color:#64748b; white-space:nowrap; }
.qc-bar-clear[b-a93jw9iay3] { align-self:flex-end; border:1px solid #cbd5e1; background:#f8fafc; color:#0f172a; border-radius:6px; padding:.3rem .6rem; font-size:.78rem; cursor:pointer; }
.qc-bar-clear:hover:not(:disabled)[b-a93jw9iay3] { background:#e2e8f0; }
.qc-bar-clear:disabled[b-a93jw9iay3] { opacity:.45; cursor:default; }
/* Reads as a way out rather than as a sixth filter, which is what it is: the decision
       this map is evidence for gets made on the page it points back to. */
.qc-bar-back[b-a93jw9iay3] { align-self:flex-end; border:1px solid #bfdbfe; background:#eef5ff; color:#1e40af;
                               border-radius:6px; padding:.3rem .6rem; font-size:.78rem; text-decoration:none; white-space:nowrap; }
.qc-bar-back:hover[b-a93jw9iay3] { background:#dbeafe; }
/* flex-basis 100% so it takes a row of the bar to itself. The bar already wraps and the map
       simply gets shorter, so a full-width row here costs nothing that a narrow viewport does not
       already cost. */
.qc-bar-handoff[b-a93jw9iay3] { flex:1 0 100%; display:flex; align-items:center; gap:.6rem;
                                  border:1px solid #fde68a; background:#fff7e6; color:#92400e;
                                  border-radius:6px; padding:.35rem .6rem; font-size:.78rem; }
.qc-bar-handoff-text[b-a93jw9iay3] { flex:1 1 auto; }
.qc-bar-handoff-line[b-a93jw9iay3] { display:block; }
.qc-bar-handoff-line + .qc-bar-handoff-line[b-a93jw9iay3] { margin-top:.2rem; }
.qc-bar-scope[b-a93jw9iay3] { max-width:16rem; font-size:.78rem; color:#0f172a; }
.qc-bar-scope-text[b-a93jw9iay3] { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* The scene chip carries the scene track's own light purple, which is the point: the line on the
       map and the chip that says why it is there are the same fact, and an operator should not
       have to work out which control put it there. */
.qc-bar-scene-chip[b-a93jw9iay3] { display:inline-flex; align-items:center; gap:.25rem; margin-top:.15rem; padding:.05rem .3rem; border:1px solid #d8b4fe; border-radius:999px; background:#faf5ff; color:#7e22ce; font:inherit; font-size:.7rem; font-weight:700; cursor:pointer; white-space:nowrap; }
.qc-bar-scene-chip:hover[b-a93jw9iay3] { background:#f3e8ff; }
.qc-bar-scene-x[b-a93jw9iay3] { font-weight:400; opacity:.7; }
.qc-bar-scope .muted[b-a93jw9iay3] { color:#64748b; font-style:italic; }
/* The cluster is a box around the two halves of one artifact, so ORTHO and OBLIQUE
       read as two ways of asking about imagery rather than as two more peers of SCANNER
       and ADP. */
.qc-bar-cluster[b-a93jw9iay3] { display:flex; align-items:center; gap:.5rem; border:1px solid #cbd5e1; border-radius:8px; padding:.28rem .45rem; }
.qc-bar-cluster-title[b-a93jw9iay3] { font-size:.68rem; font-weight:700; letter-spacing:.12em; color:#475569; }
.qc-bar-cluster-btns[b-a93jw9iay3] { display:flex; gap:.35rem; }
.qc-bar-btn[b-a93jw9iay3] { border:1px solid #94a3b8; background:#f1f5f9; color:#0f172a; border-radius:6px; padding:.32rem .7rem; font-size:.75rem; font-weight:700; letter-spacing:.08em; cursor:pointer; white-space:nowrap; }
.qc-bar-btn:hover:not(:disabled)[b-a93jw9iay3] { background:#e2e8f0; border-color:#64748b; }
.qc-bar-btn-solo[b-a93jw9iay3] { padding:.55rem .85rem; }
/* Dimmed rather than hidden: the point of the gate is that an operator can see what
       picking a scope will get them. */
.qc-bar-btn:disabled[b-a93jw9iay3] { opacity:.4; cursor:not-allowed; }
.qc-bar-data.is-locked .qc-bar-cluster[b-a93jw9iay3] { border-style:dashed; opacity:.75; }
/* The open button reads as pressed, since the panel it opened sits above the bar
       rather than attached to it and nothing else would tie the two together. */
.qc-bar-btn.is-open[b-a93jw9iay3] { background:#0f172a; border-color:#0f172a; color:#f8fafc; }
.qc-bar-btn.is-open:hover:not(:disabled)[b-a93jw9iay3] { background:#1e293b; border-color:#1e293b; }
/* How many layers are hidden, on the button rather than behind it. Amber and not the bar's
       slate, because it is the one number here that says something is missing from the map:
       a hidden layer with nothing to say so is indistinguishable from ground nothing collected.
       Inherits nothing from .is-open on purpose — it has to stay readable on the pressed button
       as well, which is the state it is most often looked at in. */
.qc-bar-btn-badge[b-a93jw9iay3] { display:inline-block; margin-left:.35rem; padding:0 .32rem; border-radius:999px; background:#f59e0b; color:#0f172a; font-size:.68rem; font-weight:700; letter-spacing:0; vertical-align:baseline; }
/* Anchored to the bar's right edge -- see the comment on the markup. bottom:100% puts
       it on the bar's top edge whatever the bar's height is, so it follows the wrap the
       same way everything else on this page now does. */
.qc-popover[b-a93jw9iay3] {
        position:absolute; right:.9rem; bottom:calc(100% + .45rem); z-index:1103;
        /* Wider than the rail's 22rem because it can be: it is a transient panel over the
           map rather than one of a stack of docked rails, and the extra 3rem is what lets
           the filter chips sit in one row with room to spare instead of only just. */
        width:27rem; max-width:calc(100vw - 240px - 1.8rem);
        display:flex; flex-direction:column;
        /* Bounded here and scrolled in the body below, not on the panel: the head carries
           the project the settings are about and the Close, and both have to stay put
           while the geometry controls are scrolled. */
        max-height:min(70vh, 40rem);
        background:#fff; border:1px solid #cbd5e1; border-radius:8px;
        box-shadow:0 6px 22px rgba(15,23,42,.22);
    }
/* The scanner panel holds two toggles and a note, so the 27rem sized for a rig's worth of
       filter chips would leave it mostly empty. Narrowed rather than given its own block, so it
       keeps the anchoring, the flip at the narrow breakpoint and the scroll behaviour. */
.qc-popover-narrow[b-a93jw9iay3] { width:20rem; }
.qc-popover:focus[b-a93jw9iay3] { outline:none; }
.qc-popover:focus-visible[b-a93jw9iay3] { outline:2px solid #93c5fd; outline-offset:2px; }
.qc-popover-head[b-a93jw9iay3] { display:flex; align-items:baseline; gap:.5rem; flex:0 0 auto; padding:.55rem .7rem .4rem; border-bottom:1px solid #e2e8f0; }
.qc-popover-head strong[b-a93jw9iay3] { display:flex; align-items:center; gap:.35rem; }
.qc-popover-head .muted[b-a93jw9iay3] { font-size:.78rem; color:#64748b; }
/* Named but not editable. The picker lives in the bar, and a second one here is the
       split the popover exists to avoid. */
.qc-popover-project[b-a93jw9iay3] { font-size:.8rem; font-weight:600; color:#334155; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.qc-popover-head .rtqc-btn[b-a93jw9iay3] { margin-left:auto; align-self:center; }
.qc-popover-body[b-a93jw9iay3] { flex:1 1 auto; min-height:0; overflow-y:auto; padding:.6rem .7rem .7rem; }

@media (max-width: 900px) {
    .rtqc-stage.has-readout[b-a93jw9iay3] { --feature-card-inset-left: 0px; }
    .qc-bar-input[b-a93jw9iay3] { min-width:8rem; }
    .qc-bar-scope[b-a93jw9iay3] { display:none; }
}

@media (max-width: 1500px) {
    .pole-review-panes.with-map[b-a93jw9iay3] { grid-template-columns:repeat(var(--pole-panes,2), minmax(0,1fr)) 22rem; }
    .pole-review-panes.stacked.with-map[b-a93jw9iay3] { grid-template-columns:minmax(0,1fr) minmax(0,1.35fr) 22rem; }
}

@media (max-width: 1000px) {
    .pole-review-panes[b-a93jw9iay3],
.pole-review-panes.with-map[b-a93jw9iay3],
.pole-review-panes.stacked[b-a93jw9iay3],
.pole-review-panes.stacked.with-map[b-a93jw9iay3] { grid-template-columns:1fr; grid-template-rows:none; height:auto; }
    .pole-review-panes.stacked > .pole-pane[b-a93jw9iay3],
.pole-review-panes.stacked > .pole-mini[b-a93jw9iay3] { grid-column:auto; grid-row:auto; }
    .pole-review-panes.stacked .pole-pane-stage > img[b-a93jw9iay3] { max-height:72vh; }
    /* One column of panes runs far taller than the modal, and the panes are a flex item of
       the 96vh column with min-height:0 — so flexbox SQUEEZED the grid to fit instead of
       letting it grow, the grid split that height into equal rows, and every frame spilled
       out of its pane over the next. The grid keeps its own height and the modal scrolls;
       the header and the verdict bar stay pinned so G / N are never scrolled out of reach.
       Above 1000px none of this applies: those layouts are built to fit the viewport. */
    .pole-review-inner[b-a93jw9iay3] { overflow-y:auto; }
    .pole-review-panes[b-a93jw9iay3] { flex-shrink:0; }
    .pole-review-head[b-a93jw9iay3] { position:sticky; top:0; z-index:1100; }
    .pole-review-bar[b-a93jw9iay3] { position:sticky; bottom:0; z-index:1100; }
}

@media (min-width: 1200px) {
    .pole-pane.side-text[b-a93jw9iay3] {
            display:grid;
            grid-template-columns:minmax(0,1fr) 11.5rem;
            grid-template-rows:auto minmax(0,1fr);
            grid-template-areas:"head head" "stage foot";
            column-gap:.5rem;
        }
    .pole-pane.side-text > .pole-pane-stage[b-a93jw9iay3] { grid-area:stage; min-height:0; }
    .pole-pane.side-text > .pole-pane-head[b-a93jw9iay3] { grid-area:head; }
    /* Scrolls rather than spilling: a frame carrying every optional chip at once (heading
               unknown, banked, outside the frame, sight line only) is taller than a short pane's
               column, and an overflowing grid item would lay its text across the picture — which is
               the thing this layout exists to stop. */
    .pole-pane.side-text > .pole-pane-foot[b-a93jw9iay3] { grid-area:foot; min-height:0; overflow-y:auto; }
    .pole-pane.side-text > .pole-pane-note[b-a93jw9iay3] { grid-column:1 / -1; }
    /* A COLUMN of facts, one per line — the point of moving them here. Wrapped across a
               narrow column instead, the chips reflow into a ragged block that is harder to scan
               than the row they came from. */
    .pole-pane.side-text .pole-pane-foot[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.35rem; }
    .pole-pane.side-text .pole-pane-meta[b-a93jw9iay3] { flex-direction:column; align-items:flex-start; gap:.25rem; }
    .pole-pane.side-text .pole-frame-scrub[b-a93jw9iay3] { flex-wrap:wrap; justify-content:flex-start; }
    .pole-pane.side-text .pole-frame-scrub input[type=range][b-a93jw9iay3] { flex:1 1 100%; max-width:none; }
}

@media (max-width: 1440px) {
    .qc-bar-data[b-a93jw9iay3] { margin-left:0; }
    /* Below this width the bar wraps and the data group stops being right-aligned, so
               the popover's anchor has to move with it — pinned right it ends up above the far
               side of the bar from the button that opened it. This is the same breakpoint that
               moves the group, which is what keeps the two from disagreeing. */
    .qc-popover[b-a93jw9iay3] { left:.9rem; right:auto; }
}

/* ---- camera footprints (FOOTPRINTS panel) --------------------------------

   Pink leads the palette because every hue this map already spends is taken: cyan is an
   image station, green an ADP sample, purple a planned line, red an ortho gap, amber a scan
   line, and indigo/sky the ortho swaths. A rig carries three or four obliques, so telling one
   camera's trapezoid from the next is the whole reason they draw per camera. */
.fp-legend-dot[b-a93jw9iay3] { display:inline-block; width:7px; height:7px; border-radius:50%; background:#ec4899; border:1.5px solid #0f172a; margin-right:.35rem; vertical-align:baseline; }

.fp-cams[b-a93jw9iay3] { display:flex; flex-direction:column; gap:.4rem; margin-top:.4rem; }
.fp-cam[b-a93jw9iay3] { border:1px solid #e2e8f0; border-radius:6px; padding:.35rem .5rem; }
.fp-cam-head[b-a93jw9iay3] { display:flex; align-items:center; gap:.4rem; cursor:pointer; }
.fp-cam-swatch[b-a93jw9iay3] { display:inline-block; width:10px; height:10px; border-radius:2px; border:1px solid #0f172a; flex:none; }
.fp-cam-name[b-a93jw9iay3] { font-weight:600; }

/* The function is the half the NAME cannot carry: camera0..camera4 says nothing about which
   of them look sideways, and this panel is for the ones that do. Obliques are tinted so the
   pick is made on purpose rather than by position in the list. */
.fp-cam-fn[b-a93jw9iay3] { font-size:.7rem; color:#64748b; text-transform:uppercase; letter-spacing:.02em; }
.fp-cam-fn.is-oblique[b-a93jw9iay3] { color:#be185d; font-weight:600; }

.fp-cam-actions[b-a93jw9iay3] { display:flex; flex-wrap:wrap; gap:.3rem; margin-top:.3rem; }

/* The chips themselves live with the markup that renders them, in FootprintSetStats: scoped
   CSS follows its own component, so a rule kept here would have styled the panel's copy and
   silently left the scene cards' as bare text. */

/* The layers a scene card ticked, which the bar's selects deliberately leave standing. Listed
   here because the card carrying their own tick sits behind a rail that closes, and a drawn
   layer with no way off is the state this panel exists to prevent. */
.fp-others[b-a93jw9iay3] { border-top:1px dashed #e2e8f0; margin-top:.5rem; padding-top:.4rem; display:flex; flex-direction:column; gap:.4rem; }
.fp-cam-scope[b-a93jw9iay3] { margin:.15rem 0 0 1.35rem; font-size:.7rem; color:#64748b; font-variant-numeric:tabular-nums; }

.fp-error[b-a93jw9iay3] { color:#b91c1c; font-weight:600; }
