/* THE DESIGN SYSTEM. It consumes the custom properties in /tokens.css, which are DERIVED from
   house/palette.py rather than written here — one palette, every renderer.

   REPLACING THIS FILE IS HOW A DIFFERENT DESIGN SYSTEM DROPS IN. So nothing outside it sets a
   colour, a size or a spacing, and no panel carries an inline style: use the style layer, do not
   set fills and fonts at a call site. */

:root {
  /* COLOURS AND THE FONT COME FROM /tokens.css, generated by desk/theme.py from
     house/palette.py, the dark scheme with them; nothing here re-states one. What is defined
     here is scale, rhythm and measure: the design system's own, under its names and held to its
     values by a book's brand check, and the few steps that are genuinely this renderer's. */
  /* THE TYPE SCALE, and every size on the desk is one of these. Five steps, one per job, and
     nothing outside :root states a size. The design system's label is 11.5px, so the label step
     is too. */
  --text-lead:  1.0625rem;   /* 17px — a lead row, the brand */
  --text-body:  0.9375rem;   /* 15px — body copy */
  --text-note:  0.8125rem;   /* 13px — notes, footers, the freshness line, .small */
  --text-label: 0.71875rem;  /* 11.5px — the design system's label: headings, column heads, field labels, tags */
  --text-micro: 0.6875rem;   /* 11px — the wordmark's second word */
  /* TWO DISPLAY STEPS: a page's title, expanded 800 as
     The design system's display-l, and a figure leading the Dashboard's band. */
  --text-display: 2.5rem;    /* 40px — a page's title */
  --text-numeral: 2.25rem;   /* 36px — a figure on the Dashboard's ultramarine band */
  /* THE DESIGN SYSTEM'S SPACING, CORNERS, RULES AND GEOMETRY. Square corners everywhere but a status point
     and a scrollbar's thumb; borders, never shadows; a 2px rule opens every table and section;
     every control at least `--touch` tall. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --radius-none: 0px;
  --radius-pill: 999px;
  --radius-round: 50%;
  --rule-section: 2px;
  --rule-lead: 3px;
  --container: 1328px;
  --measure: 760px;
  --touch: 44px;
  /* THE DESK'S OWN, which the design system has no word for. A data row's padding, top and bottom, kept small so
     more rows show, and a cell's, left and right: 16px between columns. */
  --row-pad: 0.1875rem;
  --cell-pad: 0.5rem;
  /* The page's side margin: the design system's 32px on a wide window, 16px on a phone. */
  --gutter: var(--space-6);
}
@media (max-width: 48rem) {
  :root { --gutter: var(--space-4); --text-numeral: 1.75rem; --text-display: 1.875rem; }
}

* { box-sizing: border-box; }

/* THE FOOTER SITS AT THE FOOT OF THE WINDOW on a short page, not halfway up it. */
body {
  min-height: 100vh; display: flex; flex-direction: column;
  margin: 0;
  padding: 0 var(--gutter) var(--gutter);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.45;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* FIGURES LINE UP. The design system sets every figure in Archivo's tabular numerals, never a second face:
   a column of figures reads down its digits. */
table, .fresh, .steps, pre { font-variant-numeric: tabular-nums; }

/* THE BAR: the book's lockup and what this window is, ruled off from the work. Nothing in it
   moves when a page changes: a frame that moves with its contents is not a
   frame. */
.bar {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--hair);
}
.brand { font-size: var(--text-lead); }
/* THE BOOK'S LOCKUP: its mark beside its wordmark (portfusion.brand), then what this window
   is. The name is expanded 800 and the line under it condensed 600 at a half-em's tracking. */
.brand { display: flex; align-items: center; gap: var(--space-4); }
.lockup { display: inline-flex; align-items: center; gap: var(--space-3); color: var(--mark); }
.lockup svg { height: 28px; width: auto; flex: none; }
.wordmark { display: flex; flex-direction: column; gap: var(--space-1); line-height: 0.95;
            white-space: nowrap; }
.wordmark .name { font-weight: 800; font-stretch: 125%; color: var(--heading); }
.wordmark .sub { font-size: var(--text-micro); font-weight: 600; font-stretch: 75%;
                 letter-spacing: 0.5em; color: var(--muted); }
.desk-name { padding-left: var(--space-4); border-left: 1px solid var(--hair);
             font-size: var(--text-label); font-weight: 600; font-stretch: 75%;
             letter-spacing: 0.1em; text-transform: uppercase; color: var(--heading); }
.muted { color: var(--muted); }

/* THE FRAME: the rail beside the work. The rail keeps its place while a page scrolls, so the
   pages are always one press away; the work takes the rest of the window and grows to the
   right. */
.frame { flex: 1 0 auto; display: flex; flex-wrap: wrap; align-items: flex-start;
         gap: 0 var(--space-6); }
.rail {
  flex: 1 1 13.5rem; max-width: 15rem; min-width: 0;
  position: sticky; top: 0; max-height: 100vh; overflow-y: auto;
  padding: var(--space-5) 0 var(--space-5);
  display: flex; flex-direction: column; gap: var(--space-5);
}

/* THE PAGES ON THE THREAD, in the order of the work. The design system's thread joins things in the order they
   happened; here it joins the pages in the order they are worked, so a gap in it would be a page
   missing. Each page is a point on it, and the open page is the one spark point on the screen. */
.tabs { display: flex; flex-direction: column; margin: 0; }
.tabs .thread { display: flex; flex-direction: column; position: relative; }
.tabs .thread::before {
  content: ""; position: absolute; left: 6px; top: 22px; bottom: 22px; width: var(--rule-section);
  background: var(--accent);
}
.tabs button {
  position: relative; display: flex; align-items: center; text-align: left;
  appearance: none; background: none; border: 0; cursor: pointer;
  font: inherit; font-weight: 500; color: var(--ink);
  min-height: var(--touch); padding: 0 0 0 30px;
}
.tabs button::before {
  content: ""; position: absolute; left: 1px; top: 50%; width: 12px; height: 12px;
  margin-top: -6px; border-radius: var(--radius-round); background: var(--accent);
}
.tabs button:hover { color: var(--heading); }
.tabs button[aria-current="page"] { color: var(--heading); font-weight: 700; }
.tabs button[aria-current="page"]::before {
  left: 0; width: 14px; height: 14px; margin-top: -7px;
  background: var(--spark); border: 2px solid var(--heading);
}

/* THE PAGES APART FROM THE WORK, below a rule and off the thread, with no heading: Method and
   Access. */
.tabs .apart { display: flex; flex-direction: column; margin-top: var(--space-4);
               padding-top: var(--space-3); border-top: var(--rule-section) solid var(--rule); }

/* ACCESS: an enrol code is read off the screen and typed on another device, so it is set large,
   spaced, in tabular figures. */
.enrol-code { display: block; font-size: var(--text-numeral); font-weight: 800;
              letter-spacing: 0.08em; font-variant-numeric: tabular-nums; color: var(--heading); }
tr.devices > td { padding: 0 0 var(--space-3) var(--space-5); }

/* THE FRESHNESS LINE sits under the pages: when the store last moved, the price date, the desk's
   own code, and the button that acts on it. */
.fresh { font-size: var(--text-note); line-height: 1.6; color: var(--muted);
         padding-top: var(--space-3); border-top: var(--rule-section) solid var(--rule); }
/* A WARNING ON ANY PAGE wears the warning ink: a line the sweep could not price, a mark past the
   age limit, a document the Bench cannot read. */
.stale { color: var(--warn-ink); }

/* THE PAGES FOLD ON A PHONE. The pages down a rail are taller than a phone's first screen, so
   below 48rem the rail is a button naming the open page, and pressing it shows the rest. */
.pages-toggle { display: none; }
@media (max-width: 48rem) {
  .frame { display: block; }
  .rail { position: static; max-width: none; max-height: none; padding: var(--space-3) 0 0; }
  .rail .tabs, .rail .fresh { display: none; }
  .rail.open .tabs, .rail.open .fresh { display: flex; }
  .rail.open .fresh { display: block; }
  .pages-toggle {
    display: inline-flex; align-items: center; min-height: var(--touch); padding: 0 var(--space-4);
    font: inherit; font-weight: 600; color: var(--heading); background: var(--recessed);
    border: 1px solid var(--control); border-radius: var(--radius-none); cursor: pointer;
  }
  .pages-toggle::after { content: "▾"; margin-left: var(--space-2); }
}

/* A SCREEN WITH NOTHING TO NAVIGATE — signing in, the Mac not answering, a version mismatch —
   draws no rail and no page button. */
body.bare .rail, body.bare .pages-toggle { display: none; }

/* FOCUS IS ALWAYS SEEN: the design system's ring, 2px solid in ink and offset 2px, on whatever the keyboard
   reaches. */
:focus-visible { outline: 2px solid var(--heading); outline-offset: 2px; }

/* LEFT-ALIGNED, NOT CENTRED. Centred content re-centres itself whenever the measure changes, so
   one page's first column lands apart from another's. One left edge for the whole desk: content
   grows to the RIGHT and the eye never has to find the start of a line twice. */
main { flex: 999 1 35rem; min-width: 0; max-width: var(--container); margin: 0;
       padding-top: var(--space-5); }
.loading { color: var(--muted); }

/* THE DESIGN SYSTEM'S LABEL: condensed 600 at 11.5px, set in capitals with a tenth of an em between letters,
   for a section heading, a column head, a field label and a state's word.
   The words are still WRITTEN in sentence case
   (`sentence()` in kit.js), so the capitals are the style's and the source reads as written. */
h2, .diff h3, th, .f > span, .tag {
  font-size: var(--text-label); font-weight: 600; font-stretch: 75%; letter-spacing: 0.1em;
  text-transform: uppercase;
}
h2 {
  color: var(--heading);
  margin: var(--space-6) 0 var(--space-3);
}
h2:first-of-type { margin-top: 0; }
/* A SECTION UNDER A TABLE KEEPS ITS SPACE: the zero above is for a page's opening heading. */
.scroll + h2 { margin-top: var(--space-6); }

/* FIGURES. No row banding — house/palette.py: a second light fill beside the accepted grey
   would dilute the fill channel, and the fill channel carries meaning. Horizontal rules only.
   THE ONE EXCEPTION IS THE POINTER: the row under it takes the band, the
   palette's "one step off the paper", so a line can be followed from its first column to its
   last. It is never a row's state, so a differing row keeps its own fill. */
/* A ROW IS ONE LINE AT A DATA ROW'S LEADING. Body text keeps 1.45 for prose; a table is scanned,
   not read, and at 1.3 with --row-pad a plain row is 27px against 35px. Nothing in a row is
   bold: weight is for a headline figure (`table.figures`, `tr.lead`) and an item's label. */
table { width: 100%; border-collapse: collapse; line-height: 1.3; }
/* A TABLE OPENS ON THE DESIGN SYSTEM'S 2px RULE, and its heads sit on the page in the label style, with a
   hairline under them: borders, not bands. */
table { border-top: var(--rule-section) solid var(--rule); }
th {
  text-align: left; color: var(--muted); vertical-align: bottom;
  padding: var(--space-2) var(--cell-pad); border-bottom: 1px solid var(--hair);
}
td { padding: var(--row-pad) var(--cell-pad); border-bottom: 1px solid var(--hair); }
tr:last-child td { border-bottom: 0; }
/* WHERE ONE ACCOUNT'S ROWS START, in a table that names the account once (Performance): a rule
   in the ink of the table's own top, one pixel — not a title row. */
tr.opens td { border-top: 1px solid var(--rule); }
/* A FIGURE IS ARCHIVO'S, TABULAR, AT THE ROW'S OWN SIZE. Archivo's tabular figures are narrow,
   so a figure reads at the size of the text beside it. */
td.num { text-align: right; white-space: nowrap; }

/* MOVEMENT — a gain's SIGN, and nothing else. house/palette.py heads the two colours these derive
   from "movement, which is not provenance", which is the whole rule: this is a THIRD channel,
   beside font-colour-as-origin and fill-as-state, and it must not borrow from either. So it
   colours the figure only — no fill, no weight, no size — and only on the three gain columns
   kit.js lists. Magnitude is not encoded at all; that is what sorting a column is for.
   Exactly zero wears neither. */
td.num.up   { color: var(--up); }
td.num.down { color: var(--down); }
tr.lead td { font-size: var(--text-lead); }
tr.lead td.num { font-weight: 600; }
td.indent { padding-left: var(--space-6); color: var(--muted); }

/* WHAT CHANGED — the two bases, one under the other, and the windows above them.

   A BLOCK IS A SECTION UNDER ITS CLOCK. Its label is a sub-heading in the column heads' ink, so
   "Securities owned" reads as part of "Market time" and not as a third section beside it; the
   figures table and the data table below it are the same two objects every other panel uses.

   THE WINDOW CHIPS say which two dates a group of lines was compared across. There can be more
   than one, since lines are not all marked on one date — so this is a LIST, and it has to
   look like one rather than like a single date that happens to be wide. */
.diff h3 { color: var(--muted); margin: var(--space-3) 0 var(--space-2); }
.diff + .diff { margin-top: var(--space-6); }
.win { display: inline-block; margin-right: var(--space-3); white-space: nowrap; }

/* NEEDS ATTENTION. Fill carries state. */
.items { list-style: none; margin: 0; padding: 0; }
.items li { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--hair); }
.items li:last-child { border-bottom: 0; }
/* A STATE IS A KEY DOT: a round point in one of the design system's bar colours, which
   The design system gives to table keys, beside the state's word in ink. The word is the reading and the dot
   the scan, so colour is never the only signal. */
/* THE WORD IN SENTENCE CASE: "Ready", "Not built", "Owner", "Signed in". A
   state's word is read, so it is written as a word rather than set as a label in capitals; the
   size and weight stay the label's. ONE RULE FOR EVERY TAG, whoever wrote the word — the desk's
   script or an engine's answer: the first letter is raised here, so the dot sits outside the
   text's flow. */
.tag {
  display: inline-block; position: relative; padding-left: calc(8px + var(--space-2));
  min-width: 9ch; margin-right: var(--space-3); color: var(--heading);
  text-transform: none; letter-spacing: 0.02em; font-stretch: 85%;
}
.tag::first-letter { text-transform: uppercase; }
.tag::before {
  content: ""; position: absolute; left: 0; top: 50%; margin-top: -4px;
  width: 8px; height: 8px; border-radius: var(--radius-round);
  background: var(--key-note);
}

/* THE PAGE TEMPLATE — `page()` in kit.js. The title is the page's one heading that is not a
   section heading: the tab's own name at lead size, its scope line beside it, and every `h2`
   below it is a section of the work. A RULE UNDER THE HEAD ON EVERY PAGE,
   so the title and its scope read as the page's label and everything below it as the page. */
.page-head { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--space-3);
             margin: 0 0 var(--space-3); padding-bottom: var(--space-2);
             border-bottom: 1px solid var(--hair); }
.page-head h1 { margin: 0; }

/* A STEP'S NAME is body size at 600. */
.steps strong { font-size: var(--text-body); font-weight: 600; }
/* A PAGE'S TITLE IS THE DESIGN SYSTEM'S DISPLAY: the tab's own name, expanded 800, its scope line beside it
   in body text. */
.page-head { row-gap: var(--space-2); padding-bottom: var(--space-4); margin-bottom: var(--space-4); }
.page-head h1 { font-size: var(--text-display); font-weight: 800; font-stretch: 125%;
                line-height: 1.05; letter-spacing: -0.015em; color: var(--heading);
                margin-right: var(--space-3); }
.page-head .muted { font-size: var(--text-lead); color: var(--ink); }

/* THE FIELD: the design system's ultramarine, the one strong moment on the Dashboard.
   It carries the page's head and the figures the panel marks as leading, each with
   the parts that sit under it, in white; everything else on the page stays on the white ground. */
.field { background: var(--field); color: var(--on-field); padding: var(--space-6) var(--space-6)
         var(--space-6); margin-bottom: var(--space-6); }
.field .page-head { border-bottom-color: var(--field-rule); }
.field .page-head h1 { color: var(--on-field); }
.field .page-head .muted { color: var(--on-field-muted); }
.field-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
                 gap: var(--space-5) 0; }
.field-figure { display: flex; flex-direction: column; gap: var(--space-2);
                padding: 0 var(--space-5); border-left: 1px solid var(--field-rule); }
.field-figure:first-child { padding-left: 0; border-left: 0; }
.field-figure .label { font-size: var(--text-label); font-weight: 600; font-stretch: 75%;
                       letter-spacing: 0.1em; text-transform: uppercase; color: var(--on-field); }
.field-figure .numeral { font-size: var(--text-numeral); font-weight: 800; font-stretch: 125%;
                         line-height: 1; font-variant-numeric: tabular-nums; }
.field-figure .part { font-size: var(--text-note); color: var(--on-field-muted);
                      font-variant-numeric: tabular-nums; }
.field :focus-visible { outline-color: var(--on-field); }
/* ON A PHONE THE BAND'S FIGURES STACK, each ruled off from the one above rather than beside it. */
@media (max-width: 48rem) {
  .field { padding: var(--space-5); }
  .field-figure { padding: var(--space-4) 0 0; border-left: 0; border-top: 1px solid var(--field-rule); }
  .field-figure:first-child { padding-top: 0; border-top: 0; }
}

/* A TABLE TAKES THE WIDTH ITS COLUMNS NEED, a data table too: stretched to the window, its gaps
   make a line hard to follow. Wider than the window, it scrolls in its box. */
.page table { width: auto; }

/* THE STEPS ON ONE LINE — `stepLine()` in kit.js. Each step is its state, its name, then what
   can be pressed, and the steps run left to right in the order the work is done. A narrow
   window wraps a whole step to the next line, and splits one only when it is wider than the
   line itself. */
.steps { list-style: none; margin: 0 0 var(--space-5); padding: var(--space-2) 0;
         display: flex; flex-wrap: wrap; align-items: baseline;
         column-gap: var(--space-3); row-gap: var(--space-2);
         border-bottom: 1px solid var(--hair); }
.steps li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.steps li + li::before { content: "›"; color: var(--muted); margin-right: var(--space-2); }
.steps .tag { min-width: 0; margin-right: 0; }
.problem .tag::before, .tag.problem::before { background: var(--key-problem); }
.gap     .tag::before, .tag.gap::before     { background: var(--key-gap); }
.note    .tag::before, .tag.note::before    { background: var(--key-note); }
.clear   .tag::before, .tag.ok::before      { background: var(--key-clear); }
.clear   .tag { color: var(--muted); }
.pending .tag::before { visibility: hidden; }   /* a step with no state yet: the space, no dot */
.check .tag::before { visibility: hidden; }     /* a check the record ran: the space, no dot */
.items li.check { color: var(--muted); }

/* THE FOOTER is the design system's: the footer ground in both themes, full width, with a hairline above it in
   Ink so it parts from a dark page. */
.foot { margin: var(--space-6) calc(-1 * var(--gutter)) calc(-1 * var(--gutter));
        padding: var(--space-4) var(--gutter);
        background: var(--footer); border-top: 1px solid var(--footer-edge);
        color: var(--on-footer-muted); font-size: var(--text-note); }
/* AN ERROR is set in the desk's own face, never the browser's monospace, with the warning ink's
   rule above it. */
pre { font-family: var(--font-sans); }
.error { border-top: var(--rule-section) solid var(--warn-ink); padding-top: var(--space-2);
         white-space: pre-wrap; font-size: var(--text-note); }
/* A SCREEN WITH NOTHING TO NAVIGATE says what happened in the design system's display, as a page's title does. */
body.bare #main > h2 { font-size: var(--text-display); font-weight: 800; font-stretch: 125%;
                       letter-spacing: -0.015em; text-transform: none; line-height: 1.05;
                       margin: var(--space-5) 0 var(--space-4); }

/* --- THE BENCH ------------------------------------------------------------------------- */
.row-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.row-head h2 { margin: 0; }

button.link {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--link); text-decoration: underline; text-underline-offset: 2px;
}
button.link.danger { color: var(--warn-ink); }
/* A LINK DARKENS TO INK UNDER THE POINTER, as the website's do. A destructive one keeps its
   warning ink, and a disabled one does not answer. */
button.link:not(.danger):not([disabled]):hover { color: var(--heading); }

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
        gap: var(--space-3); margin-bottom: var(--space-5); }
/* `.f`'s grid rows are declared near the foot of this file. */
.f { gap: 2px; }
.f > span { font-size: var(--text-label); color: var(--heading); }
.f em { display: block; font-style: normal;
        font-size: var(--text-label); color: var(--muted); margin-top: 2px; }
.f .req { color: var(--warn-ink); }
/* WHAT AN INPUT LOOKS LIKE ON THIS DESK, and it is not "what a .f input looks like". Scoped to
   `.f`, every other input would fall to the browser default: a design system that only styles
   one caller's inputs has a hole in it. `td input` joins by being an input. So does the Price
   Refresh's date in its step line. */
.f input, .f select, td input, td select, .steps input, textarea {
  font: inherit; color: var(--ink); background: var(--recessed);
  border: 1px solid var(--control); border-radius: var(--radius-none);
  padding: var(--space-2) var(--space-3);
}
/* In a table an input sits in a row, and a row is one line: its box keeps the border and loses
   the padding that would make its row the tallest on the page. */
td input, td select { padding-top: 1px; padding-bottom: 1px; }
/* A FIELD'S FOCUS: the border takes the accent, and the design system's ring sits outside it. */
.f input:focus, .f select:focus, td input:focus, td select:focus, .steps input:focus,
textarea:focus {
  border-color: var(--accent); outline: 2px solid var(--heading); outline-offset: 2px;
}
/* The native date picker and checkbox draw themselves from the scheme, not from our tokens. */
:root { color-scheme: light dark; }
textarea { width: 100%; resize: vertical; }

.row-card { border: 1px solid var(--hair); border-top: var(--rule-section) solid var(--rule);
            padding: var(--space-3); margin-bottom: var(--space-3); }

/* The word count turns when it passes the cap. The cap is a rule of the record, not a
   suggestion — a rationale that needs 60 words is usually restating figures the row carries. */
.overcap { color: var(--warn-ink); font-weight: 600; }

.gates .ok   .tag::before { background: var(--key-clear); }
.gates .no   .tag::before { background: var(--key-problem); }

pre.paste, pre.doc {
  background: var(--band); color: var(--ink);
  padding: var(--space-3); overflow-x: auto;
  font-size: var(--text-note);
  white-space: pre-wrap; word-break: break-word;
}
pre.doc { max-height: 22rem; overflow-y: auto; }

/* THE DROP-OFF ZONE. A dashed outline is the one place in this design system that reads as
   "put something here" rather than "here is a figure" — everything else is hairlines and
   fills that carry meaning. It lights up on `.over` so a drag has visible feedback before
   the release, which is the moment a drop is either aimed or abandoned. */
.drop {
  display: flex; flex-direction: column; gap: var(--space-2); align-items: center;
  text-align: center;
  padding: var(--space-5); margin: var(--space-3) 0;
  border: 2px dashed var(--control);
  color: var(--muted);
}
.drop strong { color: var(--ink); font-weight: 600; }
.drop.over { border-color: var(--accent); border-style: solid; background: var(--band); }

/* THE QUOTE UNDER A PROPOSED FIELD. Set quietly on purpose — it is evidence to be read
   against the document, not a second figure competing with the value above it. */
.f .quote {
  display: block; font-style: normal; font-size: var(--text-label); color: var(--muted);
  margin-top: 2px; padding-left: var(--space-2);
  border-left: 2px solid var(--accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* THE DOCUMENT BESIDE THE FORM. Sticky, because the job is cross-referencing a quote against
   the page it came from and a preview that scrolls away is one you stop using. The measure
   suits prose; a page and a form beside each other need more, so the body widens only while the
   preview is open and returns when it closes. */
/* THE DOCUMENT BESIDE THE FORM TAKES THE WINDOW: a document needs the area. This is the one
   screen where BOTH halves are being read at once. */
body.wide main { max-width: none; }

/* A TABLE OF FIGURES IS NOT PROSE. `--measure` is where a LINE OF TEXT stops being comfortable
   to read, so prose keeps it (below) and a page of figures does not.

   THE HOOK IS WHAT WAS RENDERED, NOT A LIST OF PANEL NAMES, which would drift the first time a
   panel was added: `data-wide`, which kit.js's page() puts on every tab, or `.scroll`, the box
   the wide-table helper emits. A page with neither (an error, the sign-in) keeps the measure. */
body.data main { max-width: none; }

/* PROSE KEEPS ITS MEASURE ON A WIDE PAGE. A table wants the window; the paragraph explaining it
   does not. TABLES ARE UNTOUCHED by this — it caps paragraphs and list items only. */
body.data #main p,
body.data #main .items li { max-width: var(--measure); }
body.wide #item { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
                  gap: var(--space-5); align-items: start; }
body.wide #item > #preview-pane { grid-row: 1 / 99; grid-column: 2; position: sticky; top: var(--space-3); }
body.wide #item > *:not(#preview-pane) { grid-column: 1; }
.docframe { width: 100%; height: 78vh; border: 1px solid var(--hair);
            background: var(--paper); }

/* Stacked on a narrow window: a side-by-side at 40rem is two unreadable columns. */
@media (max-width: 70rem) {
  body.wide #item { display: block; }
  body.wide #item > #preview-pane { position: static; }
  .docframe { height: 60vh; }
}

/* A DRAFTED CELL IS NOT EVIDENCE. Same shape as a quote so the eye reads them together, but
   in the warning colour, because it is a reading of the document rather than a piece of it. */
.f .quote.drafted { border-left-color: var(--warn-ink); color: var(--warn-ink); }

/* FROM THE RECORD, NOT THE DOCUMENT — an allocated id, or the provenance line built from the
   three evidence limbs. Neither quoted nor composed: the book already knew it. */
.f .quote.derived { border-left-color: var(--hair); }

/* A PROSE FIELD TAKES THE WHOLE ROW. `note` is the cell the machine wrote and the one the owner
   most has to read before approving it; in a 15rem column it would be a box to scroll sideways. */
.f.long { grid-column: 1 / -1; }
.f.long textarea { min-height: 4.5rem; }

.small { font-size: var(--text-note); }

/* A LINK IN THE WORK is the working blue, as a button.link is. */
a { color: var(--link); text-underline-offset: 2px; }
a:hover { color: var(--heading); }

/* REPORTS: one line per report — its state, its name (a link once the gate allows it), its date —
   and the gate's own words under a quarter it refuses. */
.items li.report { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-4);
                   padding: var(--space-3) 0; }
.items li.report strong { font-size: var(--text-lead); }
/* EVERY NAME STARTS IN ONE COLUMN: each state's word takes the room of the
   longest, "not ready", so a quarter's name sits at the same place on every line. The `.tag`
   minimum of 9ch holds nine characters of figures, not nine of the label's spaced capitals and
   the dot before them. */
.items li.report .tag { min-width: 16ch; }
.items li.report .gaps { flex-basis: 100%; margin: 0; padding-left: var(--space-5);
                         color: var(--muted); font-size: var(--text-note); }

/* THE DESIGN SYSTEM'S TWO BUTTONS, square and at least `--touch` tall: the one thing to press, in the working
   blue, and anything beside it, outlined in ink. */
button.primary, button.secondary {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: var(--touch); padding: 0 var(--space-5); cursor: pointer;
  font: inherit; font-weight: 600; border-radius: var(--radius-none);
}
button.primary { background: var(--accent); color: var(--paper); border: 2px solid var(--accent); }
button.secondary { background: none; color: var(--heading); border: 2px solid var(--heading); }

/* SIGNING IN: the field beside the form, as the hosted desk's own front door. The field carries
   the book's web in white; the form asks for the passkey first and the enrol code after it. */
.signin { display: flex; flex-wrap: wrap; margin-top: var(--space-5); }
.signin-field { flex: 1 1 20rem; display: flex; flex-direction: column; justify-content: flex-end;
                gap: var(--space-5); min-height: 22rem; padding: var(--space-6);
                background: var(--field); color: var(--on-field); }
.signin-field svg { width: 6rem; height: auto; }
.signin-field svg g { stroke: var(--on-field); }
.signin-field svg circle { fill: var(--on-field); }
.signin-field h1 { margin: 0; font-size: var(--text-display); font-weight: 800; font-stretch: 125%;
                   line-height: 1.05; color: var(--on-field); }
.signin-form { flex: 1 1 20rem; display: flex; flex-direction: column; align-items: flex-start;
               gap: var(--space-4); padding: var(--space-6); border: 1px solid var(--hair); }
.signin-form .f { width: 100%; max-width: 20rem; }
.signin-form #signin { width: 100%; max-width: 20rem; }
/* A FIFTH OF THE FILL, NOT TWO: at 40% the muted text in a differing row scores 1.76:1 on the
   dark ground. At 20% it is the same tint on white and legible on ink. */
tr.differs td { background: color-mix(in srgb, var(--warn) 20%, transparent); }
th.num { text-align: right; }
/* A HEADING THAT SORTS ITS COLUMN: the pointer says it can be pressed, and the
   sorted one carries its arrow, small, in the heading's own ink. */
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover, th.sortable:focus-visible { color: var(--heading); }
th .arrow { margin-left: var(--space-1); font-size: var(--text-label); color: var(--heading); }
button.link[disabled] { color: var(--muted); cursor: not-allowed; text-decoration: none; }
.items .tag.ok::before { background: var(--key-clear); }

/* The expansion is a table inside a cell; it must not inherit the row's padding twice, nor take
   a box of its own height inside the box it sits in. */
tr.detail-row .scroll { margin: var(--space-2) 0; max-height: none; }

/* --- THE REFRESH BAY -------------------------------------------------------------------
   A form that writes marks. `.tick` keeps the checkbox and its word on one line so a disabled
   row reads as one thing rather than two; `.wide-cell` lets the source take the width it needs,
   because a source that cannot be read back is not a source. */
.tick { white-space: nowrap; display: inline-flex; align-items: center; gap: 0.4ch; }
label.tick:has(input[disabled]) { color: var(--muted); cursor: not-allowed; }
td.wide-cell { min-width: 22rem; }
td.wide-cell input { width: 100%; }
/* A FETCHED FIGURE IS READ, NOT TYPED, so it sits in its cell as text; a rate the sweep left
   unpriced loses `readonly` and looks like an input again. */
td input[readonly] { border-color: transparent; background: transparent; padding-left: 0; }
/* A FIGURE IN AN INPUT READS DOWN ITS COLUMN like one in a cell: right-set under its `th.num`,
   and a read-only one flush to the edge the heading sits on. */
td.num input { text-align: right; }
td.num input[readonly] { padding-right: 0; }
/* A FIGURE TO BE TYPED READS ON THE SAME LINE AS A FETCHED ONE: its box reaches out into the
   cell's padding by exactly its own padding — a read-only field keeps its border, only
   transparent — so the text inside starts where the read-only text above it does, and only the
   box says it is waiting to be typed. The Price Refresh only: it is the one form where a typed
   figure sits in a column of fetched ones. */
#rb-form td input:not([readonly]):not([type="checkbox"]) {
  padding-left: var(--space-2); padding-right: var(--space-2);
  margin-left: calc(-1 * var(--space-2));
}
#rb-form td.num input:not([readonly]) {
  margin-left: 0; margin-right: calc(-1 * var(--space-2));
}

/* WHY IT WORKS THAT WAY, BELOW THE WORK IT DESCRIBES: explanation above a table dilutes its data,
   and the desk is for managing the accounts. The steps keep their state lines, which are the
   work; the explanations live here, closed by default. */
.why-fold { margin-top: var(--space-6); border-top: 1px solid var(--hair); padding-top: var(--space-3); }
.why-fold summary { cursor: pointer; color: var(--muted); font-size: var(--text-note); }
.why-fold dl { margin: var(--space-3) 0 0; max-width: 52rem; }
.why-fold dt { font-weight: 600; font-size: var(--text-note); margin-top: var(--space-3); }
.why-fold dd { margin: 0; color: var(--muted); font-size: var(--text-note); }

/* What Changed's earlier writes: the journal before the span its marks cover, folded. */
.earlier { margin-top: var(--space-3); }
.earlier summary { cursor: pointer; color: var(--muted); font-size: var(--text-note); }
.earlier[open] summary { margin-bottom: var(--space-3); }

/* =================================================================================
   Holdings, Round Trips, Performance: a panel uses the classes declared here, and invents none.
   ================================================================================= */

/* A WIDE TABLE SCROLLS INSIDE ITS OWN BOX. Without this the page itself scrolls sideways and the
   tab bar goes with it.

   BEST PRACTICE FOR A DESKTOP TABLE, NOT A SQUEEZE TO FIT: a table
   wider than the window keeps its columns whole and scrolls. The box is no taller than the
   window, so its heading row stays in view down a long table (Trades) and its sideways bar is
   on screen rather than under the last row; the first column, the row's name, stays put while
   the figures scroll under it. Every row is one line; a note is still clipped, whole on hover. */
.scroll { overflow: auto; max-height: calc(100vh - var(--space-5)); }
.scroll > table > thead > tr > th { position: sticky; top: 0; z-index: 2; background: var(--paper); }
.scroll > table > thead > tr > th:first-child { left: 0; z-index: 3; }
.scroll > table > tbody > tr:not(.detail-row):not(.devices) > td { white-space: nowrap; }
.scroll > table > tbody > tr:not(.detail-row):not(.devices) > td:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--paper);
}
/* THE PINNED EDGE shows only while the box scrolls sideways (`overflows`, set by app.js). */
.scroll.overflows > table > * > tr > :first-child { box-shadow: inset -1px 0 0 var(--hair); }
.scroll > table > tbody > tr.differs > td:first-child {
  background: color-mix(in srgb, var(--warn) 20%, var(--paper));
}
.scroll > table > tbody > tr:not(.detail-row):not(.devices):not(.differs):hover > td {
  background: var(--band);
}
/* ITS SCROLLBAR SITS UNDER THE LAST ROW, NEVER ON IT. Safari on a Mac draws an overlay bar, painted
   over the box's last row. A styled bar is a classic one: it takes its own 10px below the table,
   appears only while the table is wider than the window, and stays in view while it does, so the
   hidden columns are evident. The thumb is a control, so it takes the control boundary's colour. */
.scroll::-webkit-scrollbar { height: 10px; width: 10px; }
.scroll::-webkit-scrollbar-thumb {
  background: var(--control); border-radius: var(--radius-pill);
  border: 2px solid transparent; background-clip: padding-box;
}
.scroll::-webkit-scrollbar-thumb:hover { background-color: var(--muted); }

/* A LONG NOTE MUST NOT SET THE ROW HEIGHT. Round Trips carries the WHY, and some run to several
   sentences. One line, ellipsis, full text on hover. The note is not lost. */
td.clip {
  max-width: 26rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* WHERE THE EXPOSURE SITS: three small tables side by side under Holdings, each slice a bar on
   the report's colours (band under chart). The bar takes the width its table leaves. */
.allocs { display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
          gap: var(--space-6); align-items: start; }
.page table.alloc { width: 100%; }
td.alloc-bar { width: 100%; }
td.alloc-bar svg { display: block; width: 100%; min-width: 4rem; height: 10px; }
td.alloc-bar rect { fill: var(--chart); }
td.alloc-bar rect.track { fill: var(--band); }
td.oneline { white-space: nowrap; }

/* THE DASHBOARD'S GLANCE: its figures beside what needs attention; on a phone, below them, as
   beside them the list would be one letter wide. */
.glance { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-6);
          align-items: start; }
@media (max-width: 48rem) { .glance { grid-template-columns: minmax(0, 1fr); } }
.glance > section > h2 { margin-top: 0; }

/* Headline figures above a table, the same shape the Dashboard uses. */
table.figures { width: auto; margin-bottom: var(--space-3); }
table.figures td { border-bottom: 0; padding: 2px var(--space-3) 2px 0; }
table.figures td:first-child { color: var(--muted); }
table.figures td.num { font-weight: 600; padding-right: 0; }
/* A HEADLINE FIGURE KEEPS ITS LABEL'S SIZE: the note size is for a column, which is short of
   width, and a list of figures beside their labels is not. */
table.figures td.num { font-size: var(--text-body); }
table.figures tr.lead td { font-size: var(--text-lead); }
table.figures tr.lead td:first-child { color: var(--ink); }
table.figures td.indent { padding-left: var(--space-5); }

/* THE FILTER ROW — one shape on every tab that has one: the `.f` box, the bench's field, ONE idea
   of a labelled control. The grid's gap keeps a label off the select beside it.

   NARROWER THAN A BENCH FORM. A bench field holds a note and wants 15rem; a filter holds a date
   or a short list and reads better in a tighter track, so more of them fit on one line. */
.grid.filters { grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
                margin-bottom: var(--space-3); }
.grid.filters .f input, .grid.filters .f select { width: 100%; min-width: 0; max-width: none; }
.filter-clear { margin: 0 0 var(--space-5); }

/* THE COMBOBOX: start typing and find the ticker.
   Not a <datalist>: Safari does not filter one as you type. */
.combo { position: relative; }
.combo input { width: 100%; }
.combo-list {
  position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
  margin: 2px 0 0; padding: 0; list-style: none;
  max-height: 15rem; overflow-y: auto;
  /* A DROPDOWN OVER A PANEL NEEDS AN EDGE or it reads as part of the form beneath it. The design system draws
     edges with borders, never shadows, so it takes the strong rule. */
  background: var(--paper); border: 1px solid var(--rule);
}
.combo-list li { padding: var(--space-2) var(--space-3); cursor: pointer; }
/* `.on` IS KEYBOARD POSITION, hover is the mouse. Both look the same on purpose: there is one
   highlighted row and Enter takes it, however you got there. */
.combo-list li.on, .combo-list li:hover { background: var(--band); color: var(--ink); }

/* A LINK IN A TABLE CELL MUST NOT WRAP mid-word — a broken link makes rows uneven. */
td.nowrap { white-space: nowrap; }

/* THE DETAIL: a link at the end of the row, what it opens at full width below it. An unopened
   row is one line high, which is what "the rows are tighter" asks for, and an opened detail gets
   the whole width rather than a column. */
/* LOWER CASE, LIKE EVERY OTHER LINK.
   Reasoning headings are sentence case (docs/glossary.md §5). */
.detail-toggle { font-size: var(--text-note); }
.detail-row { color: var(--muted); font-size: var(--text-note); }
.detail-row p { margin: var(--space-2) 0 0; max-width: var(--measure); }
/* THE METHOD PAGE: the methodology, read down. */
dl.method { max-width: var(--measure); }
dl.method dt { font-weight: 600; margin-top: var(--space-4); }
dl.method dd { margin: var(--space-1) 0 0; }
/* WHAT A ROW'S DETAIL HOLDS, each part under its heading: prose read down, not a table scanned
   across. The mark history is the one table, and takes the width. */
.detail-row dl.detail { margin: var(--space-2) 0 0; }
.detail-row dl.detail dt { font-weight: 600; margin-top: var(--space-2); }
.detail-row dl.detail dd { margin: 0; max-width: var(--measure); }
.detail-row dl.detail dd.wide { max-width: none; }

/* THE THREE EVIDENCE BOXES LINE UP. The three statement-grade limbs carry help text of different
   lengths. As a grid with a flexible label row and an auto input row, the label area absorbs the
   difference and every input in a row starts on the same line. Applies to every form field
   here, not only the limbs. */
.f { display: grid; grid-template-rows: 1fr auto; align-content: start; }
.f > span { align-self: start; }

/* A SELECT MUST NOT BE SIZED BY ITS CONTENTS ALONE. A native select shrinks to its widest
   option, so a short list clips its own words. A floor stops that, and a ceiling stops one long
   account name stretching the list. In a FILTER grid the track supplies the width instead, which
   is why .grid.filters overrides both bounds. */
.f select { min-width: 9rem; max-width: 18rem; }

/* A DETAIL ROW INSIDE A TABLE: a pane cannot sit inside a <tr> and still span the table, so it
   IS the next row. No display rule, so [hidden] keeps working. */
tr.detail-row td { border-bottom: 1px solid var(--hair); }
tr.detail-row p { margin: 0; max-width: var(--measure); }



/* THE DESCRIPTION AND THE STATUS HOLD ONE SHAPE — one left, one right, neither wrapping into the
   other.

   A SWEPT ROW TAKES THE SCREEN. `body.data #main .items li` holds a list item to the PROSE
   measure, which is right for every other list on the desk and wrong for this one: a swept row
   carries a generated CSV line. That is data, it is the widest thing here, and it is exactly what
   a wide window is for. */
/* THE SELECTOR HAS TO OUTRANK THE RULE IT IS EXCEPTING. `.items li.swept` loses to
   `body.data #main .items li` on specificity — (0,2,1) against (1,2,2). Matched shape, one class
   deeper. */
body.data #main .items li.swept { max-width: none; }
.swept-head { display: flex; align-items: baseline; gap: var(--space-5); width: 100%; }
.swept-what { flex: 1 1 auto; min-width: 0; }
.swept-do { flex: 0 0 auto; margin-left: auto; text-align: right; white-space: nowrap; }
.swept-meta { margin: 2px 0 0; font-size: var(--text-note); }

/* An event on the bench says what it still owes, beside it. */
.swept-state { flex: 0 0 auto; margin-left: auto; white-space: nowrap; }
