/* building — design tokens & base styles (SPEC.md §12).
   Aesthetic: OpenAI / Notion / Vercel — monochrome, whitespace, subtle borders. */

:root {
  --bg: #ffffff;
  --sidebar: #f7f7f8;
  --fg: #0a0a0a;
  --muted: #6b7280;
  --border: #e5e7eb;
  --accent: #111827;
  --accent-fg: #ffffff;
  --link: #2563eb;
  --radius: 8px;
  --space: 8px;

  --green: #047857; --green-bg: #ecfdf5;
  --amber: #b45309; --amber-bg: #fffbeb;
  --blue:  #1d4ed8; --blue-bg:  #eff6ff;
  --grey:  #374151; --grey-bg:  #f3f4f6;
  --red:   #b91c1c; --red-bg:   #fef2f2;

  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
/* 16px base: form inputs use `font: inherit`, and iOS Safari zooms into any field whose
   computed font-size is < 16px on focus — 16px here keeps login/signup fields from zooming. */
body { color: var(--fg); background: var(--bg); font-size: 16px; line-height: 1.5; }
/* Links: navigation/brand/buttons are neutral (set below); content links (in page
   content, footers, cards) are a consistent colour + underlined. */
a { color: inherit; text-decoration: none; }
.site-main a:not(.btn), .site-footer a:not(.btn), .auth-card a:not(.btn),
.main a:not(.btn):not(.subnav-link) {
  color: var(--link); text-decoration: underline;
}
.btn { text-decoration: none; }

/* The app/dashboard shell locks the viewport (only the main panel scrolls).
   Marketing and auth shells scroll normally. The shell class lives on the #shell wrapper
   (inside <body>) so htmx boost + back/forward swap it natively; body is height:100%. */
:root { --topbar-h: 49px; --sidebar-w-full: 248px; }
.app-shell {
  min-height: 100%;
  display: flex; flex-direction: column;
}

/* --- Sandbox banner (SPEC §12.7) — site-wide invite-only notice ---------- */
:root { --sandbox-h: 40px; }
.sandbox-banner {
  height: var(--sandbox-h);
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 0 14px; text-align: center;
  background: #7c2d12; color: #fff;            /* amber-900: clearly "not production" */
  font-size: 13px; line-height: 1.25; font-weight: 500;
}
.sandbox-banner strong { font-weight: 700; }
/* Admin-bypass banner (SPEC §12.7) — stacks ABOVE the sandbox banner for signed-in staff. Red so
   it reads as "you are not seeing the normal gated experience". */
:root { --admin-h: 40px; }
.admin-banner {                                /* inline in-page notice (dashboard + billing only) */
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; text-align: center; border-radius: 8px; margin-bottom: 16px;
  background: #b91c1c; color: #fff;            /* red-700: clearly an admin/bypass state */
  font-size: 13px; line-height: 1.3; font-weight: 600;
}
/* The banners are normal flow above #shell. In the locked app shell, reserve their height so the
   sidebar/main still fit the viewport (marketing/auth scroll normally, so the banners just scroll
   away there). The combined selector wins when both banners are present (additive). No-op unless
   the banner is present. */
/* Banners are normal flow above #shell and scroll off the top with the page (§12.7); the app-shell
   top bar + sidebar are sticky, so only the banners leave. Auth keeps its centred min-height. */
.has-sandbox-banner .auth-wrap { min-height: calc(100vh - var(--sandbox-h)); }
.has-admin-banner .auth-wrap { min-height: calc(100vh - var(--admin-h)); }
.has-admin-banner.has-sandbox-banner .auth-wrap { min-height: calc(100vh - var(--admin-h) - var(--sandbox-h)); }
@media (max-width: 600px) {
  :root { --sandbox-h: 56px; --admin-h: 56px; }  /* room for the message to wrap on phones */
  .sandbox-banner, .admin-banner { white-space: normal; }
}

/* --- Icons --------------------------------------------------------------- */
.icon {
  width: 18px; height: 18px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* --- App shell: full-viewport, only the main panel scrolls --------------- */
/* Persistent top bar: brand left, user-menu widget top-right (same across all shells).
   EDGE GEOMETRY (shared with .app2-topbar below — same metrics, different surface): the heart
   sits 12px from the left; the right pad is 10px, aligning the user-menu trigger's HOVER PILL
   edge with the heart's margin (owner-tuned by eye: exact 12px read as slightly too far in —
   pill alignment rather than caret-glyph alignment, also the owner's call). */
.topbar {
  display: flex; align-items: center; gap: 12px; flex: 0 0 auto; padding: 8px 10px 8px 0;
  height: var(--topbar-h); box-sizing: border-box;
  background: var(--sidebar); border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 30;   /* stays; the banner above scrolls off */
}
.topbar .brand { text-decoration: none; color: inherit; }
.topbar-actions { margin-left: auto; display: flex; align-items: center; }

/* app2's top bar (SPEC §22): the SAME metrics as .topbar above — height via --topbar-h and the
   identical edge geometry — only the surface differs (app2 is white, app is grey). The rules live
   HERE, beside .topbar, so the two headers cannot drift apart again; app2.html keeps only its
   page-specific styles. Content alignment: the "B" of the brand text starts at
   12px pad + 22px icon + 8px gap = 42px, and .app2-main/.app2-subnav use that as their x padding
   so content lines up under the B, not under the heart — with the equal 42px on the right. */
.app2-topbar { display: flex; align-items: center; gap: 20px;
               height: var(--topbar-h); box-sizing: border-box; padding: 8px 10px 8px 12px;
               border-bottom: 1px solid var(--line, #e5e5e5); position: sticky; top: 0;
               z-index: 30; background: var(--bg, #fff); }
.app2-topbar .brand { text-decoration: none; color: inherit; }
.app2-primary { display: flex; gap: 14px; }
.app2-primary a { text-decoration: none; color: inherit; font-weight: 600; padding: 4px 2px; }
.app2-actions { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.app2-subnav { padding: 0 42px; border-bottom: 1px solid var(--line, #e5e5e5); }
.app2-subnav .subnav { margin: 0; }
.app2-main { padding: 18px 42px; }
@media (max-width: 768px) {
  .app2-topbar { padding: 8px 9px 8px 10px; gap: 12px; }   /* owner-tuned mobile edges, = .topbar's */
  .app2-subnav { padding: 0 14px; }
  .app2-main { padding: 14px; }
}
/* Logo + toggle share the sidebar's (expanded) width, so the toggle lands at the sidebar's right
   edge. Fixed width — the brand never squeezes when the rail collapses. */
/* Spans exactly the sidebar column (its own left pad matches the sidebar's), so the toggle lands
   on the sidebar's right edge — not past it. */
.topbar-brand { display: flex; align-items: center; justify-content: space-between; gap: 12px;
                width: var(--sidebar-w-full); box-sizing: border-box; padding-left: 12px;
                flex: 0 0 auto; }
@media (max-width: 768px) { .topbar-brand { width: auto; } }  /* natural width on phones */
/* TWO nav toggles, exactly one visible (SPEC §12.2.3): the desktop chevron lives in the brand
   segment (at the sidebar's right edge); the mobile hamburger/✕ is a separate button at the
   topbar's EXTREME right (past the AI + account icons), swapped to an ✕ while the drawer is open.
   COMPOUND selector on purpose: the button also carries .icon-btn, whose `display: flex` (below)
   ties this rule on specificity and won on order — hamburger+✕ leaked onto desktop (owner-caught
   2026-07-12). .icon-btn.shell-toggle-m outranks it whatever the order. */
.icon-btn.shell-toggle-m { display: none; }
.shell-toggle-m .x-icon { display: none; }
.shell-toggle .chev-expand { display: none; }
@media (min-width: 769px) {
  .nav-collapsed .shell-toggle .chev-collapse { display: none; }
  .nav-collapsed .shell-toggle .chev-expand { display: inline; }   /* points right = expand */
  /* Collapsed: shrink the segment so the arrow tucks right up against the brand. */
  .nav-collapsed .topbar-brand { width: auto; gap: 6px; }
}
.icon-btn {
  border: none; background: none; cursor: pointer; color: var(--fg);
  padding: 6px; border-radius: 6px; display: flex;
}
.icon-btn:hover { background: #ececee; }
.backdrop { display: none; }

.app {
  flex: 1 1 auto; min-height: 0;          /* fill remaining viewport height */
  display: grid;
  grid-template-columns: var(--sidebar-w, 248px) 1fr;
  transition: grid-template-columns 0.15s ease;
}

.sidebar {
  background: var(--sidebar);
  border-right: 1px solid var(--border);
  padding: 12px;
  display: flex; flex-direction: column; gap: 12px;
  overflow-y: auto; min-height: 0;        /* its own scroll if nav grows */
}
.brand-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 16px; letter-spacing: -0.01em; }
.brand-icon { width: 22px; height: 22px; }
.collapse-btn {
  border: none; background: none; cursor: pointer; color: var(--muted);
  padding: 4px; border-radius: 6px; display: flex;
}
.collapse-btn:hover { background: #ececee; color: var(--fg); }
.chev-expand { display: none; }  /* only shown when collapsed (re-open affordance) */
.switcher { color: var(--muted); font-size: 13px; padding: 0; }
.switcher-current {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-weight: 600; color: var(--fg); margin-bottom: 6px;
}
.switcher-select { max-width: 240px; }
.nav { display: flex; flex-direction: column; gap: 2px; }
.nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--radius); color: var(--fg); white-space: nowrap;
}
.nav a:hover { background: #ececee; }
.nav a.active { background: #e6e6e9; font-weight: 600; }
/* indented sub-items (rooms under Requirements, phases under Build) */
.nav a.nav-sub { padding: 4px 10px 4px 24px; font-size: 13px; color: var(--muted); gap: 8px; }
.nav a.nav-sub .icon { width: 15px; height: 15px; }
.nav a.nav-sub:hover { color: var(--fg); }
.sidebar .spacer { flex: 1; }
.sidebar hr { border: none; border-top: 1px solid var(--border); margin: 4px 0; }

/* Collapsed state (desktop only): icon-only rail, centred. Class lives on <html>
   and is applied before first paint, so navigating never flashes. */
@media (min-width: 769px) {
  .nav-collapsed { --sidebar-w: 60px; }
  .nav-collapsed .nav-label,
  .nav-collapsed .nav a.nav-sub { display: none; }
  .nav-collapsed .sidebar { padding-left: 8px; padding-right: 8px; }
  .nav-collapsed .nav a { justify-content: center; gap: 0; padding: 8px 0; }
}

.main { padding: calc(var(--space) * 4); }   /* the page scrolls; the top bar + sidebar are sticky */
/* Desktop: the sidebar sticks below the top bar and scrolls independently if the nav is long.
   Extra bottom padding (12px on top of the base 12px): the browser's link-preview overlay sits
   over the bottom corner and was covering the last entry (Policies) — this keeps the full label
   plus a little air visible above it. */
@media (min-width: 769px) {
  .sidebar { position: sticky; top: var(--topbar-h); align-self: start;
             height: calc(100vh - var(--topbar-h)); padding-bottom: 24px; }
}
.page-title { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 4px; }
.page-sub { color: var(--muted); margin: 0 0 24px; }

/* --- Components ---------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--accent); background: var(--accent); color: var(--accent-fg);
  border-radius: var(--radius); padding: 8px 14px; font-size: 14px; cursor: pointer;
}
.btn:hover { opacity: 0.92; }
.btn.secondary { background: var(--bg); color: var(--fg); border-color: var(--border); }
.btn.secondary:hover { background: var(--grey-bg); }
.btn.small { padding: 5px 10px; font-size: 13px; }

.card {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg); padding: 16px;
}
.card h3 { margin: 0 0 6px; font-size: 15px; }
.card p { margin: 0; color: var(--muted); }

.input, textarea.input {
  width: 100%; border: 1px solid var(--border); border-radius: var(--radius);
  padding: 8px 10px; font: inherit; background: var(--bg); color: var(--fg);
}
.input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 4px; }

.badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 12px; font-weight: 600; background: var(--grey-bg); color: var(--grey);
}
.badge.needed   { background: var(--grey-bg);  color: var(--grey); }
.badge.quoted   { background: var(--blue-bg);  color: var(--blue); }
.badge.ordered  { background: var(--amber-bg); color: var(--amber); }
.badge.purchased{ background: var(--green-bg); color: var(--green); }
/* variant statuses (§16.3) */
.badge.draft        { background: var(--grey-bg);  color: var(--grey); }
.badge.under_review { background: var(--amber-bg); color: var(--amber); }
.badge.chosen       { background: var(--green-bg); color: var(--green); }
.badge.archived     { background: var(--grey-bg);  color: var(--grey); }
/* phase statuses (§16.3) */
.badge.planned      { background: var(--grey-bg);  color: var(--grey); }
.badge.in_progress  { background: var(--blue-bg);  color: var(--blue); }
.badge.done         { background: var(--green-bg); color: var(--green); }
/* item kinds + sourcing route kinds (§16.4) */
.badge.material     { background: var(--grey-bg);  color: var(--grey); }
.badge.labour       { background: var(--blue-bg);  color: var(--blue); }
.badge.self         { background: var(--grey-bg);  color: var(--grey); }
.badge.quoted       { background: var(--blue-bg);  color: var(--blue); }

.grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }

/* §12.1 comparison — plain tables */
.table-wrap { overflow-x: auto; }
.compare { border-collapse: collapse; width: 100%; font-size: 14px; }
.compare th, .compare td {
  border: 1px solid var(--border); padding: 10px 12px; text-align: left; vertical-align: top;
}
.compare thead th { background: var(--grey-bg); }
.compare tbody th { background: var(--grey-bg); font-weight: 600; white-space: nowrap; }
.compare td.na { color: var(--muted); }
.compare tr.selected { background: var(--green-bg); }

/* room board (Phase 6) */
.items { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
.items td { padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.items td:last-child { text-align: right; white-space: nowrap; }

/* media thumbnails + rendered-asset grids (SPEC §7) */
.opt-thumb { display: inline-block; width: 28px; height: 28px; border-radius: 4px;
  background-size: cover; background-position: center; background-color: var(--grey-bg);
  vertical-align: middle; margin-right: 6px; }
.doc-thumb { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px;
  border: 1px solid var(--border); background: var(--grey-bg); display: block; }
.doc-thumb.placeholder { display: grid; place-items: center; color: var(--muted); aspect-ratio: 4/3; }
.doc-cover { display: block; background-repeat: no-repeat; background-color: var(--grey-bg);
  border: 1px solid var(--border); border-radius: 8px; }
/* page grid: tiles cropped out of the one sprite via background-position */
.page-grid { display: flex; flex-wrap: wrap; gap: 12px; }
.page-cell { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.page-cell figcaption { font-size: 12px; }
.btn.danger { background: #b3261e; border-color: #b3261e; color: #fff; }
.btn.danger:hover { background: #8f1d17; }
.linklike { background: none; border: none; padding: 0 4px; color: var(--muted);
  font-size: 12px; cursor: pointer; text-decoration: underline; }
.linklike:hover { color: var(--fg); }
.page-tile { display: block; background-repeat: no-repeat; background-color: var(--grey-bg);
  border: 1px solid var(--border); border-radius: 6px; }
a.page-tile { cursor: zoom-in; transition: border-color 0.1s ease; }
a.page-tile:hover { border-color: var(--muted); }
.page-tile.placeholder { opacity: 0.55; }
/* Mid-render, a page whose base has landed is already openable (SPEC §7) — a live link, no thumbnail yet. */
a.page-tile.is-ready { opacity: 1; display: grid; place-items: center; font-size: 12px;
                       font-weight: 600; color: var(--accent, #2563eb); text-decoration: none; }

/* Comments (threaded; SPEC §16.6) */
.comments { max-width: 640px; }
.comment { border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 12px; margin-bottom: 8px; background: var(--bg); }
.comment.resolved { opacity: 0.6; }
.comment-head { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 4px; }
.comment p { margin: 0; white-space: normal; }
.comment .reply { margin: 8px 0 0 16px; background: var(--grey-bg); }
.comment .reply-form { margin-top: 8px; }
.stack { display: flex; flex-direction: column; gap: 16px; }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.muted { color: var(--muted); }

/* --- Marketing shell (public pages: landing, /ui, legal) ----------------- */
/* Same header METRICS as .topbar/.app2-topbar (SPEC §12.2.3) — height + edge geometry — so all
   three shells' headers are pixel-consistent; marketing just isn't sticky (the page scrolls whole)
   and the brand styling comes from the shared .brand rule (16px). */
.site-header {
  display: flex; align-items: center; justify-content: space-between;
  height: var(--topbar-h); box-sizing: border-box; padding: 8px 10px 8px 12px;
  border-bottom: 1px solid var(--border); background: var(--bg);
}
.site-header nav { display: flex; align-items: center; gap: 16px; }
.site-main { max-width: 920px; margin: 0 auto; padding: 32px 24px; }
.site-footer {
  max-width: 920px; margin: 0 auto; padding: 24px; color: var(--muted);
  border-top: 1px solid var(--border); display: flex; gap: 14px; flex-wrap: wrap;
}
.hero { display: grid; grid-template-columns: 1.1fr 1fr; gap: 40px; align-items: center; padding: 24px 0; }
.hero-copy h1 { font-size: 40px; line-height: 1.1; letter-spacing: -0.02em; margin: 0 0 14px; }
.hero-copy p { font-size: 16px; color: var(--muted); margin: 0; max-width: 46ch; }
.hero-art { color: var(--fg); }
.hero-art svg { width: 100%; height: auto; }
@media (max-width: 768px) {
  .hero { grid-template-columns: 1fr; gap: 24px; }
  .hero-copy h1 { font-size: 30px; }
}

/* --- Auth shell (login/signup/reset/verify) — no sidebar ----------------- */
/* Use the plain white body background (not the grey --sidebar) so navigating between auth and app/marketing
   pages doesn't flash white→grey→white; the bordered .auth-card defines the form on its own. */
/* Extra bottom padding lifts the vertically-centred card higher up the page (it looked too low centred dead-centre). */
.auth-wrap { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px; padding: 24px 24px 14vh; }
.auth-brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 18px; }
.auth-wrap .auth-card { width: 100%; }

.auth-card { max-width: 420px; margin: 24px auto; }

/* --- Forms (allauth, via our fields.html override) ----------------------- */
/* Placeholder style: inputs show a placeholder hint; labels are sr-only (a11y). */
.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;
}
.form-field { margin-bottom: 16px; }
.form-field .input { width: 100%; }
.form-field label.check { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; color: var(--fg); }
.form-field label.check span a { white-space: normal; }
.form-field .field-error, ul.errorlist { color: #991b1b; font-size: 12.5px; margin-top: 4px; list-style: none; padding: 0; }
.form-field .help { font-size: 12px; margin-top: 4px; }

/* --- Flash messages ------------------------------------------------------ */
.messages { margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }
/* The #messages container is always in the DOM (htmx OOB target); collapse it when empty. */
.messages:empty { margin: 0; }
.msg-flash { border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 12px; background: var(--grey-bg); }
.msg-flash.error { background: #fef2f2; border-color: #fecaca; color: #991b1b; }
.msg-flash.success { background: var(--green-bg); border-color: #a7f3d0; color: var(--green); }

/* --- Agent chat (append-only; errors & tool events retained) ------------- */
.chat { display: flex; flex-direction: column; gap: 10px; }
.msg { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; }
.msg .who { font-size: 12px; font-weight: 600; color: var(--muted); margin-bottom: 4px; }
.msg.user { background: var(--grey-bg); }
.msg.assistant { background: var(--bg); }
.msg.tool { background: #fafafa; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12.5px; }
.msg.error {                       /* errors stay in the chat, never auto-dismissed */
  background: #fef2f2; border-color: #fecaca; color: #991b1b;
}
.msg pre { margin: 0; white-space: pre-wrap; word-break: break-word; }

/* --- Mobile: off-canvas drawer + top bar --------------------------------- */
@media (max-width: 768px) {
  .topbar {
    display: flex; align-items: center; gap: 12px;
    /* Owner-tuned edges (SPEC §12.2.3): 10px left (the brand sits flush-but-breathing), 9px right
       (the account/person icon lines up with the assistant drawer's ✕). */
    flex: 0 0 auto; padding: 8px 9px 8px 10px;
    background: var(--sidebar);   /* no border-bottom on mobile — the grey bg separates it, and the
                                     open drawer shouldn't read as having a 1px top border */
  }
  .app { grid-template-columns: 1fr; }
  /* The nav drawer slides in from the RIGHT, BELOW the top bar (SPEC §12.2.3) — mirroring the
     assistant drawer — and stays UNDER the bar's z-index (30) so the far-right ✕ keeps working.
     Z-ORDER: topbar 30 > nav drawer 28 > its backdrop 26 > the assistant drawer 25 — the nav
     drawer + backdrop sit ABOVE an open assistant, which reads as backgrounded until dismissed. */
  .sidebar {
    position: fixed; top: var(--topbar-h); right: 0; bottom: 0; width: 248px; z-index: 28;
    transform: translateX(calc(100% + 20px)); transition: transform 0.18s ease;  /* clear the shadow */
    box-shadow: -2px 0 12px rgba(0, 0, 0, 0.12);
  }
  body.nav-open .sidebar { transform: none; }
  /* Backdrop starts below the top bar (the bar stays undimmed + clickable — it holds the ✕). */
  body.nav-open .backdrop {
    display: block; position: fixed; inset: var(--topbar-h) 0 0 0; z-index: 26;
    background: rgba(0, 0, 0, 0.35);
  }
  /* The drawer always shows full labels; desktop collapse is irrelevant here. */
  .sidebar .nav-label, .sidebar .switcher { display: revert; }
  .collapse-btn { display: none; }
  /* Tighter, even padding on phones (was a heavy left inset from doubled top-bar padding). */
  .main { padding: 14px; }
  .topbar-brand { padding-left: 0; justify-content: flex-start; gap: 8px; }
  .topbar-brand .shell-toggle { display: none; }        /* desktop chevron — mobile uses the far-right toggle */
  .icon-btn.shell-toggle-m { display: flex; }           /* hamburger at the EXTREME right */
  body.nav-open .shell-toggle-m .menu-icon { display: none; }
  body.nav-open .shell-toggle-m .x-icon { display: inline; }  /* same button closes the drawer */
  .user-menu-name, .user-menu-caret { display: none; }  /* icon-only account widget */
}

/* --- Badge: test statuses (staff gallery, SPEC §12.5) ----------------------- */
.badge.passed  { background: var(--green-bg); color: var(--green); }
.badge.failed  { background: #fef2f2; color: #b91c1c; }
.badge.skipped { background: var(--grey-bg); color: var(--grey); }

/* --- Secondary nav component (components/subnav.html, §12.6) ---------------- */
/* Tab row: the bar sits on a grey baseline; the active section is underlined black. */
.subnav { display: flex; gap: 4px; flex-wrap: wrap; margin: 0 0 22px;
  border-bottom: 1px solid var(--border); }
.subnav-link { padding: 8px 12px; margin-bottom: -1px; color: var(--muted);
  font-weight: 600; font-size: 14px; border-bottom: 2px solid transparent; }
.subnav-link:hover { color: var(--fg); }
.subnav-link.active { color: var(--fg); border-bottom-color: var(--fg); }

/* --- allauth element overrides (templates/allauth/elements/*) --------------- */
/* Restyle EVERY allauth page (login/signup/reset/verify, email + MFA management) through the shared
   element templates, so they use the design-system components below rather than allauth's bare tags. */
.section-title { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; margin: 18px 0 8px; }
.auth-text { color: var(--muted); margin: 0 0 14px; }
.auth-text:last-child { margin-bottom: 0; }
hr.rule { border: none; border-top: 1px solid var(--border); margin: 18px 0; }
.btn.block { width: 100%; justify-content: center; }        /* allauth "prominent" login/signup CTAs */
.btn-group { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 12px; }
.badge.success { background: var(--green-bg); color: var(--green); }
.badge.warning { background: var(--amber-bg); color: var(--amber); }
.badge.danger  { background: #fef2f2; color: #b91c1c; }
.auth-details { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; margin: 12px 0; }
.auth-details > summary { cursor: pointer; font-weight: 600; }
.auth-img { display: block; max-width: 100%; margin: 8px 0; }

/* --- Screenshot gallery (/staff/test) -------------------------------------- */
/* TOC: one chip per section (product + each package), plain anchor links. */
.shot-toc { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }
.shot-toc a { border: 1px solid var(--border); border-radius: 999px; padding: 3px 12px;
              font-size: 13px; text-decoration: none; color: inherit; }
.shot-toc a:hover { border-color: var(--muted, #888); }
/* Anchored section titles land below the sticky topbar, not under it. */
.shot-section-title { scroll-margin-top: 60px; }
/* Unit-suite listing (building/test_gallery.py manifests): compact multi-column tick list. */
.unit-summary { font-weight: 400; font-size: 13px; color: var(--muted, #667); margin-left: 8px; }
.unit-summary.is-failing { color: #b91c1c; font-weight: 600; }
.unit-group { margin: 12px 0 4px; font-size: 12px; font-weight: 600; color: var(--muted, #667);
              font-family: ui-monospace, monospace; }
.unit-list { columns: 3; column-gap: 24px; list-style: none; margin: 0; padding: 0; }
.unit-test { font-size: 13px; padding: 1px 0; break-inside: avoid; }
.unit-test::before { content: '✓ '; color: #137333; }
.unit-failed::before, .unit-error::before { content: '✗ '; color: #b91c1c; }
.unit-skipped::before { content: '– '; color: var(--muted, #888); }
.unit-failed, .unit-error { color: #b91c1c; font-weight: 600; }
@media (max-width: 900px) { .unit-list { columns: 1; } }
.shot-feature { margin-top: 28px; }
.shot-feature-title { font-size: 16px; margin: 0 0 10px; }
.shot-grid { display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
.shot { margin: 0; border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden; }
.shot-cap { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 10px; font-size: 13px; border-bottom: 1px solid var(--border); }
.shot-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shot img { width: 100%; display: block; }
/* API-level scenario card (no UI under test) — replaces the meaningless blank screenshot (§18.0) */
.shot-api-level { padding: 2rem 1rem; text-align: center; color: var(--muted, #667);
  background: repeating-linear-gradient(45deg, transparent, transparent 12px,
    rgba(127,127,127,.06) 12px, rgba(127,127,127,.06) 24px); }


/* Assistant usage footer + meters (SPEC §13.7). Hidden until a budget bucket is ≥60% used, so the
   assistant feels limitless until a limit is near. No numbers — a coarse bar per over-threshold
   bucket, coloured by band (green→amber→red), black when blocked. */
.usage-footer { position: sticky; bottom: 0; background: var(--bg); display: none; }
.usage-footer.is-shown { display: block; margin-top: 12px; padding: 10px 0;
  border-top: 1px solid var(--border); }
.usage-footer .meter + .meter { margin-top: 8px; }
.meter__label { font-size: 13px; color: var(--muted); margin-bottom: 4px; }
.meter__track { height: 8px; max-width: 680px; border-radius: 999px;
  background: var(--grey-bg); overflow: hidden; }
.meter__fill { height: 100%; border-radius: 999px; transition: width .3s ease;
  background: var(--grey); }
.meter--green .meter__fill { background: var(--green); }
.meter--amber .meter__fill { background: var(--amber); }
.meter--red   .meter__fill { background: var(--red); }
.meter--black .meter__fill { background: var(--accent); }   /* blocked — near-black, fully stopped */
.meter--black .meter__label { color: var(--fg); font-weight: 600; }

/* --- user menu (SPEC §12/§22): shared account dropdown across all shells --- */
.user-menu { position: relative; display: inline-block; }
.user-menu-trigger { display: inline-flex; align-items: center; gap: 6px; background: none;
  border: 0; color: inherit; font: inherit; cursor: pointer; padding: 6px 8px; border-radius: 6px; }
.user-menu-trigger:hover { background: rgba(0,0,0,0.05); }
.user-menu-caret { font-size: 11px; opacity: 0.7; }
.user-menu-panel { position: absolute; right: 0; top: calc(100% + 4px); min-width: 168px;
  background: var(--bg, #fff); border: 1px solid var(--line, #e5e5e5); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12); padding: 4px; z-index: 100; display: none; }
.user-menu.open .user-menu-panel { display: block; }
.user-menu-panel a { display: block; padding: 7px 10px; border-radius: 6px; text-decoration: none;
  color: inherit; white-space: nowrap; }
.user-menu-panel a:hover, .user-menu-panel a:focus { background: rgba(0,0,0,0.06); outline: none; }
.user-menu-sep { height: 1px; background: var(--line, #e5e5e5); margin: 4px 6px; }
.user-menu--up .user-menu-panel { top: auto; bottom: calc(100% + 4px); right: auto; left: 0; }

/* The user menu lives in the top bar (not the sidebar), so its name never collapses. */

/* Engineering blog prose (SPEC §23) — long-form reading inside the app2 shell */
.prose { max-width: 720px; line-height: 1.65; }
.prose h2 { margin: 1.6em 0 .5em; }
.prose h3 { margin: 1.3em 0 .4em; }
.prose p, .prose ul, .prose ol { margin: .8em 0; }
.prose pre { background: var(--panel, #f6f7f8); border: 1px solid var(--border, #e5e5e5);
  border-radius: 6px; padding: 12px 14px; overflow-x: auto; font-size: .9em; line-height: 1.5; }
.prose code { background: var(--panel, #f6f7f8); padding: .1em .35em; border-radius: 4px;
  font-size: .92em; }
.prose pre code { background: none; padding: 0; }
.prose blockquote { border-left: 3px solid var(--border, #ddd); margin: 1em 0; padding: .2em 1em;
  color: var(--muted, #556); }
.prose table { border-collapse: collapse; margin: 1em 0; }
.prose th, .prose td { border: 1px solid var(--border, #e5e5e5); padding: 6px 10px; text-align: left; }

/* Engineering blog diagrams (SPEC §23) — inline SVG figures */
.prose .diagram { margin: 1.2em 0; }
.prose .diagram svg { width: 100%; height: auto; display: block; border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px; background: var(--bg); box-sizing: border-box; }
.prose .diagram pre.mermaid { background: none; border: 0; padding: 0; margin: 0;
  display: flex; justify-content: center; }

/* Engineering blog tags (SPEC §23) — small colour-coded chips on the index + each post */
.eng-tags { margin: 8px 0 0; display: flex; flex-wrap: wrap; gap: 6px; }
.eng-tag { font-size: 11px; line-height: 1; padding: 3px 8px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .04em; font-weight: 600; border: 1px solid transparent; }
.eng-tag--architecture { background: var(--grey-bg); color: var(--grey); border-color: var(--grey); }
.eng-tag--api          { background: var(--blue-bg); color: var(--blue); border-color: var(--blue); }
.eng-tag--ai           { background: #f5f3ff; color: #6d28d9; border-color: #6d28d9; }
.eng-tag--testing      { background: var(--green-bg); color: var(--green); border-color: var(--green); }
.eng-tag--platform     { background: var(--amber-bg); color: var(--amber); border-color: var(--amber); }
.eng-tag--security     { background: var(--red-bg); color: var(--red); border-color: var(--red); }
.eng-tag--ui           { background: #ecfeff; color: #0e7490; border-color: #0e7490; }
.eng-tag--staff        { background: var(--grey-bg); color: var(--grey); border-color: var(--grey); }
.eng-live { margin: 12px 0; padding: 8px 12px; border-left: 3px solid var(--link);
  background: var(--blue-bg); border-radius: 0 6px 6px 0; font-size: .95em; }
.eng-live a { font-weight: 600; }

/* Staff-section badge in the account widget (SPEC §12.2.3) */
.user-menu-section { padding: 4px 14px 2px; }
.staff-badge { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; padding: 2px 7px; border-radius: 999px;
  background: var(--amber-bg); color: var(--amber); border: 1px solid var(--amber); }

/* Top-bar project switcher + New button (SPEC §12) — sits right of the sidebar toggle */
.topbar-projects { display: flex; align-items: center; gap: 8px; margin-left: 12px; }
.topbar-projects .switcher { margin: 0; }
.topbar-projects .switcher-select { max-width: 240px; }
.topbar-projects .new-project { white-space: nowrap; }

/* Dropdown / select component (SPEC §12; showcased in /staff/ui) — a custom chevron, consistent
   border/height with .input, and a clear focus ring. Applied to the project switcher. */
.select, .switcher-select {
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  font: inherit; font-size: 14px; color: var(--fg); background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 7px 30px 7px 10px; line-height: 1.2; cursor: pointer; max-width: 100%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center;
}
.select:hover, .switcher-select:hover { border-color: var(--muted); }
.select:focus, .switcher-select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(17,24,39,.12);
}
.select:disabled, .switcher-select:disabled { opacity: .55; cursor: not-allowed; }

/* Read-only detail list (dt label / dd value) — project home + other read-only views (§16) */
.detail { display: grid; grid-template-columns: 140px 1fr; gap: 6px 16px; margin-top: 16px; }
.detail dt { color: var(--muted); font-size: 13px; }
.detail dd { margin: 0; }
@media (max-width: 560px) { .detail { grid-template-columns: 1fr; gap: 2px; }
  .detail dd { margin-bottom: 10px; } }


/* Bottom-aligned per-project Settings sub-section in the project sidebar (SPEC §24.5) */
.nav-settings { margin-top: auto; border-top: 1px solid var(--border); padding-top: 8px; gap: 2px; }
.nav-admin { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 8px; gap: 2px; }
.nav-section-label { font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); padding: 2px 8px 4px; }
.nav-collapsed .nav-section-label { display: none; }

.linkbtn { background:none; border:none; color:inherit; cursor:pointer; padding:0 2px; font-weight:700; }

.kind-badge { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; padding: 1px 5px; border-radius: 6px; vertical-align: middle; }
.kind-read { background: rgba(120,130,150,.16); color: var(--muted, #667); }
.kind-write { background: rgba(200,130,0,.16); color: #a86400; }
@media (prefers-color-scheme: dark) { .kind-write { color: #e6b357; } }

/* --- Progressive-enhancement fallback controls (SPEC §22, propositions exemplar) ------------ */
/* Present so the island forms submit without JS; hidden once <script> marks the document JS-capable
   (the islands then persist on change / intercept submit). */
.js .fallback-only { display: none; }
.fit-link-go, .note-save, .assum-save {
  border: 1px solid var(--border); background: var(--grey-bg, #f3f3f3); color: var(--fg);
  border-radius: 6px; padding: 2px 8px; margin-left: 4px; cursor: pointer; font-size: 13px; line-height: 1.4;
}

/* --- Global AI-chat drawer (SPEC §13.5) — the AI icon by the account widget opens it ------- */
.assistant-toggle { border: none; background: none; cursor: pointer; color: inherit;
  display: inline-flex; align-items: center; padding: 4px; border-radius: 6px; }
.assistant-toggle:hover { background: rgba(0,0,0,.06); }
/* The drawer sits below the top nav (--topbar-h) so the account widget + AI icon stay visible. On
   DESKTOP it doesn't overlay: the main content squashes beside it (a reserved right margin, below);
   on MOBILE it overlays. Shown only when <html> has .assistant-open. */
:root { --assistant-w: 380px; }
.assistant-drawer { position: fixed; top: var(--topbar-h, 52px); right: 0; bottom: 0;
  width: var(--assistant-w); max-width: 92vw; z-index: 25; background: var(--bg,#fff);
  border-left: 1px solid var(--line,#e5e5e5); box-shadow: -8px 0 24px rgba(0,0,0,.12);
  display: none; flex-direction: column; padding-top: 2px; }
.assistant-open .assistant-drawer { display: flex; }
/* DESKTOP ONLY: reserve room so content sits NEXT TO the drawer, not under it (the fixed drawer
   fills the reserved strip). +10px past the drawer width so its left shadow doesn't fall over the
   content. The topbar spans full width (drawer starts below it), so the widget is unaffected.
   On MOBILE the drawer is a PURE overlay — these rules are scoped to ≥769px so opening/closing
   never touches the page's own padding (the old `padding-right: 0` override shifted buttons/text
   under the overlay — owner-flagged 2026-07-12). */
@media (min-width: 769px) {
  .assistant-open .main, .assistant-open .app2-main { padding-right: calc(var(--assistant-w) + 10px); }
  .main, .app2-main { transition: padding-right .18s ease; }
}
.assistant-drawer-head { display: flex; align-items: center; gap: 6px; padding: 10px 12px;
  border-bottom: 1px solid var(--line,#e5e5e5); }
/* Nudge the header label down ~2px within the (fixed-height) bar for optical centring. */
.assistant-drawer-head strong, .assistant-drawer-head .assistant-scope { position: relative; top: 2px; }
.assistant-close { margin-left: auto; border: none; background: none; font-size: 20px; line-height: 1;
  cursor: pointer; color: var(--muted,#666); padding: 0 4px; }
.assistant-close:hover { color: var(--fg); }
#assistant-panel { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.assistant-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px;
  border-bottom: 1px solid var(--line,#e5e5e5); }
#assistant-panel .chat { flex: 1; overflow-y: auto; padding: 12px; }
#assistant-panel form#ask { border-top: 1px solid var(--line,#e5e5e5); padding: 10px; }

/* Assistant drawer — conversation list (§13.5) */
.assistant-convos { font-size: 13px; }
.assistant-convos summary { cursor: pointer; color: var(--muted); list-style: none; padding: 2px 6px;
  border-radius: 6px; }
.assistant-convos summary:hover { background: rgba(0,0,0,.05); color: var(--fg); }
.assistant-convo-list { position: absolute; z-index: 2; margin-top: 4px; min-width: 200px; max-height: 40vh;
  overflow-y: auto; background: var(--bg,#fff); border: 1px solid var(--line,#e5e5e5); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12); padding: 4px; }
.assistant-convo-list a { display: block; padding: 6px 8px; border-radius: 6px; text-decoration: none;
  color: inherit; white-space: nowrap; }
.assistant-convo-list a:hover { background: rgba(0,0,0,.06); }
