/* ============================================================================
   Network visuals (ADR-0026) - the board's 24-hour strips, the building tiles,
   the floor diagrams, the line page and the vendor scorecard.

   Every colour here is one of app.css's tokens, or a mix of one with the
   surface, so a palette change restyles the charts with no edit to this file.
   States are the status tokens and nothing else: up --ok (softened, so trouble
   is what catches the eye), slow --warn, down --crit. Missing data - no check,
   or a reading too old to trust - is hatched in the hairline colour: it is not
   up and it is not down. One series colour, the cobalt --acid, for latency.
   Colour is never the only cue: up is drawn lower than trouble on every strip
   and bar, so a reader who cannot tell the greens from the reds still sees
   where the line stood up.

   Drawn in the design system's own terms (ADR-0029): labels, legends and names in
   the interface face and sentence case, figures, addresses and times in mono;
   cards, tiles and toggles are the app's cards, tiles and segmented tabs.
   ========================================================================== */
:root{
  --vz-up:color-mix(in srgb,var(--ok) 58%,var(--bg-base));
  --vz-hatch:repeating-linear-gradient(135deg,var(--line-strong) 0 1px,transparent 1px 4px);
  --vz-wash:color-mix(in srgb,var(--acid) 14%,transparent);
  --vz-band:color-mix(in srgb,var(--acid) 28%,transparent);
  --vz-inc:color-mix(in srgb,var(--crit) 13%,transparent);
  --vz-inc-edge:color-mix(in srgb,var(--crit) 55%,transparent);
  --vz-warn-text:color-mix(in srgb,var(--warn) 70%,var(--text-hi));
  --vz-up-inset:38%;   /* how much lower than trouble an up stretch is drawn */
}
/* dark: a deeper up, so it and --crit sit further apart in lightness as well as hue */
@media (prefers-color-scheme:dark){:root{--vz-up:color-mix(in srgb,var(--ok) 45%,var(--bg-base));}}
:root[data-theme="light"]{--vz-up:color-mix(in srgb,var(--ok) 58%,var(--bg-base));}
:root[data-theme="dark"]{--vz-up:color-mix(in srgb,var(--ok) 45%,var(--bg-base));}

/* ---- state fills, shared by strips, bars and day columns ----------------- */
.vz-seg.vz-up,.vz-bar>.vz-up,.vz-day>.vz-up{background:var(--vz-up);}
.vz-seg.vz-up{top:var(--vz-up-inset);}
.vz-seg.vz-degraded,.vz-bar>.vz-degraded,.vz-day>.vz-degraded{background:var(--warn);}
.vz-seg.vz-down,.vz-bar>.vz-down,.vz-day>.vz-down{background:var(--crit);}
.vz-seg.vz-no_data,.vz-bar>.vz-no_data,.vz-day>.vz-no_data{background:var(--vz-hatch),var(--bg-void);}
.vz-seg.vz-pending{background:transparent;}
.vz-bar>.vz-empty{background:var(--line-faint);}
/* devices whose checks are paused: hollow, like their chips and the Not monitored pill */
.vz-bar>.vz-unmonitored{background:transparent;box-shadow:inset 0 0 0 1px var(--line-strong);}
/* a stretch that was up with some checks failed: a notch from the top, as deep as the
   share that failed (charts.marks), over the lower up fill */
.vz-mark{position:absolute;top:0;display:block;min-width:2px;background:var(--crit);z-index:1;}

/* ---- the hover layer (viz.js) --------------------------------------------- */
.vz-cross{position:absolute;top:0;bottom:0;left:0;width:1px;margin-left:-.5px;background:var(--text-hi);
  opacity:0;pointer-events:none;transition:opacity var(--dur-fast);z-index:3;}
.is-hover .vz-cross{opacity:.6;}
.vz-tip{position:fixed;z-index:210;display:none;pointer-events:none;min-width:150px;max-width:260px;
  background:var(--bg-overlay);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow-3);padding:8px 10px;font:400 var(--fs-2)/1.5 var(--sans);color:var(--text);}
.vz-tip-when{color:var(--text-mut);font:500 var(--fs-1)/1.3 var(--mono);margin-bottom:4px;white-space:nowrap;}
.vz-tip-row{display:flex;align-items:center;gap:7px;line-height:1.55;white-space:nowrap;}
.vz-tip-row b{color:var(--text-hi);font-weight:600;}
.vz-tip-key{width:10px;height:2px;background:var(--acid);flex:none;}
.vz-tip-dot{width:8px;height:8px;border-radius:2px;flex:none;background:var(--vz-up);}
.vz-tip-dot.vz-degraded{background:var(--warn);}
.vz-tip-dot.vz-down{background:var(--crit);}
.vz-tip-dot.vz-blip{box-shadow:inset 0 3px 0 var(--crit);}
.vz-tip-dot.vz-no_data,.vz-tip-dot.vz-pending{background:var(--vz-hatch),var(--bg-void);box-shadow:inset 0 0 0 1px var(--line-strong);}

/* ---- the board: a line's last 24 hours in its row ------------------------- */
table.lines td.vz-cell{width:140px;min-width:140px;padding:6px 10px;}
/* every floor is its own table (it folds away, ADR-0032), so Status and Line get one width
   in all of them - a spacer in the header sets the least they can shrink to, `width` the
   most they can grow to - and the strips line up down the page whatever the other columns
   hold. Status is as wide as its widest pill (No address, a line not checked yet, 93px); a
   long line label wraps at the name cell's cap. */
table.lines th.vz-c-status{width:94px;}
table.lines th.vz-c-line{width:180px;}
table.lines th.vz-c-status::after,table.lines th.vz-c-line::after{content:"";display:block;width:inherit;}
/* a long line label wraps inside Line's width rather than widen its floor's column */
table.lines-board td.lb-line>*{max-width:180px;}
/* ...and so does every other column of the board, so the floors still read as one grid.
   Each measured column is as wide as its widest value (a full IPv4 address, "1000M",
   "100.0%", "2 y 11 m", "Rs 12,00,000") and no narrower - `min-width` as well as `width`,
   because a table given less room than its columns ask for shrinks each one towards its
   own values, which differ from floor to floor. Circuit, the one column with no width,
   wraps and takes what is left (a 100% width would shrink the others to their content
   instead); a circuit ID breaks anywhere, so the longest one (DD LGF's) does not hold its
   floor's Circuit wider than the rest, and every floor's Circuit shrinks alike, to six
   digits a line at least - a TATA or ACT ID in two lines, no taller than the ARC beside
   it. Below the width the grid needs (about 1,220px of screen) every floor's table is as
   wide as the next and scrolls sideways by as much, its columns still in line. A value
   wider than its column widens that floor's column only. */
table.lines-board td.lb-circuit{overflow-wrap:anywhere;}
/* the account a line is billed under, a quiet second line under its circuit (ADR-0039); an
   ACT line's circuit is its account, marked once */
table.lines-board td .lb-account{color:var(--text-mut);}
table.lines-board td .lb-ac{color:var(--text-mut);font-family:var(--sans);font-size:var(--fs-2);}
table.lines-board th.lb-circuit{min-width:75px;}
table.lines-board th:is(.lb-vendor,.lb-wan,.lb-speed,.lb-latency,.lb-sla,.lb-age,.lb-arc,.lb-actions){
  width:var(--lb-w);min-width:var(--lb-w);}
table.lines-board th.lb-vendor{--lb-w:76px;}
table.lines-board th.lb-wan{--lb-w:146px;}
table.lines-board th.lb-speed{--lb-w:68px;}
table.lines-board th.lb-latency{--lb-w:72px;}
table.lines-board th.lb-sla{--lb-w:76px;}
table.lines-board th.lb-age{--lb-w:92px;}
table.lines-board th.lb-arc{--lb-w:108px;}
table.lines-board th.lb-actions{--lb-w:70px;}
/* the box scrolls sideways only: while the rows rise into place on first paint
   (floorplate-motion.js) the last one hangs a few px below the table, and the vertical
   scrollbar that drew for it took 10px from that floor's columns until it went. Nothing
   is clipped that overflow-x:auto did not clip already. */
.tablewrap:has(> table.lines-board){overflow-y:hidden;}
.vz-col-scale{display:block;margin-top:2px;white-space:nowrap;font-weight:400;font-size:var(--fs-1);color:var(--text-mut);}
/* while a row is open in the editor, its floor's table gives the strip's width back to
   the inputs, so Save stays on screen at laptop width; the other floors keep theirs. That
   table is laid out for its inputs, not the grid: its columns take the width they need. */
table.lines:has(tr.row-edit) .vz-col{display:none;}
table.lines-board:has(tr.row-edit) th:is(.lb-vendor,.lb-wan,.lb-speed,.lb-latency,.lb-sla,.lb-circuit,.lb-age,.lb-arc,.lb-actions){
  width:auto;min-width:0;}
.vz-row{position:relative;display:flex;flex-direction:column;gap:3px;width:120px;cursor:crosshair;
  border-radius:var(--r-sm);outline:none;}
.vz-row:focus-visible{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--acid);}
.vz-strip{position:relative;height:8px;border-radius:2px;overflow:hidden;background:var(--bg-void);}
.vz-seg{position:absolute;top:0;bottom:0;display:block;}
.vz-spark{display:block;overflow:visible;}
.vz-spark-line{fill:none;stroke:var(--acid);stroke-width:1.4;stroke-linejoin:round;stroke-linecap:round;}
.vz-spark-area{fill:var(--vz-wash);stroke:none;}
/* above the shared scale: held at the top edge and capped there */
.vz-spark-over{fill:none;stroke:var(--warn);stroke-width:2.5;stroke-linecap:butt;}
.vz-none{font:400 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
/* a line's name opens its page: the name's own ink, underlined quietly until pointed at */
table.lines a.vz-linelink{color:var(--text-hi);text-decoration:underline;text-decoration-color:var(--line-strong);
  text-decoration-thickness:1px;text-underline-offset:3px;}
table.lines a.vz-linelink:hover{color:var(--acid);text-decoration-color:var(--acid);}

/* ---- the estate: a tile per building ------------------------------------- */
.vz-estate{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--space-3);margin:0 0 var(--space-5);}
/* a tile is a card like Home's health cards: the building, its probe, two rows of figures
   over their bars, and its incidents at the foot */
.vz-tile{display:flex;flex-direction:column;gap:10px;min-width:0;padding:14px var(--space-4) 12px;
  background:var(--bg-base);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-1);}
.vz-tile-head{display:flex;align-items:baseline;gap:var(--space-2);min-width:0;flex-wrap:wrap;}
.vz-tile-code{font:600 var(--fs-5)/1.3 var(--sans);letter-spacing:-.005em;color:var(--text-hi);}
.vz-tile-name{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font:400 var(--fs-3)/1.3 var(--sans);color:var(--text-mut);}
.vz-probe{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;font:500 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
.vz-probe-dot{width:7px;height:7px;border-radius:50%;background:var(--idle);flex:none;}
.vz-probe-live .vz-probe-dot{background:var(--ok);}
/* a probe that stopped reporting is down, in the words and the colour of the
   Infrastructure tab's PROBE DOWN banner; the label stays in the text colour, the state
   is on the dot */
.vz-probe-silent{color:var(--crit-ink);font-weight:600;}
.vz-probe-silent .vz-probe-dot{background:var(--crit);box-shadow:0 0 0 3px color-mix(in srgb,var(--crit) 22%,transparent);}
/* silent with nothing to check - every device here paused: no colour, a hollow dot */
.vz-probe-paused .vz-probe-dot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--idle);}
/* a silent probe tints its tile, the health card's rule for something wrong */
.vz-tile.is-silent{background:color-mix(in srgb,var(--crit) 5%,var(--bg-base));border-color:color-mix(in srgb,var(--crit) 32%,var(--bg-base));}
.vz-tile-row{display:grid;grid-template-columns:44px minmax(0,1fr);grid-template-rows:auto auto;column-gap:var(--space-2);row-gap:5px;}
.vz-tile-lbl{grid-row:1 / 3;padding-top:2px;font:500 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
.vz-tile-num{font:400 var(--fs-3)/1.3 var(--sans);color:var(--text-mut);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.vz-tile-num b{color:var(--text-hi);font-weight:600;font-size:var(--fs-5);font-variant-numeric:tabular-nums;}
.vz-txt-down{color:var(--crit-ink);font-weight:500;}
.vz-txt-slow{color:var(--warn-ink);font-weight:500;}
.vz-bar{display:flex;align-items:flex-end;gap:2px;height:6px;}
.vz-bar>i{display:block;flex:0 1 0;min-width:3px;height:100%;border-radius:1px;}
.vz-bar>.vz-up{height:calc(100% - var(--vz-up-inset));}
.vz-bar>.vz-grow-1{flex-grow:1;}
.vz-tile-foot{display:flex;align-items:center;justify-content:space-between;gap:4px var(--space-2);flex-wrap:wrap;
  margin-top:auto;padding-top:10px;border-top:1px solid var(--line-faint);font:400 var(--fs-2)/1.4 var(--sans);}
.vz-tile-quiet{color:var(--text-mut);}
.vz-tile-inc{color:var(--crit-ink);font-weight:600;}
a.vz-tile-inc:hover{color:var(--crit-ink);text-decoration:underline;}
.vz-tile-note{flex-basis:100%;color:var(--text);line-height:1.45;}

/* ---- the Infrastructure tab: each floor as a tree -------------------------- */
/* Diagram or table: a label, then the app's segmented tabs (.segbar) made of two radios */
.vz-viewtoggle{display:flex;align-items:center;gap:var(--space-3);margin:0 0 var(--space-4);}
.vz-viewtoggle-lbl{font:500 var(--fs-3)/1.3 var(--sans);color:var(--text-mut);}
.vz-viewtoggle-track{display:inline-flex;gap:2px;padding:3px;background:var(--bg-void);border:1px solid var(--line);
  border-radius:calc(var(--r) + 3px);}
.vz-view-input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none;}
.vz-viewtoggle label{display:inline-flex;align-items:center;gap:6px;min-height:30px;padding:0 14px;cursor:pointer;
  border-radius:var(--r);font:500 var(--fs-3)/1 var(--sans);color:var(--text-mut);
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease);}
.vz-viewtoggle label .i{width:16px;height:16px;}
.vz-viewtoggle label:hover{color:var(--text-hi);background:color-mix(in srgb,var(--bg-base) 55%,transparent);}
.vz-view-input:checked+label{background:var(--bg-base);color:var(--text-hi);font-weight:600;box-shadow:var(--shadow-1);}
.vz-view-input:focus-visible+label{box-shadow:inset 0 0 0 2px var(--acid);}
.vz-view-input:checked:focus-visible+label{box-shadow:inset 0 0 0 2px var(--acid),var(--shadow-1);}
/* the APs Central lists but no device stands for have no tree to draw: always a table */
body:has(#vz-view-diagram:checked) details.floor-group:not(.central-only)>.tablewrap{display:none;}
body:has(#vz-view-table:checked) .vz-topo{display:none;}

.vz-topo{padding:var(--space-3) var(--space-4) var(--space-4);border-bottom:1px solid var(--line-faint);}
/* the label in a column of its own, the lines wrapping beside it: the tree below always
   hangs from the label, never from whichever line wrapped under it */
.vz-topo-feeds{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;column-gap:8px;}
.vz-topo-chips{display:flex;flex-wrap:wrap;gap:6px;min-width:0;}
.vz-topo-lbl{font:500 var(--fs-2)/26px var(--sans);color:var(--text-mut);white-space:nowrap;}
.vz-topo-none{font:400 var(--fs-3)/1.4 var(--sans);color:var(--text-mut);}
.vz-topo-chips .vz-topo-none{line-height:26px;}
p.vz-topo-none{margin:var(--space-2) 0 0;}
.vz-tree{list-style:none;margin:0;padding:0;}
.vz-tree-root{margin-left:9px;}
.vz-tree .vz-tree{margin-left:9px;}
.vz-tree-root>.vz-branch,.vz-tree .vz-tree>.vz-branch{position:relative;padding:6px 0 0 20px;}
.vz-tree-root>.vz-branch::before,.vz-tree .vz-tree>.vz-branch::before{content:"";position:absolute;left:0;top:0;bottom:0;
  border-left:1px solid var(--line-strong);}
.vz-tree-root>.vz-branch:last-child::before,.vz-tree .vz-tree>.vz-branch:last-child::before{bottom:auto;height:18px;}
.vz-tree-root>.vz-branch::after,.vz-tree .vz-tree>.vz-branch::after{content:"";position:absolute;left:0;top:18px;
  width:14px;border-top:1px solid var(--line-strong);}
.vz-leaves{display:flex;flex-wrap:wrap;gap:4px;}
/* a device on the tree: its name in the interface face, its address in mono after it */
.vz-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;max-width:100%;
  border:1px solid var(--line);border-radius:var(--r);background:var(--bg-base);box-shadow:var(--shadow-1);
  font:500 var(--fs-2)/1 var(--sans);color:var(--text-hi);white-space:nowrap;}
.vz-chip-name{overflow:hidden;text-overflow:ellipsis;min-width:0;}
.vz-chip-sub{color:var(--text-mut);font:400 var(--fs-1)/1 var(--mono);}
.vz-chip-tag{padding-left:6px;border-left:1px solid var(--line);color:var(--text-mut);font-size:var(--fs-1);
  overflow:hidden;text-overflow:ellipsis;min-width:0;}
a.vz-chip{text-decoration:none;}
a.vz-chip:hover{border-color:var(--acid);color:var(--acid);}
.vz-chip.vz-role-gateway .vz-chip-name,.vz-chip.vz-role-firewall .vz-chip-name,
.vz-chip.vz-role-switch .vz-chip-name{font-weight:600;}
.vz-leaves .vz-chip{height:22px;padding:0 7px;font-size:var(--fs-1);gap:5px;box-shadow:none;background:var(--bg-raised);}
.vz-dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--idle);}
.vz-chip.vz-up .vz-dot{background:var(--ok);}
.vz-chip.vz-degraded .vz-dot{background:var(--warn);}
.vz-chip.vz-down{border-color:color-mix(in srgb,var(--crit) 50%,var(--line));background:color-mix(in srgb,var(--crit) 6%,var(--bg-base));color:var(--crit-ink);}
.vz-chip.vz-down .vz-dot{background:var(--crit);}
/* stale: hollow and dashed, like the app's own Stale pill - no reading, not down */
.vz-chip.vz-no_data{border-style:dashed;color:var(--text-mut);background:transparent;}
.vz-chip.vz-no_data .vz-dot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--text-mut);}
/* not monitored - checks paused, CCTV kept as inventory (ADR-0036): hollow and dotted like
   the app's Not monitored pill, its dot a dash. Nobody asked for a reading, so it is
   neither stale (dashed, a ring) nor down (red). */
.vz-chip.vz-unmonitored{border-style:dotted;border-color:var(--line-strong);color:var(--text-mut);background:transparent;}
.vz-chip.vz-unmonitored .vz-dot{width:8px;height:2px;border-radius:1px;background:var(--idle);}
/* the childless devices under a node, a row per kind (ADR-0036): the kind and its count
   on the branch line, the chips wrapping under it - 28 access points and 33 cameras read
   as two rows, not one wall */
.vz-leafrow-head{display:flex;align-items:center;flex-wrap:wrap;gap:2px 8px;min-height:24px;margin-bottom:3px;}
.vz-leafrow-lbl{font:600 var(--fs-2)/1.2 var(--sans);color:var(--text);}
.vz-leafrow-n{font:500 var(--fs-2)/1.2 var(--sans);color:var(--text-mut);}
.vz-leafrow-head .pill{min-height:18px;padding:0 7px 0 6px;font-size:var(--fs-1);}

/* ---- the line page -------------------------------------------------------- */
/* the history is behind: a warning in the alerts' amber, above what it qualifies */
.vz-note{margin:0 0 var(--space-4);padding:10px var(--space-4);border:1px solid color-mix(in srgb,var(--warn) 34%,var(--bg-base));
  border-left:3px solid var(--warn);border-radius:var(--r);background:color-mix(in srgb,var(--warn) 7%,var(--bg-base));
  font:400 var(--fs-3)/1.5 var(--sans);color:var(--text-hi);}
.vz-history .vz-note{margin:var(--space-3) var(--space-4) 0;}
.vz-facts{padding:var(--space-4) 20px 20px;display:grid;gap:var(--space-4);}
.vz-facts-status{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;}
.vz-facts-status .mono{font-size:var(--fs-2);}
/* each fact as wide as its value, so an address or a circuit ID never breaks mid-number;
   a phone lays them out two to a row instead */
.vz-facts-grid{display:flex;flex-wrap:wrap;gap:var(--space-3) var(--space-5);margin:0;}
.vz-facts-grid>div{flex:1 0 auto;min-width:110px;}
.vz-facts-grid dt,.vz-card-grid dt{font:500 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
.vz-facts-grid dd,.vz-card-grid dd{margin:3px 0 0;font-size:var(--fs-4);color:var(--text-hi);overflow-wrap:anywhere;}

/* the three uptimes and the incident count: KPI tiles, label over figure over a note */
.vz-uptimes{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--space-3);margin:0 0 var(--space-5);}
.vz-stat{display:flex;flex-direction:column;gap:6px;min-width:0;padding:14px var(--space-4) var(--space-4);
  background:var(--bg-base);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-1);}
.vz-stat-lbl{font:500 var(--fs-3)/1.3 var(--sans);color:var(--text-mut);}
.vz-stat-num{font:600 26px/1.1 var(--sans);letter-spacing:-.015em;color:var(--text-hi);font-variant-numeric:tabular-nums;}
.vz-stat-sub{font:400 var(--fs-2)/1.45 var(--sans);color:var(--text-mut);}
/* over a window that is mostly without data, or that the hourly history has not reached:
   the figure is there, but it does not get the headline's weight */
.vz-stat-num.is-partial{color:var(--text-mut);}
.vz-stat-tag{display:inline-block;margin-left:4px;padding:3px 7px;vertical-align:middle;border:1px dashed var(--line-strong);
  border-radius:var(--r-full);font:600 var(--fs-1)/1 var(--sans);letter-spacing:0;text-transform:capitalize;color:var(--text-mut);}

.vz-history .panel-head{align-items:center;}
/* the window: the app's segmented tabs, as links */
.vz-range{display:inline-flex;gap:2px;padding:3px;background:var(--bg-void);border:1px solid var(--line);border-radius:calc(var(--r) + 3px);}
.vz-range-opt{display:inline-flex;align-items:center;min-height:28px;padding:0 12px;border-radius:var(--r);
  font:500 var(--fs-3)/1 var(--mono);color:var(--text-mut);transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease);}
.vz-range-opt:hover{color:var(--text-hi);background:color-mix(in srgb,var(--bg-base) 55%,transparent);}
.vz-range-opt.is-on{background:var(--bg-base);color:var(--text-hi);font-weight:600;box-shadow:var(--shadow-1);}
.vz-range-opt:focus-visible{box-shadow:inset 0 0 0 2px var(--acid);}
.vz-legend{display:flex;flex-wrap:wrap;gap:6px 18px;list-style:none;margin:0;padding:var(--space-4) 20px 0;
  font:400 var(--fs-2)/1.4 var(--sans);color:var(--text-mut);}
.vz-legend li{display:inline-flex;align-items:center;gap:7px;}
.vz-legend i{display:block;flex:none;}
.vz-key-line{width:16px;height:2px;border-radius:1px;background:var(--acid);}
.vz-key-band{width:16px;height:9px;background:var(--vz-band);box-shadow:inset 0 1px 0 color-mix(in srgb,var(--acid) 60%,transparent);}
.vz-key-thr{width:16px;border-top:1px dashed var(--warn);}
.vz-key-inc{width:10px;height:10px;background:var(--vz-inc);box-shadow:inset 1px 0 0 var(--vz-inc-edge);}
.vz-key-gap{width:10px;height:10px;background:var(--vz-hatch),var(--bg-void);}
.vz-key-state{width:10px;height:10px;border-radius:2px;background:var(--vz-up);}
.vz-key-state.vz-up{box-sizing:border-box;border-top:4px solid transparent;background-clip:padding-box;border-radius:0 0 2px 2px;}
.vz-key-mark{width:10px;height:10px;border-radius:2px;background:linear-gradient(var(--crit) 0 4px,var(--vz-up) 4px);}
.vz-key-state.vz-degraded{background:var(--warn);}
.vz-key-state.vz-down{background:var(--crit);}

.vz-chart{position:relative;display:grid;grid-template-columns:44px minmax(0,1fr);
  grid-template-rows:210px 10px 64px 20px;gap:8px 10px;padding:var(--space-5) var(--space-4) var(--space-2) var(--space-3);
  outline:none;cursor:crosshair;}
.vz-chart:focus-visible{box-shadow:inset 0 0 0 2px var(--acid);}
.vz-axis{position:relative;font-family:var(--mono);font-size:var(--fs-1);color:var(--text-mut);}
.vz-axis span{position:absolute;right:0;transform:translateY(50%);line-height:1;white-space:nowrap;}
.vz-axis em{position:absolute;right:0;top:-18px;font-style:normal;color:var(--text-mut);}
.vz-plot{position:relative;border-bottom:1px solid var(--line-strong);}
.vz-plot-strip{border:none;border-radius:2px;overflow:hidden;background:var(--bg-void);}
.vz-grid{position:absolute;left:0;right:0;height:0;border-top:1px solid var(--line-faint);}
.vz-gap{position:absolute;top:0;bottom:0;background:var(--vz-hatch);opacity:.8;}
.vz-inc{position:absolute;top:0;bottom:0;background:var(--vz-inc);box-shadow:inset 1px 0 0 var(--vz-inc-edge);}
.vz-svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible;}
.vz-line{fill:none;stroke:var(--acid);stroke-width:1.75;vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round;}
.vz-band{fill:var(--vz-band);stroke:none;}
/* the slow end of each bucket as a hairline, so the band reads against any panel */
.vz-band-edge{fill:none;stroke:var(--acid);stroke-width:1;opacity:.55;vector-effect:non-scaling-stroke;stroke-linejoin:round;}
.vz-loss-area{fill:var(--vz-band);stroke:none;}
.vz-loss-line{fill:none;stroke:var(--acid);stroke-width:1.25;vector-effect:non-scaling-stroke;stroke-linejoin:round;}
.vz-thr{position:absolute;left:0;right:0;height:0;border-top:1px dashed var(--warn);z-index:2;}
.vz-plot-name{position:absolute;left:6px;top:2px;z-index:2;font:500 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
.vz-clip{position:absolute;top:-16px;right:0;font-family:var(--mono);font-size:var(--fs-1);color:var(--text-mut);}
.vz-xaxis{position:relative;font-family:var(--mono);font-size:var(--fs-1);color:var(--text-mut);}
.vz-xaxis span{position:absolute;top:0;transform:translateX(-50%);white-space:nowrap;}
.vz-caption{margin:0;padding:0 20px var(--space-3);max-width:100ch;font:400 var(--fs-3)/1.5 var(--sans);color:var(--text-mut);}
/* the chart as a table: folded under a quiet summary with the app's chevron; opened, it
   is as long as it is and scrolls with the page (ADR-0029: no table in a box of its own) */
.vz-tableview{border-top:1px solid var(--line-faint);}
.vz-tableview>summary{display:flex;align-items:center;gap:8px;cursor:pointer;list-style:none;padding:12px 20px;
  font:500 var(--fs-3)/1.3 var(--sans);color:var(--text-mut);}
.vz-tableview>summary::-webkit-details-marker{display:none;}
.vz-tableview>summary::before{content:"";width:6px;height:6px;border:solid currentColor;border-width:0 1.5px 1.5px 0;
  transform:rotate(-45deg);transition:transform var(--dur) var(--ease);}
.vz-tableview[open]>summary::before{transform:rotate(45deg);}
.vz-tableview>summary:hover{color:var(--acid);}
.vz-tableview .tablewrap{border-top:1px solid var(--line-faint);}
.vz-state{display:inline-flex;align-items:center;gap:6px;font:500 var(--fs-3)/1.3 var(--sans);}
.vz-state::before{content:"";width:8px;height:8px;border-radius:2px;background:var(--vz-up);}
.vz-state.vz-degraded::before{background:var(--warn);}
.vz-state.vz-down::before{background:var(--crit);}
.vz-state.vz-no_data::before,.vz-state.vz-pending::before{background:var(--vz-hatch),var(--bg-void);box-shadow:inset 0 0 0 1px var(--line-strong);}

/* ---- the vendor scorecard --------------------------------------------------- */
.vz-hbars{display:grid;gap:var(--space-3);padding:var(--space-4) 20px 20px;}
.vz-hbar{display:grid;grid-template-columns:120px minmax(0,1fr) 112px 150px;align-items:center;gap:var(--space-3);}
.vz-hbar-name{font:600 var(--fs-4)/1.3 var(--sans);color:var(--text-hi);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.vz-hbar-track{display:block;height:14px;border-radius:var(--r-full);background:var(--bg-void);overflow:hidden;}
.vz-hbar-fill{display:block;height:100%;background:var(--acid);border-radius:var(--r-full);min-width:4px;}
.vz-hbar-val{font:600 var(--fs-4)/1.3 var(--mono);color:var(--text-hi);text-align:right;}
.vz-hbar-sub{font:400 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
.vz-hbar-none{font:400 var(--fs-3)/1.3 var(--sans);color:var(--text-mut);white-space:nowrap;}
/* a vendor's card is the app's card: a head, the uptime figure, its days, its facts */
.vz-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--space-4);margin-bottom:var(--space-5);}
.vz-card{display:flex;flex-direction:column;min-width:0;background:var(--bg-base);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--shadow-1);overflow:clip;}
.vz-card-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-2);flex-wrap:wrap;
  padding:14px 20px;border-bottom:1px solid var(--line);background:var(--bg-base);}
.vz-card-head h2{margin:0;font:600 var(--fs-5)/1.3 var(--sans);letter-spacing:-.005em;color:var(--text-hi);}
.vz-card-head .dim{font:400 var(--fs-3)/1.3 var(--sans);}
.vz-card-up{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px var(--space-2);padding:var(--space-4) 20px var(--space-3);}
.vz-card-aside{flex-basis:100%;font:400 var(--fs-2)/1.45 var(--sans);color:var(--text-mut);}
.vz-days-fig{margin:0;padding:0 20px var(--space-4);}
.vz-days-cap{display:flex;justify-content:space-between;gap:var(--space-2);margin-bottom:6px;font:500 var(--fs-2)/1.3 var(--sans);color:var(--text-mut);}
.vz-days-cap .mono{font-weight:400;font-size:var(--fs-1);}
.vz-days{position:relative;display:flex;align-items:flex-end;gap:2px;height:44px;border-bottom:1px solid var(--line-strong);
  cursor:crosshair;outline:none;}
.vz-days:focus-visible{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--acid);}
.vz-day{flex:1 1 0;min-width:0;height:100%;display:flex;align-items:flex-end;}
.vz-day>i{display:block;width:100%;border-radius:2px 2px 0 0;}
.vz-day>.vz-up{min-height:2px;border-radius:0;}
.vz-days-axis{display:flex;justify-content:space-between;margin-top:4px;font:400 var(--fs-1)/1.3 var(--sans);color:var(--text-mut);}
.vz-days-worst{margin:8px 0 0;font:400 var(--fs-3)/1.45 var(--sans);color:var(--text);}
.vz-card-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-3) var(--space-4);margin:auto 0 0;
  padding:var(--space-4) 20px 20px;border-top:1px solid var(--line-faint);}

/* ---- narrow screens ----------------------------------------------------------- */
/* a laptop: the Leased Lines tables are tight, so their cells give up a little padding
   rather than the strips giving up their line */
@media(max-width:1440px){
  table.lines:has(th.vz-col) :is(th,tr:not(.row-edit)>td):not(:first-child):not(:last-child){padding-left:10px;padding-right:10px;}
  table.lines th.vz-c-line{width:150px;}
  table.lines-board td.lb-line>*{max-width:150px;}
  /* the same columns with their cells' 8px less padding (at 1280 the floors fit as one
     grid); Actions, the last cell, keeps its padding and so its width */
  table.lines-board th.lb-vendor{--lb-w:66px;}
  table.lines-board th.lb-wan{--lb-w:138px;}
  table.lines-board th.lb-speed{--lb-w:60px;}
  table.lines-board th.lb-latency{--lb-w:64px;}
  table.lines-board th.lb-sla{--lb-w:68px;}
  table.lines-board th.lb-circuit{min-width:67px;}
  table.lines-board th.lb-age{--lb-w:84px;}
  table.lines-board th.lb-arc{--lb-w:100px;}
}
@media(max-width:820px){
  table.lines th.vz-c-line{width:110px;}   /* the table scrolls here: let the strip peek in */
  table.lines-board td.lb-line>*{max-width:110px;}
  /* ...and every floor's scrolls anyway, so Circuit can hold a whole TATA or ACT ID */
  table.lines-board th.lb-circuit{min-width:114px;}
  .vz-estate{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--space-2);}
  .vz-tile{padding:var(--space-3);}
  .vz-tile-name{display:none;}
  .vz-tile-head .vz-probe{flex-basis:100%;}
  .vz-tile-row{grid-template-columns:34px minmax(0,1fr);}
  .vz-chart{grid-template-columns:34px minmax(0,1fr);grid-template-rows:170px 10px 52px 20px;
    padding:var(--space-5) var(--space-3) var(--space-2) var(--space-2);gap:8px 6px;}
  .vz-xaxis .is-minor{display:none;}
  .vz-hbar{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"name val" "track track" "sub sub";row-gap:4px;}
  .vz-hbar-name{grid-area:name;}
  .vz-hbar-val{grid-area:val;}
  .vz-hbar-track{grid-area:track;}
  .vz-hbar-sub{grid-area:sub;}
  .vz-cards{grid-template-columns:minmax(0,1fr);}
  .vz-stat-num{font-size:22px;}
}
/* a phone: the tiles become one row that swipes, the next one peeking in, so the four
   buildings cost one tile's height above the tabs instead of four. The row runs to the
   screen's edge through the page's gutter (16px here), and no further: one px more and the
   whole page pans sideways. */
@media(max-width:600px){
  .vz-estate{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;gap:var(--space-2);
    margin-right:calc(var(--space-4) * -1);padding-right:var(--space-4);scrollbar-width:none;}
  .vz-estate::-webkit-scrollbar{display:none;}
  .vz-tile{flex:0 0 80%;scroll-snap-align:start;}
  .vz-tile-name{display:block;}
  .vz-tile-head .vz-probe{flex-basis:auto;margin-left:auto;}
  .vz-facts-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));}
  .vz-facts-grid>div{min-width:0;}
}
@media (prefers-reduced-motion:reduce){.vz-cross{transition:none;}}
/* forced colours: the states keep their own fills rather than all turning one colour */
@media (forced-colors:active){
  .vz-seg,.vz-bar>i,.vz-day>i{forced-color-adjust:none;}
}
