:root {
  --navy: #12263a; --amber: #e8a33d; --green: #177e63;
  --line: #d8dde0; --paper: #f5f8fa; --ink: #26282b; --muted: #7c8890;
  --red: #a3231b;
}
* { box-sizing: border-box; }
body {
  margin: 0; font: 14px/1.5 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
  color: var(--ink); background: #fff;
}
header {
  background: var(--navy); color: #fff; padding: 14px 20px;
  display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap;
}
.wordmark { font-weight: 700; letter-spacing: 4px; }
.wordmark .dot { color: var(--amber); }
.strap { font-size: 10px; letter-spacing: 3px; color: #9fb0bd; flex: 1; }
.who { font-size: 12px; display: flex; align-items: center; gap: 8px; }
.who .tag { text-transform: uppercase; letter-spacing: 1px; }

/* The login pane. Same column width as the verb pane so signing in does not
   move the page about. */
#login { max-width: 420px; margin: 32px auto; }
#login .field { margin-bottom: 12px; }
#login input { width: 100%; padding: 6px 8px; }
input[readonly] { opacity: 0.7; cursor: not-allowed; }
[hidden] { display: none !important; }

.warn {
  margin: 0; padding: 8px 20px; background: #fff3b8; color: #5a5000;
  border-bottom: 1px solid #c9a400; font-size: 12px;
}
main { display: flex; align-items: flex-start; gap: 0; }
nav {
  width: 340px; min-width: 300px; border-right: 1px solid var(--line);
  padding: 10px 0; min-height: 80vh;
}
nav .group { padding: 10px 16px 4px; font-size: 11px; letter-spacing: 2px;
             color: var(--muted); text-transform: uppercase; }
nav button {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  padding: 8px 16px; cursor: pointer; font: inherit; border-left: 3px solid transparent;
}
nav button:hover { background: var(--paper); }
nav button[aria-current="true"] { background: var(--paper); border-left-color: var(--green); }
nav button[disabled] { opacity: .45; cursor: not-allowed; }
nav .vname { font-weight: 600; color: var(--navy); }
nav .vsum { font-size: 12px; color: var(--muted); }
.tag {
  font-size: 10px; letter-spacing: 1px; padding: 1px 5px; border: 1px solid;
  border-radius: 2px; margin-left: 6px; vertical-align: 1px;
}
.tag.mut { color: var(--amber); border-color: var(--amber); }
.tag.no { color: var(--red); border-color: var(--red); }

section#pane { flex: 1; padding: 18px 24px; max-width: 900px; }
h1 { font-size: 18px; color: var(--navy); margin: 0 0 2px; }
h2 { font-size: 13px; letter-spacing: 1px; text-transform: uppercase;
     color: var(--muted); margin: 22px 0 8px; }
.muted { color: var(--muted); }
.schemaid { font-family: ui-monospace, Menlo, monospace; font-size: 12px; color: var(--green); }

fieldset { border: 1px solid var(--line); margin: 8px 0; padding: 8px 12px 12px; }
legend { font-size: 12px; color: var(--navy); font-weight: 600; }
.field { margin: 10px 0; }
.field > label { display: block; font-weight: 600; font-size: 13px; color: var(--navy); }
.field .desc { font-size: 12px; color: var(--muted); margin-bottom: 3px; }
.field input[type=text], .field input[type=number], .field select, .field textarea {
  width: 100%; padding: 5px 7px; border: 1px solid var(--line); font: inherit;
}
.field textarea { min-height: 150px; font-family: ui-monospace, Menlo, monospace; font-size: 12px; }
.req { color: var(--red); }
.row { display: flex; gap: 8px; align-items: flex-start; }
.row .field { flex: 1; }

button.act {
  background: var(--navy); color: #fff; border: 0; padding: 8px 16px;
  font: inherit; cursor: pointer; margin-right: 8px;
}
button.act.confirm { background: var(--green); }
button.act[disabled] { background: #b9c2c9; cursor: not-allowed; }
/* ⚠️ NO `color` HERE, DELIBERATELY, AND THE REASON COST A ROUND TRIP.
   A bare `<button class="small">Log out</button>` lives in the NAVY header and
   takes its white from there. Setting a colour on this rule to fix the
   `act small` case below turned that one dark-on-navy — trading one invisible
   button for another. The fix belongs on the combination that is actually
   broken, not on the modifier in general. See `button.act.small`. */
button.small { font-size: 12px; padding: 3px 8px; background: none;
               border: 1px solid var(--line); cursor: pointer; }

/* ⚠️ A THIRD INVISIBLE CONTROL, and this one was NOT introduced by the fix
   above — it has been here since the header was written. `header` sets
   `color: #fff`, but a <button> does not inherit it: the UA stylesheet gives
   every button `color: buttontext`, which is near-black. So "Log out" has
   always been dark text on the navy header. Measured contrast 1.36:1 against
   a 4.5:1 floor.

   It survived because it is the one control nobody looks for until they want
   it, and because reading the CSS shows a header that says `color: #fff` — the
   rule is there, it simply does not reach the button. Found by computing the
   contrast of every visible button on the page rather than by trusting the
   two this session had touched. */
header button.small { color: #fff; border-color: rgba(255, 255, 255, .55); }
header button.small:hover { background: rgba(255, 255, 255, .12); }

/* The share picker. It sits under the text input it fills and never replaces
   it — the field stays typeable, which is what makes an unmounted share a
   degraded experience rather than a blocked one. */
.pickbar { margin: 4px 0 0; }
.picker {
  border: 1px solid var(--line); border-top: 2px solid var(--navy);
  background: var(--paper); padding: 10px 12px; margin: 6px 0 0;
}
.picker .crumbs { margin: 0 0 8px; font-size: 12px; }
.picker .crumbs .sep { color: var(--muted); margin: 0 2px; }
.picker button.crumb-btn {
  border: 0; background: none; font: inherit; font-size: 12px; padding: 1px 3px;
  color: var(--navy); text-decoration: underline; cursor: pointer;
}
.picker ul.dirs {
  list-style: none; margin: 0; padding: 0; max-height: 260px; overflow: auto;
  background: #fff; border: 1px solid var(--line);
}
.picker ul.dirs li { border-bottom: 1px solid var(--line); }
.picker ul.dirs li:last-child { border-bottom: 0; }
.picker button.dir {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  font: inherit; padding: 6px 10px; cursor: pointer;
}
.picker button.dir::before { content: "📁"; margin-right: 8px; }
.picker button.dir:hover { background: var(--paper); }
.picker .actions { margin: 10px 0 0; display: flex; align-items: center; gap: 10px; }
.picker .chosen { font-size: 12px; }

/* The entity picker's result list reuses .picker/.dirs, but a property is not
   a folder — the 📁 that button.dir carries would be a lie about what was
   found. */
.entity-results button.dir::before { content: "🏠"; }
.entity-results button.dir .muted { margin-left: 8px; font-size: 12px; }
/* The confirmation under a chosen entity: the NAME is what a person reads and
   the uuid is small — present so it can be quoted, never the thing that has to
   be understood. */
.field > p.pickbar .chosen { font-weight: 600; }
.tiny { font-size: 11px; font-family: var(--mono, ui-monospace, monospace); }

pre {
  background: var(--paper); border: 1px solid var(--line); padding: 10px;
  overflow: auto; max-height: 460px; font-size: 12px;
}
.diff { border-left: 4px solid var(--amber); background: #fffaf0;
        padding: 8px 12px; margin: 8px 0; }
/* ⚠️ The old `.diff th { background: navy }` rule was written for the union
   table that used to live here, and it silently swallowed the row labels of
   the key/value table that replaced it — white-on-navy in a cell whose text is
   a heading, not a column. Diff tables are `table.kv` now and are styled in
   one place, below. */
.err { border-left: 4px solid var(--red); background: #fdf2f1; padding: 8px 12px; }
.err h3 { margin: 0 0 4px; color: var(--red); font-size: 14px; }
.ok { border-left: 4px solid var(--green); background: #eef4f2; padding: 8px 12px; }

/* ------------------------------------------------------------------ 2026-08-10
   Making the daily surface calmer. Nothing here is decoration: each rule is
   either "the plumbing is out of the way" or "a person can read the result".  */

.linkish { background: none; border: 0; padding: 0; font: inherit;
           color: #5a5000; text-decoration: underline; cursor: pointer; }
.explain { background: #fffdf2; border-bottom: 1px solid #e6dfae;
           padding: 8px 20px; font-size: 13px; }
.explain p { margin: 4px 0; max-width: 70ch; }

nav .group { padding: 14px 16px 2px; }
nav .glabel { font-size: 12px; letter-spacing: 1px; color: var(--navy);
              text-transform: uppercase; font-weight: 700; }
/* ⚠️ text-transform and letter-spacing are reset explicitly: the older
   `nav .group` rule uppercases and tracks out its whole subtree, which is fine
   for a three-word heading and unreadable for a sentence. */
nav .gdesc { font-size: 11px; color: var(--muted); margin-top: 2px;
             text-transform: none; letter-spacing: 0; line-height: 1.4; }
nav button.askbtn { border-bottom: 1px solid var(--line); padding: 12px 16px; }
nav button.askbtn .vname { color: var(--green); }

.crumb { font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
         color: var(--muted); margin: 0 0 2px; }
.lede { margin: 0 0 10px; max-width: 70ch; }
.willchange { background: #fffaf0; border-left: 4px solid var(--amber);
              padding: 6px 10px; max-width: 70ch; }
.fromagent { background: #eef4f2; border-left: 4px solid var(--green);
             padding: 6px 10px; max-width: 70ch; }
.attrib { max-width: 70ch; font-size: 12px; }
.actions { margin: 16px 0 4px; }

/* The plumbing lives here: schema ids, verb names, raw JSON. Present for the
   person who wants it, out of the way of the person who does not. */
details.tech { margin: 12px 0; font-size: 12px; }
details.tech > summary { cursor: pointer; color: var(--muted); }
details.tech p { margin: 6px 0; }
details.optional { margin: 12px 0; border: 1px solid var(--line);
                   padding: 6px 12px 10px; }
details.optional > summary { cursor: pointer; font-weight: 600;
                             color: var(--navy); }
.req { color: var(--muted); font-weight: 400; font-size: 11px;
       text-transform: uppercase; letter-spacing: 1px; }

/* A diff a person can read: one statement per change, not a union of columns. */
.diff .change { margin: 8px 0; }
table.kv { border-collapse: collapse; width: 100%; font-size: 12px;
           margin: 4px 0 10px; background: #fff; }
table.kv th { text-align: left; padding: 3px 6px; border-bottom: 1px solid var(--line);
              color: var(--navy); font-weight: 600; width: 30%; }
table.kv thead th { background: var(--navy); color: #fff; width: auto; }
table.kv td { padding: 3px 6px; border-bottom: 1px solid var(--line);
              font-family: ui-monospace, Menlo, monospace; }
.fromto { margin: 4px 0; font-family: ui-monospace, Menlo, monospace; }
.fromto .from { color: var(--red); }
.fromto .to { color: var(--green); font-weight: 700; }
.fromto .arrow { color: var(--muted); margin: 0 6px; }
.do-next { margin: 6px 0 0; }

/* The assistant. */
.rails { background: var(--paper); border: 1px solid var(--line);
         padding: 8px 12px; margin: 10px 0; font-size: 13px; }
.rails p { margin: 0 0 6px; max-width: 75ch; }
.rails ul { margin: 4px 0; padding-left: 18px; }
#chat { margin: 14px 0; }
.turn { margin: 10px 0; padding: 8px 12px; border-left: 3px solid var(--line); }
.turn > b { font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
            color: var(--muted); }
.turn p { margin: 4px 0; max-width: 75ch; white-space: pre-wrap; }
.turn.you { background: var(--paper); }
.turn.bot { border-left-color: var(--green); }
details.working { font-size: 12px; margin-top: 8px; }
details.working > summary { cursor: pointer; color: var(--muted); }
.step { margin: 6px 0; }
.step code { color: var(--navy); font-weight: 600; }
.bad-step .refused { color: var(--red); }
.step .args { margin-left: 12px; }
.proposal { border: 1px solid var(--amber); background: #fffaf0;
            padding: 8px 12px; margin: 8px 0; }
form.ask { display: flex; gap: 8px; align-items: flex-start; }
form.ask textarea { flex: 1; padding: 6px 8px; border: 1px solid var(--line);
                    font: inherit; }
button.small-act { padding: 5px 10px; font-size: 13px; }

/* The model-backend switch. Folded by default when something IS answering —
   it is a setting, not a daily control — and open when nothing is, because
   then it is the only thing on the page worth touching. */
details.backend { margin: 12px 0; border: 1px solid var(--line);
                  padding: 6px 12px 10px; max-width: 70ch; }
details.backend > summary { cursor: pointer; font-weight: 600;
                            color: var(--navy); }
.bgrid { display: grid; grid-template-columns: max-content 1fr; gap: 8px 12px;
         align-items: center; margin: 10px 0; }
.bgrid label { font-size: 12px; color: var(--muted); }
.bgrid select, .bgrid input { padding: 5px 8px; width: 100%; }
/* ⚠️ Amber, not grey: "this changes it for everyone" is not a footnote. */
.warn-inline { background: #fff3b8; border-left: 4px solid var(--amber);
               padding: 6px 10px; margin: 8px 0; font-size: 12px; }
ul.alts { margin: 4px 0 8px; padding-left: 18px; font-size: 12px; }

/* The answer as it arrives. ⚠️ The steps appear while the model is still
   working — that is most of what "fluid" means here, and it is why the panel
   streams rather than waiting for one JSON object at the end. */
ul.livesteps { margin: 4px 0 8px; padding-left: 18px; font-size: 12px; }
.caret { opacity: 0.55; animation: blink 1s step-start infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* ---------------------------------------------------------------- work list
   ⚠️ Three tones and no more, matching control/verbs/result.py's closed TONES.
   The adapter decides which bucket is which; this file only knows how each of
   the three should look. A fourth tone would need a change in both places,
   which is the point of closing the set. */
.chips { margin: .4rem 0 .8rem; display: flex; flex-wrap: wrap; gap: .4rem; }
.chip {
  display: inline-block; padding: .12rem .5rem; border-radius: 999px;
  font-size: .82rem; line-height: 1.5; white-space: nowrap;
  border: 1px solid transparent;
}
.chip b { font-weight: 700; }
/* Colour is never the only signal — each tone also differs in weight and
   border, so the list still reads on a monochrome print or to a colour-blind
   reader. */
.tone-alert { background: #fdecea; border-color: #e5534b; color: #7d1f19; font-weight: 600; }
.tone-warn  { background: #fdf3e2; border-color: #e8a33d; color: #7a5312; }
.tone-ok    { background: #eef4f0; border-color: #cfe0d6; color: #2f5d47; }

.headline { font-size: 1.15rem; margin: .2rem 0 .1rem; }
.headline b { color: #7d1f19; }

/* ⚠️ The empty state is a sentence the adapter wrote, not "no results". It
   gets room to be read rather than being tucked under the table. */
.emptynote {
  padding: .9rem 1rem; background: #f7f7f5; border-left: 3px solid #cfcfc8;
  color: #444; margin: .6rem 0;
}

table.worklist { width: 100%; border-collapse: collapse; margin: .5rem 0; }
table.worklist th {
  text-align: left; font-size: .78rem; letter-spacing: .04em;
  text-transform: uppercase; color: #666; border-bottom: 1px solid #ddd;
  padding: .35rem .5rem;
}
table.worklist td { padding: .4rem .5rem; border-bottom: 1px solid #f0f0ee; }
table.worklist tr.row-alert td:first-child { box-shadow: inset 3px 0 0 #e5534b; }
table.worklist tr.row-warn  td:first-child { box-shadow: inset 3px 0 0 #e8a33d; }

/* ------------------------------------------------------------ sections/tiles
   ⚠️ The left column is now TEN sections, not 38 verbs. Ben: "task oriented,
   settings/account in separate section, pretty standard but it has to flow
   nicely for a human who is non technical". */
.sectionbtn[aria-current] { background: #12263a; color: #fff; }
.sectionbtn[aria-current] .vsum { color: #c9d4e0; }

/* Tiles, per Ben's "like tiles, and expand/reduce what we see". A section
   shows only its own actions — that is the reduction — and they sit as cards
   rather than as another vertical list to scan. */
.tiles {
  display: grid; gap: .7rem; margin: 1rem 0;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
.tile {
  text-align: left; padding: .8rem .9rem; border: 1px solid #e2e2dd;
  border-radius: 6px; background: #fff; cursor: pointer; font: inherit;
  display: flex; flex-direction: column; gap: .3rem;
}
.tile:hover:not(:disabled) { border-color: #12263a; background: #fbfbfa; }
.tile:disabled { opacity: .55; cursor: default; }
.tname { font-weight: 600; }
.tsum { font-size: .86rem; color: #555; line-height: 1.35; }

.todaylist { margin: 0 0 2rem; }
.todaylist h2 { font-size: 1rem; font-weight: 600; margin: 0 0 .3rem; }
/* ⚠️ `color` HERE IS LOAD-BEARING, and its absence was a live INVISIBLE BUTTON
   on the screen the app opens on. `button.act` sets `background: var(--navy);
   color: #fff`; `button.small` sets `background: none` and, matching at equal
   specificity but later in the file, wins the background. A button carrying
   BOTH — `<button class="act small">Open the full list</button>` under every
   work list on Today — was therefore white text on the white page. The label
   was in the DOM and the button was clickable; a screenshot showed an empty
   rectangle.

   This rule is the right home for the fix because it is the only selector that
   matches exactly the broken combination: `.act` supplies a foreground whose
   background `.small` has just taken away. Putting it on `button.small`
   instead breaks the bare `.small` in the navy header — measured, not guessed.

   ⚠️ THE SECOND TIME THIS EXACT SHAPE HAS BEEN FOUND BY LOOKING RATHER THAN BY
   READING; the first was `.vname` navy-on-navy, just below. Neither is
   reachable by any test in this repo — `tests/js/render.test.mjs` can prove the
   label is in the HTML, and it IS in the HTML. Only a screenshot shows the
   colour. */
button.act.small { font-size: .85rem; padding: .3rem .7rem; color: var(--ink); }

/* ⚠️ Caught by looking at it, not by reading the CSS: `.vname` carries the
   navy brand colour, so on the selected section — which is navy — the label
   disappeared entirely and only its description showed. The one section a
   person is looking at was the one they could not read. */
.sectionbtn[aria-current] .vname { color: #fff; }

/* The work-list heading was inheriting the uppercase section-header style and
   shouting a verb summary at the reader. It is a sentence, so it reads as one. */
.todaylist h2 {
  text-transform: none; letter-spacing: 0; font-size: .95rem;
  color: #555; font-weight: 500;
}

/* Clickable rows — the difference between a report and a step. */
table.worklist tr.clickable { cursor: pointer; }
table.worklist tr.clickable:hover td { background: #f4f7fa; }
table.worklist tr.clickable:focus { outline: 2px solid #12263a; outline-offset: -2px; }
table.worklist td.go { color: #9aa5b1; text-align: right; width: 1.5rem; }

/* A record reads as a thing, not as a row dump. */
.fact { display: flex; gap: .8rem; padding: .3rem 0; border-bottom: 1px solid #f2f2ef; }
.flabel { flex: 0 0 9rem; color: #666; font-size: .86rem; padding-top: .1rem; }
.fval { font-size: 1.02rem; }
