/* Roboto Condensed, served from here rather than from Google.
   It was the only third party this application talked to, which meant every
   page load reported a plant engineer's IP address to a company with no part
   in the trial. Self-hosting also lets the policy in app/security.py say
   style-src 'self' with no second origin to trust.

   One file per subset, not one per weight: this is a variable font, so 300
   through 700 come out of the same bytes. font-display:swap keeps text
   readable while it loads rather than leaving a blank page. */
@font-face{
  font-family:'Roboto Condensed';
  font-style:normal;
  font-weight:300 700;
  font-display:swap;
  src:url('/static/fonts/roboto-condensed-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Roboto Condensed';
  font-style:normal;
  font-weight:300 700;
  font-display:swap;
  src:url('/static/fonts/roboto-condensed-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* BlastWave Brand Guidelines 2025 (Drive: • 2025 BRAND ASSETS / 05).
   Primary palette, verbatim:
     BlastWave Gold  #B79B5E   key accent — highlights and CTA buttons
     BlastWave Red   #AA0E1D   secondary accent — highlights, never body
     BlastWave Black #414042   text at 100%, light tints for backgrounds
   Roboto Condensed, tracking tightened, 10px 0 notch.

   The guide asks for a 60/30/10 balance: dominant, secondary, accent. Gold
   carries actions here and red is kept scarce, which is what puts us inside it.

   On dark, the guide lightens the artwork colors and warns that brand red
   "has a tendency to get lost". The favicon's own dark variant is the source
   for --gold and --logo-red below. --red is a further-lightened tint of the
   2025 red: #AA0E1D on #414042 is 1.37:1, unreadable, and even the lightened
   artwork red only reaches 1.64:1. Red appears here only as display headings
   and a 3px rule, so the 3:1 threshold applies and this clears it at 3.27:1. */
:root{
  --ink:#414042; --red:#AA0E1D; --gold:#B79B5E; --gold-deep:#9c8248;
  --logo-gold:#B79B5E; --logo-red:#AA0E1D;
  /* Emphasis in headings. Gold, not red: the logotype already carries the red,
     and a second red beside it reads as a near-miss rather than a match. Gold
     is also what the guide calls the key accent, red only the secondary one.
     Light mode uses the deeper gold — #B79B5E on white is 2.68:1, under the
     3:1 that display text needs, while this is 3.68:1. */
  --em:#9c8248;
  --band:#F7F7F7; --line:#e3e1de; --soft:#757476; --gold-tint:#fbf7ef;
  --card:#fff; --bg:#fff; --ok:#2f6a45; --notch:10px 0;
  --shadow:0 1px 2px rgba(65,64,66,.04), 0 12px 30px rgba(65,64,66,.07);
  --lift:0 6px 16px rgba(65,64,66,.10), 0 18px 44px rgba(65,64,66,.09);

  /* Secondary palette. The guide assigns one color to each of the three
     product areas and says to use it "as a replacement for the BlastWave brand
     red when covering the subject". Those three areas are exactly the first
     three proof templates (§11), so a generated plan can be colour-coded by
     what it proves without inventing anything. */
  --cloaking:#00A9A5; --remote-access:#A34779; --segmentation:#11A1DC;

  /* ------------------------------------------------------------------ scale
     Every size, height and gap in the application comes from this block.

     It was written after the fact, against a stylesheet that had grown 27
     distinct font sizes, 7 letter-spacings and 9 card paddings — sizes like
     .92rem and .98rem and 1.02rem sitting a hair apart with no rule saying
     which belonged where. Nothing looked broken on its own page; put two of
     those pages side by side and the whole thing read as approximate.

     Each size answers a question rather than a preference: how big is a page
     title, a card title, a row title, the paragraph under a title, prose, and
     data set beside data. Every page title in the application is the same size
     — they had been split between an h1 on the trial page and an h2 everywhere
     else, which is two sizes doing one job. Two sizes are uppercase, one for
     things you press and one for labels that name things, and both take the
     same tracking: two letter-spacings on one screen is the kind of difference
     nobody can name but everybody sees. */
  --fs-display:2.8rem;  /* the page's title, h1, on every page */
  --fs-card:1.55rem;    /* the heading on a card or a section, h2 */
  --fs-title:1.2rem;    /* a roll-up, a row, a tile */
  --fs-lead:1.15rem;    /* the paragraph under a title */
  --fs-body:1.05rem;    /* prose inside a card, and the questions */
  --fs-quiet:.95rem;    /* data beside data — never a sentence */
  --fs-action:.8rem;    /* uppercase, on something you press */
  --fs-micro:.72rem;    /* uppercase, naming something */
  --ls-caps:1.5px;      /* every uppercase run, without exception */

  /* One height for every field and button, so a row of mixed controls lines up
     without anyone tuning padding per control. */
  --ctl:3.25rem;

  /* One width for every page in the application. Wide enough that a Gateway
     asks its six questions on one line, narrow enough that a paragraph filling
     it is still a paragraph. Pages used to carry three different values and a
     page whose content stopped short of its own frame read as off-centre. */
  --page:64rem;

  --stack:1rem;             /* between sibling cards */
  --block:2.5rem;           /* between the blocks of a page */
  --pad-card:1.3rem 1.5rem; /* inside a card */
  --pad-row:1rem 1.5rem;    /* inside a one-line row */
  --pad-band:1rem 1.2rem;   /* inside a tinted note */
}
@media (prefers-color-scheme:dark){
  :root{--ink:#f3f2f0;--red:#EA6674;--gold:#C5AB71;--gold-deep:#dcc48f;
    --logo-gold:#C5AB71;--logo-red:#BA2125;--em:#C5AB71;
    --band:#333235;--line:#4d4b50;--soft:#a9a7a4;--gold-tint:#3b3529;
    --card:#3a383c;--bg:#414042;--ok:#7bbd93;
    --shadow:0 1px 2px rgba(0,0,0,.3), 0 12px 30px rgba(0,0,0,.25);
    --lift:0 6px 16px rgba(0,0,0,.35), 0 18px 44px rgba(0,0,0,.3);}
}
*{box-sizing:border-box}
/* The guide asks for Roboto Condensed set slightly tighter than default —
   -20 in InDesign, which is -0.02em on the web. */
body{margin:0;background:var(--bg);color:var(--ink);letter-spacing:-.02em;
  font:400 17px/1.5 "Roboto Condensed","Helvetica Neue Condensed","Arial Narrow",
       -apple-system,BlinkMacSystemFont,sans-serif;-webkit-font-smoothing:antialiased}

/* Slim vertical padding because the logotype file already includes the
   exclusion zone; .9rem on top of it left the bar looking hollow. */
.masthead{background:#414042;padding:.35rem 1.75rem;display:flex;align-items:center;gap:1rem}
/* Height, not width: the artwork carries its own exclusion zone, so the visible
   logo is about half the box. 58px here reads as roughly 30px of logo. */
.wordmark{height:58px;width:auto;display:block}
.masthead .who{margin-left:auto;color:#b8b6b3;font-size:var(--fs-quiet);font-weight:300;
  display:flex;align-items:center;gap:1rem}
.masthead form{margin:0}
.masthead button{appearance:none;background:none;border:0;font-family:inherit;color:#b8b6b3;cursor:pointer;padding:0}
.masthead button:hover{color:#fff}
/* Outlined so it reads as a thing you can press, rather than as a third piece
   of masthead text. Still quiet — it sits above every page in the application
   and must never compete with what the page is actually for. */
.masthead button.helpme{border:1.5px solid #6b6a68;border-radius:var(--notch);
  padding:.3rem .8rem;color:#d6d4d1;white-space:nowrap}
.masthead button.helpme:hover{border-color:var(--gold);color:var(--gold)}
/* The address is the first thing to go: it identifies the session, and on a
   narrow screen the two controls are worth more than the label. */
@media (max-width:34rem){
  .masthead{padding:.35rem 1rem;gap:.6rem}
  .masthead .who{gap:.7rem}
  .masthead .who > span{display:none}
  /* Both controls have to fit on one line beside the logotype, and the bar
     doubling in height to hold a wrapped label costs more than the type size. */
  .wordmark{height:44px}
  .masthead button.helpme{padding:.28rem .6rem}
}

.shell{max-width:var(--page);margin:0 auto;padding:3.5rem 1.5rem 6rem}
/* A centred page is one short column with nothing to balance it horizontally,
   so it needs the vertical room instead. */
.shell.center{text-align:center;max-width:34rem;padding-top:5rem}

h1{font-size:var(--fs-display);line-height:1;font-weight:600;margin:0 0 1.25rem;letter-spacing:-.01em}
h1 .em{color:var(--em);display:block}
/* A title that is one sentence rather than a greeting over a statement. The
   block .em above exists to stack two lines; here the emphasis is one word
   inside the line and has to stay in it. */
h1.oneline .em{display:inline}
h2{font-size:var(--fs-card);line-height:1.15;font-weight:600;margin:0 0 .6rem}
h2 .em{color:var(--em)}
/* No measure of its own. This is the paragraph that used to stop two thirds of
   the way across a card and leave a ragged right edge nothing else on the page
   shared — the single most visible piece of the old arrangement. It ends where
   the column ends, like every other paragraph. */
p.lead{font-size:var(--fs-lead);font-weight:300;color:var(--ink);
  margin:0 auto var(--block)}
/* Flush left under a left-aligned title. Only the centred pages want the auto
   margins, and every other page was overriding them one inline style at a time
   — ten of them, which is how a stylesheet loses an argument with itself. */
.shell:not(.center) p.lead{margin-left:0}
.mailed{font-weight:600}

/* The logotype leading a centred page. No plate: signin.html hands the theme
   the artwork drawn for it. The file's own exclusion zone is most of the
   breathing room, so the margin below is smaller than it looks. */
.heromark{display:block;margin:0 auto 2.25rem}
.heromark img{display:block;width:390px;max-width:100%;height:auto;margin:0 auto}

.mark{margin:0 auto 2rem;width:96px;height:96px;border-radius:var(--notch);
  background:var(--gold-tint);border:2px solid var(--gold);display:grid;place-items:center}
.mark svg{width:48px;height:48px;stroke:var(--gold-deep);stroke-width:1.5;fill:none;
  stroke-linecap:round;stroke-linejoin:round}

input[type=email]{width:100%;font:inherit;font-size:var(--fs-lead);font-weight:300;
  padding:1rem 1.1rem;border:2px solid var(--line);border-radius:var(--notch);
  background:var(--card);color:var(--ink);text-align:center}
input:focus{outline:none;border-color:var(--gold)}
::placeholder{color:var(--soft);opacity:.8}

.btn{appearance:none;font-family:inherit;padding:1rem 2.5rem;border-radius:var(--notch);border:0;background:var(--gold);color:#fff;cursor:pointer;margin-top:1.25rem}
.btn:hover{filter:brightness(1.08)}
/* A link wearing the button style. Needs the box model back, and needs to beat
   `.shell a`, which otherwise paints the label gold on gold — the button looks
   disabled rather than styled.

   `a.btn` alone does not beat it: both are one class and one element, so the
   later rule wins on source order and `.shell a` is further down. The second
   selector is the one that actually carries this; the first only covers a
   button that lives outside a shell. */
a.btn, .shell a.btn{text-decoration:none;color:#fff}

/* One height for every control in the application, stated once here.

   Inside a single row they had been four different ones — a text input at
   54.8px, a select at 51.1, a checkbox box at 47.2 and the button at 40.1 —
   because each was sized by its own font and padding with nothing tying them
   together. Set on the token rather than per control, so a change to any one
   font size cannot pull a row apart again, and so a field on one page is the
   same object as a field on the next. */
input.t,select.t,input[type=email],.btn,.checkrow{height:var(--ctl)}
input.t,select.t,input[type=email]{padding-block:0}
.btn,a.btn,.shell a.btn{padding-block:0;display:inline-flex;align-items:center;
  justify-content:center}

/* --------------------------------------------------------------- primitives
   Five shapes the whole application is built from.

   Each of these was written out in full wherever it was wanted — 160
   declarations saying the same thing in 39 rules — and that is how one card
   ends up 2px from another with nobody able to say which is right. A component
   rule further down now carries only what makes it different: a colour, a
   margin, a rule down one edge.

   These come first deliberately. A component that genuinely needs its own
   answer says so below and wins on source order, which makes the exception
   visible as an exception. */

/* A card. Anything that holds content on its own ground. */
.trial,.panel,.proof,.proofcard,.trialrow,.rollup,.tile,.doc,
.whatsnext.quiet-panel{background:var(--card);border:2px solid var(--line);
  border-radius:var(--notch)}

/* A note. Tinted, ruled down one edge, always about the page it sits on. */
.error,.empty,.progress-note,.danger form,.edit form{
  background:var(--gold-tint);padding:var(--pad-band);
  border-left:3px solid var(--gold);border-radius:var(--notch)}
/* Red for the two that report a problem rather than a state. */
.error,.danger form{border-left-color:var(--red)}

/* Uppercase, naming a thing. */
.eyebrow,.prog .n,.trial .phase,.trialrow .phase,.task .flags span,
.edit summary,.danger summary,.doc h4,.doc-close,.inv button,.inv .role,
.devices button,.devices th,.devices .tag,.fld > span,.rollup summary .c,
.proofcard .count,.proofcard .verdict,.whatsnext h3,.panel h3,
.timeline .lbl,.lenses a,.chip,label.f{font-size:var(--fs-micro);font-weight:600;
  letter-spacing:var(--ls-caps);text-transform:uppercase}

/* Uppercase, on a thing you press. */
.btn,.back,.answer,.masthead button{font-size:var(--fs-action);font-weight:600;
  letter-spacing:var(--ls-caps);text-transform:uppercase}

/* A button that is really a text link: no box, and no weight of its own. */
.back,.doc-close,.inv button,.devices button{appearance:none;background:none;
  border:0;padding:0;font-family:inherit;cursor:pointer}

/* The reassurance under the sign-in form. Named .assure rather than .why: it
   was .why, and so is the paragraph explaining a checklist item, and the two
   are not the same object. The sign-in list capped itself at 26rem, which is
   right for a centred column and was silently squeezing every explanation on
   the readiness page to the same width. Two components cannot share a class
   name and only one of them be right. */
.assure{display:flex;flex-direction:column;gap:.9rem;margin:2.5rem auto 0;max-width:26rem;
  text-align:left}
.assure div{display:flex;gap:.85rem;align-items:flex-start;font-size:var(--fs-body);
  font-weight:300;color:var(--soft)}
.assure strong{color:var(--ink);font-weight:600}
.assure svg{width:20px;height:20px;stroke:var(--gold);stroke-width:2;fill:none;flex:none;
  margin-top:.2rem;stroke-linecap:round;stroke-linejoin:round}

.error{border-left:3px solid var(--red);margin:0 0 var(--stack);font-size:var(--fs-body);font-weight:300;text-align:left}

.eyebrow{color:var(--gold);margin:0 0 .6rem}
.trial{padding:var(--pad-card);margin:0 0 var(--stack);display:flex;align-items:center;gap:1rem}
.trial .nm{font-size:var(--fs-title);font-weight:600;line-height:1.2}
.trial .meta{font-size:var(--fs-quiet);font-weight:300;color:var(--soft)}
.trial .phase{margin-left:auto;color:var(--gold-deep);border:1.5px solid var(--gold);padding:.2rem .6rem}
.empty{border-left:3px solid var(--gold);font-size:var(--fs-body);font-weight:300}
@media (max-width:32rem){ h1{font-size:2.1rem} .shell{padding:2.5rem 1.1rem 4rem} }

/* ---- forms and panels (internal screens) ---- */
.field{margin:0 0 1.25rem;text-align:left}
label.f{display:block;margin:0 0 .3rem;color:var(--soft)}
input.t,select.t{width:100%;font:inherit;font-size:var(--fs-body);font-weight:300;
  padding:.8rem .9rem;border:2px solid var(--line);border-radius:var(--notch);
  background:var(--card);color:var(--ink);text-align:left}
input.t:focus,select.t:focus{outline:none;border-color:var(--gold)}
.hintline{font-size:var(--fs-body);font-weight:300;color:var(--soft);margin:.35rem 0 0}
.hintline strong{color:var(--ink);font-weight:600}

.permit{display:flex;gap:.8rem;align-items:flex-start;background:var(--gold-tint);
  border-left:3px solid var(--gold);padding:1rem 1.15rem;margin:0 0 1rem;
  font-size:var(--fs-body);font-weight:300;text-align:left;cursor:pointer}
.permit input{margin-top:.25rem;flex:none;width:18px;height:18px;accent-color:var(--gold-deep)}
/* The authorisation only means anything once something other than cloud is
   chosen, so it stays hidden until then. `option:checked` tracks the select
   live, which is why this needs no script.

   Guarded by @supports on purpose: where :has() is missing the rules never
   apply and the box stays visible, which is the safe direction to fail. A
   hidden checkbox would leave a sales manager unable to authorise a customer
   who genuinely cannot use cloud, and the database would refuse the trial with
   no way to satisfy it. */
@supports selector(:has(*)) {
  .permit{display:none}
  form:has(select[name="hosting_mode"] option:checked:not([value="cloud"])) .permit{display:flex}
}

.panel{padding:var(--pad-card);margin:0 0 var(--stack);text-align:left}
.panel h3{margin:0 0 .9rem;color:var(--soft)}
.kv{display:flex;justify-content:space-between;gap:1rem;padding:.45rem 0;
  border-bottom:1px solid var(--line);font-size:var(--fs-body);font-weight:300}
.kv:last-of-type{border-bottom:0}
.kv strong{font-weight:600}

.inviterow{display:flex;gap:.6rem;margin:1rem 0 0;flex-wrap:wrap}
.inviterow input.t{flex:1;min-width:14rem}
.inviterow select.t{width:auto}
.btn.small{margin-top:0;padding:0 1.5rem;font-size:var(--fs-action)}
.shell a{color:var(--gold-deep)}

/* --------------------------------------------------------------- intake
   The big-icon question screens. One question per screen, tiles chosen with
   the keyboard or the mouse, no JavaScript: each tile is a label wrapping its
   own radio or checkbox, so selection state is the input's and `:has()` does
   the styling. A form that works without script is also a form that cannot get
   stuck halfway through on a locked-down plant laptop. */
.prog{display:flex;align-items:center;gap:1rem;margin:0 0 3rem}
.prog .bar{flex:1;height:4px;background:var(--line);overflow:hidden}
.prog .bar i{display:block;height:100%;background:var(--gold);
  transition:width .45s cubic-bezier(.4,0,.2,1)}
.prog .n{color:var(--soft);white-space:nowrap}

/* Progress widths as classes, not inline style attributes. A style
   attribute would force 'unsafe-inline' into style-src, and the whole
   value of the policy in app/security.py is that it needs no such
   word anywhere. Rounded to five per cent, which no eye resolves. */
.bar i.w0{width:0%}
.bar i.w5{width:5%}
.bar i.w10{width:10%}
.bar i.w15{width:15%}
.bar i.w20{width:20%}
.bar i.w25{width:25%}
.bar i.w30{width:30%}
.bar i.w35{width:35%}
.bar i.w40{width:40%}
.bar i.w45{width:45%}
.bar i.w50{width:50%}
.bar i.w55{width:55%}
.bar i.w60{width:60%}
.bar i.w65{width:65%}
.bar i.w70{width:70%}
.bar i.w75{width:75%}
.bar i.w80{width:80%}
.bar i.w85{width:85%}
.bar i.w90{width:90%}
.bar i.w95{width:95%}
.bar i.w100{width:100%}

.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(11.5rem,1fr));gap:1rem}
.grid.two{grid-template-columns:repeat(auto-fit,minmax(19rem,1fr))}
.rows{display:grid;grid-template-columns:repeat(auto-fit,minmax(21rem,1fr));gap:.9rem}

.tile{position:relative;padding:2rem 1.15rem 1.6rem;text-align:center;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;gap:1rem;overflow:hidden;
  transition:border-color .18s,box-shadow .18s,transform .18s,background .18s}
.tile:hover{border-color:var(--gold);box-shadow:var(--lift);transform:translateY(-3px)}
/* The input is the source of truth for selection; it is only visually removed,
   so it keeps its place in the tab order and its accessible name. */
.tile input{position:absolute;opacity:0;width:1px;height:1px;margin:0}
.tile:has(input:focus-visible){outline:3px solid var(--gold);outline-offset:2px}
.tile:has(input:checked){border-color:var(--gold);background:var(--gold-tint);
  box-shadow:var(--shadow)}
.tile svg.pic{width:54px;height:54px;stroke:var(--ink);stroke-width:1.35;fill:none;
  stroke-linecap:round;stroke-linejoin:round;opacity:.75;transition:stroke .18s,opacity .18s}
.tile:hover svg.pic{opacity:1}
.tile:has(input:checked) svg.pic{stroke:var(--gold-deep);opacity:1}
.tile .lab{font-size:var(--fs-title);font-weight:600;line-height:1.2}
.tile .say{font-size:var(--fs-body);font-weight:300;color:var(--soft);line-height:1.4;margin-top:-.5rem}
.tick{position:absolute;top:-2px;right:-2px;width:30px;height:30px;background:var(--gold);
  display:none;place-items:center;border-radius:0 0 0 10px}
.tile:has(input:checked) .tick{display:grid}
.tick svg{width:15px;height:15px;stroke:#fff;stroke-width:2.6;fill:none;
  stroke-linecap:round;stroke-linejoin:round}

.rows .tile{flex-direction:row;text-align:left;align-items:center;gap:1.25rem;
  padding:1.35rem 1.4rem}
.rows .tile svg.pic{width:42px;height:42px;flex:none}
.rows .tile .tx .lab{font-size:var(--fs-title);margin-bottom:.1rem;display:block}
.rows .tile .tx .say{margin-top:0;font-size:var(--fs-body);display:block}

/* Back on the left, forward on the right, which is the direction the whole
   sequence runs. `margin-left:auto` rather than space-between so the primary
   action still sits right on the first screen, where there is no Back. */
.nav{display:flex;align-items:center;gap:1.5rem;margin-top:2.75rem}
.nav .btn{margin-top:0;margin-left:auto}
.back{color:var(--soft);padding:.5rem 0;text-decoration:none}
.back:hover{color:var(--ink)}
/* Every way out of a page, at the top of it. Leaving is something a reader may
   want at any moment and should never have to scroll for; saving or continuing
   is the end of the work and stays at the foot, alone and on the right.
   `.nav .btn` already pushes it there with margin-left:auto.

   The colour needs saying twice because `.shell a` — one class, one element —
   beats a bare `.back`, and would otherwise paint these gold like a link in
   running text. */
.back.up{display:inline-block;margin:0 0 1.2rem;padding-top:0}
.shell a.back{color:var(--soft)}
.shell a.back:hover{color:var(--ink)}

/* ------------------------------------------------------- the generated plan
   The SA's view: every task, editable. The colour on each proof is the brand's
   own — the 2025 secondary palette assigns one to each of Cloaking, Remote
   Access, and Segmentation, so a plan is colour-coded by what it proves without
   anything being invented. Quick Start has no feature colour and takes gold. */
/* Nothing caps its own width any more. A page is one column, every block in it
   runs the full width of that column, and a paragraph ends where the card it
   sits in ends. The two-tier arrangement this replaces — a 76rem frame holding
   56rem cards holding 44rem text — gave one screen three different right-hand
   edges, and the eye reads three edges as three mistakes rather than as a
   deliberate measure. */

.proof{padding:var(--pad-card);margin:0 0 var(--stack);border-left-width:5px;border-left-color:var(--gold)}
.proof.feature-cloaking{border-left-color:var(--cloaking)}
.proof.feature-remote_access{border-left-color:var(--remote-access)}
.proof.feature-segmentation{border-left-color:var(--segmentation)}
.proof h3{margin:0 0 .35rem;font-size:var(--fs-card);font-weight:600;line-height:1.15}
.proof .proves{margin:0 0 .7rem;font-size:var(--fs-body);font-weight:300;color:var(--ink)}
.proof .because{margin:0;font-size:var(--fs-body);font-weight:300;color:var(--soft)}
.chip{display:inline-block;border:1px solid var(--line);padding:.05rem .5rem;margin:0 .15rem;color:var(--gold-deep)}

.tasks{list-style:none;counter-reset:t;margin:1.25rem 0 0;padding:0}
.task{counter-increment:t;position:relative;padding:1rem 0 1rem 2.6rem;
  border-top:1px solid var(--line)}
.task::before{content:counter(t);position:absolute;left:0;top:1rem;width:1.7rem;
  height:1.7rem;display:grid;place-items:center;border:1.5px solid var(--line);
  border-radius:50%;font-size:var(--fs-quiet);font-weight:600;color:var(--soft)}
.task.state-successful::before{border-color:var(--ok);color:var(--ok)}
.task.state-failed::before{border-color:var(--red);color:var(--red)}
.task .instruction{margin:0 0 .3rem;font-size:var(--fs-body);line-height:1.35}
.task .criterion{margin:0 0 .5rem;font-size:var(--fs-body);font-weight:300;color:var(--soft)}
.task .criterion strong{color:var(--ink);font-weight:600}
.task .flags{margin:0;display:flex;flex-wrap:wrap;gap:.4rem;align-items:center}
.task .flags span{padding:.15rem .5rem;border:1.5px solid var(--line);color:var(--soft)}
.who-blastwave{border-color:var(--gold)!important;color:var(--gold-deep)!important}
.who-customer{border-color:var(--segmentation)!important;color:var(--segmentation)!important}
.who-partner{border-color:var(--remote-access)!important;color:var(--remote-access)!important}
/* §4: the tasks that pass when nothing happens are the single most common place
   a customer reports a fault that is a correct result. Marked, not implied. */
.task.negative .neg{border-color:var(--cloaking)!important;color:var(--cloaking)!important}

.edit{margin-top:.7rem}
.edit summary{color:var(--soft);cursor:pointer}
.edit summary:hover{color:var(--ink)}
.edit form{margin-top:.9rem;border-radius:var(--notch)}
.edit textarea.t{width:100%;font:inherit;font-size:var(--fs-body);font-weight:300;padding:.7rem .8rem;
  border:2px solid var(--line);border-radius:var(--notch);background:var(--card);
  color:var(--ink);resize:vertical}
.pair{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
@media (max-width:34rem){ .pair{grid-template-columns:1fr} }

/* One invitation, one line: address, where it stands, and the only action it
   has. Stacking these was fine for a single invitation and would have read as a
   wall for five. */
.inv{display:flex;align-items:baseline;gap:1rem;padding:.5rem 0;
  border-bottom:1px solid var(--line);font-size:var(--fs-body)}
.inv:last-of-type{border-bottom:0}
.inv .addr{flex:1;min-width:0;overflow-wrap:anywhere}
.inv .role{color:var(--soft);white-space:nowrap}
.inv .state{font-weight:600;white-space:nowrap}
.inv .state-expired,.inv .state-revoked{color:var(--soft);font-weight:400}
.inv .state-joined{color:var(--ok)}
.inv form{margin:0;flex:none}
/* Resending is routine, not a recovery step, so it stays a quiet action rather
   than competing with Invite. */
.inv button{color:var(--gold-deep);white-space:nowrap}
.inv button:hover{color:var(--ink)}
@media (max-width:34rem){
  .inv{flex-wrap:wrap;gap:.35rem 1rem}
  .inv .addr{flex:1 0 100%}
}

/* ------------------------------------------------- the customer's plan view
   The same rows the architect edits, presented as claims rather than as work.
   No states, no assignees, no step text — those belong to the guided setup,
   one at a time, not to a wall on the screen after answering five questions. */
.proofcard{border-left-width:5px;border-left-color:var(--gold);padding:var(--pad-card);margin:0 0 var(--stack)}
.proofcard.feature-cloaking{border-left-color:var(--cloaking)}
.proofcard.feature-remote_access{border-left-color:var(--remote-access)}
.proofcard.feature-segmentation{border-left-color:var(--segmentation)}
.proofcard h2{margin:0 0 .5rem}
.proofcard .claim{margin:0 0 .9rem;font-size:var(--fs-body);font-weight:300;line-height:1.45}
/* Their own sentence, handed back. Set apart so it reads as a quotation of the
   customer rather than as more of our copy. */
.proofcard .yours{margin:0 0 .9rem;padding-left:1rem;border-left:2px solid var(--gold);
  font-size:var(--fs-body);font-weight:300;font-style:italic;color:var(--soft)}
.proofcard .count{margin:0;color:var(--soft)}

/* Leads the page rather than trailing it: the firewall conversation is the long
   pole on nearly every trial, so the ask sits above the reading. */
.whatsnext{background:var(--gold-tint);border-radius:var(--notch);padding:var(--pad-card);
  margin:0 0 var(--block)}
.whatsnext h3{margin:0 0 .6rem;color:var(--gold-deep)}
.whatsnext p{margin:0 0 .7rem;font-size:var(--fs-body);font-weight:300;line-height:1.5}
.whatsnext p:last-child{margin-bottom:0}
.whatsnext .quiet{font-size:var(--fs-body);color:var(--soft)}
.whatsnext .actions{display:flex;gap:.6rem;flex-wrap:wrap;margin:1.1rem 0 0}
/* Four separate errands, not a row of alternatives. Wrapping put two on one
   line and two on the next, in an order that meant nothing. Stacked and left
   aligned, each is its own line and the widths stop competing. */
.whatsnext .actions.stacked{flex-direction:column;align-items:flex-start}

/* The end of the phase, at the end of the page. Disabled says "not yet", and
   the line under it says what is left — a greyed control with no explanation is
   a puzzle, and the reader is the one person who can resolve it. */
.nextphase{margin:var(--block) 0 0;padding-top:var(--block);border-top:2px solid var(--line)}
.nextphase .btn{margin-top:0}
.nextphase .btn[disabled]{background:none;color:var(--soft);cursor:not-allowed;
  box-shadow:inset 0 0 0 2px var(--line)}
.nextphase .btn[disabled]:hover{filter:none}
.nextphase .hintline{margin:.7rem 0 0}
.whatsnext ul.loose{margin:0 0 .7rem;padding-left:1.1rem;font-size:var(--fs-body);
  font-weight:300;line-height:1.5}
.whatsnext ul.loose li{margin:.2rem 0}
/* Archive asks for nothing, so its panel does not use the gold that everywhere
   else in this box means "here is the thing to do". It takes the card surface
   instead, declared with the other cards above. */
.whatsnext.quiet-panel h3{color:var(--soft)}

/* How a proof turned out, in a word. The number is underneath for anyone who
   wants it; this is the line somebody repeats in a meeting. */
.proofcard .verdict{margin:0 0 .7rem;color:var(--soft)}
.proofcard .verdict.v-proved{color:var(--ok)}
.proofcard .verdict.v-failed{color:var(--red)}
.proofcard .verdict.v-running{color:var(--gold-deep)}

/* The phase control on the internal page. A select and a button inside a .kv
   row, which is otherwise a label and a value. */
.phaseset{margin:0;gap:.7rem;align-items:center}
.phaseset select.t{width:auto;flex:1;min-width:8rem;font-size:var(--fs-quiet)}
.phaseset .btn{margin-top:0;padding:0 1.1rem;font-size:var(--fs-action)}

/* Secondary action. Outlined rather than greyed: these are things the reader may
   legitimately do, just not the one being suggested, and a disabled-looking
   control reads as broken. Uses inset box-shadow for the rule so the border does
   not change the box size against a solid sibling. */
.btn.ghost{background:transparent;box-shadow:inset 0 0 0 2px var(--gold)}
.btn.ghost,a.btn.ghost,.shell a.btn.ghost{color:var(--gold-deep)}
.btn.ghost:hover{background:var(--card);filter:none}

/* ------------------------------------------------------ internal trial lists
   Two lenses on the same list — every trial, or the ones you manage. The tabs
   exist because the pages are otherwise identical, and an unlabelled pair of
   near-identical screens is worse than either alone. */
.lenses{display:flex;gap:.4rem;margin:0 0 var(--block);border-bottom:2px solid var(--line)}
.lenses a{padding:.5rem .9rem;color:var(--soft);text-decoration:none;border-bottom:3px solid transparent;margin-bottom:-2px}
.lenses a:hover{color:var(--ink)}
.lenses a.on{color:var(--gold-deep);border-bottom-color:var(--gold)}

.trialrow{display:flex;align-items:baseline;gap:1rem;padding:var(--pad-row);margin:0 0 var(--stack);text-decoration:none;color:var(--ink);transition:border-color .15s,box-shadow .15s}
.trialrow:hover{border-color:var(--gold);box-shadow:var(--shadow)}
.trialrow .nm{flex:1;min-width:0;font-size:var(--fs-title);font-weight:600}
.trialrow .who,.trialrow .steps,.trialrow .meta{font-size:var(--fs-quiet);font-weight:300;
  color:var(--soft);white-space:nowrap}
/* Fixed width so the column lines up down the list even when a trial has no
   number to show. A percentage that shifts left and right by row is a column
   you have to read rather than scan. */
.trialrow .pct{flex:0 0 2.6rem;text-align:right;font-size:var(--fs-quiet);font-weight:600;
  color:var(--ink);white-space:nowrap}
.trialrow .who em{font-style:normal;color:var(--red)}
.trialrow .phase{color:var(--gold-deep);border:1.5px solid var(--gold);padding:.2rem .6rem;white-space:nowrap}
/* The customer's row carries none of the internal columns, so it can breathe. */
.trialrow.customer{padding:var(--pad-row)}
.trialrow.customer .meta{margin-left:auto}
@media (max-width:44rem){
  .trialrow{flex-wrap:wrap;gap:.3rem .9rem}
  .trialrow .nm{flex:1 0 100%}
}

/* What a step records. The tracker's Asset Topology tab asked for all of this at
   once, in the abstract, which is why nobody ever finished one. Attached to the
   step that needs it, each field has an obvious reason to exist. */
.task .asks{margin:.5rem 0 0;font-size:var(--fs-body);font-weight:300;color:var(--soft)}
.task .asks strong{color:var(--ink);font-weight:600}
.ask{display:inline-block;border:1px solid var(--line);border-radius:var(--notch);
  padding:.05rem .5rem;margin:.15rem .2rem .15rem 0;font-size:var(--fs-quiet)}

/* Deleting a trial. Folded away behind a summary and styled apart from every
   other action, because the cost of an accidental click here is a plan, a set of
   answers, and a topology somebody spent a call collecting. */
.danger{margin-top:1.4rem;border-top:1px solid var(--line);padding-top:1rem}
.danger summary{color:var(--soft);cursor:pointer}
.danger summary:hover{color:var(--red)}
.danger p{margin:.9rem 0 0;font-size:var(--fs-body);font-weight:300;line-height:1.5}
.danger form{margin-top:var(--stack);border-left:3px solid var(--red);border-radius:var(--notch)}
.danger input.t{margin-bottom:.9rem}
.btn.destructive{background:var(--red);color:#fff}

/* ------------------------------------------------------- the guide's diagram
   Shown at the top of each stage, exactly as the Quick Start does it: the whole
   lab, with what you have configured in full colour and what you have not
   greyed out. Reading back through the steps to work out where you are is the
   thing this replaces. */
/* Fills the column, like every other block on the page. Drawn at 798px and
   scaled up from there, which takes the labels with it — the alternative was a
   diagram that stopped short of the roll-ups underneath it for no reason a
   reader could see. */
.topology{display:block;width:100%;height:auto;margin:0 0 .6rem}
.topology .node rect{fill:var(--card);stroke:var(--line);stroke-width:2}
.topology .node text{fill:var(--soft);font-family:inherit;font-size:15px;
  font-weight:600;text-anchor:middle;letter-spacing:-.02em}
.topology .node.lit rect{stroke:var(--gold);fill:var(--gold-tint)}
.topology .node.lit text{fill:var(--ink)}
/* A dashed wire is the guide's own convention: the path exists, but no policy
   allows anything across it yet. */
.topology .wire{fill:none;stroke:var(--line);stroke-width:2;stroke-dasharray:5 5}
.topology .wire.live{stroke:var(--gold);stroke-dasharray:none}
.topology .node text.sub{font-size:12px;font-weight:400}
.diagramkey{margin:0 0 var(--block)}

/* What the customer has told us is in their lab. A table because these are rows
   of the same shape — name, address, what it is — and prose would make five of
   them unreadable. */
.devices{width:100%;border-collapse:collapse;margin:.2rem 0 1rem;font-size:var(--fs-body);
  font-weight:300}
.devices th{text-align:left;padding:.4rem .6rem .4rem 0;color:var(--soft);border-bottom:1px solid var(--line)}
.devices td{padding:.6rem .6rem .6rem 0;border-bottom:1px solid var(--line);
  vertical-align:top;overflow-wrap:anywhere}
.devices tr:last-child td{border-bottom:0}
.devices .nm{font-weight:600}
.devices .addr{font-variant-numeric:tabular-nums;color:var(--ink)}
.devices .desc{color:var(--soft)}
.devices .act{text-align:right;white-space:nowrap}
.devices form{margin:0}
.devices button{color:var(--soft)}
.devices button:hover{color:var(--red)}

/* Labelled fields rather than placeholder-only, because "10.20.1.5" in a grey
   box does not say whether it wants the uplink or the endpoint side, and the
   answer stops being visible the moment somebody types.

   The bottom margin is the fix for a row of inputs sitting hard against the
   edge of the panel — the roll-up's own padding was sized for paragraphs. */
.adddevice{display:flex;gap:.6rem;flex-wrap:wrap;align-items:flex-end;
  margin:.6rem 0 1.4rem}
/* Stretched to a common height so every label sits on one line across the row,
   with the controls pushed to the bottom. A checkbox is half the height of a
   text field and was dragging its own label down with it. */
/* Nothing here is sized for a phone. This page is a network diagram and five
   tables of addresses; it is filled in at a desk, from a laptop, next to the
   rack — so the fields are given the room a desk has rather than the floor of a
   width that has to survive 375px. */
.fld{display:flex;flex-direction:column;gap:.3rem;flex:1;min-width:11rem;
  align-self:stretch}
.fld > :not(span:first-child){margin-top:auto}
.fld.wide{flex:2;min-width:15rem}
.fld > span{color:var(--soft)}
.fld input.t,.fld select.t{width:100%}
/* An address field is sized to the longest address there is — 255.255.255.255 —
   rather than stretching with the row. A box three times wider than anything
   that can go in it reads as though more is wanted, and the room it took is room
   the name and description fields wanted.

   Two characters over the fifteen, so the longest address sits inside the box
   rather than against its edge, and a typed address is not touching the caret.
   Padding and border are added back because the box is sized border-box. */
.fld.ip{flex:0 0 auto;min-width:0}
.fld.ip input.t{width:calc(17ch + 1.8rem + 4px)}
/* A dropdown is as wide as its longest option. Stretching one that offers
   Active or Passive across a third of the row spends space on a settled answer
   and takes it from the name and description, which are the fields with
   something to say. */
.fld:has(select){flex:0 0 auto;min-width:0}
.fld:has(select) select.t{width:auto}
/* A checkbox is not a column of text, so it does not stretch like one. */
.fld:has(input[type=checkbox]){flex:0 0 auto;min-width:0}
.fld .checkrow{display:flex;align-items:center;margin-top:auto}
.fld input[type=checkbox]{width:18px;height:18px;margin:0;
  accent-color:var(--gold-deep)}
.adddevice .btn{margin-top:0;flex:0 0 auto}

/* A field that only exists once another answer makes it relevant: the specific
   address once DHCP is ruled out, the second uplink once HA is ticked.

   Guarded by @supports and written as "hide when not chosen" rather than "show
   when chosen", so a browser without :has() shows every field. Failing hidden
   would leave a question on screen with no way to reach it — the same reasoning
   as the hosting authorisation and the "something else" box. */
@supports selector(:has(*)) {
  .adddevice:has(select[name="address_mode"] option[value="dhcp"]:checked)
    .gated.g-address_mode{display:none}
  .adddevice:not(:has(input[name="ha"]:checked)) .gated.g-ha{display:none}
  .adddevice:has(select[name="mode"] option[value="passive"]:checked)
    .gated.g-mode{display:none}
}

/* Which Gateways are in a pair. A column of "no" against the rest would say
   nothing, so it marks the ones that are and stays quiet otherwise. */
.devices .tag{display:inline-block;margin-left:.4rem;padding:.05rem .45rem;border:1px solid var(--gold);border-radius:var(--notch);color:var(--gold-deep);vertical-align:middle}

/* Yes or no, as buttons that submit rather than radios needing a save. It is
   one answer and it changes what the page says underneath, so waiting for a
   separate save would leave the warning stale on the screen. */
.switchask{margin:.2rem 0 1rem}
.switchask .answer{cursor:pointer;background:none}
.switchask .answer.on.a-done{border-color:var(--ok);color:var(--ok)}
.switchask .answer.on.a-not_yet{border-color:var(--red);color:var(--red)}
@media (max-width:34rem){
  .devices thead{display:none}
  .devices td{display:block;border-bottom:0;padding:.15rem 0}
  .devices tr{display:block;padding:.6rem 0;border-bottom:1px solid var(--line)}
  .devices .act{text-align:left;padding-top:.4rem}
}

/* ------------------------------------------------------------- phase timeline
   Where the trial is, on the customer's own page. Five dots on one line:
   finished behind in brand red, the phase they are in filled gold, the ones
   ahead drawn as outlines.

   `--logo-red` rather than `--red`. The text red lightens to a pink in dark
   mode for legibility, and a pink dot beside the gold is the clash that got
   these two colours separated in the first place. The logotype's red is the one
   that belongs next to the logotype's gold. */
/* Sits under the title, so it needs air above it as well as below — the h1's
   own margin is sized for a paragraph following it, not for a row of dots. */
.timeline{display:flex;list-style:none;margin:var(--block) 0;padding:0}
.timeline li{flex:1;position:relative;display:flex;flex-direction:column;
  align-items:center;gap:.7rem;text-align:center;min-width:0}
/* The connector belongs to the dot on its right, so it can be coloured by how
   far the trial has come rather than tracked as a sixth thing. */
.timeline li::before{content:"";position:absolute;top:9px;left:-50%;right:50%;
  height:2px;background:var(--line)}
.timeline li:first-child::before{display:none}
.timeline li.done::before,.timeline li.now::before{background:var(--logo-red)}
.timeline .dot{position:relative;z-index:1;width:20px;height:20px;flex:none;
  border-radius:50%;border:2px solid var(--line);background:var(--bg)}
.timeline li.done .dot{background:var(--logo-red);border-color:var(--logo-red)}
.timeline li.now .dot{background:var(--gold);border-color:var(--gold)}
.timeline .lbl{color:var(--soft);overflow-wrap:anywhere}
.timeline li.done .lbl{color:var(--ink)}
.timeline li.now .lbl{color:var(--gold-deep)}
@media (max-width:30rem){
  .timeline .lbl{font-size:.6rem;letter-spacing:.5px}
}

/* --------------------------------------------------------- panel documentation
   A "?" beside each panel heading, opening the panel's own explanation. Built on
   the platform's popover attribute, so there is no script behind it and nothing
   to get stuck open when a request fails.

   Note what is deliberately absent: no `[popover] { display: none }`. A browser
   without popover support ignores the attribute and renders the documentation
   inline, which is untidy and completely usable. Hiding it here would hide it in
   exactly the browsers that have no way to bring it back. */
.panelhead{display:flex;align-items:center;gap:.55rem;margin:0 0 .9rem}
.panelhead h3{margin:0}
.helpbtn{appearance:none;flex:none;width:17px;height:17px;padding:0;line-height:1;
  border:1.5px solid var(--line);border-radius:50%;background:none;cursor:pointer;
  font-family:inherit;font-size:var(--fs-micro);font-weight:600;color:var(--soft);
  transition:border-color .15s,color .15s}
.helpbtn:hover{border-color:var(--gold);color:var(--gold-deep)}
.helpbtn:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

/* The longest of these runs to four paragraphs, which is taller than a laptop
   viewport with the browser chrome taken off. Cap it and let it scroll rather
   than letting the close button fall off the bottom of the screen. */
.doc{max-width:34rem;max-height:calc(100vh - 4rem);overflow-y:auto;margin:auto;padding:var(--pad-card);color:var(--ink);text-align:left;box-shadow:0 24px 60px rgba(0,0,0,.45)}
.doc::backdrop{background:rgba(0,0,0,.55)}
.doc h4{margin:0 0 .9rem;color:var(--gold-deep)}
.doc p{margin:0 0 .9rem;font-size:var(--fs-body);font-weight:300;line-height:1.55}
.doc strong{font-weight:600}
.doc em{font-style:normal;color:var(--gold-deep)}
.doc-close{margin:.2rem 0 0;color:var(--gold-deep)}
.doc-close:hover{color:var(--ink)}
@media (max-width:34rem){ .doc{padding:1.3rem 1.2rem 1.1rem} }

/* ------------------------------------------------------------- phase progress
   One row per phase, and the row for the phase the trial is actually in is the
   only one that gets colour. Five equally-weighted bars would say every phase
   matters the same today, which is the one thing a status readout must not say. */
.phaserow{display:flex;align-items:center;gap:.9rem;padding:.5rem 0;
  border-bottom:1px solid var(--line);font-size:var(--fs-body);font-weight:300}
.phaserow:last-of-type{border-bottom:0}
.phaserow .nm{flex:0 0 6.5rem}
.phaserow .bar{flex:1;min-width:4rem;height:6px;background:var(--line);
  border-radius:3px;overflow:hidden}
.phaserow .bar i{display:block;height:100%;background:var(--soft);
  transition:width .4s cubic-bezier(.4,0,.2,1)}
.phaserow .pc{flex:0 0 2.6rem;text-align:right;font-weight:600}
.phaserow .ct{flex:0 0 8.5rem;text-align:right;font-size:var(--fs-quiet);color:var(--soft);
  white-space:nowrap}
.phaserow.now .nm{font-weight:600;color:var(--gold-deep)}
.phaserow.now .bar i{background:var(--gold)}
@media (max-width:34rem){
  .phaserow{flex-wrap:wrap;gap:.3rem .8rem}
  .phaserow .bar{flex:1 0 100%;order:3}
  .phaserow .nm{flex:1}
  .phaserow .ct{flex:0 0 auto}
}

/* ----------------------------------------------------------- the checklist */
.progress-note{border-left:3px solid var(--gold);margin:0 0 var(--block);font-size:var(--fs-body);font-weight:300}

/* The guide's two piles, rolled up. <details> rather than script, because this
   has to work on a locked-down plant laptop, and because a closed section still
   prints and still finds text on Ctrl-F in current browsers. */
.rollup{padding:0 1.5rem;margin:0 0 var(--stack)}
.rollup summary{display:flex;align-items:center;gap:1rem;padding:1.1rem 0;
  cursor:pointer;list-style:none}
.rollup summary::-webkit-details-marker{display:none}
/* Own marker, so it can sit ahead of the title and rotate. */
.rollup summary::before{content:"";width:0;height:0;flex:none;
  border-left:6px solid var(--soft);border-top:5px solid transparent;
  border-bottom:5px solid transparent;transition:transform .15s}
.rollup[open] summary::before{transform:rotate(90deg)}
.rollup summary:hover::before{border-left-color:var(--gold)}
.rollup summary .t{flex:1;font-size:var(--fs-title);font-weight:600}
.rollup summary .c{color:var(--soft);white-space:nowrap}
.rollup summary .c.all{color:var(--ok)}
.rollup summary:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.rollup .blurb{margin:0 0 .9rem;font-size:var(--fs-body);font-weight:300;color:var(--soft);
  line-height:1.5}
.rollup .check:last-of-type{padding-bottom:1.4rem}

.check{border:0;border-top:1px solid var(--line);margin:0;padding:1rem 0}
.check legend{padding:0;font-size:var(--fs-body);font-weight:400;line-height:1.4}
/* What the line means and what goes wrong without it. Set quieter than the
   question, because somebody who already knows should be able to skim past it
   to the buttons without reading a paragraph per item. */
.check .why{margin:.5rem 0 0;font-size:var(--fs-body);font-weight:300;line-height:1.55;
  color:var(--soft)}
.answers{display:flex;gap:.5rem;margin-top:.7rem;flex-wrap:wrap}
.answer{position:relative;cursor:pointer;border:2px solid var(--line);border-radius:var(--notch);padding:.4rem 1rem;color:var(--soft);transition:border-color .15s,color .15s,background .15s}
.answer input{position:absolute;opacity:0;width:1px;height:1px}
.answer:hover{color:var(--ink)}
.answer:has(input:focus-visible){outline:3px solid var(--gold);outline-offset:2px}
.answer.a-done:has(input:checked){border-color:var(--ok);color:var(--ok)}
.answer.a-not_yet:has(input:checked){border-color:var(--gold);color:var(--gold-deep);
  background:var(--gold-tint)}
/* "I need help" is the answer worth having. It is not a failure state, it is the
   customer telling the architect where to spend the call. */
.answer.a-help:has(input:checked){border-color:var(--red);color:var(--red)}
/* Withdrawing sits next to resending but must not read as its equal — one sends
   an email, the other ends someone's access before they have used it. */
.inv button.withdraw{color:var(--soft)}
.inv button.withdraw:hover{color:var(--red)}

/* ------------------------------------------------- who the customer named
   A stakeholder is a name, not an access grant. The customer types it, a sales
   manager turns it into an invitation, and until then nobody has been
   contacted — which the copy says out loud, because a form that might be
   emailing your colleagues gets filled in cautiously and incompletely. */
.inv.person{align-items:center;padding:.7rem 0}
.inv .addr strong{display:block;font-weight:600;line-height:1.3}
.inv .addr .pos{font-size:var(--fs-quiet);font-weight:300;color:var(--soft)}
.inv .addr .pos::after{content:" · ";color:var(--line)}
.inv .addr .mail{font-size:var(--fs-quiet);font-weight:300;color:var(--soft)}
.inv .state-waiting{color:var(--gold-deep);font-weight:400}

/* `.inv button` is the quiet-text-link style and it beats a bare `.btn` on
   specificity — one class plus an element against one class — so an actual
   button inside a row needs saying twice or it renders as a link with no box.
   The same tie that once painted a button gold on gold. */
.inv button.btn{background:var(--gold);color:#fff;padding:0 1.2rem;
  border-radius:var(--notch);letter-spacing:var(--ls-caps)}
.inv button.btn:hover{color:#fff;filter:brightness(1.08)}

/* The block leads the People panel, so it needs a line under it to stop the
   customer's names reading as part of the invitation list below. */
.waiting{padding-bottom:.9rem;margin-bottom:.4rem;
  border-bottom:2px solid var(--line)}
.waiting .hintline{margin:0 0 .4rem}

/* The customer's list reads as a table like the lab's does, so the state column
   borrows the colours the invitation rows use rather than inventing its own. */
.devices .state{font-weight:600;white-space:nowrap}
.devices .state-joined{color:var(--ok)}
.devices .state-waiting{color:var(--gold-deep);font-weight:400}
/* Which partner company. Only meaningful when inviting a partner, so it is
   hidden the rest of the time — the same select-driven :has() rule as the
   hosting authorisation.

   Written as "hide unless partner" rather than "show when partner" so that
   where :has() is missing the field stays visible. Failing hidden would leave
   no way to name a partner company at all, and the whole point of the field is
   that the association cannot be guessed. */
.inviterow .partner-org{flex:1 0 100%}
@supports selector(:has(*)) {
  .inviterow:has(select[name="invited_role"] option[value="customer"]:checked)
    .partner-org{display:none}
}
/* The name box for a partner we have not met. Hidden unless "New partner…" is
   chosen, and — like every other :has() rule here — written so that missing
   support leaves it visible rather than unreachable. */
.new-partner{margin-top:.6rem}
@supports selector(:has(*)) {
  .field:has(select[name="partner_org_id"] option:checked:not([value="new"]))
    .new-partner{display:none}
}
/* The free-text escape hatch under a tile grid, shown only once "Something
   else" is the answer — until then it is a question nobody has been asked.

   Written as "hide while it is unchosen" rather than "show when chosen" so that
   where :has() is missing the box stays visible. Failing hidden would leave a
   pharmaceutical plant or a port with no way to say so. */
.tell-us{margin-top:1.5rem;text-align:left}
@supports selector(:has(*)) {
  form:has(input[name="value"][value="other"]:not(:checked)) .tell-us{display:none}
}
