/* ============================================================================
   PLUMB — the application
   ----------------------------------------------------------------------------
   Same world as the marketing site, but this is scanned and operated rather
   than read: denser, quieter, faster. The rules that hold:
     - no boxed sidebar, no bordered cards in a grid, no row of stat tiles
     - severity is an ANGLE before it is a colour, so a list of findings is
       sorted by eye before a word is read
     - corners are cut, never rounded
     - orange only ever means out of true
   ========================================================================== */

.app{display:grid;grid-template-columns:230px minmax(0,1fr);min-height:100vh}
@media (max-width:900px){.app{grid-template-columns:minmax(0,1fr)}}

/* ------------------------------------------------------------------- nav --- */
/* Not a boxed sidebar: one hairline datum with the navigation hanging off it,
   the same device the marketing site uses. */
.nav{position:sticky;top:0;height:100vh;padding:22px 18px 20px 24px;
  border-right:1px solid var(--line);background:var(--paper);overflow-y:auto;
  display:flex;flex-direction:column;gap:22px}
.nav-head{margin-bottom:2px}
.brandmark{display:flex;gap:10px;align-items:flex-start}
.brandmark svg{width:23px;height:23px;flex:none}
.wordmark{font-family:var(--serif);font-size:19px;letter-spacing:-.032em;line-height:1.05;
  color:var(--ink)}
.nav-group{display:flex;flex-direction:column;gap:1px}
.nav-group > .label{margin-bottom:7px}
.nav .item{display:flex;align-items:center;gap:10px;padding:7px 0 7px 13px;font-size:14px;
  color:var(--ink-2);position:relative;transition:color .14s}
.nav .item::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:2px;height:0;background:var(--ink);transition:height .2s cubic-bezier(.3,.8,.4,1)}
.nav .item:hover{color:var(--ink)}
.nav .item.on{color:var(--ink)}
.nav .item.on::before{height:17px}
.nav .ico{width:15px;height:15px;flex:none;opacity:.6}
.nav .item.on .ico{opacity:1}
.nav .count{margin-left:auto;font-family:var(--mono);font-size:10.5px;color:var(--flag-ink);
  font-variant-numeric:tabular-nums}
.nav-foot{margin-top:auto;padding-top:15px;border-top:1px solid var(--line-soft)}
.dot.verified{background:var(--ink-3)}
.avatar{width:25px;height:25px;flex:none;display:grid;place-items:center;background:var(--ink);
  color:var(--paper);font-family:var(--mono);font-size:10px;letter-spacing:.03em;
  clip-path:polygon(0 0,100% 0,100% calc(100% - 6px),calc(100% - 6px) 100%,0 100%)}

.menubtn{display:none}
@media (max-width:900px){
  /* A closed drawer is CLOSED, not merely parked off-screen.
     transform alone leaves everything inside it hit-testable, focusable and in
     the accessibility tree. Measured at 390px with the drawer shut: focusing
     the first nav link succeeded and put the caret on "Overview" at x = -236,
     so tabbing off the menu button walked a keyboard or a screen reader
     through all ten navigation links and the brand link, none of them on
     screen. visibility:hidden removes them from all three at once, and is
     delayed by the length of the slide so the panel is still painted while it
     is closing — visibility is one of the few properties that will animate as
     a discrete step like this. */
  .nav{position:fixed;inset:0 auto 0 0;width:260px;z-index:60;transform:translateX(-100%);
    visibility:hidden;
    transition:transform .26s cubic-bezier(.3,.8,.4,1),visibility 0s linear .26s;
    box-shadow:var(--lift-lg)}
  .nav.open{transform:none;visibility:visible;
    transition:transform .26s cubic-bezier(.3,.8,.4,1),visibility 0s}
  .navscrim{position:fixed;inset:0;background:rgba(8,10,11,.5);z-index:55}
  .menubtn{display:inline-flex}
}

.security-grid { gap: 16px; }
.security-inline { display:flex; gap:10px; align-items:flex-end; flex-wrap:wrap; }
.security-inline .field { min-width:220px; flex:1; max-width:420px; }
.security-secret { border:1px solid var(--line); background:var(--paper-2); padding:16px; display:grid; gap:10px; max-width:680px; }
.security-secret > code { font:600 14px/1.5 var(--mono); overflow-wrap:anywhere; letter-spacing:.08em; }
.recovery-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:7px 18px; }
.recovery-grid code { font:600 13px/1.5 var(--mono); }
@media (max-width: 620px) { .recovery-grid { grid-template-columns:1fr; } }

/* ---------------------------------------------------------------- topbar --- */
.topbar{display:flex;align-items:center;gap:11px;padding:0 0 18px;margin-bottom:20px;
  border-bottom:1px solid var(--line);flex-wrap:nowrap;min-width:0}
.topbar .spacer{flex:1 1 auto;min-width:0}
.crumbs{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 4px of block padding takes the ancestor links from 16.8px tall to 24.8px.
   WCAG 2.2 AA 2.5.8 asks for 24, and a breadcrumb can claim the inline-text
   exception, but this one is a lone link in a control bar rather than a link
   inside a sentence, so it does not get to. */
.crumbs a{color:var(--ink-3);padding:4px 0}
.crumbs a:hover{color:var(--ink)}

/* ------------------------------------------------------------------ menu --- */
.menu{position:absolute;right:0;top:calc(100% + 8px);min-width:236px;z-index:70;
  background:var(--raise);box-shadow:var(--lift-lg);border:1.5px solid var(--ink);padding:5px}
.menu a{display:block;padding:8px 10px;font-size:13.5px;color:var(--ink-2)}
.menu a:hover{background:var(--paper-2);color:var(--ink)}
.menu .sep{margin:5px 0}

/* ------------------------------------------------------------------ main --- */
.main{padding:26px clamp(20px,3.4vw,42px) 70px;min-width:0}
.page-head{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;
  flex-wrap:wrap;padding-bottom:20px;margin-bottom:22px;border-bottom:1px solid var(--line)}
.page-head p{margin:9px 0 0;max-width:62ch;color:var(--ink-2);font-size:14.5px;line-height:1.6}
.display{font-family:var(--serif);font-size:clamp(25px,3vw,34px);font-weight:400;
  letter-spacing:-.03em;line-height:1.08;margin:0}
.title{font-family:var(--serif);font-weight:400;letter-spacing:-.03em}
.subtitle{font-family:var(--serif);font-size:23px;font-weight:400;letter-spacing:-.03em;margin:0}
.label{font-family:var(--mono);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-3)}
.dim{color:var(--ink-3)}
.mono{font-family:var(--mono)}
.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.measure{max-width:66ch}
.sep{height:1px;background:var(--line-soft);border:0;margin:20px 0}
.grid{display:grid}
.g2{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}

/* ----------------------------------------------------------------- panel --- */
/* A plate, not a card: paper stock with one cut corner and no border. */
.panel{background:var(--card);box-shadow:var(--lift);margin-bottom:20px;
  clip-path:polygon(0 0,100% 0,100% calc(100% - 16px),calc(100% - 16px) 100%,0 100%)}
.panel-head{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:15px 20px;border-bottom:1px solid var(--line-soft);flex-wrap:wrap}
.panel-body{padding:18px 20px}

/* ------------------------------------------------------------------ rows --- */
.rows{display:flex;flex-direction:column}
.row{display:grid;gap:16px;align-items:center;padding:13px 20px;
  border-bottom:1px solid var(--line-soft);cursor:pointer;transition:background .13s}
.row:last-child{border-bottom:0}
.row:hover{background:var(--paper-2)}
/* A finding row carries role="button" and tabindex="0" — it is the only way
   into the drawer — so it has to show where the caret is. The ring is inset
   because rows sit flush against each other and their panel's edge, where an
   outset one is drawn over the neighbouring row and clipped by the panel. */
.row[data-find]:focus-visible{outline:2px solid var(--flag);outline-offset:-2px}
.row .primary{font-size:14.5px;color:var(--ink);line-height:1.35}
.row .secondary{font-size:12.5px;color:var(--ink-3);margin-top:3px;line-height:1.45}

/* ----------------------------------------------------------------- stats --- */
/* Figures hang off a rule; they are not tiles. */
.stat{padding:0 22px 0 0;border-left:1px solid var(--line-soft);padding-left:16px}
.stat:first-child{border-left:0;padding-left:0}
.stat .k{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.17em;
  text-transform:uppercase;color:var(--ink-3);margin-bottom:6px}
.stat .v,.stat strong{font-family:var(--serif);font-size:27px;line-height:1;letter-spacing:-.025em;
  font-weight:400}

/* ------------------------------------------------------------------ chip --- */
.chip.critical,.chip.high{background:var(--flag-wash);color:var(--flag-ink)}
.chip.moderate{background:var(--paper-3);color:var(--ink-2)}
.chip.low{background:var(--paper-2);color:var(--ink-3)}
.chip.verified{background:var(--paper-2);color:var(--ink-2)}

/* ------------------------------------------------------------- controls --- */
/* Stroked, therefore not clipped — see the rule in plumb.css. */
.seg{display:inline-flex;border:1.5px solid var(--line);overflow:hidden}
.seg button{background:transparent;border:0;border-right:1px solid var(--line);color:var(--ink-3);
  font-family:var(--mono);font-size:10px;letter-spacing:.13em;text-transform:uppercase;
  padding:7px 12px;cursor:pointer;transition:background .13s,color .13s}
.seg button:last-child{border-right:0}
.seg button:hover{color:var(--ink)}
.seg button.on{background:var(--ink);color:var(--paper)}
.filters{display:flex;gap:11px;align-items:center;flex-wrap:wrap}
.switch{width:34px;height:19px;background:var(--paper-3);position:relative;cursor:pointer;flex:none;
  transition:background .18s}
.switch::after{content:'';position:absolute;top:2px;left:2px;width:15px;height:15px;
  background:var(--raise);transition:transform .18s cubic-bezier(.3,.8,.4,1)}
.switch.on{background:var(--ink)}
.switch.on::after{transform:translateX(15px)}

.hint{font-size:12.5px;color:var(--ink-3);line-height:1.55}
.quote{font-family:var(--mono);font-size:12.5px;line-height:1.7;color:var(--ink-2);
  background:var(--paper-2);border-left:2px solid var(--flag);padding:11px 15px;
  clip-path:polygon(0 0,100% 0,100% calc(100% - 9px),calc(100% - 9px) 100%,0 100%)}
.empty{text-align:left;padding:44px 20px;color:var(--ink-3);font-size:14px}

/* Slack and Teams: operational routing on the same paper/ink datum as the
   rest of the app. Orange is the live signal at the left edge, never a wash
   behind whole cards, and every control remains native-keyboard reachable. */
.integration-intro{display:grid;grid-template-columns:minmax(240px,.8fr) minmax(300px,1.2fr);
  gap:clamp(22px,5vw,72px);align-items:end;padding:4px 0 22px;margin-bottom:20px;
  border-bottom:1px solid var(--line)}
.integration-intro .subtitle{margin-top:7px;max-width:16ch}
.integration-intro p{margin:0;color:var(--ink-2);font-size:14px;line-height:1.6;max-width:62ch}
.integration-upsell{display:flex;justify-content:space-between;align-items:flex-start;gap:18px;flex-wrap:wrap}
.integration-upsell p{font-size:13.5px;margin:6px 0 0}
.integration-row{grid-template-columns:32px minmax(0,1fr) auto auto!important;position:relative}
.integration-row::before{content:'';position:absolute;left:0;top:12px;bottom:12px;width:2px;background:var(--flag)}
.connector-pick{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:8px}
.connector-pick select{min-width:220px;max-width:420px}
.connector-row .integration-actions{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
.integration-mark{width:28px;height:28px;display:grid;place-items:center;background:var(--ink);color:var(--paper);
  font-family:var(--mono);font-size:11px}
.integration-copy{min-width:0}.integration-copy .secondary{overflow-wrap:anywhere}
.integration-actions{display:flex;gap:7px;flex-wrap:wrap;justify-content:flex-end}
.integration-form{display:grid;gap:20px}
.integration-basics{display:grid;grid-template-columns:180px minmax(180px,.7fr) minmax(280px,1.3fr);gap:14px}
.integration-url{min-width:0}
.integration-route{border:0;border-top:1px solid var(--line-soft);padding:16px 0 0;margin:0}
.integration-route legend{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);padding:0 12px 0 0}
.integration-options{display:flex;gap:9px 18px;flex-wrap:wrap;margin-top:2px}
.integration-options label{display:inline-flex;align-items:center;gap:7px;min-height:28px;color:var(--ink-2);font-size:12.5px}
.integration-options input{accent-color:var(--flag)}
.integration-delivery{grid-template-columns:minmax(0,1fr) 120px auto!important;cursor:default}

@media (max-width:900px){
  .integration-basics{grid-template-columns:1fr 1fr}.integration-url{grid-column:1/-1}
}
/* Imported answers are an evidence register, never a decorative AI score. */
.ai-register{border-top:1px solid var(--ink);border-bottom:1px solid var(--line);margin-bottom:20px}
.ai-register-head,.ai-register-row{display:grid;grid-template-columns:minmax(220px,1.35fr) minmax(180px,1fr) minmax(170px,.8fr) 150px;gap:18px;align-items:center}
.ai-register-head{padding:10px 0;font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3)}
.ai-register-row{padding:15px 0;border-top:1px solid var(--line-soft)}
.ai-register-row strong,.ai-register-row span{display:block}.ai-register-row span,.ai-register-row time{font-size:12px;color:var(--ink-3);margin-top:3px}
.ai-state{font-family:var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2)!important}.ai-state.alert{color:var(--flag-ink)!important}
.ai-evidence-reason{display:block;max-width:36ch;margin-top:5px;color:var(--ink-3);overflow-wrap:anywhere}
.ai-matrix-panel{margin-bottom:20px}.ai-matrix-scroll{overflow-x:auto;padding:0!important}
.ai-matrix{display:grid;grid-template-columns:minmax(220px,1.35fr) repeat(var(--ai-provider-columns),minmax(145px,1fr));min-width:max-content}
.ai-matrix-corner,.ai-matrix-provider,.ai-matrix-prompt,.ai-matrix-cell{padding:12px 14px;border-right:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)}
.ai-matrix-corner,.ai-matrix-provider{position:sticky;top:0;z-index:1;background:var(--paper);font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.ai-matrix-corner{left:0;z-index:2}.ai-matrix-provider{text-align:center;color:var(--ink-2)}
.ai-matrix-prompt{position:sticky;left:0;z-index:1;background:var(--paper);min-width:220px}.ai-matrix-prompt strong,.ai-matrix-prompt span,.ai-matrix-prompt small{display:block}
.ai-matrix-prompt span,.ai-matrix-prompt small,.ai-matrix-cell small,.ai-matrix-cell time{font-size:11px;color:var(--ink-3);margin-top:3px}
.ai-matrix-cell{min-width:145px;background:color-mix(in srgb,var(--paper) 96%,var(--flag) 4%)}.ai-matrix-cell span,.ai-matrix-cell small,.ai-matrix-cell time{display:block}
.ai-matrix-cell.absent{background:repeating-linear-gradient(135deg,transparent 0 9px,var(--line-soft) 9px 10px)}
.ai-workbench{align-items:start;margin-bottom:20px}.ai-workbench summary{cursor:pointer;list-style:none}.ai-workbench summary::-webkit-details-marker{display:none}
.ai-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:18px;padding-top:16px;border-top:1px solid var(--line-soft)}
.ai-form .wide{grid-column:1/-1}.ai-form button{justify-self:start;align-self:end}
.ai-line,.ai-benchmark{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:11px 0;border-bottom:1px solid var(--line-soft)}
.ai-line:first-child,.ai-benchmark:first-child{padding-top:0}.ai-line:last-child,.ai-benchmark:last-child{border-bottom:0}.ai-line strong,.ai-line span,.ai-benchmark strong,.ai-benchmark span{display:block}
@media (max-width:800px){.ai-register-head{display:none}.ai-register-row{grid-template-columns:1fr 1fr}.ai-form{grid-template-columns:1fr}.ai-form .wide{grid-column:auto}}
.track{height:3px;background:var(--paper-3);overflow:hidden}
.track i{display:block;height:100%;background:var(--ink)}
.dot{width:5px;height:5px;background:var(--ink-4);border-radius:50%;flex:none}

/* ------------------------------------------------------------- sign in --- */
.auth{min-height:100vh;display:grid;place-items:center;padding:32px;
  grid-template-columns:minmax(0,1fr)}
.auth-in{width:min(392px,100%)}
.auth .lockup{margin-bottom:30px}
.auth .lockup .mark{width:.92em;height:.92em;color:var(--ink)}
.auth .panel{margin:0}
.auth-provider{width:100%;min-height:44px;display:grid;place-items:center;overflow:hidden}
.auth-provider>div{width:100%;display:grid;place-items:center}
.auth-provider iframe{max-width:100%!important}
.auth .or{display:flex;align-items:center;gap:13px;margin:20px 0;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-3)}
.auth .or::before,.auth .or::after{content:'';flex:1;height:1px;background:var(--line-soft)}
.auth .foot{font-family:var(--mono);font-size:10.5px;line-height:1.7;color:var(--ink-3);
  margin-top:22px;letter-spacing:.02em}
.auth .err{font-size:13px;color:var(--flag-ink);font-family:var(--mono);line-height:1.5}

/* ==========================================================================
   SHARPENING
   The app is scanned and operated, so density and hierarchy do the work here
   rather than atmosphere. The field appears only behind a page heading and the
   sign-in; everywhere else the screen stays flat and fast to read.
   ========================================================================== */
.page-head{padding:22px 0 24px;overflow:hidden}
.page-head .display{max-width:20ch}

/* A findings row should be legible at a glance from three feet away: the angle
   first, then the title, then everything else in a quieter register. */
.rows .row{padding:15px 20px}
.row .primary{font-size:15px;letter-spacing:-.005em}
.row .secondary{font-size:12.5px;color:var(--ink-3)}
.rows .row:hover{background:var(--paper-2)}
.rows .row:hover .primary{color:var(--ink)}

/* Severity chips: state carried by weight and ground, never by hue alone. */
.chip{font-weight:500}
.chip.critical{background:var(--ink);color:var(--paper)}
.chip.high{background:var(--flag-wash);color:var(--flag-ink)}
.chip.moderate{background:var(--paper-3);color:var(--ink-2)}
.chip.low{background:transparent;color:var(--ink-3);box-shadow:inset 0 0 0 1px var(--line)}

/* The one number that matters on a dashboard gets the serif and the size. */
.stat .v,.stat strong{font-size:31px}
.panel-head{padding:16px 20px}
.panel-head .label{letter-spacing:.19em}

/* ------------------------------------------------- the missing sixteen --- */
/**
 * Sixteen class names were rendered by app.js and defined in no stylesheet.
 *
 * Two of them were load-bearing: .drawer and .scrim are the finding overlay, so
 * with no rules the drawer rendered as ordinary static content in the document
 * flow, under everything else, with no backdrop and no way to tell it apart
 * from the page. .g3 was the three-stat row on the overview, which stacked
 * vertically instead.
 *
 * Nothing here invents a token. Every value comes from web/plumb.css, and every
 * colour is a token rather than a literal, so both themes resolve — a literal
 * would have been correct in exactly one of them, which is the classic way this
 * page breaks.
 */
.page{display:block}
/* A header row inside .rows — the column labels above a list, not a record. */
.row.head{padding-top:11px;padding-bottom:11px;background:var(--paper-2);
  border-bottom:1px solid var(--line-soft);font-family:var(--mono);font-size:9px;
  letter-spacing:.17em;text-transform:uppercase;color:var(--ink-3)}
.row.head:hover{background:var(--paper-2)}
.h-sec{font-family:var(--mono);font-size:9px;letter-spacing:.17em;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 10px}
.g3{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:20px}
.divider{height:1px;background:var(--line-soft);border:0;margin:18px 0}

/* A stat that is also a control. Same plate as .stat, plus an affordance. */
.act{cursor:pointer;background:none;border:0;border-left:1px solid var(--line-soft);
  text-align:left;font:inherit;color:inherit}
.act:hover{color:var(--flag-ink)}
.act:focus-visible{outline:2px solid var(--flag);outline-offset:3px}

/* Held at the final value while the counter animates, so a throttled
   requestAnimationFrame leaves the true number on screen rather than a zero. */
.counting{font-variant-numeric:tabular-nums}

.scale{display:flex;align-items:baseline;gap:8px}
.stat .d{display:block;font-family:var(--mono);font-size:10px;color:var(--ink-3);margin-top:5px}

/* Quoted evidence. No mix-blend-mode: it collapsed to 1.23:1 in dark mode on
   the marketing page, and the same trick would fail the same way here. */
.evidence{font-family:var(--mono);font-size:12px;line-height:1.7;background:var(--paper-2);
  padding:12px 14px;color:var(--ink-2);overflow-x:auto}
.evidence .e{color:var(--flag-ink);font-weight:600;
  /* The phrase and its page count were two inline children with nothing
     between them, so they rendered welded together — "98% Client
     Satisfaction1 page" — and a long phrase pushed the count out of the box
     entirely. A row that separates them wraps instead of clipping. */
  display:flex;gap:14px;align-items:baseline;justify-content:space-between;
  flex-wrap:wrap;padding:3px 0}
.evidence .e > b{min-width:0;overflow-wrap:anywhere}
.evidence .e > .dim{flex:none;white-space:nowrap}
.fix{border-left:2px solid var(--flag);padding-left:14px;color:var(--ink-2)}

/* ---------------------------------------------------------- the drawer --- */
.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;
  margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;
  white-space:nowrap!important;border:0!important}
/* touch-action:none because the scrim is the whole of the page on a phone and
   a drag on it used to scroll the document underneath — app.js takes the
   document's own scroll away while an overlay is open, and this is the half of
   that a touch screen needs. */
.scrim{position:fixed;inset:0;background:color-mix(in srgb,var(--ink) 42%,transparent);
  z-index:40;border:0;padding:0;width:100%;cursor:pointer;touch-action:none}
.drawer{position:fixed;top:0;right:0;bottom:0;width:min(560px,100%);z-index:41;
  background:var(--card);box-shadow:var(--lift-lg);display:flex;flex-direction:column;
  overflow:hidden}
/* A dialog container is focused on open so a screen reader announces its role
   and its title; it is not a click target and must not draw a ring for one.
   The controls inside keep their own :focus-visible rings. */
[data-overlay]:focus{outline:none}
.drawer-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;
  padding:18px 22px;border-bottom:1px solid var(--line-soft);flex-shrink:0}
/* overscroll-behavior:contain so reaching the end of a long finding does not
   hand the scroll on to the page behind the drawer. */
.drawer-body{padding:20px 22px;overflow-y:auto;overscroll-behavior:contain;
  display:flex;flex-direction:column;gap:16px}

@media (prefers-reduced-motion:no-preference){
  .drawer{animation:drawer-in .18s ease-out}
  @keyframes drawer-in{from{transform:translateX(12px);opacity:0}to{transform:none;opacity:1}}
}

/* A quote is the evidence under a finding, and this product's whole claim is
   that it shows you the sentence a finding came from. So it may not silently
   lose characters: a URL with a query string measured 406px of content in a
   344px box, and .quote's cut corner is a clip-path, which clips the overflow
   away rather than letting it spill somewhere a reader could still see it.
   .evidence next to it already scrolled; this is the same treatment, plus a
   break for the unbroken runs — tokens, hashes, query strings — that are what
   put an unwrappable 406px line in a phone-width panel in the first place. */
.quote{overflow-x:auto;overflow-wrap:anywhere}

/* .sep is the 1px rule above. app.js also renders <span class="sep">/</span>
   between breadcrumbs, so the separator inherited the rule's 1px height, its
   --line-soft background and its 20px margins: a slash drawn on a bar of
   background colour, measured at 4.22:1 in dark mode against a 4.5:1 floor.
   Inside .crumbs it is a character. */
.crumbs .sep{height:auto;background:none;margin:0;color:var(--ink-3)}

/* ==========================================================================
   CONNECTIONS
   Which Google profile, which advertiser and which handles belong to this
   customer. Three states, and none of them may look like another:

     connected and read        a chip, a date, and the sentence saying so
     connected and never read  a DASHED rule, because connected is not working
     not readable here         prose and no control at all

   The third is analytics, and it is the one the design has to get right.
   Reading a customer's analytics needs OAuth and a hosted redirect that do not
   exist, so there is nothing to draw: a disabled button is a promise, and this
   product is sold against controls that imply something untrue.
   ========================================================================== */
.conn-act{display:flex;align-items:center;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.conn-inline{display:inline-flex;align-items:center;gap:8px;min-width:0;flex-wrap:wrap;
  font-size:12.5px;color:var(--ink-3)}
.conn-ident{font-size:12.5px;color:var(--ink-2);overflow-wrap:anywhere}
/* Underlined, because it sits in a paragraph of the same size and colour and
   nothing else would separate it from the prose around it. */
.conn-link{color:var(--ink-2);text-decoration:underline;text-underline-offset:2px;
  font-size:12.5px;display:inline-block;padding:2px 0}
.conn-link:hover{color:var(--ink)}

/* Why a surface cannot be read, and why a viewer is not offered the control.
   Both are quiet: neither is a fault and neither is an error. */
.conn-blocked{display:block;font-size:12.5px;line-height:1.6;color:var(--ink-3);
  margin:7px 0 0;border-left:2px solid var(--line);padding-left:10px}
.conn-needs{font-size:12.5px;line-height:1.6;color:var(--ink-3);margin:6px 0 0}
.conn-under{margin-top:7px}

/* CONNECTED IS NOT READ. A connection nothing has ever read carries a dashed
   rule, and one whose last read failed carries the flag ink, so the three
   states separate by eye before the sentence is read — the same line the
   surfaces table draws between unread and clean. */
.conn-read{font-size:12.5px;line-height:1.6;color:var(--ink-2);margin:7px 0 0;
  border-left:2px solid var(--line-soft);padding-left:10px}
.conn-read.fresh{border-left-style:dashed;border-left-color:var(--thread);color:var(--ink-3)}
.conn-read.bad{border-left-color:var(--flag);color:var(--flag-ink)}

/* The server's own sentence about the identifier, directly under the field
   holding it. Mono because it is quoting a machine. */
.conn-err{font-family:var(--mono);font-size:12.5px;line-height:1.55;color:var(--flag-ink);margin:0}
.conn-help{font-size:12.5px;line-height:1.6;color:var(--ink-2);margin:0;max-width:62ch}
.conn-formerr{border-left:2px solid var(--flag);padding-left:12px}

/* The overlay centres this form in the viewport, so a form taller than the
   viewport hangs off both ends and the submit button cannot be reached at all.
   It is tallest exactly when it matters most: the server's sentence about a
   refused identifier is two more lines under the field. */
#cform{max-height:calc(100vh - 48px);overflow-y:auto}

/* A Google connection that is still a NAME, connected before names were
   resolved at connect time. It works the way it always did — searched for, and
   proved by the profile's own link — which is a weaker thing than the rows
   around it, so it reads as a note about this connection and not as an error
   the customer caused. Dashed, like the never-read rule, for the same reason:
   this one is not solid either. */
.conn-legacy{font-size:12.5px;line-height:1.6;color:var(--ink-2);margin:7px 0 0;
  border-left:2px dashed var(--thread);padding-left:10px;max-width:62ch}

/* ------------------------------------------------------------- THE PICK STEP
   Several Google listings matched the name and we are not choosing one. Each
   row has to carry enough to choose by: name, address, category, phone, and
   the WEBSITE Google holds — the field that separates two businesses of the
   same name in the same city.

   The whole row is the <label>, so the target is the row and not a 16px
   circle. :has() draws the choice from :checked, which means arrow-keying
   through the group repaints with no JavaScript involved; re-rendering on
   change would tear the group out from under the key walking it. */
.conn-cands{border:0;margin:0;padding:0;min-width:0;display:block}
.conn-cands legend{padding:0}
.conn-cand{display:grid;grid-template-columns:auto minmax(0,1fr);gap:11px;align-items:start;
  padding:11px 13px;margin-bottom:8px;cursor:pointer;
  border:1px solid var(--line);background:var(--paper-2);color:var(--ink)}
.conn-cand:hover{border-color:var(--ink-4)}
.conn-cand:has(.conn-cand-in:checked){border-color:var(--flag);background:var(--flag-wash)}
/* The focus ring belongs on the ROW, because the row is what the key is
   choosing. On the input alone it draws a 16px ring beside four lines of text
   that give no sign of being the thing with focus. */
.conn-cand:has(.conn-cand-in:focus-visible){outline:2px solid var(--flag);outline-offset:2px}
.conn-cand-in{width:16px;height:16px;margin:2px 0 0;accent-color:var(--flag)}
.conn-cand-t{display:grid;gap:3px;min-width:0}
.conn-cand-n{font-size:13.5px;line-height:1.4;color:var(--ink)}
.conn-cand-a{font-size:12.5px;line-height:1.55;color:var(--ink-2);overflow-wrap:anywhere}
.conn-cand-m{font-size:12.5px;line-height:1.55;color:var(--ink-2);overflow-wrap:anywhere}
/* The identifier that will actually be stored, on the row, because storing
   something the customer never saw is exactly what the name did.

   --ink-2 rather than the quieter --ink-3 this size usually takes: measured on
   the SELECTED row in dark mode, --ink-3 on --flag-wash is 4.04:1 at 11px,
   under the 4.5:1 floor. Mono and 11px is separation enough without spending
   the contrast. */
.conn-cand-id{font-family:var(--mono);font-size:11px;line-height:1.5;color:var(--ink-2);overflow-wrap:anywhere}

.conn-strip{display:flex;flex-direction:column;gap:10px;align-items:center;margin-top:2px}
.conn-strip-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:center}
.conn-actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}

/* ==========================================================================
   THE SHELL ON A PHONE
   Everything below is measured at 390x844. The app's own breakpoint for the
   navigation is 900px; these are lower, because they are about a column of
   text getting too narrow to read rather than about the shell folding.
   ========================================================================== */
@media (max-width:700px){
  .integration-intro{grid-template-columns:1fr;gap:12px}
  .integration-intro .subtitle{max-width:22ch}
  .integration-basics{grid-template-columns:1fr}.integration-url{grid-column:auto}
  .integration-actions{justify-content:flex-start;margin-top:7px}
  /**
   * EVERY ROW CARRIES ITS COLUMNS AS AN INLINE STYLE.
   *
   * app.js writes grid-template-columns on the element — nineteen distinct
   * templates, almost all of them fixed pixel columns sized for a desktop
   * shell. They do not degrade; they just take their pixels and leave the
   * remainder to the 1fr. Measured on the settings panel at 390px,
   * `190px 1fr` resolved to `190px 104px`: a 9.5px uppercase label owned 190
   * of the 294 available pixels while "owner — everything an admin can do,
   * plus changing the plan" was folded into 104px over five lines, and the
   * organisation identifier broke mid-word into "example-" / "test".
   *
   * Below this width a row stacks. !important is the only lever a stylesheet
   * has over an inline style, and the alternative is editing nineteen call
   * sites in a file another agent owns.
   */
  .row{grid-template-columns:minmax(0,1fr)!important;gap:5px 14px!important;
    align-items:start!important}
  /* A header row names columns that no longer exist once the cells stack. */
  .row.head{display:none}
  /* The findings list keeps its first column. Severity is an angle before it
     is a word — a column of marks reads as a fan and sorts itself by eye — and
     that only survives if the marks stay in one vertical line. */
  .row:has(> .sev){grid-template-columns:20px minmax(0,1fr)!important;
    column-gap:14px!important}
  .row:has(> .sev) > *{grid-column:2}
  .row:has(> .sev) > .sev{grid-column:1;grid-row:1}
  /* Stacked, a cell that was told to sit hard right is aligned to nothing. */
  .row [style*="text-align:right"]{text-align:left!important}

  /**
   * The settings tabs. .seg is a segmented control: one stroked rectangle
   * divided by hairlines. The settings tabs will not fit across 350px, and wrapping a
   * flex row left the frame drawn around three ragged rows — cells ending at
   * x = 338, 283.8 and 162.6 with the dividers between them lining up with
   * nothing, and 32px of empty stroke hanging off the first row. Equal grid
   * cells give every row the same divisions, which is the only arrangement
   * that still reads as one control.
   *
   * The dividers are drawn on each cell's LEADING edges — left and top — not
   * its trailing ones. Drawn trailing, the last cell in every row and every
   * cell in the last row lay a hairline directly on the frame and it read as a
   * doubled stroke. Leading edges mean the frame draws the outside and a cell
   * only ever draws a division between itself and a neighbour, whatever the
   * tab count is: seven here, four on the property page's cadence control.
   */
  .seg{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
  .seg button{border-right:0;padding:10px 12px;text-align:left;
    box-shadow:inset 1px 1px 0 0 var(--line)}
  .seg button:nth-child(-n+2){box-shadow:inset 1px 0 0 0 var(--line)}  /* top row */
  .seg button:nth-child(odd){box-shadow:inset 0 1px 0 0 var(--line)}   /* left column */
  .seg button:first-child{box-shadow:none}

  /**
   * The drawer head put a 76px chip, the title, and a 67px Close button on one
   * line. At 390px that left the title 174.8px: six lines of 23px serif, a
   * 219.6px header, a quarter of the viewport spent before the finding starts.
   * The chip and the control are short and belong together on one line; the
   * title is the finding's name and takes the width.
   */
  /* THE CRUMB GETS ITS OWN LINE. The topbar is flex-wrap:nowrap and holds a
     64px menu button, the crumb, a Theme button and a profile button carrying
     an avatar and a name. Measured at 390px the crumb was left with 90px for
     180px of content and ellipsed to "SETTINGS / O" — the only thing on the
     screen that says which page you are on. Nothing here is droppable, so the
     row wraps and the crumb takes the width above the controls. */
  .topbar{flex-wrap:wrap}
  .crumbs{flex:1 0 100%;order:-1;margin-bottom:4px}

  .drawer-head{flex-wrap:wrap;gap:11px 12px;padding:16px 18px}
  /* !important because app.js writes flex:1 on this element, and a shorthand
     in a style attribute beats any longhand from a stylesheet: without it the
     basis stayed 0 and the title never took its own line. */
  .drawer-head > div{flex:1 1 100%!important;order:2}
  .drawer-body{padding:18px}

  /* Once .row stacks, a right-aligned action column is a button hanging off
     the far edge of a left-aligned block of text with nothing above it to
     align to. It joins the column. */
  .conn-act{justify-content:flex-start}

  /* Measured at 390px: .panel-head wraps, and Close dropped onto its own line
     under "EXAMPLE.COM", left-aligned, where it read as an action about the
     property rather than the way out of the dialog. Held on one line the title
     wraps instead, which is what a title is for. */
  #cform .panel-head{flex-wrap:nowrap;align-items:flex-start}
  #cform .panel-head > div{min-width:0}
}

/* A candidate Google will not let us store: shown, explained, not selectable.
   Hiding it is what let two businesses collapse into one and be connected
   without anybody being asked. */
.conn-cand.off{opacity:.72;cursor:not-allowed}
.conn-cand.off .conn-cand-n{color:var(--ink-2)}
.conn-cand-why{display:block;margin-top:5px;font-family:var(--mono);font-size:10.5px;
  line-height:1.5;color:var(--flag-ink)}

/* ==========================================================================
   THE COMING-SOON SCREEN
   A waitlisted account gets no shell: no sidebar, no crumb, no page-head.
   Every one of those leads somewhere that answers 403, and a navigation full
   of refusals is a navigation full of painted controls. What is left is one
   column of paper, the two controls that work, and the record we hold.
   ========================================================================== */
.gate{min-height:100vh;padding:clamp(22px,4vw,44px) clamp(18px,4vw,40px) 64px;
  display:flex;justify-content:center}
.gate-in{width:min(680px,100%)}
.gate-top{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  padding-bottom:18px;margin-bottom:30px;border-top:2px solid var(--ink);padding-top:18px}
.gate-acts{display:flex;gap:8px;flex-wrap:wrap}
.gate .lockup .wm{font-size:.92em}

/* Label beside value, not above it: these are four short facts about one
   person and stacking them doubles the height of the panel for no gain. Below
   560px the 150px label column leaves an email 96px and it breaks mid-domain,
   so there it stacks after all. */
.gate-facts{display:grid;grid-template-columns:150px minmax(0,1fr);gap:11px 20px;margin:0}
.gate-facts dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-3);padding-top:4px;line-height:1.5}
.gate-facts dd{margin:0;font-size:14.5px;line-height:1.5;color:var(--ink);overflow-wrap:anywhere}
@media (max-width:560px){
  .gate-facts{grid-template-columns:minmax(0,1fr);gap:0}
  .gate-facts dt{padding-top:12px}
  .gate-facts dd{margin-top:3px}
  .gate-facts dt:first-child{padding-top:0}
}


/* ------------------------------------------------ findings: which property --
   The findings list pools every property an account owns. `.pick` is the
   filter that separates them and `.dom` names the domain on each row while
   more than one is in view; both are built to sit beside `.seg` without
   competing with it, so the severity and module filters stay the loudest
   controls in the bar. */
.pick{display:inline-flex;align-items:center;gap:8px;border:1.5px solid var(--line);
  padding:0 0 0 11px;background:transparent}
.pick > .label{white-space:nowrap}
.pick select{appearance:none;background:transparent;border:0;border-left:1px solid var(--line);
  color:var(--ink);font-family:var(--mono);font-size:10px;letter-spacing:.13em;
  text-transform:uppercase;padding:7px 26px 7px 11px;cursor:pointer;max-width:230px;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
    linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 14px) 12px,calc(100% - 9px) 12px;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.pick select:focus-visible{outline:2px solid var(--flag);outline-offset:1px}
.dom{font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--ink-3);margin-top:3px}
.sweep-of{font-size:13px;color:var(--ink-3);margin:-6px 0 14px}
.sweep-of strong{color:var(--ink-2);font-weight:600}

/* ------------------------------------------------------------ the info dot --
   An "i" that explains the control beside it. <details> so it opens with the
   keyboard and needs no JS; the panel is absolutely positioned so opening one
   never reflows the row it sits in. */
.with-info{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.info{position:relative;display:inline-block}
.info > summary{list-style:none;cursor:pointer;width:17px;height:17px;border-radius:50%;
  border:1.2px solid var(--line);color:var(--ink-3);font-family:var(--mono);font-size:10px;
  line-height:15px;text-align:center;user-select:none;transition:color .13s,border-color .13s}
.info > summary::-webkit-details-marker{display:none}
.info > summary:hover{color:var(--ink);border-color:var(--ink-3)}
.info > summary:focus-visible{outline:2px solid var(--flag);outline-offset:2px}
.info[open] > summary{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.info > p{position:absolute;z-index:40;top:calc(100% + 8px);left:0;width:min(330px,78vw);
  margin:0;padding:12px 14px;background:var(--raise);border:1.5px solid var(--line);
  box-shadow:0 10px 26px rgba(0,0,0,.13);font-size:12.5px;line-height:1.6;color:var(--ink-2)}
@media (max-width:640px){.info > p{left:auto;right:0}}

/* ------------------------------------------------------------- the sweep ---
   Deliberately INDETERMINATE. The server reports a status and the instants
   either side of it, never a percentage, so the rail shows that work is
   happening and the clock counts real elapsed time. A bar creeping toward a
   number nobody measured would be the invented figure this product argues
   against. */
.sweep{border:1.5px solid var(--line);background:var(--paper-2);padding:14px 16px}
.sweep-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.sweep-clock{font-size:13px;color:var(--ink-2);font-variant-numeric:tabular-nums}
/* Motion is opt-IN here, the way the chart system does it: the rail is
   legible and correct with no animation at all, and only moves for a reader
   who has not declined motion. A panel whose only signal of life is movement
   says nothing to everybody else. */
.sweep-rail{position:relative;height:3px;margin:11px 0 10px;background:var(--line);overflow:hidden}
.sweep-rail > i{position:absolute;inset:0 auto 0 0;width:100%;background:var(--flag);opacity:.45}
.sweep[data-sweep="queued"] .sweep-rail > i{opacity:.28}
.sweep[data-sweep="done"] .sweep-rail > i{opacity:1}
.sweep[data-sweep="failed"] .sweep-rail > i{background:var(--ink-3);opacity:1}
.sweep-say{margin:0;font-size:13px;line-height:1.55;color:var(--ink-3)}
.sweep[data-sweep="done"] .sweep-say{color:var(--ink-2)}
@keyframes sweep-run{0%{transform:translateX(-100%)}100%{transform:translateX(365%)}}
@media (prefers-reduced-motion:no-preference){
  .sweep[data-sweep="queued"] .sweep-rail > i,
  .sweep[data-sweep="running"] .sweep-rail > i{width:38%;opacity:1;
    animation:sweep-run 1.45s cubic-bezier(.62,.03,.35,1) infinite}
  .sweep[data-sweep="queued"] .sweep-rail > i{width:22%;opacity:.6;animation-duration:2.6s}
}

/* ==========================================================================
   SITE INSIGHT — the chart system
   --------------------------------------------------------------------------
   NOTHING HERE IS ORANGE. plumb.css allows one accent and it means OUT OF
   TRUE; a popular page is not a defect and must not be drawn like one. The one
   exception on the screen is the rule beside the floor callout, where a floor
   wearing the clothes of a total IS a reading out of true.

   THE RAMP. Chart colour is therefore a single-hue ORDINAL ramp cut from ink
   the system already has. Four steps and no more: the fifth candidate,
   --thread, measures 1.80:1 against --card in light and 1.76:1 in dark, and a
   segment nobody can see is not a segment. Measured with the product's own
   relative-luminance function, on --card, at both themes:

       --ch-1  --ink     18.60:1 light   16.53:1 dark
       --ch-2  --ink-2   10.09:1 light    8.62:1 dark
       --ch-3  --ink-3    5.58:1 light    4.52:1 dark
       --ch-4  --ink-4    3.77:1 light    3.01:1 dark   (marks only, never text)

   On the page ground --paper, which is where the KPI row's delta marks sit
   rather than on a panel, the lightest step measures 3.52:1 light and 3.16:1
   dark. test/ui.charts.test.mjs recomputes all of these from web/plumb.css on
   every run, so an edit to a token has to re-earn the numbers above.

   Every step is an ALIAS of a token plumb.css defines in BOTH themes, so no
   colour on this screen exists in only one of them — the failure this page has
   already had once, where a value defined solely inside a dark block rendered
   as nothing in light.
   ========================================================================== */
:root{
  --ch-1:var(--ink);
  --ch-2:var(--ink-2);
  --ch-3:var(--ink-3);
  --ch-4:var(--ink-4);
  --ch-grid:var(--line-soft);
  /* The heavier of the two hairlines, for the edge of a shape rather than a
     gridline behind one: 1.80:1 on --card in light and 1.76:1 in dark, against
     --ch-grid's 1.18 and 1.07. */
  --ch-axis:var(--thread);
  --ch-surface:var(--card);
}

/* The range control and the re-read button. The seg is allowed to grow so
   that at 390px it claims the row and pushes the button onto the next line —
   left to shrink instead, the two sat side by side with the seg folded into
   its two-column mobile form and 30 DAYS alone on a second row, which reads as
   a broken control rather than a wrapped one. */
.ins-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.ins-head .seg{flex:1 1 260px}
.ins-head .btn{flex:0 0 auto}

/* -------------------------------------------------------------- the floor -- */
/* The callout keeps the orange rule it has always had, and gains a heading, so
   the sentence is findable at a glance instead of being a paragraph a reader
   has to enter to discover what it is about. */
.floorcall .panel-body{padding-top:16px}
.floorcall-h{font-family:var(--serif);font-size:20px;line-height:1.2;letter-spacing:-.02em;
  margin:0 0 10px;color:var(--ink)}
.floorcall-b{font-size:13.5px;margin:0}
.floorcall-f{margin:12px 0 0}

/* THE QUALIFICATION RIDES THE FIGURE. A callout is read once; a number is read
   every time the screen is opened and is what gets quoted out of it. */
.floor-b{display:inline-block;font-family:var(--mono);font-size:8.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--flag-ink);border:1px solid var(--flag-line);
  padding:1px 5px;margin-left:5px;vertical-align:2px;cursor:help}

/* ----------------------------------------------------------- the KPI row -- */
/* Four figures, then the detail. minmax(184px) so 390px gives one per row with
   the delta mark still wide enough to read, and 1440px gives four. */
.kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(184px,1fr));gap:22px 20px;
  margin:0 0 22px}
.kpi .stat{padding-right:18px}
/* Exactly one hero on the view, in the same serif as every other figure —
   a display face here would read as decoration rather than as a reading. */
.kpi .hero .v{font-size:clamp(40px,5.6vw,52px)}
.kpi .stat .d{margin-top:8px;line-height:1.5;text-transform:none;letter-spacing:0;
  font-size:11px;max-width:34ch}
.live-d{color:var(--ink-3)}
@media (max-width:900px){
  /* Stacked, so the left rule that separates columns becomes a top rule. */
  .kpi{gap:18px}
  .kpi .stat{border-left:0;padding-left:0;padding-top:16px;border-top:1px solid var(--line-soft)}
  .kpi .stat:first-child{padding-top:0;border-top:0}
}

/* ------------------------------------------------------------- the delta -- */
/* A dumbbell: the window before at the light end of the ramp, this window at
   the dark end, on one track scaled to whichever is larger. Direction is the
   glyph and the sign, never colour. */
.dlt{margin-top:9px}
.dlt.none{font-family:var(--mono);font-size:10px;color:var(--ink-3);line-height:1.5;margin-top:9px}
.dlt-n{display:block;font-family:var(--mono);font-size:11.5px;letter-spacing:.02em;color:var(--ink);
  font-variant-numeric:tabular-nums}
.dlt-a{margin-right:6px;font-size:9px;color:var(--ink-2)}
.dlt-w{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;color:var(--ink-3);
  margin-top:5px}
.dumb{display:block;position:relative;height:10px;margin-top:7px}
.dumb i{position:absolute;display:block}
.dumb-rail{left:4.5px;right:4.5px;top:4.5px;height:1px;background:var(--ch-grid)}
.dumb-span{top:4.5px;height:1px;background:var(--ch-4)}
/* Both dots carry a 2px ring in the surface colour so they stay legible where
   they overlap — a flat period beside a busy one puts them on the same pixel.
   Positioned by their LEFT edge across (100% - 9px) rather than centred on a
   percentage: centred, the dot at 100% hung four and a half pixels past the
   tile and gave the stat its own horizontal scrollbar. */
.dumb-was,.dumb-now{width:9px;height:9px;top:0;border-radius:50%;
  box-shadow:0 0 0 2px var(--ch-surface)}
.dumb-was{background:var(--ch-4)}
.dumb-now{background:var(--ch-1)}

/* ------------------------------------------------------------ the plots --- */
/**
 * TEXT IS NEVER INSIDE A PLOT.
 *
 * Every <svg> here is preserveAspectRatio="none" with a fixed height and a
 * fluid width, so the vertical scale is exactly 1 at any viewport and only the
 * horizontal scale moves. That is what keeps a 2px visitor cap 2px at 390 and
 * at 1440 without a resize listener re-rendering the page. It also means
 * anything inside would be stretched horizontally, so the axis labels, the
 * legend and the ticks are HTML sitting around the plot — where they keep
 * their declared size instead of shrinking to six pixels on a phone.
 */
.ch{display:grid;grid-template-columns:auto minmax(0,1fr);gap:0 8px}
.ch-y{position:relative;width:34px;height:168px}
.ch-y span{position:absolute;right:0;font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;
  color:var(--ink-3);font-variant-numeric:tabular-nums;line-height:14px;white-space:nowrap}
.ch-plot{min-width:0;position:relative}
/* The plot is drawn OVER the column strip and takes no pointer events, so the
   hover target is the full-height HTML column underneath rather than a 9px
   bar somebody has to land on. */
.ch-plot svg{display:block;width:100%;position:relative;z-index:1;pointer-events:none}

/**
 * THE COLUMN STRIP: hit targets, hover, and the baseline that makes a zero
 * visible.
 *
 * A column of height zero renders as nothing at all, so the baseline hairline
 * under every column is what makes an observed zero a mark instead of a gap —
 * without it, "none" and "not counted" look identical, and telling those apart
 * is the entire product. It is HTML rather than a rect inside the plot for two
 * reasons: the plot is stretched horizontally and a per-column rule drawn in
 * it would inherit the stretch, and a hover target big enough to hit belongs
 * where the browser can size it against real pixels.
 *
 * The height is PLOT_H from web/app.js. The two have to stay equal or the
 * baseline detaches from the columns it is under.
 */
.ins-cols{position:absolute;left:0;right:0;top:0;height:168px;display:flex;z-index:0}
.ins-col{position:relative;flex:1 1 0;min-width:0;height:100%}
.ins-col::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;background:var(--line)}
.ins-col:hover{background:var(--paper-3)}

.ch-grid{fill:var(--ch-grid)}
/* fill and not background: these two are SVG marks. The legend swatches below
   are HTML and take the same colours through the same tokens. */
.ins-v{fill:var(--ch-4)}
.ins-v.is-peak{fill:var(--ch-2)}
/* Unique visitors: a 2px cap on top of its own column and joined to nothing.
   A line would let a reader run along it and read the area underneath as
   people, and the hash rotates at midnight so that number does not exist. */
.ins-u{fill:var(--ch-1)}

.ins-axis{display:flex;justify-content:space-between;margin-top:8px}
.ins-axis.slots{justify-content:flex-start}
.ins-tick{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;color:var(--ink-3)}
.ins-slot{flex:1 1 0;min-width:0;text-align:center;overflow:hidden}
.ins-legend{display:flex;gap:14px;align-items:center;flex-wrap:wrap;max-width:100%}
.ins-key{display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3);line-height:1.5}
.ins-key i{width:10px;display:block;flex:none}
.ins-key.v i{height:9px;background:var(--ink-4)}
.ins-key.u i{height:2px;background:var(--ink)}
.ch-peak{display:flex;gap:12px;align-items:center;flex-wrap:wrap}
@media (max-width:560px){
  /* The visitor key carries a full clause; on a phone it takes the whole row
     under the heading rather than squeezing the title to four characters. */
  .ins-legend{gap:8px}
  .ins-key{letter-spacing:.08em}
}

/* ---------------------------------------------------------- ranked bars --- */
/* Name and count on one line, the rule beneath spanning both columns: a fixed
   bar column at 390px leaves a URL forty pixels. Horizontal because the labels
   are paths, hosts and language tags, all of which wrap badly above a column. */
.brk{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 14px;padding:8px 0;
  align-items:baseline}
.brk-k{font-size:13.5px;color:var(--ink-2);line-height:1.4}
.brk-n{font-size:13.5px;color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.brk-p{font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;color:var(--ink-3);margin-left:8px}
/* One hue for every bar. These are nominal categories and bar length already
   carries the value; a darker-where-bigger ramp would spend the identity
   channel re-encoding what the reader can already see. */
.bar{grid-column:1/-1;height:8px;background:var(--ch-grid);display:block}
.bar i{display:block;height:100%;background:var(--ch-1);border-radius:0 4px 4px 0}

/* --------------------------------------------------------------- donut --- */
/* Fixed square, because it is the one mark on the screen that cannot be
   stretched: an ellipse would misstate every angle in it. */
.dn{display:flex;gap:26px;align-items:center;flex-wrap:wrap}
.dn-fig{position:relative;width:132px;height:132px;flex:none}
.dn-mid{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;text-align:center;pointer-events:none}
.dn-mid b{font-family:var(--serif);font-size:26px;font-weight:400;line-height:1;letter-spacing:-.02em}
.dn-mid span{font-family:var(--mono);font-size:8.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-3);margin-top:5px}
.dn-track{stroke:var(--ch-grid)}
/* Segments are separated by a 2px gap cut out of the dash, never by a stroke:
   a stroke would add ink to the chart that is not data. */
.dn-1{stroke:var(--ch-1)}
.dn-2{stroke:var(--ch-2)}
.dn-3{stroke:var(--ch-3)}
.dn-4{stroke:var(--ch-4)}
.dn-key{list-style:none;margin:0;padding:0;flex:1 1 190px;min-width:0;display:grid;gap:9px}
.dn-key li{display:grid;grid-template-columns:10px minmax(0,1fr) auto;gap:10px;align-items:center}
.dn-sw{width:10px;height:10px;display:block}
/* The ramp as a FILL, for the legend swatch and for the stacked band. The
   .dn-N rules above set `stroke`, which is the only property a donut arc has
   and the only one an HTML block ignores: the band rendered as four invisible
   flex children until these existed. */
.dn-sw.dn-1,.band-s.dn-1{background:var(--ch-1)}
.dn-sw.dn-2,.band-s.dn-2{background:var(--ch-2)}
.dn-sw.dn-3,.band-s.dn-3{background:var(--ch-3)}
.dn-sw.dn-4,.band-s.dn-4{background:var(--ch-4)}
.dn-lb{font-size:13.5px;color:var(--ink-2);line-height:1.35}
.dn-vl{font-size:13.5px;color:var(--ink);font-variant-numeric:tabular-nums;text-align:right;
  white-space:nowrap}
.dn-vl small{font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;color:var(--ink-3);
  margin-left:8px}

/* --------------------------------------------------- one ordered band ----- */
/* Screen width is the only breakdown here that is a SCALE and not a set of
   names, so it is the only place a lightness ramp carries information rather
   than repeating the bar: more pixels, more ink. The 2px gaps are surface, not
   strokes. */
.band{display:flex;gap:2px;height:30px;margin:2px 0 16px}
.band-s{display:block;min-width:3px}
.band-key{margin-top:0}
/* Not a fifth size. A client that reported no width is a measured absence
   sitting inside a measured distribution, and it wears the same hatch as the
   not-collected placard so the two read as the same kind of fact. */
.band-u,.dn-sw.band-u{background:repeating-linear-gradient(45deg,var(--ch-grid) 0 3px,
  var(--ch-axis) 3px 5px)}

/* ---------------------------------------------- no chart, and why not ----- */
/* A dimension we never collected takes the space its chart would have taken,
   hatched rather than blank. Every analytics product on earth draws a flat
   line at zero here, and a flat line at zero claims we looked and found none.
   We did not look. */
.ndrw{height:168px;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:8px;text-align:center;padding:0 16px;
  background:repeating-linear-gradient(45deg,transparent 0 7px,var(--ch-grid) 7px 8px);
  border:1px solid var(--line)}
.ndrw-t{font-family:var(--serif);font-size:19px;letter-spacing:-.02em;color:var(--ink-2);
  background:var(--ch-surface);padding:2px 10px}
.ndrw-s{font-family:var(--mono);font-size:9.5px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--ink-3);background:var(--ch-surface);padding:2px 10px}

/* ------------------------------------------ the numbers, for a reader ----- */
/* Every chart carries its own table. A screen reader must not lose the data
   because it was drawn, and this is also the relief channel the contrast rules
   ask for wherever a mark sits near the 3:1 line: the value is always
   available as text and never only as an area. */
.ch-nums{margin-top:16px;border-top:1px solid var(--line-soft);padding-top:10px}
.ch-nums summary{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);cursor:pointer;list-style:none;padding:3px 0;display:inline-block}
.ch-nums summary::-webkit-details-marker{display:none}
.ch-nums summary::before{content:'+ ';color:var(--ink-4)}
.ch-nums[open] summary::before{content:'\2212 '}
.ch-nums summary:hover{color:var(--ink)}
.ch-nums summary:focus-visible{outline:2px solid var(--flag);outline-offset:3px}
/* Wide content scrolls inside its own container; the body never scrolls
   sideways. */
.ch-scroll{overflow-x:auto;margin-top:8px;max-height:280px;overflow-y:auto}
.ch-tbl{border-collapse:collapse;width:100%;font-size:12.5px}
.ch-tbl th,.ch-tbl td{text-align:left;padding:6px 12px 6px 0;border-bottom:1px solid var(--line-soft);
  white-space:nowrap}
.ch-tbl th{font-family:var(--mono);font-size:9px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);position:sticky;top:0;background:var(--ch-surface)}
.ch-tbl td{color:var(--ink-2)}
.ch-tbl .n{text-align:right;padding-right:0;font-variant-numeric:tabular-nums;color:var(--ink)}

/* ------------------------------------------------------- live and feed ---- */
/* Not a green light. This says a live figure is on this tile, not that
   anything is healthy — there is no "true" colour in this system. */
.ins-dot{display:inline-block;width:6px;height:6px;background:var(--ink);margin-right:9px;
  vertical-align:middle}
@media (prefers-reduced-motion:no-preference){
  .ins-dot{animation:ins-pulse 2.4s ease-in-out infinite}
}
@keyframes ins-pulse{0%,100%{opacity:1}50%{opacity:.28}}
.rows.recent .row{padding-top:10px;padding-bottom:10px}

/* ========================================================================
   GROWTH OS
   One operating ledger, not a sales dashboard skin. Figures hang from a rule,
   tables remain the primary working surface, and incomplete coverage is named
   beside the number that depends on it.
   ====================================================================== */
.growth-head{margin-bottom:0}
.growth-head-actions{display:flex;gap:8px;align-items:flex-start;flex-wrap:wrap}
.growth-export{position:relative}
.growth-export>summary{list-style:none}.growth-export>summary::-webkit-details-marker{display:none}
.growth-export>div{position:absolute;right:0;z-index:5;min-width:180px;margin-top:6px;padding:7px;background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow)}
.growth-export a{display:block;padding:7px 9px;color:var(--ink);text-decoration:none;text-transform:capitalize}
.growth-export a:hover,.growth-export a:focus-visible{background:var(--paper-2)}
.growth-tabs{display:flex;gap:0;overflow-x:auto;border-bottom:1px solid var(--line);
  margin:0 0 24px;scrollbar-width:thin}
.growth-tabs a{flex:0 0 auto;padding:11px 13px 10px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--ink-3);border-bottom:2px solid transparent}
.growth-tabs a:hover{color:var(--ink)}
.growth-tabs a.on{color:var(--ink);border-bottom-color:var(--ink)}
.growth-tabs a:focus-visible{outline:2px solid var(--flag);outline-offset:-3px}

.growth-measures{display:grid;grid-template-columns:repeat(4,minmax(140px,1fr));
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-bottom:18px}
.growth-measures > div{padding:16px 18px 17px;border-right:1px solid var(--line-soft);min-width:0}
.growth-measures > div:first-child{padding-left:0}
.growth-measures > div:last-child{border-right:0}
.growth-measures .label{display:block;margin-bottom:9px}
.growth-measures strong{display:block;font-family:var(--serif);font-size:31px;line-height:1;
  font-weight:400;letter-spacing:-.025em;font-variant-numeric:tabular-nums}
.growth-measures small{display:block;margin-top:7px;color:var(--ink-3);font-size:11.5px;line-height:1.35}

.growth-coverage{display:flex;gap:10px 22px;align-items:center;flex-wrap:wrap;padding:10px 0 21px;
  font-size:12.5px;color:var(--ink-3)}
.growth-coverage b{font-weight:620;color:var(--ink)}
.growth-coverage span{font-family:var(--mono);font-size:10px;letter-spacing:.06em}
.growth-split{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(260px,.65fr);gap:20px}
.growth-stage-list{padding:10px 20px 16px}
.growth-stage-list > div{display:grid;grid-template-columns:112px minmax(60px,1fr) 34px;gap:12px;
  align-items:center;padding:7px 0;border-bottom:1px solid var(--line-soft)}
.growth-stage-list > div:last-child{border-bottom:0}
.growth-stage-list span{font-size:12.5px;text-transform:capitalize;color:var(--ink-2)}
.growth-stage-list i{display:block;height:5px;background:var(--paper-3)}
.growth-stage-list i b{display:block;height:100%;background:var(--ink);min-width:1px}
.growth-stage-list strong{font-family:var(--mono);font-size:11px;text-align:right;font-weight:500;
  font-variant-numeric:tabular-nums}
.growth-facts{display:grid;grid-template-columns:minmax(120px,.8fr) minmax(0,1fr);gap:11px 16px;margin:0}
.growth-facts dt{font-family:var(--mono);font-size:9px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-3)}
.growth-facts dd{margin:0;font-size:12.5px;color:var(--ink);overflow-wrap:anywhere}

.growth-create{margin:0 0 20px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.growth-create summary{cursor:pointer;display:inline-block;padding:11px 0;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-2);list-style:none}
.growth-create summary::-webkit-details-marker{display:none}
.growth-create summary::before{content:'+ ';color:var(--ink-3)}
.growth-create[open] summary::before{content:'\2212 '}
.growth-create summary:focus-visible{outline:2px solid var(--flag);outline-offset:3px}
.growth-form{display:grid;grid-template-columns:repeat(4,minmax(150px,1fr));gap:14px 16px;padding:7px 0 20px}
.growth-form .field{min-width:0}
.growth-form .field label{display:block;margin-bottom:6px}
.growth-authorise{display:flex;align-items:center;gap:9px;align-self:end;padding-bottom:10px;font-size:12.5px;color:var(--ink-2)}
.growth-authorise input{accent-color:var(--flag)}
.growth-wide{grid-column:1/-1}
.growth-submit{display:flex;align-items:center;gap:14px;min-height:36px}

.growth-table-panel{clip-path:none;overflow:hidden}
.growth-table-scroll{overflow:auto;max-width:100%}
.growth-table{width:100%;border-collapse:collapse;min-width:860px;font-size:12.5px}
.growth-table th{position:sticky;top:0;z-index:1;background:var(--card);padding:9px 14px;text-align:left;
  font-family:var(--mono);font-size:8.5px;letter-spacing:.15em;text-transform:uppercase;color:var(--ink-3);
  border-bottom:1px solid var(--line)}
.growth-table td{padding:12px 14px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line-soft);
  color:var(--ink-2);line-height:1.4}
.growth-table tbody tr:last-child td{border-bottom:0}
.growth-table tbody tr:hover{background:var(--paper-2)}
.growth-table td strong,.growth-table td b{display:block;color:var(--ink);font-weight:620}
.growth-table td small{display:block;margin-top:3px;max-width:42ch;color:var(--ink-3);line-height:1.4}
.growth-links{display:flex;gap:9px;flex-wrap:wrap;margin-top:6px}
.growth-links a{font-size:11.5px}
.growth-status{min-width:138px;padding:7px 27px 7px 9px;font-size:12px;text-transform:capitalize}
.growth-missing{display:inline-block;font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--flag-ink);border-bottom:1px solid var(--flag-line)}
.growth-activity .row{grid-template-columns:142px 88px minmax(0,1fr) minmax(90px,.3fr);cursor:default}
.growth-activity .row small{display:block;margin-top:3px;color:var(--ink-3);font-size:11.5px}
.growth-note{margin-top:7px;color:var(--ink)}
.growth-note summary{cursor:pointer;font:600 11px var(--sans);letter-spacing:.04em;text-transform:uppercase}
.growth-note p{margin:8px 0 0;max-width:46ch;white-space:normal;line-height:1.55}
.growth-time{font-size:10.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.growth-desk{background:var(--ink);color:var(--paper);padding:clamp(20px,3vw,34px);margin-bottom:20px}
.growth-desk .label,.growth-desk .hint,.growth-desk-head p,.growth-desk .growth-facts dt{color:color-mix(in srgb,var(--paper) 60%,transparent)}
.growth-desk-head{display:flex;justify-content:space-between;align-items:flex-start;gap:24px;padding-bottom:22px;border-bottom:1px solid color-mix(in srgb,var(--paper) 22%,transparent)}
.growth-desk-head h2{font-family:var(--serif);font-size:clamp(30px,4vw,48px);font-weight:400;line-height:1;margin:7px 0 6px;letter-spacing:-.03em}
.growth-desk-head p{margin:0}.growth-desk-head>strong{font:400 26px/1 var(--serif);white-space:nowrap}
.growth-desk-grid{display:grid;grid-template-columns:minmax(240px,.75fr) minmax(0,1.25fr);gap:clamp(24px,4vw,54px);padding:26px 0}
.growth-desk .growth-facts dd{color:var(--paper)}
.growth-desk-note{font-size:17px;line-height:1.62;max-width:54ch;margin:10px 0 8px;white-space:pre-wrap}
.growth-desk-actions{display:flex;align-items:center;gap:9px;flex-wrap:wrap;padding-top:20px;border-top:1px solid color-mix(in srgb,var(--paper) 22%,transparent)}
.growth-desk .btn{background:var(--paper);border-color:var(--paper);color:var(--ink)}
.growth-desk .btn.ghost{background:transparent;color:var(--paper)}
.growth-desk-actions .hint{margin-left:5px}

.phone-console{background:var(--ink);color:var(--paper);margin-bottom:20px;padding:clamp(20px,3vw,34px)}
.phone-console-head{display:flex;justify-content:space-between;align-items:flex-start;gap:30px;
  padding-bottom:24px;border-bottom:1px solid color-mix(in srgb,var(--paper) 22%,transparent)}
.phone-console-head .label,.phone-station .label{color:color-mix(in srgb,var(--paper) 58%,transparent)}
.phone-console-head h2{font:400 clamp(31px,4vw,50px)/1 var(--serif);letter-spacing:-.035em;margin:7px 0 8px}
.phone-console-head p{max-width:64ch;margin:0;color:color-mix(in srgb,var(--paper) 66%,transparent);line-height:1.55}
.phone-number{flex:0 0 auto;text-align:right}.phone-number .label{display:block;margin-bottom:8px}
.phone-number a,.phone-number strong{font:400 clamp(19px,2.2vw,28px)/1 var(--serif);color:var(--paper)}
.phone-console-grid{display:grid;grid-template-columns:1fr 1fr}
.phone-station{min-width:0;padding:26px 30px 0 0}
.phone-station+.phone-station{padding-left:30px;border-left:1px solid color-mix(in srgb,var(--paper) 22%,transparent)}
.phone-station-state{display:flex;align-items:center;gap:12px;margin-bottom:22px}
.phone-station-state strong{display:block;margin-top:5px;font:500 17px/1.25 var(--sans);text-transform:capitalize}
.phone-station-state small{display:block;margin-top:6px;color:color-mix(in srgb,var(--paper) 62%,transparent)}
.phone-signal{display:block;width:10px;height:10px;border:1px solid color-mix(in srgb,var(--paper) 55%,transparent);border-radius:50%}
.phone-signal.live{background:#56b381;border-color:#56b381;box-shadow:0 0 0 4px color-mix(in srgb,#56b381 18%,transparent)}
.phone-station>.btn{margin-bottom:20px}.phone-station>.btn:disabled{opacity:.5;cursor:not-allowed}
.phone-station .growth-facts{margin:0 0 22px}.phone-station .growth-facts dd{color:var(--paper)}
.phone-dial{display:grid;gap:8px;margin:0 0 18px}.phone-dial>label{font:500 10px var(--mono);letter-spacing:.12em;text-transform:uppercase;
  color:color-mix(in srgb,var(--paper) 58%,transparent)}
.phone-dial>div{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px}
.phone-dial .input{background:transparent;color:var(--paper);border-color:color-mix(in srgb,var(--paper) 30%,transparent)}
.phone-dial small,.phone-rule{color:color-mix(in srgb,var(--paper) 58%,transparent);font-size:11.5px;line-height:1.5}
.phone-rule{margin:20px 0 0;padding-top:16px;border-top:1px solid color-mix(in srgb,var(--paper) 18%,transparent)}
.phone-live-actions{display:flex;gap:8px;margin-bottom:18px;flex-wrap:wrap}
.phone-console .btn{background:var(--paper);border-color:var(--paper);color:var(--ink)}
.phone-console .btn.ghost{background:transparent;color:var(--paper)}
.phone-error{margin:0 0 18px;color:#ff9c79;font-size:12.5px;line-height:1.5}

@media (max-width:980px){
  .growth-measures{grid-template-columns:repeat(2,minmax(140px,1fr))}
  .growth-measures > div:nth-child(2){border-right:0}
  .growth-measures > div:nth-child(3),.growth-measures > div:nth-child(4){border-top:1px solid var(--line-soft)}
  .growth-measures > div:nth-child(3){padding-left:0}
  .growth-split{grid-template-columns:minmax(0,1fr)}
  .growth-form{grid-template-columns:repeat(2,minmax(150px,1fr))}
}
@media (max-width:620px){
  .growth-measures{grid-template-columns:minmax(0,1fr)}
  .growth-measures > div{padding-left:0;border-right:0;border-top:1px solid var(--line-soft)}
  .growth-measures > div:first-child{border-top:0}
  .growth-form{grid-template-columns:minmax(0,1fr)}
  .growth-wide{grid-column:auto}
  .growth-submit{align-items:flex-start;flex-direction:column}
  .growth-activity .row{grid-template-columns:1fr auto;gap:7px 12px}
  .growth-activity .row > :nth-child(3),.growth-activity .row > :nth-child(4){grid-column:1/-1}
  .growth-stage-list > div{grid-template-columns:96px minmax(50px,1fr) 28px;gap:9px}
  .growth-desk-grid{grid-template-columns:minmax(0,1fr)}
  .growth-desk-head{display:block}.growth-desk-head>strong{display:block;margin-top:14px}
  .growth-desk-actions .btn{width:100%}.growth-desk-actions .hint{margin:5px 0 0}
  .phone-console-head{display:block}.phone-number{text-align:left;margin-top:22px}
  .phone-console-grid{grid-template-columns:minmax(0,1fr)}
  .phone-station{padding:24px 0}
  .phone-station+.phone-station{padding:24px 0 0;border-left:0;border-top:1px solid color-mix(in srgb,var(--paper) 22%,transparent)}
  .phone-live-actions .btn{flex:1}.phone-dial>div{grid-template-columns:minmax(0,1fr)}
}

.ins-facts{margin:0;padding:0;list-style:none;display:grid;gap:12px}
.ins-facts li{font-size:13.5px;line-height:1.6;color:var(--ink-2);max-width:74ch;
  padding-left:15px;position:relative}
.ins-facts li::before{content:'';position:absolute;left:0;top:9px;width:6px;height:1px;
  background:var(--ink-4)}
