:root{--bg:#f4f7fb;--panel:#fff;--panel2:#f0f3f8;--text:#10213f;--muted:#68758c;--line:#dbe4ef;--accent:#1769ee;--accent2:#e8f1ff;--good:#168957;--warn:#a76300;--bad:#c23a3a;--cyan:#0398b7;--shadow:0 8px 24px rgba(13,36,76,.06);--radius:14px;--sidebar:254px;--topbar:58px;--mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,Consolas,'Liberation Mono',monospace}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:14px/1.45 'DM Sans',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif}h1,h2,h3,h4{font-family:'Manrope',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;letter-spacing:-.02em}body.dark{--bg:#0c111b;--panel:#131b28;--panel2:#1a2535;--text:#ecf2fa;--muted:#91a0b6;--line:#263448;--accent:#52d3b7;--accent2:#193b3a;--good:#52d3b7;--warn:#f0b45a;--bad:#ff7474;--cyan:#56c6e6;--shadow:0 15px 35px rgba(0,0,0,.22)}
button,input,select{font:inherit}button,a{cursor:pointer}button:focus-visible,a:focus-visible,input:focus-visible{outline:3px solid color-mix(in srgb,var(--accent) 35%,transparent);outline-offset:2px}.app-shell{display:grid;grid-template-columns:var(--sidebar) 1fr;min-height:100vh}aside{background:var(--panel);border-right:1px solid var(--line);padding:18px 14px;display:flex;flex-direction:column;position:sticky;top:0;height:100vh;z-index:9;transition:.2s}.brand{display:grid;grid-template-columns:42px 1fr 26px;gap:10px;align-items:center;padding:2px 7px 22px}.brand-mark{width:42px;height:42px;border-radius:13px;background:linear-gradient(145deg,var(--accent),#24d3e8 60%,#53e3b6);color:#fff;display:grid;place-items:center;font-weight:800;box-shadow:0 8px 20px color-mix(in srgb,var(--accent) 21%,transparent)}.brand-mark:has(>img){overflow:hidden;background:#00214d}.brand-mark>img{width:100%;height:100%;display:block}.brand span:nth-child(2),.operator span:last-child{display:grid}.brand small,.operator small{font-size:10px;color:var(--muted)}#collapse{border:0;background:var(--panel2);color:var(--muted);border-radius:8px;width:26px;height:28px}
nav{display:flex;flex-direction:column;gap:3px;overflow:auto}nav small{font-size:10px;color:var(--muted);letter-spacing:.12em;padding:16px 10px 6px;text-transform:uppercase}nav a{display:grid;grid-template-columns:25px 1fr;align-items:center;text-decoration:none;color:var(--muted);padding:10px;border-radius:9px}nav a:hover,nav a.active{background:var(--accent2);color:var(--accent)}nav i{font-style:normal}.operator{margin-top:auto;border-top:1px solid var(--line);padding:16px 7px 0;display:grid;grid-template-columns:34px 1fr;gap:9px;align-items:center}.avatar{width:34px;height:34px;border-radius:50%;background:var(--accent2);color:var(--accent);display:grid;place-items:center;font-size:11px;font-weight:700}
main{min-width:0}.app-shell>main>header{height:60px;background:var(--panel);border-bottom:1px solid var(--line);display:flex;align-items:center;padding:0 28px;gap:12px;position:sticky;top:0;z-index:8}.crumb{display:flex;gap:7px;font-weight:600}.crumb span:first-child{color:var(--muted)}.header-actions{margin-left:auto;display:flex;align-items:center;gap:12px}.header-actions button,#menu{border:0;background:var(--panel2);color:var(--text);border-radius:8px;padding:7px 10px}.live{display:flex;align-items:center;gap:7px;color:var(--good);font-size:12px;font-weight:700}.live i{width:7px;height:7px;border-radius:50%;background:var(--good);box-shadow:0 0 0 4px color-mix(in srgb,var(--good) 13%,transparent)}.live.stale{color:var(--bad)}.live.stale i{background:var(--bad);box-shadow:0 0 0 4px color-mix(in srgb,var(--bad) 13%,transparent)}#menu{display:none}#content{padding:28px;max-width:1600px;margin:auto}.page-head{display:flex;justify-content:space-between;align-items:flex-end;gap:18px;margin-bottom:24px}.eyebrow{color:var(--accent);font-size:10px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.page-head h1{font-size:30px;letter-spacing:-.035em;margin:5px 0}.page-head p{color:var(--muted);margin:0}.refresh{border:1px solid var(--line);background:var(--panel2);color:var(--text);border-radius:8px;padding:9px 13px;font-weight:700}
/* THE STRIP DERIVES ITS COLUMNS FROM WHAT IS IN IT. Pinned at four, the
   portfolio's fifth tile dropped to a row of its own at a quarter width,
   and the two-tile strip left half a row empty - the same defect in both
   directions, from one number that has to be remembered whenever a tile is
   added. auto-fit lays out any count evenly; the narrow overrides below
   stay because they are deliberate, not arithmetic. */
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px;margin-bottom:18px}.metric,.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow)}.metric{padding:18px}.metric span{color:var(--muted);font-size:11px}.metric strong{font-size:28px;display:block;margin:5px 0}.metric small{color:var(--muted)}.metric.good strong{color:var(--good)}.metric.bad strong{color:var(--bad)}.metric.warn strong{color:var(--warn)}.metric.neutral strong{color:var(--muted)}.grid-2{display:grid;grid-template-columns:1.4fr 1fr;gap:18px}.card{padding:18px;margin-bottom:18px}.card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}.card h2{font-size:16px;margin:0}.card-head span{font-size:11px;color:var(--muted)}.service-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}.service{background:var(--panel2);border-radius:10px;padding:13px;display:flex;justify-content:space-between;align-items:center}.pill{display:inline-flex;padding:4px 8px;border-radius:999px;background:var(--panel2);font-size:10px;font-weight:800;text-transform:capitalize}.pill.good{background:color-mix(in srgb,var(--good) 13%,transparent);color:var(--good)}.pill.bad{background:color-mix(in srgb,var(--bad) 13%,transparent);color:var(--bad)}.pill.warn{background:color-mix(in srgb,var(--warn) 13%,transparent);color:var(--warn)}.pill.neutral{background:color-mix(in srgb,var(--muted) 15%,transparent);color:var(--muted)}button.pill{border:1px solid transparent;cursor:pointer;font-family:inherit}button.pill:hover,button.pill:focus-visible{border-color:currentColor}
.table-wrap{overflow:auto;border:1px solid var(--line);border-radius:11px}table{border-collapse:collapse;width:100%;min-width:720px;background:var(--panel)}th{text-align:left;background:var(--panel2);color:var(--muted);font-size:10px;letter-spacing:.06em;padding:11px 13px}td{padding:12px 13px;border-top:1px solid var(--line);vertical-align:middle}code{font:12px ui-monospace,SFMono-Regular,monospace;color:var(--accent)}.toolbar{display:flex;gap:10px;margin-bottom:14px}.toolbar input:not([type="checkbox"]){min-width:280px;flex:1;border:1px solid var(--line);border-radius:9px;padding:9px 12px;background:var(--panel);color:var(--text)}.empty{padding:35px;text-align:center;color:var(--muted)}.notice{padding:12px 14px;border-left:3px solid var(--warn);background:color-mix(in srgb,var(--warn) 8%,var(--panel));border-radius:8px;margin-bottom:12px}.definition{display:grid;grid-template-columns:180px 1fr;padding:10px 0;border-bottom:1px solid var(--line)}.definition span:first-child{color:var(--muted)}.definition.glance-row{grid-template-columns:150px 1fr auto;align-items:center;gap:10px}.loading{color:var(--muted);padding:50px;text-align:center}#toast{position:fixed;right:24px;bottom:24px;background:#10182a;color:#fff;padding:11px 15px;border-radius:9px;opacity:0;transform:translateY(10px);transition:.2s}#toast.show{opacity:1;transform:none}
body.collapsed{--sidebar:78px}body.collapsed .brand span:nth-child(2),body.collapsed nav span,body.collapsed nav small,body.collapsed .operator span:last-child{display:none}body.collapsed .brand{grid-template-columns:42px}body.collapsed #collapse{justify-self:center}body.collapsed nav a{grid-template-columns:1fr;text-align:center}body.collapsed .operator{grid-template-columns:1fr}
@media(max-width:980px){.metrics{grid-template-columns:repeat(2,1fr)}.grid-2{grid-template-columns:1fr}.app-shell{grid-template-columns:1fr}aside{position:fixed;left:-270px;width:254px;transition:.2s}.menu-open aside{left:0;box-shadow:20px 0 45px #0b183044}#menu{display:block}#collapse{display:none}.app-shell>main>header{padding:0 16px}#content{padding:20px}}
@media(max-width:600px){.metrics{grid-template-columns:1fr}.page-head{display:block}.page-head button{margin-top:14px}.service-grid{grid-template-columns:1fr}.toolbar input{min-width:0;width:100%}.definition{grid-template-columns:1fr;gap:3px}}
/* EVERY BUTTON VARIANT IS THE SAME BOX. This set `border:0` and `.secondary`
   below sets a 1px line, so a secondary button has always been 2px taller than
   the primary or danger button beside it - measured on the appliance at 28px
   against 26px in one row of Sites & Customers, after the tenant surface's own
   override was removed. A TRANSPARENT border of the same width equalises the
   box without changing a single colour: `.secondary` still paints its line
   over it, and nothing else gains a visible edge. */
.primary,.danger,.small,.secondary{border:1px solid transparent;border-radius:8px;padding:9px 13px;color:#fff;background:var(--accent);font-weight:700}.secondary{background:var(--panel2);color:var(--text);border:1px solid var(--line)}/* No `border:0` here: it would undo the transparent border above and put this variant back to being 2px shorter than the secondary beside it. */
.danger{background:var(--bad);color:#fff}.small{padding:5px 8px;font-size:11px;margin-right:5px}.small.secondary{background:var(--panel2);color:var(--text);border:1px solid var(--line)}.toolbar{flex-wrap:wrap;align-items:center}.toolbar .toolbar-toggle{margin-left:auto}.timeline{border-left:2px solid var(--line);margin-left:9px;padding-left:20px}.event{position:relative;padding:0 0 18px}.event:before{content:"";position:absolute;left:-26px;top:5px;width:10px;height:10px;border-radius:50%;background:var(--accent)}.event small{color:var(--muted)}.ladder{display:grid;grid-template-columns:1fr 70px 1fr;align-items:center;gap:8px;padding:9px;border-bottom:1px solid var(--line)}.ladder span:nth-child(2){text-align:center;color:var(--accent)}
.recorder[hidden]{display:none}.recorder{border-color:color-mix(in srgb,var(--accent) 35%,var(--line))}.recorder-fields{display:grid;grid-template-columns:2fr 1fr;gap:14px;margin-bottom:18px}.recorder-fields label{color:var(--muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}.recorder-fields input{display:block;width:100%;margin-top:6px;border:1px solid var(--line);border-radius:9px;padding:9px 12px;background:var(--panel);color:var(--text)}.recorder-status{display:grid;grid-template-columns:12px 1fr auto;align-items:center;gap:10px;background:var(--panel2);border-radius:10px;padding:13px;margin-bottom:14px}.recorder-status i{width:10px;height:10px;border-radius:50%;background:var(--muted)}.recorder-status i.active{background:var(--bad);box-shadow:0 0 0 5px color-mix(in srgb,var(--bad) 18%,transparent);animation:pulse 1.2s infinite}.recorder-status time{font:700 16px ui-monospace,SFMono-Regular,monospace}.recording-help{color:var(--muted);font-size:12px;margin:0}ul.recording-help{margin:6px 0 0;padding-left:18px}ul.recording-help li{margin:2px 0}.recorder button:disabled{opacity:.45;cursor:not-allowed}@keyframes pulse{50%{opacity:.45}}
/* FOUR INLINE STYLES THAT NEVER APPLIED. The Learning Center carried
   `style="..."` attributes on a summary, two manual iframes and an article
   body, and this product serves `style-src 'self'` - which blocks a style
   ATTRIBUTE as firmly as a <style> element. So the pointer cursor never
   appeared, the article body never wrapped, and the manual viewer's iframe had
   no height at all: it rendered at the browser's default 150px, on the page
   whose entire job is showing a manual. Silent, because a blocked style logs
   to the console and changes nothing else. Found by asserting on console
   errors while driving the deployed appliance. */
.learn-summary{cursor:pointer}
.learn-manual-frame{width:100%;height:60vh;border:1px solid var(--line);border-radius:9px;background:#fff}
.learn-manual-frame.tall{height:70vh}
.learn-article-body{white-space:pre-wrap;font-family:inherit}
/* A heading that separates two collections on one page. The walkthrough videos
   page carries the workspace recordings and the worked examples, and without a
   break between them the second grid reads as more of the first. */
.section-heading{margin:26px 0 6px;font-size:15px}
.section-heading:first-of-type{margin-top:8px}
/* THE SCRIPT TRAVELS WITH THE RECORDING. Collapsed, because it is long and the
   card is a card - but present, so a reader who cannot play audio still has
   every word that is spoken, and a reader deciding whether to watch can see
   what it covers. */
/* The player on a walkthrough's own page. Sized to the column rather than to
   the viewport, so the script beneath it stays reachable without scrolling
   past a full screen of video. */
/* A worked call, in the shape a reader copies. Monospace, scrollable
   sideways rather than wrapped, because a wrapped curl command is a command
   that will not run when pasted. */
.api-sample{margin:6px 0 14px;padding:13px 15px;background:var(--panel2);border:1px solid var(--line);border-radius:9px;font:12px/1.55 ui-monospace,SFMono-Regular,monospace;white-space:pre;overflow-x:auto;color:var(--text)}
.api-sample.answer{color:var(--muted)}
.sample-heading{margin:14px 0 0;font-size:11px;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.scope-card code{font-size:15px}
.scope-permits{margin:0 0 12px;color:var(--text)}
/* A written guide: readable measure, and its screenshots sized to the column
   rather than to their own pixel width. */
.learn-manual-body{max-width:64rem}
.learn-manual-body h1{font-size:22px;margin:0 0 6px}
.learn-manual-body h2{font-size:16px;margin:26px 0 8px}
.learn-manual-body h3{font-size:13px;margin:22px 0 6px;color:var(--accent)}
.learn-manual-body p{margin:0 0 12px;max-width:62ch;line-height:1.6}
.guide-shot{display:block;width:100%;max-width:100%;margin:6px 0 20px;border:1px solid var(--line);border-radius:9px}
.walkthrough-player{width:100%;max-height:70vh;border-radius:10px;background:#000;display:block}
.walkthrough-script{margin-top:12px;font-size:12px}
.walkthrough-script summary{cursor:pointer;color:var(--accent);font-weight:700}
.walkthrough-script pre{white-space:pre-wrap;margin:10px 0 0;padding:12px;background:var(--panel2);border-radius:9px;color:var(--muted);font:inherit;max-height:280px;overflow:auto}
.guided-dialog{border:0;border-radius:18px;padding:0;width:min(920px,calc(100vw - 40px));max-height:calc(100vh - 40px);background:var(--panel);color:var(--text);box-shadow:0 28px 90px #0007}.guided-dialog::backdrop{background:#071124b8;backdrop-filter:blur(3px)}.guided-dialog form{display:flex;flex-direction:column;max-height:calc(100vh - 32px)}.guided-dialog header{display:flex;justify-content:space-between;align-items:flex-start;gap:20px;flex:0 0 auto;padding:22px 26px 18px;border-bottom:1px solid var(--line)}.guided-dialog h2{margin:4px 0 7px;font-size:20px}.guided-dialog header p{margin:0;color:var(--muted)}.dialog-close{border:0;background:transparent;color:var(--muted);font-size:28px}.dialog-body{padding:22px 26px;overflow:auto;flex:1 1 auto}.guided-dialog footer{display:flex;justify-content:flex-end;gap:10px;flex:0 0 auto;padding:16px 26px;border-top:1px solid var(--line);background:var(--panel2)}.form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:22px 24px}.form-field{display:flex;flex-direction:column;gap:7px}.form-field>span{font-weight:700}.form-field b{color:var(--bad)}.form-field input,.form-field select,.guided-dialog textarea{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:9px;background:var(--panel);color:var(--text);padding:10px 11px}.form-field input[aria-invalid="true"],.form-field select[aria-invalid="true"]{border-color:var(--bad)}.form-field small{color:var(--muted)}.form-field em{color:var(--bad);font-size:12px;font-style:normal}.form-field em:empty{display:none}.switch-row{display:flex;gap:22px;margin:24px 0;align-items:center}.wizard-steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.wizard-steps>*{padding:7px 10px;border-radius:8px;background:var(--panel2);color:var(--muted)}.wizard-steps b{background:var(--accent2);color:var(--accent)}.review-box,.impact-summary,.result-panel,.warning-panel{padding:14px 16px;border:1px solid var(--line);border-radius:10px;background:var(--panel2);margin-top:24px}.warning-panel:not(:empty){border-left:3px solid var(--warn)}.warning-panel.is-info:not(:empty){border-left:3px solid var(--accent)}.warning-panel:empty{display:none}.dialog-progress{flex:0 0 auto;color:var(--muted);font-size:13px;font-variant-numeric:tabular-nums}.dialog-progress:not(:empty){padding:10px 26px 0}.dialog-result{flex:0 0 auto}.dialog-result.error{padding:12px 16px;margin:0 26px 12px;background:color-mix(in srgb,var(--bad) 10%,var(--panel));border-left:3px solid var(--bad)}@media(max-width:700px){.form-grid{grid-template-columns:1fr}.guided-dialog{width:calc(100vw - 16px)}.dialog-body{padding:18px}}
.call-row{cursor:pointer}.call-row:hover td{background:var(--accent2)}.call-link{border:0;background:transparent;padding:0;color:var(--accent);font:12px ui-monospace,SFMono-Regular,monospace;text-decoration:underline}.call-summary{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 24px;margin-bottom:24px}.call-summary>div{display:grid;gap:4px;padding:10px 0;border-bottom:1px solid var(--line)}.call-summary small{color:var(--muted);font-size:10px;font-weight:800;letter-spacing:.06em}.call-ladder{border:1px solid var(--line);border-radius:12px;overflow:hidden}.call-ladder-head,.call-ladder-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(220px,1.4fr) minmax(120px,1fr);align-items:center;gap:12px;padding:11px 14px}.call-ladder-head{background:var(--panel2);text-align:center}.call-ladder-row{border-top:1px solid var(--line)}.call-ladder-row>span:first-child{text-align:right}.call-ladder-row>div{display:grid;grid-template-columns:1fr 28px auto;align-items:center;gap:6px;text-align:center}.call-ladder-row i{color:var(--accent);font-style:normal;font-size:18px}.call-ladder-row small{color:var(--muted)}
.sip-ladder-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(260px,1.4fr) minmax(120px,1fr);align-items:center;gap:12px;padding:11px 14px;border-top:1px solid var(--line)}.sip-ladder-row>span:first-child{text-align:right}.sip-ladder-row>div{display:grid;grid-template-columns:1fr 28px auto;align-items:center;gap:6px;text-align:center}.sip-ladder-row i{color:var(--accent);font-style:normal;font-size:18px}.sip-ladder-row small{color:var(--muted)}.wrap-value{overflow-wrap:anywhere;word-break:break-word}.guided-dialog .dialog-body{min-height:0}
.sip-message-button{border:0;background:transparent;color:var(--accent);font:inherit;font-weight:700;cursor:pointer;text-decoration:underline;text-underline-offset:3px}.sip-raw-message{margin:0;max-height:55vh;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;padding:16px;border:1px solid var(--line);border-radius:10px;background:var(--panel2);color:var(--text);font:13px/1.55 ui-monospace,SFMono-Regular,Consolas,monospace}.field-help{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-left:5px;border:1px solid var(--muted);border-radius:50%;color:var(--muted);font-size:12px;cursor:help}.device-prerequisites{margin:18px 0}.device-prerequisites li{margin:7px 0}
.app-shell{grid-template-columns:var(--sidebar) minmax(0,1fr);width:100%}
.brand{grid-template-columns:42px minmax(0,1fr) 26px}.brand span:nth-child(2){min-width:0}.brand small{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.grid-2{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr)}.service-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
.learning-help{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:24px;padding:12px 14px;border:1px solid var(--line);border-radius:12px;background:var(--panel)}.learning-help b{margin-right:auto}.learning-help button{border:1px solid var(--line);background:var(--panel2);color:var(--text);border-radius:8px;padding:7px 10px}.learning-card .hint{min-height:20px}.tour-highlight{border:2px solid var(--accent);border-radius:14px;padding:22px;box-shadow:0 0 0 6px color-mix(in srgb,var(--accent) 12%,transparent)}.success{padding:12px;color:var(--good);font-weight:700;background:color-mix(in srgb,var(--good) 10%,var(--panel));border-radius:8px}
/* Dialog width is chosen by the caller instead of by the widest form on the site:
   a two-field confirmation was rendering at the 920px five-step wizard width, with
   a header floored at 112px.

   THE COMPACT HEADER IS NOW THE BASE RULE, and lg is a genuine step. The first
   attempt at this defined lg as min(920px,100vw-40px) - byte-identical to the
   width it was meant to replace - and applied the reduced header to sm and md
   only. Every dialog the operator called oversized asks for lg: the connected
   system form and therefore Clone, the route form, and the change-review panel.
   So the work landed, passed review, and changed nothing on precisely the three
   dialogs it was requested for. A size variant that equals the default is not a
   variant, and a shared rule expressed as a per-size exception is not shared:
   the header, body padding and heading size are set once on .guided-dialog
   above, which also reaches the dialogs that pass no size at all. */
.guided-dialog[data-size="sm"]{width:min(440px,calc(100vw - 32px))}
.guided-dialog[data-size="md"]{width:min(660px,calc(100vw - 32px))}
.guided-dialog[data-size="lg"]{width:min(820px,calc(100vw - 32px))}
/* THE LADDER IS THE SUBJECT, SO IT GETS THE WIDTH. A signaling ladder is three
   columns of addresses with a timestamp between them, and at the default 920px
   every row wrapped and the sentences beneath it ran the full measure. This is
   the one dialog in the product whose content is a diagram rather than a form,
   and the v13 prototype makes the same call for the same reason. */
.guided-dialog[data-size="xl"]{width:min(1240px,calc(100vw - 32px))}
.guided-dialog[data-size="sm"] .form-grid{grid-template-columns:1fr;gap:16px}
/* The form's ceiling was 8px taller than the dialog's, so a long body scrolled the
   dialog itself and carried the footer buttons off screen instead of scrolling
   inside .dialog-body. Both ceilings must be the same number. */
.guided-dialog form{max-height:calc(100vh - 40px)}
.form-field.wide{grid-column:1/-1}
.guided-dialog textarea{font:inherit;resize:vertical}
.result-panel pre{margin:0;max-height:46vh;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere}
.result-panel[data-outcome] div{margin-top:5px;color:var(--muted)}

/* The one-operation plan. The steps table is the subject of the dialog it sits
   in, so it drops the global 720px table floor - a four-column step list must
   stay readable at the dialog's own width rather than forcing a scrollbar the
   operator has to find before they can read what they are about to apply. */
.plan-summary{margin:0 0 14px;font-size:15px}
.plan-steps table{min-width:0}
.plan-steps td:first-child,.plan-steps th:first-child{width:34px;color:var(--muted)}
.plan-steps small.cost-detail{color:var(--muted)}
.plan-errors p:last-child{margin-bottom:0}
.plan-acknowledge{display:grid;gap:10px}
.plan-acknowledge label{display:flex;gap:9px;align-items:flex-start;line-height:1.45}
.plan-acknowledge input{margin-top:3px}

/* Header search, Help control and footer. The shell pieces that replaced four
   navigation entries: Search Everything, Knowledge Base, Engineering Notebook
   and About. */
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.header-search{display:flex;align-items:center;gap:6px;flex:1 1 auto;min-width:0;max-width:640px;margin-left:18px}
.header-search input{flex:1 1 auto;min-width:0;border:1px solid var(--line);border-radius:9px;padding:8px 12px;background:var(--panel2);color:var(--text);font-size:13px}
.header-search button{border:0;border-radius:9px;padding:8px 12px;background:var(--accent);color:#fff;font-size:14px;line-height:1}
@media(max-width:960px){.header-search{display:none}}
.app-footer{display:flex;flex-wrap:wrap;align-items:center;gap:14px;padding:16px 28px 26px;max-width:1600px;margin:auto;color:var(--muted);font-size:12px;border-top:1px solid var(--line)}
.app-footer button.link{border:0;background:none;color:var(--accent);font:inherit;padding:0;text-decoration:underline;cursor:pointer}
.about-panel{flex-basis:100%;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;margin-top:6px}
/* The recorded planning ranges that used to be a page of their own. Closed by
   default: they decide nothing, and leading with them is what made the one list
   that does decide something invisible. */
details.card.footnote{padding:14px 20px}
details.card.footnote summary{cursor:pointer;color:var(--muted);font-size:13px}
details.card.footnote[open] summary{margin-bottom:12px}

/* The Help window. Its own document, its own contents rail. */
.help-window{overflow:hidden}
.help-shell{display:grid;grid-template-columns:250px minmax(0,1fr);min-height:100vh}
.help-rail{background:var(--panel);border-right:1px solid var(--line);padding:18px 14px;display:flex;flex-direction:column;gap:14px}
.help-rail nav{display:flex;flex-direction:column;gap:2px}
.help-rail nav a{display:block;padding:9px 12px;border-radius:9px;color:var(--muted);text-decoration:none;font-size:13px;font-weight:600}
.help-rail nav a:hover{background:var(--panel2);color:var(--text)}
.help-rail nav a.active{background:color-mix(in srgb,var(--accent) 13%,transparent);color:var(--accent)}
.help-rail .help-foot{margin-top:auto;color:var(--muted);font-size:11px;line-height:1.5}
.help-window #helpContent{padding:28px;max-width:920px;margin:0;overflow-y:auto;height:calc(100vh - 60px)}
.help-window h1{font-size:28px;letter-spacing:-.03em;margin:0 0 6px}
.help-lede{color:var(--muted);margin:0 0 22px}
.help-section{font-size:13px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);margin:26px 0 12px}
.help-article h2{font-size:18px;margin:0 0 12px}
.help-article h3{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin:16px 0 6px}
.help-article p,.help-article li{line-height:1.6}
.help-article ol,.help-article ul{margin:0;padding-left:20px}
.help-caveat{color:var(--warn);font-size:12px}
@media(max-width:820px){.help-shell{grid-template-columns:1fr}.help-rail{border-right:0;border-bottom:1px solid var(--line)}.help-rail nav{flex-direction:row;flex-wrap:wrap}.help-window #helpContent{height:auto}}
/* Topology canvas. Scales with its container rather than a fixed pixel size,
   so the same drawing is legible on a laptop and on the wall display the
   operator actually reviews an estate on. */
.topo{display:flex;flex-direction:column;gap:14px}
/* The drawing keeps its own size and the frame scrolls. Scaling the whole
   viewBox into the card made a large estate render at four-pixel type, so the
   page silently traded away the one thing it exists to show. */
.topo-scroll{overflow:auto;max-height:62vh;border:1px solid var(--line);border-radius:10px;background:var(--panel)}
.topo-canvas{display:block;max-width:none}
.topo-node rect{fill:var(--panel2);stroke:var(--line);stroke-width:1.5}
.topo-node.route rect{fill:var(--accent2);stroke:var(--accent)}
/* Four kinds of object are drawn and three of them were introduced when the
   model learned to emit recordings and destination groups. Drawing them as one
   another's shape is the picture stating something untrue about the estate. */
.topo-node.recording rect{fill:var(--panel2);stroke:var(--line);stroke-dasharray:4 3}
.topo-node.delivery-group rect{fill:var(--panel2);stroke:var(--accent);stroke-dasharray:6 3}
/* Switched off, and unreachable. Both arrive on the node and neither was ever
   drawn, so a disabled route was the same rectangle as a live one. */
.topo-node.off rect{opacity:.45;stroke-dasharray:3 3}
.topo-node.off .topo-name,.topo-node.off .topo-sub{opacity:.55}
.topo-node.unreachable rect{stroke:var(--warn)}
.topo-node .topo-name{fill:var(--text);font:600 12px/1 inherit}
.topo-node .topo-sub{fill:var(--muted);font:400 10px/1 inherit}
.toolbar-label{align-self:center;color:var(--muted);font-size:12px;font-weight:700}
.topo-legend{display:flex;flex-wrap:wrap;gap:12px;color:var(--muted);font-size:12px}
.topo-key{display:inline-flex;align-items:center;gap:6px}
.topo-key i{width:16px;height:11px;border-radius:3px;border:1.5px solid var(--line);background:var(--panel2)}
.topo-key.route i{background:var(--accent2);border-color:var(--accent)}
.topo-key.recording i{border-style:dashed}
.topo-key.delivery-group i{border-color:var(--accent);border-style:dashed}
.topo-key.off i{opacity:.45;border-style:dashed}
.topo-node{cursor:pointer}
.topo-node:focus{outline:none}
.topo-node:focus rect,.topo-node:hover rect{stroke:var(--accent);stroke-width:2}
.topo-node.selected rect{stroke:var(--accent);stroke-width:2.5}
.topo-edge{fill:none;stroke:var(--muted);stroke-width:1.6}
.topo-wires marker path,#topoArrow path{fill:var(--muted)}
.topo-edge.lit{stroke:var(--accent);stroke-width:2.4}
.topo-edge.dim{opacity:.18}
/* Delivery through a group is a different relationship from delivery to a
   system, and reading it off the tooltip alone means tracing every curve. */
.topo-edge.kind-member{stroke-dasharray:5 4}
.topo-edge.kind-plays{stroke-dasharray:2 4}
.topo-orphans{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-top:4px}
.topo-orphans b{color:var(--warn)}
.topo-orphan{padding:5px 9px;border:1px dashed var(--warn);border-radius:8px;color:var(--text);cursor:pointer;font-size:12px}
.topo-orphan.selected{border-style:solid;border-color:var(--accent)}
.topo-detail{margin:0;color:var(--muted);min-height:20px}
/* Rendered report bodies. The reports are stored as markdown and were printed
   as source into a single paragraph; these are the styles for the rendered
   document that replaced that. */
.card-actions{display:flex;align-items:center;gap:10px}
.report-body h2,.report-body h3,.report-body h4{margin:20px 0 8px}
.report-body h2{font-size:17px}
.report-body h3{font-size:15px}
.report-body h4{font-size:13px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
.report-body p{margin:0 0 10px}
.report-body ul{margin:0 0 12px;padding-left:20px}
.report-body li{margin:3px 0}
.report-body .table-wrap{margin:0 0 14px}
.report-body table{min-width:0}
.report-body>*:first-child{margin-top:0}
/* Activity rows carry two facts in the resource column: which record changed,
   and what kind of record it is. The kind is secondary - it was the ONLY thing
   the column used to show. */
.audit-kind{display:block;color:var(--muted);font-size:11px}
/* Help control in the header. It is an anchor rather than a button so that a
   blocked popup, a middle click and a modified click all still reach the help
   window; help-launch.js upgrades a plain left click into a sized popup. The
   header rule beside it only styles `button`, so the anchor is matched here. */
.header-help{display:inline-grid;place-items:center;width:32px;height:32px;border-radius:8px;background:var(--panel2);color:var(--text);text-decoration:none;font-weight:800}
.header-help:hover{background:var(--accent2);color:var(--accent)}
/* The surface switch. Three product surfaces in the top bar, per the v4
   experience: which surfaces exist is server truth, so scripts only toggle
   .active, [hidden] and [disabled] on these buttons - the markup itself is
   static so the switch exists on the first paint of a cold load. The Tenant
   Workspace control starts hidden AND disabled: rendering it is a claim about
   the session's authority, and the honest default before /auth/me answers is
   no claim. Idle buttons use --panel2, the selected surface uses the same
   --accent2/--accent pair every other active state in the product uses. */
/* Every declaration the bare `nav` element rule above sets is RESTATED here,
   because that rule styles the sidebar by element name and therefore matches
   this nav too on both pages: without an explicit row direction the sidebar's
   `flex-direction:column` won, the three buttons stacked, and the 68px bar
   centred a 106px stack - the top surface rendered above the viewport and the
   switch read as broken on every screen. flex-shrink:0 stops the space-between
   bar squeezing the switch to min-content, which is what wrapped it. */
.surface-switch{display:flex;flex-direction:row;flex-wrap:nowrap;gap:6px;align-items:center;flex-shrink:0;overflow:visible}
.surface-switch button{display:inline-block;width:auto;border:0;background:var(--panel2);color:var(--muted);border-radius:8px;padding:7px 12px;font-size:12px;font-weight:700;white-space:nowrap}
.surface-switch button:hover{background:var(--accent2);color:var(--accent)}
.surface-switch button.active{background:var(--accent2);color:var(--accent)}
.surface-switch button[disabled]{opacity:.5;cursor:not-allowed}
@media(max-width:1180px){.surface-switch button{padding:7px 9px;font-size:11px}}
/* The signed-in identity, in the header where the v4 experience puts it. In
   single_tenant mode there is no session and the chip stays hidden - the
   sidebar operator line carries the fallback identity there. */
.user-chip{display:flex;flex-direction:column;align-items:flex-end;line-height:1.25;border:1px solid var(--line);border-radius:9px;padding:5px 10px;max-width:230px}
.user-chip b{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.user-chip small{color:var(--muted);font-size:10px}
@media(max-width:1320px){.user-chip{display:none}}
/* THE SIDEBAR IDENTITY LINE, AND WHY IT PAINTED OVER THE MAIN COLUMN.
   Owner report, punch list item 1: "the user email address in the bottom left
   is overlapping into the main view".

   MEASURED CAUSE, AND IT IS NOT A WIDTH. `.operator` is a grid (`34px 1fr`)
   inside a 254px rail, so the text track's SHARE is about 169px - but a grid
   item's automatic minimum size is its MIN-CONTENT size, and an email address
   is one unbreakable word, so its min-content width is the whole string. The
   track is forced past its share, `.operator` overflows the rail, and `aside`
   carries `z-index:9` and clips nothing - so the overflow is painted ON TOP of
   the content column. Measured in a browser 2026-08-18 with a 54-character
   name: this line rendered 434px wide inside a 254px rail, unclipped. Nudging
   `--sidebar` or a `max-width` cannot fix that, because the automatic minimum
   is computed from the string and not from the space available.

   `overflow:hidden` IS WHAT DOES THE WORK, AND THAT IS MEASURED RATHER THAN
   REASONED. A grid item whose computed `overflow` is not `visible` has an
   automatic minimum size of ZERO - which is both what lets the track take its
   share and what lets `text-overflow` fire, so the two are one fix and not
   two. `min-width:0` was written here first and REMOVED after a control run:
   with it gone and these three declarations kept, the browser journey passes.
   Shipping it would have been a declaration doing nothing under a comment
   calling it the cause.

   THE TWO SHELLS WERE NOT IN THE SAME STATE, WHICH IS WHY ONLY ONE OVERFLOWED.
   `tenant.css` already gave `.workspace .operator b` `overflow:hidden`, so
   `/app` was clipping all along; `styles.css` gave `.operator b` nothing at
   all, so `/admin` - the Engineering Studio, which is where the report came
   from - overflowed outright. Measured: with this rule removed the journey
   fails on `/admin` and PASSES on `/app`. It lives here rather than beside the
   workspace's copy because `styles.css` owns `.operator` itself, per
   `tenant.css`'s own split, so one declaration answers for both shells instead
   of two that can drift.

   A NAME RATHER THAN AN ADDRESS DOES NOT FIX THIS AND MUST NOT BE READ AS
   FIXING IT. A long full name is just as unbreakable as an email address; it
   is shorter on average, which would have hidden the defect for most people
   rather than removing it. */
.operator b,.operator small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Anchors that stand in the button rows of the learning surface. The button
   classes are class-selectors and apply, but an anchor keeps its underline and
   inline flow unless told otherwise. */
a.small{text-decoration:none;display:inline-block}
/* The re-read control on a change report. It sits below the report body
   rather than in the dialog footer, because the footer's one button closes
   the dialog and a second button there would read as a second way out. */
.report-recheck{margin:14px 0 0}
/* ONE CARD PER CONNECTED SYSTEM. Every track is minmax(0,1fr) so a long CIDR or
   destination cannot widen the page - the overflow sweep counts an element with
   no scrolling ancestor, and a card is one. */
.system-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(460px,1fr));gap:16px;margin-bottom:16px}
.system-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px;display:flex;flex-direction:column;gap:14px;min-width:0}
.system-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-wrap:wrap}
.system-card-head h3{margin:0;font-size:16px;overflow-wrap:anywhere}
.system-card>.system-card-head{display:grid;grid-template-columns:54px minmax(0,1fr);gap:11px 13px;align-items:start}
.system-card>.system-card-head>.system-card-flags{grid-column:2}
.system-card>.system-card-head>.system-card-controls{grid-column:1/-1}
.system-tile{width:54px;height:54px;border-radius:13px;display:grid;place-items:center;font-size:17px;font-weight:800;background:color-mix(in srgb,var(--accent) 12%,transparent);color:var(--accent);border:1px solid color-mix(in srgb,var(--accent) 22%,transparent)}
.system-card-identity{min-width:0;display:flex;flex-direction:column;gap:3px}
.system-card-title{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.system-card-sub{margin:0;font-size:12px;line-height:1.45;color:var(--muted);overflow-wrap:anywhere}
.system-card-flags{display:flex;gap:6px;flex-wrap:wrap}
.system-card-facts{display:grid;gap:0;margin:0}
.system-card-facts>div{display:grid;grid-template-columns:minmax(0,140px) minmax(0,1fr);gap:10px;align-items:baseline;padding:7px 0;border-top:1px solid var(--line)}
/* THE FIELD CELL, v12's shape for a labelled fact. The prototype draws each
   fact as its own tinted tile rather than as a row in a ruled list: label
   above value, 9px radius, 9px padding, a hairline border and a #f7f9fc
   ground. It is ONE class because all three Connected Systems tabs use it -
   a system card, an admission policy and a network record are the same
   affordance answering different questions, which is the reason the cards
   already share their other rules.
   Opt-in: a container adds `.facts-tiled` and its rows become tiles. The
   ruled-list form above is untouched, so nothing that has not asked for the
   new shape moves. */
.system-card-facts.facts-tiled{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
.system-card-facts.facts-tiled>div{display:block;background:#f7f9fc;border:1px solid var(--line);border-top:1px solid var(--line);border-radius:9px;padding:9px}
.system-card-facts.facts-tiled>dt,.system-card-facts.facts-tiled>div>dt{font-size:10px;font-weight:800;letter-spacing:.04em;color:var(--muted);margin:0 0 3px}
.system-card-facts.facts-tiled>div>dd{margin:0;font-weight:600}
.system-card-facts>div:first-child{border-top:0}
.system-card-facts dt{color:var(--muted);font-size:10px;font-weight:800;letter-spacing:.06em}
.system-card-facts dd{margin:0;min-width:0;font-size:13px;overflow-wrap:anywhere;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.system-card-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:auto;padding-top:4px}
/* The head carries Open, Duplicate and the enable/disable control; it wraps
   rather than shrinking, because a card is as narrow as 340px. */
.system-card-controls{display:flex;flex-wrap:wrap;gap:6px}
/* A control that reads as a link inside a fact cell. It is a BUTTON - it
   opens a dialog rather than navigating - so it is styled down rather than
   rendered as an anchor, which would promise an address it does not have. */
.link-button{background:none;border:0;padding:0;font:inherit;font-size:12px;color:var(--accent);cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.link-button:hover{opacity:.8}
/* The ladder legend. The muted key is the step drawn for a check the far end
   never answered, which carries no time and no arrow. */
.ladder-legend{display:flex;flex-wrap:wrap;gap:16px;margin:10px 0 0;color:var(--muted);font-size:12px}
.ladder-key{color:var(--accent);font-style:normal}
.ladder-key.muted{color:var(--muted)}
.system-card-actions .small{margin-right:0}
/* ROW ACTIONS LINE UP, AND THEY WRAP AS A GROUP. Owner report, 2026-08-20:
   Open / Edit / Remove sat ragged in the Numbers table because `.small`
   carries `margin-right:5px` and the buttons were emitted straight into the
   cell, so they wrapped as loose inline boxes with the trailing margin still
   applied - the last button on a line pushed the row's width out and the
   wrapped one hung left of the others. A flex row with a real gap aligns them
   and removes the trailing margin; `align-items:start` keeps a wrapped button
   flush with the one above rather than stretched to the cell height. */
/* ONE ROW (owner, 2026-08-27: "the buttons on the main table are not on
   one row"). `flex-wrap:wrap` let a three-control cell fold onto a second
   line and doubled the height of every row in the table. The controls stay
   on their row and the cell refuses to be the column that wraps; a table too
   wide for its container already scrolls inside `.table-wrap`. */
.row-actions{display:flex;flex-wrap:nowrap;align-items:center;gap:6px;white-space:nowrap}
.row-actions .small{margin-right:0}

.row-actions .small{margin-right:0}
/* THE COLUMN-RESIZE HANDLE lives inside the header cell, pinned to its right
   edge, so it travels with the cell when the table scrolls sideways inside
   `.table-wrap`. A handle positioned between cells needs absolute coordinates
   and drifts the moment the wrap scrolls. `th` gets `position:relative` for
   that anchoring only. It is decorative and `aria-hidden`: resizing is a
   viewing convenience with no keyboard equivalent to promise. */
th{position:relative}
.col-resize{position:absolute;top:0;right:0;width:9px;height:100%;cursor:col-resize;touch-action:none;user-select:none}
.col-resize:hover,.col-resize:active{background:linear-gradient(to right,transparent,color-mix(in srgb,var(--accent) 45%,transparent))}
/* The local-system toggle sits in the toolbar beside the search and the facet. */
.toolbar-toggle{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:12px}
/* THE CONFIGURATION CHECK'S RESULT, GROUPED. Three sections, each item carrying
   its own state pill, so the reader finds what did not pass without reading
   every line of what did. */
.check-headline{margin:0 0 16px;font-size:15px}
.check-group{margin:0 0 18px}
.check-group h3{margin:0 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.check-list{list-style:none;margin:0;padding:0;display:grid;gap:8px}
.check-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;align-items:start;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--panel2)}
.check-item>div{display:grid;gap:3px;min-width:0}
.check-item b{font-size:13px}
.check-item span{color:var(--muted);font-size:12px;line-height:1.5;overflow-wrap:anywhere}
/* A HIDDEN FIELD MUST ACTUALLY HIDE. `[hidden]` is a UA rule and loses to the
   class selectors that give these containers their display, which is the trap
   the sidebar's `hidden` fell into once already: the attribute was set, the
   element stayed on screen, and nothing looked broken. The route dialog has
   been setting `hidden` on a `.form-field` since it was written. */
.form-grid[hidden],.form-field[hidden],p[hidden],[data-engine-notes][hidden]{display:none}
/* THE ENGINE NOTES GET THEIR OWN FULL-WIDTH ROW, AND A CEILING.
   They are inserted as a sibling of the engine field, so they land in the NEXT
   GRID CELL and share its row - and a note long enough (Kokoro once carried
   three absent-language paragraphs) made that row about 750px tall, which tore
   the dialog apart: the owner reported the view "messed up", with the panel
   seam visible and the submit button clipped. Spanning the full width puts the
   notes on their own row where their height cannot stretch a row containing a
   control, and the max-height means no future note can do this again however
   long it gets. It is ALSO in the hidden rule above because this container is a
   `div` - `p[hidden]` stopped matching it the moment it gained paragraph
   children, and an engine with nothing to declare would have rendered an empty
   box, which reads as something that failed to load. */
/* THE ENGINE NOTES ARE READ, SO THEY ARE SET TO BE READ. They were --muted at
   12px on --panel2, which is the treatment this sheet gives to incidental help
   text, and the owner reported the result as hidden. They are not incidental:
   they are what an engine can and cannot say, which is the one thing that
   decides whether the voice chosen above them is usable at all.
   THE RAIL IS THE ACCENT AND DELIBERATELY NOT --warn. `.notice` is the warning
   tone, and painting "speaks six languages" in it would repeat the confusion
   this repository already paid for when the neutral reachability state shared
   a colour with the failing one. Accent reads as "look here", not "something
   is wrong". */
[data-engine-notes]{grid-column:1/-1;max-height:190px;overflow-y:auto;color:var(--text);font-size:13px;line-height:1.5;background:color-mix(in srgb,var(--accent) 7%,var(--panel));border-left:3px solid var(--accent);border-radius:0 10px 10px 0;padding:12px 14px}
/* THE SPECIFICITY IS DELIBERATE. `.form-field small` already claims --muted at
   (0,1,1); a bare `.message-count` at (0,1,0) loses to it and the over-limit
   colour would silently never apply - a cascade collision that looks correct
   in the source and does nothing on screen. */
.form-field small.message-count{display:block;margin-top:2px;color:var(--muted);font-variant-numeric:tabular-nums}
.form-field small.message-count.over{color:var(--bad);font-weight:700}
[data-engine-notes] p{margin:0 0 8px}
[data-engine-notes] p:last-child{margin-bottom:0}
/* THE CONNECTED-SYSTEM DIALOG'S TWO BLOCKS, and both are named in the rule
   above for the reason that rule exists: each gets its display from a class,
   so `[hidden]` alone would set the attribute and leave the block on screen.
   The credential panel in particular is shown for ONE peering mode, and a
   panel that stays visible for the other is a form offering a secret for a
   system that can hold none. */
.boxed-check[hidden],.credential-panel[hidden]{display:none}
/* A CHECKBOX THAT CHANGES WHETHER CALLS ARE ROUTED IS NOT A ROW OF THE FORM
   GRID. It is drawn as its own bordered block with the consequence under it,
   because the switch and the sentence that says what it costs have to be read
   together - the keepalive control was once reported MISSING from this dialog
   when it was merely the seventh field down. */
.boxed-check{display:grid;grid-template-columns:auto minmax(0,1fr);gap:4px 12px;align-items:start;padding:14px 16px;border:1px solid var(--line);border-radius:10px;background:var(--panel2);margin-top:24px}
.boxed-check input{margin:2px 0 0;grid-row:1}
.boxed-check b{grid-column:2;font-size:13px}
.boxed-check small{grid-column:2;color:var(--muted);font-size:12px;line-height:1.5}
/* THE GENERATED CREDENTIAL, MARKED AS THE ONE THING ON THIS FORM THAT CANNOT
   BE READ BACK. The accent border is the only visual weight on the dialog and
   it is spent here deliberately: everything else can be reopened and checked,
   and this cannot - see `registration.SECRET_SHOWN_ONCE`. */
.credential-panel{margin-top:24px;padding:16px 18px;border:1px solid color-mix(in srgb,var(--accent) 40%,var(--line));border-left-width:3px;border-radius:10px;background:color-mix(in srgb,var(--accent) 6%,var(--panel2))}
.credential-panel>h3{margin:0 0 6px;font-size:13px}
.credential-panel>p{margin:0 0 14px}
.credential-panel .form-grid{gap:16px 18px}
/* The generator sits beside its box rather than under it, so the value and the
   control that replaces it are one row. */
.credential-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:end}
.credential-row .form-field{margin:0}
.credential-value{font:12px ui-monospace,SFMono-Regular,monospace}
/* THREE QUESTIONS, THREE TABS, ONE VIEW ID. The tabs are ANCHORS on purpose -
   see `PEER_TABS` in app.js. A button with no action name is treated as a
   write by the control sweep and would be DISABLED for exactly the read-only
   roles these two new tabs exist to serve, so the tab strip carries no control
   at all: it is navigation, and the browser's own Back moves through it. The
   declarations mirror `.flow-tabs`, which is the same affordance one surface
   over; they are spelled separately because that stylesheet ships only with
   the designer and a page tab must not depend on the designer being loaded. */
.page-tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin:0 0 18px}
.page-tab{padding:10px 12px;color:var(--muted);text-decoration:none;border-bottom:3px solid transparent;font-size:12px;font-weight:700}
.page-tab:hover{color:var(--text)}
.page-tab.active{color:var(--accent);border-bottom-color:var(--accent)}
/* Network Inventory reuses the connected-system card's internals - the same
   `<dl>` of facts, the same head, the same action row - because it is the same
   affordance answering a different question, and a second set of declarations
   would drift into a second look. Only the grid is its own: a record carries
   more facts than a system does, so its cards are wider. */
.inventory-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(400px,1fr));gap:16px;margin-bottom:16px}
/* A SIP Admission Policy card is the SAME card, and it shares the rule rather
   than copying it: the two tabs sit one click apart over one view id, and two
   card styles for two lists of ranges would read as two kinds of record. */
.policy-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px;display:flex;flex-direction:column;gap:14px;min-width:0}
.policy-card .system-card-facts>div{grid-template-columns:minmax(0,170px) minmax(0,1fr)}
.policy-card .system-card-head h3 code{font-size:0.95em}
/* THE FACT DISCLOSURE. The compact value is the summary and the server's
   sentence sits behind it, AT the box - the register's requirement - rather
   than open on every card, which was five identical paragraphs per card. The
   marker is the affordance; it is a read, so every role keeps it. */
.fact-note summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:5px}
.fact-note summary::after{content:"\25B8";font-size:9px;color:var(--muted);transition:transform .15s}
.fact-note[open] summary::after{transform:rotate(90deg)}
.fact-note>.recording-help{margin-top:5px}
/* AN ABSENCE IS DRAWN AS AN ABSENCE. Nobody having recorded a VLAN is not a
   fault, so it must not borrow the warning tone - the same rule the
   reachability indicator's neutral state is held to, and the same reason. */
/* A site sits under the customer above it. The indent is the only thing
   carrying that relationship in a flat table, so it is a real rule rather
   than a non-breaking space in the markup. */
.site-child{padding-left:18px;border-left:2px solid var(--line)}
.muted-fact{color:var(--muted)}
.system-card-facts ul.recording-help{margin:0;padding-left:16px}
.system-card-facts ul.recording-help li{margin-bottom:6px}

/* DIALOG RHYTHM. Three rules that were each reasonable alone and together made
   every guided dialog sprawl.

   `.form-field em` reserved 16px under EVERY field so an error could appear
   without moving the layout - which cost 23px of dead space (the reservation
   plus the field's own 7px gap) beneath all of them, on every dialog, forever,
   to avoid a 16px shift on the one field that is actually wrong. It collapses
   when empty now; the shift is the cheaper of the two.

   And the header is PINNED (`flex:0 0 auto` above). It carried `min-height:0`,
   which was a workaround for the bare `header{height:60px}` type selector that
   used to reach into dialogs - that selector is scoped to `.app-shell>main>header`
   now, so the workaround outlived its cause and became the defect: a flex item
   with min-height:0 and the default flex-shrink:1 is squashed whenever the form
   exceeds its ceiling. Measured 2026-08-19 on Add connected system - header box
   87px against a scrollHeight of 123px, so its explanation paragraph ran 36px
   past the header's own bottom border and painted over the first row of fields. */

/* POLICIES. Six families in a card grid, each with its own live count, so the
   page answers "what reusable behaviour does this organisation hold" before an
   engineer opens any one library. The count is aligned to the far edge of the
   head row rather than following the title, because the six titles differ in
   length and a reader comparing counts down a column cannot do it if the
   numbers move with the words. */
.policy-family-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:16px}
.policy-family-card{display:flex;flex-direction:column;gap:12px}
.policy-family-head{display:flex;align-items:baseline;justify-content:space-between;gap:14px}
.policy-family-head h2{margin:0;font-size:17px}
.policy-family-head b{font-size:26px;font-weight:800;font-variant-numeric:tabular-nums;letter-spacing:-.03em}
.policy-family-sub{margin:0;color:var(--muted);font-size:13px;line-height:1.5;flex:1 1 auto}
.policy-family-card .card-actions{margin-top:auto}

/* READ-ONLY RECORD VIEWS. A detail popup is a set of labelled facts and then
   the records joined to it, so the facts sit in a two-column grid that keeps
   label and value on one line at dialog width, and the joins are ordinary
   tables and lists underneath. `.definition` is the same row shape the system
   detail page uses, so a reader meeting the same fact on both surfaces meets
   it in the same form. */
.detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:2px 24px}
/* The shared `.definition` row reserves 180px for its label, which is right on
   a full-width page card and leaves about 110px for the value inside a
   two-column grid in a 660px dialog - so every address wrapped over three
   lines. The label is narrower here and nowhere else. */
.detail-grid .definition{grid-template-columns:minmax(88px,116px) 1fr;gap:10px;align-items:baseline}
.guided-dialog .dialog-body h3{margin:22px 0 10px;font-size:14px;letter-spacing:.02em}
.guided-dialog .dialog-body h3:first-child{margin-top:0}
.guided-dialog .dialog-body>p{margin:0 0 12px}
.plain-list{margin:0;padding-left:18px;display:grid;gap:5px}
.guided-dialog .dialog-body .empty{color:var(--muted);margin:0 0 12px}

/* A SECONDARY LINE IN A TABLE CELL IS A LINE. Several cells render
   `<b>primary</b><small>secondary</small>` - the Dial Plan's KIND cell, the
   recordings NAME cell, the connected-system cells - and <small> is inline, so
   the two ran together as one word ("Delivery routeBridgePeer"). It reads as a
   rendering fault rather than as two facts, and it got worse as columns were
   added and cells narrowed. */
td>small,td>b+small{display:block;color:var(--muted);font-size:12px;line-height:1.4;margin-top:2px}

/* THE PAGER. A row under a table: what is shown on the left, the controls on
   the right, wrapping to two lines rather than overflowing when a table has
   many pages. `tabular-nums` because "Showing 9-16 of 17" must not jitter as
   the reader steps through it. */
.check-panel{display:flex;flex-wrap:wrap;align-items:flex-end;gap:14px 16px;margin-top:16px}.check-panel .form-field{flex:1 1 210px;min-width:0}.check-panel button{flex:0 0 auto}
.pager{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 16px;margin-top:14px;color:var(--muted);font-size:13px;font-variant-numeric:tabular-nums}
.pager-controls{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.pager-controls button[disabled]{opacity:.45}.table-controls{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:12px}.table-search{flex:1 1 220px;min-width:180px}.table-page-size{flex:0 0 auto}.table-controls .result-count{margin:0;margin-left:auto}.result-count{margin:0 0 10px;color:var(--muted);font-size:11px}.pager-gap{padding:0 4px;color:var(--muted)}
/* THE ADMISSION BANNER. The deny-by-default posture leads the SIP Admission
   Policies tab (owner, 2026-08-23) - a good-toned lead, because refusal of the
   unknown is the protection working, distinct from the warn-toned .notice that
   marks something needing attention. */
.enforced-banner{padding:13px 16px;border-left:3px solid var(--good);background:color-mix(in srgb,var(--good) 7%,var(--panel));border-radius:8px;margin-bottom:14px;line-height:1.55}
.policy-card .system-card-sub code{font-size:12px}
/* THE POLICY DIALOG'S METHOD CHECKBOXES. A class, not inline style: the
   workspace CSP forbids style attributes, and the first render of these as
   inline styles logged eleven blocked-style console errors in one journey. */
.method-choices{display:flex;gap:14px;flex-wrap:wrap;margin:8px 0}
.method-choices label{display:inline-flex;gap:6px;align-items:center;font-weight:600}

/* THE EMPTY STATE'S CANDIDATE RANGES: one wrapped row of chips, each a
   control that opens the Add dialog prefilled - visible where the fold that
   replaced the 2026-08-23 bullet list read as an empty section. */
.candidate-ranges{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin:10px 0 0}

/* THE HEAD CONTROLS DO NOT WRAP MID-LABEL (owner, 2026-08-24: "Refresh
   data" broke onto two lines on every page with a wide lede). */
.refresh,.card-actions button,.card-actions a{white-space:nowrap}

/* A FACET SELECT DRESSES LIKE THE SEARCH BESIDE IT (owner, 2026-08-24: the
   native selects did not match the page). Same border, radius, background
   and padding as .toolbar's inputs, sized to content rather than stretched. */
.toolbar select{border:1px solid var(--line);border-radius:9px;padding:9px 12px;background:var(--panel);color:var(--text);font:inherit}

/* THE DESTINATION GROUP'S ORDER, AS A LIST OF NAMES. One system per line,
   first to last, with its own move and remove controls. */
.member-order{list-style:none;margin:0;padding:0;border:1px solid var(--line);border-radius:9px;background:var(--panel)}
.member-order li{display:flex;align-items:center;gap:10px;padding:9px 13px;border-top:1px solid var(--line)}
.member-order li:first-child{border-top:0}
.member-order .order-index{font-weight:700;color:var(--muted);min-width:18px;font-variant-numeric:tabular-nums}
.member-order .row-actions{margin-left:auto;display:flex;gap:6px}
.member-order .empty-line{color:var(--muted)}
.member-order .member-tools{margin-left:auto;display:flex;gap:6px}
.member-order .codec-include{display:flex;align-items:center;gap:8px;font-weight:500;flex:1;min-width:0;white-space:nowrap}
.member-order .codec-planned{color:var(--muted)}
.member-order .codec-planned small{color:inherit}
/* One normalization rule or header entry in the policy dialog: its fields on
   one row, the remove control at the end, the group boxed like the member
   order above so a list reads as a list. */
.policy-rule{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr)) auto;gap:10px;align-items:end;padding:9px 13px;border-top:1px solid var(--line)}
.policy-rule:first-child{border-top:0}
[data-policy-rules],[data-policy-headers]{border:1px solid var(--line);border-radius:9px;background:var(--panel);margin-bottom:8px}
.policy-rule .form-field{margin:0}
.policy-rule [data-remove-row]{margin-bottom:6px}
.codec-presets{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:6px 0}
.codec-presets small{color:var(--muted)}

/* Dial Plan row actions: one fixed-width strip, never a ragged pile (owner,
   2026-08-26). Equal minimum widths keep Open / Enable / Disable / Delete
   aligned column-to-column across rows; nowrap keeps the strip on one line -
   the table's own horizontal scroll absorbs narrow viewports. */
.route-actions{flex-wrap:nowrap;white-space:nowrap;gap:5px}
.route-actions .small{min-width:56px;padding:5px 9px;text-align:center}

/* The maintenance window's banner, on every plane (owner decision C45). Amber,
   not red: the platform is healthy and deliberately quiet, and painting it as
   failure would teach operators to ignore the color that means failure. */
.maintenance-banner{background:color-mix(in srgb,var(--warn) 14%,var(--panel));border:1px solid var(--warn);border-radius:10px;padding:10px 14px;margin:0 0 14px;font-size:13.5px}
.maintenance-banner b{margin-right:6px}
/* A secondary fact inside a table cell - the days remaining beside a date,
   the reason a row has no call. Muted so the cell still reads as its
   primary value first. */
.muted-note{color:var(--muted);font-size:11px}
