/* Retirement plan UI: the components, written against the tokens of theme.css.
   Layout: a 48px header, a navigation rail on the canvas, a main pane on the
   canvas whose content sits in white panels (tables, forms, charts, cards). */
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body { font: var(--fs)/var(--lh) var(--font-ui); color: var(--ink); background: var(--paper); -webkit-font-smoothing: antialiased; }
#app { display: flex; flex-direction: column; height: 100vh; }
.num, .tnum { font-variant-numeric: tabular-nums; }

/* header */
.topbar { display: flex; align-items: center; gap: var(--sp-4); height: var(--header-h); padding: 0 var(--sp-4); background: var(--paper-raised); border-bottom: 1px solid var(--rule); flex: none; }
.brand { display: flex; align-items: center; gap: var(--sp-2); font-weight: 600; font-size: var(--fs); letter-spacing: -0.01em; }
/* the lockup: the mark and the wordmark in the display face, and nothing beneath it. The
   descriptor that sat under the name at eyebrow scale came out in 1.16.0 item 9 (D7); the
   header keeps its 48px, and the column stays so the wordmark centres in it. */
.brand .lockup { display: flex; flex-direction: column; justify-content: center; }
.brand .wordmark { font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 600; line-height: 1.15; letter-spacing: 0; }
.brand .mark { width: 20px; height: 20px; flex: none; display: inline-block; background: var(--mark-image) center / contain no-repeat; }   /* the ensō, from ui/img/ (1.10.0); 10px made a brush stroke unreadable */
/* the name goes home (docs/PLAN_PROSPEROUS.md A6): the brand is a link to the Front Door, reached as a menu row is
   and, on the Front Door, lit as its row is -- .menu .room[aria-current="page"]'s ground and 3px --mark edge below */
a.brand { height: calc(var(--header-h) - 10px); padding: 0 var(--sp-2) 0 calc(var(--sp-2) - 3px); color: var(--ink); text-decoration: none; border-left: 3px solid transparent; }
a.brand:hover { background: var(--paper-sunken-2); }
a.brand[aria-current="page"] { background: var(--paper-sunken); border-left-color: var(--mark); }
a.brand:focus-visible { outline: 2px solid var(--mark); outline-offset: -2px; }
.topbar-right { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }
/* The household: a button in the header's top right carrying the household's name, opening a
   menu of switch, rename, new and delete. Until 1.11.0 this was a collapsible section in the
   rail. It sits here rather than in the rail's foot beside the role badge because this is where
   a multi-user build would put an account menu (docs/PLAN_1.11.0.md, "Future, named and not
   built"); that layer is not built here. */
.household-menu { position: relative; }
.household-button { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 0; max-width: 320px; height: calc(var(--header-h) - 10px); padding: 0 var(--sp-3); font: inherit; line-height: 1.2; color: var(--ink); background: var(--paper-sunken); border: 1px solid var(--rule); cursor: pointer; }
.household-button:hover { background: var(--paper-sunken-2); }
.household-button:disabled { cursor: default; }
/* D16 (docs/PLAN_PROSPEROUS.md A7): the household's name over who is looking, two lines at the header's height, and no chevron */
.household-title { max-width: 100%; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.household-who { max-width: 100%; color: var(--ink-2); font-size: var(--fs-tiny); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* a floating thing: --paper-raised with --shadow, as DESIGN.md section 10 has it */
.menu-panel { position: absolute; top: calc(100% + 4px); right: 0; z-index: 30; min-width: 280px; max-width: 360px; padding: var(--sp-3); background: var(--paper-raised); border: 1px solid var(--rule); box-shadow: var(--shadow); }
.menu-panel h3 { margin: 0 0 var(--sp-2); }
/* the household panel (A7, D16): three groups of one row style, 280px on a wide screen and the header's whole width on a phone */
#household-panel { width: 280px; min-width: 0; padding: var(--sp-2) 0; }
#household-panel .menu-group-rows { padding: var(--sp-1) 0; }
#household-panel .menu-group-rows + .menu-group-rows { border-top: 1px solid var(--rule); }
#household-panel .menu-group-word { padding: var(--sp-1) var(--sp-3); color: var(--ink-2); font-size: var(--fs-tiny); }
#household-list { max-height: 40vh; overflow-y: auto; }
#household-panel .hint { margin: 0; padding: 5px var(--sp-3); }
.menu-panel .household-option { display: flex; align-items: center; gap: var(--sp-2); width: 100%; min-height: 36px; text-align: left; padding: 5px var(--sp-3) 5px calc(var(--sp-3) - 3px); font: inherit; color: var(--ink); background: none; border: 0; border-left: 3px solid transparent; cursor: pointer; }
.menu-panel .household-option:hover { background: var(--paper-sunken); }
.menu-panel .household-option:focus-visible { outline: 2px solid var(--mark); outline-offset: -2px; }
.menu-panel .household-option[aria-current="true"] { background: var(--paper-sunken); border-left-color: var(--mark); font-weight: 600; }
.menu-panel .household-option .tick { flex: none; width: 1em; color: var(--mark); }
.menu-panel .household-option[aria-current="true"] .tick::before { content: "✓"; }
.menu-panel .household-option .row-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 640px) { #household-panel { position: fixed; top: var(--header-h); left: 0; right: 0; width: auto; max-width: none; } }
/* What's waiting (docs/PLAN_WAITING.md item 01; the record, docs/design/WAITING.md §2, §3 and §9): the bell between
   Rōshi and the household, in .household-button's height and ground, and its panel in .menu-panel's shape. The bell is
   a monoline path in the row's own colour, as a room's icon in the menu is. The numeral is --mark in the mono face and
   the dot --ink-3: a count and a presence, never a colour that grades (D3), and no new ground for §11's gate. */
.waiting-menu { position: relative; }
.waiting-menu[hidden] { display: none; }
.household-button.waiting-button { flex-direction: row; align-items: center; gap: 6px; padding: 0 10px; }
.waiting-button .icon { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.waiting-count { display: inline-block; font-family: var(--font-mono); font-size: var(--fs-small); font-weight: 600; line-height: 1; color: var(--mark); }
.waiting-count[hidden] { display: none; }
.waiting-count.waiting-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ink-3); }
/* 340 to 420 wide (§3); the panel sets its own width, since a panel hung from a button this narrow shrinks to nothing */
#waiting-panel { width: 400px; min-width: 340px; max-width: 420px; max-height: calc(100vh - var(--header-h) - 16px); overflow-y: auto; padding: var(--sp-2) 0 0; font-size: var(--fs-small); }
#waiting-panel .waiting-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-1) var(--sp-3) var(--sp-2); }
#waiting-panel .waiting-title { font-family: var(--font-ui); font-size: var(--fs); font-weight: 600; color: var(--ink); }
#waiting-panel .waiting-filter { font-family: var(--font-mono); font-size: var(--fs-tiny); color: var(--ink-2); white-space: nowrap; }
#waiting-panel .filter-word { font: inherit; color: var(--ink-2); background: none; border: 0; padding: 0; cursor: pointer; }
#waiting-panel .filter-word[aria-pressed="true"] { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
#waiting-panel .filter-word:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
#waiting-panel .menu-group-rows { padding: var(--sp-1) 0; border-top: 1px solid var(--rule); }
#waiting-panel .menu-group-word { padding: var(--sp-1) var(--sp-3); color: var(--ink-2); font-size: var(--fs-tiny); }
#waiting-panel .list-row { padding: 6px var(--sp-3); }
#waiting-panel .list-row + .list-row { border-top: 1px solid var(--rule); }
#waiting-panel .room-word { font-family: var(--font-mono); font-size: var(--fs-tiny); color: var(--ink-2); text-transform: uppercase; letter-spacing: .06em; }
#waiting-panel .one-word { display: block; font-family: var(--font-mono); font-size: var(--fs-tiny); font-variant: small-caps; letter-spacing: .06em; color: var(--ink-2); }
#waiting-panel .waiting-links { display: flex; gap: var(--sp-4); flex-wrap: wrap; padding: 2px var(--sp-3) 6px; }
#waiting-panel .waiting-links a, #waiting-panel .personal .suggest + a { color: var(--ink-2); }
#waiting-panel .home-row .rl { width: auto; min-width: 5em; }
#waiting-panel .home-resume .trail { font-weight: 600; }
#waiting-panel .thread-fold > summary { cursor: pointer; color: var(--ink-2); font-size: var(--fs-tiny); }
#waiting-panel .waiting-empty { margin: 0; padding: var(--sp-2) var(--sp-3); }
#waiting-panel .waiting-foot { position: sticky; bottom: 0; padding: var(--sp-2) var(--sp-3); background: var(--paper-raised); border-top: 1px solid var(--rule); }
#waiting-panel .waiting-foot form.task-add { margin: 0; }
@media (max-width: 640px) { #waiting-panel { position: fixed; top: var(--header-h); left: 0; right: 0; width: auto; min-width: 0; max-width: none; } }
.body { display: flex; flex: 1; min-height: 0; }
/* 264px and not --rail-w's 300 (docs/design/NAVIGATION.md §3): the menu is a list of words, where
   the rail was a list of scenarios with badges. --rail-w is theme.css's, which this release leaves
   as it is (D2), so the width is written here. */
.sidebar { width: 264px; flex: none; display: flex; flex-direction: column; background: var(--paper); border-right: 1px solid var(--rule); }
.rail-foot { margin-top: auto; border-top: 1px solid var(--rule); padding: 10px var(--sp-3); display: flex; flex-direction: column; gap: 8px; }
/* The menu at the left (docs/PLAN_NAVIGATION.md item 01; ui/js/menu.js). Every place in one list:
   a room is a 44px row -- its icon, its word, the open-facts count, a chevron when it has tabs --
   and its tabs beneath it under each group's word in the eyebrow treatment. Lit once (the plan's
   D-01b): the 3px --mark edge and a ground on the one row that is the place, the lit tab on
   --mark-wash or the room's row on --paper-sunken, which is the shape .household-option takes in
   the household menu. The room holding it is set in --ink at 600 whichever row carries the edge.
   The icon takes the row's own colour, so it carries nothing a hue could. */
.menu { flex: 0 1 auto; min-height: 0; overflow-y: auto; padding: var(--sp-2) 0; }
.menu .rooms, .menu .places { display: flex; flex-direction: column; }
.menu .room, .menu .place { display: flex; align-items: center; gap: var(--sp-3); width: 100%; height: 44px; padding: 0 var(--sp-4) 0 13px; overflow: hidden; white-space: nowrap; font: inherit; font-weight: 500; color: var(--ink-2); background: none; border: 0; border-left: 3px solid transparent; text-align: left; cursor: pointer; }
.menu .icon { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
/* the word is the row's own text, so the count and the chevron are pushed to the right edge by a margin rather than by a label that grows */
.menu .room .chev { order: 2; margin-left: auto; width: 12px; flex: none; text-align: center; color: var(--ink-3); font-size: var(--fs-tiny); }
.menu .room .chev::before { content: '▸'; }
.menu .room[aria-expanded="true"] .chev::before { content: '▾'; }
.menu .menu-tabs { padding: 0 0 6px; }
.menu .menu-group { padding: 10px var(--sp-4) 2px 50px; font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); }
.menu .menu-tab { display: block; width: 100%; padding: 6px var(--sp-4) 6px 50px; font: inherit; color: var(--ink-2); background: none; border: 0; border-left: 3px solid transparent; text-align: left; cursor: pointer; }
.menu .room:hover, .menu .place:hover, .menu .menu-tab:hover { color: var(--ink); background: var(--paper-sunken-2); }
.menu .room.active, .menu .place.active { color: var(--ink); font-weight: 600; }
.menu .room[aria-current="page"], .menu .place[aria-current="page"] { color: var(--ink); background: var(--paper-sunken); border-left-color: var(--mark); }
.menu .menu-tab[aria-current="page"] { color: var(--ink); font-weight: 600; background: var(--mark-wash); border-left-color: var(--mark); }
.menu .room:focus-visible, .menu .place:focus-visible, .menu .menu-tab:focus-visible { outline: 2px solid var(--mark); outline-offset: -2px; }
.menu .menu-rule { margin: var(--sp-2) var(--sp-4); border-top: 1px solid var(--rule); }
.menu .menu-tab.active { color: var(--ink); font-weight: 600; }
/* Folded by ☰ (docs/PLAN_NAVIGATION.md item 02; the record §3, "Folded"): 56px of icons, the
   width alone moving, at --dur-enter on --ease, and nothing else animated. A row's word is its
   own text node, so a zero font size is what takes it off the row while its title still names
   it; the count, the chevron, the tabs and the foot are not drawn. A room with tabs shows them in
   a flyout beside its icon, on --paper-raised with --shadow as every floating panel is. */
.sidebar { transition: width var(--dur-enter) var(--ease); }
@media (prefers-reduced-motion: reduce) { .sidebar { transition: none; } }
.menu { overflow-x: hidden; }
.body.menu-folded .sidebar { width: 56px; }
.body.menu-folded .menu .room, .body.menu-folded .menu .place { font-size: 0; gap: 0; padding: 0 0 0 15px; }
.body.menu-folded .menu .room .chev { display: none; }   /* a room's row carries no count since docs/PLAN_WAITING.md item 04: the bell does */
.body.menu-folded .menu .menu-rule { margin: var(--sp-2) 10px; }
.body.menu-folded #rail-foot { display: none; }
.menu-flyout { position: fixed; z-index: 40; min-width: 220px; padding: 6px 0 8px; background: var(--paper-raised); border: 1px solid var(--rule); box-shadow: var(--shadow); font-size: var(--fs); }
.menu-flyout .flyout-word { padding: 6px var(--sp-4) 4px 22px; font-weight: 600; color: var(--ink); }
.menu .menu-flyout .menu-group { padding-left: 22px; }
.menu .menu-flyout .menu-tab { padding-left: 22px; }
.rail-conn { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.main { flex: 1; min-width: 0; overflow: auto; padding: var(--sp-5) var(--sp-6) 40px; }

/* controls: 32px tall, 28px small */
.field { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--fs-small); color: var(--ink-2); }
.field.inline { flex-direction: row; align-items: center; gap: 6px; }
input, select, textarea, button { font: inherit; color: var(--ink); }
input, select, textarea { background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--radius); padding: 5px 8px; min-height: 30px; }
select.small { min-height: var(--control-h-sm); padding: 3px 6px; font-size: var(--fs-small); }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--mark); outline-offset: 1px; border-color: var(--mark); }
.btn { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--rule-strong); background: var(--paper-raised); border-radius: var(--radius); padding: 0 12px; height: var(--control-h); cursor: pointer; color: var(--ink); font-weight: 500; white-space: nowrap; }
/* A button marked hidden stays hidden (1.20.0 item 6). .btn sets display, and an author rule outranks the browser's own
   [hidden] rule, so every hidden .btn was drawn: Dōgen's button showed to every role, not the administrator's alone, while
   the end-to-end test read the property and passed. Sign out is hidden the same way on the development loop. */
.btn[hidden] { display: none; }
.field[hidden] { display: none; }   /* the same for a dialog's field, which .field draws as a column: a figure of your own, asked only when chosen (docs/PLAN_CHANGE_GRID.md item 03) */
.btn:hover { background: var(--paper-sunken); }
.btn:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
.btn.primary { background: var(--mark); color: var(--mark-ink); border-color: var(--mark); }
.btn.primary:hover { background: var(--mark-hover); border-color: var(--mark-hover); }
.btn.ghost { border-color: transparent; background: transparent; }
.btn.ghost:hover { background: var(--paper-sunken-2); }
.btn.danger { color: var(--shortfall); }
.btn.small { height: var(--control-h-sm); padding: 0 10px; font-size: var(--fs-small); }
.btn:disabled { opacity: .45; cursor: default; }
.badge { display: inline-block; padding: 1px 7px; border-radius: var(--radius); font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 500; background: var(--paper-sunken-2); color: var(--ink-2); border: 1px solid transparent; white-space: nowrap; line-height: 1.5; }
.badge.num { font-family: var(--font-ui); font-variant-numeric: tabular-nums; }   /* a badge that is only a count is a figure, and no figure is set in mono */
.badge.stale { background: var(--limit-wash); border-color: var(--limit); color: var(--ink); }
.badge.muted { color: var(--ink-3); }
.badge.tag { background: var(--mark-wash); border-color: var(--mark); color: var(--ink); }   /* --mark on --mark-wash fell to 3.8:1 over a hovered rail item; every other wash badge already reads --ink, and the hue stays in the border */
.badge.status-active { background: var(--settled-wash); color: var(--ink); }
.badge.status-archived { opacity: .6; }
.hint { color: var(--ink-2); font-size: var(--fs-small); margin: var(--sp-1) 0; }
h1 { font-size: var(--fs-h1); font-weight: 600; margin: 0; letter-spacing: -0.015em; line-height: 1.3; }
h2 { font-size: var(--fs-h2); font-weight: 600; margin: var(--sp-6) 0 var(--sp-2); letter-spacing: -0.005em; }
h2:first-child { margin-top: 0; }
h3 { font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 600; margin: var(--sp-4) 0 6px; color: var(--ink-2); text-transform: uppercase; letter-spacing: .06em; }
a { color: var(--mark); }

/* navigation rail */
.side-head { display: flex; justify-content: space-between; align-items: center; margin: var(--sp-1) 0 var(--sp-2); }
.side-head h3 { margin: 0; }
/* The rail's head (#564, docs/PLAN_1.18.1.md D12): the title in the eyebrow face, the count beside
   it. It was the Spending room's rule (docs/PLAN_1.18.0.md §17.3) until the scenario rail took the
   same head; the rails went with docs/PLAN_NAVIGATION.md items 04 and 05, and their chevrons with
   them, and the scenario chooser's panel keeps the head. */
.rail-top { display: flex; align-items: center; justify-content: space-between; margin: 0 0 var(--sp-2); }
.rail-top .rail-title { font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 500; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-2); }
.rail-top .rail-title .badge { margin-left: 4px; vertical-align: middle; }
.side-actions { display: flex; gap: 6px; flex-wrap: wrap; margin: var(--sp-2) 0 var(--sp-3); }
.scenario-list { list-style: none; margin: 0; padding: 0; }
.scenario-item { display: flex; align-items: center; gap: 6px; min-height: 30px; padding: 3px 8px 3px 6px; border-radius: var(--radius); cursor: pointer; border-left: 3px solid transparent; }
.scenario-item:hover { background: var(--paper-sunken-2); }
.scenario-item.selected { background: var(--paper-raised); border-left-color: var(--mark); box-shadow: inset 0 0 0 1px var(--rule); }
.scenario-item input[type=checkbox] { margin: 0 2px 0 0; accent-color: var(--mark); }
.scenario-item .name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-display); font-size: var(--fs); }
.scenario-item .name.base { font-weight: 600; }
.scenario-item .depth-1 { margin-left: 14px; } .scenario-item .depth-2 { margin-left: 28px; } .scenario-item .depth-3 { margin-left: 42px; }
.scenario-item .tree { color: var(--ink-3); }
/* the ticked count and the way to clear it, beside the tick boxes they belong to: Compare
   went to the phase strip in 1.11.0 item 3 and took its nav item with it */
.compare-ticks { margin: var(--sp-2) 0 0; padding: 0 6px; }
/* THE SCENARIO CHOOSER (docs/PLAN_NAVIGATION.md item 04; the design record §4a). The rail's list,
   in a panel under a button in the pane's head: the button is the scenario's name after the word
   "scenario", on --paper-sunken with the rule round it, and the panel is .menu-panel's shape and
   ground (--paper-raised, --rule, --shadow), opening from the button's left edge. The rules above
   draw what is inside it unchanged, but for the chosen row: the rail drew it raised on a sunken
   column, and on a raised panel that would be no ground at all, so it takes --paper-sunken and the
   3px --mark edge, the shape the household menu's current row has (D-01b's lit row). One scenario:
   the name alone, the panel never opened (D18). */
.chooser { position: relative; display: inline-flex; }
.chooser-button { display: inline-flex; align-items: baseline; gap: var(--sp-2); min-height: 28px; padding: 2px 10px; font: inherit; color: var(--ink); background: var(--paper-sunken); border: 1px solid var(--rule); cursor: pointer; }
.chooser-button:hover, .chooser.open .chooser-button { background: var(--paper-sunken-2); }
.chooser-button:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
.chooser-button .chev { color: var(--ink-2); font-size: var(--fs-tiny); }
.chooser .chooser-button .scenario-word { color: var(--ink-2); }   /* on the button's sunken ground the word takes --ink-2, as every quiet word on a ground does */
.chooser-panel { position: absolute; top: calc(100% + 4px); left: 0; z-index: 30; min-width: 360px; max-width: min(480px, 80vw); max-height: 70vh; overflow-y: auto; padding: var(--sp-3); background: var(--paper-raised); border: 1px solid var(--rule); box-shadow: var(--shadow); }
.chooser-panel .side-head { margin-top: 0; }
.chooser-panel .scenario-item.selected { background: var(--paper-sunken); box-shadow: none; }
/* Nineteen rules came out here in 1.14.0 item 5, and none of them had a producer.
   Nine were the rail sections -- Household (collapsible), Scenarios, Reports -- whose
   last producer went in 1.11.0 item 2, when the Household section moved to the header;
   they had been dead CSS for three releases (docs/PLAN_1.14.0.md, F2). Ten were the
   rail's navigation items, .nav-section to .nav-sub, which the Reports section was the
   only thing drawing. The rail is the scenarios and nothing else now. */
.btn.xlsx svg { width: 14px; height: 14px; }

/* the funding-order recommendation */
table.grid tr.best td { background-color: var(--settled-wash) !important; }
table.grid tr.current td { font-weight: 600; }
table.grid tr.in-view td { background-color: var(--mark-wash) !important; }   /* the row the Set up's summary sent the reader to (ui/js/rooms/retirement/setup.js, every column; ui/js/grid.js, inView) */

/* Front Door (1.14.0 item 2). Sentences and a card, so it is prose measure rather than the
   full pane width: a line of body text past about 70 characters is read twice. Nothing
   here paints a ground of its own -- the resume card takes .panel, which section 11's
   sweep already stands on -- and nothing here needs a print rule, because it prints as
   it stands. Its head is the pane's, which every screen has (docs/PLAN_NAVIGATION.md item 03).

   It draws no scenario chooser: nothing on the Front Door is chosen per scenario, so a list to
   choose one from is furniture. The rail at the left that held the scenario list went with
   docs/PLAN_NAVIGATION.md items 04 and 05, and the rule hiding it on a screen without one went with
   it (it was no-rail, then rail-empty); #rail-foot stays under the menu -- Mode, Connection, the
   role badge and the version badge are the application's footer, and a reader who lands on the
   Front Door with a token the server refuses needs the dialog that fixes it. 1.18.2 item 1 (#585)
   laid the body out as a column where there was no rail, with the foot along the bottom; the menu
   (item 01) is on every screen, so the sidebar is a column on every screen again and the foot is
   its foot, and those four rules went with item 01. */
.home-head .when { color: var(--ink-2); }
.home-speaks, .home-changed, .home-checklist { max-width: 62ch; }   /* .home-speaks: Summary's paragraph on the Front Door (1.17.0 item 10), in the prose column */
/* Between you is not in that column, because it is not prose (#503): its figures take the
   width of the column they are in, and the count line under them is a sentence and keeps the
   measure. How they wrap is the passage below .home-between .ensos. */
.home-between { max-width: none; }
.home-between .counts { max-width: 62ch; }
.home-changed, .home-between { margin-top: var(--sp-6); }
/* One column (docs/PLAN_WAITING.md item 03). The two of #559 and #883 put the sentences at the measure and
   what is not prose in a side column; once docs/PLAN_PROSPEROUS.md A2 made the blocks lead the page across its
   width, the side column held For the household alone, which is What's waiting's since item 03. Under the
   blocks is Changed, at the measure. */
/* Between you (1.17.0 item 9, §18): open ensōs in a row, the product's own mark in ink
   for one that is earned, a dashed circle for one that is not, the words beneath in the body
   face; no colour, no number, no bar. A class of its own: .badge is the scenario head's.
   One row where the section holds them all, and otherwise rows as even as the count allows
   (#883): that rule is ui/js/tabs/home.js's, under between(), because it is measured from the
   figures drawn and a width here would name a count (audit BETWEEN-1, #1288). */
.home-between .ensos { display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-3); margin: var(--sp-3) 0 var(--sp-2); }
.home-between .enso { width: 92px; text-align: center; font-size: var(--fs-small); }
.home-between .enso .ring { display: block; width: 44px; height: 44px; margin: 0 auto 6px; }
.home-between .enso.earned .ring { background: var(--mark-image) center / contain no-repeat; }
.home-between .enso.not-yet .ring { border: 2px dashed var(--ink-3); border-radius: 50%; box-sizing: border-box; }
.home-between .enso .name { color: var(--ink); line-height: 1.25; }
.home-between .enso .by { color: var(--ink-2); font-size: var(--fs-tiny); margin-top: 2px; }
.home-between .enso.not-yet .name, .home-between .enso.not-yet .by { color: var(--ink-3); }
.home-between .counts { color: var(--ink-2); font-size: var(--fs-small); margin: 0; }
.home-blocks { margin-top: var(--sp-6); }   /* the household's chosen blocks (1.16.0 item 5): full width, because a chart needs it; first on the page since A2, below */
.home-blocks > h2 { font-family: var(--font-ui); font-size: var(--fs-h2); font-weight: 600; margin: var(--sp-5) 0 var(--sp-2); }
.home-blocks > h2:first-child { margin-top: 0; }
.home-blocks > h2 .badge { margin-left: 6px; vertical-align: middle; }
/* THE FRONT DOOR'S FIGURES (docs/PLAN_PROSPEROUS.md A2, D3). The blocks lead the page now, so the section loses the margin
   it had below the prose. The lead row is the year and the coverage score (and the one thing to do next until
   docs/PLAN_WAITING.md item 03), side by side on a wide pane and one under another on a narrow one; then the three
   tiles; then the chart, at the page's width. */
.home-blocks:first-child, .home-blocks { margin-top: 0; margin-bottom: var(--sp-6); }
.front-lead { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-4) calc(var(--sp-6) * 2); align-items: start; margin: 0 0 var(--sp-5); }
.hero .hero-year { font-family: var(--font-display); font-size: 48px; font-weight: 600; line-height: 1.05; letter-spacing: -0.02em; color: var(--ink); }   /* the one figure set larger than the scale's top step: D3's 48px, the first thing on the screen */
.hero .hero-year.short { color: var(--shortfall); }
.hero .hero-mark { font-family: var(--font-ui); font-size: var(--fs-h1); vertical-align: middle; }
.hero .hero-line { color: var(--ink-2); font-size: var(--fs-h2); margin-top: var(--sp-2); }
.hero .badge { font-size: var(--fs-tiny); vertical-align: middle; }
.score .label { color: var(--ink-2); font-size: var(--fs-small); }
.score .score-value { font-size: var(--fs-value); font-weight: 600; margin-top: 4px; font-variant-numeric: tabular-nums; }
.score .sub, .score .score-none { color: var(--ink-2); font-size: var(--fs-small); margin: 4px 0 0; }
.cards.tiles { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.tile .meter { height: 8px; background: var(--rule-soft); margin: var(--sp-2) 0 0; position: relative; }
.tile .meter > span { display: block; height: 100%; background: var(--series-1); }
.tile .sub.ceiling-line { color: var(--ink-2); }
.chart.area .area-fill { fill-opacity: 0.22; stroke: none; }
.chart.area .band { fill: var(--rule-soft); fill-opacity: 0.35; }
.chart.area .band.band-1 { fill-opacity: 0.6; }
.chart.area .band.band-2 { fill-opacity: 0.85; }
.chart.area .band-label { fill: var(--ink-2); font-family: var(--font-ui); font-size: calc(10px * var(--u, 1)); }
.chart.area .milestone { stroke: var(--ink-2); stroke-width: 2; }
.chart.area .short-mark { fill: var(--shortfall); }
.chart.area .weakest-mark { fill: var(--paper-raised); stroke: var(--ink); stroke-width: 2; }
.chart.area .weakest-label { fill: var(--ink); font-family: var(--font-ui); font-size: calc(10px * var(--u, 1)); font-weight: 600; }
.stack { display: flex; height: 18px; background: var(--rule-soft); margin: var(--sp-2) 0; }
.stack .seg { display: block; height: 100%; }
.stack-key { list-style: none; padding: 0; margin: 0 0 var(--sp-2); display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); font-size: var(--fs-small); }
.stack-key .sw { display: inline-block; width: 10px; height: 10px; margin-right: 6px; vertical-align: -1px; }
.month-review { list-style: none; padding: 0; margin: 0; max-width: 40ch; }
.month-review li { display: flex; justify-content: space-between; gap: var(--sp-4); padding: 2px 0; border-bottom: 1px solid var(--rule-soft); }
/* Arrange (1.16.0 item 6): four buttons on every block while the screen is being arranged,
   and the foot that switches it on. Real buttons, so the keyboard and a finger both drive
   them; .no-print keeps an arranged Summary printing as its blocks and not its buttons. */
.block-controls { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px dashed var(--rule); }
.card .block-controls { margin-top: 8px; }
.arrange-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin: var(--sp-4) 0 var(--sp-2); }
.arrange-foot .hint { margin: 0; }
.arrange-foot .add-block { display: inline-flex; align-items: center; gap: 6px; }   /* an h2 that opens its section takes no top margin, so the section carries it */
/* a word the interface defines: a button that opens its sentence in a panel on a click, a
   tap or Enter (1.16.0 item 8, ui/js/define.js), and the mark is a shape and not a colour,
   so nothing here is told by hue alone (section 11). The button is reset to read as the
   word it always was: the dotted underline and the ? cursor are what say it opens, and the
   title is gone from these sites. */
.term { border-bottom: 1px dotted var(--ink-3); cursor: help; }
button.term, button.fig { font: inherit; color: inherit; background: none; border: 0; border-bottom: 1px dotted var(--ink-3); border-radius: 0; padding: 0; margin: 0; cursor: help; text-align: inherit; line-height: inherit; }
button.term:focus-visible, button.fig:focus-visible, button.badge.term:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
button.term[aria-expanded="true"], button.fig[aria-expanded="true"] { border-bottom-style: solid; }
button.badge.term { font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 500; padding: 1px 7px; border: 1px solid transparent; border-bottom: 1px dotted var(--ink-3); border-radius: var(--radius); background: var(--paper-sunken-2); color: var(--ink-2); line-height: 1.5; cursor: help; }
.define-panel { position: fixed; z-index: 40; max-width: min(44ch, calc(100vw - 16px)); padding: 10px 12px; background: var(--paper-raised); color: var(--ink); border: 1px solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow); font: var(--fs-small)/1.45 var(--font-ui); }
/* Summary's paragraph (1.16.0 item 7): the run's figures in sentences, at the full width of
   the pane above the blocks, in the display face the Front Door's answers use. A figure in it is a
   .fig mark: the same dotted underline as a term, tabular figures, and the definition
   behind it, which is item 8's panel. */
.summary-speaks { max-width: none; font-family: var(--font-display); font-size: var(--fs-h2); line-height: 1.55; margin: 0 0 var(--sp-5); }
/* the most you could spend (docs/PLAN_PROSPEROUS.md A1, D2): a fact beside the planned figure, in the paragraph's voice and a
   step smaller, under it on Summary and the Front Door */
.ceiling-sentence { font-family: var(--font-display); font-size: var(--fs); line-height: 1.55; margin: calc(-1 * var(--sp-3)) 0 var(--sp-5); }
/* What would change it, as one grid (docs/PLAN_CHANGE_GRID.md; ui/js/rooms/retirement/change-grid.js): table.grid's paper
   and ink and nothing of its own. The figure is bold and to the right, or a state in italics and --ink-3, never red
   (principle 5); the best order's star is --settled, as the trials' best row is; Rests on and Takes wrap, Takes at the
   hint's size. Each reading is a tbody of its own, so no reading carries the stripe and an opened row moves none. */
table.grid.change-grid td { vertical-align: top; }
table.grid.change-grid td.figure { font-weight: 600; }
table.grid.change-grid .missing { color: var(--ink-3); font-style: italic; font-weight: 400; }
table.grid.change-grid .star { color: var(--settled); }
table.grid.change-grid .montecarlo-band { color: var(--ink-2); font-size: var(--fs-small); font-weight: 400; }
table.grid.change-grid td { white-space: normal; height: auto; }   /* six columns across the pane at 1366: a cell wraps rather than push Takes out of it */
table.grid.change-grid td.reading { min-width: 16ch; }
table.grid.change-grid td.figure { min-width: 15ch; }
table.grid.change-grid td.find { min-width: 15ch; }
table.grid.change-grid td.found { white-space: nowrap; }
table.grid.change-grid td.rests { min-width: 24ch; }
table.grid.change-grid td.takes, table.grid.change-grid td.across { min-width: 14ch; color: var(--ink-2); font-size: var(--fs-small); }
table.grid.change-grid td.find .btn { white-space: normal; height: auto; min-height: var(--control-h-sm); text-align: left; }
table.grid.change-grid .ceiling-floor { white-space: nowrap; }
table.grid.change-grid td.rests select { font: inherit; }
table.grid.change-grid a.opener { white-space: nowrap; }
table.grid.change-grid .compare-six { display: inline-flex; gap: var(--sp-2); align-items: center; white-space: nowrap; }
/* a row opened under its row: one cell across the six on --paper-sunken, its sentences wrapping. A grid inside it keeps
   its own stripe and hover, row by row, which table.grid's rules, written for a grid inside nothing, would otherwise
   paint across every cell beneath a striped or hovered row at any depth; its words wrap and its figures do not; and
   a start year's or a path's year by year opens on the opened row's own ground */
table.grid.change-grid > tbody > tr.opened > td { background-color: var(--paper-sunken); white-space: normal; height: auto; padding: var(--sp-3) var(--sp-4); }
table.grid.change-grid > tbody > tr.opened > td > .hint:first-child { margin-top: 0; }
table.grid.change-grid tr.opened table.grid td { background-color: transparent; }
table.grid.change-grid tr.opened table.grid td:not(.num) { white-space: normal; }
table.grid.change-grid tr.opened table.grid > tbody > tr:nth-child(even) > td { background-color: var(--paper-stripe); }
table.grid.change-grid tr.opened table.grid > tbody > tr:hover > td { background-color: var(--paper-sunken-2); }
table.grid.change-grid tr.opened table.grid > tbody > tr.years > td { background-color: var(--paper-sunken); padding: var(--sp-2) var(--sp-3); }
.fig { font-variant-numeric: tabular-nums; font-weight: 600; border-bottom: 1px dotted var(--ink-3); cursor: help; white-space: nowrap; }
button.fig { font-family: var(--font-display); font-size: inherit; }
.badge.term { border-bottom-style: dotted; border-bottom-color: var(--ink-3); }
.home-row { display: flex; gap: var(--sp-3); margin: var(--sp-1) 0; }
.home-row .rl { flex: none; width: 5em; color: var(--ink-2); font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: .06em; padding-top: 2px; }
.home-changed .note { color: var(--ink-2); font-size: var(--fs-small); margin: var(--sp-2) 0 0; }   /* the second line of the So row: why nothing is listed */
.home-checklist .because { color: var(--ink-2); font-size: var(--fs-small); margin: 0; }
.home-checklist .lead { margin: 0 0 var(--sp-1); }
.home-checklist .setup-offer { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin: 0 0 var(--sp-3); }   /* the one way in: the Set up's button and its line (docs/PLAN_SETUP.md) */
.home-checklist .setup-offer .hint { margin: 0; }
/* no bar and no percentage: a tick is a fact, a percentage is a grade (docs/PERSONA.md) */
.checklist { margin: var(--sp-3) 0 var(--sp-4); }
.check-row { display: flex; align-items: baseline; gap: var(--sp-2); padding: 6px 0; border-bottom: 1px solid var(--rule); }
.check-row .tick { flex: none; width: 1.2em; color: var(--ink-2); }
.check-row.done .tick { color: var(--ink); }   /* the shape carries it: a tick and a ring are told apart with no colour at all, so none is spent here */
.check-row .what { flex: 1; }
.check-row.done .what { color: var(--ink-2); }
.check-row span.fact { flex: none; color: var(--ink-2); font-size: var(--fs-small); }
.check-row a.fact { flex: none; font-size: var(--fs-small); }
.check-row button.fact { flex: none; }   /* Continue, on the next section's row (docs/PLAN_INTERVIEW.md item 05) */
.check-row.next { padding: 8px 0; }
.home-less { margin: 0 0 var(--sp-3); }
.home-less .less-word { margin: 0; padding-top: var(--sp-2); border-top: 1px solid var(--rule-strong); }
.home-less .less-list { margin: 0 0 var(--sp-2); }
.home-less .applies-line { margin: 4px 0 0; }
.home-change { max-width: 62ch; margin: var(--sp-3) 0 var(--sp-2); }
.home-change .hint { margin: 0; }
.home-change-list { max-width: 62ch; }
.home-sections { margin: 0 0 var(--sp-3); }
.check-sub { padding: 2px 0 6px 1.2em; margin-left: var(--sp-2); color: var(--ink-2); font-size: var(--fs-small); border-bottom: 1px solid var(--rule); }   /* a second line under a checklist row (1.15.0 item 9): indented past the tick, quiet */   /* a link keeps the link colour: scoping the grey to span leaves it alone */

/* the main pane: the pane's head on the canvas, content in panels */
/* THE PANE'S HEAD (docs/PLAN_NAVIGATION.md item 03; ui/DESIGN.md §10). Every screen opens with
   where it is and what it is called, drawn by the shell (paneHead in ui/js/base.js): the trail
   in mono at --fs-tiny in --ink-3, as words and not an eyebrow, so not in capitals; then the
   title's line, the tab's word as the one h1 in the display face, and beside it whatever the
   room heads its screen with -- Retirement's scenario, badges, Run and More ▾ at the line's
   end, the today's plan badge where the household's base is what the screen answers with --
   wrapping under the title on a narrow window. A rule under the line closes the head, as the
   tab row's underline did. It replaces the room's own heads and the tab row, whose rules went
   with them: the menu at the left is where the tabs are now. */
.pane-head { margin: 0 0 var(--sp-5); }
.pane-trail { font-family: var(--font-mono); font-size: var(--fs-tiny); color: var(--ink-3); letter-spacing: .02em; }
.pane-title { display: flex; align-items: center; gap: var(--sp-2) var(--sp-3); flex-wrap: wrap; padding: var(--sp-1) 0 var(--sp-3); border-bottom: 1px solid var(--rule); }
.pane-title h1 { font-family: var(--font-display); letter-spacing: 0; line-height: 1.2; }
.pane-head .room-line { margin: var(--sp-2) 0 0; color: var(--ink-2); font-size: var(--fs-small); }   /* one line saying what a room is, where a badge with no bearing on it used to be (1.18.4 item 11, #608 B6) */
/* the head's quiet links (item 03): walk through it again on About you's tabs, in place of the
   About you door's foot, and Talk it through instead, which sat in the doors' row */
/* Retirement's pieces of the head. The scenario's name beside the title, the word "scenario"
   before it in the eyebrow's mono: the chooser's button with two scenarios or more (item 04, its
   rules with the scenario list's), the words alone with one. */
.scenario-name { display: inline-flex; align-items: baseline; gap: var(--sp-2); }
.scenario-name .scenario-word { font-family: var(--font-mono); font-size: var(--fs-tiny); color: var(--ink-3); text-transform: uppercase; letter-spacing: .06em; }
.scenario-name .name { font-weight: 600; }
.scenario-head .desc { color: var(--ink-2); }
/* The scenario's actions (1.11.0 item 4): Run and More ▾, at the right of the title's line, the
   way TrueNAS puts a screen's one action (D1). Wrapped under the title on a narrow window, they
   keep to the right. */
.pane-title .toolbar { margin: 0 0 0 auto; }
/* About (1.11.0 item 5): reference material about the scenario, closed until it is asked
   for, in the head under the line it renames rather than at the foot of Summary. Its own
   line, so opening it never reflows the name or the actions above it. */
.scenario-head .about { margin: var(--sp-2) 0 0; }
.scenario-head .about > summary { cursor: pointer; color: var(--ink-2); font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 500; text-transform: uppercase; letter-spacing: .04em; }
.scenario-head .about > summary:hover { color: var(--ink); }
.scenario-head .about .kv { margin: var(--sp-2) 0 0; }
/* Summary's two groups (1.11.0 item 5). The group head is the level that is new, so it
   takes the report's section treatment -- the display face over a rule -- which the design
   already specifies and a reader has already seen. The sections inside keep the weight and
   the size they had as h2s: nothing on the page reads smaller than it did, and the spans
   set inside those heads (the stale badge, the hover hint) keep their case and family. */
h2.group { font-family: var(--font-display); font-size: var(--fs-h2); letter-spacing: 0; border-bottom: 1px solid var(--rule-strong); padding-bottom: 6px; margin: var(--sp-6) 0 var(--sp-3); }
.group-body > h3 { font-family: var(--font-ui); font-size: var(--fs-h2); font-weight: 600; color: var(--ink); text-transform: none; letter-spacing: -0.005em; margin: var(--sp-5) 0 var(--sp-2); }
.group-body > h3:first-child { margin-top: 0; }
.toolbar { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; margin: 0 0 var(--sp-4); }
.toolbar .spacer { flex: 1; }
/* The pane (1.11.0 item 6), on Year by year alone: the table fills the height left under the
   toolbar and scrolls inside itself, so the page stops growing with the household's horizon.
   It was renderGrid's .grid-wrap, which already overflowed under a sticky head (section 1.6),
   and all that was missing was a height for the wrapper to be given. Since docs/PLAN_TABULATOR.md
   item 04 the table is ui/js/table.js's .table-wrap, whose library scrolls the rows under its own
   head, and the wrapper takes the same height.

   The cost is two nested scrolls, and the mitigation is that only the grid gets one: the
   pane's own scrollbar appears only when a window is too short to hold the head and the
   toolbar, which is why .main.paned scrolls rather than clips. The aside carries no
   ground of its own -- it is the canvas with a rule down its left -- so the sweep has no new
   painted ground to reach here. The pinned toolbar's ground is --paper, which is the ground
   it was drawn on before. */
.main.paned { display: flex; flex-direction: column; overflow: auto; padding-bottom: var(--sp-4); }
.main.paned > .tab-body { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
.tab-body > .toolbar.pinned { position: sticky; top: 0; z-index: 3; flex: none; background: var(--paper); margin: 0 0 var(--sp-3); padding: 2px 0; }
.pane { flex: 1 1 0; min-height: 0; display: flex; gap: var(--sp-4); align-items: stretch; }
.pane-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.pane-main > .grid-wrap, .pane-main > .table-wrap { flex: 1 1 0; min-height: 180px; }
.pane-aside { flex: 0 0 280px; width: 280px; min-height: 0; overflow: auto; border-left: 1px solid var(--rule); padding-left: var(--sp-4); }
.pane-aside .flags-legend { display: block; }
.pane-aside .flags-legend > span { display: block; margin: 0 0 4px; }
/* Compare's year-over-year pivot is one row per year and the only thing on that screen that
   grows with the horizon, so it is capped rather than given a pane (ui/js/rooms/retirement/compare.js). */
.grid-wrap.capped { max-height: 55vh; }
/* Summary's charts, two up: three views of the same forty years, and two side by side can be
   held against each other where three cannot show forty years legibly at this width. An odd
   third takes the full row, which is what the heatmap below them does too. */
.charts-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); align-items: start; }
.charts-two > .chart { margin: 0; }
.charts-two > .chart:last-child:nth-child(odd) { grid-column: 1 / -1; }
.charts-two.stacked { grid-template-columns: minmax(0, 1fr); }   /* the reader's choice, one under another (#1176; ui/js/charts.js) */
/* drawn just before the run's heading and floated, so it stands at the heading's right on its line; the grid clears it */
.charts-layout { float: right; margin: var(--sp-3) 0 0 var(--sp-3); font-size: var(--fs-small); color: var(--ink-2); white-space: nowrap; }
.charts-layout select { margin-left: 4px; }
.charts-two { clear: both; }
/* the Results column picker (v1.2.0): a grouped checklist under a toolbar button */
.column-picker { position: relative; }
.column-picker summary { list-style: none; }
.column-picker summary::-webkit-details-marker { display: none; }
.column-picker .menu { position: absolute; right: 0; top: 36px; z-index: 20; background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px 12px; display: grid; grid-template-columns: repeat(3, max-content); gap: 8px 22px; max-width: min(90vw, 760px); }
.column-picker .group-name { font-family: var(--font-mono); font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-2); margin: 2px 0 4px; }
.column-picker .group label { display: flex; flex-direction: row; align-items: center; gap: 6px; font-size: var(--fs-small); white-space: nowrap; padding: 1px 0; cursor: pointer; }
.column-picker .menu-foot { grid-column: 1 / -1; display: flex; gap: 12px; align-items: center; justify-content: space-between; border-top: 1px solid var(--rule); padding-top: 8px; }
/* The picker lives on Year by year, whose pane clips what overflows it (1.11.0 item 6), so
   a menu longer than the pane put its foot -- Reset to the default -- out of reach. The suite
   caught it. The menu carries its own height and its own scroll instead. */
.column-picker .menu { max-height: 60vh; overflow: auto; }
/* three levels, and each is a left edge over a wash -- the same shape as a
   warned row, so a reader who has learnt one has learnt the other */
.banner { padding: 8px 12px; border-radius: var(--radius); border: 1px solid var(--rule); border-left: 3px solid var(--limit-edge); background: var(--limit-wash); margin: 0 0 var(--sp-4); display: flex; gap: 12px; align-items: center; }
.banner.info { background: var(--mark-wash); border-left-color: var(--mark); }
.banner.error { background: var(--shortfall-wash); border-left-color: var(--shortfall-edge); }
.banner[hidden] { display: none; }   /* a banner kept on the page for an error not yet met is drawn as display: flex above, so hidden needs saying (the Set up's, docs/PLAN_SETUP.md; the conversation's drew an empty bar the same way) */

.banner.issues { align-items: flex-start; }
.issue-list { margin: 4px 0 0; padding-left: 18px; }
.issue-list li { margin: 3px 0; }
.issue-fix { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-left: 8px; }

/* the metric strip */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--sp-3); margin: var(--sp-2) 0 var(--sp-5); }
.card { background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); padding: 12px 16px 14px; }
.card .label { font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 500; color: var(--ink-2); text-transform: uppercase; letter-spacing: .06em; }
.card .value { font-size: var(--fs-value); font-weight: 600; margin-top: 4px; font-variant-numeric: tabular-nums; letter-spacing: -0.015em; line-height: 1.2; }
.card .sub { font-size: var(--fs-small); color: var(--ink-2); margin-top: 4px; font-variant-numeric: tabular-nums; }
/* On the Front Door a card's line in today's dollars is drawn at the value's own size and ink, not muted, so that the two
   figures read as a pair and the label between them says which is which (docs/PLAN_PROSPEROUS.md A8, O16, Q18) */
.home-blocks .card .sub.today { color: var(--ink); }
.home-blocks .card .sub.today .fig { font-size: var(--fs-value); font-weight: 600; line-height: 1.2; letter-spacing: -0.015em; }
.home-blocks .card .sub.today .words { color: var(--ink-2); }
.legend-key { display: flex; gap: 14px; font-size: var(--fs-small); color: var(--ink-2); margin: 0 0 var(--sp-2); flex-wrap: wrap; }
.legend-key .sw { display: inline-block; width: 12px; height: 12px; border-radius: var(--radius); vertical-align: -2px; margin-right: 4px; border: 1px solid var(--rule-strong); }
.sw.own { background: linear-gradient(225deg, var(--own-edge) 0 6px, transparent 6px) no-repeat, var(--own-wash); border-color: var(--own-edge); }
.sw.ancestor { background: var(--inherited-wash); border-color: var(--inherited-edge); border-left-width: 3px; }
.sw.explicit { background: transparent; border-color: var(--rule-strong); border-left: 3px solid var(--explicit-edge); }

/* panels and tables: 32px rows, sticky header, right-aligned tabular numbers */
.panel { background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); }
.grid-wrap { overflow: auto; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper-raised); max-width: 100%; }
table.grid { border-collapse: separate; border-spacing: 0; width: 100%; font-variant-numeric: tabular-nums; font-size: var(--fs); }
table.grid th, table.grid td { padding: var(--cell-pad); border-bottom: 1px solid var(--rule); text-align: left; white-space: nowrap; vertical-align: middle; height: var(--row-h); }
table.grid th { position: sticky; top: 0; z-index: 1; background: var(--paper-sunken); font-family: var(--font-mono); font-weight: 600; font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); padding: var(--head-pad); height: 36px; }   /* mono is the label face; the head's text is unchanged, only its case is drawn */
table.grid th.group { text-align: center; border-left: 1px solid var(--rule-strong); color: var(--ink); letter-spacing: .06em; }
table.grid thead tr + tr th { top: 36px; }
/* A head that sorts (docs/PLAN_1.27.0.md item 1): its label is a button drawn as the head's own
   text, and the arrow is drawn from aria-sort, so the head's words are its label and nothing
   else -- which is what a reader's eye, a screen reader and the suite each read. No ground of
   its own: the button is transparent on the head's. */
table.grid th button.head-sort { font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; text-align: inherit; }
table.grid th button.head-sort:hover { color: var(--ink); }
table.grid th[aria-sort=ascending] button.head-sort::after { content: ' \2191'; }
table.grid th[aria-sort=descending] button.head-sort::after { content: ' \2193'; }
table.grid td.num, table.grid th.num { text-align: right; }
table.grid tbody tr:nth-child(even) td { background-color: var(--paper-stripe); }
table.grid tbody tr:hover td { background-color: var(--paper-sunken-2); }
table.grid td.editable { cursor: text; }
table.grid td.editable:hover { outline: 1px dashed var(--rule-strong); outline-offset: -2px; }
/* Provenance, and the one place the marks are composed. Up to three can land on
   one cell -- paintCell adds own or ancestor, then explicit on top of either,
   then frozen on top of that -- and two rules that both set box-shadow do not
   compose, the later one simply wins. Before 1.10.0 a frozen own cell lost its
   provenance edge to the frozen underline for exactly that reason. Each state
   now sets one custom property and this rule draws them together, so adding a
   fourth is a variable rather than a combinatorial rule. */
table.grid td, .kv .v {
  background-image: var(--cell-tick, none), var(--cell-edge, none), var(--cell-underline, none), var(--cell-overline, none);
  background-size: 100% 100%, 3px 100%, 100% 3px, 100% 3px;
  background-position: 0 0, 0 0, 0 100%, 0 0;
  background-repeat: no-repeat;
}
table.grid td.own, .kv .v.own, table.grid.ss-claim tr.own td { background-color: var(--own-wash) !important; --cell-tick: linear-gradient(225deg, var(--own-edge) 0 7px, transparent 7px); }   /* ss-claim: the claim month in force, People tab */
table.grid td.ancestor, .kv .v.ancestor { background-color: var(--inherited-wash) !important; --cell-edge: linear-gradient(var(--inherited-edge) 0 0); }
table.grid td.explicit { --cell-edge: linear-gradient(var(--explicit-edge) 0 0); }   /* a left edge and no wash: explicit is the plan's own value, not an override of one */
table.grid td.frozen { --cell-underline: linear-gradient(var(--frozen-edge) 0 0); }
/* Not saved yet (docs/PLAN_1.27.0.md item 3, DESIGN.md §6): a value set on many lines at once
   waits for Apply, on the accent's wash under a solid 3px line along the cell's top; one the store
   refused at Apply keeps waiting, on the shortfall's wash under the same line dashed, so the two
   differ in shape as well as hue. The fourth slot, which is the whole of adding them. */
table.grid td.waiting { background-color: var(--mark-wash) !important; --cell-overline: linear-gradient(var(--mark-edge) 0 0); }
table.grid td.refused { background-color: var(--shortfall-wash) !important; --cell-overline: repeating-linear-gradient(90deg, var(--shortfall-edge) 0 6px, transparent 6px 10px); }
table.grid td input.pick, table.grid th input.pick-all { width: 14px; height: 14px; min-height: 0; margin: 0 8px 0 0; padding: 0; vertical-align: -2px; accent-color: var(--mark); cursor: pointer; }   /* the box that chooses a line, in the line's first cell (docs/PLAN_1.27.0.md item 4) */
.apply-bar { position: sticky; top: 0; z-index: 4; display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--sp-2); margin: 0 0 var(--sp-2); padding: 6px 12px; background: var(--paper-raised); border: 1px solid var(--rule); border-left: 3px solid var(--mark-edge); border-radius: var(--radius); font-size: var(--fs-small); }
.apply-bar[hidden] { display: none; }
.apply-bar .apply-said { margin-right: var(--sp-2); }
/* Marks on Categories (1.17.0 item 5): a line the two people see differently takes the limit
   edge on both mark cells, the same left edge the row warning and the banner use; the other
   person's column, folded until you have marked once, is one sunken cell with the sentence,
   the locked cell's ground and a wrapped line where every other cell is one; the note behind
   your mark is a small control in the cell, a button that reads as a term does. */
table.grid td.differ { --cell-edge: linear-gradient(var(--limit-edge) 0 0); }
table.grid td.mark-fold { background-color: var(--paper-sunken) !important; color: var(--ink-3); white-space: normal; vertical-align: top; max-width: 180px; font-size: var(--fs-small); line-height: 1.4; border-bottom-color: transparent; }   /* one cell per row, the rules between them dropped, so the column reads as one */
table.grid tbody tr:last-child td.mark-fold { border-bottom-color: var(--rule); }
table.grid td.mark .note-btn { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; margin-left: 6px; cursor: pointer; }
table.grid td.mark .note-btn:hover { color: var(--ink); }
table.grid td.mark .note-mark { font-size: var(--fs-tiny); color: var(--ink-2); }
.differ-line { margin: 0 0 var(--sp-2); }
/* The household line (1.17.0 item 7): under Spending's head and above Retirement's scenario
   head, one quiet line in two halves -- the open facts as links, then each person's word.
   Your word is a select drawn as text; the other's is text; what moved since is italic and
   fainter. It prints as it stands (acceptance 14: nothing new joins the hide list), and the
   Report tab draws none. */
.household-line { margin: calc(-1 * var(--sp-3)) 0 var(--sp-4); font-size: var(--fs-small); color: var(--ink-2); line-height: 1.6; }
.household-line .word b { color: var(--ink); font-weight: 600; }
.household-line .since { color: var(--ink-3); }
.household-line select.word-select { font: inherit; color: var(--ink); background: var(--paper-sunken); border: 1px solid var(--rule); border-radius: var(--radius); padding: 0 4px; height: 22px; }
.household-line button.word-line, .household-line button.word-again { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; cursor: pointer; }
.household-line button.word-line:hover, .household-line button.word-again:hover { color: var(--ink); }
/* The list's rows (1.17.0 item 8): the product's steps, the household's tasks and notes, a thread under each, one field at
   the foot. A done task is greyed and struck, kept for the session. Nothing numbers or ranks the rows. They were a closed
   disclosure under each room's line and on the Front Door until docs/PLAN_WAITING.md items 02 and 03, and are What's
   waiting's panel's now (ui/js/rooms.js draws them, ui/js/waiting.js holds them). */
#waiting-panel .list-row .because { color: var(--ink-2); }
#waiting-panel .list-row .whose { color: var(--ink-2); }
#waiting-panel .list-row.done .item-body { color: var(--ink-3); text-decoration: line-through; }
#waiting-panel .list-row .tick { margin: 0 6px 0 0; vertical-align: -1px; }
#waiting-panel button.leave, #waiting-panel button.change, #waiting-panel button.delete { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; cursor: pointer; }
#waiting-panel button.leave:hover, #waiting-panel button.change:hover, #waiting-panel button.delete:hover { color: var(--ink); }
#waiting-panel .thread { margin: 4px 0 0 var(--sp-4); }
#waiting-panel .thread .reply { padding: 2px 0; color: var(--ink-2); }
#waiting-panel .thread .reply .item-body { color: var(--ink); }
#waiting-panel form.task-add, #waiting-panel form.reply-add { display: flex; gap: 6px; align-items: center; margin: var(--sp-2) 0 0; flex-wrap: wrap; }
#waiting-panel form input[name=body] { flex: 1 1 18ch; min-width: 12ch; font: inherit; font-size: var(--fs-small); padding: 3px 6px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }
#waiting-panel form select { font: inherit; font-size: var(--fs-small); background: var(--paper-sunken); color: var(--ink); border: 1px solid var(--rule); border-radius: var(--radius); height: 26px; }
.about-task { margin: var(--sp-2) 0 0; }
table.grid td .task-btn { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; margin-left: 6px; cursor: pointer; }
table.grid td .task-btn:hover { color: var(--ink); }
/* Less on Categories (1.17.0 item 6): the prose above the grid under one disclosure, drawn as
   the answers key is; All columns where Retirement's Show everything sits, at the row's end;
   a row that opens its own reading shows the hand off its editors. */
.more-about { margin: 0 0 var(--sp-3); }
.more-about > summary { cursor: pointer; color: var(--ink-2); font-size: var(--fs-small); }
.more-about > .hint, .more-about > .answers-key, .more-about > .legend-key { margin-top: var(--sp-2); }
.columns-line { margin: 0 0 var(--sp-2); text-align: right; font-size: var(--fs-small); }
/* Search and filter on Categories (docs/PLAN_1.27.0.md item 2): the box and the two quick
   filters at the left of the line All columns ends, n of m under them while a line is hidden,
   and a column's filter as a small triangle beside its head's label -- drawn, so the head's
   text is still its label -- which opens a list on the raised ground a dialog uses. A filter
   that is set marks its triangle in the accent; a quick filter that is on is pressed. */
.view-line { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-4); margin: 0 0 var(--sp-2); }
.view-line .columns-line { margin: 0; }
.view-find { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.view-find input.cat-search { width: 26ch; }
.btn[aria-pressed=true] { background: var(--mark-wash); border-color: var(--mark); }
.shown-line { margin: 0 0 var(--sp-2); font-size: var(--fs-small); color: var(--ink-2); }
table.grid th button.head-filter { font: inherit; color: var(--ink-3); background: none; border: 0; padding: 0 2px; margin: 0 0 0 4px; cursor: pointer; line-height: 1; }
table.grid th button.head-filter::before { content: '\25BE'; }
table.grid th button.head-filter:hover, table.grid th button.head-filter[aria-expanded=true] { color: var(--ink); }
table.grid th button.head-filter.on { color: var(--mark); }
.filter-pop { position: fixed; z-index: 20; min-width: 200px; max-width: 280px; max-height: 50vh; overflow: auto; padding: var(--sp-2) var(--sp-3); background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--radius); box-shadow: var(--shadow); font-size: var(--fs-small); color: var(--ink); }
.filter-pop .tick { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; }
.filter-pop .tick input { margin: 0; accent-color: var(--mark); }
.filter-pop .tick .count { margin-left: auto; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.filter-pop .filter-foot { margin: var(--sp-2) 0 0; padding-top: var(--sp-2); border-top: 1px solid var(--rule); }
table.grid tr.about td:not(.editable):not(.editing) { cursor: pointer; }
table.grid tr.about td:first-child .line-mark { cursor: pointer; }
/* A row-level warning, and it is a rule rather than one tab's special case.
   An edge on the row and a bordered mono tag in the cell that causes it, with
   the explanation once below the grid on the same edge. Never another wash:
   a wash on a cell already means provenance, and a second meaning for the
   same device would collapse both. */
table.grid tbody tr.warn td:first-child { box-shadow: inset 3px 0 0 var(--limit-edge); }
.warn-tag { display: inline-block; margin-left: 8px; padding: 0 5px; font-family: var(--font-mono); font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--limit); border: 1px solid var(--limit-edge); line-height: 1.4; vertical-align: 1px; }
.grid-note.warn { border-left: 3px solid var(--limit-edge); padding: 2px 0 2px 10px; margin: var(--sp-2) 0 0; color: var(--ink-2); font-size: var(--fs-small); }
.sw.frozen { background: var(--frozen-wash); border-color: var(--frozen-edge); }
.badge.frozen { background: var(--frozen-wash); border-color: var(--frozen-edge); color: var(--ink); }
.badge.unfunded { background: var(--shortfall-wash); border-color: var(--shortfall); color: var(--ink); }   /* the last run left a month unpaid (v1.4.0) */
.badge.optimising { background: var(--mark-wash); border-color: var(--mark); color: var(--ink); }   /* an optimisation that has not finished (audit OPT-1) */
table.grid td.readonly { color: var(--ink-2); }
/* locked: a real value, and this is not the place to type it. Sunken ground and
   ink-3, upright -- no wash and no mark, because it is not provenance and must
   not read as one, and not the grey italics of derived either, which can be
   typed over. The reason is on the title, from the column's lockedTitle. */
table.grid td.locked, .kv .v.locked { background-color: var(--paper-sunken) !important; color: var(--ink-3); cursor: default; }
table.grid td.actions { text-align: right; padding-top: 1px; padding-bottom: 1px; }   /* a 28px row button inside 6px of cell padding made a 41px row, so Accounts and Income ran nine pixels taller than every other grid */
table.grid tr.removed td { text-decoration: line-through; color: var(--ink-3); }
table.grid tr.outside td { color: var(--ink-3); font-style: italic; }
table.grid td.editing { padding: 0; }
table.grid td.editing input, table.grid td.editing select { width: 100%; min-width: 90px; min-height: 0; height: var(--row-h); border-radius: var(--radius); border: 2px solid var(--mark); padding: 3px 10px; outline: none; }
table.grid td .null { color: var(--ink-3); }
table.grid tfoot td { background-color: var(--paper-sunken); font-weight: 600; border-top: 2px solid var(--rule-strong); }
/* THE TABLE TABULATOR DRAWS (docs/PLAN_TABULATOR.md item 03; ui/js/table.js; ui/DESIGN.md
   §10, "The table Tabulator draws"). Year by year's, and no other. The library's own sheet,
   ui/js/vendor/tabulator/tabulator.css, is linked before this one in ui/index.html and lays the
   table out; every colour it sets on a part the registered modules can put on the screen is
   replaced here, light and dark, so the table reads as table.grid above and the contrast sweep
   measures grounds it knows -- a literal left from that sheet would be a ground it was never
   told about. The sheet's other literals are for modules ui/js/table.js does not register (the
   footer, pages, groups, calcs, menus, popups, editors, the library's print table) and draw
   nothing here. Tokens only: these rules hold no colour of their own.
   The table's ground is --paper-raised, its rows striped --paper-stripe, a hovered row
   --paper-sunken-2, the head --paper-sunken in the mono face as table.grid th; the pinned
   column's edge is a --rule; a selected block is --mark-wash inside a --mark-edge, the mark's
   colours, as a chosen line's is in Categories' bulk line. */
.table-wrap { display: flex; flex-direction: column; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper-raised); max-width: 100%; overflow: hidden; }
.table-wrap > .table-host { flex: 1 1 auto; min-height: 0; }
.table-wrap .tabulator { background-color: var(--paper-raised); border: 0; border-radius: 0; color: var(--ink); font-size: var(--fs); font-variant-numeric: tabular-nums; }
.table-wrap .tabulator .tabulator-header { background-color: var(--paper-sunken); border-bottom: 1px solid var(--rule); color: var(--ink-2); font-weight: 600; }
.table-wrap .tabulator .tabulator-header .tabulator-col { background: var(--paper-sunken); border-right: 0; color: var(--ink-2); font-family: var(--font-mono); font-weight: 600; font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: .04em; }   /* the head's text is unchanged, only its case is drawn (§10, Tables) */
.table-wrap .tabulator .tabulator-header .tabulator-col .tabulator-col-content { padding: var(--head-pad); }
.table-wrap .tabulator .tabulator-header .tabulator-col.tabulator-range-highlight { background-color: var(--paper-sunken-2); color: var(--ink); }   /* the heads over a selected block */
.table-wrap .tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left, .table-wrap .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left { border-right: 1px solid var(--rule); }
.table-wrap .tabulator .tabulator-tableholder .tabulator-table { background-color: var(--paper-raised); color: var(--ink); }
.table-wrap .tabulator-row { background-color: var(--paper-raised); min-height: var(--row-h); border-bottom: 1px solid var(--rule); }
.table-wrap .tabulator-row.tabulator-row-even { background-color: var(--paper-stripe); }
.table-wrap .tabulator-row:hover { background-color: var(--paper-sunken-2); }
.table-wrap .tabulator-row .tabulator-cell { padding: var(--cell-pad); border-right: 0; }
.table-wrap .tabulator-row .tabulator-cell.num { text-align: right; }
.table-wrap .tabulator-row .tabulator-cell .null { color: var(--ink-3); }
.table-wrap .tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header) { background-color: var(--mark-wash); }
.table-wrap .tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range { border: 1px solid var(--mark-edge); }
.table-wrap .tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active { border: 2px solid var(--mark-edge); }
.table-wrap .tabulator .tabulator-col-resize-guide { background-color: var(--mark-edge); }
.table-wrap .tabulator .tabulator-tableholder .tabulator-placeholder .empty { color: var(--ink-3); }
.cell-menu { position: absolute; background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow); padding: 4px; z-index: 20; display: flex; flex-direction: column; min-width: 160px; }
.cell-menu button { text-align: left; border: none; background: none; padding: 6px 10px; cursor: pointer; border-radius: var(--radius); color: var(--ink); }
.cell-menu button:hover { background: var(--paper-sunken-2); }
.cell-menu .menu-hint { font-size: var(--fs-tiny); color: var(--ink-2); padding: 2px 10px 6px; }
.add-row { display: flex; gap: var(--sp-2); align-items: end; flex-wrap: wrap; margin-top: var(--sp-3); padding: 10px 12px; border: 1px dashed var(--rule-strong); border-radius: var(--radius); background: var(--paper-raised); }
.add-row .field { min-width: 120px; }
.kv { display: grid; grid-template-columns: 280px 1fr; gap: 0; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper-raised); overflow: hidden; }
.kv > div { padding: var(--cell-pad); border-bottom: 1px solid var(--rule); min-height: var(--row-h); display: flex; flex-direction: column; justify-content: center; }
.kv > div:nth-last-child(-n+2) { border-bottom: none; }
.kv > div:nth-child(4n+1), .kv > div:nth-child(4n+2) { background: var(--paper-stripe); }
.kv .k { color: var(--ink-2); font-size: var(--fs-small); }
.kv .k small { display: block; color: var(--ink-3); font-size: var(--fs-tiny); }   /* the floor, not the browser's `smaller`, which took a hint inside a --fs-tiny label to 10.83px (1.18.2 item 3, #585) */
.kv .v { font-variant-numeric: tabular-nums; }
.kv .v.editable { cursor: text; }
.kv .v input, .kv .v select { width: 100%; }

/* flags */
.flag { display: inline-block; width: 10px; height: 10px; border-radius: var(--radius); margin-right: 3px; vertical-align: -1px; border: 1px solid transparent; }
.flag.on-critical { background: var(--shortfall); } .flag.on-serious { background: var(--serious); } .flag.on-warning { background: var(--limit); } .flag.on-good { background: var(--settled); }
.flag.off { background: transparent; border-color: var(--rule-strong); }
.flags-legend { font-size: var(--fs-small); color: var(--ink-2); display: flex; gap: 12px; flex-wrap: wrap; margin: var(--sp-2) 0; }

/* charts: a panel with a header row (title left, legend right) */
.chart { background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); padding: var(--panel-pad); padding-bottom: 10px; margin: 0 0 var(--sp-3); position: relative; }
.chart .chart-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: 8px; padding-bottom: 6px; border-bottom: 1px solid var(--rule-soft); }
.chart h3 { margin: 0; color: var(--ink); font-family: var(--font-display); text-transform: none; letter-spacing: 0; font-size: var(--fs-h2); font-weight: 600; }
.chart svg { width: 100%; height: auto; display: block; overflow: visible; font-family: var(--font-ui); }
/* the axis ink is the label ink and the gridlines are the softest rule, so the
   grid sits behind the data in both themes instead of competing with it */
/* OFF THE SCALE, AND ON PURPOSE (1.18.2 item 3, #585). The two rules below and the Sankey's
   label in the Spending room are the only type in the interface not taken from the five steps
   in theme.css. They are drawn inside a chart's frame and measured in that frame's user units
   rather than in the page's, so they are laid out against the drawing and not against the text
   around them; and docs/audit/ui/15_chart_type_at_width.mjs asks that every axis label arrive
   between 9.5px and 10.5px, which is the auditor's reading of #504 and not a release's to move.
   Written here because an exception nobody wrote down is how six sizes became eleven. */
.chart .axis text { fill: var(--ink-2); font-family: var(--font-mono); font-size: calc(10px * var(--u, 1)); letter-spacing: .02em; font-variant-numeric: tabular-nums; }   /* --u is the frame's user units per pixel, set on the svg by ui/js/charts.js: the type is 10px at whatever width the column gives the chart (#504) */
.chart .axis line, .chart .gridline { stroke: var(--rule-soft); stroke-width: 1; }
.chart .series { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* A dashed series takes butt caps (CG-3, #301): a round cap grows every dash by the stroke
   width at each end, which closes the 1.5-long dot up into a near-solid line. The solid
   slot keeps its round caps, and is the only path without the attribute. */
.chart .series[stroke-dasharray] { stroke-linecap: butt; }
.chart .legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: var(--fs-small); color: var(--ink-2); }
/* today's dollars (docs/PLAN_PROSPEROUS.md A8): the unit the chart is drawn in, beside the title, and the toggle that
   flips it, at the head's right in the legend's size and ink */
.chart .chart-unit { flex: 1 1 auto; font-size: var(--fs-small); color: var(--ink-2); }
.chart .chart-today { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-small); color: var(--ink-2); cursor: pointer; white-space: nowrap; }
.chart .chart-today input { margin: 0; }
/* a page's own control for today's dollars, where a table and its charts share one unit (A8, D22) */
.today-control { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-small); color: var(--ink-2); cursor: pointer; white-space: nowrap; }
.today-control input { margin: 0; }
/* the header's switch for every one of them (#1167; ui/js/today.js), in the same words and the same size */
.today-all { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-small); color: var(--ink-2); cursor: pointer; white-space: nowrap; margin-right: var(--sp-2); }
.today-all input { margin: 0; }
/* on a phone the header has no room for it beside Rōshi, the bell and the household: the same switch is drawn at the
   foot of the menu instead, beside Mode, and the header's is not (#1167) */
.today-all-foot { display: none; }
@media (max-width: 520px) { .topbar .today-all { display: none; } .today-all-foot { display: inline-flex; align-items: center; gap: 6px; } }
/* The key is the line's own stroke, drawn, rather than a block of its colour: a swatch
   filled with the hue is itself keyed by hue (CG-3, #301). */
.chart .legend .sw, .chart .tooltip .sw { display: inline-block; width: 24px; height: 8px; vertical-align: -1px; margin-right: 5px; overflow: visible; }
.chart .sw line { stroke-width: 2; stroke-linecap: butt; }
/* stacked bars (#1182): a filled key, since a bar is a fill and not a stroke; the bars are parted by a hairline of the
   paper so two neighbouring inks read as two parts */
.chart .sw.sw-fill { width: 12px; height: 10px; }
.chart .bar { stroke: var(--paper-raised); stroke-width: 0.75; }
.chart .tooltip { position: absolute; pointer-events: none; background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); padding: 6px 10px; font-size: var(--fs-small); box-shadow: var(--shadow); display: none; z-index: 5; white-space: nowrap; color: var(--ink); font-variant-numeric: tabular-nums; }
.chart .tooltip .row { display: flex; justify-content: space-between; gap: 14px; }
.chart .crosshair { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 2 3; display: none; }
.chart .marker { display: none; stroke: var(--paper-raised); stroke-width: 2; }
/* The limits heatmap as a chart (1.17.0 item 2, D20): an SVG in the line charts' frame, the
   row labels set as the axis figures are and the cells filled with the flag levels' inks --
   the same four tokens .flag above takes, so nothing new is painted. It replaced a table,
   .heat, whose stripe was the grid's stripe. */
.chart.heat text.rowh { fill: var(--ink); font-family: var(--font-mono); font-size: calc(10px * var(--u, 1)); letter-spacing: .02em; }
.chart.heat rect.cell.on-critical { fill: var(--shortfall); } .chart.heat rect.cell.on-serious { fill: var(--serious); } .chart.heat rect.cell.on-warning { fill: var(--limit); } .chart.heat rect.cell.on-good { fill: var(--settled); }
.chart.heat rect.cell.off { fill: none; stroke: var(--rule-strong); stroke-width: 1; }
.chart .chart-head .flags-legend { margin: 0; }

/* reports */

/* the progress overlay: locks the page while scenarios run */
.progress[hidden] { display: none; }
.progress { position: fixed; inset: 0; z-index: 90; background: var(--backdrop); display: flex; align-items: center; justify-content: center; }
/* The run overlay locks the page, and it is the one moment the interface asks
   for patience. Deliberate rather than apologetic: the mark above a serif title,
   the step in mono, a square bar, and no rounded corner anywhere to soften it. */
.progress-box { background: var(--paper-raised); border: 1px solid var(--rule-strong); border-top: 3px solid var(--mark); border-radius: var(--radius); box-shadow: var(--shadow); padding: var(--sp-6) var(--sp-6) var(--sp-5); min-width: 380px; max-width: 560px; }
.progress-box::before { content: ''; display: block; width: 40px; height: 40px; margin: 0 0 var(--sp-3); background: var(--mark-image) left center / contain no-repeat; }
.progress-title { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-h1); line-height: 1.2; }
.progress-step { color: var(--ink-2); font-family: var(--font-mono); font-size: var(--fs-small); min-height: 18px; margin-top: 6px; }
.progress-bar { height: 4px; background: var(--paper-sunken-2); border-radius: var(--radius); margin: var(--sp-4) 0 var(--sp-2); overflow: hidden; position: relative; }
.progress-bar span { display: block; height: 100%; width: 0; background: var(--mark); border-radius: var(--radius); transition: width var(--dur-enter) var(--ease); }
.progress-bar.indeterminate span { width: 35% !important; position: absolute; animation: progress-slide 1.4s ease-in-out infinite; }
@keyframes progress-slide { 0% { left: -35%; } 100% { left: 100%; } }
body.busy { cursor: progress; }

/* ☰ folds the menu to its icons (docs/PLAN_NAVIGATION.md item 02); the rules are the menu's, above */
.rail-toggle { padding: 0 8px; font-size: var(--fs); line-height: 1; }

/* a value nobody typed: a default or what the last run did */
table.grid td.derived, .kv .v.derived { color: var(--ink-faint); font-style: italic; }
table.grid td.derived.own, table.grid td.derived.ancestor { font-style: normal; color: var(--ink); }

/* toasts, dialogs */
.toasts { position: fixed; right: 16px; bottom: 16px; display: flex; flex-direction: column; gap: 8px; z-index: 50; }
.toast { background: var(--paper-raised); border: 1px solid var(--rule); border-left: 3px solid var(--mark); border-radius: var(--radius); padding: 8px 12px; max-width: 460px; box-shadow: var(--shadow); }
.toast.error { border-left-color: var(--shortfall-edge); }
.toast.ok { border-left-color: var(--settled-edge); }
.toast.stay { display: flex; gap: 12px; align-items: flex-start; }
.toast.stay .toast-close { flex: none; }
dialog { border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper-raised); color: var(--ink); min-width: 420px; max-width: 640px; box-shadow: var(--shadow); padding: var(--sp-5); }
/* A dialog holding a document rather than a note (#572): wide enough that a book's table
   rows and a figure's alignment are visible while they are being written, and still inside
   the window on a laptop. The face is mono because what is typed here carries marks whose
   columns have to line up -- the pipes of a table, the spacing of a figure. */
dialog.wide { max-width: min(94vw, 96ch); }
.dialog-form textarea { font: inherit; padding: 6px 8px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); resize: vertical; }
.dialog-form textarea.long { font: var(--fs-small)/1.6 var(--font-mono); white-space: pre-wrap; tab-size: 2; max-height: 62vh; }
.add-row .field.wide { flex-basis: 100%; min-width: 0; }
.add-row textarea { font: var(--fs-small)/1.6 var(--font-mono); width: 100%; padding: 6px 8px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); resize: vertical; white-space: pre-wrap; }
/* The household lock (#312, docs/PLAN_1.12.0.md item 5): what a household that
   requires a password draws in place of everything else. It paints --paper-raised,
   which is the ground .empty above already paints, so the contrast gate's list of
   painted grounds does not grow by this rule -- a new token here would need a sweep
   standing on it or a named exemption (ui/dev/e2e.js, PAINTED and NO_TEXT). */
.lock-panel { max-width: 30rem; margin: var(--sp-6) auto; padding: var(--sp-5); background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); }
.lock-panel h1 { margin: 0 0 var(--sp-2); }
.lock-panel .lock-why { color: var(--ink-2); font-size: var(--fs-small); margin: 0 0 var(--sp-4); }
.lock-form { display: flex; flex-direction: column; gap: var(--sp-3); }
.lock-form .btn { align-self: flex-start; }
.lock-panel .banner { margin: var(--sp-3) 0 0; }
/* Who's looking (1.17.0 item 4): the lock panel's shape and ground; the two names as buttons
   side by side and Just looking quieter beneath them, so the third choice reads as the way to
   decline rather than as a third person. */
.who-panel .who-choices { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin: 0 0 var(--sp-3); }
.who-panel .who-choices .btn { height: auto; padding: 10px 18px; font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 600; }
.who-panel .who-looking { margin: 0 0 var(--sp-2); }
.who-panel .hint { margin: 0; }
.mono { font-family: var(--font-mono); font-size: var(--fs-small); }
.muted { color: var(--ink-3); }
.pivot-select { margin-left: auto; }
@media (max-width: 900px) { .pane { flex-direction: column; } .pane-aside { flex: none; width: auto; overflow: visible; border-left: 0; border-top: 1px solid var(--rule); padding: var(--sp-3) 0 0; } .charts-two { grid-template-columns: 1fr; } .sidebar { width: 240px; } .kv { grid-template-columns: 1fr; } .kv > div:nth-child(4n+1), .kv > div:nth-child(4n+2) { background: transparent; } .main { padding: var(--sp-4); } }

/* the scenario report: a printable document */
.report { max-width: 1000px; }
.report .report-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.report .meta { color: var(--ink-2); font-size: var(--fs-small); }
.report section { margin: 0 0 var(--sp-6); }
.report section > h2 { font-family: var(--font-display); font-size: var(--fs-h2); border-bottom: 1px solid var(--rule-strong); padding-bottom: 6px; margin-bottom: var(--sp-3); letter-spacing: 0; }
.report .cards { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
.report .two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.report .cover { padding: var(--sp-5) 0 var(--sp-3); }
.report .cover .mark { width: 64px; height: 64px; margin: 0 0 var(--sp-3); background: var(--mark-image) left center / contain no-repeat; }
.report .cover .title { font-family: var(--font-display); font-size: calc(var(--fs-value) * 1.25); font-weight: 600; letter-spacing: -0.01em; line-height: 1.15; }
.report .cover .sub { font-size: var(--fs); color: var(--ink-2); margin-top: 8px; }
.report .cover .meta, .report .cover .note { max-width: 70ch; }
.report .note { color: var(--ink-2); font-size: var(--fs-small); }
.report ul.plain { margin: 4px 0; padding-left: 18px; }
.report h3 { font-family: var(--font-mono); }
/* the cover for the advisor (docs/PLAN_PROSPEROUS.md B9, D21): the household in five labelled lines, the year, the score, the questions */
.report .cover .cover-head { font-family: var(--font-display); font-size: var(--fs-h2); margin: var(--sp-4) 0 var(--sp-2); }
.report .household-lines { display: grid; grid-template-columns: max-content 1fr; gap: 4px var(--sp-3); margin: 0 0 var(--sp-3); max-width: 80ch; }
.report .household-lines .line { display: contents; }
.report .household-lines dt { font-family: var(--font-mono); color: var(--ink-2); }
.report .household-lines dd { margin: 0; }
.report .cover-figures .hero-year { font-family: var(--font-display); font-size: var(--fs-value); font-weight: 600; }
.report .cover-figures .score-line { margin: 4px 0 var(--sp-3); max-width: 80ch; }
.report ol.questions { margin: 4px 0 var(--sp-3); padding-left: 22px; max-width: 80ch; }
.report .questions-edit textarea { width: 100%; max-width: 80ch; }
.report .closing { font-weight: 600; margin-top: var(--sp-3); }
/* the chance of success, historical (docs/PLAN_PROSPEROUS.md B8): Summary's section, one row a start year that opens */
.backtest .backtest-share { font-family: var(--font-display); font-size: var(--fs-value); }
.backtest .backtest-years { margin: var(--sp-2) 0; }
.backtest .backtest-year { margin: 2px 0 2px var(--sp-3); }
.backtest .backtest-year table { margin: 4px 0 var(--sp-2); }
.lead-block.chance .chance-def { max-width: 46ch; }
/* the chance of success, Monte Carlo (C3): Summary's section as the historical one's, one row a path that opens; and the
   Front Door block's two figures, each under its label, historical and Monte Carlo, the band beside the share in the
   sub-line's ink so that the figure stays the one the eye takes first */
.montecarlo .montecarlo-share { font-family: var(--font-display); font-size: var(--fs-value); }
.montecarlo .montecarlo-band { color: var(--ink-2); }
.montecarlo .montecarlo-paths { margin: var(--sp-2) 0; }
.montecarlo .montecarlo-path { margin: 2px 0 2px var(--sp-3); }
.montecarlo .montecarlo-path table { margin: 4px 0 var(--sp-2); }
.lead-block.chance .chance-row { margin-top: var(--sp-2); }
.lead-block.chance .chance-kind { color: var(--ink-2); font-size: var(--fs-small); font-weight: 600; }
.lead-block.chance .score-value .chance-band { color: var(--ink-2); font-size: var(--fs-small); font-weight: 400; }
/* Print. theme.css resets every token to the light palette here, in all three
   of the on-screen blocks at once, so a report printed from dark mode is ink on
   paper: the rules below read tokens and inherit that, and the page ground is
   the printer's own white rather than the screen's warm paper. */
/* THE NAMES STAND UP, AND ON ONE EDGE (1.18.4 item 9, #608 B4). A name was the body size in
   a run with its own sentence and clause, and the disclosure mark sat inside the name, so
   the names of the rows that open began one character further right than the names of the
   rows that do not. The mark moves into a gutter the row's own padding makes -- present on
   every row and drawn on the ones that open -- and the name takes --fs-h2, so the list gains
   a hierarchy of weight without gaining a heading, a tab or a group. */
details.lib-row > summary { cursor: pointer; list-style: none; }
details.lib-row > summary::-webkit-details-marker { display: none; }
details.lib-row > summary .name::before,
details.lib-row[open] > summary .name::before { content: '▾'; }
/* a video does not open, so its gutter is empty and its name is the link (item 13, B10) */
/* A PLACE TO START, ON ITS OWN LINE (item 12, #608 B7): the row's left edge and ground carry
   it, which is the template's own device, and the clause is a line of its own rather than
   five words on the end of the provenance -- the part of a row that runs off a narrow window
   first. No colour on the type, so the contrast gate has nothing new to read. */
/* a line about an absence is not a row, so it carries neither the gutter nor the rule */
/* A book's own text (#572). Before 1.18.1 a body was drawn as one run of paragraphs, because
   that was all the room could draw; a book long enough to be worth writing is a document, so
   headings, lists, tables and a figure block are drawn here. The rhythm is a reading one and
   not the grid's: a looser line, the display face on the headings, and space above a heading
   that is larger than the space below it, so a heading belongs to what follows. The measure
   stays 62ch -- the width, not the type size, is what makes prose readable. */
/* A SHELF BOOK'S BODY IN THE DISPLAY FACE (1.18.4 item 10, #608 B5): the display face at
   --fs-h2 on 1.6, because a reading is read and the UI face at the UI size is for scanning.
   A glossary book's entries are the exception below: the ten are scanned. */
.book-body { margin: var(--sp-2) 0 var(--sp-2) var(--sp-4); max-width: 62ch; line-height: 1.6; font-family: var(--font-display); font-size: var(--fs-h2); }
.book-body.glossary-body { font-family: var(--font-ui); font-size: var(--fs); }
/* the states, the ask and the thread are the room's own lines and not the book's prose, so
   they keep the UI face whatever the body above them is drawn in */
.book-body .book-states, .book-body .book-ask, .book-body .thread-list { font-family: var(--font-ui); }
.book-body > *:first-child { margin-top: 0; }
.book-body p { margin: 0 0 var(--sp-3); }
/* text-transform and letter-spacing are reset because the page's own h3 (line 89) is a mono
   eyebrow in upper case, which is the wrong thing for a heading inside prose: .chart h3 and
   .group-body > h3 reset the same two for the same reason. */
.book-body h3, .book-body h4 { font-family: var(--font-display); color: var(--ink); font-weight: 600; text-transform: none; letter-spacing: 0; }
.book-body h3 { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-h2); line-height: 1.3; }
.book-body h4 { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs); line-height: 1.35; }
.book-body ul, .book-body ol { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); }
.book-body li { margin: 0 0 var(--sp-1); padding-left: 2px; }
.book-body li::marker { color: var(--ink-3); }
.book-body strong { font-weight: 600; color: var(--ink); }
.book-body em { font-style: italic; }
/* A table is the one block that cannot always be made to fit, so its wrapper scrolls and the
   page does not. Head cells take the rule above and below, as the grids do. */
.book-table { margin: 0 0 var(--sp-3); overflow-x: auto; }
.book-table table { border-collapse: collapse; width: 100%; font-size: var(--fs-small); line-height: 1.45; }
.book-table th, .book-table td { padding: 6px 10px 6px 0; text-align: left; vertical-align: top; border-bottom: 1px solid var(--rule); }
.book-table th { color: var(--ink-2); font-weight: 600; border-bottom: 1px solid var(--rule-strong); white-space: nowrap; }
.book-table tr:last-child td { border-bottom: 0; }
/* A quotation: what a screen says, in the screen's own words. The edge and the indent are what
   tell a reader where the quoting starts and stops, since the type does not change. */
.book-body blockquote { margin: 0 0 var(--sp-3); padding: 2px 0 2px var(--sp-4); border-left: 2px solid var(--rule-strong); color: var(--ink-2); }
.book-body blockquote strong { color: var(--ink-2); }
/* A figure keeps the spacing it was written with: a diagram, a timeline, a ladder of rates.
   It is the one place a book's own line breaks are load-bearing. */
.book-figure { margin: 0 0 var(--sp-3); padding: var(--sp-3) var(--sp-4); overflow-x: auto; background: var(--paper-sunken); border-left: 2px solid var(--rule-strong); font: var(--fs-small)/1.6 var(--font-mono); color: var(--ink-2); white-space: pre; }
@media print {
  .chart .chart-today, .today-control { display: none; }   /* a toggle cannot be pressed on paper; the unit beside the title stays (A8) */
  .book-body h3, .book-body h4 { break-after: avoid-page; }
  .book-table, .book-figure { break-inside: avoid-page; }
}
/* THE OPEN BOOK'S PARTS (1.18.4 item 13, #608 B8). Your read state, the other person's, the
   household's ask and the conversation were one run of small grey, and they are not one kind
   of thing. A hairline closes the prose; your state is at full ink with its control as the
   last clause; the other person's sits beside it, quieter; the ask takes its own line; and
   the thread has air above it. Told apart by weight, ink and space -- nothing here is colour,
   so the four survive the colour being turned off, which is B8's own "done is". */
.book-states { font-size: var(--fs-small); color: var(--ink-2); margin: var(--sp-3) 0 0; padding-top: var(--sp-2); border-top: 1px solid var(--rule); }
.book-ask { font-size: var(--fs-small); color: var(--ink-2); margin: var(--sp-2) 0 0; display: block; }
.book-states .state.mine { color: var(--ink); font-weight: 600; }
.book-states .state.theirs { color: var(--ink-3); }
.book-ask .state.done { color: var(--ink); }
.book-body .thread-list { margin-top: var(--sp-4); }
/* a comment from the person you live with is not metadata: reading size, not --fs-small */
.book-body .thread-list .list-row .body { font-size: var(--fs); }
/* B9: the one control that stands in for the add form until it is tapped */
.thread-list button.note-open { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; cursor: pointer; }
.thread-list button.note-open:hover { color: var(--ink); }
.book-body button.read-toggle, .book-body button.ask-all, .book-body button.delete { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; cursor: pointer; }
.book-body button.read-toggle:hover, .book-body button.ask-all:hover, .book-body button.delete:hover { color: var(--ink); }
.thread-list { font-size: var(--fs-small); }
.thread-list .list-row { padding: 6px 0; border-bottom: 1px solid var(--rule); }
.thread-list .list-row .whose { color: var(--ink-2); }
.thread-list .thread { margin: 4px 0 0 var(--sp-4); }
.thread-list .thread .reply { padding: 2px 0; color: var(--ink-2); }
.thread-list .thread .reply .body { color: var(--ink); }
.thread-list form.note-add, .thread-list form.reply-add { display: flex; gap: 6px; align-items: center; margin: var(--sp-2) 0 0; flex-wrap: wrap; }
.thread-list form input[name=body] { flex: 1 1 18ch; min-width: 12ch; font: inherit; font-size: var(--fs-small); padding: 3px 6px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }
.thread-list button.change, .thread-list button.delete { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; cursor: pointer; }
.thread-list button.change:hover, .thread-list button.delete:hover { color: var(--ink); }

/* Many lines at once (1.18.4 item 16, #610): a box per line in a column of its own, and one
   line above the grid that appears when a box is ticked. It says how many are chosen and what
   would be written before anything is -- the screen's habit everywhere else, and the reason
   nothing here needs a confirmation of its own. */
.grid td.choose { width: 1px; padding-right: 4px; }
.grid td.choose input.pick { margin: 0; cursor: pointer; }
.bulk-line { margin: 0 0 var(--sp-2); padding: 6px 10px; background: var(--paper-sunken); border-left: 2px solid var(--mark-edge); font-size: var(--fs-small); }
.bulk-line select.bulk-what { font: inherit; font-size: var(--fs-small); padding: 2px 4px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }

/* The one who answers (1.17.0 item 15): a header button carrying the mark and the name, and a
   panel of the definition panel's kind held open at the right edge. The mark is drawn at 18px
   in the button and the head; the four objects are strokes in currentColor, so they take the
   ink of wherever they sit and no colour of their own. */
.roshi-slot { display: inline-flex; }
.roshi-button { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px; font: inherit; font-weight: 600; color: var(--ink); background: none; border: 1px solid var(--rule); border-radius: var(--radius); cursor: pointer; }
.roshi-button:hover { background: var(--paper-sunken-2); }
.roshi-button:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
.roshi-mark { width: 18px; height: 18px; flex: none; display: inline-block; vertical-align: middle; }
.roshi-mark.enso { background: var(--mark-image) center / contain no-repeat; }
.roshi-mark.initial { display: inline-flex; align-items: center; justify-content: center; border: 1.5px solid currentColor; border-radius: 50%; font-family: var(--font-display); font-size: var(--fs-tiny); font-weight: 600; line-height: 1; }
.roshi-panel { position: fixed; top: calc(var(--header-h) + 8px); right: 8px; z-index: 40; width: min(44ch, calc(100vw - 16px)); max-height: calc(100vh - var(--header-h) - 16px); overflow: auto; padding: 12px 14px; background: var(--paper-raised); color: var(--ink); border: 1px solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow); font: var(--fs-small)/1.45 var(--font-ui); }
.roshi-panel .roshi-head { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; font-size: var(--fs-base); }
.roshi-panel .roshi-head .roshi-name { font-family: var(--font-display); font-size: var(--fs-h2); }
.roshi-panel .roshi-close { margin-left: auto; font: inherit; font-size: var(--fs-h2); color: var(--ink-2); background: none; border: 0; cursor: pointer; }
.roshi-panel .roshi-close:hover { color: var(--ink); }
.roshi-panel .roshi-where { margin: 0 0 8px; color: var(--ink-2); }
.roshi-panel form.roshi-ask { display: flex; gap: 6px; margin: 0 0 8px; }
.roshi-panel form.roshi-ask input { flex: 1; min-width: 0; font: inherit; padding: 4px 8px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }
.roshi-panel .roshi-answer .answer { margin: 0 0 6px; }
.roshi-panel .roshi-answer .section { margin: 0 0 6px; color: var(--ink-2); }
.roshi-panel .roshi-answer .goto { margin: 0 0 6px; color: var(--ink-2); }   /* the screen the answer sends you to, a place the menu holds (#1116) */
.roshi-panel .roshi-off { margin: 0 0 8px; }
.roshi-panel .roshi-foot { margin: 8px 0 0; padding-top: 8px; border-top: 1px solid var(--rule); color: var(--ink-2); font-size: var(--fs-tiny); }
.define-ask { position: fixed; z-index: 40; max-width: min(44ch, calc(100vw - 16px)); padding: 4px 12px 6px; margin-top: -1px; background: var(--paper-raised); border: 1px solid var(--rule); border-top: 0; border-radius: 0 0 var(--radius) var(--radius); box-shadow: var(--shadow); font-size: var(--fs-tiny); }
/* A glossary book's entries (1.18.4 item 7): the section opened, its entries as rows inside
   it. The ground is a book's own, since .glossary-body carries .book-body too -- the measure,
   the leading and the indent are one decision for both kinds and are made above. A hairline
   between entries and none under the last, so the run ends where the book does. */
/* the entry an answer rested on, marked the same way a row is: one wash, two places it can sit */

/* Dōgen (1.17.0 item 16): the administrator's area, in the house shape: a head like a room's,
   four sections read down at the prose measure where they are prose and the grid's width
   where they are a grid, and a thread under the feedback grid. */
.dogen-why { max-width: 62ch; margin: calc(-1 * var(--sp-3)) 0 var(--sp-4); }
.dogen-section { margin: 0 0 var(--sp-6); }
.dogen-section h2 { font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 600; margin: 0 0 var(--sp-2); padding-bottom: 4px; border-bottom: 1px solid var(--rule-strong); }
.dogen-section > .hint { max-width: 62ch; margin: 0 0 var(--sp-3); }
.dogen-thread { max-width: 62ch; margin: var(--sp-3) 0 0; font-size: var(--fs-small); }
.dogen-thread .thread-head { color: var(--ink-2); margin: 0 0 4px; }
.dogen-thread .body { margin: 0 0 var(--sp-2); }
.dogen-thread .reply { padding: 2px 0; color: var(--ink-2); }
.dogen-thread .reply .body { color: var(--ink); }
.dogen-thread .reply.mine b { color: var(--mark); }
.dogen-thread form.reply-add { display: flex; gap: 6px; align-items: center; margin: var(--sp-2) 0; }
.dogen-thread form.reply-add input { flex: 1 1 18ch; font: inherit; font-size: var(--fs-small); padding: 3px 6px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }
.dogen-feedback button.thread-open { font: inherit; font-size: var(--fs-tiny); color: var(--ink-2); background: none; border: 0; border-bottom: 1px dotted var(--ink-3); padding: 0; cursor: pointer; }
.dogen-roshi form.roshi-address { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.dogen-roshi form.roshi-address input { min-width: 28ch; }
.dogen-roshi .fact.on { color: var(--settled); }
.dogen-roshi .fact.off { color: var(--ink-2); }
.dogen-handbook .fact { margin: 0 0 var(--sp-2); }

/* Write to Dōgen (1.17.0 item 17): a fixed control at the bottom right of every screen, outside
   the pane as the toasts are, and a panel of Rōshi's shape above it. The toasts sit above the
   control so a toast never covers it. */
.write-fab { position: fixed; right: 16px; bottom: 16px; z-index: 45; font: inherit; font-size: var(--fs-small); font-weight: 600; color: var(--ink); background: var(--paper-raised); border: 1px solid var(--rule); border-radius: 999px; padding: 6px 14px; box-shadow: var(--shadow); cursor: pointer; }
.write-fab:hover { background: var(--paper-sunken-2); }
.write-fab:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
.toasts { bottom: 56px; }
/* the panel grows upward from the control and stops short of the header: with a long sent list it reached the
   header's right edge and sat over the household button (#493), which is the one control it must never cover */
.write-panel { position: fixed; right: 8px; bottom: 56px; z-index: 46; width: min(48ch, calc(100vw - 16px)); max-height: calc(100vh - 56px - var(--header-h) - 16px); overflow: auto; padding: 12px 14px; background: var(--paper-raised); color: var(--ink); border: 1px solid var(--rule); border-radius: var(--radius); box-shadow: var(--shadow); font: var(--fs-small)/1.45 var(--font-ui); }
.write-panel .write-head { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; font-size: var(--fs); }
.write-panel .write-close { margin-left: auto; font: inherit; font-size: var(--fs-h2); color: var(--ink-2); background: none; border: 0; cursor: pointer; }
.write-panel form.write-form { display: flex; flex-direction: column; gap: 8px; margin: 0 0 8px; }
.write-panel form.write-form .kinds { display: flex; gap: var(--sp-3); }
.write-panel form.write-form textarea, .write-panel form.write-form input { font: inherit; padding: 4px 8px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }
.write-panel form.write-form button { align-self: flex-start; }
.write-panel .write-off { margin: 0 0 8px; }
.write-panel .write-sent h3 { font-size: var(--fs-small); text-transform: uppercase; letter-spacing: .06em; font-family: var(--font-mono); font-weight: 500; color: var(--ink-2); margin: 10px 0 6px; }
.write-panel .sent { padding: 6px 0; border-top: 1px solid var(--rule); }
.write-panel .sent .sent-head { color: var(--ink-2); }
.write-panel .sent .body { margin: 2px 0 4px; }
.write-panel .sent .reply { padding: 2px 0 2px var(--sp-3); color: var(--ink-2); }
.write-panel .sent .reply .body { color: var(--ink); }
.write-panel .sent .reply.dogen b { color: var(--mark); }
.write-panel form.reply-add { display: flex; gap: 6px; margin: 4px 0 0; }
.write-panel form.reply-add input { flex: 1; min-width: 0; font: inherit; font-size: var(--fs-small); padding: 3px 6px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper); color: var(--ink); }
.write-panel .write-foot { margin: 8px 0 0; padding-top: 8px; border-top: 1px solid var(--rule); color: var(--ink-2); font-size: var(--fs-tiny); }

@media print {
  @page { size: letter; margin: 0.55in; }
  /* Section 4's projection table is sixteen columns wide and does not fit a
     portrait sheet. It never has: the table has had those columns since the
     report was written, and until this rule the printer simply cut the sheet
     where the paper ran out -- the head cut off mid-word inside After-tax
     (heirs), Limits gone entirely, and every data row a figure short (#265).
     Where the cut lands is a function of how wide that household's figures
     are, so it is silent as often as not: a row can end in a complete,
     comma-grouped number with two columns missing behind it, and nothing on
     the sheet says so.
     A named page is the remedy that loses nothing. The measured alternative
     was 9px for that one table, which fits but sets the report's widest table
     in a face smaller than the report; landscape keeps every figure at the
     10px below. The cost is a sheet or two turned sideways in the middle of
     a portrait report, which the reader can see. Safari lays out a named
     page -- the owner printed the test on 2026-09-15 and read the sheet as
     landscape with its 9-inch rule complete -- and Safari is what the report
     is read in. */
  @page projection { size: letter landscape; margin: 0.55in; }
  .report section.landscape { page: projection; }
  /* A background is how this interface carries meaning, so it is not decoration
     a print path may drop. A browser omits backgrounds when it prints -- Chrome's
     Save as PDF has Background graphics off by default -- and with them went the
     provenance washes, own's corner tick, inherited's and explicit's left edge,
     the frozen underline, the locked cell's ground, which is its only signal,
     every filled cell of Limits by year, and every chart legend swatch. Read off
     a PDF saved with Background graphics off before this rule existed: the
     eight-row Limits by year grid printed empty, a locked cell printed as a
     typed one, and the chart legends read as four words with nothing tying each
     to a line. The property inherits, so the one declaration covers all of it,
     the swatches charts.js paints as inline styles included. -webkit- is for
     Safari, which is what the report is read in.
     It does NOT cover the cover mark, which was absent for its own reason and is
     fixed in ui/js/rooms/retirement/report.js: the mark is a different file in print and
     nothing had ever asked for it. */
  html { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .topbar, .sidebar, .toolbar, .progress, .toasts, .waiting-menu, .guide-foot, .chooser-panel, .chooser-button .chev, .no-print { display: none !important; }   /* .sidebar takes the menu with it and .topbar its ☰ (docs/PLAN_NAVIGATION.md items 01, 02); .guide-foot is a control, hidden as the tab row and the doors were, which went with item 03 (.pane-links, beside it until docs/PLAN_WAITING.md item 02, went to What's waiting); the chooser's panel and its ▾ are controls too (item 04), and its name prints as the words it is (below) */
  .chooser-button { background: none !important; border: 0 !important; padding: 0 !important; }
  /* What would change it on paper is the readings, their figures, what each rests on and when: Find it and Takes are a
     screen's controls, as a toolbar is, and so is the link that opens a row, whose rows are .no-print (docs/PLAN_CHANGE_GRID.md acceptance 12) */
  table.grid.change-grid th:nth-child(n+5), table.grid.change-grid td.find, table.grid.change-grid td.takes, table.grid.change-grid td.across, table.grid.change-grid .opens { display: none !important; }
  /* the pane is a screen layout: on paper the grid runs its full length and the aside follows it */
  .main.paned { display: block !important; }
  .pane { display: block !important; }
  .pane-aside { width: auto !important; border-left: 0 !important; padding-left: 0 !important; overflow: visible !important; }
  .pane-main > .grid-wrap, .grid-wrap.capped { max-height: none !important; min-height: 0 !important; }
  /* the table Tabulator draws holds every row in the page (ui/js/table.js, renderVertical 'basic'); its library
     sizes the table and its scrolling region with inline heights for the screen, and on paper both run their length */
  .pane-main > .table-wrap { display: block !important; min-height: 0 !important; overflow: visible !important; }
  .table-wrap .tabulator, .table-wrap .tabulator .tabulator-tableholder { height: auto !important; min-height: 0 !important; max-height: none !important; overflow: visible !important; }
  .charts-two { display: block !important; }
  #app, .body, .main { height: auto !important; overflow: visible !important; display: block !important; }
  .main { padding: 0 !important; }
  /* the sheet is its own medium and its own measure: paper is read at arm's length and a
     table has to fit a page, so print keeps its own two sizes rather than the screen's five
     (1.18.2 item 3, #585, which is about a screen). */
  body { background: #fff; color: var(--ink); font-size: 11px; }
  .report { max-width: none; }
  .report section { break-inside: avoid-page; }
  .report section.page { break-before: page; }
  .report section > h2 { break-after: avoid-page; }   /* a section head never prints as the last line of a page */
  /* The cover mark keeps its 64px. It was 52px here and 64px on screen, and
     nothing had reconciled the two because until 1.10.0 it printed at neither:
     a background image with nothing having fetched it. Read off the page at 52,
     56 and 64: at 52 the brush fibres close up and the ensō reads as a drawn
     ring. ui/img/README.md, "Ships as PNG", is why that is the wrong way to
     lose it -- the fibres are the mark -- and .brand .mark above carries the
     same finding at 10px. So one number, not two. */
  .grid-wrap { overflow: visible !important; border-color: var(--rule); }
  table.grid th { position: static !important; }
  table.grid thead { display: table-header-group; }   /* a table that spans pages repeats its heads */
  table.grid tr { break-inside: avoid; }
  table.grid th, table.grid td { padding: 3px 6px; height: auto; font-size: 10px; }
  .card, .panel, .chart, .kv, .grid-note { break-inside: avoid; box-shadow: none; }
  a { color: inherit; text-decoration: none; }
}

/* the change record (1.23.0 item 5) */
table.grid.changes td { vertical-align: top; }
table.grid.changes .nowrap { white-space: nowrap; }
.change-field { font-size: var(--fs-small); }
.change-field .k { font-family: var(--font-mono); color: var(--ink-muted, inherit); }
.changes-screen .muted { color: var(--ink-muted, inherit); }
.changes-more { margin-top: var(--sp-3); }

/* Housekeeping (docs/PLAN_PROSPEROUS.md A5): the dialogs that were, as screens at the pane's measure */
.housekeeping > .members-screen, .housekeeping > .rooms-screen, .housekeeping > .changes-screen { max-width: 96ch; }
.housekeeping .member-add { margin-top: var(--sp-4); }
.household-name-kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-2) var(--sp-4); margin: 0 0 var(--sp-3); }
.household-name-kv dt { color: var(--ink-2); }
.household-name-kv dd { margin: 0; }
.household-name-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }

/* Styles that were style="..." attributes in markup until the Content-Security-Policy (1.24.0, #644 stage 6)
   left 'unsafe-inline' out of style-src: an attribute is markup, and markup no longer styles anything. */
.add-row > strong { align-self: center; }
summary.hint { cursor: pointer; }

/* Rōshi's own screen (docs/PLAN_ONBOARDING.md item 02, the record §1): one column at any
   width, at most 560px, drawn inside the shipped shell and lighting no room. The way in's
   four choices are the doors' shape -- a word and a line on .card's ground, --paper-raised
   with .btn's hover, --paper-sunken -- so §11's sweep reaches no ground it has not measured;
   the six rings are .btn.primary's ground for the current one and a rule for the rest. */
.roshi-screen { max-width: 560px; }
.roshi-screen .roshi-head-line { display: flex; align-items: center; gap: 8px; margin: 0 0 var(--sp-3); }
.roshi-screen .roshi-head-line .roshi-mark { width: 22px; height: 22px; }
.roshi-screen .roshi-head-line .roshi-name { font-family: var(--font-display); font-size: var(--fs-h2); }
.roshi-screen .roshi-title { font-family: var(--font-display); font-size: var(--fs-h1); font-weight: 600; letter-spacing: 0; margin: 0 0 var(--sp-3); }
.roshi-screen .roshi-lead, .setup-before .roshi-lead { font-family: var(--font-display); font-size: var(--fs-h2); line-height: 1.5; margin: 0 0 var(--sp-3); }
.roshi-screen .roshi-readonly { margin: 0 0 var(--sp-3); }
.way-in .way-cleared, .setup-before .way-cleared { padding: 8px 12px; border-left: 3px solid var(--mark); background: var(--mark-wash); margin: 0 0 var(--sp-4); }
.way-in .way-what, .no-household .way-what { margin: 0 0 var(--sp-5); padding: 0 0 0 var(--sp-4); border-left: 3px solid var(--rule-strong); font-family: var(--font-display); font-size: var(--fs-h2); line-height: 1.5; color: var(--ink); }
/* the house rules (docs/PLAN_PROSPEROUS.md A3, D5; ui/js/house-rules.js): one rule in the display face, as the way in's
   sentence is, with who it is from under it in the quiet colour; at the head of Categories and on Learn first */
.house-rules { margin: 0 0 var(--sp-4); }
.house-rules .house-rules-word { margin: 0 0 var(--sp-1); color: var(--ink-2); font-size: var(--fs-tiny); }
.house-rule { margin: 0 0 var(--sp-2); padding: 0 0 0 var(--sp-4); border-left: 3px solid var(--rule-strong); }
.house-rule blockquote { margin: 0; font-family: var(--font-display); font-size: var(--fs-h2); line-height: 1.5; color: var(--ink); }
.house-rule figcaption { margin: var(--sp-1) 0 0; color: var(--ink-2); font-size: var(--fs-small); }
.roshi-rings { display: flex; gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.roshi-rings .ring { width: 28px; height: 28px; padding: 0; font: inherit; font-size: var(--fs-small); font-weight: 600; color: var(--ink-2); background: none; border: 1.5px solid var(--rule-strong); border-radius: 50%; cursor: pointer; }
.roshi-rings .ring.seen { color: var(--mark); border-color: var(--mark); }
.roshi-rings .ring.current { color: var(--mark-ink); background: var(--mark); border-color: var(--mark); cursor: default; }
.roshi-rings .ring:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
.roshi-foot-box { margin: var(--sp-5) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--rule); }
.roshi-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.roshi-foot a { font-size: var(--fs-small); }
.roshi-fixed { color: var(--ink-3); font-size: var(--fs-small); margin: var(--sp-3) 0 0; }
.roshi-links { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin: var(--sp-4) 0 0; }
.roshi-kept { color: var(--ink-2); margin: 0 0 var(--sp-3); }
.example-set { display: flex; flex-direction: column; gap: var(--sp-3); margin: var(--sp-3) 0; }
.example-card { padding: 12px 16px; background: var(--paper-raised); border: 1px solid var(--rule); border-radius: var(--radius); }
.example-card h3 { font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 600; margin: 0 0 4px; }
.example-card .story { margin: 0 0 6px; }
.example-card .shows { color: var(--ink-2); font-size: var(--fs-small); margin: 0; }
.example-card .gap { margin: 6px 0 0; padding: 4px 0 4px 10px; border-left: 3px solid var(--limit-edge); color: var(--ink-2); font-size: var(--fs-small); }
.roshi-button.active { border-color: var(--mark); box-shadow: inset 0 -2px 0 var(--mark); }
.roshi-making { margin-top: var(--sp-6); }
/* a question answered with controls (item 03, item 04): the question, chips, one chosen or several */
.roshi-q { margin: 0 0 var(--sp-4); }
.roshi-q .q { font-weight: 600; margin: 0 0 var(--sp-2); }
.roshi-q .choices { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.roshi-q .roshi-ask-this { display: inline-block; margin-top: 6px; font-size: var(--fs-small); }
.chip { font: inherit; font-size: var(--fs-small); color: var(--ink); background: var(--paper-raised); border: 1px solid var(--rule-strong); border-radius: var(--radius); padding: 6px 12px; cursor: pointer; text-align: left; }
.chip:hover { background: var(--paper-sunken); }
.chip.on { border-color: var(--mark); background: var(--mark-wash); }
.chip:focus-visible { outline: 2px solid var(--mark); outline-offset: 1px; }
.roshi-before, .roshi-own { margin: 0 0 var(--sp-4); }

/* two marks beside a figure (docs/PLAN_ONBOARDING.md item 08, DESIGN.md section 6): a WORD, not a wash,
   because a wash on a cell already means provenance and a second meaning for the same device would
   collapse both. Rough is a dotted underline in the limit's ink, from the example a dashed one in the
   inherited ink -- a shape each, so the two are told apart with the colour turned off. */
.mark-word { display: inline-block; margin-left: 6px; font-family: var(--font-body); font-size: var(--fs-tiny); font-style: normal; font-weight: 500; letter-spacing: .02em; line-height: 1.3; vertical-align: 1px; white-space: nowrap; }
.mark-word.rough { color: var(--limit); border-bottom: 1px dotted var(--limit-edge); }
.mark-word.example { color: var(--inherited); border-bottom: 1px dashed var(--inherited-edge); }
table.grid td .mark-word { float: right; }
.legend-key .mark-word { margin-left: 0; }

/* Rōshi · what was heard, first on the Front Door on a return visit (docs/PLAN_ONBOARDING.md item 11), in the accent's border */
.home-roshi { margin: 0 0 var(--sp-4); padding: 12px 16px; border: 1px solid var(--mark); border-radius: var(--radius); }
.home-roshi h2 { margin: 0 0 6px; }
.home-roshi .roshi-heard { margin: 0 0 6px; font-family: var(--font-display); font-size: var(--fs-h2); }
.home-roshi .home-roshi-line { margin: 0; color: var(--ink-2); }
/* Back, beside Rōshi in the header while the screen is on (item 10): the arrow always, the words at desktop width */

/* The band across every screen of an example household (docs/PLAN_ONBOARDING.md item 13): in ink on the sunken paper, the
   word Example first, the way back and Start mine from this one at its end */
.example-band { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); padding: 8px 14px; background: var(--paper-sunken); border: 1px solid var(--rule-strong); border-radius: var(--radius); color: var(--ink); }
.example-band .example-acts { display: inline-flex; gap: var(--sp-2); margin-left: auto; }
.example-card .example-open { margin: 6px 0 4px; }
.confirm-figure { font-family: var(--font-display); font-size: var(--fs-h2); margin: var(--sp-2) 0; }
.confirm-field { display: flex; gap: var(--sp-2); align-items: end; margin: var(--sp-2) 0; }

/* a person in no household (docs/PLAN_INTERVIEW.md item 06): the two sentences and why nothing can be made */
.no-household { max-width: 560px; margin-top: var(--sp-4); }

/* a glossary entry drawn in the panel under the answer that rests on it (docs/PLAN_INTERVIEW.md item 07) */
.roshi-panel .roshi-entry { margin: 4px 0 8px; padding: 6px 10px; background: var(--paper-sunken); border-left: 2px solid var(--mark); font-size: var(--fs-small); }
.roshi-panel .roshi-entry .term { font-weight: 600; margin-right: 4px; }
