/* ABH custom-app stylesheet — canonical source.
 *
 * Spec: Architecture/design-system/ABH_App_UI_Styleguide.md. Brand: Architecture/design-system/ABH_Style_Guide.md.
 *
 * This file is the ONE source. Apps carry a verbatim copy, vendored by
 * app_runtime.revendor_platform_files() before every image build, the same way
 * abh_app.py and privilege.py are — see _VENDORED_PLATFORM_FILES. Never edit an
 * app's copy: the next deploy overwrites it.
 *
 * Every colour is chosen by MEANING, not appearance. If a decorative element
 * wants bronze, it does not get bronze.
 */

/* ---------------------------------------------------------------- tokens -- */
:root {
  /* Surfaces — vellum recedes, white raises. No shadows, no invented greys.
     Panel-on-ground is only 1.13:1, so every panel carries a --rule border:
     the border does the separating, not the fill. */
  --bg:#F5F1E8;          /* Soft Vellum — page ground                        */
  --panel:#FFFFFF;       /* Pure White — panels, cards, step rows            */
  --inset:#F5F1E8;       /* Soft Vellum — worklog, notes, read-only blocks   */
  --rule:#DDDDDD;        /* Light Grey — all borders and dividers            */
  --rule-strong:#0B223B; /* Royal Navy — selection, focus, active tab        */

  /* Ink — all four clear AA on BOTH grounds (white and vellum). */
  --ink:#121212;         /* body                        18.73 / 16.62        */
  --navy:#0B223B;        /* headings, app title, nav    16.08 / 14.26        */
  --dim:#5A6672;         /* labels, secondary            5.87 /  5.21        */
  --faint:#5F6B76;       /* timestamps, hints, disabled  5.45 /  4.84        */

  /* Action — Antique Bronze, derived: hue sits between the two brand metals
     (Aged Brass 36.9deg, Bronzed Sand 24.5deg), lightness in Deep Burgundy's
     register. Neither brand metal can carry a white label — both sit at ~2x
     the luminance AA allows. White on bronze is 5.60:1. */
  --action:#8B5E34;
  --action-hover:#734B29;       /* white 7.59:1 */
  --action-active:#5F3E22;      /* white 9.55:1 */
  --action-ink:#FFFFFF;         /* white 5.60:1 — navy would be 2.87:1, fails */

  /* Semantic states. The brand guide anticipates these but assigns no hex. */
  --signal:#8A6220;      /* your turn — a human must act   5.46 / 4.84       */
  --good:#1E6B45;        /* done, succeeded, met           6.47 / 5.74       */
  --bad:#C0262C;         /* failed, rejected, blocked      5.91 / 5.24       */
  --running:#1F5B8F;     /* an agent is working            7.12 / 6.31       */
  --agent:#0F6D74;       /* actor: an agent                6.07 / 5.38       */
  --human:#523682;       /* actor: a person                9.51 / 8.43       */

  /* State tints — each paired with its own ink above 4.9:1. */
  --tint-attn:#FBF3E2;   /* + --signal   4.94:1 */
  --tint-err:#FCEDED;    /* + --bad      5.20:1 */
  --tint-run:#EAF2FA;    /* + --running  6.30:1 */
  --tint-done:#EAF4EE;   /* + --good     5.76:1 */

  --sans:"Inter",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* Type scale — styleguide §4.7, as TOKENS rather than literals.
     Named for the role the guide gives each rung, not for a pixel value, so
     the names stay true when the values move. Nothing outside this block and
     its large-display override below declares a px font-size; that is what
     makes "one scale, no ad-hoc sizes" checkable instead of aspirational. */
  --fs-overline:11px;   /* overline, field label — uppercase, .1em            */
  --fs-secondary:12px;  /* descriptions, hints, timestamps                    */
  --fs-dense:13px;      /* body-dense — step titles, table cells              */
  --fs-body:14px;       /* body                                               */
  --fs-title:15px;      /* app title, dialog title                            */
}

/* Large display (§2.1 decision 13). Every rung moves one step up the ladder:
   12/13/14/15/16. The step is +1px uniformly rather than a ratio, because the
   scale's own rungs are 1px apart — a proportional bump would land on
   fractions and reintroduce the 10.5/11.5/12.5 noise §4.7 exists to remove.

   1728 is the top of tier A, not tier B's 1024: at 1024 this would enlarge
   type on every 13" laptop, which is not what a large monitor is. If the text
   still reads small on a 32" panel, change the five values here — that is the
   entire point of the tokens, and no call site moves. */
@media (min-width:1728px) {
  :root {
    --fs-overline:12px;
    --fs-secondary:13px;
    --fs-dense:14px;
    --fs-body:15px;
    --fs-title:16px;
  }
}

/* -------------------------------------------------------------- baseline -- */
*, *::before, *::after { box-sizing:border-box; }
* { margin:0; }
body {
  background:var(--bg); color:var(--ink);
  /* Longhand, not the `font` shorthand: the shorthand cannot take a token for
     its size alone, and hardcoding 14px here would strand every element that
     inherits the body size — `.tabs button { font:inherit }` among them — at
     the small-display rung on a large monitor. */
  font-family:var(--sans); font-size:var(--fs-body); line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
.mono { font-family:var(--mono); font-variant-numeric:tabular-nums; }
:focus-visible { outline:2px solid var(--rule-strong); outline-offset:2px; }

/* Type scale — the five §4.7 tokens only. No px font-size outside :root. */
h1 { font-size:var(--fs-title); font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--navy); }
h2 { font-size:var(--fs-overline); font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--dim); margin-bottom:10px; }
h3 { font-size:var(--fs-dense); font-weight:600; color:var(--navy); }

/* ------------------------------------------------------------------ shell -- */
header {
  display:flex; align-items:center; gap:12px;
  padding:14px 20px; background:var(--panel); border-bottom:1px solid var(--rule);
}
header .sub { color:var(--faint); font-size:var(--fs-secondary); }
header .spacer { flex:1; }
/* The bar is chrome: the same height in every app whether or not one of them
   puts a button in it. support-assistant's "New Chat" made its header 17px
   taller than its three siblings' — the apps looked like different products
   when opened side by side. Header buttons are compact by rule, not by the
   author remembering `.small`. */
header button, header .btn { padding:4px 11px; font-size:var(--fs-secondary); }
/* Navigation, not action. A filled bronze button for "go and look at something"
   competes with the app's real primary action; a plain link does not. Reserved
   for header chrome that leaves the app's own screens (currently: Security). */
header .navlink {
  color:var(--navy); font-size:var(--fs-secondary); font-weight:600; text-decoration:none;
  border-bottom:1px solid transparent; padding-bottom:1px;
}
header .navlink:hover, header .navlink:focus-visible { border-bottom-color:var(--navy); }
/* The language switcher (abh-app.js), only in apps that declare two locales. */
header .navlang { width:auto; padding:3px 7px; font-size:var(--fs-secondary); }

.tabs { display:flex; gap:4px; padding:10px 20px 0; }
.tabs button {
  background:transparent; border:1px solid var(--rule); border-bottom:0; color:var(--dim);
  border-radius:6px 6px 0 0; padding:8px 18px; cursor:pointer; font:inherit; font-weight:500;
}
.tabs button:hover { color:var(--navy); }
.tabs button.on { color:var(--navy); border-color:var(--rule-strong); background:var(--panel); font-weight:600; }

/* Fixed, not negotiable per app. */
main {
  display:grid; grid-template-columns:240px 1fr; gap:16px;
  padding:16px 20px; max-width:1500px; margin:0 auto;
}
main.single { grid-template-columns:1fr; max-width:900px; }
/* The list column is 240px, so what stands side by side elsewhere stacks in it:
   two paired fields would be 100px each, too narrow for a date, and a .kv's
   150px key would leave its value 50px. The column is whichever child of main
   is shown first — an app with several tabs hides the others. Only while the
   shell has two columns: below 1024 the column is the full width again. */
@media (min-width:1024px) {
  main:not(.single) > :nth-child(1 of :not([hidden])) :is(.row2, .kv) { grid-template-columns:1fr; }
}
/* A single column that holds a week (.week): seven days need more than the
   reading width of a list. */
main.single.wide { max-width:1280px; }

.panel { background:var(--panel); border:1px solid var(--rule); border-radius:6px; padding:14px; }

/* ------------------------------------------------------------------ forms -- */
label { display:block; font-size:var(--fs-overline); font-weight:500; letter-spacing:.06em;
        text-transform:uppercase; color:var(--dim); margin:8px 0 4px; }
input, textarea, select {
  width:100%; background:var(--panel); border:1px solid var(--rule); border-radius:5px;
  color:var(--ink); padding:8px 10px; font:inherit;
}
textarea { min-height:60px; resize:vertical; }
/* Choice — a checkbox with its text beside it on ONE line, in the text's own
   case: what is ticked is a name or a sentence, not a field label. Several
   stand one under the other beneath an ordinary label that names the group. */
label.check { display:flex; align-items:center; gap:8px; margin:4px 0; cursor:pointer;
              font-size:var(--fs-dense); font-weight:400; letter-spacing:0;
              text-transform:none; color:var(--ink); }
label.check input { width:auto; flex:none; margin:0; padding:0; }
input:focus, textarea:focus, select:focus {
  outline:none; border-color:var(--rule-strong); box-shadow:0 0 0 3px rgba(11,34,59,.11);
}
/* A date/time control sizes itself from its own picker UI and ignores
   width:100% on iOS unless its native appearance is dropped. Left alone it
   keeps an intrinsic width wider than the cell it sits in and prints past the
   panel's right border — reported on iPad portrait, invisible in desktop
   Chrome, whose intrinsic floor is only ~140px. */
input[type=date], input[type=datetime-local], input[type=time], input[type=month] {
  -webkit-appearance:none; appearance:none;
}
.row2 { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
/* A grid item's min-width is `auto`, which means "never shrink below my
   min-content width". A 1fr column therefore does NOT bound what it holds: the
   column stops at the control's intrinsic floor and the control overflows the
   row. Measured in Chrome at a 200px row — the date column sticks at 139.5px
   and the input prints 8px past the row's right edge, then 88px at 120px.
   `min-width:0` is what makes 1fr actually mean "share the space". */
.row2 > * { min-width:0; }

/* ---------------------------------------------------------------- buttons -- */
/* ALL available actions carry equal weight. There is no secondary tier.
   The 1px border matches the fill so active and inactive buttons keep
   identical geometry — bronze is 5.60:1 against a white panel and needs no
   edge of its own. */
button, .btn {
  font:inherit; font-size:var(--fs-dense); font-weight:600; padding:8px 16px; border-radius:5px;
  background:var(--action); color:var(--action-ink); border:1px solid var(--action);
  cursor:pointer; transition:background .13s;
}
button:hover, .btn:hover { background:var(--action-hover); border-color:var(--action-hover); }
button:active, .btn:active { background:var(--action-active); border-color:var(--action-active); }

/* Destructive — equal weight, different meaning. Never mistakable for approve. */
button.danger, .btn.danger { background:var(--bad); border-color:#9E1F24; color:#FFFFFF; }
button.danger:hover, .btn.danger:hover { background:#A81F25; border-color:#A81F25; }

/* INACTIVE means "you cannot do this right now" — a different thing from an
   action, not a quieter one. `.ghost` as a secondary-action tier is removed. */
button:disabled, button.inactive, .btn.inactive {
  background:var(--panel); border:1px solid var(--rule); color:var(--faint);
  font-weight:500; cursor:not-allowed;
}
button:disabled:hover, button.inactive:hover, .btn.inactive:hover { background:var(--panel); }
button.small, .btn.small { padding:4px 11px; font-size:var(--fs-secondary); }

/* ------------------------------------------------------------------ chips -- */
.chip {
  display:inline-block; font-size:var(--fs-overline); font-weight:500; padding:2px 9px; border-radius:99px;
  border:1px solid var(--rule); color:var(--dim); background:var(--panel); white-space:nowrap;
}
/* The five step states (7 collapsed to 5: current+parked -> active, auto -> locked). */
.chip.done    { border-color:var(--good);    color:var(--good);    background:var(--tint-done); }
.chip.active  { border-color:var(--signal);  color:var(--signal);  background:var(--tint-attn); }
.chip.running { border-color:var(--running); color:var(--running); background:var(--tint-run); }
.chip.locked  { border-color:var(--rule);    color:var(--faint); }
.chip.blocked { border-color:var(--bad);     color:var(--bad);     background:var(--tint-err); }
/* Record status — rendered from server state, verbatim (see the shared map). */
.chip.new, .chip.submitted { border-color:var(--running); color:var(--running); }
.chip.assessment, .chip.authorization, .chip.approved, .chip.assigned { border-color:var(--agent); color:var(--agent); }
.chip.implementation, .chip.in_progress, .chip.in_delivery, .chip.scheduled { border-color:var(--signal); color:var(--signal); }
/* ai_solution_proposed is a human's turn: an agent drafted a resolution and a
   person must confirm it — same register as review/pending, not a done state. */
.chip.review, .chip.pending, .chip.revised, .chip.ai_solution_proposed { border-color:var(--human); color:var(--human); }
.chip.closed, .chip.delivered, .chip.fulfilled, .chip.resolved, .chip.value_realized { border-color:var(--good); color:var(--good); }
.chip.rejected, .chip.cancelled { border-color:var(--bad); color:var(--bad); }
/* Priority */
.chip.P1 { border-color:var(--bad); color:var(--bad); }
.chip.P2 { border-color:var(--signal); color:var(--signal); }
.chip.P3 { border-color:var(--running); color:var(--running); }
.chip.P4 { border-color:var(--rule); color:var(--faint); }
/* Actor */
.chip.agent { border-color:var(--agent); color:var(--agent); }
.chip.human { border-color:var(--human); color:var(--human); }

/* ------------------------------------------------------- queue + item hdr -- */
.list { margin-top:12px; display:flex; flex-direction:column; gap:6px; max-height:56vh; overflow:auto; }
.card {
  border:1px solid var(--rule); border-radius:5px; padding:10px 11px;
  background:var(--panel); cursor:pointer;
}
.card:hover { border-color:var(--dim); }
.card.sel { border-color:var(--rule-strong); box-shadow:0 0 0 2px rgba(11,34,59,.09); }
.card .title { color:var(--dim); font-size:var(--fs-secondary); margin-top:3px;
               overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

.ihdr { display:flex; align-items:flex-start; gap:14px; }
.ihdr .idm { flex:1; min-width:0; }
.ihdr .iid { font-family:var(--mono); font-size:var(--fs-secondary); color:var(--faint); }
.ihdr .itl { font-size:var(--fs-title); font-weight:700; color:var(--navy); margin-top:2px; }
.ihdr .ich { display:flex; gap:7px; margin-top:9px; flex-wrap:wrap; }

/* Record actions live here — labelled "Actions", never a bare glyph. */
.actions-menu { position:relative; flex:none; }
.actions-menu > summary {
  list-style:none; cursor:pointer; height:32px; padding:0 13px; user-select:none;
  border:1px solid var(--action); border-radius:5px; background:var(--action);
  color:var(--action-ink); font-size:var(--fs-dense); font-weight:600;
  display:flex; align-items:center; gap:7px; white-space:nowrap;
}
.actions-menu > summary::-webkit-details-marker { display:none; }
.actions-menu > summary:hover { background:var(--action-hover); border-color:var(--action-hover); }
.actions-menu .menu {
  position:absolute; right:0; top:38px; z-index:40; min-width:216px; padding:5px;
  background:var(--panel); border:1px solid var(--rule); border-radius:6px;
  box-shadow:0 8px 22px rgba(11,34,59,.15);
}
.actions-menu .menu button {
  display:block; width:100%; text-align:left; background:transparent; border:0;
  font-size:var(--fs-dense); font-weight:500; color:var(--navy); padding:7px 10px; border-radius:4px;
}
.actions-menu .menu button:hover { background:var(--inset); }
.actions-menu .menu button.danger { background:transparent; border:0; color:var(--bad); }
.actions-menu .menu button.danger:hover { background:var(--tint-err); }
.actions-menu .menu hr { border:0; border-top:1px solid var(--rule); margin:5px 2px; }
/* The compact form, for a menu that repeats down a list or stands in a narrow
   column: the same menu behind three bars, drawn here so no font has to hold
   the glyph. The word "Actions" stays the control's name (aria-label, title). */
.actions-menu.compact > summary {
  width:28px; height:28px; padding:0; justify-content:center;
  background:transparent; border-color:transparent; color:var(--navy);
}
.actions-menu.compact > summary::before {
  content:""; width:14px; height:10px;
  background:linear-gradient(currentColor, currentColor) top / 100% 2px no-repeat,
             linear-gradient(currentColor, currentColor) center / 100% 2px no-repeat,
             linear-gradient(currentColor, currentColor) bottom / 100% 2px no-repeat;
}
.actions-menu.compact > summary:hover,
.actions-menu.compact[open] > summary { background:var(--inset); border-color:var(--rule); }
.actions-menu.compact .menu { top:32px; }

/* ----------------------------------------------------------- guided flow -- */
.flow { border:1px solid var(--rule); border-radius:6px; background:var(--panel); overflow:hidden; }
.gstep { display:flex; gap:12px; padding:13px 15px; border-top:1px solid var(--rule); }
.flow > .gstep:first-child { border-top:0; }
.gstep.active { background:var(--tint-attn); }
.gstep.locked { opacity:.62; }
.g-num {
  width:24px; height:24px; border-radius:50%; flex:none; margin-top:1px;
  border:1.5px solid var(--rule); background:var(--panel);
  display:flex; align-items:center; justify-content:center;
  font-family:var(--mono); font-size:var(--fs-overline); font-weight:500; color:var(--faint);
}
.gstep.done .g-num    { border-color:var(--good);    color:var(--good); }
.gstep.active .g-num  { border-color:var(--signal);  color:var(--signal); }
.gstep.running .g-num { border-color:var(--running); color:var(--running); }
.gstep.blocked .g-num { border-color:var(--bad);     color:var(--bad); }
.gstep .g-main { flex:1; min-width:0; }
.g-title { font-size:var(--fs-dense); font-weight:600; color:var(--navy);
           display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.gstep.locked .g-title { font-weight:500; color:var(--dim); }
.g-desc { font-size:var(--fs-secondary); color:var(--dim); margin-top:3px; }
.g-pre { margin-top:5px; font-size:var(--fs-secondary); }
.g-pre .ok { color:var(--good); }
.g-pre .no { color:var(--signal); }
.g-pre .opt { color:var(--faint); }
/* Action row — inside a step body or under a panel. ALL available actions carry
   equal weight, so this is a plain row with no primary/secondary ordering. */
.actions { display:flex; gap:8px; margin-top:11px; flex-wrap:wrap; align-items:center; }
/* Step actions are chips on the title row, right after the state chip — the
   state says whose turn it is, the action chip says what to do:
   "your turn → Upload the filled test plan …". A done step that can still be
   re-run carries an "optional: Re-schedule …" chip. A chip renders only while
   its action is allowed, so it disappears on its own once the record is closed
   (process-flow.js `.g-act`; styleguide §10 decision 10). A chip whose action
   reads a field (approval comment, evidence box) still sits up here — the
   field stays in the body and the handler reads it by id. */
.g-act { display:inline-flex; gap:6px; align-items:center; flex-wrap:wrap; }
.g-act button, .g-act .btn {
  font-size:var(--fs-overline); font-weight:600; padding:2px 10px; border-radius:99px; white-space:nowrap;
  background:var(--action); color:var(--action-ink); border:1px solid var(--action);
}
.g-act button.danger, .g-act .btn.danger { background:var(--bad); border-color:#9E1F24; }
.gstep.active .g-act button::before, .gstep.blocked .g-act button::before { content:'\2192  '; }
.gstep.done .g-act button::before { content:'optional: '; font-weight:500; }
/* Generated files a step offers (implementation plan, test plan, documentation):
   downloads, not process actions — plain links so they never compete with the
   step's button. */
.files { display:flex; gap:14px; flex-wrap:wrap; margin-top:6px; font-family:var(--mono); font-size:var(--fs-secondary); }
.files a { color:var(--navy); text-decoration:none; border-bottom:1px dotted var(--navy); cursor:pointer; }
.files a:hover { color:var(--action); border-color:var(--action); }
.actor { font-family:var(--mono); font-size:var(--fs-overline); letter-spacing:.09em; text-transform:uppercase; }
.actor.a { color:var(--agent); }
.actor.h { color:var(--human); }

/* --------------------------------------------------- running-agent banner -- */
/* Directly under the step description, above its actions — and nowhere else.
   §7.1: a running agent is announced INSIDE its step, never as a page-level
   banner above the record or a busy banner below it, and the step number
   carries the spinner while it runs. Format: "Running n/M · <Agent Name>".
   M comes from the workflow design (steps naming a capability); never
   hard-code it. Plain names only — no URN, no namespace, no version. */
.agent-run {
  display:flex; align-items:center; gap:10px; margin-top:9px; padding:8px 12px;
  background:var(--tint-run); border:1px solid var(--running); border-radius:5px;
}
.agent-run .spinner {
  width:12px; height:12px; border-radius:50%; flex:none;
  border:2px solid rgba(31,91,143,.25); border-top-color:var(--running);
  animation:abh-spin .8s linear infinite;
}
.agent-run .count {
  font-family:var(--mono); font-size:var(--fs-overline); font-weight:700; color:var(--running);
  font-variant-numeric:tabular-nums; flex:none;
}
.agent-run .name { font-size:var(--fs-dense); font-weight:600; color:var(--running); flex:1; min-width:0; }
.agent-run .bar { width:88px; height:4px; border-radius:99px;
                  background:rgba(31,91,143,.2); flex:none; overflow:hidden; }
.agent-run .bar i { display:block; height:100%; background:var(--running);
                    border-radius:99px; transition:width .4s ease; }
@keyframes abh-spin { to { transform:rotate(360deg); } }

/* ----------------------------------------------------------- facts + log -- */
.kv { display:grid; grid-template-columns:150px 1fr; gap:5px 10px; font-size:var(--fs-dense); margin-top:8px; }
.kv .k { color:var(--faint); }
.notes { white-space:pre-wrap; background:var(--inset); border:1px solid var(--rule);
         border-radius:5px; padding:10px; margin-top:8px; font-size:var(--fs-dense); }
.wl { margin-top:10px; display:flex; flex-direction:column; gap:8px; }
.wl .e { border-left:2px solid var(--rule); padding:4px 0 4px 10px; }
.wl .who { font-size:var(--fs-overline); font-weight:600; color:var(--agent); }
.wl .who.human { color:var(--human); }
.wl .who.system { color:var(--dim); }
.wl .chip.kind { font-size:var(--fs-overline); padding:0 6px; margin-left:4px; vertical-align:1px; }
.wl .when { color:var(--faint); font-size:var(--fs-overline); margin-left:6px; font-family:var(--mono); }
.wl .txt { font-size:var(--fs-secondary); color:var(--dim); white-space:pre-wrap; word-break:break-word; margin-top:2px; }
.agent-result { white-space:normal; margin:2px 0; line-height:1.35; }
.agent-result .result-title { font-weight:600; color:var(--ink); margin-bottom:3px; }
.agent-result .result-section { margin:3px 0; }
.agent-result .result-label { font-weight:600; color:var(--dim); }
.agent-result .result-value { white-space:pre-wrap; overflow-wrap:anywhere; color:var(--ink); }
.agent-result .inline .result-value { display:inline; }
.agent-result ul { margin:0; padding-left:18px; }
.agent-result li { margin:1px 0; }
.agent-result .result-nested { white-space:normal; }

/* Data row — one record in a short list: SLA clock, fulfilment task, approval,
   status-history entry. Chips + text + an optional control, never a step. */
.drow {
  display:flex; gap:8px; align-items:center; margin-top:5px; font-size:var(--fs-secondary);
  border:1px solid var(--rule); border-radius:5px; padding:7px 10px; background:var(--panel);
}
.drow select { width:auto; padding:3px 7px; font-size:var(--fs-secondary); }
.drow .grow { flex:1; min-width:0; }
/* A row's compact Actions menu stands in the row's upper right corner and
   takes no column of its own: the text keeps the full width and only its
   first line gives way to the bars (the float below). */
.drow:has(> .grow ~ .actions-menu.compact) { position:relative; }
.drow > .grow ~ .actions-menu.compact { position:absolute; top:2px; right:2px; }
.drow > .grow ~ .actions-menu.compact > summary { width:24px; height:24px; }
.drow > .grow ~ .actions-menu.compact .menu { top:28px; }
.drow:has(> .grow ~ .actions-menu.compact) > .grow::before { content:""; float:right; width:18px; height:14px; }

/* Week — the seven days of ONE calendar week side by side, Monday first, each
   a .day with its name (.dh) and what falls on it as .drow rows. A day is a
   narrow column: the row's text wraps, and its Actions menu opens towards the
   middle of the week, so it never leaves the panel. Below `lg` the days stack — seven columns do not fit a phone, and
   the type does not shrink to make them (§2.1). */
.week { display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:6px; margin-top:10px; }
.week .day { min-width:0; padding:8px; border:1px solid var(--rule); border-radius:5px; background:var(--inset); }
.week .day.today { border-color:var(--rule-strong); box-shadow:0 0 0 2px rgba(11,34,59,.09); }
.week .dh { font-size:var(--fs-secondary); font-weight:600; color:var(--navy); }
.week .dh .hint { display:block; font-weight:400; }
.week .drow { flex-wrap:wrap; overflow-wrap:anywhere; }
.week .drow .grow { flex-basis:100%; }
.week .actions-menu { margin-left:auto; }
.week .day:nth-child(-n+4) .actions-menu .menu { left:0; right:auto; }

/* Customer-visible marker. A work note or closure note the requester can see is
   a different kind of artefact from an internal one, and must read as such. */
.notes.customer, .wl .e.customer { border-color:var(--good); }
.wl .e.customer { border-left-color:var(--good); }

/* ---------------------------------------------- TRANSITIONAL — remove in C -- */
/* The flat chip-row stepper and the gate block. The styleguide supersedes both
   with .gstep (one row per process task, rendered FROM the process design by
   process-flow.js). They are kept here only so Increment A can repoint the apps
   onto the palette without also rewriting their flow markup — that rewrite is
   Increment C. Delete this block with the last runHtml(). */
.steps { display:flex; gap:6px; flex-wrap:wrap; margin-top:8px; }
.step {
  font-size:var(--fs-overline); padding:3px 9px; border-radius:5px;
  border:1px solid var(--rule); color:var(--dim); background:var(--panel);
}
.step.done { border-color:var(--good); color:var(--good); background:var(--tint-done); }
.step.gate-open { border-color:var(--signal); color:var(--signal); background:var(--tint-attn); }
.gate {
  border:1px solid var(--signal); background:var(--tint-attn);
  border-radius:5px; padding:11px; margin-top:12px;
}
.gate .g-label { color:var(--signal); font-weight:600; }
.runbox { border:1px solid var(--rule); border-radius:5px; padding:11px; margin-top:12px; background:var(--panel); }

/* --------------------------------------------------------------- banners -- */
.banner { display:flex; gap:9px; align-items:center; padding:9px 13px;
          border-radius:5px; font-size:var(--fs-dense); border:1px solid; margin-top:8px; }
.banner[hidden] { display:none; }
.banner.busy { background:var(--tint-run);  border-color:var(--running); color:var(--running); }
.banner.err  { background:var(--tint-err);  border-color:var(--bad);     color:var(--bad); }
.banner.ok   { background:var(--tint-done); border-color:var(--good);    color:var(--good); }
.banner.attn { background:var(--tint-attn); border-color:var(--signal);  color:var(--signal); }
/* Busy banners were already emitting <span class="spinner">, but the only
   spinner rule was scoped to .agent-run — so it rendered as nothing at all. */
.banner .spinner {
  width:12px; height:12px; border-radius:50%; flex:none;
  border:2px solid rgba(31,91,143,.25); border-top-color:currentColor;
  animation:abh-spin .8s linear infinite;
}
/* A banner pinned to the viewport. An action confirmed in a dialog closes that
   dialog, and a banner written into the detail panel then lands wherever that
   panel happens to scroll — for a long record, off-screen, so a run that takes
   minutes looks like a click that did nothing. The toast lives OUTSIDE the
   re-rendered panel, so a poll tick cannot wipe it either. */
.toast {
  position:fixed; right:18px; bottom:18px; z-index:60; margin-top:0;
  max-width:min(440px, calc(100vw - 36px)); align-items:flex-start;
  box-shadow:0 6px 22px rgba(0,0,0,.18);
}
.toast .t-msg { flex:1; white-space:pre-wrap; overflow-wrap:anywhere; }
.toast .t-x {
  border:0; background:none; cursor:pointer; color:inherit; opacity:.7;
  font-size:var(--fs-title); line-height:1; padding:0 2px;
}
.toast .t-x:hover { opacity:1; }
/* Errors render at the control that caused them. */
.err { color:var(--bad); font-size:var(--fs-secondary); margin-top:8px; white-space:pre-wrap; }
.err:empty { display:none; }
.hint { color:var(--faint); font-size:var(--fs-secondary); }

/* ------------------------------------------------- collapsible section -- */
/* A record section the READER opens (styleguide §1.3, "What may expand").
   Native <details class="fold">: the keyboard, the expanded state and
   find-in-page come with the element, and nothing has to remember that it was
   open. The summary line is the section's heading (.panel.fold: an h2; a fold
   inside a fold: .fold-title) and one line saying what the section holds
   (.fold-sum). A section's own control stands in the opened body, never in
   the summary — a button inside a summary toggles it. Inputs and evidence
   still open in a dialog; this is for reading a record, not for acting on it. */
details.fold > summary {
  list-style:none; cursor:pointer; user-select:none; position:relative; padding-left:20px;
  display:flex; align-items:baseline; gap:4px 10px; flex-wrap:wrap;
}
details.fold > summary::-webkit-details-marker { display:none; }
details.fold > summary::before {
  content:"\25B8"; position:absolute; left:0; color:var(--faint); font-size:var(--fs-secondary);
}
details.fold[open] > summary::before { content:"\25BE"; }
details.fold > summary h2 { margin-bottom:0; }
details.fold > summary .fold-title { font-size:var(--fs-dense); font-weight:600; color:var(--navy); }
/* Beside the heading where there is room for it, on a line of its own - under
   the heading, not under the marker - where there is not (a phone). */
details.fold > summary .fold-sum { flex:1 1 14em; min-width:0; font-size:var(--fs-secondary); color:var(--ink); }
details.fold[open] > summary { margin-bottom:10px; }
/* A fold inside a fold is a row of the opened section, not a second card. */
details.fold details.fold { border-top:1px solid var(--rule); padding-top:8px; margin-top:8px; }
details.fold details.fold details.fold { margin-left:20px; }
/* A titled part of an opened section: an h3 line, ruled off from the part above. */
.fold-sub { border-top:1px solid var(--rule); padding-top:12px; margin-top:12px; }
.fold-sub:first-of-type { border-top:0; padding-top:0; margin-top:0; }

/* --------------------------------------------------------------- dialogs -- */
/* Every action needing more than one click opens one. The detail view NEVER
   expands in place — no .subpanel un-hiding, no <details> revealing step
   content. Closing returns the reader exactly where they were. */
/* margin:auto is what centres a modal dialog in the viewport. The browser sets
   it, and the `* { margin:0; }` reset above takes it away again — without this
   line every dialog opens in the top-left corner. */
dialog {
  margin:auto;
  border:0; padding:0; border-radius:8px; max-width:520px; width:calc(100% - 40px);
  background:var(--panel); color:var(--ink); box-shadow:0 18px 50px rgba(11,34,59,.28);
}
dialog::backdrop { background:rgba(11,34,59,.42); }
dialog .d-head { padding:16px 20px 13px; border-bottom:1px solid var(--rule); }
dialog .d-kicker { font-family:var(--mono); font-size:var(--fs-overline); letter-spacing:.13em;
                   text-transform:uppercase; color:var(--faint); }
dialog .d-title { font-size:var(--fs-title); font-weight:700; color:var(--navy); margin-top:3px; }
dialog .d-body { padding:18px 20px; font-size:var(--fs-dense); }
dialog .d-foot { padding:13px 20px; border-top:1px solid var(--rule); background:var(--inset);
                 display:flex; gap:9px; justify-content:flex-end; border-radius:0 0 8px 8px; }

/* -------------------------------------------- conversational surface (§3) -- */
/* Styleguide decision 3 exempts a chat app from the two-column shell — NOT from
   the token set or the closed component set. These are that exemption's
   components, canonical here rather than inlined in the one app that uses them
   today: an app-local <style> is exactly the drift this file exists to stop.
   §3's inventory owes them a row; noted in the adoption plan. */
body.conversational { min-height:100vh; display:flex; flex-direction:column; }
body.conversational > main {
  display:flex; flex-direction:column; gap:14px;
  flex:1; overflow-y:auto; max-width:760px; width:100%; margin:0 auto; padding:20px;
}
.empty { margin:auto; text-align:center; color:var(--dim); font-size:var(--fs-dense); }

/* A turn. The person's own words are navy-filled; the assistant answers on a
   white panel — the same raised/recessed logic as the rest of the system. */
.msg { display:flex; flex-direction:column; max-width:78%; }
.msg.user { align-self:flex-end; align-items:flex-end; }
.msg.bot  { align-self:flex-start; align-items:flex-start; }
.bubble {
  padding:10px 14px; border-radius:10px; font-size:var(--fs-body); line-height:1.5;
  white-space:pre-wrap; word-break:break-word;
}
.msg.user .bubble { background:var(--rule-strong); color:#FFFFFF; border-bottom-right-radius:3px; }
.msg.bot .bubble  { background:var(--panel); border:1px solid var(--rule); border-bottom-left-radius:3px; }
.msg.error .bubble { background:var(--tint-err); border-color:var(--bad); color:var(--bad); }

/* Citations: the DOCUMENTS an answer draws on, never raw chunk text. */
.sources { margin-top:6px; display:flex; flex-direction:column; gap:6px; width:100%; }
.sources-label { font-size:var(--fs-overline); color:var(--faint); }
.source {
  display:flex; align-items:center; gap:8px; font-size:var(--fs-secondary);
  background:var(--inset); border:1px solid var(--rule); border-radius:5px; padding:5px 10px;
}
.source .doc-title { color:var(--ink); }
.source a.doc-title { color:var(--navy); text-decoration:none; border-bottom:1px dotted var(--navy); cursor:pointer; }
.source a.doc-title:hover { color:var(--action); border-color:var(--action); }
/* A cited document opened for reading (decision 16): the one wide dialog, its
   body scrolls so the head and Close stay put. Rendered from escaped markdown. */
dialog.doc { max-width:860px; }
dialog.doc .d-body { max-height:70vh; overflow-y:auto; }
.doc-text { font-size:var(--fs-body); line-height:1.55; color:var(--ink); }
.doc-text h1, .doc-text h2, .doc-text h3, .doc-text h4 { color:var(--navy); margin:16px 0 6px; }
.doc-text p, .doc-text ul, .doc-text ol { margin:0 0 10px; }
.doc-text pre { font-family:var(--mono); font-size:var(--fs-secondary); background:var(--inset);
  border:1px solid var(--rule); border-radius:5px; padding:8px 10px; white-space:pre-wrap; margin:0 0 10px; }
.doc-text code { font-family:var(--mono); background:var(--inset); padding:0 3px; border-radius:3px; }
.doc-text table { border-collapse:collapse; margin:0 0 10px; font-size:var(--fs-secondary); }
.doc-text th, .doc-text td { border:1px solid var(--rule); padding:4px 8px; text-align:left; vertical-align:top; }
.doc-text th { background:var(--inset); }
/* Audience, not state — so it is deliberately not a .chip (§3). */
.doc-kind {
  font-size:var(--fs-overline); text-transform:uppercase; letter-spacing:.09em; padding:1px 7px;
  border-radius:99px; border:1px solid var(--rule); color:var(--faint);
}
.doc-kind.end_user  { border-color:var(--good);    color:var(--good); }
.doc-kind.technical { border-color:var(--running); color:var(--running); }
.register-note { font-size:var(--fs-overline); color:var(--faint); margin-top:5px; }

/* Agent attribution on a surface with no step list (§7): each dispatched agent
   names itself while it runs and leaves one sentence behind. Plain names only —
   the server sends the name, never the URN. */
.agent-steps { display:flex; flex-direction:column; gap:6px; font-size:var(--fs-secondary); }
.agent-step { display:flex; align-items:flex-start; gap:8px; }
.agent-step-icon { flex:none; width:12px; text-align:center; color:var(--faint); }
.agent-step.done .agent-step-icon   { color:var(--good); }
.agent-step.failed .agent-step-icon { color:var(--bad); }
.agent-step-name { color:var(--navy); font-weight:600; }
.agent-step.running .agent-step-name { color:var(--running); font-weight:500; }
.agent-step-outcome { color:var(--dim); margin-top:2px; line-height:1.4; }
.agent-steps + .typing { margin-top:8px; }

.typing { display:inline-flex; gap:4px; padding:4px 0; }
.typing span {
  width:6px; height:6px; border-radius:50%; background:var(--faint);
  animation:abh-blink 1.2s infinite ease-in-out;
}
.typing span:nth-child(2) { animation-delay:.2s; }
.typing span:nth-child(3) { animation-delay:.4s; }
@keyframes abh-blink { 0%, 80%, 100% { opacity:.25; } 40% { opacity:1; } }

.composer {
  display:flex; gap:10px; align-items:flex-start;
  padding:16px 20px 20px; border-top:1px solid var(--rule); background:var(--panel);
  max-width:760px; width:100%; margin:0 auto;
}
.composer textarea { flex:1; min-height:0; resize:none; }

/* Past the shell's 1500px cap `main` centres itself while the header and the
   tab row keep a flat 20px padding — so on a wide monitor the chrome sits hard
   left of the content it labels, and the tabs no longer meet the panels they
   open. Pad them out to meet it.

   This pads the CONTENT and does not cap the element: the header is a bar and
   its ground and bottom rule must still span the viewport. `100%` resolves
   against the body, so it excludes the scrollbar in a way `100vw` would not.
   `main`'s 1500px is a border-box width, hence the + 20px to clear its own
   padding and line up with the panel edge rather than the grid edge. */
@media (min-width:1500px) {
  header, .tabs {
    padding-left:calc((100% - 1500px) / 2 + 20px);
    padding-right:calc((100% - 1500px) / 2 + 20px);
  }
}

/* ------------------------------------------------------------ responsive -- */
/* Styleguide §2.1. Until this block landed, THIS FILE HAD NO BREAKPOINTS AT
   ALL — one @media, for reduced motion — while `main` was a hard
   `400px 1fr` grid. Below roughly 800px the detail column was crushed against
   the queue, so tiers C and D were committed to on paper and unmet in code. */

/* Tier D (768-1023): the two-column shell collapses to one.
   The queue stays ABOVE the detail rather than becoming a drawer — a drawer
   needs a per-app view toggle and this file is CSS only. That makes `.list`'s
   height the whole ballgame: at the desktop 56vh the reader scrolls past most
   of a screen of queue to reach the record they just picked, every time. 32vh
   keeps roughly four cards visible and puts the detail one short scroll away.
   The first-class queue VIEW of §2.1 is still owed; this is the half that can
   be done in the shared stylesheet, not the whole answer. */
@media (max-width:1023px) {
  main { grid-template-columns:1fr; padding:12px 14px; gap:12px; }
  main.single { max-width:none; }
  .list { max-height:32vh; }
  /* The header is a flex row with no wrap: app name, tabs, Security, identity.
     Unwrapped it pushes the sign-in state off the right edge. */
  header { flex-wrap:wrap; row-gap:8px; padding:12px 14px; }
  /* Tabs scroll sideways rather than wrapping into a second row that would
     collide with the panel edge they are supposed to sit on. */
  .tabs { padding:8px 14px 0; overflow-x:auto; }
  .tabs button { white-space:nowrap; }
  /* Paired fields stack. Side by side they are ~350px each on a portrait iPad,
     which fits — but only just, and not once a 44px touch target and a date
     picker are in one of them. Stacking also removes the whole overflow class
     rather than relying on every control being shrinkable. */
  .row2 { grid-template-columns:1fr; }
  /* A week reads top to bottom: one day under the other, each row as wide as
     any other .drow, its Actions menu back at the right edge. */
  .week { grid-template-columns:1fr; }
  .week .dh .hint { display:inline; }
  .week .drow { flex-wrap:nowrap; }
  .week .drow .grow { flex-basis:auto; }
  .week .day:nth-child(-n+4) .actions-menu .menu { left:auto; right:0; }
  /* support-assistant is exempt from the two-column shell (§2 decision 3) but
     not from §2.1. A 78% bubble wastes a narrow screen. */
  .composer { padding:12px 14px 16px; }
  .msg { max-width:88%; }
}

/* Touch (tiers C and D) — §2.1's 44x44 minimum.
   Keyed on the POINTER, not the viewport: an iPad in landscape at 1366 needs
   fat controls and is outside the width query above, while a 1000px desktop
   window does not need them and is inside it. Width is the wrong signal for a
   question about fingers. */
@media (pointer:coarse) {
  button, .btn { min-height:44px; }
  button.small, .btn.small { min-height:44px; padding:8px 14px; }
  .actions-menu.compact > summary { width:44px; height:44px; }
  .actions-menu.compact .menu,
  .drow > .grow ~ .actions-menu.compact .menu { top:48px; }
  .drow > .grow ~ .actions-menu.compact { top:0; right:0; }
  .drow > .grow ~ .actions-menu.compact > summary { width:44px; height:44px; }
  .drow:has(> .grow ~ .actions-menu.compact) > .grow::before { width:24px; height:20px; }
  /* Header controls are deliberately compact by rule (4px 11px) so the bar is
     the same height in every app; on touch that rule loses to reachability. */
  header button, header .btn { min-height:44px; padding:8px 14px; }
  .tabs button { min-height:44px; }
  /* The step-action chips of decision 10 are the worst offenders — 2px 10px
     pills that are real, and sometimes destructive, actions. */
  .g-act button, .g-act .btn { min-height:44px; padding:8px 14px; }
  /* A choice is ticked with a finger: the whole line is the target. */
  label.check { min-height:44px; margin:0; }
  /* A card selects a record: it is a tap target, not decoration. */
  .card { padding:12px 13px; }
  /* textarea keeps its own 60px minimum — this is a floor, not a reset. */
  input, select { min-height:44px; }
}

@media (prefers-reduced-motion:reduce) {
  *, *::before, *::after { animation:none !important; transition:none !important; }
  .agent-run .spinner { border-top-color:var(--running); }
}
