/* ---------------------------------------------------------------------------
   NGE portal.

   A tool, not a document. It gets used one handed on a phone in a mechanical
   room with poor light, and on a desk with twenty rows on screen. Both of those
   want the same thing: state visible before it is read.

   Colour comes from the logo, not from taste — #0d79ff and #41b9ff are sampled
   out of it. Everything else is a cold neutral biased a few degrees towards
   that blue so the accent never looks stuck on.

   Three colours are reserved and never used for decoration: green, amber and
   red mean current, due soon and overdue. That is the vocabulary of the trade,
   and it is worth more than any styling on this page. The brand blue means
   "you can act on this" and nothing else, so the two can never be confused.
--------------------------------------------------------------------------- */

@font-face{font-family:Plex;src:url(/assets/font/ibm-plex-sans-latin-400-normal.woff2) format('woff2');
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Plex;src:url(/assets/font/ibm-plex-sans-latin-600-normal.woff2) format('woff2');
  font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:Plex;src:url(/assets/font/ibm-plex-sans-latin-700-normal.woff2) format('woff2');
  font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:PlexMono;src:url(/assets/font/ibm-plex-mono-latin-500-normal.woff2) format('woff2');
  font-weight:500;font-style:normal;font-display:swap}

:root{
  --brand:#0d79ff;         /* the logo's deep azure. Interactive things, nothing else */
  --brand-ink:#0a5fcc;     /* the same, dark enough to read as text on paper */
  --arc:#41b9ff;           /* the logo's light sky. The sweep, and focus in the dark */

  /* Four grounds, far enough apart to be told apart at arm's length in bad
     light: the page, a card on it, a field sunk into the card, and the hairline
     between them. They were within a couple of percent of each other and the
     whole thing read as one sheet of white. */
  --paper:#e3e8ef; --surface:#fff; --sunk:#eef1f6;
  --line:#c2cbd8; --line-soft:#dae0e9;
  /* Two more, so a screen divides into what it is about and where you type.
     A band is a section inside a card: its title, or a part that edits. A field
     is tinted where it sits on white, and turns white where it sits on a band,
     so it always differs from whatever is behind it. */
  --band:#f2f5f9;
  --field:#ebeff5; --field-line:#b5c0ce; --field-in-band:#fff;
  --ink:#0b1016; --ink-2:#414b57; --ink-3:#6b7683;
  /* a whisper of a lift under a card, so it sits on the page rather than in it */
  --lift:0 1px 2px rgba(16,24,40,.05),0 2px 6px -2px rgba(16,24,40,.05);
  --inset:inset 0 1px 1px rgba(16,24,40,.045);

  --ok:#0f8a43;            /* inspected, in date */
  --due:#a8630c;           /* falls due soon */
  --over:#cc2b21;          /* past due, or a deficiency */

  --r:6px;                 /* one radius, everywhere. Pills are the exception */
  --sans:Plex,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:PlexMono,ui-monospace,Menlo,Consolas,monospace;
  --head:60px;
}
/* Light unless somebody chooses otherwise. Choosing Dark stamps
   data-theme="dark"; choosing System stamps data-theme="system", and only then
   does the phone or laptop's own setting count. With no stamp at all, including
   with scripts off, it is light. */
@media (prefers-color-scheme:dark){
  :root[data-theme="system"]{
    --brand:#2f8fff; --brand-ink:#7cbcff; --arc:#41b9ff;
    --paper:#090d12; --surface:#111821; --sunk:#0d131a;
    --line:#232c37; --line-soft:#1a222b;
    --band:#151d26; --field:#0b1016; --field-line:#2f3a47; --field-in-band:#0b1016;
    --ink:#e6eaee; --ink-2:#a3aeba; --ink-3:#78838f;
    --ok:#36bd6c; --due:#dda033; --over:#ff6a5e;
  }
}
:root[data-theme="dark"]{
  --brand:#2f8fff; --brand-ink:#7cbcff; --arc:#41b9ff;
  --paper:#090d12; --surface:#111821; --sunk:#0d131a;
  --line:#2a3542; --line-soft:#1e2731;
  --band:#151d26; --field:#0b1016; --field-line:#2f3a47; --field-in-band:#0b1016;
  --ink:#e6eaee; --ink-2:#a3aeba; --ink-3:#7d8894;
  --ok:#36bd6c; --due:#dda033; --over:#ff6a5e;
  --lift:none; --inset:none;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);
  font:15px/1.5 var(--sans);-webkit-font-smoothing:antialiased}
a{color:var(--brand-ink);text-underline-offset:2px}
a:hover{color:var(--brand)}
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:3px}

h1{font:700 25px/1.2 var(--sans);margin:0 0 4px;letter-spacing:-.022em;text-wrap:balance}
h2{font:700 12px/1.3 var(--sans);margin:34px 0 12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-2);display:flex;align-items:center;gap:12px}
/* a rule running off to the right, so a heading reads as the start of a section
   rather than as a line of small text that happens to be above one */
h2::after{content:"";flex:1;height:1px;background:var(--line)}
h3{font:600 15px/1.3 var(--sans);margin:0 0 6px;letter-spacing:-.01em}
.lede{color:var(--ink-2);margin:0 0 20px;max-width:62ch}
.muted{color:var(--ink-3)}
.mono{font:500 13px/1.4 var(--mono);font-variant-numeric:tabular-nums}
.right{text-align:right}
.num{font-variant-numeric:tabular-nums}

/* --- the header -----------------------------------------------------------
   Two zones on a phone: identity and the person on one line, the whole of the
   navigation on the next, one line, evenly divided so every target is the same
   size and none of them wrap. One zone on a desk. */
.top{position:sticky;top:0;z-index:20;background:var(--surface);
  border-bottom:1px solid var(--line);
  display:grid;grid-template-columns:auto 1fr;grid-template-areas:"brand me" "nav nav";
  align-items:center;column-gap:14px;padding:8px 14px 0}
.brand{grid-area:brand;display:flex;flex-direction:column;gap:1px;text-decoration:none;padding:2px 0 6px}
.brand img{display:block;height:26px;width:auto}
/* the wordmark is near black, so the dark ground needs the pale version */
.brand img.dark{display:none}
@media (prefers-color-scheme:dark){
  :root[data-theme="system"] .brand img.light{display:none}
  :root[data-theme="system"] .brand img.dark{display:block}
}
:root[data-theme="dark"] .brand img.light{display:none}
:root[data-theme="dark"] .brand img.dark{display:block}
.brand b{font:700 10px/1 var(--sans);letter-spacing:.34em;text-transform:uppercase;
  color:var(--ink-3);padding-left:2px}

nav.main{grid-area:nav;display:flex;align-items:stretch;margin:0 -14px;
  border-top:1px solid var(--line-soft);position:relative}
nav.main a{position:relative;flex:1 1 0;min-width:0;display:flex;align-items:center;justify-content:center;
  padding:13px 4px 12px;text-decoration:none;color:var(--ink-2);
  font:600 15px/1 var(--sans);letter-spacing:-.01em;
  border-bottom:2px solid transparent;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
nav.main a:hover{color:var(--ink);background:var(--sunk)}
nav.main a.on{color:var(--ink);border-bottom-color:var(--brand)}
/* the live rail under the open page, the same blue as the mark in the logo */
nav.main a.on::after{content:"";position:absolute;bottom:0;left:0;right:0;height:2px;
  background:linear-gradient(90deg,transparent,var(--arc),transparent);opacity:.55;
  pointer-events:none}

/* the sixth item and beyond, on a phone. Hidden until app.js finds an overflow */
/* widths are read with the growing off, see app.js */
nav.main.measuring a{flex:0 0 auto}
nav.main .more{flex:0 0 46px;border:0;background:none;color:var(--brand-ink);
  font:700 17px/1 var(--sans);cursor:pointer;border-bottom:2px solid transparent}
nav.main .more[hidden]{display:none!important}
nav.main .more:hover{background:var(--sunk)}
.overflow{position:absolute;top:100%;right:0;z-index:30;background:var(--surface);
  border:1px solid var(--line);border-top:0;border-radius:0 0 var(--r) var(--r);
  min-width:170px;box-shadow:0 14px 28px rgba(6,12,22,.16);padding:4px}
.overflow a{display:block;padding:11px 14px;border-radius:4px;text-align:left;flex:none}

.me{grid-area:me;display:flex;align-items:center;justify-content:flex-end;gap:10px;padding-bottom:6px}
.me .who{display:flex;flex-direction:column;line-height:1.15;text-align:right;text-decoration:none;
  color:var(--ink);max-width:40vw}
.me .who span{font:600 13px/1.2 var(--sans);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.me .who b{font:700 9px/1.2 var(--sans);color:var(--ink-3);text-transform:uppercase;letter-spacing:.12em}
.me form{margin:0;display:flex}
/* sign out is a power button. Red only while it is being pressed, so it reads
   as "this ends the session" without shouting on every screen. */
.power{width:38px;height:38px;display:grid;place-items:center;border:1px solid var(--line);
  border-radius:50%;background:var(--surface);color:var(--ink-2);cursor:pointer;padding:0;
  transition:color .12s,border-color .12s,background .12s}
.power svg{width:17px;height:17px;display:block}
.power:hover{color:var(--over);border-color:var(--over);background:color-mix(in srgb,var(--over) 8%,transparent)}
.power:active{transform:scale(.94)}

@media (min-width:860px){
  .top{grid-template-columns:auto 1fr auto;grid-template-areas:"brand nav me";
    padding:0 26px;column-gap:26px}
  .brand{padding:9px 0}
  .brand img{height:30px}
  nav.main{margin:0;border-top:0;gap:2px}
  nav.main a{flex:0 0 auto;padding:20px 15px 18px;font-size:16px}
  .me{padding:0}
  .me .who{max-width:none}
  .overflow{right:auto;left:0}
}

/* --- the arc ---------------------------------------------------------------
   A page change should be felt, not waited for. One line of the logo's light
   blue drops down the screen once, over content that is already drawn, and is
   gone in under half a second. Nothing is hidden behind it. */
.arc{position:fixed;left:0;right:0;top:0;height:2px;z-index:50;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--arc) 18%,#fff 50%,var(--arc) 82%,transparent);
  box-shadow:0 0 14px 2px color-mix(in srgb,var(--arc) 70%,transparent);
  animation:arc .46s cubic-bezier(.4,0,.25,1) 1 forwards}
@keyframes arc{
  0%{transform:translateY(-2px);opacity:0}
  12%{opacity:1}
  88%{opacity:1}
  100%{transform:translateY(100vh);opacity:0}
}
@media (prefers-reduced-motion:reduce){
  .arc{display:none}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}

.page{max-width:1180px;margin:0 auto;padding:24px 14px 90px}
@media (min-width:860px){.page{padding:28px 26px 90px}}
.shell{min-height:100dvh;display:grid;place-items:center;padding:24px 16px}

/* --- surfaces --------------------------------------------------------------
   A card says "this is a separate object". Forms and notes are; a list of
   buildings is not, so lists get rules instead and the border is spent where
   it means something. */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:18px;margin:0 0 16px;box-shadow:var(--lift)}
.card.tight{padding:0}
/* a card that opens with its title wears it as a band across the top */
.card > h3:first-child{margin:-18px -18px 16px;padding:12px 18px;background:var(--band);
  border-bottom:1px solid var(--line-soft);border-radius:var(--r) var(--r) 0 0}
/* the parts of a screen where you change things, set apart from what you read */
.card > details[open],.row-item details[open]{background:var(--band);--field:var(--field-in-band);
  border:1px solid var(--line-soft);border-radius:var(--r);padding:11px 13px 13px}
.card > details[open]{margin-left:-6px;margin-right:-6px}
.grid{display:grid;gap:14px}
@media(min-width:760px){.grid.two{grid-template-columns:1fr 1fr}.grid.three{grid-template-columns:repeat(3,1fr)}}

/* --- the count strip -------------------------------------------------------
   Not tiles in boxes. Four figures divided by hairlines, which is lighter and
   reads faster than four bordered rectangles. */
.counts{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;margin:0 0 22px;
  box-shadow:var(--lift)}
@media(min-width:620px){.counts{grid-template-columns:repeat(4,1fr)}}
.counts > *{background:var(--surface);padding:14px 16px;text-decoration:none;color:inherit;display:block}
.counts a:hover{background:var(--sunk)}
.counts b{display:block;font:700 30px/1.05 var(--sans);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.counts span{color:var(--ink-3);font-size:13px}
.counts .flag b{color:var(--over)}

/* --- rows ------------------------------------------------------------------
   The main list component. A 3px edge on the left carries inspection state, so
   a column of buildings can be read for trouble without reading a word. On a
   phone the same markup stacks and each value keeps its label. */
.rows{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;box-shadow:var(--lift)}
.row-item{display:grid;gap:2px 14px;padding:13px 15px 13px 18px;border-bottom:1px solid var(--line);
  position:relative;align-items:baseline}
.row-item:last-child{border-bottom:0}
.row-item::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:transparent}
.row-item.is-ok::before{background:var(--ok)}
.row-item.is-due::before{background:var(--due)}
.row-item.is-over::before{background:var(--over)}
.row-item:hover{background:var(--sunk)}
.row-item .t{font-weight:600;font-size:15px}
.row-item .t a{text-decoration:none;color:var(--ink)}
.row-item .t a:hover{color:var(--brand-ink);text-decoration:underline}
.row-item .s{color:var(--ink-3);font-size:13px}
.row-item .f{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:center;margin-top:5px}
.row-item .f > *{font-size:13px}
.row-item .k{color:var(--ink-3);font-size:11px;text-transform:uppercase;letter-spacing:.07em;
  font-weight:700;margin-right:5px}
.row-item .go{justify-self:end;align-self:center}
@media (min-width:760px){
  .row-item{grid-template-columns:1fr auto;padding:14px 18px 14px 21px}
  .row-item .f{margin-top:6px}
}

/* --- tables ----------------------------------------------------------------
   Kept for genuinely tabular things: the equipment register, the activity log.
   Never used as a layout. */
table{width:100%;border-collapse:collapse;font-size:14px}
th{text-align:left;font:700 11px/1.4 var(--sans);text-transform:uppercase;letter-spacing:.07em;
  color:var(--ink-3);padding:0 10px 9px;border-bottom:1px solid var(--line)}
td{padding:11px 10px;border-bottom:1px solid var(--line-soft);vertical-align:top}
tbody tr:last-child td,table tr:last-child td{border-bottom:0}
.wrap-x{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* --- forms ----------------------------------------------------------------- */
label{display:block;font:600 12px/1.3 var(--sans);letter-spacing:.03em;margin:0 0 6px;
  color:var(--ink-2);text-transform:uppercase}
.check label,label.check{text-transform:none;letter-spacing:0;font-size:14px}
input,select,textarea{width:100%;padding:10px 12px;border:1px solid var(--field-line);border-radius:var(--r);
  background:var(--field);color:var(--ink);font:15px var(--sans);box-shadow:var(--inset)}
/* paler than anything typed, so an example is never mistaken for an answer */
input::placeholder,textarea::placeholder{color:var(--ink-3);opacity:.72}
input[type=checkbox],input[type=radio]{box-shadow:none}
input[type=date],input[type=datetime-local]{font-variant-numeric:tabular-nums}
input:focus,select:focus,textarea:focus{outline:2px solid var(--brand);outline-offset:1px;
  border-color:var(--brand);background:var(--surface);box-shadow:none}
textarea{min-height:84px;resize:vertical}
.field{margin:0 0 13px}
/* a hint is small and grey wherever it sits, inside a field or under a form */
.hint{font-weight:400;font-size:12px;line-height:1.45;color:var(--ink-3);margin:5px 0 0}
.row{display:grid;gap:13px}
@media(min-width:620px){.row.two{grid-template-columns:1fr 1fr}.row.three{grid-template-columns:repeat(3,1fr)}}
.check{display:flex;align-items:flex-start;gap:9px;font-weight:400;color:var(--ink)}
.check input{width:auto;flex:0 0 auto;margin-top:2px}

.btn{display:inline-flex;align-items:center;gap:7px;background:var(--brand);color:#fff;border:1px solid var(--brand);
  border-radius:var(--r);padding:11px 17px;font:600 14px/1 var(--sans);cursor:pointer;text-decoration:none;
  transition:filter .12s,transform .06s}
.btn:hover{filter:brightness(1.08);color:#fff}
.btn:active{transform:translateY(1px)}
.btn.quiet{background:var(--surface);border-color:var(--line);color:var(--ink-2)}
.btn.quiet:hover{border-color:var(--brand);color:var(--brand-ink);filter:none}
.btn.danger{background:var(--surface);border-color:var(--over);color:var(--over)}
.btn.small{padding:7px 12px;font-size:13px}
.btn-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center}

/* --- signals --------------------------------------------------------------- */
.note{border-radius:var(--r);padding:12px 15px;margin:0 0 18px;font-size:14px;font-weight:600;
  border-left:3px solid}
.note.ok{background:color-mix(in srgb,var(--ok) 11%,transparent);color:var(--ok);border-color:var(--ok)}
.note.bad{background:color-mix(in srgb,var(--over) 11%,transparent);color:var(--over);border-color:var(--over)}
.pill{display:inline-block;padding:3px 9px;border-radius:999px;font:700 11px/1.4 var(--sans);
  text-transform:uppercase;letter-spacing:.06em;border:1px solid var(--line);color:var(--ink-2);
  white-space:nowrap}
.pill.ok{color:var(--ok);border-color:currentColor}
.pill.bad{color:var(--over);border-color:currentColor}
.pill.warn{color:var(--due);border-color:currentColor}
.pill.on{color:#fff;background:var(--brand);border-color:var(--brand)}
.empty{color:var(--ink-3);padding:30px 20px;text-align:center;font-size:14px}

/* a phone number worth tapping rather than reading */
.tel{display:inline-flex;align-items:center;gap:6px;font:500 14px/1 var(--mono);
  text-decoration:none;color:var(--brand-ink);border:1px solid var(--line);
  border-radius:999px;padding:7px 13px 7px 11px;background:var(--surface)}
.tel:hover{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 7%,transparent)}
.tel svg{width:13px;height:13px}

details{border-top:1px solid var(--line-soft);margin-top:14px;padding-top:12px}
details summary{cursor:pointer;font-weight:600;font-size:14px;color:var(--ink-2)}
details summary:hover{color:var(--ink)}
details[open] summary{margin-bottom:12px}

/* --- sign in --------------------------------------------------------------- */
.login{width:min(410px,100%);background:var(--surface);border:1px solid var(--line);
  border-radius:10px;padding:30px 28px 28px}
.login .mark{display:block;height:34px;width:auto;margin:0 0 20px}
.login h1{font-size:20px;margin-bottom:3px}
.login p.sub{color:var(--ink-3);font-size:14px;margin:0 0 22px}
.login .btn{width:100%;justify-content:center}
.login .alt{text-align:center;margin:16px 0 0;font-size:14px}

/* --- the secret, at setup -------------------------------------------------- */
.secret{font:500 16px/1.7 var(--mono);word-break:break-all;background:var(--sunk);
  border:1px dashed var(--line);padding:11px 13px;border-radius:var(--r);margin:0 0 4px}
.recovery{font:500 21px/1.4 var(--mono);letter-spacing:.06em;background:var(--sunk);
  border:1px dashed var(--due);color:var(--ink);padding:14px;border-radius:var(--r);text-align:center}

/* --- the booking track -----------------------------------------------------
   Four steps to getting an inspection into the diary: it falls due, somebody
   rings, a time is set, the customer agrees to it. Drawn as a track rather than
   four tick boxes so the gap is obvious — the useful question is never "how
   many are done", it is "which one is it stuck on". */
.track{display:grid;grid-template-columns:repeat(4,1fr);gap:2px;margin:0 0 18px}
.track .step{background:var(--sunk);border-top:3px solid var(--line);padding:10px 12px 12px}
.track .step .k{display:block;font:700 10px/1.3 var(--sans);text-transform:uppercase;
  letter-spacing:.08em;color:var(--ink-3);margin-bottom:3px}
.track .step .v{font:600 13px/1.35 var(--sans);color:var(--ink-3)}
.track .step.done{border-top-color:var(--ok);background:var(--surface)}
.track .step.done .v{color:var(--ink)}
.track .step.now{border-top-color:var(--due);background:var(--surface)}
.track .step.now .k{color:var(--due)}
.track .step.now .v{color:var(--ink)}
.track .step.late{border-top-color:var(--over);background:var(--surface)}
.track .step.late .k{color:var(--over)}
.track .step.late .v{color:var(--ink)}
@media (max-width:559px){
  .track{grid-template-columns:1fr 1fr}
}

/* the headline date on the site page: the one number the page exists for */
.due-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 14px;margin:0 0 14px}
.due-head .big{font:700 30px/1 var(--sans);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.due-head .big.over{color:var(--over)}
.due-head .big.soon{color:var(--due)}

/* the mark on the sign in, reset and code pages */
.login .mark.dark{display:none}
@media (prefers-color-scheme:dark){
  :root[data-theme="system"] .login .mark.light{display:none}
  :root[data-theme="system"] .login .mark.dark{display:block}
}
:root[data-theme="dark"] .login .mark.light{display:none}
:root[data-theme="dark"] .login .mark.dark{display:block}

/* --- who gets told what ----------------------------------------------------
   One block per thing that can be announced. The two audiences read as a pair
   of switches because that is the decision; the people underneath are the
   detail, and they are only relevant once "inside NGE" is on. */
.alert-rule{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:16px 18px;margin:0 0 12px}
.alert-rule.off{opacity:.62}
.alert-rule > h3{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:4px}
.alert-rule p.what{color:var(--ink-3);font-size:13px;margin:0 0 14px;max-width:64ch}
.audience{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px}
.audience label{display:inline-flex;align-items:center;gap:8px;margin:0;padding:9px 14px;
  border:1px solid var(--line);border-radius:999px;background:var(--sunk);
  font-weight:600;font-size:14px;color:var(--ink-2);cursor:pointer;user-select:none}
.audience label:hover{border-color:var(--brand)}
.audience input{width:auto;margin:0}
.audience input:checked + span{color:var(--brand-ink)}
.audience label:has(input:checked){border-color:var(--brand);
  background:color-mix(in srgb,var(--brand) 10%,transparent)}
.who-grid{display:grid;grid-template-columns:1fr;gap:7px;margin:0 0 13px}
@media (min-width:560px){.who-grid{grid-template-columns:1fr 1fr}}
@media (min-width:900px){.who-grid{grid-template-columns:repeat(3,1fr)}}
.who-grid label{display:flex;align-items:center;gap:9px;margin:0;padding:9px 11px;
  border:1px solid var(--line-soft);border-radius:var(--r);background:var(--sunk);
  font-weight:500;font-size:14px;color:var(--ink);cursor:pointer}
.who-grid label:has(input:checked){border-color:var(--brand);
  background:color-mix(in srgb,var(--brand) 8%,transparent)}
.who-grid input{width:auto;margin:0;flex:0 0 auto}
.who-grid .r{margin-left:auto;font:700 10px/1 var(--sans);text-transform:uppercase;
  letter-spacing:.08em;color:var(--ink-3)}

/* The sum only appears after several wrong passwords, so when it does appear it
   is new to whoever is looking at it. Boxed and coloured, because the failure
   mode is not answering it wrongly — it is not noticing it is there. */
.login .field.challenge{border:1px solid var(--due);border-left-width:3px;
  border-radius:var(--r);padding:13px 14px 11px;background:color-mix(in srgb,var(--due) 8%,transparent)}
.login .field.challenge label{color:var(--ink);font-size:15px}
.login .field.challenge .hint{margin-bottom:0}

/* --- the menu behind your name ---------------------------------------------
   Your own name is the one place in a portal people look for their own
   settings, so it opens rather than navigating. */
.me .who{border:0;background:none;font:inherit;cursor:pointer;padding:4px 6px;
  border-radius:var(--r);display:flex;flex-direction:column;line-height:1.15;
  text-align:right;color:var(--ink);max-width:40vw}
.me .who:hover{background:var(--sunk)}
.me .who[aria-expanded="true"]{background:var(--sunk)}
.me .who span{font:600 13px/1.2 var(--sans);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.me .who b{font:700 9px/1.2 var(--sans);color:var(--ink-3);text-transform:uppercase;letter-spacing:.12em}
@media (min-width:860px){.me .who{max-width:none}}

.menu{position:absolute;top:calc(100% - 4px);right:12px;z-index:40;min-width:250px;
  max-width:calc(100vw - 24px);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:0 18px 40px rgba(6,12,22,.22);padding:6px;text-align:left}
@media (min-width:860px){.menu{right:24px}}
.menu .head{font:700 10px/1 var(--sans);text-transform:uppercase;letter-spacing:.1em;
  color:var(--ink-3);padding:11px 12px 7px}
.menu a{display:block;padding:11px 12px;border-radius:4px;text-decoration:none;
  color:var(--ink);font:600 14px/1.3 var(--sans)}
.menu a:hover{background:var(--sunk)}
.menu a .sub{display:block;font:400 12px/1.35 var(--sans);color:var(--ink-3);margin-top:2px}
.menu hr{border:0;border-top:1px solid var(--line-soft);margin:6px 0}

/* three buttons in a track: light, dark, and "whatever this device is set to",
   which a two-way switch cannot say */
.themes{display:grid;grid-template-columns:repeat(3,1fr);gap:3px;padding:0 6px 8px}
.themes button{border:1px solid var(--line);background:var(--sunk);color:var(--ink-2);
  border-radius:4px;padding:9px 4px;font:600 12px/1.2 var(--sans);cursor:pointer;
  display:flex;flex-direction:column;align-items:center;gap:5px}
.themes button:hover{border-color:var(--brand);color:var(--ink)}
.themes button svg{width:15px;height:15px}
.themes button[aria-pressed="true"]{background:var(--brand);border-color:var(--brand);color:#fff}

/* the bug icon, quieter than the power button because it is used less often */
.bug{width:38px;height:38px;display:grid;place-items:center;border:1px solid var(--line);
  border-radius:50%;background:var(--surface);color:var(--ink-3);cursor:pointer;padding:0;
  transition:color .12s,border-color .12s}
.bug svg{width:17px;height:17px;display:block}
.bug:hover,.bug[aria-expanded="true"]{color:var(--brand-ink);border-color:var(--brand)}
.bug:active{transform:scale(.94)}
/* min-width lets content push it wider, so cap it too or it reaches the edge */
.menu.bug-form{min-width:min(340px,calc(100vw - 24px));max-width:calc(100vw - 24px);
  padding:6px 14px 14px}
.menu.bug-form .field{margin-bottom:11px}
.menu.bug-form textarea{min-height:92px}

/* --- the people inside a client company ------------------------------------
   Grouped by department, because "who do I send the invoice to" and "who lets
   us in" are different questions and the answer is rarely the same person.
   An empty department still shows its heading: a blank Accounts payable is
   information, and hiding it is how a company ends up with one address. */
.dept{margin:0 0 18px}
.dept > h3{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin:0 0 8px}
.dept > h3 .n{font:700 11px/1 var(--sans);color:var(--ink-3);letter-spacing:.06em}
.dept .rows{margin:0}
.dept .empty{padding:16px 18px;text-align:left;font-size:13px}
.contact-lines{display:flex;flex-wrap:wrap;gap:6px 10px;margin-top:6px}
.contact-lines a{font-size:13px}
.mailto{display:inline-flex;align-items:center;gap:6px;font:500 13px/1 var(--mono);
  text-decoration:none;color:var(--brand-ink);border:1px solid var(--line);
  border-radius:999px;padding:7px 12px;background:var(--surface);word-break:break-all}
.mailto:hover{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 7%,transparent)}
.add-contact > summary{display:inline-flex;align-items:center;gap:8px;list-style:none;
  border:1px dashed var(--line);border-radius:var(--r);padding:10px 15px;
  font:600 14px var(--sans);color:var(--brand-ink);background:var(--surface)}
.add-contact > summary::-webkit-details-marker{display:none}
.add-contact > summary:hover{border-color:var(--brand);border-style:solid}
.add-contact > summary .plus{font:700 18px/1 var(--sans);margin-top:-1px}
.add-contact{border-top:0;margin-top:0;padding-top:0}
.add-contact[open] > summary{margin-bottom:14px}

/* --- the sign in chart -----------------------------------------------------
   Drawn as SVG on the server. No library, nothing to load, and the colours are
   the same three the rest of the portal uses for current, warning and trouble,
   so a red bar here means what a red bar means everywhere else. */
.chart-card .legend{display:flex;flex-wrap:wrap;gap:6px 16px;margin:0 0 12px;
  font-size:12px;color:var(--ink-3)}
.chart-card .legend span{display:inline-flex;align-items:center;gap:6px}
.chart-card .legend i{width:10px;height:10px;border-radius:2px;display:block}
.legend i.k-over{background:var(--over)}
.legend i.k-block{background:var(--due);border-radius:50%}
/* sized for the narrowest phone, capped so the labels do not grow on a desk */
.chart{width:100%;max-width:620px;height:auto;display:block;margin:0 auto}
.chart .grid{stroke:var(--line-soft);stroke-width:1}
.chart .grid.strong{stroke:var(--line)}
.chart .axis{fill:var(--ink-3);font:500 10px var(--mono)}
.chart .b-over{fill:var(--over)}
.chart .b-block{fill:var(--due)}

/* the count strip is links on most pages and plain figures here */
.counts > span{background:var(--surface);padding:14px 16px;display:block}

.chart-card .quiet-chart{margin:0;font-size:14px;line-height:1.55}

/* --- emailing a document to the client -------------------------------------
   A button that opens the list of people NGE actually holds for that client,
   with the usual ones already ticked. Built from <details> so it needs no
   script and works the same on a phone, where it is mostly used. */
.emailer{grid-column:1/-1;border-top:1px solid var(--line-soft);margin-top:11px;padding-top:11px}
.emailer > summary{display:inline-flex;align-items:center;gap:8px;list-style:none;cursor:pointer;
  border:1px solid var(--line);border-radius:999px;padding:9px 16px;background:var(--surface);
  font:600 14px var(--sans);color:var(--brand-ink)}
.emailer > summary::-webkit-details-marker{display:none}
.emailer > summary:hover{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 7%,transparent)}
.emailer > summary .ico{font-size:15px;line-height:1}
.emailer[open] > summary{margin-bottom:13px}
.pick{display:grid;gap:7px;margin:0 0 13px}
.pick label{display:grid;grid-template-columns:auto 1fr;gap:3px 11px;align-items:start;margin:0;
  padding:11px 13px;border:1px solid var(--line);border-radius:var(--r);background:var(--field);
  cursor:pointer;text-transform:none;letter-spacing:0;font-weight:400}
.pick label:has(input:checked){border-color:var(--brand);
  background:color-mix(in srgb,var(--brand) 8%,transparent)}
.pick input{width:auto;margin:2px 0 0;grid-row:span 2;align-self:center}
.pick .n{font:600 14px/1.3 var(--sans);color:var(--ink)}
.pick .n b{display:block;font:400 12px/1.4 var(--sans);color:var(--ink-3)}
.pick .e{font:500 13px/1.3 var(--mono);color:var(--brand-ink);word-break:break-all}
.pick .has-portal{display:inline-block;font:700 9px/1 var(--sans);font-style:normal;text-transform:uppercase;
  letter-spacing:.08em;color:var(--ok);border:1px solid currentColor;border-radius:999px;
  padding:3px 6px 2px;margin-left:7px;vertical-align:2px}
@media (min-width:620px){.pick{grid-template-columns:1fr 1fr}}

/* --- a pencil that turns ---------------------------------------------------
   Sideways while a section is folded, pointing down while it is open, the way a
   disclosure arrow does — so the thing you press to edit also tells you whether
   you are editing. Rotated rather than swapped, so it moves rather than jumps. */
details.turn > summary .pen{width:17px;height:17px;flex:0 0 auto;
  transition:transform .22s cubic-bezier(.3,.7,.3,1)}
details.turn[open] > summary .pen{transform:rotate(90deg)}
@media (prefers-reduced-motion:reduce){details.turn > summary .pen{transition:none}}

/* the two ways of making a document, folded until wanted */
.section-fold{margin:0 0 12px}
.section-fold > summary{display:flex;align-items:center;gap:10px;list-style:none;cursor:pointer;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:14px 16px;font:600 15px var(--sans);color:var(--ink);box-shadow:var(--lift)}
.section-fold > summary::-webkit-details-marker{display:none}
.section-fold > summary:hover{border-color:var(--brand)}
.section-fold > summary .pen{color:var(--brand-ink)}
.section-fold[open] > summary{border-bottom-left-radius:0;border-bottom-right-radius:0;
  border-bottom-color:transparent;box-shadow:none}
.section-fold[open] > .card{border-top-left-radius:0;border-top-right-radius:0;margin-top:-1px}


/* --- the document list -----------------------------------------------------
   One line per document on a desk: kind, title, who it is for and when, the
   amount, where it stands, and the three things you do with it. The columns
   are the same width on every row so the amounts and the statuses line up down
   the page and can be read as a column.

   On a phone the same row takes two lines: what it is and what it costs on the
   first, who and when and what to do with it on the second. The tools become
   icons there, forty pixels square, because three labelled buttons and a date
   will not share a line a thumb can use. */
.row-item.doc-row{display:grid;align-items:center;column-gap:12px;row-gap:5px;
  padding:11px 14px 11px 18px;
  /* fixed widths everywhere but the title, so amounts and statuses form columns
     down the page even when a row has fewer tools than the one above it */
  grid-template-columns:92px minmax(0,1fr) 300px 132px 110px 296px;
  grid-template-areas:"kind title meta amount status tools"}
.doc-row > .kind{grid-area:kind;justify-self:start;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.doc-row > .d-title{grid-area:title;min-width:0}
.doc-row > .d-meta{grid-area:meta;min-width:0}
.doc-row > .d-amount{grid-area:amount;justify-self:end;display:flex;align-items:center;gap:6px;
  font:600 15px/1 var(--mono);font-variant-numeric:tabular-nums;color:var(--ink)}
.doc-row > .d-status{grid-area:status;justify-self:start}
.doc-row > .doc-tools{grid-area:tools;display:flex;gap:6px;justify-self:end}
.doc-row > .doc-panel{grid-column:1 / -1;margin-top:8px;padding:13px 14px 14px;
  background:var(--band);--field:var(--field-in-band);border:1px solid var(--line-soft);border-radius:var(--r)}

/* a long title takes two lines, never more */
.d-title a{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  font:600 15px/1.3 var(--sans);color:var(--ink);text-decoration:none;overflow-wrap:anywhere}
.d-title a:hover{color:var(--brand-ink);text-decoration:underline}
.d-meta{display:flex;align-items:baseline;gap:4px 12px;font-size:13px;color:var(--ink-2);overflow:hidden}
.d-meta .for{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.d-meta .when{white-space:nowrap;flex:0 0 auto}
.d-meta .k{margin-right:5px}

.tool{display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid var(--line);
  background:var(--surface);color:var(--brand-ink);border-radius:999px;padding:7px 12px;
  font:600 13px/1 var(--sans);text-decoration:none;cursor:pointer;white-space:nowrap}
.tool:hover{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 7%,transparent)}
.tool[aria-expanded="true"]{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 10%,transparent)}
.tool svg{width:15px;height:15px;flex:0 0 auto}
.tool .pen{transition:transform .22s cubic-bezier(.3,.7,.3,1)}
.tool[aria-expanded="true"] .pen{transform:rotate(90deg)}
@media (prefers-reduced-motion:reduce){.tool .pen{transition:none}}

.pill.sent{color:var(--brand-ink);border-color:currentColor}
.q-title,.q-amount{padding:6px 10px;font-size:14px;border-style:dashed}
.q-title{width:100%}
.q-amount{width:92px;font-family:var(--mono)}

/* the filter along the top: big enough for a thumb, and it scrolls sideways on
   a phone rather than wrapping into a block of buttons */
.doc-filter{display:flex;gap:8px;overflow-x:auto;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x proximity;scrollbar-width:none;padding:2px 2px 8px;margin:0 -2px 10px}
.doc-filter::-webkit-scrollbar{display:none}
.chip{flex:0 0 auto;scroll-snap-align:start;display:inline-flex;align-items:center;gap:9px;
  min-height:42px;padding:0 16px;border-radius:999px;border:1px solid var(--line);
  background:var(--surface);color:var(--ink-2);font:600 14px var(--sans);text-decoration:none;
  white-space:nowrap;box-shadow:var(--lift)}
.chip b{font:700 12px/1 var(--mono);background:var(--sunk);color:var(--ink-3);border-radius:999px;
  padding:4px 7px;min-width:24px;text-align:center}
.chip:hover{border-color:var(--brand);color:var(--ink)}
.chip.on{background:var(--brand);border-color:var(--brand);color:#fff}
.chip.on b{background:rgba(255,255,255,.24);color:#fff}
.chip.empty{opacity:.62}
.chip.alarm b{background:var(--over);color:#fff}

/* four to begin with, the rest on request */
.row-item.doc-row.later{display:none}
.more-docs{display:flex;align-items:center;justify-content:center;gap:14px;margin:12px 0 4px;
  font-size:13px}

@media (max-width:1179px){
  .row-item.doc-row{grid-template-columns:auto minmax(0,1fr) auto auto;
    grid-template-areas:"kind title title amount" "meta meta status tools"}
}
@media (max-width:699px){
  .row-item.doc-row{column-gap:8px;padding:10px 12px 10px 16px;
    grid-template-columns:auto minmax(0,1fr) auto 132px}
  .doc-row .d-status .pill.redundant{display:none}
  .doc-row > .kind{font-size:10px;padding:2px 7px;letter-spacing:.05em}
  .doc-row .tool .lbl{display:none}
  .doc-row .doc-tools .tool{width:40px;height:40px;padding:0}
  .doc-row .d-status .pill{font-size:10px;padding:3px 7px}
  .d-meta .k,.d-meta .yr{display:none}
  .d-meta .when::before{content:"\00B7";margin-right:6px;color:var(--ink-3)}
  .d-meta{gap:0 6px}
}

/* the list page is allowed to be wider than a page written to be read */
.page.wide{max-width:1480px}
.tool.tick{width:34px;height:34px;padding:0;font-size:16px}
.doc-panel .field.typed{max-width:520px;margin:4px 0 14px}
.doc-panel .field.typed input{font-family:var(--mono);font-size:14px}

/* --- sharing the portal with a client --------------------------------------
   Who can sign in, where each of them stands, and the one button that matters
   next to each: the invite, until it has gone. Adding somebody sits in a band
   below, because it is the part that edits. */
.portal-what{font-size:13px;margin:0 0 14px;max-width:66ch}
.portal-people{margin:0 0 14px;box-shadow:none}
.portal-people .row-item{align-items:center;gap:10px 14px}
.portal-people .row-item.is-off{background:var(--sunk)}
.portal-people .row-item.is-off .t{color:var(--ink-3)}
.portal-email{word-break:break-all}
.portal-actions form{margin:0}
.portal-actions{justify-content:flex-start}
@media (min-width:760px){.portal-actions{justify-content:flex-end}}
.portal-none{margin:0 0 14px;padding:14px 16px;border:1px dashed var(--line);border-radius:var(--r);
  color:var(--ink-3);font-size:14px}
.portal-add{background:var(--band);--field:var(--field-in-band);border:1px solid var(--line-soft);
  border-radius:var(--r);padding:14px 15px 12px;margin:0}
.portal-add > h3{margin:0 0 10px}
.portal-add > h3 .muted{font:600 11px/1 var(--sans);text-transform:uppercase;letter-spacing:.08em;margin-left:6px}
.portal-add .hint{font-size:12px;color:var(--ink-3);margin:10px 0 0}
fieldset.portal-add{margin:4px 0 16px;min-width:0}
/* date and calendar pickers drawn by the browser follow the theme too */
:root[data-theme="dark"]{color-scheme:dark}
@media (prefers-color-scheme:dark){:root[data-theme="system"]{color-scheme:dark}}

/* a client's view of a building's status: a plain line, not a warning label */
.calm{font:600 13px/1.4 var(--sans);color:var(--ink-2)}
.calm.ok{color:var(--ok)}
.calm.sent{color:var(--brand-ink)}

/* --- finding a document once there are hundreds ---------------------------- */
.doc-search{display:flex;gap:8px;margin:0 0 12px;max-width:560px}
.doc-search input{flex:1;min-width:0;min-height:44px;font-size:16px}
.doc-search .btn{min-height:44px}
.doc-found{font-size:13px;color:var(--ink-2);margin:-2px 0 12px}
.chip.quiet-chip:not(.on){background:transparent;box-shadow:none;border-style:dashed}
.list-more{display:flex;align-items:center;gap:14px;margin:12px 0 4px;font-size:13px}

/* --- the test copy ---------------------------------------------------------
   Striped and amber, in both themes, so a screenshot of it can never be taken
   for the real portal. */
.test-copy{position:relative;z-index:25;display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px;
  padding:7px 14px;font:600 13px/1.35 var(--sans);color:#1d1400;
  background:repeating-linear-gradient(135deg,#ffc53d 0 14px,#ffb81f 14px 28px);
  border-bottom:1px solid #b88100}
.test-copy b{font:800 11px/1 var(--sans);letter-spacing:.14em;text-transform:uppercase;
  background:#1d1400;color:#ffc53d;padding:4px 8px;border-radius:3px}

/* the off-site backup, on the admin home page: one quiet line while it is fine */
.backup-line{display:flex;flex-wrap:wrap;align-items:center;gap:6px 9px;margin:-8px 0 18px;font-size:13px;color:var(--ink-3)}
.backup-line .dot{width:8px;height:8px;border-radius:50%;background:var(--line)}
.backup-line.ok .dot{background:var(--ok)}
.backup-line.late{color:var(--over)}
.backup-line.late .dot{background:var(--over)}
.backup-line b{font-weight:700}

/* --- invoice lines -----------------------------------------------------------
   A table on a desk: description, quantity, unit price, and the amount it comes
   to. On a phone each line stacks: what it is across the top, the figures under
   it, so nothing has to be typed into a box the width of a thumbnail. */
.inv-lines{border:0;padding:0;margin:4px 0 12px;min-width:0}
.inv-lines legend{font:600 12px/1.3 var(--sans);letter-spacing:.03em;text-transform:uppercase;
  color:var(--ink-2);margin:0 0 8px;padding:0}
.inv-head,.inv-line{display:grid;grid-template-columns:minmax(0,1fr) 72px 118px 104px;gap:8px;align-items:center}
.inv-head{font:700 11px/1 var(--sans);text-transform:uppercase;letter-spacing:.07em;color:var(--ink-3);margin:0 0 7px}
.inv-head span:nth-child(n+2){text-align:right}
.inv-line{margin:0 0 8px}
.inv-line input[name="line_qty[]"],.inv-line input[name="line_price[]"]{text-align:right;font-variant-numeric:tabular-nums}
.inv-amt{text-align:right;font:600 14px/1 var(--mono);color:var(--ink-2);font-variant-numeric:tabular-nums}
@media (max-width:619px){
  .inv-head{display:none}
  .inv-line{grid-template-columns:76px minmax(0,1fr) auto;padding:0 0 10px;margin:0 0 10px;
    border-bottom:1px solid var(--line-soft)}
  .inv-line input[name="line_desc[]"]{grid-column:1 / -1}
  .inv-amt{min-width:84px}
}
.inv-bottom{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px 28px;margin:6px 0 16px}
.inv-tax{display:flex;flex-wrap:wrap;gap:8px 20px;padding-top:4px}
.inv-tax label{margin:0}
.inv-totals{display:grid;grid-template-columns:auto auto;gap:5px 20px;margin:0 0 0 auto;font-variant-numeric:tabular-nums}
.inv-totals dt{color:var(--ink-3);font-size:13px;text-align:right}
.inv-totals dd{margin:0;text-align:right;font:600 14px/1.3 var(--mono);color:var(--ink)}
.inv-totals .grand{font-size:16px;color:var(--ink);font-weight:700;padding-top:4px;border-top:1px solid var(--line)}
.inv-no{font:600 12px/1 var(--mono);color:var(--ink-3);letter-spacing:.02em}

/* a folded section holding something other than a plain card */
.section-fold > summary{flex-wrap:wrap}
.section-fold[open] > .alert-rule,.section-fold[open] > .rows{border-top-left-radius:0;border-top-right-radius:0;margin-top:-1px}
.section-fold[open] > .rows{border-top:1px solid var(--line)}
.rule-fold{margin:0 0 10px}
.rule-fold > summary .rule-name{font-weight:600}
.section-fold > summary .rule-who{flex:1 1 100%;font:400 12px/1.4 var(--sans);color:var(--ink-3);
  padding-left:27px;margin-top:-2px}
.section-fold > summary .pill{font-size:10px}

/* a client answering a quote: the two buttons sit with the other row tools and
   wrap rather than squeeze, because Accept is the one thing they came to press */
.doc-row .doc-tools{flex-wrap:wrap;justify-content:flex-end}
.doc-row .doc-tools .btn{white-space:nowrap}
.doc-row > .quote-answer{grid-column:1 / -1;display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;
  margin-top:6px;padding-top:10px;border-top:1px solid var(--line-soft)}
.doc-row > .quote-answer form{margin:0}
.doc-row > .quote-answer .muted{font-size:13px;margin-right:auto}
@media (max-width:699px){.doc-row > .quote-answer .muted{flex:1 1 100%;margin:0}}

/* --- directions ---------------------------------------------------------------
   A pill with a navigation arrow, beside the phone number, because the two
   questions about a building on the way to it are "how do I get there" and
   "who do I call when I arrive". */
.row-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px}
.directions{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:999px;
  padding:7px 13px 7px 11px;background:var(--surface);color:var(--brand-ink);text-decoration:none;
  font:600 13px/1 var(--sans);white-space:nowrap}
.directions:hover{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 7%,transparent)}
.directions svg{width:14px;height:14px;flex:0 0 auto}
@media (max-width:759px){.row-item .row-actions{justify-content:flex-start;margin-top:8px}}

/* --- the job sheet ---------------------------------------------------------------- */
.crumb{margin:0 0 4px;font-size:13px}
.job-head{display:grid;gap:14px}
.job-status{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;font-size:13px}
.job-go{display:flex;flex-wrap:wrap;gap:8px}
.job-steps{display:flex;flex-wrap:wrap;gap:10px;padding-top:12px;border-top:1px solid var(--line-soft)}
.job-steps form{margin:0}
.job-steps .btn{min-height:46px;font-size:15px}
.offline-note{margin:0 0 12px;padding:10px 12px;border-radius:var(--r);font-size:13px;font-weight:600;
  background:color-mix(in srgb,var(--brand) 9%,transparent);color:var(--brand-ink)}
.offline-note.bad{background:color-mix(in srgb,var(--due) 12%,transparent);color:var(--due)}
.h2-count{font:700 11px/1 var(--mono);background:var(--sunk);color:var(--ink-3);border-radius:999px;padding:4px 8px}
.photo-add{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin:0 0 14px}
.photo-pick{position:relative;overflow:hidden;min-height:46px;font-size:15px}
.photo-pick svg{width:18px;height:18px}
.photo-pick input{position:absolute;inset:0;opacity:0;cursor:pointer;font-size:0}
.photo-add.js .no-js-only{display:none}
.photo-status{flex:1 1 240px;margin:0;font-size:13px}
.photo-status.bad{color:var(--due);font-weight:600}
.photo-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px}
@media (max-width:420px){.photo-grid{grid-template-columns:repeat(2,1fr)}}
.photo{position:relative;margin:0;border-radius:var(--r);overflow:hidden;background:var(--sunk);aspect-ratio:1}
.photo img{display:block;width:100%;height:100%;object-fit:cover}
.photo form{position:absolute;top:6px;right:6px;margin:0}
.photo-x{width:30px;height:30px;border-radius:50%;border:0;background:rgba(6,12,22,.62);color:#fff;
  font:700 18px/1 var(--sans);cursor:pointer;display:grid;place-items:center;padding:0}
.photo.pending img{opacity:.55}
.photo-tag{position:absolute;left:6px;bottom:6px;font:700 10px/1 var(--sans);text-transform:uppercase;letter-spacing:.06em;
  background:rgba(6,12,22,.7);color:#fff;border-radius:999px;padding:5px 8px}
.photo.failed .photo-tag{background:var(--over)}
.office-tools form{margin:0}
