/* ─── Achromatic chrome, on purpose.
       Colour on this page always MEANS something: a status, a signal series, or
       where the playhead sits. Nothing is tinted for decoration, which is what
       lets four camera feeds and seven traces sit on one screen without fighting.
       Single committed dark theme — viewports demand a dark ground, and every
       colour is painted explicitly so the page holds on any host background. ─── */
:root {
  --ground:  #0B0B0C;
  --panel:   #131315;
  --panel-2: #1A1A1D;
  --panel-3: #232327;
  --line:    #2B2B30;
  --line-2:  #1F1F23;
  --ink:     #F2F1EF;
  --ink-2:   #B3B2B0;
  --muted:   #7B7A79; --muted-2:#57565A;
  --accent:  #F2F1EF;            /* active / selected reads as LIGHT, not as a hue */
  --accent-w:#FFFFFF14;
  --play:    #E9A13B;            /* in / out markers, and anything live */
  --play-w:  #E9A13B1F;
  --ok:      #6FBF73; --ok-w:  #6FBF731C;
  --warn:    #E9A13B; --warn-w:#E9A13B1C;
  --crit:    #E4695E; --crit-w:#E4695E1C;
  /* categorical series palette — warm-led and muted; only ever inside charts and lanes */
  --p1:#E9A13B; --p2:#E4695E; --p3:#C77DC0; --p4:#8E92DE;
  --p5:#5FB3B8; --p6:#A8C05A; --p7:#DCDCE0;
  --r: 5px;
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--ground); color: var(--ink);
  font-family: "Barlow", ui-sans-serif, system-ui, sans-serif;
  font-size: 13.5px; line-height: 1.45; -webkit-font-smoothing: antialiased;
}
h1,h2,h3 { font-family: "Barlow", sans-serif; margin: 0; font-weight: 600; }
.mono, code { font-family: "JetBrains Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; }
button { font: inherit; color: inherit; background: none; border: 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 3px; }
@media (prefers-reduced-motion: reduce) { * { animation-duration: .001ms !important; } }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 9px; }
::-webkit-scrollbar-track { background: transparent; }

/* ── shell ───────────────────────────────────────────────────────────── */
.shell { display: grid; grid-template-columns: 200px minmax(0,1fr); min-height: 100vh; }
.rail { background: var(--panel); border-right: 1px solid var(--line); padding: 16px 10px;
        display: flex; flex-direction: column; gap: 22px; position: sticky; top: 0; height: 100vh; }
.brand { display: flex; gap: 9px; align-items: center; padding: 2px 6px 0; }
.brand svg { width: 24px; height: 24px; flex: none; color: var(--ink); }
.brand .n { font-weight: 700; font-size: 12.5px; letter-spacing: .015em; line-height: 1.1; }
.brand .s { font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.navgroup { display: flex; flex-direction: column; gap: 1px; }
.navlabel { font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted-2); padding: 0 8px 5px; }
.navitem { display: flex; align-items: center; gap: 9px; padding: 6px 8px; width: 100%;
           border-radius: var(--r); cursor: pointer; text-align: left; color: var(--ink-2); font-size: 13px; }
.navitem:hover { background: var(--panel-2); color: var(--ink); }
.navitem[aria-current="page"] { background: var(--panel-3); color: var(--ink); font-weight: 600;
  box-shadow: inset 2px 0 0 var(--ink); }
.navitem svg { flex: none; opacity: .85; }
.navitem .c { margin-left: auto; font-family: "JetBrains Mono"; font-size: 10.5px; color: var(--muted); }
.rail-foot { margin-top: auto; border-top: 1px solid var(--line-2); padding-top: 11px; font-size: 11px; color: var(--muted); padding-left: 8px; }
.rail-foot b { color: var(--ink-2); font-weight: 600; }

.main { min-width: 0; display: flex; flex-direction: column; }
.topbar { border-bottom: 1px solid var(--line); background: var(--panel); padding: 11px 20px;
          display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap; }
.crumb { font-size: 11px; color: var(--muted); display: flex; gap: 6px; align-items: center; margin-bottom: 2px; }
.crumb button { cursor: pointer; color: var(--muted); }
.crumb button:hover { color: var(--accent); }
.topbar h1 { font-size: 17px; letter-spacing: -.005em; }
.topbar .sub { color: var(--muted); font-size: 12px; }
.chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line);
        border-radius: 3px; padding: 3px 8px; font-family: "JetBrains Mono"; font-size: 10.5px;
        color: var(--ink-2); background: var(--panel-2); }
.body { padding: 16px 20px 40px; display: flex; flex-direction: column; gap: 14px; }

/* ── primitives ──────────────────────────────────────────────────────── */
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); }
.card-h { display: flex; align-items: center; justify-content: space-between; gap: 12px;
          padding: 9px 13px; border-bottom: 1px solid var(--line-2); min-height: 38px; }
.card-h h2 { font-size: 12px; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-2); }
.card-h .note { font-size: 11px; color: var(--muted); }
/* A header caption also carries failure text on some cards. A failure in caption grey is a
   failure nobody reads. */
.card-h .note.fault { color: var(--warn); }
.card-b { padding: 13px; }
.grid { display: grid; gap: 12px; }
.g4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
.g3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.g2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (max-width:1150px){ .g4{grid-template-columns:repeat(2,1fr)} .g3{grid-template-columns:repeat(2,1fr)} }
@media (max-width:820px){ .shell{grid-template-columns:1fr} .rail{position:static;height:auto} .g4,.g3,.g2{grid-template-columns:1fr} }

.statstrip { display: grid; grid-template-columns: repeat(4, minmax(0,1fr));
             background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); }
.statstrip .stat { border-right: 1px solid var(--line-2); }
.statstrip .stat:last-child { border-right: 0; }
@media (max-width:1150px){ .statstrip{grid-template-columns:repeat(2,1fr)}
  .statstrip .stat:nth-child(2n){border-right:0}
  .statstrip .stat:nth-child(-n+2){border-bottom:1px solid var(--line-2)} }
.sectionhead { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
               margin: 12px 2px -4px; padding-bottom: 2px; }
.sectionhead h2 { font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.sectionhead .note { font-size: 11.5px; color: var(--muted-2); }
.player > .stage { padding: 12px; border-bottom: 1px solid var(--line-2); }
.stat { padding: 13px 15px; }
.stat .k { font-size: 9.5px; letter-spacing: .15em; text-transform: uppercase; color: var(--muted); }
.stat .v { font-size: 24px; font-weight: 600; letter-spacing: -.02em; margin-top: 2px;
           font-family: "JetBrains Mono"; font-variant-numeric: tabular-nums; }
.stat .v small { font-size: 12px; color: var(--muted); margin-left: 3px; font-weight: 400; }
.stat .d { font-size: 11px; color: var(--muted); margin-top: 2px; }

.pill { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 600;
        padding: 2px 7px; border-radius: 3px; white-space: nowrap; letter-spacing: .02em; }
.pill.ok{color:var(--ok);background:var(--ok-w)} .pill.warn{color:var(--warn);background:var(--warn-w)}
.pill.crit{color:var(--crit);background:var(--crit-w)} .pill.idle{color:var(--muted);background:#78839014}
.pill.live{color:var(--play);background:var(--play-w)}
.dot { width: 5px; height: 5px; border-radius: 5px; background: currentColor; flex: none; }
.pill.live .dot { animation: blip 1.8s ease-in-out infinite; }
@keyframes blip { 0%,100%{opacity:1} 50%{opacity:.25} }

table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.tablewrap { overflow-x: auto; }

/* Signals and the capture log are a PAIR in the same .g2 row, so they share one height — two
   numbers would drift apart the first time either was tuned. Shorter than the old 322px because
   neither is the point of the page: the video and the timeline are, and these two were pushing
   them off the top of a 1080p screen. */
:root { --scrollbox: 228px; }
.scrollbox { max-height: var(--scrollbox); overflow-y: auto; }
/* The header must survive the scroll — a rate column is unreadable once its heading is gone. */
.scrollbox thead th { position: sticky; top: 0; background: var(--panel); z-index: 1; }
th { text-align: left; font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
     font-weight: 600; padding: 8px 12px; border-bottom: 1px solid var(--line); white-space: nowrap; }
td { padding: 9px 12px; border-bottom: 1px solid var(--line-2); }
tbody tr:last-child td { border-bottom: 0; }
tr.click { cursor: pointer; }
tr.click:hover td { background: var(--panel-2); }
.num { font-family: "JetBrains Mono"; font-variant-numeric: tabular-nums; white-space: nowrap; }
.id { font-family: "JetBrains Mono"; font-size: 11.5px; color: var(--ink-2); }
.sub { color: var(--muted); font-size: 11px; }
.kv { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; padding: 1px 0; }
.kv > :first-child { color: var(--muted); }
.kv > :last-child { font-family: "JetBrains Mono"; font-size: 11.5px; text-align: right; }

/* ── viewports ───────────────────────────────────────────────────────── */
.stage { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: 12px; }
@media (max-width:1250px){ .stage{grid-template-columns:1fr} }
.view { position: relative; background: #05070A; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.view canvas { display: block; width: 100%; height: 100%; }
.view .vh { position: absolute; top: 0; left: 0; right: 0; display: flex; justify-content: space-between;
            align-items: center; padding: 7px 10px; font-family: "JetBrains Mono"; font-size: 10.5px;
            color: #9FB0C4; background: linear-gradient(#05070ACC, #05070A00); pointer-events: none; }
.view .vh b { color: #DCE6F2; font-weight: 500; }
.view .vf { position: absolute; bottom: 0; left: 0; right: 0; display: flex; justify-content: space-between;
            padding: 6px 10px; font-family: "JetBrains Mono"; font-size: 10px; color: #6C7A8B;
            background: linear-gradient(#05070A00, #05070ACC); pointer-events: none; }
.viewmain { height: 476px; }
.feedcol { display: grid; grid-template-rows: repeat(3, minmax(0,1fr)); gap: 12px; }
.feedcol .view { height: auto; min-height: 0; }
@media (max-width:1250px){ .feedcol{grid-template-rows:none;grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
  .feedcol .view{height:168px} .viewmain{height:380px} }

/* ── the replay header: robot, footage, provenance ─────────────────────────
   ⚠ THE FOOTAGE IS THE SUBJECT (owner's wireframe, 2026-09-12). The 3-D view used to take a
   large square with the four cameras stacked in a 300 px column beside it — a few hundred pixels
   each, on the screen whose entire purpose is looking at what the robot saw. The robot is CONTEXT
   for the footage, so it gets one column and the cameras get a 2x2 grid of roughly twice the area.

   `minmax(0, …)` on every track because a canvas in a grid does not shrink below its intrinsic
   size otherwise, and one oversized frame silently pushes the provenance column off the page. */
.replaytop { display: grid; grid-template-columns: minmax(0,0.85fr) minmax(0,1.5fr) minmax(0,290px);
             gap: 12px; padding: 12px; border-bottom: 1px solid var(--line-2); }
.replaytop .viewmain { height: 100%; min-height: 340px; }
.feedgrid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr));
            grid-template-rows: repeat(2, minmax(0,1fr)); gap: 10px; }
.feedgrid .view { height: auto; min-height: 0; }
/* The provenance column scrolls rather than stretching the row: the tallest thing on this row
   should be the video, not a list of identifiers. */
.provcol { margin: 0; overflow: auto; max-height: 100%; }

/* One column below 1250 px: side by side, each of the three would be too narrow to read, and a
   camera feed that small is worse than one you scroll to. */
@media (max-width:1250px){
  .replaytop { grid-template-columns: 1fr; }
  .replaytop .viewmain { height: 360px; }
  .feedgrid { grid-template-rows: none; grid-template-columns: repeat(auto-fit, minmax(260px,1fr)); }
  .feedgrid .view { height: 200px; }
  .provcol { max-height: none; }
}

.vtools { position: absolute; right: 8px; bottom: 26px; display: flex; flex-direction: column; gap: 4px; }
.vtool { width: 27px; height: 27px; border: 1px solid #23303F; background: #0B1219CC; border-radius: 4px;
         cursor: pointer; display: grid; place-items: center; color: #93A4B6; font-size: 10.5px;
         font-family: "JetBrains Mono"; backdrop-filter: blur(3px); }
.vtool:hover { border-color: var(--accent); color: var(--accent); }
.vtool[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: #4C8DFF22; }

/* ── transport + timeline ────────────────────────────────────────────── */
/* ⚠ THREE COLUMNS SO THE CONTROLS SIT IN THE TRUE CENTRE. A flex row with the cut controls pushed
   right by `margin-left:auto` left the transport hugging the left edge with a large void beside it.
   Centring the flex row alone would not work either: the cut group's width would shift the centre.
   An empty 1fr on the left mirrors the right-hand column, so the middle is centred against the CARD
   rather than against whatever happens to be beside it. */
.transport { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
             gap: 14px; padding: 12px 14px; }
@media (max-width: 1150px) {
  .transport { grid-template-columns: 1fr; }
  .cutbtn { grid-column: 1; justify-self: center; }
}
.tmain { grid-column: 2; display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
         justify-content: center; }
.timecard .transport { border-top: 1px solid var(--line-2); }
/* Related controls touch; unrelated ones are separated by the flex gap above. Before this the
   transport was ONE undifferentiated row of nine controls at an even 10px, so nothing read as
   belonging with anything else. */
.tgroup { display: flex; align-items: center; gap: 4px; }
.tsep { width: 1px; align-self: stretch; background: var(--line-2); }

/* ⚠ min-width, NOT width. These were a fixed 30x30 square holding "◀◀ 5s", so the label wrapped
   inside the button and the seconds rendered on a second line under the arrow — which is what made
   the step buttons look broken. They size to their content now and never wrap. */
.tbtn { min-width: 32px; height: 32px; padding: 0 9px; border: 1px solid var(--line); border-radius: 4px;
        cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
        white-space: nowrap; font-size: 11.5px; font-family: "JetBrains Mono"; color: var(--ink-2);
        background: var(--panel-2); }
.tbtn .g { color: var(--muted-2); }
.tbtn:hover .g { color: inherit; }
.tbtn:hover { border-color: var(--accent); color: var(--accent); }
.tbtn.primary { background: var(--accent); border-color: var(--accent); color: #06101F;
                min-width: 38px; padding: 0; }
.tclock { font-family: "JetBrains Mono"; font-size: 15px; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.tclock small { color: var(--muted); font-size: 11.5px; }
.speeds { display: flex; gap: 2px; border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.speeds button { padding: 4px 8px; font-size: 11px; font-family: "JetBrains Mono"; cursor: pointer; color: var(--muted); }
.speeds button[aria-pressed="true"] { background: var(--panel-3); color: var(--ink); }
.cutbtn { grid-column: 3; justify-self: end; display: flex; gap: 8px; align-items: center; }
.btn { padding: 6px 11px; border: 1px solid var(--line); border-radius: 4px; cursor: pointer;
       font-size: 12px; color: var(--ink-2); background: var(--panel-2); }
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn.go { background: var(--accent); border-color: var(--accent); color: #06101F; font-weight: 600; }
.btn.go:hover { filter: brightness(1.08); color: #06101F; }

/* ONE TIME ROW, full width. The 158 px names gutter is gone with the per-signal lanes (owner's
   wireframe): it had nothing left to name, and removing it makes the drag target that much wider. */
/* ⚠ THE TIMELINE'S GEOMETRY LIVES IN THESE TWO VARIABLES, and nothing hard-codes it again.
   `.sel` and `.selhandle` were pinned at `top: 24px`, the ruler height at the time — so raising the
   ruler to 30px silently pushed the selection band 6px up INTO the ruler. Two elements needing to
   agree about a height is exactly the drift a variable exists to prevent. */
:root { --ruler-h: 30px; --lane-h: 104px; }

/* Inset, NOT edge to edge. The bar used to run into both card borders, so the first tick sat on the
   left edge and the last label was clipped in half by the right one. Percentages inside `.tl-area`
   are relative to the inset box, and `#at()` measures the same box, so the drag maths is unchanged. */
.tl { display: grid; grid-template-columns: minmax(0,1fr); padding: 0 14px 14px; }
.tl-area { position: relative; cursor: crosshair; border: 1px solid var(--line-2); border-radius: 5px;
           overflow: hidden; background: var(--panel-2); }

/* Double height (owner, 2026-09-13). This IS the scrubbing fix: earlier attempts tuned drag
   SENSITIVITY and each felt identical, because the problem was never the ratio — it was the size of
   the thing being aimed at. */
.lane-time { height: var(--lane-h); border-bottom: 0; background: var(--bg); }
/* Inset from the lane edges by a proportion of it, so both track --lane-h automatically. */
.lane-time .gap { top: 14%; height: 72%; }
.lane-time .ep { top: 10%; height: 80%; line-height: normal; font-size: 10.5px; }

.tl-ruler { height: var(--ruler-h); border-bottom: 1px solid var(--line-2); position: relative;
            background: var(--panel); }
.tl-ruler span { position: absolute; top: 10px; font-family: "JetBrains Mono"; font-size: 9.5px;
                 color: var(--muted-2); transform: translateX(-50%); white-space: nowrap; }
/* A label at either extreme would hang outside the box; these two pull it back inside instead of
   letting it clip, which is what produced the half-rendered "17" at the right edge. */
.tl-ruler span.at-start { transform: none; }
.tl-ruler span.at-end { transform: translateX(-100%); }
.tl-ruler i { position: absolute; top: 0; width: 1px; height: 6px; background: var(--line); }

.lane { height: 22px; border-bottom: 1px solid var(--line-2); position: relative; }
.lane:last-child { border-bottom: 0; }
.lane .fill { position: absolute; top: 5px; height: 12px; border-radius: 2px; }
.lane .gap { position: absolute; top: 5px; height: 12px; background: var(--crit); min-width: 2px; border-radius: 1px; }
.lane .ep { position: absolute; top: 3px; height: 16px; border-radius: 3px; border: 1px solid;
            font-size: 9.5px; font-family: "JetBrains Mono"; display: flex; align-items: center;
            padding: 0 5px; overflow: hidden; white-space: nowrap; }
.sel { position: absolute; top: var(--ruler-h); bottom: 0; background: #FFB0201A;
       border-left: 1px solid var(--play); border-right: 1px solid var(--play); pointer-events: none; }
.selhandle { position: absolute; top: var(--ruler-h); bottom: 0; width: 11px; cursor: ew-resize; z-index: 3; }
.selhandle::after { content:""; position: absolute; top: 0; bottom: 0; left: 5px; width: 1px; background: var(--play); }
.selhandle b { position: absolute; top: 0; width: 11px; height: 14px; background: var(--play); border-radius: 0 0 2px 2px; }
.ph { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--ink); z-index: 4; pointer-events: none; }
.ph::before { content:""; position: absolute; top: 0; left: -5px; border: 5.5px solid transparent; border-top-color: var(--ink); border-bottom: 0; }

.logbox { max-height: var(--scrollbox); overflow-y: auto; font-family: "JetBrains Mono"; font-size: 11px; }
.logbox div { display: grid; grid-template-columns: 56px 74px minmax(0,1fr); gap: 9px; padding: 3px 13px; border-bottom: 1px solid var(--line-2); }
.logbox div:hover { background: var(--panel-2); }
.logbox .t { color: var(--muted-2); }
.logbox .lv { font-weight: 600; }
.logbox .lv.i { color: var(--accent); } .logbox .lv.w { color: var(--warn); }
.logbox .lv.e { color: var(--crit); } .logbox .lv.o { color: var(--ok); }
.logbox .m { color: var(--ink-2); }

/* ── device tiles ────────────────────────────────────────────────────── */
.devcard { cursor: pointer; overflow: hidden; display: flex; flex-direction: column; }
.devcard:hover { border-color: var(--accent); }
.devthumb { height: 148px; background: #05070A; border-bottom: 1px solid var(--line-2); position: relative; }
.devthumb canvas { display: block; width: 100%; height: 100%; }
.devthumb .tag { position: absolute; top: 8px; right: 8px; }
.devbody { padding: 11px 13px 13px; display: flex; flex-direction: column; gap: 6px; }
.devname { font-size: 14px; font-weight: 600; }

.bars { display: flex; flex-direction: column; gap: 7px; }
.barrow { display: grid; grid-template-columns: 128px minmax(0,1fr) 62px; gap: 10px; align-items: center; font-size: 12px; }
.barrow .tr { height: 6px; border-radius: 3px; background: var(--line-2); overflow: hidden; }
.barrow .tr i { display: block; height: 100%; border-radius: 3px; }
.barrow .n { font-family: "JetBrains Mono"; font-size: 11px; text-align: right; color: var(--ink-2); }

.legend { display: flex; flex-wrap: wrap; gap: 11px; font-size: 11px; color: var(--muted); font-family: "JetBrains Mono"; }
.legend i { width: 10px; height: 2px; display: inline-block; vertical-align: middle; margin-right: 5px; }
.tabs { display: flex; gap: 2px; }
.tab { padding: 5px 11px; cursor: pointer; font-size: 12px; color: var(--muted); border-radius: 3px; }
.tab[aria-selected="true"] { background: var(--panel-3); color: var(--ink); font-weight: 600; }
.screen[hidden] { display: none; }
.note-strip { display: flex; gap: 9px; align-items: flex-start; border: 1px dashed var(--line);
              border-radius: var(--r); padding: 9px 11px; font-size: 12px; color: var(--ink-2); background: var(--panel-2); }
.note-strip .tag { font-size: 9px; letter-spacing: .12em; text-transform: uppercase; font-weight: 700;
                   color: var(--warn); background: var(--warn-w); padding: 2px 6px; border-radius: 3px; flex: none; margin-top: 1px; }

/* ── shell additions (the SPA replaced the mockup's show/hide screens) ─────── */
.empty {
  padding: 26px 16px; text-align: center; color: var(--muted); font-size: 13px;
  border: 1px dashed var(--line); border-radius: var(--r); background: var(--panel);
}
.card .empty { border: 0; background: none; }
.navitem { border: 0; font-family: inherit; }
.tab, .vtool, .tbtn, .btn, .speeds button { font-family: inherit; }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn[disabled]:hover { border-color: var(--line); color: var(--ink-2); }
.devthumb .empty { display: grid; place-items: center; height: 100%; }

/* --- Embodiments: self-sizing tile grid, bounded per robot region --------------------------
   ADDITIVE, beside .g2/.g3/.g4 rather than replacing them. Those are FIXED column counts with
   media-query breakpoints; this fills the width with as many tiles as fit, at any viewport, with
   no breakpoint to maintain.

   auto-fill, NOT auto-fit: with a single configuration, auto-fit collapses the empty tracks and
   stretches that one tile across the full width, which reads as a banner rather than as one item
   among several. auto-fill keeps the tile its natural size and leaves the rest of the row empty —
   honest about how much is actually there. */
.gauto { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

/* Bounded so a robot with fifteen historical configurations cannot push the next robot off the
   page. The screen stays a list of ROBOTS; depth lives inside each region. */
.embregion-tiles { max-height: 420px; overflow-y: auto; padding-right: 4px; }

/* Tile header: the name reads left, the STATUS reads right. Both tags are always present — a
   status column that is sometimes blank makes the reader check whether it is missing or meaningful,
   and that hesitation costs more than the pixels the tags occupy. */
.tilehead { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tilehead .devname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tiletags { display: inline-flex; gap: 5px; flex: none; }

/* The ARBITRARY name, under the descriptive one. Quieter than the machine name deliberately: the
   name answers "what is this and whose is it", which is what someone scanning a fleet needs first;
   the nickname is how people refer to it once they already know. Rendered only when it exists —
   most customer-facing machines have none, and an empty line would read as a missing value. */
.nickname { font-size: 12px; color: var(--muted); margin-top: -2px; }


/* ── camera picker (a panel is a viewport, not a camera) ──────────────────── */
/* ⚠ pointer-events: auto is LOAD-BEARING. `.view .vf` sets pointer-events: none so the readout
   overlay never intercepts a drag on the video beneath it — which would also have made this select
   impossible to open. The overlay stays transparent to the pointer; only the control takes it. */
.feedpick { pointer-events: auto; max-width: 62%; border: 1px solid var(--line); border-radius: 3px;
            background: #05070ACC; color: var(--ink-2); font-family: "JetBrains Mono";
            font-size: 10px; padding: 2px 4px; cursor: pointer; }
.feedpick:hover { border-color: var(--accent); color: var(--accent); }
.feedpick:focus-visible { outline: 1px solid var(--accent); outline-offset: 1px; }
