/* 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 */
  --tint-human:#F1ECF7;  /* + --human    8.19: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                            */
  /* One control height (§3, decision 26): a select is as tall as the text
     input beside it, and a date input no taller. Compact is the data row's. */
  --field-h:38px;
  --field-h-compact:26px;
}

/* 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; overflow-x:auto; }
/* The tab row is its own row and scrolls itself, at every width: however many
   tabs an app has, the page body never scrolls sideways (styleguide §2). */
.tabs button {
  flex:none; white-space:nowrap;
  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. No max-width: the shell takes the full width
   of the viewport (decision 29) — a cap left a large monitor's sides empty
   while the detail column, where the work happens, wrapped. */
main {
  display:grid; grid-template-columns:240px 1fr; gap:16px;
  padding:16px 20px;
}
main.single { grid-template-columns:1fr; max-width:900px; margin:0 auto; }
/* 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; }
}
/* Two panes (decision 31). The page is exactly as tall as the screen and each
   column scrolls on its own: the list stays where it is while the detail is
   read, instead of leaving with the page. Only for the two-column shell — a
   single column (main.single, the chat surface) keeps the page scroll. The
   list column is one scroller, so its .list drops its own 56vh box: two
   nested scrollbars for one list is the thing this removes. */
@media (min-width:1024px) {
  body:not(.conversational):has(> main:not(.single)) {
    height:100vh; height:100dvh; display:flex; flex-direction:column; overflow:hidden;
  }
  body:not(.conversational):has(> main:not(.single)) > * { flex:none; }
  body:not(.conversational) > main:not(.single) {
    flex:1 1 auto; min-height:0; grid-template-rows:minmax(0, 1fr);
  }
  body:not(.conversational) > main:not(.single) > * {
    min-height:0; overflow-y:auto; overscroll-behavior:contain;
  }
  body:not(.conversational) > main:not(.single) > :nth-child(1 of :not([hidden])) .list {
    max-height:none; overflow:visible;
  }
}
/* A single column that holds a week (.week): seven days need more than the
   reading width of a list, so it takes the full width like the shell. */
main.single.wide { max-width:none; }

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

.panel-stack { display:flex; flex-direction:column; gap:16px; }
.panel-stack[hidden] { display:none; }

/* ------------------------------------------------------------------ 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;
}
/* One control height (decision 26). Every single-line control — a text-like
   input, a date/time input, a select — is var(--field-h), so a row of fields
   lines up. Left to the browser a select came out 3px shorter than the input
   beside it in Chrome and ignores its padding on Safari/iPad; dropping its
   native appearance is what makes the height hold there, so the chevron is
   drawn here, in the dim ink. */
input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]):not([type=color]),
select { height:var(--field-h); }
select:not([multiple]) {
  -webkit-appearance:none; appearance:none; padding-right:28px;
  background-image:linear-gradient(45deg, transparent 50%, var(--dim) 50%),
                   linear-gradient(135deg, var(--dim) 50%, transparent 50%);
  background-position:calc(100% - 15px) 50%, calc(100% - 10px) 50%;
  background-size:5px 5px; background-repeat:no-repeat;
}
select[multiple] { height:auto; }
.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.
   An action on the page is BOLD INK TEXT (decision 23, Thomas 2026-10-08):
   filled boxes were too big and overlapped in rows and on small screens.
   No fill, no border; underlined on hover; a focus ring for the keyboard. */
button, .btn {
  font:inherit; font-size:var(--fs-dense); font-weight:700; padding:4px 2px; border-radius:3px;
  background:transparent; color:var(--ink); border:0;
  cursor:pointer; text-decoration:none; text-underline-offset:3px;
}
button:hover, .btn:hover { text-decoration:underline; }
button:active, .btn:active { color:var(--navy); }
button:focus-visible, .btn:focus-visible { outline:2px solid var(--action); outline-offset:2px; }

/* Destructive — equal weight, different meaning: bold crimson text. */
button.danger, .btn.danger { color:var(--bad); }
button.danger:hover, .btn.danger:hover { 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 {
  color:var(--faint); font-weight:500; cursor:not-allowed; text-decoration:none;
}
button.small, .btn.small { padding:2px 2px; font-size:var(--fs-secondary); }

/* A dialog's foot is where a decision is committed - never in a row, never
   crowded - so its actions stay filled buttons (decision 23). The 1px border
   matches the fill so active and inactive buttons keep identical geometry;
   bronze is 5.60:1 against white. */
dialog .d-foot button, dialog .d-foot .btn {
  font-weight:600; padding:8px 16px; border-radius:5px;
  background:var(--action); color:var(--action-ink); border:1px solid var(--action);
  transition:background .13s;
}
dialog .d-foot button:hover, dialog .d-foot .btn:hover {
  background:var(--action-hover); border-color:var(--action-hover); text-decoration:none;
}
dialog .d-foot button:active, dialog .d-foot .btn:active {
  background:var(--action-active); border-color:var(--action-active); color:var(--action-ink);
}
dialog .d-foot button.danger, dialog .d-foot .btn.danger { background:var(--bad); border-color:#9E1F24; color:#FFFFFF; }
dialog .d-foot button.danger:hover, dialog .d-foot .btn.danger:hover { background:#A81F25; border-color:#A81F25; }
dialog .d-foot button:disabled, dialog .d-foot button.inactive, dialog .d-foot .btn.inactive {
  background:var(--panel); border:1px solid var(--rule); color:var(--faint); font-weight:500;
}

/* An icon button: one conventional glyph (a funnel for Filter) that stands
   where a labelled button outweighed the heading it sits in — the compact
   Actions menu's weight, 28px, no fill. The word stays as aria-label and
   title; the markup carries the glyph as an inline SVG on currentColor. */
button.icon, .btn.icon {
  width:28px; height:28px; padding:0; display:inline-flex; align-items:center; justify-content:center;
  background:transparent; border-color:transparent; color:var(--navy);
}
button.icon:hover, .btn.icon:hover { background:var(--inset); border-color:var(--rule); }
button.icon svg { width:16px; height:16px; display:block; }
/* The display rule above would otherwise override the hidden attribute. */
button.icon[hidden], .btn.icon[hidden] { display:none; }
/* Something is applied (a filter narrowing the list): the glyph takes the
   "your turn" tint and the count stands beside it, from data-count. */
button.icon.on, .btn.icon.on { background:var(--tint-attn); border-color:var(--signal); color:var(--signal); }
button.icon[data-count] { width:auto; padding:0 7px 0 5px; gap:3px; }
button.icon[data-count]::after { content:attr(data-count); font-size:var(--fs-overline); font-weight:600; }

/* ------------------------------------------------------------------ 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 24px 3px 7px; font-size:var(--fs-secondary); height:var(--field-h-compact);
               background-position:calc(100% - 12px) 50%, calc(100% - 7px) 50%; }
/* A short entry box in a row (a rank, a count) keeps its own size: at the
   base width:100% it squeezed the row's text to nothing and covered it. */
.drow input:not([type=checkbox]):not([type=radio]) { width:auto; flex:none; padding:3px 7px; font-size:var(--fs-secondary); }
/* Compact height: as specific as the one-height rule it narrows (decision 26). */
.drow input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]):not([type=color]) { height:var(--field-h-compact); }
.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; }

/* Hours (decision 33) — a week as hours, 06:00 to 22:00: a column per day, an
   hour gutter on the left, an all-day row under the day heads. An entry with
   a time is a block (.hr-ent) set at its start and as tall as it lasts, its
   colour the KIND of entry: training, task, competition. A stable's standing
   arena plan is a hatched band behind the entries (.hr-plan), the arena
   upright at its right edge and the use at its foot. Where a block stands is
   the page's data (--hr-top, --hr-height, --hr-lane of --hr-lanes, set from
   its data-hr); how it looks is here. One hour is 44px: 16 hours, 704px.
   Below `lg` the page draws one day (.hours.one). */
.hours { --hr-hour:44px; --hr-edge:20px; display:grid; grid-template-columns:44px repeat(7, minmax(0, 1fr)); margin-top:10px; }
.hours.one { grid-template-columns:44px minmax(0, 1fr); }
.hours .hr-head { min-width:0; padding:6px 6px 4px; border-bottom:1px solid var(--rule);
                  font-size:var(--fs-secondary); font-weight:600; color:var(--navy); }
.hours .hr-head .hint { display:block; font-weight:400; }
.hours .hr-head.today { background:var(--tint-run); border-radius:5px 5px 0 0; }
.hours .hr-lab { font-size:var(--fs-secondary); color:var(--faint); text-align:right; padding:4px 6px 0 0; white-space:nowrap; }
.hours .hr-allday { min-width:0; min-height:28px; padding:3px; border-bottom:1px solid var(--rule); border-left:1px solid var(--rule); }
.hours .hr-allday .drow { margin-top:2px; padding:3px 6px; }
.hours .hr-gutter, .hours .hr-day { position:relative; height:calc(16 * var(--hr-hour)); }
.hours .hr-gutter .hr-lab { position:absolute; right:0; top:var(--hr-top); padding:0 6px 0 0; transform:translateY(-50%); }
.hours .hr-day { min-width:0; border-left:1px solid var(--rule);
                 background-image:linear-gradient(var(--rule) 1px, transparent 1px);
                 background-size:100% var(--hr-hour); }
.hours .hr-day.today { background-color:rgba(31,91,143,.035); }
.hours .hr-ent { position:absolute; z-index:1; display:flex; top:var(--hr-top); height:var(--hr-height);
                 left:calc((100% - var(--hr-edge)) / var(--hr-lanes, 1) * var(--hr-lane, 0) + 2px);
                 width:calc((100% - var(--hr-edge)) / var(--hr-lanes, 1) - 4px); }
.hours .hr-ent > .drow { flex:1; min-width:0; margin:0; padding:2px 5px; border:0; border-left:3px solid; border-radius:4px; align-items:flex-start; }
.hours .hr-ent > .drow > .grow { overflow:hidden; max-height:100%; white-space:nowrap; text-overflow:ellipsis; }
.hours .hr-ent > .drow > .grow .hint { white-space:nowrap; }
.hours .hr-train > .drow, .hours .hr-allday .drow.hr-train { background:var(--tint-run);   border-left:3px solid var(--running); }
.hours .hr-task  > .drow, .hours .hr-allday .drow.hr-task  { background:var(--tint-attn);  border-left:3px solid var(--signal); }
.hours .hr-comp  > .drow, .hours .hr-allday .drow.hr-comp  { background:var(--tint-human); border-left:3px solid var(--human); }
/* A session with no duration is drawn an hour long, its edge dashed. */
.hours .hr-ent.est > .drow { border-left-style:dashed; }
.hours .hr-plan { position:absolute; left:0; right:0; z-index:0; top:var(--hr-top); height:var(--hr-height);
                  border-right:3px solid var(--dim); color:var(--dim);
                  background:repeating-linear-gradient(135deg, var(--inset) 0 6px, var(--panel) 6px 12px); }
.hours .hr-plan .hr-arena { position:absolute; right:2px; top:4px; bottom:4px; writing-mode:vertical-rl; transform:rotate(180deg);
                            white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-size:var(--fs-overline); }
.hours .hr-plan .hr-use { position:absolute; left:4px; right:var(--hr-edge); bottom:2px; white-space:nowrap; overflow:hidden;
                          text-overflow:ellipsis; font-size:var(--fs-overline); }
.hours .hr-out { grid-column:2 / -1; padding:4px; border-top:1px solid var(--rule); }
.hours .hr-more { font-size:var(--fs-secondary); padding:2px 4px; }
/* The first days of a week open an entry's menu towards the middle. */
.hours .hr-start .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; }

/* The header's ask field (My Horses, 2026-10-10): one line said to the app from
   any tab, handed to the agents that tab offers. What became of it drops down
   under the header as turns (.msg) with their agents (.agent-steps). On a tab
   where no agent listens the field is disabled and says so. */
header .ask { flex:1; display:flex; gap:8px; min-width:220px; max-width:560px; }
header .ask input { padding:4px 10px; font-size:var(--fs-secondary); }
header .ask input:disabled { background:var(--inset); color:var(--faint); }
.ask-thread {
  display:flex; flex-direction:column; gap:10px; max-height:50vh; overflow-y:auto;
  padding:12px 20px; background:var(--inset); border-bottom:1px solid var(--rule);
}
.ask-thread .msg { max-width:88%; }
.ask-thread .ask-close { align-self:flex-end; }
@media (max-width:1023px) {
  header .ask { order:9; flex-basis:100%; max-width:none; }
  .ask-thread { padding:10px 14px; }
}

/* ------------------------------------------------------------ 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.
   That is the state before a row is picked; once one is, the record switcher
   below (decision 31) puts the list column away altogether. */
@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 { padding:8px 14px 0; }
  /* Paired fields stack. Side by side they are ~350px each on a portrait iPad,
     which fits — but only just, and not once a date picker is 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%; }
}

/* The record switcher (decision 31, abh-app.js). Below 1024px, once a row is
   picked, the list column is put away and this one line stands in for it,
   held at the top while the record scrolls: ‹ name ▾ n of m ›. The name
   brings the list column back in the record's place (body.abh-picking).
   Never drawn at 1024px and above, where the list stays beside the record. */
.abh-switch { display:none; }
@media (max-width:1023px) {
  body.abh-switching .abh-switch {
    display:flex; align-items:center; gap:6px;
    position:sticky; top:0; z-index:5;
    padding:6px 14px; background:var(--panel); border-bottom:1px solid var(--rule);
  }
  .abh-switch button.icon { flex:none; font-size:var(--fs-title); }
  .abh-switch button.icon:disabled { color:var(--faint); background:transparent; border-color:transparent; cursor:default; }
  .abh-switch .abh-switch-name {
    flex:1; min-width:0; display:flex; align-items:center; gap:6px;
    min-height:var(--field-h-compact); padding:4px 8px;
    background:transparent; border:1px solid transparent; border-radius:5px;
    color:var(--navy); font:inherit; font-weight:600; text-align:left; cursor:pointer;
  }
  .abh-switch .abh-switch-name:hover { background:var(--inset); border-color:var(--rule); }
  .abh-switch .n { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .abh-switch .arrow { flex:none; color:var(--dim); }
  .abh-switch .c { flex:none; margin-left:auto; color:var(--faint); font-size:var(--fs-secondary); font-weight:400; }
  body.abh-switching:not(.abh-picking) > main > [data-abh-col=list] { display:none; }
  body.abh-switching.abh-picking > main > [data-abh-col=detail] { display:none; }
  body.abh-switching.abh-picking > main > [data-abh-col=list] .list { max-height:none; }
}

/* Touch (tiers C and D) — §2.1, decision 27: a control is as big on a touch
   screen as on a desktop. The one touch rule is the WCAG 2.5.8 floor, so the
   smallest buttons (.small, the step-action chips) still reach 24px. Keyed on
   the POINTER, not the viewport: width is the wrong signal for fingers. */
@media (pointer:coarse) {
  button, .btn { min-height:24px; }
  /* Decision 32: iOS Safari zooms the whole page when a field under 16px
     takes the focus - a dialog focusing its first field zoomed the page on
     the iPhone. 16px on touch keeps the page at its scale. */
  input, textarea, select { font-size:16px; }
}

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