
:root{--bg:#fafafa;--card:#fff;--bg-step:#f1f1f3;--ink:#18181b;--muted:#63676f;
--line:#e9e9ec;
/* ux1 slice 9, #18: a form control's own border, at 3:1 against any of the
   backgrounds above — --line alone (a hairline divider, never meant to be
   read on its own) measures under 1.3:1 and stays exactly that for the
   dividers and card edges it already draws. */
--line-strong:#7d828c;
--accent:#3d63dd;--accent-hi:#3053be;--accent-ink:#fff;
/* ux1 slice 9, #18: --accent TEXT on an --accent-soft background (the
   settings gear's "you are here" pill, a phone board-tab's selected state)
   measured 4.49:1 at the old .08 — the same colour on both sides of a
   contrast check leaves little room. .06 keeps the same tinted-pill look
   everywhere else this token backs a hover or selected state, where the
   text on top is --ink or --muted rather than --accent and was never close
   to the floor. */
--accent-soft:rgba(61,99,221,.06);--accent-tint:rgba(61,99,221,.13);
--ring:rgba(61,99,221,.28);
--ok:#15803d;--ok-bg:rgba(22,163,74,.11);
--warn:#b45309;--warn-bg:rgba(180,83,9,.11);
--bad:#dc2626;--bad-bg:rgba(220,38,38,.10);
--shadow:0 1px 2px rgba(16,24,40,.04);--radius:8px}
@media(prefers-color-scheme:dark){:root{--bg:#0e1013;--card:#16181d;
--bg-step:#1c1f25;--ink:#e6e8ec;--muted:#8b919e;--line:#23262c;
--line-strong:#8b919e;
--accent:#7c97fb;--accent-hi:#9db1fc;--accent-ink:#0d1220;
--accent-soft:rgba(124,151,251,.10);--accent-tint:rgba(124,151,251,.17);
--ring:rgba(124,151,251,.35);
--ok:#4ccb7e;--ok-bg:rgba(76,203,126,.13);
--warn:#e5b04b;--warn-bg:rgba(229,176,75,.13);
--bad:#ef7070;--bad-bg:rgba(239,112,112,.13);
--shadow:0 1px 2px rgba(0,0,0,.4)}}
/* A DOCUMENT PREVIEW IS A WHITE PAGE IN EVERY THEME (owner, 2026-09-29: "the
   colour for the preview of documents is all black"). The template box and
   the flow preview draw the document on white paper with dark ink, but the
   table rules below paint every table in --card and every heading cell in
   --bg-step — the DARK ones on a machine in dark mode, so a customer's
   table-heavy template came out black writing on black. The paper puts the
   light palette back for everything inside it, so every rule that reads a
   token draws the page the way the document prints. The accent tokens are
   left alone: they read on white in both themes and carry the company's own
   colour (_accent_override). */
.doc-paper{--bg:#fafafa;--card:#fff;--bg-step:#f1f1f3;--ink:#18181b;
--muted:#63676f;--line:#e9e9ec;--line-strong:#7d828c;
--shadow:0 1px 2px rgba(16,24,40,.04);
color-scheme:light;background:#fff;color:#111}
*{box-sizing:border-box}
/* ux1 slice 9, #21: ONE blanket rule rather than hunting every transition
   and @keyframes this file adds. Everything the more specific rules below
   already turn off for reduced motion stays off; this catches whatever
   they do not, including the loading dots' and the lookup bar's own
   infinite animations — a spinner that never stops is exactly the motion
   this preference exists to remove. */
@media (prefers-reduced-motion:reduce){
*,*:before,*:after{animation:none!important;transition:none!important}}
/* FLUID TYPE (owner ask 2026-08-27): every font-size below is rem, and THIS
   is the one knob they all hang off — 1rem glides from 14px on a phone up to
   16px on a large screen (clamp), so text scales with the screen everywhere,
   the chat box included, without a breakpoint jump. text-size-adjust stays:
   phones must not double-inflate what already scales. */
html{-webkit-text-size-adjust:100%;
font-size:clamp(14px,13px + .25vw,16px)}
body{margin:0;background:var(--bg);color:var(--ink);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
font-size:1rem;line-height:1.6}
.wrap{max-width:960px;margin:0 auto;padding:24px 20px 64px}
/* ONE PAGE OPTS OUT of that measure (owner, 2026-09-05: "for the chat box, can
   you make it fill the page ... it's a very weird shape now"). 960px is right
   for a page of prose, forms and tables, and wrong for the chat: that page is a
   panel with a rail down its left and a conversation beside it, and on a wide
   screen the two were squeezed into the middle third with empty page either
   side. The class is put on by the shell, so only the page that asks for it
   gets it and every other page is untouched.
   The padding goes with it. The chat panel's height is the window minus its own
   furniture, and .wrap's 64px of bottom padding was never in that sum — so the
   page kept a scrollbar even with nothing below the panel, which is the other
   half of what the owner was looking at. 24px matches the air the panel's
   offset already allows for at both widths.
   TWO classes on purpose: a bare .wrap-wide would lose to the 640px block near
   the foot of this sheet, which resets .wrap's padding wholesale and is later
   in the cascade — the phone would have kept the scrollbar. */
.wrap.wrap-wide{max-width:none;padding-bottom:24px}
/* The heading and the settings gear share one row: the heading takes the
   space, the gear sits at the far right of every signed-in page. A flex row
   rather than a float so the gear stays vertically centred against a heading
   that has grown a subtitle line. */
.page-head{margin:0 0 24px;padding-bottom:12px;border-bottom:1px solid var(--line);
display:flex;align-items:center;gap:12px}
.page-head>div{flex:1 1 auto;min-width:0}
/* The gear is a LINK, not a button: with no JavaScript at all a click still
   opens the settings hub in a second window (target=_blank). The script that
   ships beside it only upgrades that to the desktop client's real pop-out. */
/* The gear wears its NAME beside it (2026-08-25 click-through: a bare glyph
   in the corner was not read as "settings"). The label sets the type size —
   body text, not the glyph's — and only the glyph is drawn larger, so the
   control reads as a word with an icon rather than an oversized symbol. */
.gear{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;
font-size:0.9286rem;line-height:1;color:var(--muted);
text-decoration:none;padding:5px 8px;border-radius:8px}
.gear .gear-mark{font-size:1.1429rem}
.gear:hover{color:var(--accent);background:var(--accent-tint)}
.gear[aria-current=page]{color:var(--accent);background:var(--accent-soft)}
/* The bell (Board step 2, 2026-09-13): the gear's twin at the right end of
   the heading row. The unread count is a span the shell only writes when
   there is one, so it is styled through .bell span and NOT a class name —
   the stylesheet is inlined on every page, and a class name in it would
   make "no count shown" impossible to tell from the outside. */
.bell{flex:0 0 auto;display:inline-flex;align-items:center;gap:4px;
font-size:1.1429rem;line-height:1;color:var(--muted);text-decoration:none;
padding:5px 8px;border-radius:8px}
.bell:hover{color:var(--accent);background:var(--accent-tint)}
.bell span{font-size:0.7857rem;font-weight:600;color:#fff;background:var(--accent);
border-radius:999px;padding:1px 6px;min-width:18px;text-align:center}
/* The settings hub: one card per section, its plain description underneath
   the link, so a person choosing where to go reads what the page does rather
   than guessing from its name. */
.settings-hub{list-style:none;margin:12px 0 0;padding:0;display:grid;
grid-template-c\6f lumns:repeat(auto-fill,minmax(240px,1fr));gap:10px}
.settings-hub li{background:var(--card);border:1px solid var(--line);
border-radius:10px;padding:12px 14px}
.settings-hub a{font-weight:600;display:block}
.settings-hub span{display:block;margin-top:2px;color:var(--muted);
font-size:0.8929rem}
/* The folder picker's trail: quiet, wrapping, so a deep path does not push
   the table sideways. */
.crumbs{font-size:0.8929rem;color:var(--muted);word-break:break-all}
/* Two buttons in one table cell (Look inside / Remove) sit on one line.
   Scoped to the cell that has them so no other table changes shape. */
.row-actions form{display:inline;margin:0}
/* ONE FOLD PER PERSON on the staff page. Closed, so the list reads as a list
   of people; the summary carries the three facts you scan for and the whole
   set of controls waits inside. The rows are hairline-separated rather than
   boxed — nineteen cards would be the same wall in a different shape. */
.staff-list{border:1px solid var(--line);border-radius:10px;overflow:hidden}
.staff-person+.staff-person{border-top:1px solid var(--line)}
.staff-person>summary{cursor:pointer;padding:10px 14px}
.staff-person>summary:hover{background:var(--bg-step)}
.staff-person[open]>summary{background:var(--bg-step);
border-bottom:1px solid var(--line)}
/* The role beside the name is a fact about them, not a heading, so it stays
   quiet and lets the name and the status carry the line. */
.staff-role{color:var(--muted);font-size:0.8571rem;margin-left:6px}
.staff-fields{padding:2px 14px 14px}
.staff-fields>h3:first-of-type{margin-top:8px}
/* Every Setup needed item is a link now, so the list reads as a to-do list of
   things to go and do rather than a wall of instructions. */
.needs li{margin:2px 0}
/* The one line a gated-shut new account gets on Home, so a nearly-empty page
   reads as "not switched on yet" rather than as a broken product. (The other
   half of that fact — the admin's warning badge — reuses .st-warn, the same
   colour every other "needs attention" cell in a table already wears.) */
.empty-note{color:var(--muted);font-size:0.9286rem}
/* The Get set up checklist an admin sees until their workspace is actually
   doing work. Same quiet list treatment as Setup needed; a finished step goes
   muted rather than disappearing, so the list visibly shortens. "Close this
   list" is drawn as plain text — closing a checklist must never look like the
   main thing to do on the page. .setup-extra is the desktop-app row, which
   sits UNDER the numbered list because it is not one of the things counted. */
.setup-steps li{margin:2px 0}
.setup-steps li.done{color:var(--muted)}
.setup-extra li{margin:2px 0}
.setup-hide{margin:4px 0 0}
.setup-hide button{background:transparent;border:0;padding:0;
color:var(--muted);font-size:0.8571rem;font-weight:400}
.setup-hide button:hover{color:var(--accent);text-decoration:underline}
h1{font-size:1.4286rem;font-weight:650;letter-spacing:-.01em;margin:0}
.page-sub{margin:4px 0 0;color:var(--muted);font-size:0.9286rem}
/* THE WAY BACK (0.1.87 row 19): one quiet line above the heading row, at its
   left edge. Muted text, not a button — the page's title stays the loudest
   thing at the top. A hover or a keyboard focus brings it up to ink with an
   underline; the focus ring is the accent's, like every other control. */
.page-back{margin:0 0 4px;font-size:0.9286rem;line-height:1.4}
.page-back a{display:inline-flex;align-items:baseline;gap:6px;max-width:100%;
padding:4px 0;color:var(--muted);font-weight:400;overflow-wrap:anywhere}
.page-back a:hover,.page-back a:focus-visible{color:var(--ink);
text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
.page-back a:focus-visible{outline:2px solid var(--accent);outline-offset:3px;
border-radius:3px}
@media print{.page-back{display:none}}
/* On a phone the line is a finger's height (44px), under the Menu button. */
@media (max-width:640px){.page-back{margin:0}
.page-back a{min-height:44px;align-items:center;padding:0}}
h2{font-size:0.7857rem;font-weight:650;text-transform:uppercase;letter-spacing:.08em;
color:var(--muted);margin:28px 0 8px}
h3{font-size:1rem;font-weight:600;margin:16px 0 4px}
p{margin:8px 0}
small{color:var(--muted);font-size:0.8571rem}
strong{font-weight:600}
a{color:var(--accent);text-decoration:none}
a:hover{color:var(--accent-hi);text-decoration:underline}
ul{padding-left:20px;margin:8px 0}
ol{padding-left:24px;margin:8px 0}
li{margin:4px 0}
/* The Messages feed. It was an <ol> and got li{margin} for free; as divs it
   needs its own gap, or the messages run together into one wall — which on a
   phone is worse than the log line this replaced. The header spans sit on one
   muted line and the text wraps under them. */
.wa-msg{margin:0 0 10px;padding-bottom:8px;border-bottom:1px solid var(--line)}
.wa-msg .wa-group,.wa-msg .wa-sender,.wa-msg .wa-time{
color:var(--muted);font-size:0.8571rem}
.wa-msg .wa-sender{font-weight:600}
img{max-width:100%;border-radius:6px}
.whoami{color:var(--muted);font-size:0.8571rem;margin:0 0 8px}
.nav{font-size:0;margin:0 0 16px;padding-bottom:8px;
border-bottom:1px solid var(--line)}
.nav a{display:inline-block;font-size:0.9286rem;font-weight:550;color:var(--muted);
padding:4px 10px;margin:2px 4px 2px 0;border-radius:6px}
.nav a:hover{color:var(--ink);background:var(--bg-step);text-decoration:none}
.tiles{list-style:none;display:flex;flex-wrap:wrap;gap:8px;padding:0;
margin:12px 0}
.tiles li{flex:1 1 230px;max-width:100%;background:var(--card);
border:1px solid var(--line);border-radius:var(--radius);
box-shadow:var(--shadow);padding:12px 14px;margin:0;font-size:0.9286rem}
table{border-collapse:separate;border-spacing:0;width:100%;margin:12px 0;
background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
overflow:hidden;box-shadow:var(--shadow);font-size:0.9286rem;
font-variant-numeric:tabular-nums}
th,td{padding:10px 12px;text-align:left;border-bottom:1px solid var(--line);
vertical-align:top}
th{font-size:0.75rem;font-weight:650;text-transform:uppercase;letter-spacing:.06em;
color:var(--muted);background:var(--bg-step)}
tr:last-child td{border-bottom:0}
tr:hover td{background:var(--bg-step)}
form{display:inline-block;margin:4px 8px 4px 0;max-width:100%}
input,select,textarea{font:inherit;font-size:0.9286rem;color:var(--ink);
background:var(--card);border:1px solid var(--line-strong);border-radius:6px;
padding:7px 10px;margin:2px 6px 2px 0;max-width:100%;
transition:border-color .15s,box-shadow .15s}
input::placeholder,textarea::placeholder{color:var(--muted);opacity:.8}
/* ux1 slice 9, #17: a native checkbox/radio renders at ~13x13px in every
   browser tested and nothing here had ever sized it. Sized to the floor
   itself rather than left to "24px from its neighbour", since a run of them
   in a list (Flows' saved-file options, a settings tick-row) is exactly the
   case that carve-out does not cover. */
input[type=checkbox],input[type=radio]{width:24px;height:24px;min-width:24px;
min-height:24px;margin:2px 8px 2px 0;vertical-align:middle}
/* The Poe picture-engine list (Settings > Linked accounts). A textarea with
   no cols renders about twenty characters wide, which would sit beside the
   API-key box looking like a mistake; a bot name is a line of text, so it
   gets a line's width. */
textarea.poe-engines{width:40%;min-width:240px;resize:vertical}
/* Placeholder text disappears the moment someone types, so it can never be
   the only name a box has: every box a stranger meets (sign in, set up your
   account, new password, invite someone) wears a real label above it, and
   .field-rule says the password rule out loud instead of leaving it to be
   discovered by refusal. */
label.field{display:block;margin:0 0 4px;font-size:0.75rem;font-weight:650;
text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.field-rule{margin:-4px 0 12px;font-size:0.8214rem;color:var(--muted)}
/* The desktop app's remembered emails on the sign-in page (client 0.1.41):
   one row each, the email to press and its small Forget beside it. */
ul.app-emails{list-style:none;margin:0 0 12px;padding:0}
/* The desktop app's update notice, first on Home (client 0.1.41). */
.app-update-card{border:1px solid var(--accent);border-radius:12px;
padding:12px 16px;margin:0 0 16px;background:var(--accent-soft)}
.app-update-card .app-update-head{font-weight:650;margin:0 0 4px}
ul.app-emails li{display:flex;align-items:center;gap:6px;margin:0 0 4px}
#app-savepw:not([hidden]){display:block;margin:0 0 6px}
button.app-email-forget{background:transparent;border:0;padding:4px 6px;
font-size:0.8214rem;color:var(--muted);text-decoration:underline;cursor:pointer}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);
box-shadow:0 0 0 3px var(--ring)}
/* A form error, beside its own field (ux1 slice 8, #24): the outline on the
   field, the icon and text in .field-error all say "wrong" on their own —
   never colour alone — and the value already typed stays in the box. */
input[aria-invalid='true'],select[aria-invalid='true'],
textarea[aria-invalid='true']{outline:2px solid var(--bad);
outline-offset:1px;border-color:var(--bad)}
.field-error{color:var(--bad);font-weight:600;display:flex;align-items:center;
gap:6px}
input[type=file]{border:1px dashed var(--line-strong);background:transparent;padding:6px 10px}
select{cursor:pointer}
/* ux1 slice 9, #17: a bare <summary> (no class, the plain disclosure
   triangle browsers draw for free) measured as short as 20px — every one
   of them a real interactive control. A class'd summary elsewhere in this
   sheet already sets its own height and is untouched by a min. */
summary{min-height:24px;padding:2px 0}
button{font:inherit;font-size:0.9286rem;font-weight:600;cursor:pointer;
background:var(--accent);color:var(--accent-ink);border:1px solid transparent;
border-radius:6px;padding:7px 14px;margin:2px 0;min-height:24px;
transition:background .15s,box-shadow .15s}
button:hover{background:var(--accent-hi)}
button:active{transform:translateY(1px)}
button:focus-visible{outline:none;box-shadow:0 0 0 3px var(--ring)}
button:disabled{opacity:.55;cursor:not-allowed}
td button,li button{background:transparent;color:var(--accent);
border-color:var(--line-strong);font-weight:550;font-size:0.8571rem;padding:3px 9px}
td button:hover,li button:hover{background:var(--accent-soft);
border-color:var(--accent)}
/* A run of checkbox+label pairs on one line (e.g. Flows' "Name each saved
   file with:") used to be joined by a single space, which crowds into an
   unreadable wall the moment it wraps on a narrow screen (owner screenshot,
   2026-08-29). Global so every page's tick-row gets the same breathing room
   without each one carrying its own copy of this rule. */
.tick-row{display:flex;flex-wrap:wrap;gap:8px 20px;align-items:center;
margin:8px 0}
.tick-row label{display:inline-flex;align-items:center;gap:5px;
white-space:nowrap}
dialog.pair-choice button{display:block;width:100%;margin-top:8px}
.st-ok,.st-warn,.st-wait{font-weight:600}
.st-ok{color:var(--ok)}.st-warn{color:var(--warn)}.st-wait{color:var(--muted)}
td.st-ok{background:var(--ok-bg)}td.st-warn{background:var(--warn-bg)}
td.st-wait{background:var(--bg-step)}
/* Login records (end-to-end run 2026-09-12): on a desk the time wrapped onto
   three lines. It stays on one. */
.audit-table td:first-child{white-space:nowrap}
tr:hover td.st-ok{background:var(--ok-bg)}
tr:hover td.st-warn{background:var(--warn-bg)}
tr:hover td.st-wait{background:var(--bg-step)}
li.st-ok,li.st-warn,li.st-wait,p.st-ok,p.st-wait{list-style:none;
width:fit-content;border-radius:999px;padding:2px 10px;margin:4px 0;
font-size:0.8929rem}
li.st-ok,p.st-ok{background:var(--ok-bg)}
li.st-warn{background:var(--warn-bg)}
li.st-wait,p.st-wait{background:var(--bg-step)}
.chat-who{font-size:0.75rem;font-weight:650;text-transform:uppercase;
letter-spacing:.07em;color:var(--muted);margin:18px 0 4px}
h3.chat-you{text-align:right}
/* 0.75rem is the FLOOR for body text here (2026-08-28 audit): below it the
   uppercase, letter-spaced badges and tags were under 9px on a phone at the
   root size, which is past what a customer can read at arm's length. */
.chat-who .chat-prov{display:inline-block;font-size:0.75rem;font-weight:650;
letter-spacing:.05em;color:var(--muted);background:var(--bg-step);
border:1px solid var(--line);border-radius:999px;padding:1px 7px;
margin-left:6px;vertical-align:1px}
.chat-msg{width:fit-content;max-width:min(68%,620px);margin:0 0 4px;
background:var(--card);border:1px solid var(--line);
border-radius:12px 12px 12px 4px;padding:8px 12px}
/* The ASSISTANT bubble gets the room a real answer needs (spec 2026-09-04):
   a long reply with headings, a table or a code block inside 68% of the
   column read as a ribbon. Only the assistant's — p.chat-you inherits
   .chat-msg and a short right-aligned question must stay short. */
.chat-msg.chat-assistant{max-width:min(92%,760px)}
p.chat-you{margin-left:auto;border-color:transparent;
background:var(--accent-tint);border-radius:12px 12px 4px 12px}
.chat-warn{display:none;width:100%;color:var(--bad);background:var(--bad-bg);
font-size:0.86rem;padding:6px 12px;border-radius:6px;margin:10px 0 6px}
.chat-warn.on{display:block}
/* THE RETRIEVAL-STATUS STRIP, and it is not an error. Same box as .chat-warn
   above, muted instead of red: everything that lands in it says which shelves
   were reachable for the last answer — the office PC is off, or it was busy,
   or its search broke — and an answer still came back every time. Painted red
   it greeted a new person as a fault they had caused (2026-09-05 staff
   walk-through) before they had asked anything at all.
   .chat-warn keeps the red for what is genuinely a warning: the one strip the
   home page raises about connections that have stopped working, which is a
   real errand. Its words are NOT quoted here — this sheet ships on every page,
   so a phrase written in a comment would turn up in a search of any of them
   (the same rule the cf lumn note gives). */
.chat-note{display:none;width:100%;color:var(--muted);background:var(--bg-step);
border:1px solid var(--line);font-size:0.86rem;padding:6px 12px;
border-radius:6px;margin:10px 0 6px}
.chat-note.on{display:block}
.chat-form{display:flex;flex-wrap:wrap;gap:8px;align-items:center;width:100%;
margin-top:20px;padding:8px;background:var(--card);border:1px solid var(--line);
border-radius:10px;box-shadow:var(--shadow)}
/* The composer stacks: the text box takes the WHOLE first row (owner ask
   2026-08-27 — the old shared row left the attach/model/Send controls
   floating in dead space beside a tall box), and the controls wrap onto
   their own row below it, Send pushed to the right. */
.chat-form textarea[name=question]{flex:1 1 100%;width:100%;margin:0;
border-color:transparent;background:var(--bg-step);resize:none;
max-height:140px;overflow-y:auto;line-height:1.45}
.chat-form select{margin:0;font-size:0.8571rem;color:var(--muted);
border-color:transparent;background:var(--bg-step)}
.chat-form button{margin:0 0 0 auto}
.chat-form input[type=file]{flex:0 1 auto;max-width:190px;margin:0;padding:2px;
font-size:0.8214rem;color:var(--muted);border-color:transparent;
background:transparent}
/* The two control labels ("Attach a document", "Answer using:") ride on the
   controls row as ordinary flex items — flex:0 0 auto so they never stretch,
   and they wrap with everything else on a narrow screen. They must NOT be
   label.field (display:block), which would break the row into pieces. */
.chat-form .chat-pick{flex:0 0 auto;margin:0;font-size:0.8214rem;
font-weight:600;color:var(--muted)}
/* THE ROUND + (spec 2026-09-04). It must NOT inherit .chat-form button's
   margin-left:auto, which is what pushes Send to the far right — the + is
   the first control on the row, not the last. */
.chat-form button.chat-plus{flex:0 0 auto;margin:0;width:32px;height:32px;
padding:0;font-size:1.25rem;line-height:1;font-weight:400;border-radius:50%}
/* The chosen file, as a chip with an x. */
.chat-file{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;
max-width:100%;font-size:0.8214rem;color:var(--ink);background:var(--bg-step);
border:1px solid var(--line);border-radius:999px;padding:3px 6px 3px 12px}
/* AND IT MUST ACTUALLY HIDE. The chip ships `hidden` and stays that way until
   a file is picked — but `display:inline-flex` above BEATS the browser's own
   [hidden]{display:none} (same specificity, and this rule comes later), so
   without this line an empty chip painted as a stray grey pill between the +
   and "Answer using:" (seen on staging 2026-09-04). Any rule that gives a
   hideable element a display needs its own [hidden] arm. */
.chat-file[hidden]{display:none}
.chat-file span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-form button.chat-chip-x{margin:0;padding:0;width:18px;height:18px;
font-size:0.9286rem;line-height:1;color:var(--muted);background:transparent;
border:0;border-radius:50%}
.chat-form button.chat-chip-x:hover{color:var(--bad);background:var(--bad-bg)}
/* "How to use this chat" — closed by default, a hairline row until opened. */
.chat-help{margin:0 0 12px;font-size:0.8929rem;color:var(--muted);
background:var(--bg-step);border:1px solid var(--line);border-radius:8px;
padding:6px 12px}
.chat-help summary{cursor:pointer;font-weight:600}
.chat-help ul{margin:8px 0 4px;padding-left:18px}
.chat-help li{margin:3px 0}
/* The empty thread's three one-liners: centred, unbulleted, quiet. */
.chat-tips{list-style:none;margin:0 0 14px;padding:0;font-size:0.8571rem}
.chat-tips li{margin:3px 0}
.chat-dl{margin:8px 0 0}
.chat-dl a{display:inline-block;font-size:0.8929rem;font-weight:600;
background:var(--accent-soft);border:1px solid var(--accent);
border-radius:999px;padding:4px 12px}
.chat-pic{display:block;max-width:100%;border-radius:8px;margin:6px 0 0}
.chat-msg p{margin:6px 0}
.chat-msg ul{margin:6px 0;padding-left:18px}
.chat-msg li{margin:2px 0}
.chat-msg p:first-child,.chat-msg ul:first-child{margin-top:0}
.chat-msg p:last-child,.chat-msg ul:last-child{margin-bottom:0}
.chat-msg code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
font-size:0.8571rem;background:var(--bg-step);border:1px solid var(--line);
border-radius:4px;padding:0 4px}
/* MARKDOWN INSIDE AN ANSWER (spec 2026-09-04). Headings are h4/h5/h6 so the
   page's own h1-h3 keep their meaning; they are sized down to sit INSIDE a
   bubble rather than compete with the panel's heading. */
.chat-msg h4,.chat-msg h5,.chat-msg h6{margin:12px 0 4px;line-height:1.3}
.chat-msg h4{font-size:1.0714rem}
.chat-msg h5{font-size:0.9643rem}
.chat-msg h6{font-size:0.8929rem;color:var(--muted)}
.chat-msg h4:first-child,.chat-msg h5:first-child,.chat-msg h6:first-child{
margin-top:0}
.chat-msg ol{margin:6px 0;padding-left:22px}
.chat-msg ol:first-child{margin-top:0}
.chat-msg ol:last-child{margin-bottom:0}
.chat-msg em{font-style:italic}
.chat-msg a{text-decoration:underline}
/* A fenced code block: monospace on a soft background, its own Copy button
   parked in the top right corner, and its OWN horizontal scroll so a long
   line widens nothing but itself. */
.chat-code{position:relative;margin:8px 0}
.chat-code pre{margin:0;overflow-x:auto;background:var(--bg-step);
border:1px solid var(--line);border-radius:8px;padding:10px 12px}
.chat-code code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
font-size:0.8571rem;background:transparent;border:0;padding:0;
white-space:pre;display:block}
.chat-code .chat-copy{position:absolute;top:6px;right:6px}
/* A simple pipe table. Scrolls inside its own box for the same reason the
   code block does. */
.chat-table{display:block;overflow-x:auto;width:auto;margin:8px 0;
border-collapse:collapse;font-size:0.9286rem}
.chat-table th,.chat-table td{border:1px solid var(--line);padding:4px 10px;
text-align:left}
.chat-table th{background:var(--bg-step);font-weight:650}
/* Copy, on an answer and on a code block. Quiet until it is wanted — this is
   a control beside the words, not a second voice in the conversation. */
button.chat-copy{margin:6px 0 0;padding:2px 10px;font-size:0.8214rem;
font-weight:600;color:var(--muted);background:transparent;
border:1px solid var(--line);border-radius:999px}
button.chat-copy:hover{color:var(--accent);border-color:var(--accent);
background:var(--accent-soft)}
.chat-sources{margin:8px 0 0}
/* The answer while it is written is plain text; without this its line breaks
   ran together until the finished turn replaced it (end-to-end run
   2026-09-12). */
.chat-live{white-space:pre-wrap}
a.chat-src{cursor:pointer;text-decoration:underline dotted}
#chat-reader{position:fixed;top:0;right:0;width:min(600px,92vw);height:100vh;
  background:var(--card,#fff);border-left:1px solid var(--line,#ccc);z-index:60;
  display:flex;flex-direction:column;box-shadow:-6px 0 18px rgba(0,0,0,.12)}
#chat-reader[hidden]{display:none}
.rd-bar{display:flex;justify-content:space-between;align-items:center;gap:.5rem;
  padding:.45rem .8rem;border-bottom:1px solid var(--line,#ccc)}
.rd-title{font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rd-close{font-size:1.2rem;line-height:1;padding:.1rem .5rem}
.rd-frame{flex:1 1 auto;width:100%;border:0}
.rd-wait{margin:.75rem;color:var(--muted)}
.chat-sources small{font-size:0.75rem;font-weight:650;text-transform:uppercase;
letter-spacing:.06em;margin-right:2px}
.chat-src{display:inline-block;font-size:0.8214rem;color:var(--muted);
background:var(--bg-step);border:1px solid var(--line);border-radius:999px;
padding:2px 9px;margin:2px 0 0 6px;max-width:100%;vertical-align:middle}
.chat-typing{display:inline-flex;gap:3px;align-items:center;height:1.2em}
.chat-typing i{width:5px;height:5px;border-radius:50%;background:var(--muted);
animation:chatdot 1.2s ease-in-out infinite}
.chat-typing i:nth-child(2){animation-delay:.2s}
.chat-typing i:nth-child(3){animation-delay:.4s}
@keyframes chatdot{0%,60%,100%{opacity:.25}30%{opacity:1}}
/* The MOVING "still working" bar shown while an answer is being prepared
   (2026-08-26 owner ask: a file search can take a moment and people needed to
   see it is working, not hung). A plain label plus an indeterminate bar that
   sweeps left-to-right forever until the answer replaces it — the sweep is the
   reassurance, so it must never look parked. Same shape as the pc-health
   progress bar, kept local to the chat.*/
.chat-working{display:flex;flex-direction:column;gap:6px;min-width:200px}
.chat-working .lbl{color:var(--muted);font-size:0.9286rem}
.chat-work-bar{height:6px;border-radius:3px;background:var(--bg-step);
overflow:hidden}
.chat-work-bar span{display:block;height:100%;width:38%;border-radius:3px;
background:var(--accent);animation:chatsweep 1.15s ease-in-out infinite}
@keyframes chatsweep{0%{margin-left:-40%}100%{margin-left:100%}}
.chat-empty{text-align:center;padding:44px 16px;color:var(--muted)}
.chat-empty .brand-mark{width:36px;height:33px}
.chat-empty-title{font-size:1.0714rem;font-weight:600;color:var(--ink);
margin:10px 0 2px}
.chat-empty-sub{font-size:0.8571rem;margin:0 0 12px}
.chat-empty-hints{display:flex;flex-wrap:wrap;gap:6px;justify-content:center}
button.chat-hint,button.chat-choice{background:transparent;color:var(--muted);
font-weight:500;font-size:0.8929rem;border:1px solid var(--line-strong);
border-radius:999px;padding:5px 12px;margin:0}
button.chat-hint:hover,button.chat-choice:hover{background:var(--accent-soft);
color:var(--accent);border-color:var(--accent)}
/* The "Which one?" name buttons under an answer (2026-09-12): the same chip
   look as the example questions, in a row under the sentence. */
.chat-choices{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 0}
/* AU1's "make this a flow?" line under a fill's reply: smaller than the
   reply and set under it (ds10 au1-chat-line). */
.chat-suggest{font-size:0.8571rem;color:var(--muted);border-top:1px solid
var(--line);margin:10px 0 0;padding-top:8px}
body.auth{display:flex;min-height:100vh;align-items:center;justify-content:center;
padding:20px}
body.auth .wrap{max-width:392px;width:100%;margin:0;padding:32px 28px;
background:var(--card);border:1px solid var(--line);border-radius:12px;
box-shadow:var(--shadow)}
/* display:block undoes the flex row .page-head gained for the settings gear:
   an auth card never has a gear (nobody is signed in), and its heading is
   centred, which a flex row would quietly stop doing. */
body.auth .page-head{border-bottom:0;padding-bottom:0;margin-bottom:16px;
text-align:center;display:block}
body.auth h1{font-size:1.2857rem}
body.auth form{display:block;margin:0}
/* Not the "Keep me signed in" tick box: it stays inline, beside its words
   (bug round 2026-09-12: as a full-width block it sat alone on its own line). */
body.auth input:not([type=checkbox]){display:block;width:100%;margin:0 0 12px}
body.auth button{display:block;width:100%;margin-top:4px}
body.shell{padding-left:230px}
/* grid, not a flex col: pages must stay free of the word "col·umn" — the jobs
   rule form dropped a dead field of that name and pins its absence page-wide */
.side{position:fixed;top:0;left:0;bottom:0;width:230px;display:grid;
grid-template-rows:auto 1fr auto;align-content:start;padding:16px 12px;
background:var(--card);border-right:1px solid var(--line);overflow-y:auto}
a.side-brand{display:block;font-size:1.0714rem;font-weight:650;
letter-spacing:-.01em;color:var(--ink);padding:4px 10px;margin:0 0 12px}
a.side-brand:hover{color:var(--ink);text-decoration:none}
.brand-line{display:flex;align-items:center;gap:7px;font-size:0.9643rem;
font-weight:600;letter-spacing:.04em;
font-family:Georgia,'Times New Roman',serif}
.brand-mark{flex:none}
.brand-co{display:block;font-size:0.8214rem;font-weight:500;color:var(--muted);
margin-top:2px}
.auth-brand{text-align:center;margin:0 0 16px}
.auth-brand .brand-mark{width:62px;height:56px}
.auth-brand-agents{font-family:Georgia,'Times New Roman',serif;font-size:1.5rem;
font-weight:600;letter-spacing:.34em;text-indent:.34em;color:var(--ink);
margin-top:6px}
.auth-brand-inc{font-size:0.7143rem;font-weight:600;letter-spacing:.3em;
text-indent:.3em;color:#b6913f;margin-top:3px;display:flex;align-items:center;
gap:10px;justify-content:center}
.auth-brand-inc::before,.auth-brand-inc::after{content:'';width:26px;height:1px;
background:#b6913f}
.auth-brand-tag{font-size:0.75rem;font-weight:600;letter-spacing:.28em;
text-indent:.28em;color:var(--muted);margin-top:5px}
.side-nav{display:grid;gap:2px;align-content:start}
.side-nav a{font-size:0.9286rem;font-weight:550;color:var(--muted);
padding:6px 10px;border-radius:6px}
/* Home and Chat: the two entries everyone lives in — bigger and bold so a
   first-timer spots them instantly. */
.side-top{display:grid;gap:2px;margin-bottom:6px}
.side-top a{font-size:1.1071rem;font-weight:700;color:var(--ink)}
.side-nav a:hover{color:var(--ink);background:var(--bg-step);
text-decoration:none}
.side-nav a[aria-current=page]{color:var(--accent);
background:var(--accent-soft);font-weight:600}
.side-nav a.side-child{padding-left:26px;font-size:0.8929rem}
/* Group headers wear the brand serif — the same Georgia stack the auth
   brand uses — small, uppercase and letterspaced for a small-caps feel.
   Color stays MUTED on purpose (semantic colors only); the serif and the
   spacing are the whole distinction. Each header is the <summary> of a
   native <details class='side-sec' open> block, so a group folds with no
   JavaScript; the default marker goes (list-style + the WebKit pseudo)
   because the header row is its own affordance. */
.side-group{font-family:Georgia,'Times New Roman',serif;font-size:0.8214rem;
font-weight:600;text-transform:uppercase;letter-spacing:.08em;
color:var(--muted);margin:14px 0 4px;padding:3px 10px;border-radius:6px}
details.side-sec{margin:0}
details.side-sec>summary.side-group{cursor:pointer;list-style:none;
user-select:none;display:flex;align-items:center;gap:6px}
details.side-sec>summary.side-group::-webkit-details-marker{display:none}
/* The fold affordance the owner asked for: a gold chevron that points right
   when the section is folded and rotates down when open — drawn in CSS so
   the no-JavaScript rule holds. */
details.side-sec>summary.side-group::before{content:'\25B8';color:#b6913f;
font-size:0.7143rem;transition:transform .15s ease;display:inline-block}
details.side-sec[open]>summary.side-group::before{transform:rotate(90deg)}
details.side-sec>summary.side-group:hover{color:var(--ink);
background:var(--bg-step)}
details.side-sec a{display:block}
.side-foot{align-self:end;padding:12px 10px 0;
border-top:1px solid var(--line)}
.side-foot .whoami{margin:0 0 4px}
/* THE ONE UPDATE BUTTON (0.1.87, the approved prototype): the foot's first
   block, above "Signed in as ...". The foot sits at the bottom of the
   sidebar's grid, so it grows UPWARD and the nav above does not move. Up to
   date is a quiet headline with a calm tick and a "Check again" link; Update
   ready is the one strong accent, a dot per part and one compact "Update";
   Updating is one plain status line per part with a turning ring (stopped by
   the reduced-motion rule above); a problem is a muted red panel with
   "Update" and "Ask us"; somebody's step at a computer a calm amber panel
   with "Try again". Targets are at least 36px high, focus is always drawn. */
.side-update{margin:0 0 10px;padding:0 0 10px;border-bottom:1px solid var(--line)}
.su-head{margin:0 0 7px;font-size:0.7143rem;font-weight:700;letter-spacing:.1em;
text-transform:uppercase;color:var(--muted)}
.su-headline{display:flex;align-items:center;gap:7px;margin:0;
font-size:0.9286rem;font-weight:650;line-height:1.3;color:var(--ink)}
.su-ver{margin-left:auto;font-size:0.7857rem;font-weight:500;color:var(--muted)}
.su-rows{margin:0 0 8px;display:grid;gap:5px}
.su-row{display:grid;grid-template-columns:15px minmax(0,1fr);gap:6px;
align-items:start;font-size:0.8214rem;line-height:1.35;color:var(--ink)}
.su-detail{display:block;margin-top:1px;color:var(--muted)}
.su-dot{width:6px;height:6px;margin:6px 0 0 4px;border-radius:50%;
background:var(--muted)}
.side-update[data-state=ready] .su-dot{background:var(--accent)}
.su-ico{width:15px;height:15px;flex:none;color:var(--muted)}
.su-tick{color:var(--ok)}
.su-spin{animation:su-turn .85s linear infinite}
@keyframes su-turn{to{transform:rotate(360deg)}}
.su-copy{margin:6px 0 0;font-size:0.7857rem;line-height:1.4;color:var(--muted)}
.side-update[data-state=ready] .su-copy{margin:0 0 7px}
.su-panel{margin:2px 0 0;padding:8px 9px;border:1px solid var(--line);
border-radius:7px;font-size:0.7857rem;line-height:1.4;color:var(--ink)}
.su-panel p{margin:0}
.su-panel p+p{margin-top:6px}
.su-panel+.su-panel{margin-top:6px}
.su-warn{background:var(--warn-bg)}
.su-bad{background:var(--bad-bg)}
.su-btn{width:100%;min-height:38px;display:flex;align-items:center;
justify-content:center;gap:7px;margin-top:8px;padding:7px 12px;
border:1px solid var(--line-strong);border-radius:7px;background:var(--bg-step);
color:var(--ink);font:inherit;font-size:0.8929rem;font-weight:650;
line-height:1.25;cursor:pointer}
.su-btn:hover{border-color:var(--ink)}
.su-btn.su-primary{background:var(--accent);border-color:var(--accent);
color:var(--accent-ink)}
.su-btn.su-primary:hover{background:var(--accent-hi);border-color:var(--accent-hi)}
.su-btn.su-small{width:auto;min-height:36px}
.su-btn:disabled{cursor:not-allowed;background:var(--bg-step);
border-color:var(--line);color:var(--muted)}
.su-actions{display:flex;align-items:center;gap:12px;margin-top:8px}
.su-actions .su-btn{margin-top:0}
.su-text{display:inline-flex;align-items:center;min-height:36px;margin-top:2px;
padding:0;border:0;background:transparent;font:inherit;font-size:0.8571rem;
color:var(--muted);text-decoration:underline;text-underline-offset:3px;
cursor:pointer}
.su-text:hover{color:var(--ink)}
.su-text:disabled{cursor:not-allowed;text-decoration:none}
.su-btn:focus-visible,.su-text:focus-visible{outline:3px solid var(--accent);
outline-offset:2px}
.su-said{margin:6px 0 0;font-size:0.7857rem;line-height:1.4;color:var(--ink)}
.su-said:empty{display:none}
/* /update's own lines, one per sentence of a part. */
.su-line{margin:6px 0 0;font-size:0.8571rem;line-height:1.4;color:var(--muted)}
.su-line.su-warn,.su-line.su-bad{padding:7px 9px;border:1px solid var(--line);
border-radius:7px;color:var(--ink)}
/* THE COMPANY ASSISTANT'S BOX, on Home (see _assistant_dot). Three colours
   and one sentence. The dot is a decorative span — the sentence is the
   link's accessible name — and it is drawn with its own colours rather than
   the theme's so green/orange/red mean the same thing under every company
   accent. align-items:baseline keeps the dot on the first line of a sentence
   that wraps. .pc-notice is the box itself, with the close button fix #1
   added; .pc-dot-line/.pc-dot are also used standalone by _dot in tests. */
.pc-notice{display:flex;align-items:baseline;justify-content:space-between;
gap:8px;padding:6px 12px;margin:10px 0 6px;border:1px solid var(--line);
border-radius:var(--radius)}
.pc-dot-line{margin:0}
.pc-dot{display:flex;gap:6px;align-items:baseline;
font-size:0.8571rem;font-weight:500;color:var(--muted);text-decoration:none}
a.pc-dot:hover .pc-dot-say{text-decoration:underline}
.pc-dot-mark{flex:0 0 auto;width:10px;height:10px;border-radius:50%;
background:#9aa0a6;transform:translateY(1px)}
.pc-dot-green .pc-dot-mark{background:#1f9254}
.pc-dot-orange .pc-dot-mark{background:#c97a12}
.pc-dot-red .pc-dot-mark{background:#c0392b}
.pc-notice-x{flex:0 0 auto;border:0;background:transparent;font-size:1.1rem;
line-height:1;cursor:pointer;color:var(--muted);padding:2px 4px}
.pc-notice-x:hover{color:var(--ink)}
.side-foot a{font-size:0.9286rem;font-weight:550}
.side-foot a[aria-current=page]{color:var(--accent);font-weight:650}
/* The phone Menu button (a checkbox and its label, see _sidebar) is not drawn
   on a desk, where the whole menu is always shown. */
.side-menu-t,.side-menu-btn,.side-home-phone{display:none}
.cards li{position:relative}
/* SIZES THAT LOOK LIKE SIZES (fx-home-cards, owner 2026-09-24: "selecting a
   size doesnt change it"). The cards used to be flex items that all GREW
   (flex:1 1 230px) while Wide was capped at 480px, so Wide came out about as
   wide as Medium and a Medium alone on its row wider than a Wide. A six-part
   grid instead: Small a third of the row, Medium half, Wide all of it — and
   on a phone Medium and Wide both take the row and Small half. */
.tiles.cards{display:grid;grid-template-columns:repeat(6,minmax(0,1fr))}
.tiles.cards>li{grid-column:span 3;max-width:none;min-width:0}
.tiles.cards>li.card-s{grid-column:span 2}
.tiles.cards>li.card-w{grid-column:1/-1}
@media (max-width:640px){.tiles.cards>li{grid-column:1/-1}
.tiles.cards>li.card-s{grid-column:span 3}}
.tiles li.card-s{padding:8px 12px}
a.card-link{display:block;color:var(--ink);margin:-12px -14px;
padding:12px 14px;border-radius:var(--radius)}
a.card-link:hover{background:var(--bg-step);color:var(--ink);
text-decoration:none}
.card-s a.card-link{margin:-8px -12px;padding:8px 12px}
.card-sub{display:block;color:var(--muted);font-size:0.8571rem;margin-top:2px}
.card-detail{display:block;margin-top:8px;padding-top:2px;
border-top:1px solid var(--line)}
.card-detail span{display:block;font-size:0.8571rem;color:var(--muted);
padding:3px 0;border-top:1px solid var(--line)}
.card-detail span:first-child{border-top:0}
.cards-head{display:flex;align-items:baseline;justify-content:space-between;
gap:8px}
.cards-head h2{margin-bottom:0}
.cards-head a{font-size:0.8571rem;color:var(--muted);padding:6px 4px;
display:inline-block;min-height:24px}
.cards-head a:hover{color:var(--accent)}
/* A refused card-layout POST, inline (ux1 slice 8, #24): the border AND
   the icon AND the words all say "wrong" on their own, so the sentence is
   never the only carrier of that meaning. */
.edit-error{display:flex;align-items:center;gap:8px;margin:8px 0;padding:8px 12px;
border:2px solid var(--bad);border-radius:var(--radius);
background:var(--bad-bg);color:var(--bad);font-weight:600}
.edit-error-icon{font-size:1.1em}
details.more-cards{margin:12px 0}
details.more-cards summary{cursor:pointer;font-size:0.8571rem;
color:var(--muted);padding:2px 0}
details.more-cards summary:hover{color:var(--ink)}
/* HOME, REBUILT (fx-111, design round 1 section 3): one state at the top
   with one primary button, four counts, and everything else under More. */
.hm-top{margin:0 0 18px}
.hm-state{color:var(--muted);margin:0 0 10px}
.hm-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}
.hm-card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
box-shadow:var(--shadow);padding:16px 18px}
.hm-card.hm-first{border-color:var(--accent)}
.hm-tag{display:inline-block;font-size:0.8571rem;font-weight:700;color:var(--warn);
background:var(--warn-bg);border-radius:999px;padding:2px 10px}
.hm-card h2{font-size:1.15rem;margin:10px 0 6px;text-transform:none;letter-spacing:normal;color:var(--ink)}
.hm-card p{margin:0 0 12px;color:var(--muted)}
.hm-go{display:inline-flex;align-items:center;min-height:44px;padding:8px 16px;
border-radius:var(--radius);border:1px solid var(--line-strong);color:var(--ink);
font-weight:650;text-decoration:none}
.hm-go.hm-primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.hm-go.hm-primary:hover{background:var(--accent-hi);border-color:var(--accent-hi)}
.hm-go:focus-visible,.hm-count:focus-visible,details.hm-more summary:focus-visible{
outline:3px solid var(--accent);outline-offset:2px}
.hm-counts{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin:0 0 6px;
padding:0;list-style:none}
.hm-counts li{margin:0}
.hm-count{display:block;height:100%;background:var(--card);border:1px solid var(--line);
border-radius:var(--radius);padding:12px 14px;color:var(--ink);text-decoration:none}
a.hm-count:hover{border-color:var(--accent)}
.hm-count b{display:block;font-size:1.5rem;font-variant-numeric:tabular-nums}
.hm-count span{color:var(--muted);font-size:0.8571rem}
.hm-private{color:var(--muted);font-size:0.8571rem;margin:0 0 14px}
details.hm-more{margin:6px 0 16px}
details.hm-more>summary{cursor:pointer;min-height:44px;display:flex;align-items:center;
color:var(--accent);font-weight:650;width:max-content}
.hm-group{margin:8px 0 0}
.hm-group h3{font-size:0.8571rem;color:var(--muted);margin:10px 0 4px}
@media(max-width:720px){.hm-counts{grid-template-columns:1fr 1fr}}
.panel{background:var(--card);border:1px solid var(--line);
border-radius:var(--radius);box-shadow:var(--shadow);padding:14px 16px;
margin:20px 0}
.panel-head{display:flex;align-items:baseline;justify-content:space-between;
gap:8px;margin-bottom:4px;padding-bottom:8px;border-bottom:1px solid var(--line)}
.panel-head h2{margin:0}
.panel-head a{font-size:0.8571rem;color:var(--muted)}
.panel-head a:hover{color:var(--accent)}
/* "Pop out" sits in a panel head beside the links, and wears the same
   muted-until-hover look — but it is a button, because it opens a window
   instead of navigating. */
.popout{font:inherit;font-size:0.8571rem;color:var(--muted);background:none;
border:0;padding:0;cursor:pointer}
.popout:hover{color:var(--accent)}
/* A destructive control (the chat page's delete) borrows the pop-out's quiet
   layout but
   wears the shared red token, so it never looks identical to a safe primary
   action — a subtle tint, not a big red block, and theme-aware in dark mode
   because it reuses --bad rather than a hardcoded hex. The :hover rule is
   needed to beat .popout:hover, which would otherwise repaint it accent-blue. */
.danger{color:var(--bad)}
.danger:hover{color:var(--bad);text-decoration:underline}
/* A FIXED height, never a max (owner ask 2026-08-28): with a max-height the
   box opened short and grew taller with every turn, so the composer below it
   walked down the screen as the conversation went on. Pinned to one height it
   scrolls inside itself from the very first message and nothing under it moves.
   Reversed flex stacking starts the scroll box at its bottom, so the newest
   chat turn is visible with no JavaScript; the single inner div keeps normal
   reading order. The keyword is spelled with a CSS hex escape (\6f = o) for
   the same reason the sidebar note above spells col·umn with a dot: pages
   must stay free of that word, and this stylesheet ships on every page. */
.chat-scroll{display:flex;flex-direction:c\6f lumn-reverse;overflow-y:auto;
height:50vh}
/* The standalone /chat page: the same panel, taller than the home panel's
   50vh of scroll, the conversation held to a centered reading measure, and
   the composer docked at the panel's foot behind a hairline that spans that
   same measure.
   The thread came DOWN from 70vh to 52vh on 2026-08-25: the composer below it
   grew to 560px, and the two together have to fit on a laptop screen. This is
   the half of "make the chatbox bigger" that the textarea attribute alone
   cannot deliver — without it the taller composer just pushes itself off the
   bottom of the window. */
/* THE PANEL FILLS THE WINDOW, and the composer is docked inside it (owner,
   staging screenshot 2026-09-04: "the text box is below the fold — I have to
   scroll the page to type, then scroll back to read"). The old fixed 52vh
   thread plus a 150px composer plus the page furniture came to more than a
   900px-tall window, so the composer fell off the bottom.
   The fix is the web-chat layout: give the PANEL a height tied to the window
   and let the thread — and only the thread — take whatever is left.
   The 150px is this page's own furniture above the panel, measured from the
   rules in this sheet at the 16px root size: .wrap's 24px top padding, the
   .page-head box (h1 at 1.4286rem x 1.6 = 36.6, + 4px + the .page-sub line at
   0.9286rem x 1.6 = 23.8, + 12px padding + 1px rule = 77.4), the 24px margin
   below it (the panel's own 20px collapses into it), and ~24px of air so the
   panel does not sit flush against the bottom of the window.
   dvh, with a vh line before it as the fallback a browser that does not know
   dvh keeps: on a phone the two differ by the address bar's height.
   min-height is the floor — on a very short window the page scrolls rather
   than crushing the composer, which is the failure this fixes.
   NOTHING SITS BELOW THE PANEL any more (2026-09-05): the kept-files list used
   to be a second panel under this one, so the page scrolled past the whole
   conversation to reach it. It is a closed fold at the foot of the rail now,
   which is why this page is one panel and one screen. Neither that list's old
   heading nor its new one is spelled out here: this sheet ships on every page,
   and a phrase quoted in a comment would show up in a search of the popped-out
   window, which does not carry the rail or the list at all (see the cf lumn
   note above for the same rule about a banned word). */
.chat-page{display:flex;flex-direction:c\6f lumn;
height:calc(100vh - 150px);height:calc(100dvh - 150px);min-height:420px}
/* Everything except the thread keeps its natural height: the head, the help
   fold, the offline warning, the composer and the note under it. flex:0 0 auto
   is what makes "the composer is always fully visible" true — without it every
   child shares the shortfall and the composer is the one that loses. */
.chat-page>*{flex:0 0 auto}
/* The thread is the ONE thing that gives. min-height:0 is load-bearing: a flex
   item defaults to min-height:auto, which refuses to shrink below its content
   and would push the composer back off the bottom. */
.chat-page .chat-scroll{flex:1 1 auto;height:auto;min-height:0}
/* THE PANEL IS AS WIDE AS THE SCREEN; THE READING IS NOT (2026-09-05, with
   the wide wrap above). It was max-width:100% back when the panel itself was
   capped at 960px and the width was somebody else's problem. Now that the
   panel runs to the edge of the screen, a line of an answer would run 1500px
   on a wide monitor, which nobody can read. 900px is the measure the
   conversation, the composer and the small print under it all share, centred
   in whatever room the panel has left after the rail. */
.chat-page .chat-scroll>div{max-width:900px;width:100%;margin:0 auto}
.chat-page .chat-empty{padding:64px 16px}
/* CENTRED ON THE SAME MEASURE as the conversation above it, and no longer
   stretched to the panel's edges by a negative margin: in a panel as wide as
   the screen that put a writing box a metre wide under a 900px conversation.
   932 = the 900px measure plus this rule's own 16px of padding on each side,
   because the sheet is border-box (see the reset at the top) — so the textarea
   inside it is 900px of content and the two columns line up exactly. The
   hairline above it now spans the composer rather than the panel, which is
   what makes the two read as one column. */
.chat-page .chat-form{width:100%;max-width:932px;margin:14px auto 0;
padding:12px 16px 2px;background:transparent;border:0;
border-top:1px solid var(--line);border-radius:0;box-shadow:none}
/* The offline note above the composer and the small print under it are its
   siblings, not its children, so without this they run the full width of the
   panel under a centred writing box — the same misshapen page, one line
   further down. Same measure, same centring. */
.chat-page .chat-main>.chat-note,.chat-page .chat-main>p{max-width:932px;margin-left:auto;margin-right:auto}
/* The full page gets a writing desk, not a slot: the composer starts at 8
   rows and may grow to ~23 (the page script reads the same cap from the
   textarea's data-cap, so CSS and script can never disagree on the limit).
   The home panel keeps its compact 2-row / 140px composer above.
   Grown twice on 2026-08-25 — the owner said it was still too small after the
   first pass, so the thread above it gave up the height (see .chat-scroll). */
/* SHORTER TO START, same room to grow (owner, 2026-09-04): the box opened at
   150px — six lines of empty white — and that height came straight out of the
   thread above it. Three lines to start (84px ~= 3 x the 1.45 line-height plus
   the padding and border, which is what rows="3" renders too, so the CSS and
   the markup agree). The 560px ceiling is untouched: the owner asked twice for
   room to write, and the panel above now yields its height to the box instead
   of pushing it off the screen. */
.chat-page .chat-form textarea[name=question]{max-height:560px;min-height:84px}
/* THE CONVERSATION RAIL (v58). The panel's lower half is two columns: the
   rail, which keeps its width, and the conversation, which takes the rest and
   is the only thing that scrolls. min-height:0 on both is load-bearing for the
   same reason it is on .chat-scroll above — a flex item that refuses to shrink
   below its content would push the composer off the bottom of the panel. */
.chat-page>.chat-body{flex:1 1 auto;min-height:0;display:flex;gap:16px}
.chat-main{flex:1 1 auto;min-width:0;min-height:0;
display:flex;flex-direction:c\6f lumn}
.chat-rail{flex:0 0 220px;min-width:0;overflow-y:auto;
border-right:1px solid var(--line);padding:6px 12px 0 0}
/* The rail is a <details> so that a phone can fold it away (the media query
   below), which is also why it has a summary at all. On a desk it is simply
   open, and the summary reads as the rail's heading. */
.chat-rail>summary{font-size:0.7857rem;letter-spacing:0.04em;
text-transform:uppercase;opacity:0.6;cursor:pointer;margin-bottom:8px}
.chat-rail .chat-new{width:100%;font-size:0.8571rem;padding:7px 10px}
.chat-rail form{margin:0}
.chat-convs{list-style:none;margin:10px 0 0;padding:0}
.chat-convs li{display:flex;align-items:center;gap:4px;border-radius:8px;
padding:2px 4px}
.chat-convs li.on{background:var(--accent-soft,rgba(0,0,0,0.05))}
.chat-convs li>a{flex:1 1 auto;min-width:0;display:block;padding:6px 4px;
text-decoration:none;color:inherit}
/* One line per name, cut with an ellipsis: a rail 220px wide that rewraps
   every time somebody asks a long question would move the whole list. */
.chat-conv-name{display:block;overflow:hidden;text-overflow:ellipsis;
white-space:nowrap;font-size:0.9286rem}
.chat-convs li small{display:block;opacity:0.55;font-size:0.7857rem}
.chat-conv-acts{display:flex;gap:2px;flex:0 0 auto}
.chat-conv-act{background:none;border:0;padding:2px 5px;cursor:pointer;
color:inherit;opacity:0.55;font-size:0.9286rem;text-decoration:none;
line-height:1}
.chat-conv-act:hover{opacity:1}
.chat-conv-rename{display:flex;gap:4px;align-items:center;width:100%}
.chat-conv-rename input{min-width:0;flex:1 1 auto;font-size:0.8571rem;
padding:4px 6px}
.chat-conv-rename button{font-size:0.7857rem;padding:4px 8px}
.chat-conv-rename a{font-size:0.7857rem;opacity:0.7}
/* THE KEPT FILES, at the foot of the rail under the conversations (moved here
   2026-09-05 — see the note on .chat-page). A <details> that starts CLOSED, the
   opposite of the rail around it: the rail is what you came to the page for and
   this is the answer to a question nobody has asked yet, so it is one line and
   one click. A rule above it, because it is a different kind of thing from the
   list it follows. Rows are stacked, not a table: the rail is 220px wide, and
   a table four cells across would have to scroll sideways before a Delete
   button was even reachable.
   The list's own words are NOT quoted here, for the reason the .chat-page note
   above gives. */
.chat-docs{margin-top:14px;border-top:1px solid var(--line);padding-top:10px}
.chat-docs>summary{font-size:0.7857rem;letter-spacing:0.04em;
text-transform:uppercase;opacity:0.6;cursor:pointer}
.chat-docs p{font-size:0.7857rem;opacity:0.7;margin:8px 0 0}
.chat-docs-list{list-style:none;margin:8px 0 0;padding:0}
.chat-docs-list li{margin:0 0 12px}
/* One line per name, cut with an ellipsis, the same rule the conversation
   names follow above: a rail this narrow must not rewrap when somebody keeps
   a file with a long name. The full name is on the row's title. */
.chat-doc-name{display:block;overflow:hidden;text-overflow:ellipsis;
white-space:nowrap;font-size:0.9286rem}
.chat-docs-list small{display:block;opacity:0.55;font-size:0.7857rem}
.chat-doc-acts{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px}
.chat-doc-acts form{margin:0}
.chat-doc-acts button{margin:0;font-size:0.7857rem;padding:4px 8px}
/* Below 760px there is no room for two columns, so the rail stops being one:
   it becomes a full-width fold above the conversation — the "dropdown" a
   phone wants — and the person taps its summary to get the list.
   TWO ROWS, not a block (2026-09-05): it was display:block and the whole body
   scrolled, which took the composer out of the panel's foot and put it at the
   bottom of the content. Stacked as a flex box instead, the rail keeps its
   natural height at the top and the conversation takes everything left, so
   .chat-main's thread is still the one thing that gives and its composer is
   still docked — the same arrangement the desk gets, turned on its side. */
/* The Board (docs/superpowers/specs/2026-09-12-kanban-design.md): columns
   side by side that scroll sideways on a desk; a card is one framed article
   whose due date turns red when overdue and amber when due within two days
   (the article's class carries the state so the list rows share the rule).
   The phone list is hidden here and shown by the 760px block BELOW —
   these rules must come first or, at equal specificity, they would win. */
/* The board picker's own rules went with it on 2026-09-13: switching board
   and making one live in the board menu now, which wears .board-menu. */
.board-filter{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:0 0 12px;font-size:.9rem}
.board-filter select{width:auto}
/* Rebuilt 2026-09-13 (docs/superpowers/specs/2026-09-13-board-redesign.md,
   sections 3 and 4): the header carries the board's name, its people and one
   menu; every column is a full-height lane (align-items:stretch, not
   flex-start — a shrink-wrapped box made the board ragged) whose name is a
   button you rename in place; and .board-cols is the ONLY thing on the page
   that scrolls sideways. */
.board-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 12px}
.board-name{flex:0 0 auto;margin:0;font-size:1.35rem;line-height:1.2}
.board-members{flex:0 0 auto;display:flex;gap:4px;list-style:none;margin:0;padding:0}
.board-search{flex:0 0 auto;margin:0;display:flex;align-items:center}
.board-search input{width:160px;max-width:100%;margin:0;border:1px solid var(--line-strong);border-radius:6px;padding:4px 8px;font-size:0.8571rem;background:var(--card);color:inherit}
.board-act{margin-left:0;font-size:0.8571rem;font-weight:550;background:transparent;color:var(--accent);border:1px solid var(--line-strong);border-radius:6px;padding:4px 10px;text-decoration:none}
.board-act:hover{background:var(--accent-soft);border-color:var(--accent)}
.board-menu{margin-left:auto}
.board-menu>summary{list-style:none;cursor:pointer;padding:4px 10px;border-radius:6px;color:var(--muted);font-size:1.15rem;line-height:1}
.board-menu>summary::-webkit-details-marker{display:none}
.board-menu>summary:hover{background:var(--accent-tint);color:var(--accent)}
.board-menu ul{list-style:none;margin:4px 0 0;padding:8px;border:1px solid var(--line);border-radius:var(--radius);background:var(--card);box-shadow:var(--shadow)}
.board-menu li{margin:2px 0}
.board-menu a,.board-menu button{display:block;width:100%;text-align:left;background:transparent;border:0;color:inherit;text-decoration:none;padding:4px 6px;border-radius:4px;font-size:0.9286rem}
.board-menu a:hover,.board-menu button:hover{background:var(--bg-step)}
.board-menu form{margin:0;display:flex;gap:6px}
.board-cols{display:flex;gap:12px;overflow-x:auto;align-items:stretch;padding-bottom:8px;min-height:calc(100vh - 260px);scroll-snap-type:none}
.board-col{flex:0 0 272px;display:flex;flex-direction:column;background:var(--bg-step);border:1px solid var(--line);border-radius:var(--radius);padding:8px}
.board-col-cards{flex:1 1 auto;min-height:40px;list-style:none;margin:0;padding:0}
.board-col-head{display:flex;align-items:center;gap:6px;margin:0 0 8px;font-size:0.9286rem;cursor:grab}
.board-col-name{flex:1 1 auto;text-align:left;background:transparent;color:var(--ink);border:0;padding:3px 4px;font-size:1rem;font-weight:650;border-radius:4px}
.board-col-name:hover{background:var(--card)}
.board-col-head input{flex:1 1 auto;min-width:0;margin:0;font-weight:650}
.board-col-head form{display:flex;flex:1 1 auto;min-width:0;gap:4px;margin:0}
.board-count{font-weight:400;color:var(--muted);font-variant-numeric:tabular-nums}
/* The "of 2" the count grows while a filter is on is the count's only
   child, which is how it is styled: naming its class here would put the
   word in the sheet, and the board's own test proves the plain count by
   the class being absent from an unfiltered page. */
.board-count>span{font-size:.85rem}
.board-col.board-over{outline:2px dashed var(--accent);outline-offset:-2px}
.board-col-menu>summary{list-style:none;cursor:pointer;color:var(--muted);
padding:0 6px;min-width:24px;text-align:center}
.board-col-menu>summary::-webkit-details-marker{display:none}
.board-col-menu ul{list-style:none;margin:4px 0 0;padding:6px;border:1px solid var(--line);border-radius:var(--radius);background:var(--card);box-shadow:var(--shadow);font-weight:400}
.board-col-menu a,.board-col-menu button{display:block;width:100%;text-align:left;background:transparent;border:0;color:inherit;text-decoration:none;padding:3px 6px;border-radius:4px;font-size:0.8571rem}
.board-col-menu form{margin:0}
.board-col-empty{color:var(--muted);margin:4px 6px;font-size:0.8571rem}
.board-search-empty{color:var(--muted);margin:4px 6px;font-size:0.8571rem}
.board-empty{color:var(--muted);margin:0 0 12px}
.board-card{background:var(--card);border:1px solid var(--line);border-radius:6px;padding:8px 10px;margin:0 0 8px;box-shadow:var(--shadow);cursor:grab}
.board-card:focus-visible{outline:none;box-shadow:0 0 0 3px var(--ring)}
.board-card.dragging{opacity:.5}
.board-card.board-lifted{box-shadow:0 0 0 3px var(--ring);cursor:grabbing}
.board-title{display:block;text-decoration:none;color:inherit;font-weight:600;
line-height:1.35;min-height:24px}
/* The description's first lines under the title (the owner, 2026-09-14).
   The server already cut it to ~120 characters at a word; the clamp is what
   keeps a card the same height whatever those characters are — two lines on
   a desk, one on a phone (see the 640px block). Muted and lighter than the
   title on purpose: the title is still what you read first.
   Its own margin, because a <p> inside a card would otherwise take the
   browser's default 1em top AND bottom and push every chip down. */
.board-preview{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
overflow:hidden;overflow-wrap:anywhere;margin:4px 0 0;color:var(--muted);
font-size:.85rem;font-weight:400;line-height:1.35}
.board-meta{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:6px;font-size:.85rem;color:var(--muted)}
.board-meta:empty{display:none}
.board-label{display:inline-block;width:auto;height:auto;padding:1px 8px;border-radius:999px;font-size:.75rem;font-weight:600;line-height:1.5}
.board-initials{display:inline-block;min-width:22px;padding:0 4px;border-radius:11px;background:var(--line);color:var(--ink);text-align:center;font-size:.75rem;line-height:22px}
/* Card sharing (spec 2026-09-14): whose card this is, when it is not
   yours, and the lane the ones with no column of their own wait in. The
   badge is quiet on purpose — it names an owner, it is not a warning. */
.board-from{display:inline-block;padding:1px 8px;border-radius:999px;background:var(--line);color:var(--muted);font-size:.72rem;font-style:italic}
.board-lane .board-col-head{color:var(--muted)}
.board-lane{border-style:dashed}
.board-card.overdue .board-due{color:var(--bad);font-weight:700}
.board-card.soon    .board-due{color:var(--warn);font-weight:650}
.board-card.done    .board-due{color:var(--ok);font-weight:550}
.board-drop{height:4px;margin:0 0 8px;border-radius:2px;background:var(--accent);opacity:.7}
/* The column composer is a block (spec 3.4) — the card title is one line
   with Add card under it. Scoped to the lanes on purpose: the card page
   reuses .board-add for its one-line checklist and attach forms, and those
   stay the inline row they have always been until step B rebuilds them. */
.board-add{display:flex;gap:6px;margin-top:4px}
.board-add input{flex:1 1 auto;min-width:0}
.board-cols .board-add{display:block;margin:0 0 8px;padding:0;max-width:none}
.board-add-open{width:100%;text-align:left;background:transparent;color:var(--muted);border:0;font-weight:550;padding:7px 8px;border-radius:6px}
.board-add-open:hover{background:var(--card);color:var(--ink)}
.board-add-box{display:flex;flex-wrap:wrap;gap:6px}
/* A class that sets display BEATS the browser's own [hidden]{display:none},
   so the script's box.hidden=true did nothing and both of these stood open
   at every width (measured 2026-09-13 at 375x667: 110px of composer under
   every column and 61px of filter strip above the lane). Spec 3.4 and 3.6
   both say folded until asked for, which is what these two rules make true.
   The card panel already carried its own for the same reason. */
.board-add-box[hidden],.board-filterbar[hidden]{display:none}
.board-add-box input{flex:1 1 auto;min-width:0}
/* THE CARD COMPOSER (2026-09-14, "it doesn't look easy to use"). Scoped to
   .board-col so the checklist, attach, move, people and + Add a column forms
   — which all wear .board-add too — keep the inline row they have.
   One line, one button: the title input takes a whole row of its own
   (flex-basis 100% forces the wrap), `Add card` and the × sit under it. 44px
   is the touch target a phone needs, and it is the same 44 on the desk so
   the control does not change shape between the two. */
.board-col .board-add-open{display:flex;align-items:center;min-height:44px}
/* …and the same trap the box fell into: a class that sets display BEATS the
   browser's own [hidden]{display:none}, so without this the opener stands
   there next to the open composer it was supposed to have become. */
.board-col .board-add-open[hidden]{display:none}
.board-col .board-add-open:focus-visible{background:var(--card);color:var(--ink)}
.board-col .board-add-box{align-items:center}
.board-col .board-add-box input[name='title']{flex:1 1 100%;min-height:44px}
.board-col .board-add-box button{min-height:44px}
/* The × is not a second Add: transparent until you reach for it, so exactly
   one thing in the open composer looks pressable. */
.board-col .board-add-cancel{background:transparent;color:var(--muted);border:0;
font-size:1.15rem;line-height:1;padding:0 12px}
.board-col .board-add-cancel:hover{background:var(--card);color:var(--ink)}
/* Where the card went: it lands at the END of the lane (the server's rule),
   which may be off the bottom of the screen, so it flashes for a second. */
.board-card.board-card-new{animation:board-card-in 1.1s ease-out}
@keyframes board-card-in{from{box-shadow:0 0 0 3px var(--ring)}to{box-shadow:var(--shadow)}}
@media (prefers-reduced-motion:reduce){
.board-card.board-card-new{animation:none;box-shadow:0 0 0 3px var(--ring)}}
/* The add-a-column form is the one direct child of .board-cols that is not
   a lane, which is how it is styled — naming it here would put its class in
   the sheet, and the board page's own test reads "where does this class
   first appear" to prove the form is the LAST thing in the lane row. */
.board-cols>form{flex:0 0 272px;align-self:flex-start}
.board-filterbar{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:0 0 12px;font-size:.9rem}
.board-filterbar select{width:auto}
.board-filter-said{flex:1 1 100%;margin:0;color:var(--muted)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* ds8 S2: a Home card's three sizes, each its own save. */
.size-seg{display:inline-flex;gap:4px;border:0;margin:0;padding:0;min-width:0}
.size-seg button[aria-pressed=true]{color:var(--accent);background:var(--accent-soft);border-color:var(--accent)}
/* THE PHONE TABS (Board spec section 7, 2026-09-13). In the markup at every
   width and shown only below 640px, so the server draws ONE board and never
   two. The rules for the flat "My cards" list that stood here are deleted
   with it: on a phone the board is now the board. */
.board-tabs{display:none}
.board-tabs ul{display:flex;gap:4px;overflow-x:auto;list-style:none;margin:0 0 6px;padding:0}
.board-tabs a{display:block;white-space:nowrap;padding:6px 10px;border-radius:999px;text-decoration:none;color:var(--muted);font-size:0.8571rem;font-weight:600}
.board-tabs a[aria-selected='true']{background:var(--accent-soft);color:var(--accent)}
.board-tab-count{font-weight:400;font-variant-numeric:tabular-nums}
.board-dots{display:none;margin:0 0 8px;text-align:center;color:var(--muted);letter-spacing:3px;font-size:.7rem}
/* THE SHORTCUT SHEET (spec 5.2). A <dialog>, so the browser gives it the
   backdrop, the focus trap and Escape; only its width and its table need
   saying here. */
.board-sheet{max-width:min(640px,92vw);border:1px solid var(--line);border-radius:var(--radius);background:var(--card);color:var(--ink);padding:16px 18px}
.board-sheet h2{font-size:1.15rem;margin:0 0 10px}
.board-sheet table{width:100%;border-collapse:collapse;font-size:0.8571rem}
.board-sheet th,.board-sheet td{text-align:left;vertical-align:top;padding:4px 8px 4px 0;border-bottom:1px solid var(--line)}
.board-sheet tbody th{white-space:nowrap;font-weight:600}
/* THE LONG-PRESS MOVE BAR (spec 5.3). A swipe is never an acceptable
   substitute for a drag, so a touch lift gets real buttons. */
.board-archived{margin-top:12px}
/* THE CHAT BAR AT THE FOOT OF THE BOARD (slice 2 of the ux1-intuitive spec,
   and ChatGPT's verified mock-up docs/design/2026-09-22-chat-bar-on-board).
   IN NORMAL FLOW, never fixed and never an overlay: it sits under the lanes,
   full width of the content column, so it can cover no card and take nothing
   away from the phone header row (which has 6.6px of slack and nothing to
   give). Quiet enough that the cards are still what the eye lands on. */
.board-chat{margin:18px 0 0;padding:14px 0 0;border-top:1px solid var(--line)}
.board-chat-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 8px}
.board-chat-head label{font-weight:650}
.board-chat-key{color:var(--muted);font-size:0.8571rem}
.board-chat-key kbd{font-family:inherit;border:1px solid var(--line);background:var(--card);border-radius:4px;padding:1px 6px;margin:0 2px}
.board-chat-reply:empty{display:none}
.board-chat-reply{margin:0 0 12px}
.board-chat-hints{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.board-chat-choices{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:8px}
.board-chat-choices form{margin:0}
.board-chat-help{margin:8px 0 0;color:var(--muted)}
/* ON A PHONE the bar is ONE LINE and grows when it is being used (spec
   slice 3: "it starts collapsed to one line and grows on focus"). It is
   still DOCKED at the foot of the content and never fixed over it, so the
   phone height budgets the board keeps (tests/test_board_headless.py) are
   untouched — the bar is below the work, not on top of it. :focus-within
   and not a script, so a phone with no JavaScript gets the same bar. */
@media (max-width:760px){
.board-chat{margin:12px 0 0;padding:10px 0 0}
.board-chat textarea[name=question]{min-height:40px;max-height:40px;transition:max-height .15s ease}
.board-chat:focus-within textarea[name=question]{max-height:160px}
.board-chat-hints,.board-chat-help{display:none}
.board-chat:focus-within .board-chat-hints{display:flex}
.board-chat:focus-within .board-chat-help{display:block}
}
/* THE CARD PANEL (Board spec 6.1 and 6.3, 2026-09-13). A card opens BESIDE
   the board instead of replacing it, so the panel is fixed to the right
   edge with its own scroll and the lanes behind it stay where they were.
   It is hidden until the script fills it, and hidden again when it closes —
   the element itself never leaves the page, so focus has somewhere to come
   back from. !important because .card-panel sets its own display. */
.card-panel{position:fixed;top:0;right:0;bottom:0;width:480px;max-width:100vw;background:var(--card);border-left:1px solid var(--line);box-shadow:-8px 0 24px rgba(16,24,40,.08);overflow-y:auto;padding:16px 18px 40px;z-index:40}
.card-panel[hidden]{display:none!important}
.card-panel-head{display:flex;align-items:flex-start;gap:8px;margin:0 0 12px}
.card-panel-close{margin-left:auto;background:transparent;color:var(--muted);border:0;font-size:1.3rem;line-height:1;padding:2px 8px}
.card-panel-close:hover{color:var(--ink)}
.card-panel-where{font-size:.8214rem;color:var(--muted);margin:0 0 4px}
/* A heading, not the page's <h1> and not a form label (finding 19): the
   board behind the panel keeps its own name at the top of the document. */
.card-panel-title{font-size:1.15rem;font-weight:650;margin:0 0 6px}
.card-panel h3{font-size:.9286rem;margin:18px 0 4px}
.card-panel-form{margin:0}
.card-panel-warn{display:none;color:var(--bad);background:var(--bad-bg);border-radius:6px;padding:6px 8px;margin:0 0 8px}
.card-panel-warn.on{display:block}
.card-panel-foot{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:18px 0 2px;color:var(--muted)}
.card-panel-foot form{display:inline-flex;gap:4px;align-items:center;margin:0}
.card-panel-foot select{width:auto}
/* Archive asks nothing, so the red only appears under the pointer: it is
   reversible from the board menu's Archived list, which is what makes the
   quiet treatment honest rather than careless. */
.card-panel-foot form:last-child button:hover{color:var(--bad);background:var(--bad-bg)}
/* People are chips: the person and the × that removes them are ONE element
   with nothing between them, and the list wraps BETWEEN chips, never
   inside one (finding 11). */
.card-people{list-style:none;display:flex;flex-wrap:wrap;gap:6px;margin:4px 0 0;padding:0}
.card-person{display:inline-flex;align-items:center;gap:5px;background:var(--bg-step);border:1px solid var(--line);border-radius:999px;padding:2px 4px 2px 3px;font-size:.8571rem}
.card-person form{display:inline;margin:0}
.card-person-none{color:var(--muted)}
.card-person-x{background:transparent;color:var(--muted);border:0;padding:0 5px;font-size:1rem;line-height:1}
.card-person-x:hover{color:var(--bad);background:var(--bad-bg);border-radius:999px}
.card-person-add{margin:8px 0 0;font-size:.9rem}
.card-person-add select{width:auto}
/* The checklist says how far along it is at a glance, and a ticked line
   stays readable but plainly done (spec 6.2). */
.card-check-bar{display:inline-block;vertical-align:middle;width:120px;height:6px;border-radius:3px;background:var(--bg-step);overflow:hidden;margin-right:8px}
.card-check-bar>span{display:block;height:100%;background:var(--accent)}
.card-check-count{font-size:.8571rem;color:var(--muted)}
.card-checklist li.done .card-check-text{text-decoration:line-through;color:var(--muted)}
.card-check-add{display:flex;gap:6px;margin-top:6px}
.card-check-add input,.card-check-add select{flex:1 1 auto;min-width:0}
.card-comments,.card-activity{list-style:none;margin:4px 0 0;padding:0}
.card-comments>li{margin:0 0 10px}
.card-comments p{margin:2px 0 0}
.card-activity>li{color:var(--muted);font-size:.8571rem;margin:0 0 2px}
.card-comment{margin:10px 0 0}
.card-comment textarea{width:100%;margin:0 0 6px;resize:vertical}
/* The @ menu the script positions under the caret has no markup on the
   server; the rule is here so step B's script has somewhere to put it. */
.card-mention-menu{position:absolute;z-index:50;list-style:none;margin:0;padding:4px;background:var(--card);border:1px solid var(--line);border-radius:8px;box-shadow:0 6px 18px rgba(16,24,40,.12)}
/* Two lines per person: the name to recognise, the address to be sure it is
   the right Raj. The row is a pointer target as well as a keyboard one, so
   hover and the picked row look the same. */
.card-mention-menu li{padding:6px 10px;border-radius:6px;cursor:pointer;line-height:1.3}
.card-mention-menu .mention-name{display:block;color:var(--ink)}
.card-mention-menu .mention-email{display:block;font-size:.8571rem;color:var(--muted)}
.card-mention-menu li:hover,.card-mention-menu li.on{background:var(--bg-step)}
/* 44px of thumb on a phone (WCAG 2.5.8), where the pointer is not a mouse. */
@media (max-width:640px){.card-mention-menu li{min-height:44px;padding:8px 12px}}
/* A phone has no room beside anything: the panel is the whole screen. */
@media (max-width:640px){.card-panel{width:100vw;border-left:0}}
@media (max-width:760px){
  .chat-page>.chat-body{display:flex;flex-direction:c\6f lumn;
  overflow-y:visible}
  /* flex:0 0 auto: the rail keeps its own height, capped by max-height
     below, and scrolls its list inside that — a quarter of the screen at
     most. It was flex:0 1 auto so it might SHRINK for the thread, but it
     shrank more the longer the conversation got (round 3, 2026-09-12: five
     questions in, at 375x667 the OPEN list was 35px with no conversation in
     sight, and the folded one cut its own label in half). So while the list
     is open the thread is the part that gives — the person is choosing a
     conversation, not reading one — and folded the list is one line (see
     .chat-rail:not([open]) at the foot of this block). */
  /* overflow-y:auto, not visible (end-to-end run 2026-09-12): a rail that
     may shrink but not clip drew its times, pencils and the kept-files
     heading over the answer and the box at 375px. Now whatever does not fit
     in at most 40% of the screen scrolls inside the rail itself. */
  .chat-rail{flex:0 0 auto;min-height:0;border-right:0;
  border-bottom:1px solid var(--line);
  padding:0 0 8px;margin-bottom:10px;max-height:40vh;overflow-y:auto}
  .chat-convs{max-height:25vh;overflow-y:auto}
  /* And the kept-files fold under it, for the same reason: opened on a phone
     an unbounded list would take the conversation's room. It scrolls its own
     quarter-screen instead. */
  .chat-docs-list{max-height:25vh;overflow-y:auto}
  /* The box on a phone (2026-09-12): no 84px floor, so the two rows the
     page script asks for are what it opens at, and a ceiling of 30% of the
     screen instead of the desk's 560px, so a long message scrolls inside
     the box rather than pushing it off the bottom of a 667px screen. The
     script still grows it towards data-cap; max-height wins over that. */
  .chat-page .chat-form textarea[name=question]{min-height:0;max-height:30vh}
  /* And the pieces round the box give back what they can (2026-09-12, the
     same fix): with the list folded and the box at two rows the thread was
     still only 109px at 375x667. No gap under the folded list — it has its
     own margin and rule. No side padding on the form: on a desk it lines
     the box up with the 900px conversation, but here the note and the small
     print already run the full width, and without it Send fits on the
     controls row instead of taking a row of its own. The grey note and the
     small print sit tighter. Measured together: 159px of thread, with the
     box and everything under it inside the panel. */
  .chat-page>.chat-body{gap:0}
  .chat-page .chat-form{margin-top:8px;padding:8px 0 2px}
  .chat-page .chat-main>.chat-note{margin:6px 0 0;padding:4px 8px;line-height:1.35}
  /* The small print's lines follow its own 12px text, not the 14px page
     text round it (rework 2026-09-12): each line was 19px for 12px words,
     and a staff member's Poe-key line ("Ask your admin…") wraps once more
     than the owner's, which left staff 141px of thread at 375x667. Now 15px
     a line: staff 156px, the owner 170px. */
  .chat-page .chat-main>p{margin:4px 0 0;line-height:1.25;font-size:0.8571rem}
  /* Folded, the list is its summary line and its rule (round 3,
     2026-09-12). The 8px under the summary and the list's own 8px padding
     and 10px margin space an OPEN list from its new-conversation button
     and from the thread; kept while folded, and with the list no longer
     shrinking, those 26px came straight out of the thread. */
  .chat-rail:not([open]){padding-bottom:0;margin-bottom:0}
  .chat-rail:not([open])>summary{margin-bottom:0}
}
/* The full page's panel head carries the delete and pop-out controls — the
   page heading already says Chat — so they sit at the right edge. Their words
   are NOT spelled out here, the same rule the note above the chat page's own
   block gives: this sheet ships on every page, so a phrase quoted in a comment
   would show up in a search of the popped-out window, which does not carry
   those controls at all. */
.chat-page .panel-head{justify-content:flex-end;gap:14px}
/* It keeps the pop-out's quiet LAYOUT but wears the danger tint, so a
   destructive control does not read as identical to the safe ones; the click
   still only opens a confirmation page and removes nothing by itself. */
.panel-head form{display:inline;margin:0}
.panel-head .popout{font:inherit;font-size:0.8571rem}
/* The popped-out chat: a small window doing one job, so no sidebar and no
   page furniture beyond the heading — the conversation gets the room. */
body.popup .wrap{max-width:none;padding:14px 14px 20px}
body.popup .panel{margin:10px 0 0}
/* The popped-out window carries less furniture than the workspace page — 14px
   of wrap padding instead of 24, and no documents list below it — so
   it gets its own, smaller offset. Same .page-head above it (the popup window
   keeps its heading and the company line), same 24px margin under it. */
body.popup .chat-page{height:calc(100vh - 130px);height:calc(100dvh - 130px)}
@media(max-width:760px){
body.shell{padding-left:0}
/* THE PANEL FILLS A PHONE SCREEN TOO (staff walk-through 2026-09-05, on a
   390x844 phone: the chat box started 1330px down a 2651px page, so you
   scrolled past the whole thread to type and back up to read the answer).
   It used to go back to a flowing layout with a fixed 52vh thread here, and
   that is what stacked into a page three screens tall.
   Same shape as the desk rule above, with this breakpoint's own furniture in
   the offset. 1rem is 14px at this width — the clamp on html bottoms out
   there — so these are real pixels: .wrap's 16px top padding, the .page-head
   box (h1 at 1.2857rem x 1.6 = 28.8, + 4px + the .page-sub line at 0.9286rem
   x 1.6 = 20.8, + 12px padding + 1px rule = 66.6), the 24px margin below it
   (the panel's own 20px collapses into it) and ~24px of air. 130px.
   WHAT IS NOT IN THAT NUMBER, and cannot honestly be: the nav. Below this
   breakpoint .side stops being fixed and becomes a bar ABOVE the page, in
   flow, and its height depends on how many modules the company has switched
   on. It scrolls away; the panel under it is one screen tall with the thread
   scrolling inside it and the composer docked at its foot, which is the part
   that was broken. Nothing is below the panel here either — the kept-files
   list is a fold inside the rail at every width.
   display and flex-direction are inherited from the .chat-page rule above —
   only the height changes here. */
.chat-page{height:calc(100vh - 130px);height:calc(100dvh - 130px)}
.side{position:static;width:auto;display:flex;flex-wrap:wrap;
align-items:center;gap:2px;padding:8px 12px;border-right:0;
border-bottom:1px solid var(--line)}
a.side-brand{margin:0 8px 0 0;padding:4px 6px}
/* The nav STACKS on a phone: wrapping it into rows scrambled Home/Chat/Work/
   Company into an unreadable order. width:100% drops the whole nav onto its own
   line under the brand, and block groups let each link (display:block) read
   top-to-bottom. display:block, not the direction keyword, keeps this
   ships-on-every-page sheet free of that forbidden word (see .chat-scroll). */
/* FOLDED behind the Menu button (end-to-end run 2026-09-12): the nav and the
   foot show only once its box is ticked. The box is invisible but still
   focusable, and its focus ring is drawn on the label. */
.side-menu-t{display:block;position:absolute;width:1px;height:1px;opacity:0;
margin:0;pointer-events:none}
.side-menu-btn{display:inline-block;margin-left:auto;padding:6px 12px;
border:1px solid var(--line);border-radius:6px;font-weight:600;
color:var(--ink);cursor:pointer;user-select:none}
.side-menu-t:focus-visible+.side-menu-btn{outline:2px solid var(--accent);
outline-offset:2px}
.side-menu-t:checked+.side-menu-btn{color:var(--accent);
background:var(--accent-soft)}
.side-home-phone{display:inline-block;padding:6px 8px;font-weight:600;
color:var(--ink);text-decoration:none}
.side-nav,.side-foot{display:none}
.side-menu-t:checked~.side-nav{display:block;width:100%}
.side-menu-t:checked~.side-foot{display:block}
.side-group{margin:0;padding:0 6px}
details.side-sec{display:block}
.side-foot{margin:0;border-top:0;padding:0 0 0 8px}
/* On a phone the assistant's sentence is a paragraph in a menu somebody
   opened to go somewhere, so only the dot is drawn; its title attribute still
   carries the sentence, and the settings page it links to says the whole
   thing in full. */
.pc-dot-say{display:none}
/* Wide tables must scroll INSIDE their own box on a phone rather than
   stretching the page — applied from 760px, not 640px, so it kicks in on the
   same breakpoint the sidebar collapses at. (The staff list was the widest of
   them and is not a table any more; the folders, templates and pending-invite
   tables still are.) */
table{display:block;overflow-x:auto;white-space:nowrap}
/* Except the login records, which stack each entry instead (end-to-end run
   2026-09-12): scrolled sideways, what happened sat off the right edge of a
   phone. Time and who on one line; what happened, then its detail, below. */
.audit-table,.audit-table tbody,.audit-table tr{display:block;
overflow-x:visible;white-space:normal}
.audit-table tr:first-child{display:none}
.audit-table tr{padding:8px 0;border-bottom:1px solid var(--line)}
.audit-table td{display:inline-block;border:0;padding:2px 10px 2px 0;
overflow-wrap:anywhere}
.audit-table td:last-child{display:block}
}
/* VIEW AS. Loud on purpose: an admin looking through somebody else's eyes must
   never lose track of whose screen this is, so the bar sits above the page
   content, wears the warning colour, and carries its own way out. Rendered
   from exactly one place (wpage, when the request is impersonated), so a
   staff member's own page can never grow one. */
.viewas-bar{background:var(--warn-bg);color:var(--warn);
border:1px solid var(--warn);border-radius:var(--radius);
padding:10px 14px;margin:0 0 16px;font-weight:600}
.viewas-bar a{color:inherit}
@media(max-width:640px){
.wrap{padding:16px 12px 56px}
/* THE BOARD IS A BOARD ON A PHONE (spec section 7, 2026-09-13; finding 3
   measured 2 cards in a flat list, no way to add one, and the first card
   453px down). One full-width column at a time that you swipe between: CSS
   scroll-snap does it with no script at all, so the swipe is the browser's
   own horizontal scroll and works with momentum, with a screen reader's
   focus movement and with a Bluetooth keyboard.
   The negative margin cancels .wrap's 12px gutter EXACTLY and adds no
   padding of its own, so flex:0 0 100% resolves against the full 375px
   screen: the spec's 20px was written against the desk's gutter, and any
   horizontal padding here would leave every column short of the screen. */
.board-cols{scroll-snap-type:x mandatory;gap:0;min-height:calc(100vh - 190px);margin:0 -12px;padding:0}
.board-col{flex:0 0 100%;scroll-snap-align:center;margin-right:12px}
.board-cols>form{flex:0 0 100%}
.board-tabs{display:block}
.board-dots{display:block}
/* ONE line of description on a phone (the owner, 2026-09-14). Same cut from
   the server — the rule here is the clamp, not a second, shorter cut — so a
   phone card is one line of title and one of description and the chips stay
   on the screen. */
.board-preview{-webkit-line-clamp:1}
/* AT PHONE WIDTH THE BOARD IS READ-ONLY (R4, spec
   docs/specs/2026-09-21-card-sharing.md §7, slice 7). The owner's decision:
   a phone is where work is LOOKED AT, and every way of changing a card on
   one is a way of changing the wrong card — the composer opens a form in a
   column 375px wide, a drag is a swipe that was meant to be a scroll, and a
   long press is a scroll that stopped for half a second.
   THE ROUTES ARE UNCHANGED AND THIS IS NOT A PERMISSION. Nothing here
   refuses anything; it stops OFFERING it. A phone with this CSS blocked and
   every script off can still post what it could always post, and every gate
   answers exactly as it did — which is why this is a display rule and the
   headless proof checks the POSTs as well as the page.
   display:none and not visibility or opacity: a control a screen reader
   still reaches, or a tab stop that leads nowhere, is worse than one that
   is plainly not there. And each name is written with .board-cols in front
   of it so these outrank the desk's own `.board-cols .board-add{display:
   block}` above: a one-class rule here would lose to a two-class rule there
   and the composer would stay on the screen. */
.board-cols .board-add,.board-cols .board-add-open,
.board-cols .board-add-box,.board-cols .board-col-menu{display:none}
.board-cols>form{display:none}
.board-card{-webkit-user-drag:none;user-select:none}
/* The panel is a sheet that comes up from the foot, not a column beside a
   board there is no room for. */
.card-panel{width:100vw;border-left:0;border-top:1px solid var(--line);top:auto;height:92vh;border-radius:12px 12px 0 0}
.board-head{gap:6px;margin:0 0 8px}
.board-name{font-size:1.2rem}
h1{font-size:1.2857rem}
/* Both selectors, because .chat-msg.chat-assistant outranks .chat-msg and a
   phone has no room to give an answer 92% and a margin as well. */
.chat-msg,.chat-msg.chat-assistant{max-width:100%}
}
/* THE CHAT PICKER (fx-chat-picker, owner 2026-09-28): a search box over one
   scrolling list, Company WhatsApp then My WhatsApp, Groups then People, and
   the chosen chat as a chip naming where it comes from. Rows are 44px tall
   so a thumb picks one; the list scrolls inside itself so a company in two
   hundred chats is still a short page. */
/* The global form rule makes a form shrink to its content, so the picker
   asks for its own width and the page caps it on a phone. */
.cp{width:560px;max-width:100%;margin:8px 0}
.cp-label{display:block;font-weight:550;margin:0 0 6px}
.cp-q{width:100%;min-height:44px;padding:8px 12px;font:inherit;color:var(--ink);
background:var(--card);border:1px solid var(--line-strong);border-radius:var(--radius)}
.cp-q:focus{outline:2px solid var(--accent);outline-offset:1px}
.cp-list{margin-top:8px;max-height:22rem;overflow-y:auto;background:var(--card);
border:1px solid var(--line);border-radius:var(--radius);overscroll-behavior:contain;
scroll-padding-top:2.75rem}
.cp-sec+.cp-sec{border-top:1px solid var(--line)}
.cp-sec-h{position:sticky;top:0;z-index:1;margin:0;padding:8px 12px;
background:var(--bg-step);font-weight:650;font-size:.93rem}
.cp-kind-h{margin:0;padding:8px 12px 2px;color:var(--muted);font-size:.8rem;
font-weight:600;text-transform:uppercase;letter-spacing:.04em}
.cp-opt{display:flex;align-items:center;min-height:44px;padding:8px 12px;
cursor:pointer;overflow-wrap:anywhere;touch-action:manipulation}
.cp-opt:hover{background:var(--accent-soft)}
.cp-opt.cp-hi{background:var(--accent-tint);box-shadow:inset 3px 0 0 var(--accent)}
.cp-opt[aria-selected=true]{font-weight:600}
.cp-empty,.cp-none{margin:0;padding:10px 12px;color:var(--muted)}
.cp-err{margin:8px 0 0;color:var(--bad)}
.cp-chip{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;
padding:10px 12px;background:var(--accent-soft);border:1px solid var(--accent);
border-radius:var(--radius)}
.cp-chip-name{font-weight:600;overflow-wrap:anywhere;min-width:0}
.cp-chip-src{font-size:.85rem;color:var(--muted);padding:1px 8px;
border:1px solid var(--line-strong);border-radius:999px;background:var(--card)}
.cp-chip-src:empty{display:none}
.cp-change{margin-left:auto;min-height:40px;background:var(--card);color:var(--ink);
border:1px solid var(--line-strong)}
.cp-change:hover{background:var(--accent-soft);border-color:var(--accent)}
@media(max-width:640px){.cp-list{max-height:60vh}}
/* hidden must win over the display each part sets for itself above. */
.cp [hidden]{display:none!important}

.door-busy{margin:10px 0 0;color:var(--muted);text-align:center}
.door-choose form{margin:0 0 10px}
.door-links{margin:14px 0 0;text-align:center}
.door-links button{display:inline;width:auto}
