:root{color-scheme:dark;--bg:#080d0c;--panel:#111a18;--panel-2:#16211e;--line:#283a35;--ink:#edf7f3;--muted:#8fa8a0;--accent:#63e6be;--warn:#ffc857;--bad:#ff6b6b;--header:72px}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:linear-gradient(145deg,#0b1714 0,#080d0c 36%,#0b1110 100%);color:var(--ink);font:15px/1.5 Inter,ui-sans-serif,system-ui,sans-serif;min-height:100vh}.app-header{position:sticky;z-index:20;top:0;min-height:var(--header);display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:0 max(22px,calc((100vw - 1180px)/2));background:#080d0cf2;border-bottom:1px solid var(--line);backdrop-filter:blur(16px)}.brand{display:flex;align-items:center;gap:10px;color:var(--ink);text-decoration:none}.brand-mark{display:block;width:34px;height:34px;border-radius:9px}.brand small,.brand strong{display:block;line-height:1.15}.brand small{font-size:.62rem;letter-spacing:.16em;color:var(--muted)}nav{display:flex;gap:4px}.nav-item{padding:9px 12px;background:transparent;color:var(--muted)}.nav-item.active,.nav-item:hover{background:var(--panel-2);color:var(--ink)}.connection{justify-self:end;display:flex;align-items:center;gap:9px;font-size:.75rem;color:var(--muted)}.live-dot{width:7px;height:7px;border-radius:50%;background:var(--warn)}.live-dot.online{background:var(--accent);box-shadow:0 0 9px var(--accent)}.live-dot.offline{background:var(--bad)}main{max-width:1180px;margin:auto;padding:34px 22px 80px}.page-heading,.title-row{display:flex;align-items:center;justify-content:space-between;gap:20px}.page-heading{margin:8px 0 24px}.page-heading>p{max-width:390px;text-align:right}.page{animation:appear .18s ease}.page[hidden]{display:none}@keyframes appear{from{opacity:.45;transform:translateY(3px)}}h1{font-size:clamp(2rem,5vw,3.8rem);margin:0;letter-spacing:-.05em;line-height:1.05}h2{margin:0;font-size:1rem;text-transform:uppercase;letter-spacing:.08em}.eyebrow{margin:0 0 5px;color:var(--accent);letter-spacing:.22em;font-size:.68rem;font-weight:750}.card,.metrics article{background:linear-gradient(145deg,#14201de8,#101816ed);border:1px solid var(--line);border-radius:13px;padding:21px;margin:18px 0;box-shadow:0 20px 55px #0003}.login-card{max-width:520px;margin:10vh auto}.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.metrics article{margin:0}.metrics span,small,.muted{color:var(--muted)}.metrics strong{display:block;font-size:2rem;letter-spacing:-.04em}.grid{display:grid;grid-template-columns:1.25fr 1fr;gap:18px}.hero-run{border-color:#63e6be45}.badge,.state{display:inline-block;border-radius:99px;padding:4px 9px;background:#263631;color:var(--warn);font-weight:750;font-size:.68rem;text-transform:uppercase;letter-spacing:.04em}.good{color:var(--accent)!important}.bad{color:var(--bad)!important}.warn{color:var(--warn)!important}.board{display:grid;grid-template-columns:1fr auto;gap:3px 12px;padding:14px 0;border-bottom:1px solid var(--line)}.board:last-child{border-bottom:0}.board code,.board small,.board form{grid-column:1/-1}.board.compact{padding:11px 0}.board.issue{padding:16px;background:#ffc85708}.board form{display:grid;grid-template-columns:1fr auto;align-items:end;gap:10px;margin-top:8px}.board form button{margin-bottom:12px}code{font-family:ui-monospace,SFMono-Regular,monospace;color:#b8d8cf}label{display:block;color:var(--muted);font-size:.8rem;font-weight:650}input,select{width:100%;padding:10px 11px;margin:6px 0 12px;background:#080d0c;color:var(--ink);border:1px solid var(--line);border-radius:7px;font:inherit}input:focus,select:focus,button:focus-visible{outline:2px solid #63e6be80;outline-offset:2px}fieldset{border:1px solid var(--line);border-radius:7px;margin:5px 0 14px;padding:10px 13px}fieldset label{display:inline-block;margin-right:15px}fieldset input{width:auto;margin-right:5px}button{background:var(--accent);color:#08231c;border:0;border-radius:7px;padding:10px 14px;font:inherit;font-weight:750;cursor:pointer}button:disabled{opacity:.55;cursor:wait}.secondary{background:#263631;color:var(--ink)}.table-wrap{overflow:auto}table{width:100%;border-collapse:collapse}td,th{text-align:left;padding:11px;border-bottom:1px solid var(--line)}th{color:var(--muted);font-size:.72rem;text-transform:uppercase;letter-spacing:.06em}.progress-track{height:5px;margin:18px 0;background:#080d0c;border-radius:5px;overflow:hidden}.progress-track span{display:block;height:100%;background:var(--accent);transition:width .3s}.prose{max-width:760px}.prose h2{margin-top:28px}.prose h2:first-child{margin-top:0}@media(max-width:850px){.app-header{grid-template-columns:1fr auto;padding-top:10px;padding-bottom:8px}.connection{display:none}nav{grid-row:2;grid-column:1/-1;width:100%;overflow:auto}.brand{margin-bottom:8px}.metrics{grid-template-columns:1fr 1fr}.grid{grid-template-columns:1fr}.page-heading{align-items:flex-start}.page-heading>p{display:none}}@media(max-width:520px){main{padding-inline:13px}.nav-item{padding:7px 9px;font-size:.75rem}.card{padding:16px}.metrics{gap:8px}.metrics article{padding:14px}.metrics strong{font-size:1.6rem}.board form{grid-template-columns:1fr}}
.fleet-counts{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;padding-bottom:12px;margin-bottom:4px;border-bottom:1px solid var(--line)}.fleet-counts span{display:block}.fleet-counts small{display:block;font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.fleet-counts strong{font-size:1.3rem;letter-spacing:-.03em}.fleet-counts .muted{color:var(--muted)}.board-actions{grid-column:1/-1;margin-top:8px}.board .details:not(:empty){grid-column:1/-1;margin-top:10px;padding:12px 14px;background:var(--panel-2);border:1px solid var(--line);border-radius:8px}.board .details p{margin:0 0 10px}.board .details>small{display:block;margin-top:10px}.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px 16px}.detail-grid small{display:block;font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.detail-grid span{word-break:break-word}@media(max-width:520px){.fleet-counts{grid-template-columns:1fr 1fr;gap:10px 8px}}.report-full{margin-top:14px}.report-full pre{max-height:420px;overflow:auto;background:#080d0c;border:1px solid var(--line);border-radius:8px;padding:12px;font-size:.76rem;white-space:pre-wrap}td.duration{font-variant-numeric:tabular-nums;color:var(--muted)}.version{padding:4px 9px;border:1px solid var(--line);border-radius:99px;color:var(--muted);font-family:ui-monospace,SFMono-Regular,monospace;font-size:.7rem}.version.warn{border-color:#ffc85759}#version-detail .detail-grid{margin-bottom:10px}.filter-bar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:14px}.filter-bar input[type=search]{flex:1 1 260px;margin:0}.filter-bar select{width:auto;margin:0}.chips{display:flex;flex-wrap:wrap;gap:6px}.chip{padding:8px 11px;background:#263631;color:var(--muted);border-radius:99px;font-size:.76rem;font-weight:650}.chip.active{background:var(--accent);color:#08231c}.chip small{opacity:.75;font-weight:700}.chip.active small{color:#08231c}.pager{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:14px;flex-wrap:wrap}.pager-buttons{display:flex;gap:8px}#config h3{margin:16px 0 8px;font-size:.78rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}#config h3:first-child{margin-top:0}.connection a{color:inherit;text-decoration:none}.repo-link[hidden]{display:none}.repo-link{display:inline-flex;align-items:center;gap:5px;padding:4px 9px;border:1px solid var(--line);border-radius:99px;color:var(--muted)}.repo-link:hover,.version:hover{color:var(--ink);border-color:#63e6be80}.repo-link svg{flex:none}.row-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.row-actions .muted{font-size:.78rem;max-width:360px;text-align:right}
.hw-table{width:100%;border-collapse:collapse;margin-bottom:12px}.hw-table td,.hw-table th{padding:8px 6px;vertical-align:top}.hw-table th{color:var(--muted);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.hw-table td small{display:block;color:var(--muted)}.hw-table .num{text-align:right;font-variant-numeric:tabular-nums}.hw-total{display:flex;gap:16px;flex-wrap:wrap;margin:4px 0 14px;color:var(--muted);font-size:.8rem}.hw-total strong{color:var(--ink)}
.live-grid{display:grid;grid-template-columns:1.2fr 1fr;gap:18px}.live-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px 16px;margin:12px 0}.live-facts small{display:block;font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.live-facts span{display:block;font-variant-numeric:tabular-nums;word-break:break-word}.timer{font-variant-numeric:tabular-nums;font-size:1.6rem;letter-spacing:-.03em;color:var(--ink)}.stage-strip{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0}.stage-strip span{padding:4px 9px;border:1px solid var(--line);border-radius:99px;font-size:.72rem;color:var(--muted)}.stage-strip .passed{color:var(--accent);border-color:#63e6be55}.stage-strip .running{color:var(--warn);border-color:#ffc85780;box-shadow:0 0 9px #ffc85733}.stage-strip .failed{color:var(--bad);border-color:#ff6b6b55}.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}button.danger{background:#3a2020;color:#ffb3b3}button.danger:hover{background:#4a2626}
.queue-list{margin:0;padding:0;list-style:none}.queue-list li{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:center;padding:10px 0;border-top:1px solid var(--line)}.queue-list li:first-child{border-top:0}.queue-pos{display:grid;place-items:center;width:28px;height:28px;border:1px solid var(--line);border-radius:50%;font-size:.75rem;color:var(--muted)}.queue-list strong{display:block}.queue-list small{display:block;color:var(--muted)}.queue-list .actions{margin:0}.queue-head{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:8px}.queue-paused{color:var(--warn)}.queue-list small.queue-wait{color:var(--warn)}.board .hold-note{display:block;color:var(--warn);margin-top:4px}.also-running{margin-top:14px;padding-top:10px;border-top:1px solid var(--line)}
.md{max-width:820px;line-height:1.55}.md h1,.md h2,.md h3,.md h4{margin:22px 0 8px;letter-spacing:-.02em;text-transform:none;font-size:1.05rem;color:var(--ink)}.md h1{font-size:1.4rem}.md h2{font-size:1.2rem}.md p{margin:8px 0}.md ul,.md ol{margin:8px 0;padding-left:22px}.md li{margin:3px 0}.md code{padding:1px 5px;background:#080d0c;border:1px solid var(--line);border-radius:4px;font-size:.82em}.md pre{margin:10px 0;max-height:360px}.md pre code{padding:0;border:0;background:none;font-size:inherit}.md table{width:auto;min-width:50%;margin:10px 0;font-size:.85rem}.md th,.md td{padding:6px 10px}.md blockquote{margin:10px 0;padding:6px 14px;border-left:3px solid var(--accent);color:var(--muted)}.md hr{border:0;border-top:1px solid var(--line);margin:18px 0}.md a{color:var(--accent)}.md img{display:none}
.artifacts button.artifact{background:transparent;cursor:pointer}.artifacts button.artifact:hover{color:var(--ink);border-color:#63e6be80}a.sha{color:var(--accent);text-decoration:none;font-family:ui-monospace,SFMono-Regular,monospace}a.sha:hover{text-decoration:underline}.board .chip-facts{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:6px 14px;font-size:.8rem;color:var(--muted)}.board .chip-facts b{color:var(--ink);font-weight:600}
/* The canary's verdict for a board, beside its state. A board nothing has
   checked says so rather than looking healthy by omission, and a failure
   the whole rig shares is coloured as the farm's fault, not the board's. */
.board .chip-facts.health b{color:var(--warn)}
.state.muted{color:var(--muted)!important}
/* Two actions now: read the chip, and run the canary on it. */
.board-actions{display:flex;gap:8px;flex-wrap:wrap}
/* What a user key may not do is not offered to it; the service refuses it either way. */
body[data-role="user"] .admin-only{display:none!important}
/* And what the farm will refuse a signed-in person, as opposed to a key: an
   account reads its own workspace, so a control or a destination whose every
   read is farm-wide is not offered to one. The service refuses it either way;
   this is so nobody is invited to find that out. */
body[data-caller="account"] .farm-wide{display:none!important}
.badge.you{text-transform:none}
.board.instrument .wiring{margin:6px 0 0;padding-left:18px;font-size:.85em}
/* A portal's workers: each node, where it is with the release, and its boards */
.worker-row{padding:12px 0;border-top:1px solid var(--line)}.worker-row:first-of-type{border-top:0}
.worker-row .title-row h2,.worker-group>.title-row h2{font-size:1.05rem}
.worker-facts{margin:8px 0}.worker-release{margin:4px 0 0}.worker-facts .state{display:inline-block;width:auto;margin-left:4px}
.worker-group{margin-bottom:22px;padding-bottom:12px;border-bottom:1px solid var(--line)}.worker-group:last-child{border-bottom:0;margin-bottom:0}
details.node-config{border-top:1px solid var(--line);padding:12px 0}details.node-config>summary{cursor:pointer;font-size:1rem}
/* Overview: the fleet at a glance */
.metrics article small{display:block;margin-top:4px;font-size:.74rem;line-height:1.3}
.overview-grid{grid-template-columns:1.6fr 1fr}
.attention-list{list-style:none;margin:0;padding:0}.attention-list li{display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:start;padding:9px 0;border-top:1px solid var(--line)}.attention-list li:first-child{border-top:0}
.attention-list .dot{width:9px;height:9px;border-radius:50%;margin-top:6px;background:var(--muted)}.attention-list .dot.bad{background:var(--bad)}.attention-list .dot.warn{background:var(--warn)}.attention-list .dot.good{background:var(--accent)}
.attention-list small{display:block;color:var(--muted)}
/* Fleet tabs */
.tabs{display:flex;gap:6px;margin:0 0 14px;border-bottom:1px solid var(--line)}.tabs a{padding:9px 14px;color:var(--muted);text-decoration:none;font-weight:650;border-bottom:2px solid transparent;margin-bottom:-1px}.tabs a:hover{color:var(--ink)}.tabs a.active{color:var(--ink);border-bottom-color:var(--accent)}
/* Rig and board tables: a row is the way in */
table.fleet{width:100%;border-collapse:collapse}table.fleet th{color:var(--muted);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em;text-align:left;padding:8px 10px}table.fleet td{padding:10px;border-top:1px solid var(--line);vertical-align:top}table.fleet td small{display:block;color:var(--muted)}table.fleet tr.clickable:hover td{background:var(--panel-2)}table.fleet .num{text-align:right;white-space:nowrap}
.state-line{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.command-log{max-height:420px;overflow:auto;white-space:pre-wrap;font-size:.78rem}
.join-command{display:flex;gap:10px;align-items:stretch;margin:12px 0}.join-command pre{flex:1;margin:0;padding:12px;background:#080d0c;border:1px solid var(--line);border-radius:8px;font-size:.78rem;white-space:pre-wrap;word-break:break-all;user-select:all}.join-wait{display:flex;align-items:center;gap:9px}.join-wait .dot{flex:none}
.settings-form{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px 16px;margin-top:10px}.settings-form label{display:flex;flex-direction:column;gap:4px;margin:0;font-size:.8rem}.settings-form input[type=number]{width:100%}.settings-form .check{flex-direction:row;align-items:center;gap:8px}
details.new-run>summary{cursor:pointer;display:flex;flex-direction:column;gap:2px;list-style:none}details.new-run>summary::-webkit-details-marker{display:none}details.new-run[open]>summary{margin-bottom:12px}
.check-table td:first-child{text-transform:none}
/* A link that does what a button does: go somewhere */
a.button{display:inline-flex;align-items:center;background:var(--accent);color:#08231c;border-radius:7px;padding:10px 14px;font-weight:750;text-decoration:none;white-space:nowrap}
a.button.secondary{background:var(--panel-2);color:var(--ink);border:1px solid var(--line)}a.button.secondary:hover{border-color:#63e6be80}
table.fleet td:first-child{white-space:nowrap}
.rig-devices li{grid-template-columns:1fr auto}.rig-devices form{display:flex;gap:6px;align-items:center;margin:0}.rig-devices form input{margin:0;width:170px}.rig-devices form button{margin:0}
@media(max-width:900px){.overview-grid{grid-template-columns:1fr}}
#jobs td small.sub{display:block;color:var(--muted)}
#node-banner h2{margin:4px 0}

@media(max-width:850px){.live-grid{grid-template-columns:1fr}}@media(max-width:520px){.queue-list li{grid-template-columns:auto 1fr}.queue-list .actions{grid-column:1/-1}}
#test-selection{margin:5px 0 14px}#test-selection summary{color:var(--muted);font-size:.8rem;font-weight:650;cursor:pointer}#test-selection[open] summary{margin-bottom:6px}#test-files label.test-file{display:block;margin:4px 0}#test-files label.test-file small{color:var(--muted)}label.check{display:flex;align-items:center;gap:8px;margin:0 0 14px;font-weight:500;color:var(--ink)}label.check input{width:auto;margin:0}

/* Artifacts page */
.linkish{padding:0;background:none;border:0;color:var(--accent);font:inherit;cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.linkish:hover{color:var(--ink)}
#bundles td small,#bundle-detail td small{display:block;color:var(--muted)}
#bundles tr.selected td{background:var(--panel-2)}
#bundles .family-chips{display:flex;flex-wrap:wrap;gap:4px;min-width:150px;max-width:240px}
.storage-track.warn span{background:var(--warn)}
.storage-track.bad span{background:var(--bad)}
.storage-table td small{display:block;color:var(--muted);font-size:.72rem;word-break:break-all}
.storage-table tr.sub td:first-child{padding-left:26px}
.storage-table td.num,.storage-table td:nth-child(3),#bundles td.num{white-space:nowrap}
.storage-table button:disabled,#bundles button:disabled,#bundle-detail button:disabled{opacity:.45;cursor:not-allowed}
.prune-form{display:flex;flex-wrap:wrap;align-items:flex-end;gap:14px;margin-bottom:12px}
.prune-form label{display:flex;align-items:center;gap:8px;margin:0;font-weight:500;color:var(--ink)}
.prune-form input{width:84px;margin:0}
/* Artifact and storage pages: rows are the way in, and dense enough to scan */table.compact td,table.compact th{padding:7px 10px}table.compact{width:100%;border-collapse:collapse}tr.clickable{cursor:pointer}tr.clickable:hover td{background:var(--panel-2)}a.row-link{color:var(--ink);font-weight:650;text-decoration:none}a.row-link:hover{color:var(--accent);text-decoration:underline}.bundle-table td small,#storage-detail td small,.storage-table td small{display:block;color:var(--muted);font-size:.72rem;line-height:1.35;margin-top:2px}.bundle-table td small .state,#storage-detail td small .state{padding:1px 6px;font-size:.6rem}.bundle-table .family-chips{display:flex;flex-wrap:wrap;gap:3px;max-width:200px}.bundle-table .family-chips .artifact{padding:1px 6px;font-size:.68rem}.branch{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.85em}#bundle-subtitle,#storage-subtitle{margin:6px 0 0}#bundle-actions{margin:0}#bundle-overview .live-facts{grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}
td.nowrap,td.nowrap small{white-space:nowrap}.bundle-table td.bundle-name{min-width:220px}.bundle-table td{vertical-align:top}
#bundle-title,#storage-title{font-size:clamp(1.7rem,3.4vw,2.6rem);line-height:1.1}#bundle-images td strong+small{margin-left:6px}.page[data-page="artifact"] .page-heading,.page[data-page="storage"] .page-heading{align-items:flex-start}
/* Statistics */.stats-metrics{grid-template-columns:repeat(6,1fr)}.stats-metrics small{display:block;font-size:.72rem;line-height:1.3;margin-top:2px}.stats-metrics strong{font-size:1.7rem}.stats-chart{width:100%}.runs-chart{width:100%;height:230px;display:block}.bar-passed{fill:var(--accent)}.bar-failed{fill:var(--bad)}.bar-cancelled{fill:#5b6f69}.bar-busy{fill:#4c8dff}.chart-axis{stroke:var(--line);stroke-width:1}.chart-label{fill:var(--muted);font-size:11px}.legend{display:inline-flex;align-items:center;gap:5px;margin-left:10px;font-size:.75rem}.legend::before{content:'';width:10px;height:10px;border-radius:2px;display:inline-block}.legend-passed::before{background:var(--accent)}.legend-failed::before{background:var(--bad)}.legend-cancelled::before{background:#5b6f69}.legend-busy::before{background:#4c8dff}.hbars{display:grid;gap:10px}.hbar-row{display:grid;grid-template-columns:minmax(120px,1.2fr) 2fr auto;align-items:center;gap:10px}.hbar-label{font-size:.85rem}.hbar{width:100%;height:10px;display:block;border-radius:3px;overflow:hidden}.hbar-track{fill:#0b1110}.hbar-fill{fill:var(--warn)}.hbar-good{fill:var(--accent)}.hbar-bad{fill:var(--bad)}.hbar-muted{fill:#5b6f69}.hbar-count{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:.85rem}.rate-cell{min-width:150px;white-space:nowrap}.rate-cell .hbar{display:inline-block;width:80px;vertical-align:middle;margin-right:6px}.stats-band{padding:16px 21px}.stats-band-row{display:grid;grid-template-columns:110px repeat(6,1fr);gap:14px;align-items:center;margin-top:10px}.stats-band-row small{display:block;font-size:.7rem}.stats-band-row strong{font-size:1.25rem;letter-spacing:-.02em}.spark{width:110px;height:34px}.stats-grid{align-items:start}@media(max-width:850px){.stats-metrics{grid-template-columns:repeat(2,1fr)}.stats-band-row{grid-template-columns:repeat(3,1fr)}.spark{grid-column:1/-1;width:100%}}
.health-summary{display:flex;flex-wrap:wrap;gap:6px 16px;align-items:center;margin:2px 0 8px;font-size:.84rem}.health-summary>span{display:inline-flex;align-items:center;gap:6px}.health-summary .dot,.health-problems .dot,.check-chip .dot,.join-wait .dot{margin:0}.health-problems{margin:0 0 8px;padding:0;list-style:none}.health-problems li{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:2px 10px;padding:8px 0;border-top:1px solid var(--line)}.health-problems small{grid-column:2;overflow-wrap:anywhere}details.compact-more>summary{cursor:pointer;color:var(--muted);font-size:.8rem;margin-top:6px}.check-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}.check-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 9px;border:1px solid var(--line);border-radius:99px;font-size:.74rem;color:var(--muted)}.check-chip .dot{width:7px;height:7px}
.setting-groups{display:grid;grid-template-columns:repeat(auto-fit,minmax(270px,1fr));gap:14px;margin-top:12px}.setting-group{border:1px solid var(--line);border-radius:10px;padding:14px 14px 6px;background:#0b12108c}.setting-group h3{margin:0 0 2px;font-size:.78rem;text-transform:uppercase;letter-spacing:.06em}.setting-group>p{margin:0 0 6px;font-size:.76rem}.setting{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:9px 0;border-top:1px solid var(--line);margin:0;color:var(--ink);font-size:inherit;font-weight:inherit}.setting strong{display:block;font-weight:600;font-size:.86rem}.setting small{display:block;font-size:.72rem;font-weight:400}.setting .value{font-variant-numeric:tabular-nums;white-space:nowrap}.setting .field{display:flex;align-items:center;gap:6px;white-space:nowrap}.setting .field input[type=number]{width:92px;margin:0}.setting .field input[type=checkbox]{width:auto;margin:0}.setting .field em{font-style:normal;color:var(--muted);font-size:.78rem}.setting.changed strong{color:var(--warn)}.settings-footer{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:14px}details.host-config{margin-top:16px}details.host-config>summary{cursor:pointer;font-weight:650}details.host-config>summary small{font-weight:400;margin-left:6px}#rig-channels .setting .value{white-space:normal;word-break:break-all;text-align:right}#rig-channels code.fingerprint{word-break:break-all}#rig-channels .setting .field input[type=password]{width:min(420px,55vw);margin:0}#rig-channels .setting .field select{margin:0}
.rig-description{margin:0 0 12px;color:var(--ink)}.rig-details-form{margin-bottom:14px}.join-panel{margin-top:14px;padding:14px;border:1px dashed var(--line);border-radius:10px}.join-panel p:last-child{margin-bottom:0}#add-rig-form label small{display:block;margin-top:-8px;font-weight:400}
#releases td small{display:block;color:var(--muted)}
#firmware-metrics{margin-bottom:14px}.library-project .title-row small{display:block;margin-top:2px}.library-table td.actions{text-align:right;white-space:nowrap}.library-table .family-chips{display:flex;flex-wrap:wrap;gap:4px}.library-show-more{margin-top:10px}#bundle-branch{cursor:pointer}#config-source{margin-top:0}#config-projects h3{margin:18px 0 8px;font-size:.78rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}

/* The console drawer: docked, collapsed to its bar until opened. */
.console{position:fixed;z-index:30;left:0;right:0;bottom:0;background:#060a09f2;border-top:1px solid var(--line);backdrop-filter:blur(14px)}
.console-bar{display:flex;align-items:center;gap:10px;justify-content:space-between;padding:6px max(22px,calc((100vw - 1180px)/2))}
.console-title{display:flex;align-items:center;gap:8px;background:transparent;color:var(--muted);font-size:.76rem;text-transform:uppercase;letter-spacing:.08em;padding:6px 0}
.console-title:hover{color:var(--ink)}
.console-title small{text-transform:none;letter-spacing:0}
.console-dot{width:7px;height:7px;border-radius:50%;background:var(--muted)}
.console.live .console-dot{background:var(--accent);box-shadow:0 0 9px var(--accent)}
.console-tools{display:flex;gap:8px;align-items:center}
.console-tools select{width:auto;margin:0;padding:6px 8px;font-size:.78rem}
.console-tools button{padding:6px 10px;font-size:.76rem}
#console-follow[aria-pressed=false]{color:var(--muted)}
.console-lines{max-height:38vh;overflow:auto;margin:0;padding:4px max(22px,calc((100vw - 1180px)/2)) 12px;list-style:none;font-family:ui-monospace,SFMono-Regular,monospace;font-size:.76rem;line-height:1.7}
.console-lines li{display:grid;grid-template-columns:76px 104px 1fr;gap:12px;white-space:pre-wrap;word-break:break-word;border-top:1px solid #1b2724}
.console-lines li:first-child{border-top:0}
.console-lines time{color:var(--muted);font-variant-numeric:tabular-nums}
.console-lines .who{color:#7fd7bd;overflow:hidden;text-overflow:ellipsis}
.console-lines .warn-line{color:var(--warn)}
.console-lines .error-line{color:var(--bad)}
.console-empty{color:var(--muted);padding:6px 0}
body.console-open main{padding-bottom:46vh}
@media(max-width:520px){.console-lines li{grid-template-columns:62px 1fr}.console-lines .who{display:none}}

/* What a rig is set up to do: one row per capability, its state, and
   where it is turned on. */
.setup-table td{vertical-align:top}
.setup-table td small{display:block;color:var(--muted)}
.setup-table td code{display:inline-block;margin-top:4px;font-size:.92em;word-break:break-all}
.setup-table .state{margin-bottom:2px}

/* What the host is doing: load, memory, temperature, uptime. */
.host-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:10px;margin:12px 0 4px}
.host-metrics strong{display:block;font-size:1.35rem;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.host-metrics small{display:block;color:var(--muted);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}
.host-metrics.warn strong{color:var(--warn)}
.host-metrics.bad strong{color:var(--bad)}

/* The channels a rig can send through, one card each. */
.channel-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-top:12px}
.channel-card{padding:13px 15px;background:var(--panel-2);border:1px solid var(--line);border-radius:9px}
.channel-card>div{display:flex;align-items:center;justify-content:space-between;gap:8px}
.channel-card small{display:block;color:var(--muted);margin-top:4px;word-break:break-word}

/* A rig's capabilities as chips: under its name on its page, under its
   name in the rigs list. A chip in the heading is a button: it opens the
   Setup table at its row, so it resets what `button` paints. */
.setup-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.setup-chip{display:inline-flex;align-items:center;gap:7px;padding:6px 11px;background:var(--panel-2);border:1px solid var(--line);border-radius:99px;color:var(--ink);font:inherit;font-size:.78rem;font-weight:600;line-height:1.2;cursor:default}
button.setup-chip{cursor:pointer}
button.setup-chip:hover{border-color:#63e6be80}
.setup-chip.muted{color:var(--muted)}
.heading-chips{margin-top:10px}
.heading-chips:empty{display:none}
.setup-chips.compact{gap:5px;margin-top:6px}
.setup-chips.compact .setup-chip{padding:2px 8px;gap:5px;font-size:.68rem;font-weight:500}
.setup-chips.compact .setup-chip .dot{width:6px;height:6px}

/* Who sees a rig: the word, and beside it the buttons for whoever may change it. */
.inline-actions{display:inline-flex;flex-wrap:wrap;gap:6px;margin-left:10px;vertical-align:middle}
.inline-actions button{padding:4px 9px;font-size:.72rem}

/* The world page: the farm for anyone. The dashboard's look, one column of
   totals and a grid of rigs, and nothing to click that needs a key. */
.world .connection{display:flex}
.world .connection .button{padding:8px 12px;font-size:.8rem;text-decoration:none;border-radius:7px}
.world .page-heading>p{max-width:520px}
.world .metrics article small{display:block;margin-top:6px}
.world .metrics article small strong{display:inline;font-size:inherit;letter-spacing:0;color:var(--ink)}
/* The hero and supporting scenes: generated editorial hardware artwork,
   captioned as illustrations rather than passed off as a particular rig. */
.world-hero{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:40px;align-items:center;margin:14px 0 34px}
.world-hero h1{font-size:clamp(2.4rem,6vw,4.2rem);line-height:1.02;letter-spacing:-.055em}
.world-hero h1 em{font-style:normal;color:var(--accent)}
.world-hero .lede{max-width:46ch;margin:22px 0 0;font-size:1.05rem}
.world-hero .hero-note{max-width:46ch;margin:14px 0 0;font-size:.85rem;color:var(--muted)}
.hero-art{margin:0;display:grid;gap:10px;width:min(560px,48vw)}
.hero-photo{display:block;width:100%;height:auto;aspect-ratio:2/1;object-fit:cover;border-radius:13px;border:1px solid var(--line);box-shadow:0 18px 40px #0008}
.hero-art figcaption{text-align:center;font-size:.72rem;color:var(--muted)}
.world-story{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.5fr);gap:14px;margin:18px 0 30px}
.world-visual{margin:0;overflow:hidden;background:var(--panel);border:1px solid var(--line);border-radius:13px}
.world-visual img{display:block;width:100%;height:260px;object-fit:cover}
.world-visual figcaption{padding:11px 14px;color:var(--muted);font-size:.76rem}
.world-visual figcaption strong{color:var(--ink)}
.world-footer{max-width:1180px;margin:0 auto;padding:26px 22px 60px;border-top:1px solid var(--line);color:var(--muted);font-size:.85rem}
.world-footer a{color:var(--accent)}
.world-rigs{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px;margin-top:18px}
.world-rig{margin:0}
.world-rig h2{text-transform:none;letter-spacing:-.02em;font-size:1.2rem}
.world-rig .title-row small{display:block;margin-top:2px}
.world-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:10px 14px;margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.world-facts small{display:block;font-size:.68rem;text-transform:uppercase;letter-spacing:.08em}
.world-facts span{display:block;margin-top:2px}
.family{display:inline-block;margin-right:8px}
@media(max-width:850px){
  .world .connection{display:flex;justify-self:end}
  .world-hero{grid-template-columns:1fr;gap:26px}
  .hero-art{width:100%;justify-items:start}
  .world-story{grid-template-columns:1fr}
  .world-visual img{height:auto}
}
.setup-chip .dot{width:7px;height:7px;border-radius:50%;background:currentColor}
.setup-chip.good .dot{background:var(--accent)}.setup-chip.bad .dot{background:var(--bad)}
.setup-chip.warn .dot{background:var(--warn)}.setup-chip.muted .dot{background:var(--muted)}
/* The login card: two ways in for a person, and the key for a program. */
.signin-methods{display:grid;gap:16px;margin:16px 0 8px}
.signin-github{display:inline-block;justify-self:start;text-decoration:none;color:#08231c;background:var(--accent);padding:12px 18px;border-radius:7px;font-weight:750}
.signin-row{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:start}
.signin-row input{margin-bottom:0}.signin-row button{margin-top:6px}
.signin-note{padding:10px 12px;border:1px solid var(--line);border-radius:7px;background:var(--panel-2)}
#signin-key{margin-top:14px}#signin-key summary{cursor:pointer;color:var(--muted);font-size:.85rem}
#signin-key[open] summary{margin-bottom:6px}
.sign-out{padding:5px 10px;font-size:.7rem}
.setup-attention{margin:12px 0 0;padding-left:18px;color:var(--bad)}
.setup-attention strong{color:var(--ink)}

/* The rig page's tabs. */
.tabs{display:flex;gap:4px;flex-wrap:wrap;margin:6px 0 2px;border-bottom:1px solid var(--line)}
.tab{padding:9px 14px;background:transparent;color:var(--muted);border-radius:8px 8px 0 0;font-weight:700}
.tab:hover{color:var(--ink);background:var(--panel-2)}
.tab.active{color:var(--ink);background:var(--panel-2);box-shadow:inset 0 -2px 0 var(--accent)}
.tab small{color:var(--muted);font-weight:650}
.tabs[hidden]{display:none}
/* A section belongs to the tabs named in its own `data-tab`, and the chosen
   tab is an attribute on the page. In CSS rather than in a renderer: the runs
   arrive after the tab was chosen, a finished command re-renders its card, and
   either would otherwise show a section the tab had already put away. It only
   ever hides -- a section that hid itself stays hidden.
   Every rule that shows carries `:not([hidden])`, so `hidden` decides on its
   own rather than by out-weighing them: the grid's rule names an id, which
   beat a rule written to keep a hidden section hidden, and a pending rig
   showed the last rig's health and activity under its join command. */
.page[data-rig-tab] > [data-tab]{display:none}
.page[data-rig-tab="overview"] > [data-tab~="overview"]:not([hidden]),
.page[data-rig-tab="boards"] > [data-tab~="boards"]:not([hidden]),
.page[data-rig-tab="runs"] > [data-tab~="runs"]:not([hidden]),
.page[data-rig-tab="activity"] > [data-tab~="activity"]:not([hidden]),
.page[data-rig-tab="setup"] > [data-tab~="setup"]:not([hidden]){display:block}
.page[data-rig-tab] > [data-tab][hidden]{display:none}
.page[data-rig-tab="overview"] > #rig-grid[data-tab~="overview"]:not([hidden]){display:grid}
/* The runs tab's own controls: what to start on this rig, above its history. */
.run-controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:12px 0 4px}
.pager{display:flex;gap:8px;align-items:center;justify-content:flex-end;margin-top:12px}
.pager .muted{margin-right:auto}

/* The run form's project strip, and a project's page under the table. */
.project-strip{display:flex;flex-wrap:wrap;gap:.4rem 1.2rem;margin:.2rem 0 .8rem;font-size:.85rem}
.project-strip span{white-space:nowrap}
.project-page{margin-top:1rem}
.project-page h3{margin:1rem 0 .4rem;font-size:.95rem}
.project-gate{margin:.6rem 0 1rem}
tr.selected td{background:rgba(127,127,127,.08)}

/* The guide, off the rig: the same row as the pages, set apart as a link out. */
#nav .nav-guide { margin-left: auto; font-size: 0.85rem; opacity: 0.8; text-decoration: none; align-self: center; padding: 0.35rem 0.6rem; }
#nav .nav-guide:hover { opacity: 1; text-decoration: underline; }

/* A details dialog: the whole picture behind one button, in the page's own colours. */
dialog.dialog{border:1px solid var(--line);border-radius:12px;padding:18px 22px 22px;max-width:760px;width:calc(100% - 32px);background:var(--panel);color:var(--ink)}
dialog.dialog::backdrop{background:rgba(0,0,0,.55)}
dialog.dialog .dialog-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
dialog.dialog h3{margin:16px 0 6px;font-size:.9rem}
dialog.dialog details summary{cursor:pointer;color:var(--muted);font-size:.85rem}
.repo-list code{margin:0 6px 6px 0;display:inline-block}
.github-actions{flex-wrap:wrap;margin-top:8px}
ul.plain{margin:6px 0;padding-left:18px}
.settings-form[hidden]{display:none}
.update-actions{flex-wrap:wrap;align-items:center;gap:10px 14px;margin-top:8px}.update-actions label.check{display:flex;align-items:center;gap:8px;font-size:.85rem}.update-state{margin:6px 0 0}

/* Settings: the administration is one group at the end of the strip, named. */
.tabs .tabs-group{margin-left:auto;align-self:center;padding:0 10px;font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.visibility-control{display:flex;flex-direction:column;gap:4px}
.visibility-control select{max-width:180px}

/* The library: a card a project, its facts in a row, its builds under it. */
.library-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px 18px;margin-top:14px}.library-facts>div{display:grid;gap:3px;align-content:start}.library-facts>div>small{font-size:.68rem;text-transform:uppercase;letter-spacing:.06em}.library-facts span small{display:block;font-size:.74rem}.library-project.builtin{border-color:#63e6be45}.library-project .title-row>div>small{display:block;margin-top:3px;max-width:640px}.library-builds{margin-top:14px}.library-builds summary{cursor:pointer;color:var(--muted);font-size:.8rem}
.usage-metrics{grid-template-columns:repeat(5,1fr);margin-bottom:14px}.usage-metrics strong{font-size:1.4rem}.state.proven{margin-left:8px;vertical-align:middle}@media(max-width:850px){.usage-metrics{grid-template-columns:1fr 1fr}}
/* Profiles; library facts that wrap rather than spill */.profile-metrics{margin-bottom:18px}.profile-can{margin:4px 0 0;padding-left:20px;color:var(--muted)}.profile-can li{margin:2px 0}pre.snippet{background:#080d0c;border:1px solid var(--line);border-radius:7px;padding:12px;overflow:auto;font-size:.8rem}a.badge.you{text-decoration:none}a.badge.you:hover{color:var(--ink)}.library-facts>div{min-width:0}.library-facts .family-chips{flex-wrap:wrap}
/* Chips that wrap inside a facts cell; a header that stays on one line */.library-facts>div>span{min-width:0}.library-facts .family-chips{display:flex;flex-wrap:wrap;gap:4px}.connection{flex-wrap:nowrap;white-space:nowrap}.connection .badge,.connection .version{white-space:nowrap}@media(max-width:1500px){#last-updated,.repo-link{display:none!important}}
/* A run's title is its project's name and an id: a page heading, not a poster. On a phone the
   heading's buttons go under it rather than squeezing it to three words a line. */
#job-title{font-size:clamp(1.7rem,3.4vw,2.6rem);line-height:1.1}
@media(max-width:600px){.page-heading{flex-direction:column;align-items:stretch;gap:12px}.page-heading .row-actions,.page-heading>.actions{justify-content:flex-start;flex-wrap:wrap}}
/* The phone menu scrolls sideways: an edge with more menu behind it fades out (app.js navHint). */
#nav.scrolls-right{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 44px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 44px),transparent)}
#nav.scrolls-left{-webkit-mask-image:linear-gradient(to right,transparent,#000 44px);mask-image:linear-gradient(to right,transparent,#000 44px)}
#nav.scrolls-left.scrolls-right{-webkit-mask-image:linear-gradient(to right,transparent,#000 44px,#000 calc(100% - 44px),transparent);mask-image:linear-gradient(to right,transparent,#000 44px,#000 calc(100% - 44px),transparent)}
#nav{scrollbar-width:none}#nav::-webkit-scrollbar{display:none}
