/* ═══════════════════════════════════════════════════════════════════════════
   BizOS — application layer
   ───────────────────────────────────────────────────────────────────────────
   Loaded AFTER gt-brand.css, which stays a verbatim copy of the website's
   tokens. This file is the app chrome, and it is a separate file on purpose:

     brand identity  = the wordmark, the blue, Barlow.          (gt-brand.css)
     app furniture   = surfaces, density, controls, layout.     (this file)

   A brochure and a tool that somebody uses for six hours a day should share
   the first and disagree about the second. Trying to serve both from one set
   of tokens is why the earlier panel read as a web page with buttons on it.

   WHAT CHANGED, AND WHY
   · White surfaces. The site's #f2f2f3 ground is right for a brochure and
     makes an app look unwashed. Cards are white, the canvas is near-white,
     and separation comes from a hairline plus a very low shadow.
   · Sentence-case controls. ALL-CAPS letterspaced buttons are the single
     loudest "this is a marketing site" signal. Kept ONLY for small eyebrow
     labels, where they are doing real work.
   · A 4px grid. The site's 3.4px scale produces half-pixel gaps at app
     density and nothing lines up.
   · Condensed type is now a brand MOMENT, not the default. Page titles and
     the wordmark only; everything else is Barlow regular, which is what a
     dense interface needs.
   · 6/8/12px radii instead of 2/4/7.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── surfaces: white-first ───────────────────────────────────────────── */
  --c-bg:            #ffffff;   /* cards, sidebar, menus */
  --c-canvas:        #fafafb;   /* the area behind cards */
  --c-sunken:        #f5f6f7;   /* table headers, inset wells, hover fills */
  --c-border:        #e6e7e9;
  --c-border-strong: #d3d5d8;

  /* ── ink ─────────────────────────────────────────────────────────────── */
  --c-ink:   #16181a;   /* headings, primary text */
  --c-ink-2: #55585c;   /* body, descriptions */
  /* #82868b looked right and measured 3.66:1 on white - a fail for 12px text,
     and 3.39:1 once it sat on the sunken fill behind a table header. Chosen by
     measurement, not by eye: 5.05:1 on white, 4.67:1 on --c-sunken. A tertiary
     ink still has to be readable; "de-emphasised" is not a licence to be
     illegible to anyone over forty in a badly lit back office. */
  --c-ink-3: #6b6f75;   /* meta, timestamps, placeholders */

  /* ── brand, used as the action colour ────────────────────────────────────
     #0033A0 is the site's own accent - not, as an earlier note here claimed,
     a departure from it. greattech.net has two :root blocks and the second
     resets --color-accent to the wordmark blue; reading only the first gives
     a slate the site never actually renders. So this ties the panel to the
     website AND to the logo, and measures 12.1:1 on white. */
  --c-brand:       #0033a0;
  --c-brand-hover: #002877;
  --c-brand-soft:  #eef3fd;
  --c-brand-ring:  rgba(0, 51, 160, .16);

  /* ── status. Desaturated for an app; a control panel shows these all day
        and saturated ones vibrate. ────────────────────────────────────── */
  --c-ok:    #0f7a46;  --c-ok-bg:    #ecf7f1;  --c-ok-br:    #b8e0cb;
  --c-warn:  #9a6206;  --c-warn-bg:  #fdf6e9;  --c-warn-br:  #edd6a6;
  --c-bad:   #b3271b;  --c-bad-bg:   #fdf0ee;  --c-bad-br:   #f2c3bc;
  --c-info:  #1f5f97;  --c-info-bg:  #eef4fb;  --c-info-br:  #c2d8ee;

  /* ── 4px grid ────────────────────────────────────────────────────────── */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 20px; --s6: 24px; --s8: 32px; --s10: 40px; --s12: 48px;

  /* ── radii ───────────────────────────────────────────────────────────── */
  --r-sm: 6px; --r-md: 8px; --r-lg: 12px; --r-full: 999px;

  /* ── elevation: low and tight. Big soft shadows read as 2014. ────────── */
  --sh-xs: 0 1px 2px rgba(16, 24, 40, .04);
  --sh-sm: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .04);
  --sh-md: 0 2px 4px rgba(16, 24, 40, .05), 0 4px 12px rgba(16, 24, 40, .06);
  --sh-lg: 0 8px 28px rgba(16, 24, 40, .10);

  /* ── type scale ──────────────────────────────────────────────────────── */
  --t-xs: 11px; --t-sm: 12px; --t-base: 13px; --t-md: 14px;
  --t-lg: 16px; --t-xl: 19px; --t-2xl: 23px; --t-3xl: 28px;

  --ease: cubic-bezier(.2, 0, .13, 1);
}

/* ── reset the brochure defaults gt-brand.css set ───────────────────────── */
body {
  background: var(--c-canvas);
  color: var(--c-ink-2);
  font-family: var(--font-body);
  font-size: var(--t-md);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, h5, h6 {
  color: var(--c-ink);
  font-family: var(--font-body);       /* condensed is now opt-in */
  font-weight: 600;
  letter-spacing: -0.006em;
  line-height: 1.3;
  margin: 0;
}
h1 { font-size: var(--t-2xl); letter-spacing: -0.015em; }
h2 { font-size: var(--t-xl); }
h3 { font-size: var(--t-lg); }
h4 { font-size: var(--t-md); }
p  { margin: 0; }
a  { color: var(--c-brand); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* The one place the condensed face still leads: a page title. It is the brand
   showing up where it is welcome, rather than everywhere. */
.title-brand {
  font-family: var(--font-heading);
  font-weight: 600;
  letter-spacing: -0.01em;
  font-size: var(--t-3xl);
  line-height: 1.15;
  color: var(--c-ink);
}

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--c-brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
::selection { background: var(--c-brand-ring); }

.muted  { color: var(--c-ink-3); }
.body-2 { color: var(--c-ink-2); }

/* Eyebrow. ALL-CAPS survives here because it is a label, not a control. */
.eyebrow {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--c-ink-3);
}

/* ═══ app shell ═══════════════════════════════════════════════════════════ */
.app {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  min-height: 100vh;
  background: var(--c-canvas);
}

.side {
  background: var(--c-bg);
  border-right: 1px solid var(--c-border);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
}
.side-brand { padding: var(--s5) var(--s4) var(--s4); min-width: 0; }
/* The rail is 260px and the lockup has three things in it. Left at the
   default sizes it measured 284px and clipped the GREAT TECH wordmark against
   the sidebar edge - and a clipped logo is the one thing a customer's eye
   goes straight to. Sized for the container it is actually in, rather than
   for the header it was designed in. */
.side-brand .lockup { gap: var(--s2); }
.side-brand .lockup .slot { height: 26px; }
.side-brand .lockup .slot svg,
.side-brand .lockup .slot img { max-width: 100px; }
.side-brand .lockup .gt-logo { height: 19px; }
.side-brand .lockup .plate { height: 26px; font-size: var(--t-base); padding: 0 var(--s2); }
.side-nav { padding: var(--s2) var(--s3); display: flex; flex-direction: column; gap: 2px; }
.side-sec {
  padding: var(--s4) var(--s3) var(--s2);
  font-size: var(--t-xs); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--c-ink-3);
}
.nav-item {
  display: flex; align-items: center; gap: var(--s3);
  padding: 7px var(--s3); border-radius: var(--r-sm);
  color: var(--c-ink-2); font-size: var(--t-md); font-weight: 500;
  cursor: pointer; border: 0; background: transparent; width: 100%;
  text-align: left; font-family: inherit;
  transition: background .12s var(--ease), color .12s var(--ease);
}
.nav-item svg { flex: none; color: var(--c-ink-3); transition: color .12s var(--ease); }
.nav-item:hover { background: var(--c-sunken); color: var(--c-ink); text-decoration: none; }
.nav-item:hover svg { color: var(--c-ink-2); }
.nav-item[aria-current="page"] {
  background: var(--c-brand-soft); color: var(--c-brand); font-weight: 600;
}
.nav-item[aria-current="page"] svg { color: var(--c-brand); }
.nav-item .count {
  margin-left: auto; font-size: var(--t-sm); color: var(--c-ink-3);
  font-variant-numeric: tabular-nums;
}
.side-foot {
  margin-top: auto; padding: var(--s4);
  border-top: 1px solid var(--c-border);
  display: flex; flex-direction: column; gap: var(--s2);
  font-size: var(--t-sm); color: var(--c-ink-3);
}

/* ── top bar ────────────────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s4);
  padding: 0 var(--s6); height: 56px;
  background: rgba(255, 255, 255, .86);
  backdrop-filter: saturate(180%) blur(8px);
  -webkit-backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--c-border);
}
.crumbs { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-md); }
.crumbs .sep { color: var(--c-border-strong); }
.crumbs .here { color: var(--c-ink); font-weight: 600; }

.search {
  display: flex; align-items: center; gap: var(--s2);
  background: var(--c-sunken); border: 1px solid transparent;
  border-radius: var(--r-sm); padding: 0 var(--s3); height: 34px;
  min-width: 220px; color: var(--c-ink-3);
  transition: border-color .12s var(--ease), background .12s var(--ease);
}
.search:focus-within { background: var(--c-bg); border-color: var(--c-brand); box-shadow: 0 0 0 3px var(--c-brand-ring); }
.search input {
  border: 0; background: transparent; outline: none; font: inherit;
  font-size: var(--t-md); color: var(--c-ink); width: 100%;
  /* Fill the wrapper. Left to its intrinsic height the input measured 23px,
     under the 24px minimum target size, even though the box around it looked
     comfortably large. */
  height: 100%; align-self: stretch;
}
.search input::placeholder { color: var(--c-ink-3); }

.kbd {
  font-family: var(--font-mono); font-size: var(--t-xs);
  padding: 2px 5px; border: 1px solid var(--c-border);
  border-bottom-width: 2px; border-radius: 4px;
  background: var(--c-bg); color: var(--c-ink-3);
}

/* ── the person signed in ──────────────────────────────────────────────────
   Initials until there is a photo, and the photo once there is one. It sits at
   the foot of the rail next to a status badge and two lines of small grey text,
   so it has to read as a person rather than as one more chip in a stack.

   32px, not 28: a two-letter monogram at --t-sm had no room inside 28 and the
   whole thing read as a coloured dot. Barlow is loaded here at 400 and 600 and
   nothing heavier, so the weight stays 600 - asking for 700 would get a
   synthesised bold, which on a two-letter monogram at this size is obvious.
   The presence comes from the size, the tracking and the ring instead. */
.avatar {
  width: 32px; height: 32px; flex: none;
  border-radius: var(--r-full);
  display: grid; place-items: center;
  overflow: hidden;                    /* clips a photo to the circle */
  /* Solid, not the soft tint the chips use. The rail is pure white and
     --c-brand-soft is a whisper above it, so a tinted circle disappeared - and
     the two things beside it are already soft-tinted pills, which a third soft
     shape would just join. Filled, it reads as a person rather than as another
     status. */
  background: var(--c-brand);
  color: #fff;
  font-size: var(--t-md); font-weight: 600;
  letter-spacing: .03em; text-transform: uppercase; line-height: 1;
  /* Depth only - a ring in the brand colour is invisible against a brand
     fill, and a photo would cover an inset one. */
  box-shadow: var(--sh-xs);
  user-select: none;
}

/* The photo, when an account has one. object-fit keeps a non-square crop from
   stretching a face. */
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Nobody to show: signed out, or a name with no letters in it. Deliberately
   grey rather than brand-blue - an empty state should not look like a person. */
.avatar.is-anon {
  background: var(--c-sunken); color: var(--c-ink-3);
  box-shadow: 0 0 0 1px var(--c-border), var(--sh-xs);
}
.avatar.is-anon svg { width: 18px; height: 18px; opacity: .8; }

/* One size up, for an account screen. Same object, not a second one. */
.avatar-lg {
  width: 56px; height: 56px;
  font-size: var(--t-xl); letter-spacing: .04em;
  box-shadow: var(--sh-sm);
}
.avatar-lg.is-anon svg { width: 30px; height: 30px; }

.pagehead { padding: var(--s8) var(--s6) var(--s5); }
.pagehead .lede { margin-top: var(--s2); max-width: 64ch; color: var(--c-ink-2); }
.content { padding: 0 var(--s6) var(--s12); }

/* ═══ buttons ═════════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 36px; padding: 0 var(--s4);
  font-family: var(--font-body); font-size: var(--t-md); font-weight: 600;
  letter-spacing: 0; text-transform: none;         /* the big one */
  border-radius: var(--r-sm); border: 1px solid transparent;
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background .12s var(--ease), border-color .12s var(--ease),
              box-shadow .12s var(--ease), color .12s var(--ease);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(.5px); }
.btn svg { flex: none; }

.btn-primary { background: var(--c-brand); color: #fff; box-shadow: var(--sh-xs); }
.btn-primary:hover { background: var(--c-brand-hover); }
.btn-primary:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--c-brand-ring); }

.btn-secondary {
  background: var(--c-bg); color: var(--c-ink);
  border-color: var(--c-border-strong); box-shadow: var(--sh-xs);
}
.btn-secondary:hover { background: var(--c-sunken); }

.btn-ghost { background: transparent; color: var(--c-ink-2); }
.btn-ghost:hover { background: var(--c-sunken); color: var(--c-ink); }

.btn-danger { background: var(--c-bad); color: #fff; }
.btn-danger:hover { filter: brightness(.94); }

.btn-sm { height: 30px; padding: 0 var(--s3); font-size: var(--t-base); }
.btn-lg { height: 40px; padding: 0 var(--s5); font-size: var(--t-lg); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
.btn-block { width: 100%; }

/* ═══ badges ══════════════════════════════════════════════════════════════ */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 var(--s2);
  font-size: var(--t-sm); font-weight: 600; letter-spacing: 0;
  border-radius: var(--r-sm); border: 1px solid transparent;
  white-space: nowrap;
}
.badge .dot { width: 6px; height: 6px; border-radius: var(--r-full); background: currentColor; flex: none; }
.badge-neutral { background: var(--c-sunken); color: var(--c-ink-2); border-color: var(--c-border); }
.badge-ok      { background: var(--c-ok-bg);   color: var(--c-ok);   border-color: var(--c-ok-br); }
.badge-warn    { background: var(--c-warn-bg); color: var(--c-warn); border-color: var(--c-warn-br); }
.badge-bad     { background: var(--c-bad-bg);  color: var(--c-bad);  border-color: var(--c-bad-br); }
.badge-info    { background: var(--c-info-bg); color: var(--c-info); border-color: var(--c-info-br); }
.badge.pulsing .dot { animation: bz-pulse 1.4s var(--ease) infinite; }
@keyframes bz-pulse { 0%,100%{opacity:1} 50%{opacity:.3} }
@media (prefers-reduced-motion: reduce) { .badge.pulsing .dot { animation: none } }

/* ═══ cards ═══════════════════════════════════════════════════════════════ */
.card {
  background: var(--c-bg); border: 1px solid var(--c-border);
  border-radius: var(--r-lg); box-shadow: var(--sh-xs);
}
.card-pad { padding: var(--s5); }
.card-head {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s4) var(--s5); border-bottom: 1px solid var(--c-border);
}
.card-head h3 { font-size: var(--t-md); }

/* ── job tiles ──────────────────────────────────────────────────────────── */
.jobs { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--s4); }
.job {
  background: var(--c-bg); border: 1px solid var(--c-border);
  border-radius: var(--r-lg); padding: var(--s5);
  display: flex; flex-direction: column; gap: var(--s3);
  box-shadow: var(--sh-xs); position: relative;
  transition: border-color .14s var(--ease), box-shadow .14s var(--ease), transform .14s var(--ease);
}
.job:hover { border-color: var(--c-border-strong); box-shadow: var(--sh-md); transform: translateY(-1px); }
.job-top { display: flex; align-items: flex-start; gap: var(--s3); }
.job-ico {
  width: 36px; height: 36px; border-radius: var(--r-md); flex: none;
  display: grid; place-items: center;
  background: var(--c-brand-soft); color: var(--c-brand);
}
/* The category is an eyebrow ABOVE the title, clamped to one line. Letting it
   wrap put two lines of secondary text between the icon and the thing you
   actually read, and made every tile in the row a different height. */
.job .cat {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--c-ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: block; margin-bottom: 2px;
}
.job h3 { font-size: var(--t-md); margin: 0; line-height: 1.35; }
.job .desc { font-size: var(--t-base); color: var(--c-ink-2); line-height: 1.55; flex: 1; }
/* Status lives in the FOOTER, not on the title line. A badge floated beside a
   heading that wraps to two lines gives every card a ragged top edge, and the
   eye reads the ragged edge before it reads any of the titles. */
.job-foot {
  display: flex; align-items: center; gap: var(--s2);
  padding-top: var(--s3); border-top: 1px solid var(--c-border);
}
.job-foot .meta {
  font-size: var(--t-sm); color: var(--c-ink-3); margin-left: auto;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ═══ banners (the verdict) ═══════════════════════════════════════════════ */
.banner {
  display: flex; gap: var(--s4); align-items: flex-start;
  padding: var(--s4) var(--s5);
  border: 1px solid var(--c-border); border-radius: var(--r-lg);
  background: var(--c-bg);
}
.banner h2 { font-size: var(--t-lg); margin: 0 0 2px; }
.banner p  { font-size: var(--t-md); color: var(--c-ink-2); }
.banner .caveat {
  margin-top: var(--s3); padding-top: var(--s3);
  border-top: 1px dashed var(--c-border-strong);
  font-size: var(--t-base); color: var(--c-ink-2);
}
.banner-ok   { background: var(--c-ok-bg);   border-color: var(--c-ok-br); }
.banner-warn { background: var(--c-warn-bg); border-color: var(--c-warn-br); }
.banner-bad  { background: var(--c-bad-bg);  border-color: var(--c-bad-br); }
.banner-info { background: var(--c-info-bg); border-color: var(--c-info-br); }
.banner-ok h2   { color: #0b5e35; }
.banner-warn h2 { color: #7d4f05; }
.banner-bad h2  { color: #8f1f15; }

/* ═══ tables ══════════════════════════════════════════════════════════════ */
.tbl-wrap { border: 1px solid var(--c-border); border-radius: var(--r-lg); overflow: hidden; background: var(--c-bg); }
.tbl { width: 100%; border-collapse: collapse; font-size: var(--t-md); }
.tbl th {
  text-align: left; font-size: var(--t-sm); font-weight: 600;
  color: var(--c-ink-3); padding: var(--s3) var(--s4);
  background: var(--c-sunken); border-bottom: 1px solid var(--c-border);
  white-space: nowrap;
}
.tbl td { padding: var(--s3) var(--s4); border-bottom: 1px solid var(--c-border); color: var(--c-ink-2); }
.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl tbody tr:hover td { background: var(--c-canvas); }
.tbl .mono { font-family: var(--font-mono); font-size: var(--t-base); color: var(--c-ink); }
.tbl .num  { font-variant-numeric: tabular-nums; text-align: right; }
.tbl .strong { color: var(--c-ink); font-weight: 500; }
/* A row the customer must actually look at. In a list of 340 routine price
   rises, the one that moved 231% because somebody lost a decimal point is the
   entire argument for showing a plan before writing it -- so it gets a tinted
   row and a left marker, not the same treatment as its neighbours. */
.tbl tr.flag td { background: var(--c-warn-bg); }
.tbl tr.flag:hover td { background: #fbf1dd; }
.tbl tr.flag td:first-child { box-shadow: inset 3px 0 0 var(--c-warn); }
.tbl .delta { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--c-ink-2); }
.tbl tr.flag .delta { color: var(--c-warn); }
.tbl .arrow { color: var(--c-ink-3); padding: 0 6px; }
.tbl .was { color: var(--c-ink-3); text-decoration: line-through; text-decoration-thickness: 1px; }
.tbl .now { color: var(--c-ink); font-weight: 600; }

/* ═══ log ═════════════════════════════════════════════════════════════════ */
.log {
  background: #15171a; color: #d7dade;
  font-family: var(--font-mono); font-size: var(--t-base); line-height: 1.6;
  padding: var(--s4) var(--s5); border-radius: var(--r-lg);
  max-height: 340px; overflow: auto; white-space: pre-wrap; word-break: break-word;
}
.log .a { color: #62c98d } .log .w { color: #e0b567 }
.log .e { color: #f08e7c } .log .d { color: #9aa0a6 }
/* A job that fails before it starts - the agent not being installed, say -
   emits no log lines at all, and an empty terminal rendered as a squat black
   bar under the verdict. Say there is nothing rather than drawing a void. */
.log:empty { min-height: 0; padding: var(--s3) var(--s5); }
.log:empty::before {
  content: "No output from this job.";
  color: #9aa0a6; font-style: normal;
}

/* ═══ disclosure ══════════════════════════════════════════════════════════ */
details.disc { border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-bg); }
details.disc > summary {
  cursor: pointer; list-style: none; padding: var(--s3) var(--s5);
  font-size: var(--t-md); font-weight: 600; color: var(--c-ink-2);
  display: flex; align-items: center; gap: var(--s2);
}
details.disc > summary::-webkit-details-marker { display: none; }
details.disc > summary:hover { color: var(--c-ink); }
details.disc > summary .chev { transition: transform .15s var(--ease); color: var(--c-ink-3); }
details.disc[open] > summary .chev { transform: rotate(90deg); }
details.disc[open] > summary { border-bottom: 1px solid var(--c-border); }
details.disc .disc-body { padding: var(--s5); }

/* ═══ forms ═══════════════════════════════════════════════════════════════ */
.field { display: flex; flex-direction: column; gap: 6px; }
.field > label { font-size: var(--t-base); font-weight: 600; color: var(--c-ink); }
.field .hint { font-size: var(--t-base); color: var(--c-ink-3); }
.input {
  height: 38px; padding: 0 var(--s3); font: inherit; font-size: var(--t-md);
  color: var(--c-ink); background: var(--c-bg);
  border: 1px solid var(--c-border-strong); border-radius: var(--r-sm);
  transition: border-color .12s var(--ease), box-shadow .12s var(--ease);
  width: 100%;
}
.input::placeholder { color: var(--c-ink-3); }
.input:focus { outline: none; border-color: var(--c-brand); box-shadow: 0 0 0 3px var(--c-brand-ring); }

/* ═══ segmented control ═══════════════════════════════════════════════════ */
.seg {
  display: inline-flex; background: var(--c-sunken);
  border: 1px solid var(--c-border); border-radius: var(--r-sm); padding: 2px; gap: 2px;
}
.seg button {
  border: 0; background: transparent; cursor: pointer; font: inherit;
  font-size: var(--t-base); font-weight: 600; color: var(--c-ink-3);
  padding: 5px var(--s3); border-radius: 4px;
  transition: background .12s var(--ease), color .12s var(--ease);
}
.seg button:hover { color: var(--c-ink); }
.seg button[aria-selected="true"] { background: var(--c-bg); color: var(--c-ink); box-shadow: var(--sh-xs); }

/* ═══ empty state ═════════════════════════════════════════════════════════ */
.empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
  padding: var(--s12) var(--s6); text-align: center;
  border: 1px dashed var(--c-border-strong); border-radius: var(--r-lg);
  background: var(--c-bg);
}
.empty .ico { color: var(--c-ink-3); }
.empty h3 { font-size: var(--t-md); }
.empty p { font-size: var(--t-base); color: var(--c-ink-3); max-width: 42ch; }

/* ═══ hold-to-confirm ═════════════════════════════════════════════════════ */
.hold-btn {
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--c-bad); color: #fff; border-color: transparent;
}
.hold-btn .fill {
  position: absolute; inset: 0 auto 0 0; width: 0%; z-index: -1;
  background: rgba(0, 0, 0, .26);
  transition: width .06s linear;
}
.hold-btn[data-armed="1"] { background: var(--c-ok); }

/* ═══ co-brand lockup ═════════════════════════════════════════════════════ */
.lockup { display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.lockup .slot { display: flex; align-items: center; height: 30px; flex: none; }
.lockup .slot svg, .lockup .slot img { height: 100%; width: auto; max-width: 132px; object-fit: contain; }
.lockup .rule { width: 1px; align-self: stretch; min-height: 26px; background: var(--c-border); flex: none; }
/* The wordmark's artwork carries a long fading beam to the right of the
   letters, so its bounding box is far wider than the text reads. At 24px in a
   244px sidebar that pushed the lockup against the edge and looked lopsided.
   22px in a 260px rail gives the beam the room it was drawn to have. */
.lockup .gt-logo { height: 22px; width: auto; display: block; flex: none; }
.lockup .plate {
  display: flex; align-items: center; height: 30px; padding: 0 var(--s3);
  border: 1px dashed var(--c-border-strong); border-radius: var(--r-sm);
  font-size: var(--t-md); font-weight: 600; color: var(--c-ink); white-space: nowrap;
}
.wordmark { display: flex; flex-direction: column; justify-content: center; line-height: 1.05; }
.wordmark b { font-family: var(--font-heading); font-weight: 600; font-size: 18px; letter-spacing: .01em; color: var(--c-ink); }
.wordmark i { font-family: var(--font-heading); font-style: normal; font-size: 9px; letter-spacing: .16em; color: var(--c-ink-3); margin-top: 1px; }

/* ═══ misc ════════════════════════════════════════════════════════════════ */
.row  { display: flex; align-items: center; gap: var(--s3); }
.grow { flex: 1 1 auto; min-width: 0; }
.stack{ display: flex; flex-direction: column; }
.divider { height: 1px; background: var(--c-border); border: 0; margin: var(--s6) 0; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ═══ responsive ══════════════════════════════════════════════════════════ */
/* Below 1000px the rail becomes two stacked rows rather than one horizontal
   strip. As a single strip the co-brand lockup ate most of the width and
   pushed the nav off-screen behind a horizontal scroll nobody discovers --
   the branding was literally hiding the navigation. */
@media (max-width: 1000px) {
  .app { grid-template-columns: 1fr; }
  .side {
    position: static; height: auto; flex-direction: column; align-items: stretch;
    gap: 0; border-right: 0; border-bottom: 1px solid var(--c-border);
    padding: 0;
  }
  .side-brand { padding: var(--s3) var(--s4); }
  .side-nav {
    flex-direction: row; gap: var(--s1);
    padding: 0 var(--s3) var(--s2);
    overflow-x: auto; scrollbar-width: none;
  }
  .side-nav::-webkit-scrollbar { display: none; }
  .nav-item { width: auto; white-space: nowrap; }
  .side-sec, .side-foot { display: none; }
  .nav-item .count { display: none; }
}
@media (max-width: 720px) {
  .pagehead { padding: var(--s6) var(--s4) var(--s4); }
  .content  { padding: 0 var(--s4) var(--s10); }
  .topbar   { padding: 0 var(--s4); gap: var(--s2); }
  .search   { min-width: 0; flex: 1; }
  /* A keyboard hint on a device with no keyboard, stealing room from the
     field it labels. */
  .search .kbd { display: none; }
  .jobs     { grid-template-columns: 1fr; }
  .title-brand { font-size: var(--t-2xl); }
  .crumbs .sep, .crumbs .root { display: none; }
  .lockup .slot svg, .lockup .slot img { max-width: 108px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Utilities
   ───────────────────────────────────────────────────────────────────────────
   These exist because the panel ships a strict Content-Security-Policy with
   `style-src 'self'` and NO 'unsafe-inline'. That means a style="" attribute
   is silently dropped by the browser -- the markup looks right, the DOM has
   the attribute, and the computed value is simply ignored.

   It cost a broken login page to find, because a standalone demo file has no
   CSP and looked perfect. Anything the templates need must be a class.
   Relaxing the policy instead would have been one character of work and a
   permanent hole in the panel a customer's whole office can reach.
   ═══════════════════════════════════════════════════════════════════════ */

/* layout */
.auth-wrap { min-height: 100vh; display: grid; place-items: center; padding: var(--s6); }
.auth-card { width: 100%; max-width: 400px; gap: var(--s5); box-shadow: var(--sh-lg); }
.measure   { max-width: 940px; }
.contents  { display: contents; }
.tc        { text-align: center; }
.w-full    { width: 100%; }

/* spacing */
.mt-05 { margin-top: 2px; }  .mt-1 { margin-top: 6px; }
.mt-2  { margin-top: var(--s2); }  .mt-4 { margin-top: var(--s4); }
.mb-4  { margin-bottom: var(--s4); }
.ml-1  { margin-left: 6px; }
.p-0   { padding: 0; }
.pad-6 { padding: var(--s6); }
.gap-1 { gap: var(--s1); }  .gap-2 { gap: var(--s2); }
.gap-3 { gap: var(--s3); }  .gap-4 { gap: var(--s4); }
.gap-5 { gap: var(--s5); }

/* type */
.t-sm   { font-size: var(--t-sm); }
.t-base { font-size: var(--t-base); }
.t-lg   { font-size: var(--t-lg); }
.t-xl   { font-size: var(--t-xl); }
.h1-lg  { font-size: var(--t-2xl); }
.fw-400 { font-weight: 400; }

/* component variants that were being done inline */
.banner-sm  { padding: var(--s3) var(--s4); }
.tbl-flush  { border: 0; border-radius: 0; }
.job-ico-lg { width: 40px; height: 40px; }
.col-time   { width: 90px; }
.col-who    { width: 160px; }
.col-result { width: 170px; }
.col-item   { width: 150px; }
.col-value  { width: 150px; }
.col-change { width: 90px; }
.lockup-center { display: flex; justify-content: center; }
