/* ============================================================================
   FORTRESS CANONICAL SIGNED-IN UI LAW

   The signed-in product uses a dark navy operational ground with restrained
   light data plates. Light surfaces carry work; they do not themselves imply
   verification or evidential integrity.

   Hierarchy is created first through typography, spacing, rules and
   composition. Colour supports meaning and must never carry meaning alone.

   Canonical compliance status uses three accessible tone pairs: critical,
   warning and positive. Compact rectangular status labels are permitted.
   Decorative badges and generic pills are prohibited. Large red, amber or
   green decorative surfaces are prohibited.

   Interactive refinements are controls, not statuses. Teal identifies
   interaction, selection and focus; it never represents compliance state.

   Canonical typography is DM Sans and JetBrains Mono at weights 400 and 500
   only. Monospaced type is reserved for precise factual information rather
   than ordinary prose.

   Canonical light surfaces are limited to the primary data plate, the subtle
   secondary plate and the inspector surface. Their roles must remain distinct
   and additional near-white layers must not be introduced casually.

   Sealed or verified artefacts use an explicit provenance treatment, including
   the relevant mark, fingerprint/reference, timestamp and verification
   language. Evidential authority must not depend on surface colour.

   Shared vocabulary defines reusable visual and interaction patterns. Each
   page controls its own composition and domain language.

   The compatibility layer exists only for unmigrated pages. No new development
   may use it. It is removed when every signed-in route has migrated to the
   canonical data-fortress-ui layer.

   -- GENERATED, NOT WRITTEN --------------------------------------------------
   Extracted from the locked baseline board FORTRESS-PORTAL-DESIGN-P-2026-09-03
   .html by scripts/build-fortress-ui.mjs, which subtracts the board's own page
   chrome (the specimen frame, the masthead and the calibration plate) and
   nothing else. Every value, comment and rule below is the board's.

   DO NOT HAND-EDIT THIS FILE. The board is the executable copy and wins any
   disagreement with the specification. To change the system you change the
   board, then re-run scripts/build-fortress-ui.mjs. A hand edit here silently
   forks the product from its own design authority.
   ========================================================================== */

/* ==================================================================================================
   BOARD MAP · FOUR PARTS (v20). Controlling law: the generated fortress-ui.css header.
   The parts are physically INTERLEAVED, not contiguous: reordering rules would churn the generated
   stylesheet, which the build gate forbids -- so they are signposted in place.
     PART 1 · CANONICAL RULES           the .app[data-fortress-ui] token layer (below).
     PART 2 · REUSABLE VOCABULARY       the .fui-* components (near the end).
     PART 3 · PAGE COMPOSITION          not here -- each page owns its grid, sizing and domain language.
     PART 4 · DEPRECATED COMPATIBILITY  the white-led vocabulary (the legacy :root that follows and the
                                        unprefixed components below it), compatibility-only.
   ================================================================================================== */

/* -- PART 4 · DEPRECATED COMPATIBILITY (white-led) -------------------------------------------------
   From here to the CANONICAL SIGNED-IN LAYER is the deprecated white-led vocabulary, kept only so
   unmigrated pages keep working; no new signed-in development uses it. Retained shared FOUNDATION
   (Jordan, 9 Sep 2026): the spacing scale, the --navy token, the rule weights, the shell/rail
   geometry, breakpoints and focus / reduced-motion. Deprecated: the white-canvas doctrine, the
   white-led components, IBM Plex, and the fire-red / signal-yellow / grass-green status model. */
:root{
  /* WHITE-LED -- DEPRECATED (v20): compatibility-only. In the canonical signed-in system the ground
     is the dark navy plane and light data plates carry the work (see the fortress-ui.css header); the
     text below governs legacy (unmigrated) pages until they opt in.
     The workspace is white and recedes completely. Structure comes
     from rule, spacing and type - not from tinted planes. A neutral surface now
     has to earn its existence; almost none do.

     v9 CORRECTS A DOCTRINE, NOT A LAYOUT. The old rule was "colour is scarce",
     and scarcity had leaked into the type: ordinary working information —
     owners, dates, addresses' branch suffixes, chevrons, chart annotation —
     was being rendered secondary or tertiary because it happened to be
     metadata, not because it was unimportant. The result read as fog.
     The rule now is COLOUR IS PURPOSEFUL. Three text steps, assigned by what
     the information IS rather than which column it sits in:
       --ink   #0E1621  18.2:1  addresses, names, owners, principal values,
                                actions, headings, ordinary operational copy
       --ink-2 #4D5865   7.2:1  genuine context — branch suffixes, descriptive
                                second lines, supporting metadata, labels
       --ink-3 #6B7480   4.7:1  used sparingly: pagination, breadcrumbs,
                                placeholders, superseded timestamps
     Grey is now for rules, borders and recessed states. Not for words. */
  --canvas:#FFFFFF; --rail:#FBFBFC;
  --surface:#FFFFFF; --surface-2:#F3F5F6;   /* recessed / disengaged ONLY */
  --navy:#142035;        /* EVIDENTIAL INTEGRITY ONLY — seal, fingerprint, record rule, mark */
  --steel:#5A6472;       /* boundaries and service notes — deliberately not navy */
  --ink:#0E1621; --ink-2:#4D5865; --ink-3:#6B7480;
  --on-dark:#F2F4F6; --on-dark-2:rgba(242,244,246,.66); --on-dark-3:rgba(242,244,246,.54);
  /* With canvas and card both white, the rule IS the structure. Three weights:
     --line   internal dividers, quietest thing that still divides
     --line-2 ordinary structural rules
     --edge   the boundary of an object sitting on white - one step firmer,
              because on a white-on-white ground nothing else defines the card
     --line-3 actual control boundaries (inputs, selects, radios, checkboxes) */
  --line:#EEF1F4; --line-2:#E6E9EE; --edge:#DCE0E6; --line-3:#B4BAC2;
  /* THREE LEVELS OF STRUCTURAL AUTHORITY, and only three:
       2px --ink      5.9:1 against the peer rule      PRINCIPAL apparatus.
                      Five in the whole product: the Portfolio register, the
                      Today chart, its baseline, the judgement assembly and
                      the evidence register. Nothing else earns it.
       1px --rule-2   3.1:1 on white                   REPEATED PEER SECTION.
                      A machined division between service categories and
                      queue sections. Firm, never pale, never principal.
       1px --line/-2  1.1-1.2:1                        ORDINARY ROW HAIRLINE.
     v13 gave every repeated section heading a 2px ink rule, so nine peer
     divisions carried principal authority and the hierarchy flattened. */
  --rule-2:#8C939C;
  /* ── THE SIGNAL SYSTEM ────────────────────────────────────────────────
     DEPRECATED (v20): legacy white-led status colour, compatibility-only. Canonical signed-in status
     uses the three --fui-status-* tone pairs (critical / deep-amber warning / positive); see the
     fortress-ui.css header. The model below governs legacy pages until they migrate.
     One palette. The old split - muted burgundy / brown amber / forest green
     for the UI, saturated instrumentation colour for the chart - was two
     personalities in one product. The saturated character is the correct one,
     so the whole signal system moves to it.

     SATURATION IS ALLOWED. AREA IS RATIONED. Sophistication comes from tiny,
     exact amounts of unequivocal colour, not from muting it. Rails are 3-5px,
     telltales are 7px squares, key values are single words. Nothing is washed.

     --brc      fault TEXT      4.8:1 on white, the accessible member of the
                                fire-red family. Never burgundy.
     --brc-fill fault FILL      the fire-engine red itself: rails, telltales,
                                the chart peak, the invalid boundary. There is
                                no filled chip left anywhere in the product.
     --adv      attention       signal yellow. A RAIL OR A SQUARE, NEVER TEXT
                                - 1.4:1 on white. Attention text stays dark ink.
     --ok       confirmed       grass green. Ticks and marks only, never prose.
     --sig-blue analytical      the plotted series. NOT the evidential navy:
                                hsl(220 72% 51%) against navy's hsl(218 45% 14%). */
  --ok:#35A853;
  --adv:#FFD400;
  --brc:#D92D20;  --brc-fill:#E53935;
  --sig-blue:#2864DC;
  --t-meta:12px; --t-ui:13px; --t-row:14px; --t-sec:16px; --t-page:21px; --t-metric:26px;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px;
  /* THE SIGNAL CHANNEL. One width for every state. The channel's job is
     POSITION and COLOUR; it must not also encode rank in its own width.
     Three widths (3/4/5px) put its right edge at 20/21/22px down the page,
     which reads as tolerance, not as ranking. Critical stays distinguished
     twice over: the 7px telltale before the issue count and the 700-weight
     elapsed value. 4px, because lemon yellow needs the area.

     THE CHANNEL IS GEOMETRY. SEVERITY IS INFORMATION WITHIN IT.

     --sig-w is not "every coloured vertical line". It is one component with
     one mechanical job, and it is spent on the repeated ranked objects that
     share that job - the register rows and the Today count strip. Objects
     with a different job carry their own deliberate dimension, and there
     are exactly three of them in the product:

       3px  AN ORDINARY SIGNAL ON A SINGLE OBJECT
            the Review consequence rule, the Today data plate's rule.
       4px  THE STATE CHANNEL  (--sig-w)
            repeated rows and counts, ranked against each other.
       5px  MECHANICAL PREVENTION OF COMPLETION
            the Completion Interlock, and nothing else.

     Systemisation is not one token for every line. It is one specification
     for every object that does the same work. */
  --sig-w:4px;
  --r:3px;   /* --r-chip retired with the last status badge */
  --mono:'IBM Plex Mono','SF Mono',Monaco,Consolas,monospace;
  --sans:'IBM Plex Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   PART 1 · CANONICAL RULES — CANONICAL SIGNED-IN LAYER (v20), the FORTRESS operations design system.

   This is the DESTINATION design system for every signed-in page. A page opts in with
   `data-fortress-ui` on its .app shell; until it does, it keeps the DEPRECATED COMPATIBILITY layer
   below (the white-led board vocabulary). New signed-in development MUST use this layer, and
   `data-fortress-ui` stays the canonical marker after the compatibility layer is deleted.

   Everything here is namespaced `fui` — tokens `--fui-*`, components `.fui-*` — so it cannot collide
   with a legacy page's own unprefixed classes or variables as that page opts in.

   COMPATIBILITY-LAYER REMOVAL CONDITION: delete the legacy vocabulary only when the generated route
   inventory confirms every signed-in shell route carries `data-fortress-ui`. Do not describe the
   legacy layer as an equally valid visual system; it is compatibility only, no new development. */
.app[data-fortress-ui]{
  /* ── SEMANTIC SURFACES ─────────────────────────────────────────────────────────────────────── */
  --fui-surface-app:#0A1322;            /* signed-in application ground (the dark plane) */
  --fui-surface-shell:#102036;          /* navigation / rail */
  --fui-surface-raised:#1B2D4A;         /* raised navy control: view strip, primary action */
  --fui-surface-plate:#FFFFFF;          /* light operational data plate */
  --fui-surface-plate-subtle:#FBFAF8;   /* bone plate — a quieter plate, distinct from pure white */
  --fui-surface-inspector:#F3F2F0;      /* subdued inspector / context surface */
  /* ── RULES ─────────────────────────────────────────────────────────────────────────────────── */
  --fui-rule-light:#D9D7D2;             /* separator on a light plate */
  --fui-rule-dark:#26364F;              /* separator on a dark surface */
  /* ── TEXT HIERARCHIES ──────────────────────────────────────────────────────────────────────── */
  --fui-text-primary:#0F1B27;           /* ink on light */
  --fui-text-muted:#5C6675;             /* muted on light */
  --fui-text-on-dark:#F5F4F1;           /* text on dark surfaces */
  --fui-text-on-dark-muted:#9EB1C0;     /* muted on dark */
  /* ── STATUS TONES (single-purpose fg + bg; components map product states onto a tone) ────────
     critical ← overdue / expired / failed;  warning ← attention / awaiting evidence / due soon;
     positive ← complete / current / satisfied. Status is NEVER colour alone — always paired with
     text and, where useful, a marker. Large areas must not be tinted to decorate a state. */
  --fui-status-critical-fg:#A52D2D;   --fui-status-critical-bg:#F5DEDE;
  --fui-status-warning-fg:#875A08;    --fui-status-warning-bg:#F4E6BF;
  --fui-status-positive-fg:#17684F;   --fui-status-positive-bg:#D8EDE5;
  /* ── INTERACTION (teal) — NEVER a status. Selection, active, controlled emphasis, links.
     Teal is too dark to read on navy, so on-dark interaction uses the lighter tone; both are
     defined rather than weakening contrast. Focus ring is its own token. */
  --fui-interaction:#0B6E6E;            /* on light plates */
  --fui-interaction-on-dark:#73B9B2;    /* on the navy shell / dark surfaces */
  --fui-focus-ring:#73B9B2;
  /* C7 / S2 (Marco, 22 Oct 2026) · THE RING ON A LIGHT SURFACE. #73B9B2 reads on navy (8.25:1) and not on a light
     plate (2.26:1 on white, 1.94:1 on the context-note ground), under the 3:1 a focus indicator needs. #0B6E6E is 6.05:1
     on white and 5.41:1 on the inspector, and is kept OFF navy, where it would be 3.07:1. --fui-focus-ring is set per
     surface in Part 2 — a custom property inherits, so no specificity contest decides the colour. */
  --fui-focus-ring-light:#0B6E6E;
  /* C6 (Marco, 22 Oct 2026) · A CONTROL'S BOUNDARY. #8C939C is 3.10:1 on white. The specification's #B5BABD was 1.96:1
     and the plate rule #D9D7D2 1.44:1: neither reads as the edge of something you can type into. */
  --fui-control-border:#8C939C;
  /* ── TYPE (scoped, so only opted-in pages take DM Sans — legacy pages keep their own link) ──── */
  --fui-font-sans:'DM Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --fui-font-mono:'JetBrains Mono','SF Mono',Monaco,Consolas,monospace;
  /* the app ground and base type, applied when a page opts in */
  background:var(--fui-surface-app);
  color:var(--fui-text-on-dark);
  font-family:var(--fui-font-sans);
}

*{box-sizing:border-box}
/* ── Two platform defaults the board itself never meets ─────────────────────
   The board draws every component in its visible state, and every clickable
   thing on it is a div or a button. Real pages are not like that, and both
   gaps were found by rendering converted pages, not by reading:

   [hidden] — a class that sets a display value silently defeats the browser's
   own [hidden]{display:none}, because any author declaration outranks the UA
   sheet. Measured on .err-t and .counts: both stayed on screen when a page
   tried to hide them. !important rather than source order, because [hidden]
   is 0-1-0 and would still lose to a compound like .pk-h .ok.

   a — the board's only anchors are the rail's, which .rail a already resets,
   so nothing here ever exercised the two ways a real page uses one:

     AN ANCHOR WITH A CLASS IS A COMPONENT, and says how it looks. A register
     row built as an <a> was taking the UA underline in rgb(0,0,238) over the
     top of its own treatment — measured on the dashboard's .status-row, which
     is this product's principal object.

     AN ANCHOR WITH NO CLASS IS PROSE — "start one from the AML section of the
     dashboard", "all records for this property" — and there are about thirty
     of them across fourteen pages, almost all inside template strings. Those
     need to read as links, and the UA was the only thing making them do it.

   So the default is the system's own link, the one .tools-link draws: ink,
   a --line-3 rule at a 3px offset, firming to full ink on hover. A component
   turns it off by having a class at all.

   Neither rule adds a colour, component, radius or type step. */
[hidden]{display:none!important}
a{color:inherit;text-decoration:none}
a:not([class]){text-decoration:underline;text-decoration-color:var(--line-3);
  text-underline-offset:3px}
a:not([class]):hover{text-decoration-color:var(--ink)}

/* ── And the third: bare heading elements ───────────────────────────────────
   The board titles everything with a class — h2.pt, .cap, .sec — so the
   extracted stylesheet says nothing about a bare <h2>. Real pages are full of
   them: 51 of 54 use h2/h3/h4 and not one page styles them, so every section
   heading in the product was rendering at the browser's default. Measured:
   h2 at 19.5px and h3 at 15.21px, neither of which is a step on a scale §6
   freezes at 12 / 13 / 14 / 16 / 21 / 26.

   Weights are 600 throughout, which is the weight the system gives a heading.
   h2.pt keeps the page-title step and outranks this at 0,1,1. A page that
   sets its own heading rule still wins, since its <style> follows the link.

   h1 is written as h1:not([class]) deliberately. A bare `h1` selector is the
   board's own masthead rule, which build-fortress-ui.mjs subtracts as page
   chrome by exact selector — it removed this one too, and the verifier caught
   it. The narrower selector is also the honest one: a classed h1 has said what
   it is. */
h1,h2,h3,h4,h5,h6{font-weight:600;color:var(--ink);letter-spacing:-.012em}
h1:not([class]){font-size:var(--t-page);letter-spacing:-.015em;margin:0 0 var(--s3)}
h2{font-size:var(--t-sec);margin:0 0 var(--s3)}
h3{font-size:var(--t-row);margin:0 0 var(--s2)}
h4,h5,h6{font-size:var(--t-ui);margin:0 0 var(--s2)}

/* THE SECTION DIVISION. A record is a run of ruled rows on the white plane —
   identity comes from heading, rule and rhythm, not from a rectangle, and zero
   four-sided boxes exist in the product. The name is a fossil.

   45 of 49 pages define .card locally and every copy says the same thing, so
   the division the product actually uses was written forty-five times and
   specified nowhere. That is how two pages drifted onto a SECOND heading
   vocabulary — .card-title / .card-subtitle, a step smaller at --t-row and
   carrying no rule at all — while the other three used the ruled h2 the
   comment beside it calls "a peer division, one firm rule". Same level of
   heading, same batch, two renderings, because there was no authority to
   disagree with.

   Stated once here. A page's <style> still follows the link, so a page that
   genuinely needs its own division keeps it by saying so. */
.card{background:none;border:0;border-radius:0;padding:var(--s5) 0;margin:0}
.card+.card{border-top:1px solid var(--line-2)}
/* the heading and its explanation — a peer division, one firm rule */
.card>h2{font-size:var(--t-sec);font-weight:600;letter-spacing:-.01em;color:var(--ink);
  margin:0 0 var(--s2);padding:0 0 var(--s2);border-bottom:1px solid var(--rule-2)}
.card>.sub{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s4);line-height:1.65}
/* A division closes the composition it opens. Two of the five safety-certificate
   pages ended on a button and 80px of dead white, because the terminal rule was
   only ever drawn by .card+.card — which cannot fire on the last one. */
.card.end{border-bottom:1px solid var(--line-2)}

/* THE RECORD SAYS WHICH RECORD IT IS. Every certificate form in the product opens
   on "Choose a property…" and then never names the property again. An agent keying
   six in a row has nothing on screen to catch the fifth going in against the
   sixth's address, and the named person who signs it off is reading a page that
   does not say what it is about. Typography, not a component — the same figure and
   weight relationship .agg already uses. */
.rec-id{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s4)}
.rec-id b{color:var(--ink);font-weight:600}

/* A DERIVED VALUE IS NOT A CONTROL. epc-mees drew the MEES position as a form field —
   same border, same height, same interior padding as the editable inputs two rows above
   — while its own copy said, in bold, "you don't set it". The drawing argued with the
   doctrine, and the doctrine is the product's whole position on what the machine owns.
   A value the machine owns is typography. data-empty carries the not-yet state so an
   empty derived value still says what will fill it. */
.derived{font-size:var(--t-ui);color:var(--ink);font-weight:600;padding:var(--s2) 0;min-height:19px}
.derived:empty::before{content:attr(data-empty);color:var(--ink-3);font-weight:400}

/* THE RECORD ROW. A run of these under a section heading is how this product lists anything:
   a title, a line of secondary detail, a state at the right, and where it needs one, a sentence
   underneath saying what the state means. No card, no border but the one between rows.

   Stated here because the second page needed it. gas-chase-status defined .item / .addr / .why
   locally and rtr-checks was about to hold a second copy — which is the shape this batch has
   already found four times in one file. .h is the head row: title block left, state right. */
.item{background:none;border:0;border-bottom:1px solid var(--line-2);border-radius:0;
  padding:var(--s4) 0;margin:0}
.item:last-of-type{border-bottom:0}
.item .h{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s3);flex-wrap:wrap}
.item .addr{font-size:var(--t-row);font-weight:600;color:var(--ink);letter-spacing:-.008em}
.item .meta{display:flex;flex-wrap:wrap;gap:0 var(--s3);font-size:var(--t-ui);color:var(--ink-2);margin-top:2px}
.item .meta b{color:var(--ink);font-weight:600}
/* the sentence under a row that says what its state means — secondary, measured, never a panel */
.item .why{font-size:var(--t-ui);color:var(--ink-2);line-height:1.65;margin-top:var(--s2)}
.item .why b{color:var(--ink);font-weight:600}

/* A CHECKBOX IN A TWO-COLUMN ROW ALIGNS TO THE CONTROL BESIDE IT, not to the label
   above that control. The three on eicr-observations each carried an inline
   margin-top:24px — a magic number guessed once and copied twice — and each sat
   about 23px off the label of its own paired field. The cell is already a stretched
   column; pushing its content to the foot lands the box on the input's line without
   anyone measuring anything. */
.field.pair{justify-content:flex-end}

body{margin:0;background:var(--canvas);color:var(--ink);font-family:var(--sans);font-size:var(--t-ui);line-height:1.5;
  -webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;
  @media screen{&:has(> .app[data-fortress-ui]:not(#clMfaOverlay)){background:#0A1322;font-family:'DM Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif}}}
/* Explicit keyboard focus. Royal blue is the analytical colour and it means
   ONE more thing: the keyboard is here. It is never a fill, a glow or a
   shadow. .is-focus is the same declaration, held open so a static board
   specimen can show the state a real control reaches by being focused. */
:focus-visible,.is-focus{outline:2px solid var(--sig-blue);outline-offset:2px}

/* ============================== SHELL ==================================== */
.app{display:grid;grid-template-columns:210px minmax(0,1fr);background:var(--canvas);color:var(--ink);font-size:var(--t-ui);line-height:1.5}
/* THE TWO COLUMNS NOW START ON THE SAME LINE. The rail opened at --s4 and the content column at
   --s6, so the wordmark and the page title — the two most prominent typographic objects on every
   screen in the product — sat on no common line at all, 18.6px apart at the baseline and 16.9px
   at the cap centre. Taking the rail's top padding to --s6, the value .body already uses, puts
   the lockup's optical centre 0.9px from the page title's cap centre and the wordmark's own cap
   centre 0.9px from it as well. Measured, not estimated.

   It is the same token rather than a new one BECAUSE that is the argument: the two columns are
   now offset from the top by the same amount, which is a grid decision, where a hand-picked
   34.6px that happened to match baselines would have been an arbitrary one.

   It also settles a second, quieter fault. The standfirst and the first nav item used to sit
   2.5px apart — close enough to read as a mistake, since nothing else in the system misses by
   two pixels. They are now 18.5px apart, which reads as what it is: two columns with their own
   rhythms, deliberately not interleaved. */
/* H11 (Jordan, 2026-09-04). The rail was a plain grid column, so it scrolled away with the page
   and an agent lost the way around the product the moment they started reading. Sticky needs an
   element that is not stretched to the row height, so align-self:start went on .rail — which also
   made the rail exactly as tall as its own content.

   min-height (Jordan, 6 Sep, folder-04 review). On a 900px window the rail measured 741px on
   landlords and 592px on the public page, so border-right — the one rule dividing navigation from
   content, on every screen in the product — stopped short of the bottom of the frame and the left
   column became undivided white. min-height:100vh took it to the floor.

   THE SPLIT (Jordan, 6 Sep, folder-05 review). 100vh is the viewport, and the viewport is not the
   document. Every one of those rules still described a column exactly one screen tall, so on any
   page LONGER than the window the same fault returned lower down: on the 1,914px obligations form
   the rule stopped at 897px and a thousand pixels of form sat with no left boundary at all. Every
   reviewer read it as a page that had failed to finish rendering.

   A single element cannot be both stretched to the document and sticky to the viewport, so it is
   now two. .rail is the grid column and carries the ground and the rule: it takes the default
   align-self:stretch, so it is as tall as the row — the whole document, however long the page is.
   .rail-in is the sticky group inside it, and keeps the viewport-height behaviour the navigation
   needs, max-height and overflow-y still governing the short-window case. Nothing about what the
   rail LOOKS like changes; the rule simply now reaches the floor of the page rather than the floor
   of the screen. All rail selectors are descendant (.rail .lock, .rail a, .rail .g, .rail .foot),
   so the added wrapper does not break any of them. */
/* THE RAIL IS NAVY (Jordan, 7 Sep 2026; CANONICAL 9 Sep 2026). Ground = --navy, text = the on-dark
   family, the Gatehouse mark inverts to light. Navy is no longer a scarce evidential accent: in the
   canonical signed-in system it is the operational ground (see the fortress-ui.css header), and the
   rail is navy in both the legacy and the canonical shell. Evidential integrity no longer rests on
   surface colour -- sealed artefacts carry an explicit provenance treatment (mark, fingerprint,
   timestamp, verification language) instead.
   The right border is dropped — navy against the white content column is its own boundary. */
.rail{background:var(--navy);border-right:0}
/* THE FOOT STAYS, THE NAV SCROLLS (7 Sep — replaces the 6 Sep "fits or lets go", and the media
   query below is deleted with it). The 6 Sep fix stopped the identity foot painting over the last
   nav links, but on a window shorter than 900px it moved the problem rather than solving it: the
   rail flowed with the page and the foot — Sign out included — dropped below the fold, so on a
   13-inch laptop the sign-out button looked gone. That broke the rail's own rule, stated two
   comments down, that identity is the last thing that should leave the screen.
   The honest fix keeps the foot pinned and scrolls the NAV instead. .rail-in is a flex column
   exactly one viewport tall; the lockup and the foot are flex:none, fixed at top and bottom; the
   nav groups live in .rail-scroll between them, which takes the remaining space and scrolls only
   when it must. Identity is visible at every height, nothing overlaps, and a scrollbar appears
   only when the window genuinely cannot show all seventeen destinations — a truer signal that
   there is more than hiding either the foot or the links. .rail stays the full-document grid
   column carrying the ground and the rule; only this inner group changes, and it needs a wrapper
   in the markup (fortress-shell.js) so the nav can be the one thing that scrolls. */
.rail-in{padding:var(--s5) 0 0;display:flex;flex-direction:column;
  position:sticky;top:0;height:100vh;overflow:hidden}
.rail-scroll{flex:1 1 auto;min-height:0;overflow-y:auto}
.rail .lock{display:flex;align-items:center;gap:var(--s2);padding:0 var(--s4) var(--s4);flex:none}
/* The phone-rail Menu toggle lives in the rail markup on every page but shows only below 900px
   (see the hamburger block in the mobile media query). Hidden here so the desktop rail is unchanged. */
.rail-toggle{display:none}
/* THE LOCKUP, RESIZED (Jordan, 6 Sep): "a bit like an afterthought in the top left corner".
   22px and 13px were the smallest things in the rail, below the weight of the nav labels they
   sat above, so the product signed its own interface in a whisper. Both halves move up one
   step together — the mark to 30px, the wordmark from --t-ui to --t-sec — which is a quarter to
   a third larger without touching the 210px rail or the type scale. No new type step: --t-sec
   already exists and is the next one up. Measured across the rail's 178px of content width the
   lockup now occupies about 130px, so it has not become the widest thing there either.
   The mark grows slightly more than the wordmark because it has to: the full Gatehouse carries
   six portcullis bars at 3/100 of its box, and below about 28px they stop reading as bars. */
.mk{width:30px;height:30px;flex:none;display:block;fill:#102036}
/* the knockout inside the Gatehouse mark carried a hardcoded #F1F2F4, which
   put a stray grey shape inside the logo on a near-white rail. It now takes
   the rail's own value. Geometry untouched. */
.mk-k{fill:var(--rail)}
/* wordmark set in the product face. The brand kit's lockup SVG typesets this
   as live DM Sans text, so it is not a self-contained asset — flagged.
   BOTH HALVES NOW TAKE THE BRAND-KIT NAVY #102036 rather than the --navy token
   (#142035). The sign-in lockup already made this argument and it holds here for
   the same reason: a mark and a wordmark four units apart inside one lockup read
   as a printing error, and the brand kit is the authority for the mark. --navy
   stays what it is everywhere else — the evidential colour, not a brand colour. */
.wm{font-weight:600;letter-spacing:.10em;font-size:var(--t-sec);color:#102036}
/* On the navy rail the mark inverts: a light Gatehouse whose knockout is the navy ground, and a
   light wordmark. Scoped to .rail — off-rail (login, password screens) the mark stays the dark
   brand-kit navy on white. */
.rail .mk{fill:var(--on-dark)}
.rail .mk-k{fill:var(--navy)}
.rail .wm{color:var(--on-dark)}
/* the old border-based active marker is gone; its transparent placeholder
   was still shifting every nav label 2px right of the group labels above it */
.rail a{display:block;position:relative;padding:var(--s2) var(--s4);color:var(--on-dark);text-decoration:none;font-size:var(--t-ui)}
.rail a.on{font-weight:600;color:var(--on-dark)}
.rail a.on::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:3px;height:16px;background:var(--on-dark)}
.ng{display:block}
.rail .g{font-size:var(--t-meta);color:var(--on-dark-2);padding:0 var(--s4);margin:var(--s4) 0 var(--s1);font-weight:500}
/* C1 (Marco, 22 Oct 2026) · FIVE CORE DESTINATIONS, THREE FOLDING GROUPS, ACCOUNT UNDER THE NAME. The rail had 24 links
   and showed 9–11 on a laptop. fortress-shell.js now draws the five core destinations in .rail-core and every other
   destination in three groups whose heading is a <button class="g" aria-expanded> over a .ng-items list.
   The core is STICKY at the top of the scroll region, on the rail's own ground, so Today, Portfolio, Landlords, Inbox and
   Review queue never scroll away however many groups are open; the groups scroll beneath it. */
.rail .rail-core{position:sticky;top:0;z-index:1;background:var(--navy);padding-bottom:var(--s1);
  box-shadow:0 1px 0 rgba(242,244,246,.12)}   /* its lower edge reads as an edge: what scrolls beneath it goes UNDER a line, never "overlaps" (round 2) */
.rail button.g{display:flex;align-items:center;justify-content:space-between;gap:var(--s2);width:100%;min-height:32px;
  margin:var(--s3) 0 0;padding:var(--s1) var(--s4);background:none;border:0;cursor:pointer;text-align:left;
  font-family:inherit;line-height:1.4}
/* the disclosure mark: a drawn 6px chevron, down when open, right when folded — no glyph, no icon font */
.rail button.g::after,.rail .rail-me::after{content:'';flex:none;width:6px;height:6px;margin-right:2px;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:translateY(-2px) rotate(45deg)}
.rail button.g[aria-expanded=false]::after,.rail .rail-me[aria-expanded=false]::after{transform:rotate(-45deg)}
.rail button.g:hover,.rail a:hover{background:rgba(242,244,246,.06)}
/* B0.4 · THE RAIL SAYS WHEN THERE IS MORE BELOW. fortress-shell.js sets data-more on .rail-scroll while a link is hidden
   under its bottom edge; the last 28px then fade to the ground (a mask on the scroll box, so it stays at the box's foot
   while the links scroll under it). It also scrolls the current page's item into the visible part. */
/* round 2 (1710x600): the fade only hints — its last 16px dim to a third, never to nothing, so an item passing under it
   stays legible ("RISK & AML" and "PRS Database" read as hidden under the account block when the fade went to clear) */
.rail-scroll[data-more]{-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 16px),rgba(0,0,0,.35));
  mask-image:linear-gradient(to bottom,#000 calc(100% - 16px),rgba(0,0,0,.35))}
/* THE IDENTITY IS THE LAST THING THAT SHOULD LEAVE THE SCREEN. It is a flex:none sibling after
   .rail-scroll, so it sits at the foot of the column and stays there at every window height while
   the nav scrolls above it — no margin-top:auto, no sticky, no opaque ground painting over links,
   because nothing scrolls underneath it any more. */
.rail .foot{flex:none;padding:var(--s3) var(--s4) var(--s3);border-top:1px solid rgba(242,244,246,.14);
  font-size:var(--t-meta);color:var(--on-dark-2);line-height:1.6;background:var(--navy)}
.rail .foot b{display:block;color:var(--on-dark);font-weight:600;font-size:var(--t-ui)}
/* C1 · THE ACCOUNT PAGES UNDER THE NAME. The identity lines are a <button class="rail-me" aria-expanded> that opens the
   account pages (Your account, Team, Agency settings, Licences & memberships) beneath it; Sign out stays in view below. */
.rail .rail-me{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s2);width:100%;margin:0;padding:0;
  background:none;border:0;color:inherit;font:inherit;line-height:1.6;text-align:left;cursor:pointer}
.rail .rail-me::after{margin-top:8px}
.rail .rail-me-id{display:block;min-width:0}
.rail .rail-me-id span{display:block}
.rail .rail-account{margin:var(--s1) 0 var(--s1);border-left:1px solid rgba(242,244,246,.14)}
.rail .rail-account a{padding:4px var(--s3);font-size:var(--t-ui)}
.rail .rail-account a.on::before{height:14px}
.rail .rail-foot-acts{margin-top:var(--s1)}
/* THE PAGE HAS A MEASURE AND A FOOT (7 Sep). Two complaints from the folder-07 review turned out
   to be the same one. Short pages — the Renters' Rights pack, How to Rent, the fire-safety landing
   — ended two thirds up the frame with 250–430px of nothing under them, and read as unfinished
   rather than restrained; there was no closing edge because .card:last-of-type drops its bottom
   rule, so the page simply stopped. And on wide pages a row label sat a long way from the control
   it belonged to: on the deposit components table the gap from a component name to its date was
   588px, and it grew with the monitor.
   A measure fixes both. The content column stops at 980px, so a short page reads as a document
   column with deliberate proportion, and the last card takes a rule so the page has a foot.
   Left-aligned, not centred — everything in this product aligns left and a centred column would
   be a new idea.
   Measured before shipping, because this touches all 49 pages: eye travel from label to control
   falls 588→421px on the deposit table and 435→311px on fire safety. The cost is wrapping in the
   densest three-column tables — fire safety grows 3,949→4,027px, about 2%. A 20-page sweep
   outside folder 07 found no horizontal overflow anywhere and a worst case of +36px; landlords.html
   at 11,070px moved by one pixel. 1240px was tried and is nearly free, but recovers only 47px of
   the 588 and so does not buy the thing the rooms were complaining about. */
.body{padding:var(--s6);max-width:980px}
.body>.card:last-of-type{border-bottom:1px solid var(--line-2)}
/* THE LEGAL FOOTER (C3, Jordan, 22 Oct). The company identity and the four policy documents close every signed-in
   page: fortress-shell.js appends <footer class="fortress-legal"> as the last thing in the page's content column, in
   normal flow, so it is never sticky, covers nothing, is reached by scrolling and by Tab like the rest of the page,
   and prints on the last page. It used to sit in the rail, which on a phone put it in the sticky bar (at 320 x 256 the
   bar was taller than the screen: N1). Small type in the page's own text colour, so it reads on whichever ground the
   page has; a visible focus ring; every link at least 24px tall. */
.fortress-legal{margin-top:var(--s6);padding-top:var(--s3);border-top:1px solid color-mix(in srgb,currentColor 25%,transparent);
  font-family:var(--fui-font-mono,var(--mono));font-size:12px;line-height:1.6;color:inherit}
.fortress-legal-links{margin-top:var(--s1);display:flex;flex-wrap:wrap;gap:0 var(--s4)}
.fortress-legal a{display:inline-block;padding:4px 0;color:inherit;text-decoration:underline;text-underline-offset:2px}
.fortress-legal a:focus-visible{outline:2px solid currentColor;outline-offset:2px}
/* S1 (accessibility sweep, 22 Oct) · SKIP TO CONTENT. fortress-shell.js puts .fortress-skip first in the document and
   makes the page's content column (.app > .body) the main landmark, focusable by script. The link is off screen until it
   takes focus; then it is a light box with an ink inner ring, legible on either ground. The column itself draws no ring
   when the link sends focus to it — a 3px outline round the whole page is noise, and the next Tab lands in the page. */
.fortress-skip{position:absolute;left:var(--s4);top:-200px;z-index:200;padding:var(--s2) var(--s3);
  background:var(--canvas);color:var(--ink);font-size:var(--t-ui);text-decoration:underline}
.fortress-skip:focus{top:var(--s2);outline:2px solid currentColor;outline-offset:-5px}
.app > [role=main][tabindex="-1"]:focus,.app[data-fortress-ui] > [role=main][tabindex="-1"]:focus-visible{outline:none}
/* RS-06 · "YOUR SESSION HAS ENDED", at the top of the content column, with a working Sign in link (clearline-session.js).
   A plate, a 4px critical rule and a sentence — not a red panel. */
.fortress-session-ended{margin:0 0 var(--s4);padding:var(--s3) var(--s4);background:var(--fui-surface-plate,var(--canvas));
  color:var(--fui-text-primary,var(--ink));border:1px solid var(--fui-rule-light,var(--edge));
  border-left:4px solid var(--fui-status-critical-fg,var(--brc));font-size:var(--t-ui);line-height:1.55}
.fortress-session-ended p{margin:0}
.fortress-session-ended strong{font-weight:500}
.fortress-session-ended a{color:var(--fui-interaction,var(--ink));font-weight:500;text-decoration:underline;text-underline-offset:2px}
/* N5 · THE IDLE WARNING (WCAG 2.2.1): two minutes before the idle sign-out, one sentence and "Stay signed in". Fixed at
   the foot of the window, a plate with a warning rule; no shadow, no scrim — the page behind stays usable. */
.fortress-idle{position:fixed;left:50%;bottom:var(--s5);transform:translateX(-50%);z-index:10002;width:min(560px,calc(100vw - 32px));
  display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--s3) var(--s4);padding:var(--s4);
  background:var(--fui-surface-plate,var(--canvas));color:var(--fui-text-primary,var(--ink));border:1px solid var(--fui-rule-light,var(--edge));
  border-top:3px solid var(--fui-status-warning-fg,var(--ink));font-size:var(--t-ui);line-height:1.5}
.fortress-idle p{margin:0;flex:1 1 260px}
.fortress-idle button{flex:none;min-height:40px;padding:0 var(--s4);background:var(--fui-surface-shell,var(--navy));color:#fff;
  border:1px solid var(--fui-surface-shell,var(--navy));font:inherit;font-weight:500;cursor:pointer}
/* the identifier is embedded IN a human-readable chain, so it scales with
   whatever sets it rather than dropping to a fixed 12px wherever it lands */
.ref{font-family:var(--mono);font-size:.9em;letter-spacing:-.01em}

.crumb{font-size:var(--t-meta);color:var(--ink-3);margin-bottom:var(--s3)}
/* Large uppercase with wide tracking reads as industrial signage. Small
   uppercase with disciplined tracking reads as instrumentation - so the page
   title comes back to sentence case and the micro-labels keep the caps. */
h2.pt{font-size:var(--t-page);font-weight:600;letter-spacing:-.015em;margin:0 0 var(--s3)}
/* One uppercase label treatment, applied to every 12px label in the product.
   Section headings stay sentence case - they are sentences, and caps would
   cost more legibility than they buy. */
.register-h .l,.scope .l,.control .l,.src-h,.pf .l,.svc .l,.fp-h .l,.rail .g{
  text-transform:uppercase;letter-spacing:.075em}
/* The page standfirst takes the same measure as every other run of prose in the system.
   Without it .psub was the one prose component with no cap, so on a wide window it set to
   the full content column - about 150 characters a line, where .note and .state beside it
   stop at 96ch. That is where the qualifying clause in a standfirst lives, and a line that
   long is skimmed rather than read. 96ch is the system's existing prose measure, not a new
   step: it is the value .note and .state,.empty already use. */
.psub{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s5)}
.psub b{color:var(--ink);font-weight:600}

/* Two components were carrying the same class of statement in two different
   dresses, which teaches a reader that some caveats are more real than others.
   One treatment now: a steel rule on the left, no box, both rooms' fix. */
/* Same measure as every other run of prose. .scope was the last prose component with no cap -
   .note and .state,.empty stop at 96ch and .psub now does too - so on a wide window the boundary
   block ran wider than the standfirst directly above it, which is the wrong way round: this is
   the component that carries the disclaimer, and the clause a reader must not skim lives in it. */
.scope{background:none;border:0;border-left:2px solid var(--steel);
  padding:0 0 0 var(--s3);margin-bottom:var(--s5)}
.scope .l{font-size:var(--t-meta);font-weight:600;color:var(--steel);margin-bottom:var(--s1)}
.scope p{margin:0;font-size:var(--t-ui);color:var(--ink-2);line-height:1.6}
.scope b{color:var(--ink);font-weight:600}

/* GUIDING ZERO-DATA STATE (7 Sep). A page whose prerequisite does not exist yet shows what is
   needed and the one step to get there, in place of a working form over an empty picker. One
   variant, .empty.guide, rendered by fortressEmptyState() and shared by all seven folder-07 pages
   so they cannot drift apart. Built from existing primitives - the page h2, muted body, the standard
   .btn - and scoped with the .guide modifier so it never restyles the bare .empty used elsewhere for
   inline "nothing on record" notes and small metadata lines. No new colour, component, radius or
   type step. */
.empty.guide{padding:var(--s5) 0}
.empty.guide h2{margin:0 0 var(--s2)}
.empty.guide p{font-size:var(--t-ui);color:var(--ink-2);line-height:1.65;margin:0 0 var(--s4)}

/* ─────────────────── THE CONTAINER VOCABULARY ────────────────────────────
   Both review rooms found the same thing from six directions: border, radius
   and fill were being spent once, on everything, so nothing said what kind of
   object it was. Five treatments, each meaning one thing:

     2px ink top rule, no box, full width  the screen's PRINCIPAL object.
                                           One per screen, or none.
     1px hairline band, no box             a supporting summary or statement
     2px steel rule on the left            a boundary or scope note
     1px hairline top and bottom, no box   a bounded register or readout
     one 5px signal rail on the left       a mechanism, not a message

   The consequence is that each screen now has its own silhouette, which was
   the other dominant finding. Portfolio is one full-width ruled table. Today
   is a tall ruled chart band over a continuous ruled operating queue. The
   record is three ruled service registers under a bounded readout. The pack
   is a band, one continuous evidence register, and one dark block. v13
   removed the last card primitive: no four-sided --edge box survives.
   No new colour, surface, icon or ornament was added to achieve it.
   ───────────────────────────────────────────────────────────────────────── */
/* register — an inventory. It counts what exists. It does not judge. */
/* A summary is not evidence, so the rule that opens it is not navy. Navy now
   appears only on the seal, the fingerprint and the mark - which is the whole
   basis on which the fingerprint is allowed to be authoritative. */
.register{background:none;border:0;border-top:1px solid var(--edge);
  border-bottom:1px solid var(--edge);border-radius:0;margin-bottom:var(--s5)}
.register-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);
  padding:var(--s3) 0;border-bottom:1px solid var(--line)}
.register-h .l{font-size:var(--t-meta);font-weight:600;color:var(--ink)}
.register-h .t{font-size:var(--t-meta);color:var(--ink-2)}
/* One ruled assembly, four readings, a single baseline grid. The number
   leads; the label is instrumentation; the qualifier is information. No
   tiles, no fills, no icons, no KPI-card language. The open statutory count
   is the one exceptional reading, so the NUMBER carries the signal. */
.register-b{display:grid;grid-template-columns:repeat(4,1fr);padding:var(--s4) 0 var(--s5)}
/* three cells when only three things are worth acting on */
.register-b.three{grid-template-columns:repeat(3,minmax(0,1fr))}
.register-b div{display:flex;flex-direction:column;align-items:flex-start;
  padding-right:var(--s5);border-right:1px solid var(--line)}
.register-b div:last-child{border-right:0;padding-right:0}
.register-b b{font-size:22px;font-weight:600;letter-spacing:-.022em;line-height:1;color:var(--ink)}
.register-b i{font-style:normal;font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.075em;color:var(--ink);margin-top:var(--s2);line-height:1.3}
.register-b span{font-size:var(--t-meta);color:var(--ink-2);margin-top:3px;line-height:1.4}
.register-b .x b{color:var(--brc)}

/* The four-sided box is gone. A working section is now a heading, a
   structural rule and a run of ruled rows mounted on the white plane.
   Identity comes from heading + rule + rhythm, not from a rectangle. */
.work{background:none;border:0;border-radius:0;margin-bottom:var(--s5)}
/* Shared grammar: name left, count right, one firm 1px division beneath.
   These are PEER service categories and PEER queue sections - not three or
   four separate principal objects - so the rule ranks below the register,
   the chart and the judgement assembly. Property and Today stay different
   silhouettes because their rows differ, not because their headings do. */
.work-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);
  padding:0 0 var(--s2);border-bottom:1px solid var(--rule-2)}
.work-h h3{margin:0;font-size:var(--t-sec);font-weight:600;letter-spacing:-.01em;color:var(--ink)}
.work-h .n{font-size:var(--t-meta);color:var(--ink-2)}
.work-b{padding:0}
/* Portfolio's principal object. A box would make it one object among several;
   it IS the object, so it loses the box and runs the full width of the body,
   opened by a 2px ink rule and closed by a hairline. */
.work.reg{margin-left:-16px;background:none;border:0;border-top:2px solid var(--ink);
  border-bottom:1px solid var(--edge);border-radius:0;margin-bottom:var(--s5)}
.work.reg .work-b{padding:0 0 var(--s3)}
.work.reg .rhead,.work.reg .crow,.work.reg .prow{margin-left:0}
.work.reg .pgin{margin-left:16px}
.work.reg .rhead{color:var(--ink-2);font-weight:600}

/* NOT A WARNING CARD. A system interlock: a condition is unsatisfied, so
   completion is mechanically unavailable. White surface, one hard red control
   rail, one solid-red state telltale. The red says the mechanism is blocked;
   the typography says why - so the headline is ink, not red. */
.control{background:var(--surface);border:0;border-left:5px solid var(--brc-fill);
  border-radius:0;padding:2px 0 var(--s3) var(--s3);margin-bottom:var(--s5)}
.control .l{font-size:var(--t-meta);font-weight:600;color:var(--brc);margin-bottom:6px;
  text-transform:uppercase;letter-spacing:.075em;display:flex;align-items:center;gap:var(--s2)}
.control .l::before{content:'';width:7px;height:7px;background:var(--brc-fill);flex:none}
.control .h{font-weight:600;color:var(--ink);font-size:var(--t-page);letter-spacing:-.015em;margin-bottom:var(--s2);line-height:1.25}
.control p{margin:0;font-size:var(--t-ui);color:var(--ink-2);line-height:1.6}
.control p b{color:var(--ink);font-weight:600}

/* the filter toolbar. NOT .bar — that name belongs to a chart column. */
.toolbar{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center;margin-bottom:var(--s4)}
/* Controls are machined, not moulded: a firm boundary, an exact height, a
   tight radius and no inset shadow pretending to be depth. */
.input{flex:1;min-width:200px;height:36px;display:flex;align-items:center;padding:0 var(--s3);
  font-size:var(--t-ui);color:var(--ink-3);background:var(--surface);border:1px solid var(--line-3);
  border-radius:var(--r)}
.select{height:36px;display:flex;align-items:center;gap:var(--s2);padding:0 var(--s3);font-size:var(--t-ui);font-weight:500;
  color:var(--ink);background:var(--surface);border:1px solid var(--line-3);border-radius:var(--r)}
.select em{font-style:normal;font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.07em;color:var(--ink-2)}
/* a drawn chevron - the typed character sat off-baseline and at the mercy of
   the font's own metrics */
/* the triangle's visual mass sits above its box centre, so it carries a 1px
   optical correction - a real geometric reason, not an arbitrary value */
.select::after{content:'';width:0;height:0;margin-left:var(--s3);transform:translateY(1px);
  border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid var(--ink-2)}
.filters{display:flex;flex-wrap:wrap;gap:var(--s2);margin-bottom:var(--s3)}
.filter{font-size:var(--t-ui);height:28px;display:inline-flex;align-items:center;padding:0 var(--s3);border-radius:var(--r);border:1px solid var(--line-3);
  background:var(--surface);color:var(--ink-2);line-height:1.7}
.filter .c{margin-left:var(--s1);color:var(--ink-2)}
.filter.on{background:var(--ink);border-color:var(--ink);color:var(--on-dark);font-weight:500}
.filter.on .c{color:var(--on-dark-2)}
/* One component was serving as primary action, secondary action, inline
   disclosure and navigation link - three voices in one room and two on the
   Board counted the same defect. .act is now only ever an ACTION ON AN OBJECT.
   .lnk is a disclosure or a navigation link, and looks like one. */
.act{font-size:var(--t-meta);font-weight:500;height:28px;display:inline-flex;align-items:center;padding:0 var(--s3);border-radius:var(--r);
  border:1px solid var(--line-3);background:var(--surface);color:var(--ink);white-space:nowrap}
.lnk{font-size:var(--t-meta);font-weight:500;color:var(--ink);white-space:nowrap;
  text-decoration:underline;text-decoration-color:var(--line-3);text-underline-offset:3px}
/* the rail foot sits on navy now — its Sign out link takes on-dark text and a light underline */
.rail .foot .lnk{color:var(--on-dark);text-decoration-color:rgba(242,244,246,.38)}
.rail .foot .lnk:hover{text-decoration-color:var(--on-dark)}
.btn{font-size:var(--t-ui);font-weight:600;height:36px;display:inline-flex;align-items:center;padding:0 var(--s4);border-radius:var(--r);
  border:1px solid var(--ink);background:var(--ink);color:var(--on-dark)}
/* An available secondary control is white with a firm boundary. .ghost is the
   same rank under a second name: 20 pages write `btn ghost` in markup, 41 define
   it locally, and this file defined it nowhere. */
.btn.sec,.btn.ghost{background:var(--surface);color:var(--ink);border-color:var(--line-3)}
/* THE DISENGAGED CONTROL KEEPS ITS RANK. .btn.off was the only disengaged state
   the system specified and it painted the same recessed aperture over BOTH ranks,
   so a screen that disabled its primary and its secondary together showed two
   identical grey blocks — the user in the blocked state was handed a hierarchy
   that does not exist, at exactly the moment one was load-bearing. The system
   knows the difference everywhere else.

   A disengaged primary stays FILLED: the same block, recessed material. A
   disengaged secondary stays an APERTURE: different material, quiet edge. Rank
   survives being switched off.

   :disabled is named here beside .off because the design system specified
   NEITHER — which is why 45 pages wrote their own disabled button, and why one
   of them ended up ranking Save and Generate the opposite way round from the
   page next to it without anything to contradict it. */
.btn:disabled,.btn.off{background:var(--ink-3);border-color:var(--ink-3);color:var(--on-dark);
  cursor:not-allowed;box-shadow:none}
.btn.sec:disabled,.btn.ghost:disabled,.btn.sec.off,.btn.ghost.off{
  background:var(--surface-2);color:var(--ink-3);border-color:var(--line-2)}
.agg{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s4);display:flex;flex-wrap:wrap;gap:0 var(--s2);align-items:baseline}
.agg b{color:var(--ink);font-weight:600}
/* the verified-vs-declared distinction is the sharpest thing on this screen.
   Promoted one notch — not to a panel, just off the smallest size. */
.agg .prov-split{color:var(--ink);font-weight:500}
.agg .prov-split b{color:var(--ink)}
.agg .gap{color:var(--brc);font-weight:600}
/* On the daily register the boundary is a precision line, not a bordered box:
   same seriousness, none of the apology. The scope COMPONENT is kept where the
   boundary is part of what is being read - the record and the pack. */
.scope-l{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s5);padding-left:var(--s3);
  border-left:2px solid var(--steel);line-height:1.65}
.scope-l b{color:var(--ink);font-weight:600}
.scope-l i{font-style:normal;color:var(--steel);font-weight:600}
/* selection is TRANSIENT. It was the darkest object on the canonical screen,
   outranking the register it acts on. No surface at all, two firm rules. */
.bulk{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);background:none;color:var(--ink);
  border:0;border-top:1px solid var(--edge);border-bottom:1px solid var(--edge);
  border-radius:0;padding:var(--s2) 0;margin-bottom:var(--s3);font-size:var(--t-ui)}
.bulk .n{font-weight:600}
.bulk .b{border:1px solid var(--line-3);border-radius:var(--r);height:28px;display:inline-flex;
  align-items:center;padding:0 var(--s3);font-size:var(--t-meta);color:var(--ink)}
.bulk .x{margin-left:auto;color:var(--ink-2);font-size:var(--t-meta)}
.tick{width:14px;height:14px;border:1px solid var(--line-3);border-radius:2px;display:block;background:var(--surface)}
/* The attestation box IS the Portfolio selection box: same 14px geometry,
   same 2px radius, same drawn tick, same dark ink. Checked is a shape
   change, not a colour change - green stays the confirmation indicator and
   never becomes the generic selected-control colour. One declaration, so the
   two can never drift apart. */
.tick.on,.cb.on{background:var(--ink);border-color:var(--ink);position:relative}
.tick.on::after,.cb.on::after{content:"";position:absolute;left:5px;top:2px;width:3px;height:6px;border:solid #fff;
  border-width:0 2px 2px 0;transform:rotate(42deg)}

/* ===================== THE REGISTER — canonical portfolio ================= */
.rhead,.crow{display:grid;grid-template-columns:16px minmax(0,1fr) minmax(0,1.3fr) 92px 84px 16px;
  gap:var(--s4);align-items:center;padding:0 0 0 var(--s4);margin-left:-16px;position:relative}
.rhead{height:28px;font-size:var(--t-meta);font-weight:500;color:var(--ink-2);border-bottom:1px solid var(--line-2)}
.rhead .r{text-align:right}
/* Drawn as a pseudo-element rather than a border: a border mitres into the
   row's bottom hairline, so the last pixel of every rail tapers diagonally.
   An absolutely positioned child is not a grid item, so the grid is untouched. */
.crow{height:44px;border-bottom:1px solid var(--line)}
.crow::before,.prow::before,.row::before{content:'';position:absolute;left:0;top:0;bottom:0;
  width:var(--sig-w);background:transparent}
.crow.crit::before,.crow.brc::before,.prow.crit::before,.prow.brc::before,
.row.brc::before{background:var(--brc-fill)}
.crow.adv::before,.prow.adv::before{background:var(--adv)}
.crow.ok::before,.prow.ok::before,.row.ok::before,.row.sup::before{background:var(--line-3)}
.crow.prog::before,.prow.prog::before{background:var(--ink-3)}
.crow:last-of-type{border-bottom:0}
/* No row is ever washed. At thirty-one exceptions a full-row wash stops
   ranking anything and becomes a red screen; the channel and the text rank. */
/* Critical is differentiated by engineering grammar, not by colouring a large
   rectangle pink, and NOT by widening its channel: the channel is a fixed 4px
   for every state. One solid-red 7px telltale before the issue count and a
   700-weight elapsed value carry the rank. This keeps the screen white. */

.crow.crit .ci .n::before{content:'';display:inline-block;width:7px;height:7px;
  background:var(--brc-fill);margin-right:var(--s2);vertical-align:1px}
.crow.crit .pnext.late{font-weight:700}
.crow.crit .pnext::before{content:'';display:inline-block;width:7px;height:7px;
  background:var(--brc-fill);margin-right:var(--s2);vertical-align:1px}
/* IN PROGRESS — someone is on it. Plain ink, a progress verb, no colour:
   colour stays reserved for time and risk. Rail is a solid neutral, one
   step firmer than a clean row, so the state is legible without a hue. */
.ci .n.g{color:var(--ink);font-weight:600}
.ci .t.g{color:var(--ink-2)}
.ca{font-weight:600;font-size:var(--t-row);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ca em{font-style:normal;font-weight:400;color:var(--ink-2);font-size:var(--t-meta)}
.ci{display:flex;align-items:center;gap:var(--s2);min-width:0;font-size:var(--t-ui)}
.ci .n{font-weight:600;color:var(--brc);white-space:nowrap}
.ci .n.a{color:var(--ink)}
.ci .t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ink-2)}
.ci .t.r{color:var(--brc);font-weight:500}
.ci .t.a{color:var(--ink);font-weight:500}
.ci .p{color:var(--ink-2);white-space:nowrap}
.ci .none{color:var(--ink-2)}
/* Three 7px markers separated only by hue, at the one scale where hue is
   least reliable. MEASURED before changing anything - relative luminance:
   fault red 0.1984, confirmation green 0.2939, seal navy 0.0144. Red and
   green sit 0.68x apart, so hue was carrying the whole distinction between
   them; red and navy sit 13.8x apart and are already separated by value,
   in greyscale and on paper alike.

   So exactly one form was added, where the measurement said it was needed:
   CONFIRMATION becomes a drawn tick, in the same two-border geometry as the
   checkbox and the disclosure angle. Fault and seal stay filled blocks. An
   outlined seal was tried and rejected on sight - at 7px it reads as tofu,
   the box a browser draws for a missing character, which is the last thing
   the provenance line can afford to look like. Nothing is enlarged, nothing
   becomes an icon, nothing becomes a badge. */
.ci .none i,.cur i,.auth i,.pk-h .ok i{font-style:normal;font-size:0;line-height:0;
  display:inline-block;width:4px;height:7px;background:none;
  border:solid var(--ok);border-width:0 1.5px 1.5px 0;transform:rotate(42deg);
  vertical-align:-1px;margin:0 var(--s2) 0 1px}
.pown{font-size:var(--t-ui);color:var(--ink)}
.pnext{font-size:var(--t-row);color:var(--ink);font-weight:500;letter-spacing:-.01em;text-align:right;line-height:1.3}
.pnext.late{color:var(--brc);font-weight:600}
.pnext span{display:block;color:var(--ink-2);font-weight:400;font-size:var(--t-meta)}
/* ONE disclosure angle for the whole product, drawn from two borders.
   It was a font glyph, so its shape, weight and optical centre belonged to
   the typeface rather than to us. A disclosure indicator is control hardware.
   5px box rotated 45deg = a ~7px right-facing angle. The 1.5px stroke is the
   one sanctioned sub-pixel value in the system: a rotated border needs it to
   read as a drawn line rather than a step. */
.chev{display:flex;align-items:center;justify-content:flex-end;font-size:0;line-height:1}
.chev::after{content:'';width:5px;height:5px;flex:none;margin-right:2px;
  border-right:1.5px solid var(--ink-2);border-top:1.5px solid var(--ink-2);
  transform:rotate(45deg)}
/* the same family at pagination scale - 4px box, ~5.7px visual, tertiary ink */
.pgin i{font-style:normal;display:inline-block;width:4px;height:4px;vertical-align:1px;
  border-right:1.25px solid var(--ink-3);border-top:1.25px solid var(--ink-3)}
.pgin i.pv{transform:rotate(-135deg)}
.pgin i.pn{transform:rotate(45deg)}
.pgin{display:flex;justify-content:space-between;align-items:center;font-size:var(--t-meta);color:var(--ink-3);
  padding-top:var(--s3);border-top:1px solid var(--line)}
.pgin b{color:var(--ink);font-weight:600}

/* expanded rows — the drill-down, not the default */
.prow{display:grid;grid-template-columns:16px minmax(0,1fr) minmax(0,1.35fr) 92px 84px 16px;gap:var(--s4);
  align-items:start;padding:var(--s4) 0 var(--s4) var(--s4);margin-left:-16px;position:relative;
  border-bottom:1px solid var(--line)}
.prow:last-of-type{border-bottom:0}
.e-prog{color:var(--ink);font-weight:600}
.e-prog span{display:block;color:var(--ink-2);font-weight:400;font-size:var(--t-meta);margin-top:2px}
.prow > *{padding-top:1px}
.paddr{font-weight:600;font-size:var(--t-row);color:var(--ink);letter-spacing:-.008em;line-height:1.35}
.pmeta{font-size:var(--t-ui);color:var(--ink-2);margin-top:var(--s1)}
.exc{display:flex;flex-direction:column;gap:var(--s1);align-items:flex-start}
.e{font-size:var(--t-ui);font-weight:600;line-height:1.4}
/* Was a solid fire-red rectangle with white text - the last filled status
   badge in the product, and the last thing in it that came from a generic
   component library. COLOUR IS THE SIGNAL, TEXT IS THE INFORMATION: the
   critical state now reads as red information on the white operating plane,
   marked by the same 7px square used for every other signal. No fill, no
   border, no padding, no radius. The red itself is unchanged - area is
   reduced, saturation is not. */
.e-crit{color:var(--brc);font-weight:600;display:inline-flex;align-items:baseline;gap:var(--s2)}
.e-crit::before{content:'';width:7px;height:7px;flex:none;align-self:center;background:var(--brc-fill)}
.e-brc{color:var(--brc)}
.e-adv{color:var(--ink);font-weight:500}
.e-q{color:var(--ink-2);font-weight:500}
.cur{font-size:var(--t-ui);color:var(--ink-2);line-height:1.65;margin-top:var(--s2)}
.egap{display:block;margin-top:var(--s2);font-size:var(--t-ui);color:var(--brc);font-weight:500}

/* record rows */
.row{display:grid;grid-template-columns:minmax(0,1fr) 210px 16px;gap:var(--s4);align-items:start;
  padding:var(--s4) 0 var(--s4) var(--s4);margin-left:-16px;position:relative;
  border-bottom:1px solid var(--line)}
.row:first-of-type{padding-top:var(--s3)}
.row:last-of-type{border-bottom:0}
.row.sup .rt{color:var(--ink-2)}
.rt{font-weight:600;font-size:var(--t-row);margin-bottom:var(--s1);letter-spacing:-.008em;line-height:1.4}
.rm{font-size:var(--t-ui);color:var(--ink-2);line-height:1.7}
.rm b{color:var(--ink);font-weight:600}
/* which version you are looking at is evidence, not metadata */
.vstate{color:var(--ink)}
/* lineage — canonical wherever a record is presented as evidence */
/* LINEAGE - the one element here that is Fortress's own. Promoted a single
   step: 13px, ink-2, a legible rule. Deliberately NOT a widget - what makes it
   good is that it reads as a fact about the record, not as a feature. */
.lin{font-size:var(--t-ui);color:var(--ink-2);margin-top:var(--s3);line-height:1.75}
.lin > span{display:block;padding-left:var(--s5);position:relative}
.lin > span::before{content:'\2514';position:absolute;left:var(--s2);color:var(--ink-2);font-family:var(--mono)}
.lin .v{color:var(--ink-2)}
.lin .now{color:var(--ink);font-weight:600;padding-left:0}
.lin .now::before{content:none}
.reg{display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--s2);margin-top:var(--s2);
  font-size:var(--t-ui);color:var(--ink-2)}
.reg b{color:var(--ink);font-weight:600}
.reg .seal{display:inline-flex;align-items:center;gap:var(--s2);color:var(--navy);font-weight:600}
.reg .seal::before{content:'';width:7px;height:7px;background:var(--navy);flex:none}
/* "Record approved / property non-compliant" is the distinction the product
   exists to make, and it was the lightest type on the page. Named by two
   voices in one room and one on the Board. Weight, not colour. */
.who{font-size:var(--t-ui);color:var(--ink);font-weight:600;line-height:1.35;letter-spacing:-.006em}
/* colour is the indicator, text is the information - so a breach row gets the
   same 7px telltale as the register rather than a coloured sentence */
.row.brc .who::before{content:'';display:inline-block;width:7px;height:7px;
  background:var(--brc-fill);margin-right:var(--s2);vertical-align:1px}
/* "property non-compliant" is the operating conclusion of the record. It was
   being set in timestamp type. It is subordinate to the state above it and
   it must still land instantly - so weight and size, not colour. */
/* "property non-compliant" is the operating conclusion of the record and it
   sat in the palest ink on the page. It is subordinate to the state above it
   and it must still land instantly - so weight and ink, never colour, because
   colour here would collapse the very distinction the line exists to make. */
.when{font-size:var(--t-ui);font-weight:500;color:var(--ink);margin-top:3px;line-height:1.35}
.more{font-size:var(--t-meta);color:var(--ink-3);padding:var(--s3) 0 var(--s1)}

/* TODAY */
/* This was the one stock component in a bespoke design - the bordered stat
   strip every SaaS product ships - and it sat directly above the one object
   that is not stock. Now a line of figures under a hairline. */
.counts{display:flex;flex-wrap:wrap;gap:0 var(--s6);margin-bottom:var(--s5);border:0;
  border-bottom:1px solid var(--edge);border-radius:0;background:none;padding:0 0 var(--s3)}
.counts div{display:flex;flex-direction:column;align-items:flex-start;gap:3px;padding:0;border-right:0;
  font-size:var(--t-meta);color:var(--ink-2);line-height:1.3}
.counts b{font-size:var(--t-sec);color:var(--ink);font-weight:600;letter-spacing:-.018em;line-height:1;margin:0}
.counts .r,.counts .a{border-left:var(--sig-w) solid var(--line-2);padding-left:var(--s3)}
.counts .r{border-left-color:var(--brc-fill)}
.counts .a{border-left-color:var(--adv)}
.counts .r b{color:var(--brc)} .counts .a b{color:var(--ink)}
/* Today's principal object, given the proportion of one: the same 2px ink
   rule the register gets, full width, and half again the plot height. This is
   the whole of the differentiation work on this screen - no new device. */
.horizon{background:none;border:0;border-top:2px solid var(--ink);
  border-bottom:1px solid var(--edge);border-radius:0;
  padding:var(--s4) 0 var(--s5);margin-bottom:var(--s5)}
.horizon h4{margin:0 0 var(--s1);font-size:var(--t-sec);font-weight:600;letter-spacing:-.012em}
.horizon .cs{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s5)}
.horizon .cs b{color:var(--ink);font-weight:600}
.horizon .cs i{font-style:normal;color:var(--brc);font-weight:600}
.plot{position:relative;padding-left:var(--s6)}
.ax{position:absolute;left:0;top:0;height:224px;width:28px}
.ax span{position:absolute;right:0;font-size:var(--t-meta);color:var(--ink);font-weight:500;transform:translateY(-50%)}
.grid-l{position:absolute;left:0;right:0;border-top:1px solid rgba(14,22,33,.06)}
/* the mean is information, not decoration - the caption already refers to it */
.mean{position:absolute;left:0;right:0;border-top:1px dashed var(--ink-2)}
.mean b{position:absolute;left:0;top:-18px;font-size:var(--t-meta);font-weight:500;color:var(--ink-2);
  background:var(--surface);padding-right:var(--s2)}
.bars{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--s4);align-items:end;height:224px;
  position:relative;border-bottom:2px solid var(--ink)}
/* selected means visibly selected - a precise calibration cap, not a glow */
.bar.sel::after{content:'';position:absolute;left:0;right:0;top:-4px;height:2px;background:var(--ink)}
.bar{background:var(--sig-blue);position:relative}
.bar.hi{background:var(--brc-fill)}
.bar i{position:absolute;top:-18px;left:0;right:0;text-align:center;font-size:var(--t-meta);font-style:normal;color:var(--ink);font-weight:500}
.bar.hi i{color:var(--brc);font-weight:700}
/* ─────────────────────── THE OPTICAL LAYER ───────────────────────────────
   PERMANENT SURFACES ARE SOLID. TEMPORARY INFORMATION LAYERS MAY BE OPTICAL.
   This is the only optical surface in the product and it is deliberately the
   only one: a transient data plate brought forward over the plot, sitting
   across real bars and grid lines so the blur has something to act on.
   Clear precision optical glass, not frosted lifestyle glassmorphism -
   essentially colourless, one crisp hairline edge, a 1px top highlight, a
   minimal shadow and a single fire-red signal rule. No tint, no refraction,
   no glow, no large translucent card. Colour belongs to the instrument
   underneath and to the signal rule within, never to the material itself. */
/* Less blur, more opacity, a firmer edge and less vertical padding: a lens,
   not a frosted tooltip. Readability first - the blur only has to say "this
   is above the instrument", not obscure what is under it. */
.plate{position:absolute;right:calc(100% + 14px);bottom:34%;min-width:206px;text-align:left;z-index:3;
  overflow:hidden;
  background:rgba(255,255,255,.96);
  -webkit-backdrop-filter:blur(4px) saturate(112%);backdrop-filter:blur(4px) saturate(112%);
  border:1px solid rgba(14,22,33,.22);border-radius:4px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 4px 14px -10px rgba(14,22,33,.26);
  padding:var(--s2) var(--s4) var(--s3) var(--s3)}
/* NOT the row state channel: a transient data plate is not a ranked row, so
   it takes the ordinary-signal width and stays subordinate to the red peak
   it annotates. The plate is clipped, so the rule ends flush with the 4px
   aperture instead of overhanging it with square corners. */
.plate::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--brc-fill)}
.plate .pl{font-size:var(--t-meta);font-weight:600;color:var(--ink);text-transform:uppercase;
  letter-spacing:.075em;margin-bottom:var(--s1);padding-left:var(--s2)}
.plate .pv{font-size:var(--t-sec);font-weight:600;color:var(--ink);letter-spacing:-.014em;
  line-height:1.2;padding-left:var(--s2)}
.plate .pd{font-size:var(--t-meta);color:var(--brc);font-weight:600;margin-top:2px;padding-left:var(--s2)}
.plate .pb{font-size:var(--t-meta);color:var(--ink-2);margin-top:var(--s2);padding-left:var(--s2);
  border-top:1px solid var(--line);padding-top:var(--s2)}
.wk{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--s4);margin-top:var(--s2);padding-top:var(--s1)}
.wk span{font-size:var(--t-meta);color:var(--ink);text-align:center;letter-spacing:.01em}
.wk span.hi{color:var(--brc);font-weight:600}
.obrow{display:grid;grid-template-columns:minmax(0,1fr) 160px 96px 112px;gap:var(--s4);align-items:center;
  padding:var(--s4) 0;border-bottom:1px solid var(--line)}
.work-b .obrow:first-of-type{padding-top:var(--s3)}
.obrow:last-of-type{border-bottom:0}
.obt{font-size:var(--t-row);font-weight:600;margin-bottom:2px;letter-spacing:-.008em}
.obm{font-size:var(--t-ui);color:var(--ink-2);line-height:1.7}
.rowacts{display:flex;gap:var(--s2);justify-content:flex-end}

/* REVIEW */
.gwrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);gap:var(--s4)}
@media(max-width:1000px){.gwrap{grid-template-columns:1fr}}
/* Mounted on the plane under one structural rule. The controls inside keep
   their hard boundaries; the parent stops being a rectangle. */
.judge{border:0;border-top:2px solid var(--ink);border-radius:0;
  padding:var(--s3) 0 0;margin-bottom:var(--s5);background:none}
.judge h4{margin:0 0 var(--s1);font-size:var(--t-sec);font-weight:600;letter-spacing:-.012em}
.judge .js{font-size:var(--t-ui);color:var(--ink-2);margin:0 0 var(--s5)}
/* the prompt the operator actually answers, separated from the module's own
   explanation by a rule rather than by more space */
.judge .q{padding-top:var(--s4);border-top:1px solid var(--line-2)}
.q{font-size:var(--t-row);font-weight:600;color:var(--ink);letter-spacing:-.008em;margin-bottom:var(--s3)}
.opts{display:grid;grid-template-columns:repeat(3,1fr);border:1px solid var(--line-3);border-radius:var(--r);
  overflow:hidden;background:var(--surface)}
.opt{display:flex;align-items:center;gap:var(--s3);padding:0 var(--s4);min-height:44px;line-height:1.3;
  font-size:var(--t-ui);color:var(--ink);
  border-right:1px solid var(--line-2)}
.opt:last-child{border-right:0}
.opt .radio{width:14px;height:14px;border-radius:50%;border:1px solid var(--line-3);flex:none;background:#fff}
/* An ordinary signal on a single object, so 3px - not the 4px state channel,
   which ranks repeated rows against each other, and not the 5px interlock,
   which prevents completion. Lemon is 1.4:1 on white: at 2px it was not
   physically present. Everything else about this block is unchanged. */
.conseq{font-size:var(--t-ui);color:var(--ink-2);line-height:1.7;margin:var(--s3) 0 0;padding-left:var(--s3);
  border-left:3px solid var(--adv)}
.conseq b{color:var(--ink);font-weight:600}
.f3{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s3);margin-top:var(--s4)}
.fld label{display:block;font-size:var(--t-meta);color:var(--ink-2);margin-bottom:var(--s1);font-weight:500}
/* min-height, not height: the grid row already equalises the three fields, and
   a control that spills its own box is not an exact control. */
.fld .box{border:1px solid var(--line-3);border-radius:var(--r);background:var(--surface);min-height:36px;
  display:flex;align-items:center;padding:var(--s2) var(--s3);font-size:var(--t-ui);color:var(--ink-3);line-height:1.3}
.fld .box.up{justify-content:center;border-style:dashed;color:var(--ink);font-weight:500;background:var(--surface);box-shadow:none}
.attest{display:flex;align-items:flex-start;gap:var(--s3);padding:var(--s4) 0;border:0;
  border-top:1px solid var(--line-2);background:none;font-size:var(--t-ui);margin-bottom:var(--s3);line-height:1.6}
.cb{width:14px;height:14px;border:1px solid var(--line-3);border-radius:2px;flex:none;margin-top:3px;background:#fff}

/* THE REAL CHECKBOX, drawn to the same specification as .cb above.
   .cb is a specimen — a <span> the board uses to SHOW what a checkbox is. The product's actual
   checkboxes were <input type=checkbox> with accent-color:var(--ink) on them, which is not the
   same object: accent-color tints the browser's own box and the browser's own tick, so the shape,
   the corner radius and the tick geometry all still belonged to Chrome rather than to us. 57 real
   checkboxes across 19 pages, every one of them a control the system had specified and was not
   using. Two review rooms scored it as a browser-default control sitting beside controls that had
   plainly been made.
   appearance:none is what makes ::after render on a checkbox at all — it stops being a replaced
   element — and the checked state then takes the SAME drawn tick as .cb.on, declared once above
   so the specimen and the real control can never drift apart. No new colour, no new radius, no
   new geometry: this rule adds nothing to the vocabulary, it connects the vocabulary to the
   elements that were ignoring it.

   ON THE SELECTOR, because it looks like belt-and-braces and is not. 35 pages carry a rule
   reading `input:read-only,input:disabled,select:disabled,textarea:read-only{background:
   var(--surface-2)}` — the recessed-aperture treatment, written for a read-only TEXT field. CSS
   considers a checkbox read-only too (a checkbox is never :read-write), so that rule was painting
   every unchecked checkbox in the disabled grey while it was perfectly interactive. It is not a
   specificity contest anyone was winning: `input:read-only` and `input[type=checkbox]` are BOTH
   (0,1,1), so the only reason it won is that a page's <style> loads after this file. Naming
   :read-only here takes the base rule to (0,2,1) and settles it in the authority, rather than in
   35 copies of the same page-level fix. */
input[type=checkbox],
input[type=checkbox]:read-only{appearance:none;-webkit-appearance:none;margin:0;flex:none;
  width:14px;height:14px;min-height:0;padding:0;background:#fff;
  border:1px solid var(--line-3);border-radius:2px;cursor:pointer;position:relative}
input[type=checkbox]:checked{background:var(--ink);border-color:var(--ink)}
input[type=checkbox]:checked::after{content:"";position:absolute;left:4px;top:1px;width:3px;height:6px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(42deg)}
input[type=checkbox]:disabled{background:var(--surface-2);border-color:var(--line-2);cursor:not-allowed}
input[type=checkbox]:disabled:checked{background:var(--ink-3);border-color:var(--ink-3)}

/* THE DATE FIELD'S PICKER MARK. 67 date inputs across 19 pages, every one of them wearing
   Chrome's own calendar glyph — a raster the browser supplies, at the browser's size, in the
   browser's colour — immediately beside .select controls whose chevron this system deliberately
   DREW, because "a disclosure indicator is control hardware" and "no font glyphs in a control
   position". A date field opens a picker; that is the same disclosure the select makes, so it
   takes the same mark rather than a second one.

   clip-path is what keeps this inside the vocabulary. The obvious route — a background-image
   holding an SVG triangle — cannot read a custom property, so the colour would have to be
   hardcoded, and this system has already been bitten by exactly that (the Gatehouse knockout
   carried a literal #F1F2F4 and put a grey shape inside the logo). Here the SHAPE comes from
   clip-path and the COLOUR from var(--ink-2), so the mark stays tokenised and cannot drift from
   the chevron it matches. Same 8x4 geometry as .select::after, and the indicator keeps its own
   click target, so nothing is taken away from the control.

   DESIGN PASS D4 (Marco's live sweep, 22 Oct 2026): the chevron read as a dropdown — "native date inputs show a
   dropdown arrow" — so a date field looked like a select that opens a list. It now carries a DRAWN calendar mark: the
   shape is a mask (an inline SVG, as the brand mark above uses), the colour still var(--ink-2), so it stays tokenised,
   and the indicator keeps its own click target. datetime-local fields take the same mark. */
input[type=date]::-webkit-calendar-picker-indicator,
input[type=datetime-local]::-webkit-calendar-picker-indicator{
  -webkit-appearance:none;appearance:none;width:14px;height:14px;padding:0;margin:0 0 0 6px;
  background:var(--ink-2);cursor:pointer;opacity:1;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill-rule='evenodd' d='M3 0h1.5v2h5V0H11v2h2.25c.41 0 .75.34.75.75v10.5c0 .41-.34.75-.75.75H.75A.75.75 0 0 1 0 13.25V2.75C0 2.34.34 2 .75 2H3zM1.5 5.5v7h11v-7z'/%3E%3Cpath d='M3 7h2v2H3zM6 7h2v2H6zM9 7h2v2H9zM3 10h2v1.5H3zM6 10h2v1.5H6z'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill-rule='evenodd' d='M3 0h1.5v2h5V0H11v2h2.25c.41 0 .75.34.75.75v10.5c0 .41-.34.75-.75.75H.75A.75.75 0 0 1 0 13.25V2.75C0 2.34.34 2 .75 2H3zM1.5 5.5v7h11v-7z'/%3E%3Cpath d='M3 7h2v2H3zM6 7h2v2H6zM9 7h2v2H9zM3 10h2v1.5H3zM6 10h2v1.5H6z'/%3E%3C/svg%3E") center/contain no-repeat}
input[type=date]::-webkit-calendar-picker-indicator:hover,
input[type=datetime-local]::-webkit-calendar-picker-indicator:hover{background:var(--ink)}

/* THE REST OF THE DATE FIELD, which the mark above did not reach. Replacing the picker glyph
   fixed the one part of the control that looked like Chrome's and left the larger part that also
   is: the value itself is a ::-webkit-datetime-edit, three separately-focusable segments the
   browser spaces, colours and highlights on its own terms. So an empty date field printed
   "dd/mm/yyyy" in Chrome's placeholder grey — not --ink-3, near it, which is worse than plainly
   wrong — and focusing a segment painted Chrome's system blue rather than --sig-blue. On the
   obligations form six of these sit directly beneath six selects that had been drawn down to the
   pixel, at identical width, where the eye compares them: the review read the pair as bespoke
   controls next to browser-default ones on the same page.

   Nothing here changes the CONTROL — the segments still edit, the picker still opens, the field
   is still a real date input. It takes the parts Chrome was colouring and gives them the tokens
   everything else in the system already uses. --ink-3 is the same value the disabled select mark
   carries, so an unfilled date now reads exactly as quiet as every other unfilled thing. */
input[type=date]::-webkit-datetime-edit-text,
input[type=date]::-webkit-datetime-edit-day-field,
input[type=date]::-webkit-datetime-edit-month-field,
input[type=date]::-webkit-datetime-edit-year-field{color:var(--ink);padding:0 1px}
input[type=date]:invalid::-webkit-datetime-edit-text,
input[type=date]:invalid::-webkit-datetime-edit-day-field,
input[type=date]:invalid::-webkit-datetime-edit-month-field,
input[type=date]:invalid::-webkit-datetime-edit-year-field{color:var(--ink-3)}
input[type=date]::-webkit-datetime-edit-day-field:focus,
input[type=date]::-webkit-datetime-edit-month-field:focus,
input[type=date]::-webkit-datetime-edit-year-field:focus{
  background:var(--sig-blue);color:#fff;outline:none;border-radius:1px}

/* THE NUMBER FIELD'S SPINNER, the last browser-drawn control in the product. One field on the
   obligations form — PI cover in pounds — and Chrome renders two stacked arrows inside it on
   hover and focus: its own geometry, its own colour, its own hit area, in a system that draws
   every other indicator it owns. They are also useless here. Nobody increments an insurance cover
   amount by one, and the arrows sit exactly where a currency figure's last digits are.

   appearance:textfield rather than none: none on a number input is the same declaration but
   leaves Firefox showing the spinner anyway, and textfield is the property's own name for "this
   is a text field with a numeric value", which is what it is. */
input[type=number]{-moz-appearance:textfield;appearance:textfield}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}

/* ── THE FILTER STRIP, ONCE ───────────────────────────────────────────────────────────────────
   A count-bearing selector: which subset of the records below is on screen. Four pages use it —
   chase-review, dashboard, legislation-review, sanctions-alerts — and each carried its own
   byte-identical copy of these six rules, with sixteen further pages carrying the copy and no
   tabs to use it on. This file had none. So the vocabulary existed twenty times and was defined
   nowhere, which is why changing it on one page silently made that page the odd one out.

   THE TREATMENT CHANGED WITH THE MOVE, and this is the reason. The selected tab used to be
   dark-filled and the rest outlined — which is exactly the pairing .btn and .btn.sec use for
   primary and secondary. On sanctions-alerts those two meanings sat about 300px apart on one
   screen: a filled tab meaning "you are looking at this" above a filled button meaning "this is
   the action we recommend". One idiom, two unrelated meanings, and the tabs are higher up, so a
   user learns the wrong one first.

   Filter is a statement about what is on screen, not a recommended action, so it gives up the
   fill. It marks a current position the way this system marks one everywhere else — weight and a
   rule, like the rail's active item — leaving fill-versus-outline to mean action precedence and
   nothing else. Tabular numerals so the counts do not shift as they change. */
.tabs{display:flex;flex-wrap:wrap;gap:0 var(--s5);margin:0 0 var(--s4);
  border-bottom:1px solid var(--line-2)}
.tab{font-size:var(--t-ui);height:28px;display:inline-flex;align-items:center;padding:0;
  border:0;border-bottom:2px solid transparent;border-radius:0;background:none;
  color:var(--ink-2);line-height:1.7;cursor:pointer;font-weight:400;margin-bottom:-1px}
.tab.on{color:var(--ink);font-weight:600;border-bottom-color:var(--ink)}
.tab .n{margin-left:var(--s2);color:var(--ink-3);font-variant-numeric:tabular-nums}
.tab.on .n{color:var(--ink-2)}
.tab:not(.on):hover{color:var(--ink)}

/* THE SAME MARK ON A REAL <select>, which is the other half of the same finding and the half
   that makes it visible. .select in this system is a <div> specimen with a drawn ::after
   triangle; every actual <select> in the product was still rendering Chrome's own arrow. Left
   alone alongside the rule above, a date field would carry OUR mark and the select immediately
   beside it the BROWSER'S — two different answers to one question, on one form, which is worse
   than both being native.

   A select is a replaced element, so ::after does not render on it and the border trick .select
   uses is unavailable. Two linear-gradients are the way to draw the same 8x4 solid triangle
   while still reading var(--ink-2): each paints a 4px square cut on the diagonal, and the two
   abut to form one triangle. Gradients take custom properties, which a background-image SVG
   would not, so this stays tokenised for the same reason the date mark does.
   padding-right keeps a long option from running under the mark.

   THE SELECTOR IS :not([multiple]) FOR THE SAME REASON THE DISABLED RULE CARRIES [disabled].
   Pages set `input,select,textarea{background:var(--surface)}` — the shorthand again, at
   (0,0,1), loading after this file — which resets background-image to none and erased the mark
   entirely, leaving a select with no arrow at all. :not([multiple]) takes this to (0,1,1) so the
   image, size, position and repeat survive while the page still supplies the colour. It is also
   the honest condition: a multiple-select renders as a list box and opens nothing, so it should
   not carry a disclosure mark. */
select:not([multiple]){-webkit-appearance:none;appearance:none;padding-right:calc(var(--s3) + 14px);
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-2) 50%),
                   linear-gradient(135deg,var(--ink-2) 50%,transparent 50%);
  background-position:calc(100% - var(--s3) - 4px) center,calc(100% - var(--s3)) center;
  background-size:4px 4px,4px 4px;background-repeat:no-repeat}
/* The disabled select has to restate the WHOLE background, and the selector has to outrank a
   plain `select:disabled`. 35 pages disable a control with `background:var(--surface-2)` — the
   SHORTHAND — which resets background-image, -size, -position and -repeat to their initial
   values. Declaring only the image here left the two gradients painting at background-size:auto
   across the entire control, so a disabled select rendered as a grey block with a diagonal wedge
   through it. Restating the four properties is necessary; the extra [disabled] takes this to
   (0,2,1) so it lands after the page's (0,1,1) shorthand rather than before it. */
select[disabled]:disabled{
  background-color:var(--surface-2);
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-3) 50%),
                   linear-gradient(135deg,var(--ink-3) 50%,transparent 50%);
  background-position:calc(100% - var(--s3) - 4px) center,calc(100% - var(--s3)) center;
  background-size:4px 4px,4px 4px;background-repeat:no-repeat}
.auth{display:flex;align-items:center;gap:var(--s2);font-size:var(--t-ui);color:var(--ink-2);margin-bottom:var(--s3)}
.btns{display:flex;gap:var(--s3);align-items:center;flex-wrap:wrap}
.kbd{font-size:var(--t-meta);color:var(--ink-3);margin-left:auto}
/* A white technical document mounted inside a precise inspection area -
   not a white card sitting inside a grey SaaS card. Line and space only. */
/* One structural division instead of two nested boundaries: the column rule
   is the inspection bay, the sheet is the document. */
.src{background:none;border:0;border-left:1px solid var(--edge);border-radius:0;
  padding-left:var(--s5);overflow:visible}
.src-h{font-size:var(--t-meta);font-weight:600;color:var(--ink-2);padding:0 0 var(--s3);border-bottom:1px solid var(--line-2)}
/* Open-sided: two structural rules and one firmer document edge. Square, no
   radius, no shadow, no paper mimicry. */
.src-doc{background:var(--surface);margin:var(--s4) 0;padding:var(--s4) 0 var(--s4) var(--s4);
  border:0;border-top:1px solid var(--line-2);border-bottom:1px solid var(--line-2);
  border-left:2px solid var(--rule-2);
  border-radius:0;font-size:var(--t-meta);line-height:1.8}
.src-doc .t{font-weight:600;font-size:var(--t-ui);margin-bottom:2px}
.src-doc .sub{color:var(--ink-2);margin-bottom:var(--s3);font-size:var(--t-ui)}
.src-doc dl{margin:0;display:grid;grid-template-columns:112px minmax(0,1fr);gap:6px var(--s4)}
.src-doc dt{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.07em;
  color:var(--ink-2);align-self:baseline;padding-top:2px}
.src-doc dd{margin:0;font-weight:500;color:var(--ink)}

/* ========================= INSPECTION PACK =============================== */
/* The most consequential text on the pack screen. It had a box and body
   leading; it now has a band and room, so its visual weight agrees with what
   it carries. Not a word of it changed. */
.manifest{background:none;border:0;border-top:1px solid var(--edge);
  border-bottom:1px solid var(--edge);border-radius:0;padding:var(--s4) 0;
  margin-bottom:var(--s5);font-size:var(--t-ui);color:var(--ink-2);line-height:1.85}
.manifest b{color:var(--ink);font-weight:600}
/* A continuous ruled evidence register on one grid: title, reference,
   approval state. The expanded fingerprint interrupts it as the singular
   evidential reveal - which is the only reason a dark object exists here. */
.pk{border:0;border-bottom:1px solid var(--line);border-radius:0;background:none;
  margin-bottom:0;overflow:visible}
/* v19.1 — THE EVIDENCE REGISTER WAS NOT DRAWING ITS PRINCIPAL RULE. It is one of the five
   2px-ink principal objects the system allows, and :first-of-type selects the first element
   OF ITS ELEMENT TYPE among its siblings — which .pk never is, because .manifest is also a
   div and precedes it. Measured across all 13 product specimens: the Portfolio register, the
   judgement assembly, the Today chart and its baseline each carried their rule; the evidence
   register carried none, on both pack screens. :not(.pk ~ .pk) is "a .pk with no .pk before
   it", which is what was meant. Found by rendering, 4 Sept 2026. */
.pk:not(.pk ~ .pk){border-top:2px solid var(--ink)}
.pk-h{display:grid;grid-template-columns:minmax(0,1fr) 200px 100px;gap:var(--s3);
  align-items:baseline;padding:var(--s3) 0}
.pk-h .t{font-weight:600;font-size:var(--t-row);letter-spacing:-.008em}
.pk-h .ok{font-size:var(--t-meta);color:var(--ink-2);font-weight:600;text-align:right}
/* "Imported" is a provenance state, not an approval. It carries no tick and
   it reads in the boundary colour, not the ordinary context grey — the pack's
   right-hand column otherwise says "approved" in every row and the eye would
   read a sixth approval where there is none. */
.pk-h .ok.imported{color:var(--steel)}
/* compact seal — the default. One line, no dark panel. */
.seal-c{padding:0 0 var(--s3) 0;font-size:var(--t-ui);color:var(--ink-2);display:flex;flex-wrap:wrap;gap:0 var(--s2);align-items:baseline}
.seal-c .m,.pk-m .m{display:inline-flex;align-items:center;gap:var(--s2);color:var(--navy);font-weight:600}
.seal-c .m::before,.pk-m .m::before{content:'';width:7px;height:7px;background:var(--navy);flex:none}
.seal-c .hash,.pk-m .hash{font-family:var(--mono);color:var(--ink-2)}
.pk-b{padding:0 0 var(--s4)}
/* the expanded record. The only dark surface in the product. */
.fp{background:var(--navy);color:var(--on-dark);border-radius:var(--r);overflow:hidden;margin-bottom:var(--s4)}
.fp-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);padding:var(--s3) var(--s4);
  border-bottom:1px solid rgba(242,244,246,.16)}
.fp-h .l{font-size:var(--t-meta);font-weight:600;color:var(--on-dark)}
.fp-h .t{font-family:var(--mono);font-size:var(--t-meta);color:var(--on-dark-3)}
.fp-b{padding:var(--s4)}
.fp .h{font-family:var(--mono);font-size:var(--t-row);word-break:break-all;line-height:1.7}
.fp .v{font-size:var(--t-ui);color:var(--on-dark-2);margin-top:var(--s3);line-height:1.7}
.fp .v b{color:var(--on-dark);font-weight:600}
.fp .tok{display:inline-block;margin-top:var(--s3);border:1px solid rgba(242,244,246,.5);border-radius:var(--r);
  padding:var(--s2) var(--s3);font-size:var(--t-meta);font-weight:500}
.pk-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s4);margin-bottom:var(--s3)}
.pf .l{font-size:var(--t-meta);color:var(--ink-2);margin-bottom:var(--s1);font-weight:500}
.pf .v{font-size:var(--t-ui);color:var(--ink-2);line-height:1.7}
.pf .v b{color:var(--ink);font-weight:600}
.svc{border-top:1px solid var(--line);padding-top:var(--s3)}
.svc .l{font-size:var(--t-meta);color:var(--ink-2);margin-bottom:var(--s1);font-weight:500}
.svc .e{font-size:var(--t-ui);color:var(--ink-2);margin-bottom:2px;line-height:1.7}
.svc .e b{color:var(--ink);font-weight:600}
.support{background:none;border:0;border-left:2px solid var(--steel);border-radius:0;
  padding:0 0 0 var(--s3);font-size:var(--t-ui);color:var(--ink-2);
  margin-top:var(--s5);line-height:1.7}
.support b{color:var(--ink);font-weight:600}
.support .h{font-weight:600;color:var(--ink);font-size:var(--t-sec);margin-bottom:var(--s1);letter-spacing:-.012em}

/* ── the property record, composed by STATE ──────────────────────────────
   Three service registers opened with an identical heading, so three
   obligations in three different conditions read as one repeated thing and
   the eye had no entry point. The fix is not size - the type scale is frozen,
   and the problem was never that the headings were too small. The fix is that
   a section's opening rule now reports the section's condition.

   The rule stays 1px. What changes is its COLOUR, which is a state of the
   peer rule and not a fourth level of authority: 2px ink remains principal
   apparatus and nothing here claims it. An affected register is opened by 1px
   ink, marked with the same 7px fault block used everywhere else, states its
   count in fault red, and says its consequence before its records rather than
   leaving it to be discovered inside them. A register in order recedes to the
   peer rule and a quiet count. Density is untouched; rhythm comes from the
   space between sections, which widens only where something is wrong. */
.work.aff{margin-bottom:var(--s6)}
.work.aff .work-h{border-bottom-color:var(--ink)}
.work.aff .work-h h3{display:flex;align-items:center;gap:var(--s2)}
.work.aff .work-h h3::before{content:'';width:7px;height:7px;flex:none;background:var(--brc-fill)}
.work.aff .work-h .n{color:var(--brc);font-weight:600}
/* the consequence of the section, stated once, before the evidence */
.conseq-l{font-size:var(--t-ui);color:var(--ink);font-weight:500;line-height:1.5;
  margin:var(--s3) 0 0}
/* the reference line was one unbroken run of identity and fact. Identity
   stays on the first line; the facts drop beneath it and can be scanned. */
.rm .d{display:block;margin-top:3px}

/* THE FACT THE PRODUCT EXISTS TO HOLD APART. A record can be approved while
   the property is not compliant, and that tension was legible only after
   hunting for it in a 13px right-hand column. It is now stated once, at the
   top of the record, in the boundary grammar the product already uses - one
   3px ordinary-signal rail and three sentences. Not a banner, not a card, not
   a coloured field, and emphatically not a status. */
.scope-l.fault{border-left-color:var(--brc-fill);border-left-width:3px}
.scope-l.fault i{color:var(--brc)}

/* ── collapsed evidence is still evidence ────────────────────────────────
   A collapsed record carried a title, a reference and a seal line, which read
   as a filename in a list while the one expanded record beside it read as an
   exhibit. Each now carries the legislative basis it was made under and the
   named person who approved it, in the same grammar the expanded record uses.
   Two lines, not every field: the minimum that makes a collapsed record an
   equal evidential object. Where a record genuinely has history, the lineage
   line comes with it - the one device in this product a competitor cannot
   quickly copy, extended across the evidence surface rather than decorated. */
.pk-m{font-size:var(--t-ui);color:var(--ink-2);line-height:1.7;padding:0 0 var(--s2);
  display:flex;flex-wrap:wrap;gap:0 var(--s2)}
.pk-m b{color:var(--ink);font-weight:600}
/* A FIRST-VERSION record has no history, so it does not get a row in which to
   have none: its seal folds onto its metadata line and the entry closes at two
   rows against the four a superseding record needs. The pack therefore reads
   in three tiers - one open, two tall, four compact - and the tier is a fact
   about the record rather than a decision about its importance. */
.pk.orig .pk-m{padding-bottom:var(--s3)}
.pk-b .lin,.pk .lin{margin-top:0}

/* ── the seal marker is the seal ─────────────────────────────────────────
   THE NAVY BLOCK MEANS AN INDEPENDENT TIMESTAMP WAS OBTAINED, AND NOTHING
   ELSE MAY WEAR IT. It is therefore never drawn where no seal exists — the
   product's single authority signal cannot be allowed to appear on a record
   that has not earned it.

   But the seal POSITION is always occupied, because an unsealed record has to
   say why it is unsealed, and the three reasons are not the same thing:

     sealed        navy block  + "Evidence sealed"     an independent timestamp exists
     not yet       no block    + steel statement       correct, expected, not yet evidence
     failed        red block   + fault statement       the seal could not be obtained

   The mark appears only when it is true, and the colour of the words carries
   the distinction the mark cannot: steel is a boundary, red is a fault. A
   record imported on day one and a record whose seal failed are both unsealed
   and they are not remotely the same condition. */
/* v19.1 — .pk-m WAS MISSING FROM ALL FOUR OVERRIDES, AND THE PACK IS WHERE THE STATE IS USED.
   .seal-c .m and .pk-m .m are declared together as navy with a navy block, but only .seal-c
   and .reg were given the unsealed and failed overrides. The day-one pack below puts
   `.m unsealed` inside .pk-m, so every one of its "Not sealed — awaiting first approval"
   records rendered in navy WEARING THE NAVY SEAL BLOCK, and a failed seal would have done the
   same. That is the one thing the seal marker may never do: "the navy block means an
   independent timestamp was obtained, and nothing else may wear it … it is never drawn where
   no seal exists". Measured 4 Sept 2026 on specimen 09d — the specimen added at v19 to prove
   this exact grammar. No colour, component, radius or type step changes; the three states are
   the ones already specified. */
.seal-c .m.unsealed,.pk-m .m.unsealed,.reg .seal.unsealed{color:var(--steel)}
.seal-c .m.unsealed::before,.pk-m .m.unsealed::before,.reg .seal.unsealed::before{content:none}
.seal-c .m.failed,.pk-m .m.failed,.reg .seal.failed{color:var(--brc)}
.seal-c .m.failed::before,.pk-m .m.failed::before,.reg .seal.failed::before{background:var(--brc-fill)}
/* a version that is not yet evidence reads as a boundary, not as a state of
   the record's content */
.vstate.unsealed{color:var(--steel)}

/* ── a service register with nothing in it ───────────────────────────────
   The record's hierarchy ranks by state, and "Fortress holds nothing here" is
   a state. It recedes — its rule drops to the ordinary structural weight and
   its count goes to steel — because there is nothing to act on. It does NOT
   disappear, because the absence of a record is the exact thing this product
   refuses to let a reader mistake for an all-clear. */
.work.none .work-h{border-bottom-color:var(--line-2)}
.work.none .work-h .n{color:var(--steel);font-weight:600}
.none-l{font-size:var(--t-ui);color:var(--ink-2);line-height:1.6;margin:var(--s3) 0 0;
  padding-left:var(--s3);border-left:2px solid var(--steel)}
.none-l b{color:var(--ink);font-weight:600}

/* ── the fault report ────────────────────────────────────────────────────
   NO VALID EVIDENCE. NO COMPLETION. The interlock rail means exactly one
   thing - completion is mechanically unavailable - and it is indifferent to
   the cause. A judgement the operator has not made and a seal the system
   could not obtain are the same condition, so the fault report reuses the
   interlock unchanged: 5px rail, 7px block, micro-uppercase state, dark
   headline, dark explanation. A precision instrument reports a fault. It does
   not turn the page red, it does not apologise, and it never implies that
   anything completed. The three registers beneath it - what has NOT happened,
   what remains valid, what happens next - are the service-record component
   already used on the pack. */
.fault-g{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s5);
  margin-top:var(--s5)}
.fault-g .svc{border-top:1px solid var(--rule-2);padding-top:var(--s3)}
.fault-g .svc .l{color:var(--ink)}
.fault-g .svc .e{margin-bottom:var(--s2)}
/* a system fault is not the operator's error, and the design has to say so */
.origin{font-size:var(--t-ui);color:var(--ink-2);line-height:1.7;margin-top:var(--s4);
  padding-left:var(--s3);border-left:2px solid var(--steel)}
.origin b{color:var(--ink);font-weight:600}

/* ═════════════════════ THE INTERACTION LAYER ═══════════════════════════
   v16 freezes the constitution and proves it survives use. Nothing below
   introduces a colour, a material, a radius or a type step. Every state is
   assembled from apparatus that already exists: the boundary, the 7px
   square, the drawn angle, the dark control material, the shell's near-white.

     AVAILABLE IS NOT COLOURFUL.    SELECTED IS NOT FILLED WITH BRAND COLOUR.
     SUCCESS IS NOT A GREEN PANEL.  ERROR IS NOT A RED PANEL.
     PROCESSING IS NOT ENTERTAINMENT.

   A state change should read as a physical control mechanism changing
   position: a gate releases, a selector moves, a record opens, a process
   executes. Nothing celebrates and nothing performs.

   HOVER IS THE SMALLEST TRUE RESPONSE THE OBJECT CAN MAKE.
   An object that owns a boundary answers with that boundary, one step
   firmer. An object that owns no boundary - a register row, a cell inside a
   machined assembly - answers with the near-white the shell already uses.
   Nothing fills, moves, scales, springs or glows.

   MEASURED, and the reason the dark control does NOT lighten on hover:
   --navy IS lightened --ink. hsl(215 40% 9.2%) against hsl(218 45% 14.3%),
   23 rgb units apart. Every tonal step big enough to read as a hover lands
   inside that gap - lightening --ink by 5% comes within 3 units of the
   reserved evidential colour. So the dark control answers the pointer the
   way the white one does, with its boundary: --on-dark-3 composited over
   --ink is #898E94, and the white control's hover boundary is --rule-2
   #8C939C. Ten rgb units apart. ONE perceived boundary value across both
   materials, arrived at by measurement rather than by preference.
   ═══════════════════════════════════════════════════════════════════════ */

/* — hover, bounded objects: the boundary firms one step — */
.btn:not(.sec):not(.off):not(.busy):hover,.filter.on:hover{border-color:var(--on-dark-3)}
.btn.sec:hover,.act:hover,.select:hover,.input:hover,.filter:not(.on):hover,
.bulk .b:hover,.fld .box:hover{border-color:var(--rule-2)}
.lnk:hover{text-decoration-color:var(--ink)}
/* the disengaged control is excluded from every rule above and answers
   nothing at all. That is what disengaged means. */

/* — hover, unbounded objects: the plane, almost imperceptibly — */
/* white to --rail is 1.03:1. It is meant to be almost nothing: the row's own
   disclosure hardware carries the affordance by going to full ink. No fill
   colour, no rounded row, no shadow, no outline - the signal channel stays
   the dominant thing on the row, which is the entire point of the register. */
.crow:hover,.crow.hov,.prow:hover,.row:hover,.obrow:hover,.opt:hover{background:var(--line)}
.crow:hover,.crow.hov,.prow:hover,.row:hover{border-bottom-color:var(--rule-2)}
.crow:hover .chev::after,.crow.hov .chev::after,.prow:hover .chev::after,
.row:hover .chev::after{border-right-color:var(--ink);border-top-color:var(--ink)}

/* — focus on a segment of a machined assembly — */
/* .opts is overflow:hidden, so a positive offset on a segment is clipped by
   the assembly itself. The ring is therefore inset: the assembly keeps one
   unbroken outer edge and a single cell illuminates inside it. */
.opt:focus-visible,.opt.is-focus{outline-offset:-2px}

/* — selected: a selector moves, it does not light up — */
/* A filled dark centre and a firmer label. No tab fill, no pill, no colour,
   no tick: the state is a change of FORM, so it survives without colour. */
.opt.on{font-weight:500}
.opt.on .radio{border-color:var(--ink)}
/* 6px, and deliberately NOT the 7px micro-signal: that specification governs
   square TELLTALES, which report a state of the world. This is the moving
   part of a control. 6px is the exact figure - the radio is 14px on a 1px
   boundary, so the aperture is 12px and a 6px centre sits on a whole-pixel
   3px ring. A 7px centre would need 2.5px, and the system does not do
   half-pixels. */
.opt.on .radio::after{content:'';display:block;width:6px;height:6px;margin:3px;
  border-radius:50%;background:var(--ink)}
/* a completed field is not a placeholder: same box, same geometry, real ink */
.fld .box.done{color:var(--ink);font-weight:500}

/* — invalid: exact, not alarming — */
/* The control keeps its white material and its exact geometry. What changes
   is the boundary colour and the appearance of the same 7px square that
   marks every other fault in the product. No pink field, no pale-red panel,
   no glow, no icon. The state is carried three ways - boundary, square and
   sentence - so it never depends on colour alone. */
.fld.err .box{border-color:var(--brc)}
.fld .err-t{display:flex;align-items:baseline;gap:var(--s2);margin-top:6px;
  font-size:var(--t-meta);color:var(--brc);font-weight:500;line-height:1.4}
/* the square marks the message, so it sits on the message's FIRST line.
   align-self:center centred it over the whole wrapped block - measured 17px
   low on a three-line message. The offset is the derived half-leading:
   (12px x 1.4 - 7) / 2 = 4.9px. */
.fld .err-t::before{content:'';width:7px;height:7px;flex:none;align-self:flex-start;
  margin-top:5px;background:var(--brc-fill)}

/* — processing: the mechanism is executing — */
/* Same dark operational material, a changed verb, and a determinate 2px
   readout along the control's own bottom edge. 2px because this is an
   instrument reading inside a control, not a structural rule on the plane.
   It does not spin, pulse, bounce or travel: a specimen states a position,
   and a position is information. */
.btn.busy{position:relative;overflow:hidden;cursor:progress}
.btn.busy::before{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:rgba(242,244,246,.28)}
.btn.busy::after{content:'';position:absolute;left:0;bottom:0;height:2px;width:62%;
  background:var(--on-dark)}

/* — the interlock, satisfied — */
/* The gate is not deleted when its condition is met; it is RELEASED. Same
   location, same structure, same micro-uppercase state line - and quieter
   than blocked, because a released gate is not an announcement. The 5px
   fire-red wall becomes the 1px peer rule and the padding absorbs the
   difference, so the text sits on exactly the same vertical in both states:
   5 + 12 = 1 + 16 = 17px. Green appears as one 7px confirmation square and
   nothing else - --ok is 3.05:1 on white, which is precisely why it is never
   allowed to carry prose, a fill or a rail. */
.control.ok{border-left:1px solid var(--rule-2);padding-left:var(--s4)}
.control.ok .l{color:var(--ink)}
.control.ok .l::before{background:var(--ok)}

/* — one disclosure angle, rotated — */
/* Closed points right, open points down. The same 5px box and the same
   1.5px stroke: the hardware has not been swapped, it has moved. A square
   rotated 45deg or 135deg has an identical bounding box, so the right margin
   is unchanged and the two states sit on the same optical column. */
.chev.open::after{transform:rotate(135deg)}

/* — the external-destination angle — */
/* Leaving the product is a fact about the destination, so it earns a mark
   and not an icon. It is the SAME drawn angle as the row disclosure, at the
   same 5px / 1.5px specification, in the orientation the two borders already
   make: border-top and border-right meet at a vertex in the top right, which
   is the head of an outward arrow. One angle, three orientations, three
   meanings - right discloses, down opens, up-and-right leaves the product.
   No box, no fill, no colour, no icon library. The text remains the action;
   the angle is only the affordance.
   MEASURED: rotating this -45deg swings the vertex to vertical and the mark
   becomes a collapse chevron. The correct rotation is none. */
.act.ext::after{content:'';width:5px;height:5px;flex:none;margin-left:var(--s2);
  border-right:1.5px solid var(--ink-2);border-top:1.5px solid var(--ink-2)}

/* ── 06 · the calibration plate ─────────────────────────────────────────
   A board apparatus, not a screen: no rail, no page title, and no 2px
   principal rule - that authority is spent on the five objects that own it.
   It obeys the product's own grammar instead: an instrument label on the
   left, a continuous run of ruled rows, specimens on white, captions in the
   same context type the product uses. It is not a component catalogue and it
   must never look like one. */
/* Four exact columns. Sized by flex, each specimen took the width of its own
   caption - 60 / 525 / 83 on one row - so nothing aligned with anything on
   the row below it. A plate that calibrates the product cannot itself be
   approximate. */

@media(max-width:900px){
  /* The Board's finding was that below 900px this design was switched off
     rather than drawn: the register's headers and the rail's grouping were
     display:none and the canonical row height was released to auto. The two
     things the design is proudest of stopped existing on a phone.
     It is now a COMPOSITION, not a collapse. */
  /* minmax(0,1fr), not 1fr. A grid item's default min-width is auto, which means it refuses to be
     narrower than its own content — so a bare 1fr track does not actually constrain the rail, and
     the nav row pushed the whole document wider than the phone. The desktop rule has always used
     minmax(0,1fr) for the content column for exactly this reason; the mobile rule did not, and the
     overflow rule below cannot bite until it does. */
  .app{grid-template-columns:minmax(0,1fr)}
  .rail,.rail-in{min-width:0}
  .body{padding:var(--s4)}
  /* ── THE PHONE RAIL IS A HAMBURGER DISCLOSURE, not a horizontal index. ─────────────────────────
     The previous phone rail was a horizontal index: the nav groups laid out in a scrolling row and
     the foot — identity and Sign out — was display:none. That dropped the two things a signed-in
     product cannot drop on a phone (a way back to your account, and a way out) and still scrolled
     sideways under pressure. The rail now collapses to a sticky top BAR (lockup + a Menu toggle),
     and the whole navigation — groups, group labels, the active marker, identity and Sign out —
     opens as a drawer in normal document flow, so nothing is clipped and nothing eats the screen.
     One composition for every page; it is STRUCTURE made reachable, not collapsed.

     fortress-shell.js supplies the .rail-toggle button and flips .mnav-open on click / Escape /
     outside-click / choosing a destination. This block is colour-neutral (it recolours nothing and
     defines no token), so it is identical in the legacy and the canonical shell — the rail ground
     is --navy in both. */
  .rail{position:sticky;top:0;z-index:60;display:block;border-right:0;
    border-bottom:1px solid var(--edge);align-self:auto;height:auto}
  .rail-in{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;gap:var(--s2) var(--s3);
    padding:var(--s2) var(--s4);min-height:52px;
    position:static;height:auto;min-height:auto;max-height:none;overflow:visible}
  .rail .lock{flex:1 1 auto;padding:0;min-height:auto;margin:0}
  /* the Menu toggle (hidden on desktop, see .rail-toggle above) */
  .rail-toggle{display:inline-flex;align-items:center;gap:var(--s2);background:transparent;
    border:1px solid rgba(242,244,246,.32);color:var(--on-dark);padding:9px 12px;font-size:var(--t-ui);cursor:pointer}
  .rail-toggle-bars{width:15px;height:11px;position:relative;display:inline-block}
  .rail-toggle-bars::before,.rail-toggle-bars::after,.rail-toggle-bars span{content:'';position:absolute;
    left:0;right:0;height:1.5px;background:currentColor}
  .rail-toggle-bars::before{top:0} .rail-toggle-bars span{top:5px} .rail-toggle-bars::after{top:10px}
  /* the navigation, identity and Sign out open as a full-width drawer below the bar, in flow */
  .rail-scroll{display:none;flex:0 0 100%;max-height:60vh;overflow-y:auto;
    margin-top:var(--s1);padding:var(--s1) 0 0;border-top:1px solid rgba(242,244,246,.14);scrollbar-width:none}
  .rail-scroll::-webkit-scrollbar{display:none}
  .rail.mnav-open .rail-scroll{display:block}
  .ng{display:block;overflow:visible;padding:var(--s1) 0;border-top:1px solid rgba(242,244,246,.12)}
  .ng:first-child{border-top:0}
  .rail .g{width:auto;align-self:auto;margin:0;padding:9px var(--s4) 3px;font-size:11px;font-weight:600;
    color:var(--on-dark-2);text-transform:uppercase;letter-spacing:.07em;border:0}
  .rail a{display:block;white-space:normal;padding:11px var(--s4);margin:0;border:0;font-size:15px;color:var(--on-dark)}
  .rail a.on{font-weight:600}
  /* the desktop positional marker returns to a left rule inside the drawer row */
  .rail a.on::before{left:0;top:0;bottom:0;right:auto;width:3px;height:auto;transform:none;background:var(--on-dark)}
  .rail .foot{display:none;flex:0 0 100%;padding:var(--s3) var(--s4) var(--s1);
    border-top:1px solid rgba(242,244,246,.16);background:var(--navy)}
  .rail.mnav-open .foot{display:block}
  /* C1 in the drawer: the same groups, as accordions with 44px headings; the core is not sticky in a drawer, and the
     drawer is its own scroller, so the desktop fade is off */
  .rail .rail-core{position:static;padding-bottom:0}
  .rail button.g{min-height:44px;margin:0;padding:0 var(--s4);font-size:11px;font-weight:600}
  .rail .rail-account a{padding:11px var(--s3);font-size:15px}
  .rail .rail-me{min-height:44px}
  .rail-scroll[data-more]{-webkit-mask-image:none;mask-image:none}
  /* The register is RE-COMPOSED: two deliberate lines at a fixed 68px, the
     severity rail intact, address and the overdue figure on the first line and
     the position and owner on the second. Column headers genuinely do not
     apply to a two-line row - that is why they go, not to save space. */
  .rhead{display:none}
  .crow{grid-template-columns:16px minmax(0,1fr) auto;grid-template-rows:auto auto;
    height:68px;row-gap:3px;column-gap:var(--s2);align-items:center;padding:0 0 0 var(--s4)}
  /* Position is priority 3 and was truncating while priority-4 owner and the
     column gap held width it did not need. The gap tightens, the owner drops
     a step, and the "+1" overflow counter yields - the issue count on the
     same line already states how many there are. */
  .crow .ci .p{display:none}
  /* width priority at 390px: identity, then urgency, then position, then
     owner. The branch suffix is the lowest-priority item on the row and it
     was forcing the address into truncation, so it yields - the branch is
     already stated in the page summary above. */
  .crow .ca em{display:none}
  .crow .ca{font-size:var(--t-row)}
  .crow .pown{font-size:11px;color:var(--ink-2)}
  .crow .tick{grid-area:1 / 1 / 3 / 2}
  .crow .ca{grid-area:1 / 2 / 2 / 3}
  .crow .pnext{grid-area:1 / 3 / 2 / 4;text-align:right}
  .crow .ci{grid-area:2 / 2 / 3 / 3}
  .crow .pown{grid-area:2 / 3 / 3 / 4;text-align:right}
  .crow .chev{display:none}
  .prow,.row,.obrow{grid-template-columns:minmax(0,1fr);gap:var(--s2)}
  .f3,.pk-grid,.opts{grid-template-columns:1fr}
  .rowacts{justify-content:flex-start}
  .chev{justify-content:flex-start}
  /* the chart keeps a real plot at small width rather than a squashed one */
  /* the readout recomposes to a 2x2 assembly rather than collapsing */
  .register-b,.register-b.three{grid-template-columns:repeat(2,1fr);row-gap:var(--s5);padding:var(--s4) 0}
  .register-b div{padding-right:var(--s4)}
  .register-b div:nth-child(2n){border-right:0;padding-right:0}
  .counts{gap:var(--s5) var(--s6)}
  /* the calibration plate stacks label over specimens. No state is hidden
     on a phone - a state that only exists on a desktop is not proven. */
  /* TOUCH IS A STANDARD, NOT A REFLOW. A compact control may stay compact
     under a pointer; under a finger it may not. Every control the hand meets
     is at least 40px on a phone, and the 14px selection boxes keep their
     drawn size while carrying an invisible 36px hit area - the box is a
     precision mark, the target around it is ergonomics, and they are not the
     same object. */
  .act,.filter,.bulk .b,.select,.btn{min-height:40px}
  .act,.filter,.bulk .b{padding:0 var(--s4)}
  .lnk{display:inline-flex;align-items:center;min-height:40px}
  .tick,.cb{position:relative}
  .tick::before,.cb::before{content:'';position:absolute;left:-11px;right:-11px;top:-11px;bottom:-11px}
  /* the judgement and the certificate it is made against must not be
     separated by a screen of scrolling: the source document comes first on a
     phone, so the operator reads the evidence and then answers about it. */
  .gwrap{display:flex;flex-direction:column}
  .gwrap > .src{order:-1;margin-bottom:var(--s5);padding-bottom:var(--s5);
    border-bottom:1px solid var(--rule-2)}
  .fault-g{grid-template-columns:1fr;gap:var(--s4)}
  .pk-m{gap:0 var(--s2)}
  .pk-h{grid-template-columns:minmax(0,1fr);gap:2px}
  .pk-h .ok{text-align:left}
  .src{border-left:0;padding-left:0}
  .work.reg{margin-left:0}
  .work.reg .rhead,.work.reg .crow,.work.reg .prow{margin-left:0}
  .work.reg .pgin{margin-left:0}
  /* the optical layer is temporary by definition - it does not get to sit on
     top of a small chart and destroy the instrument underneath */
  .plate{display:none}
  .ax,.bars{height:180px}
  .bars{gap:var(--s1)}
  .wk{gap:var(--s1)}
  .wk span{font-size:10px;letter-spacing:0}}
/* N1 (accessibility sweep, 22 Oct): on a short phone window (landscape, or zoomed to 400%) a sticky bar is a permanent
   strip of lost screen, and with the drawer open it can cover the page outright. At 500px tall or less the bar scrolls
   away with the page. */
@media (max-width:900px) and (max-height:500px){
  .rail{position:static}}
/* N2 (accessibility sweep, 22 Oct): while the phone bar is sticky (wider than 900px it is a rail; 500px tall or less it
   scrolls away), a control reached by Shift+Tab could scroll in underneath it. Scrolling a focused control into view
   now keeps it clear of the bar. */
@media (max-width:900px) and (min-height:501px){
  html{scroll-padding-top:72px}}
/* A REGISTER IS WIDER THAN A PHONE, AND TOOK THE DOCUMENT WITH IT. Same failure as the nav row
   above and the same cure. A table's cells will not shrink below their content, so a
   seven-column register simply gets wider than the viewport and drags the page sideways with
   it. Measured on the deployed site at 375px: records.html scrollWidth 833 against a 360
   viewport, and team.html 383 - the whole document draggable away from the left margin, which
   is the one thing the .ng fix was written to stop.
   Twelve pages render a table and not one of them wrapped it in a scroller. display:block makes
   the table its own scroll container while the inner anonymous table box keeps the columns
   aligned, so the register still reads as a register and swipes sideways on its own.
   SCREEN ONLY. Media queries are evaluated against the printed page as well, and an A4 page has
   about 718px of content - under the 900px block above - so while this rule sat inside that
   block it fired on paper too: every printed table became a block whose inner table shrank to its
   content, and the report tables people save as PDF (landlord portfolio, monthly report) printed
   narrow, their header bands stopping short of the margin. On a phone a register still scrolls
   inside itself; on paper a table is a table. */
@media screen and (max-width:900px){
  table{display:block;overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}}
@media print{
  body,.app{background:#fff}
  .rail,.bulk{display:none}
  .fortress-legal,.fortress-legal a{color:#000}
  .fortress-skip,.fortress-idle{display:none}
  .fp{background:#fff!important;color:#000!important;border:2px solid #000}
  .fp-h{border-bottom:1px solid #000}
  .fp-h .l,.fp-h .t,.fp .v{color:#000!important}
  .fp .tok{border:1px solid #000;color:#000}
  .src{border:0}
  .pk{border:0;border-bottom:1px solid #000}
  .work-h{border:0;border-bottom:1px solid #000}
  .judge{border:0;border-top:2px solid #000}
  .src-doc{border:0;border-top:1px solid #000;border-bottom:1px solid #000;border-left:2px solid #000}
  .btn.off{background:#fff!important;border:1px solid #000;color:#666!important}
  .work.reg,.horizon{border:0;border-top:2px solid #000;border-bottom:1px solid #000}
  .manifest,.register,.counts,.bulk{border:0;border-top:1px solid #000;border-bottom:1px solid #000}
  .support,.scope{border:0;border-left:2px solid #000}
  .lnk{text-decoration-color:#000}
  .pk-h .ok,.pk-h .ok i{color:#000!important}
  .crow,.prow,.row{background:#fff!important}
  .crow::before,.prow::before,.row::before{background:#000!important}
  .crow.prog::before,.prow.prog::before{background:#8A8A8A!important}
  .bulk{border-top-color:#000}
  .mean{border-top-color:#000;opacity:1}
  .e-crit{color:#000!important}
  .e-crit::before{background:#000!important}
  .chev::after{border-color:#000}
  .pgin i{border-color:#000}
  .control{border-left:5px solid #000}
  .control .l::before,.crow.crit .ci .n::before{background:#000}
  .plate{display:none}
  .counts .r,.counts .a{border-left-color:#000}
  /* Pointer, keyboard and processing states are demonstrations, not
     evidence, so they do not print. The states that carry INFORMATION do:
     an invalid field, a satisfied gate, a made selection. Signal rails go
     to black because lemon yellow at 1.4:1 does not survive a mono printer
     in an inspection folder - the same correction the count strip already
     carries. */
  .is-focus{outline:0!important}
  .btn.busy::before,.btn.busy::after{display:none}
  .btn.busy{background:#fff!important;color:#000!important;border:1px solid #000}
  .conseq{border-left-color:#000}
  .fld.err .box{border-color:#000}
  .fld .err-t{color:#000!important}
  .fld .err-t::before{background:#000}
  .control.ok{border-left:1px solid #000}
  .opt.on .radio::after{background:#000}
  .tick.on,.cb.on{background:#000!important;border-color:#000!important}
  .e-prog,.e-prog span,.agg .prov-split,.agg .prov-split b{color:#000}
  .reg .seal::before,.seal-c .m::before{background:#000}
  /* grass green was the one signal still printing in hue. On paper the
     square is a mark and the words beside it are the meaning, exactly as
     for the red and navy squares above. */
  /* the three markers now differ in form, so on paper they stay
     distinguishable after every hue collapses to black - which is the whole
     reason the forms were separated. */
  .control.ok .l::before{background:#000}
  .ci .none i,.cur i,.auth i,.pk-h .ok i{border-color:#000!important;background:none!important}
  .reg .seal::before,.seal-c .m::before,.pk-m .m::before{background:#000!important}
  .crow.crit .pnext::before,.work.aff .work-h h3::before{background:#000}
  .work.aff .work-h{border-bottom-color:#000}
  .scope-l.fault,.origin,.none-l{border-left-color:#000}
  .fault-g .svc{border-top-color:#000}
  .crow.hov{background:#fff!important;border-bottom-color:var(--line)!important}
  /* On screen the peak is carried by hue. On paper it is carried by tone and
     weight, so the chart survives a mono printer in an inspection folder. */
  .bar{background:#8A8A8A!important} .bar.hi{background:#000!important}
  .bar i,.wk span,.ax span,.mean b{color:#000!important}
  .bar.hi i,.wk span.hi,.horizon .cs i{color:#000!important;font-weight:700}
  .bars{border-bottom-color:#000}}
/* Motion is a well-made switch, not an animated toy: immediate, resolved, no
   overshoot. Nothing enters, nothing grows from zero, nothing springs. */
@media (prefers-reduced-motion:no-preference){
  .btn,.act,.lnk,.filter,.select,.input,.rail a,
  .crow,.prow,.row,.obrow,.opt,.fld .box,.bulk .b{transition:background-color 80ms linear,
    border-color 80ms linear,color 80ms linear}
  .chev::after{transition:border-color 80ms linear}
  .plate{transition:opacity 120ms linear}}
/* even text selection: navy is evidential integrity, and a text range is not
   evidence. Ordinary control mechanics are ink. */
::selection{background:rgba(14,22,33,.16)}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   PART 2 · REUSABLE VOCABULARY — CANONICAL COMPONENT VOCABULARY (v20), namespaced .fui-*, scoped to .app[data-fortress-ui].
   Extracted from the approved Today operations workbench; GENERIC — no obligation terms, no page
   layout. COMPOSITION (how a page arranges these, its grid and viewport sizing) stays in the page.
   Grey shades from Today are consolidated onto the two on-dark text tokens rather than proliferated.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.app[data-fortress-ui] .fui-mono{font-family:var(--fui-font-mono)}
/* DM Sans loads 400;500 only. Normalise the heavy elements a page still uses bare, so nothing
   inherits the legacy 600 and the browser never synthesises a weight the font does not provide. */
.app[data-fortress-ui] :is(h1,h2,h3,h4,h5,h6,b,strong,th){font-weight:500}
.app[data-fortress-ui] :is(button,a,select,input,textarea,summary,[tabindex]):focus-visible{outline:3px solid var(--fui-focus-ring);outline-offset:2px}
/* C7 / S2 / N24 (Marco, 22 Oct 2026) · THE RING SUITS ITS SURFACE: --fui-focus-ring-light on a light surface, the navy
   ring (#73B9B2) everywhere else. Set as a custom property on the surface, so it reaches every focusable thing inside it
   through inheritance and no selector has to out-rank the (0,4,0) rule above (the review's version lost that contest
   and changed nothing). The FUI light surfaces carry it here; a page whose plate is its own class is covered by
   fortress-shell.js, which marks the focused control data-fui-ring="light" | "dark" from the background just outside
   it — the ground the ring is actually drawn on. Textarea and summary joined the ring rule: they fell through to the
   legacy 2px blue. */
.app[data-fortress-ui] :is(.fui-data-plate,.fui-inspector,.fui-disclosure-panel,.fui-combobox-field,.fui-combobox-list,.fui-context-note),
.app[data-fortress-ui] [data-fui-ring=light]{--fui-focus-ring:var(--fui-focus-ring-light)}
.app[data-fortress-ui] [data-fui-ring=dark]{--fui-focus-ring:var(--fui-interaction-on-dark)}
/* B0 · CONTROLS TAKE THE PAGE'S FACE. A <button>, <input>, <select> or <textarea> does not inherit font-family — the
   browser gives it its own (Arial on the phone Menu button on 50 pages, and on .fui-action). Zero specificity, so any
   page rule that sets a face still wins. */
:where(.app[data-fortress-ui]) :where(button,input,select,textarea){font-family:inherit}
/* B0.3 · THE GROUND REACHES THE FLOOR ON A PHONE (design sweep D1, 22 Oct 2026). Above 900px the rail's own
   min-height:100vh holds .app open to the bottom of the window; at 900px and below the rail is a 52px bar, .app is only as
   tall as its content, and a short page used to end above a white band (13 pages measured at 390). The navy body
   (build-fortress-ui.mjs) already paints that band; this is the same floor for a browser without :has(), and it replaces
   the two pages that stated it for themselves (gas-chase-status, fire-safety-assessment). align-content:start keeps the
   extra height at the foot: a grid stretches its auto rows into free space, which would otherwise grow the menu bar too.
   dvh so a phone's collapsing toolbar cannot reopen the gap; vh first for a browser that does not know dvh. The MFA
   overlay is itself an .app[data-fortress-ui] (fixed, full screen) and is left alone. */
@media(max-width:900px){
  .app[data-fortress-ui]:not(#clMfaOverlay){min-height:100vh;min-height:100dvh;align-content:start}}

/* SURFACES + SCROLL ── a light operational plate; a subdued inspector surface; a hidden-scrollbar
   region with a restrained edge-fade (place .fui-fade in a positioned wrapper over the scroller). */
.app[data-fortress-ui] .fui-data-plate{background:var(--fui-surface-plate);border:1px solid var(--fui-rule-light);color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-inspector{background:var(--fui-surface-inspector);color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-scroll-region{scrollbar-width:none;-ms-overflow-style:none}
.app[data-fortress-ui] .fui-scroll-region::-webkit-scrollbar{width:0;height:0;display:none}
.app[data-fortress-ui] .fui-fade{position:absolute;left:0;right:12px;bottom:0;height:26px;pointer-events:none;background:linear-gradient(to bottom,transparent,var(--fui-surface-plate))}
.app[data-fortress-ui] .fui-fade--inspector{background:linear-gradient(to bottom,transparent,var(--fui-surface-inspector))}

/* WORK-VIEW STRIP ── segmented primary lanes with a count and a label, on the navy plane. */
.app[data-fortress-ui] .fui-work-views{display:flex;background:var(--fui-surface-shell);border:1px solid var(--fui-rule-dark)}
.app[data-fortress-ui] .fui-work-views button{flex:1 1 0;background:transparent;color:var(--fui-text-on-dark-muted);border:0;border-right:1px solid var(--fui-rule-dark);padding:13px 15px;text-align:left;min-height:66px;font:inherit;cursor:pointer}
.app[data-fortress-ui] .fui-work-views button:last-child{border-right:0}
.app[data-fortress-ui] .fui-work-views button[aria-pressed=true]{background:var(--fui-surface-raised);box-shadow:inset 0 -2px var(--fui-interaction-on-dark)}
.app[data-fortress-ui] .fui-work-views strong{display:block;color:var(--fui-text-on-dark);font-size:22px;font-weight:500;line-height:1.1}
.app[data-fortress-ui] .fui-work-views span{display:block;color:var(--fui-text-on-dark-muted);font-size:12px;margin-top:5px}

/* REFINEMENT ── interactive filter/refinement controls on the navy plane (.fui-refinement-group wraps .fui-refinement controls -- never "chips"). Descriptive status labels look
   different on purpose (below): a filter is pressable and shows a pressed state; a status is not
   interactive. The exception variant is dashed + set apart, to read as a filter that cuts ACROSS. */
.app[data-fortress-ui] .fui-refinement-group{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.app[data-fortress-ui] .fui-refinement-group .fui-lab{font:10px var(--fui-font-mono);letter-spacing:.7px;text-transform:uppercase;color:var(--fui-text-on-dark-muted);margin-right:1px}
.app[data-fortress-ui] .fui-refinement{border:1px solid #3A506F;background:transparent;color:var(--fui-text-on-dark-muted);padding:6px 10px;font:inherit;font-size:12px;cursor:pointer}
.app[data-fortress-ui] .fui-refinement b{font-weight:500;color:var(--fui-text-on-dark);margin-left:6px;font-family:var(--fui-font-mono);font-size:11px}
.app[data-fortress-ui] .fui-refinement[aria-pressed=true]{background:var(--fui-surface-raised);border-color:#5E769A;color:#fff}
.app[data-fortress-ui] .fui-refinement--exception{border-style:dashed;border-color:#5E769A;color:#D6C2A6}
.app[data-fortress-ui] .fui-refinement--exception[aria-pressed=true]{background:var(--fui-status-warning-bg);border-style:solid;border-color:var(--fui-status-warning-fg);color:#5A3D06}

/* OPERATIONAL ROW ── a run of these lists work: identity, one line of detail, a next action, a
   status and a timing. No card; a rule between rows. Columns are the page's composition. */
.app[data-fortress-ui] .fui-op-row{width:100%;display:grid;align-items:center;gap:12px;border:0;border-bottom:1px solid var(--fui-rule-light);background:var(--fui-surface-plate);color:var(--fui-text-primary);padding:13px 16px;min-height:76px;text-align:left;font:inherit;cursor:pointer}
.app[data-fortress-ui] .fui-op-row:hover{background:#F8F7F4}
.app[data-fortress-ui] .fui-op-row[aria-pressed=true]{background:#EEEDE9;box-shadow:inset 3px 0 var(--fui-interaction)}
.app[data-fortress-ui] .fui-op-title{font-weight:500;font-size:13.5px;display:block;overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-op-sub{font:11px var(--fui-font-mono);color:var(--fui-text-muted);display:block;margin-top:3px;overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-op-next{font-size:12px;color:var(--fui-text-primary);display:block;margin-top:6px}
.app[data-fortress-ui] .fui-op-next::before{content:'→ ';color:var(--fui-interaction)}
.app[data-fortress-ui] .fui-op-due{text-align:right;font:12px/1.4 var(--fui-font-mono)}
.app[data-fortress-ui] .fui-op-due small{display:block;color:var(--fui-text-muted);font-size:10px;font-family:var(--fui-font-sans)}
.app[data-fortress-ui] .fui-op-due[data-tone=critical]{color:var(--fui-status-critical-fg)}
.app[data-fortress-ui] .fui-op-due[data-tone=warning]{color:var(--fui-status-warning-fg)}

/* REGISTER ── a scannable, selectable list of records: a client register, a certificate register,
   a review queue, a sanctions list. The sibling of the operational row, tuned for density and
   carrying a column header. GENERIC — the page composes the columns (set the same
   grid-template-columns on the head and the rows) and supplies each cell's content; the tone chip
   is the shared .fui-status, so an exception reads the same in every register. Hover, selection
   and the teal rail are the operational row's, so a selected record looks identical across the
   product. Rows are focusable controls (a <button>, or role=option); keyboard operation and the
   focus ring come from the shared rules above. */
.app[data-fortress-ui] .fui-register-head{display:grid;align-items:center;gap:12px;padding:8px 16px;border-bottom:1px solid var(--fui-rule-light);font:10px var(--fui-font-mono);letter-spacing:.8px;text-transform:uppercase;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-register-row{width:100%;display:grid;align-items:center;gap:12px;border:0;border-bottom:1px solid var(--fui-rule-light);background:var(--fui-surface-plate);color:var(--fui-text-primary);padding:12px 16px;min-height:64px;text-align:left;font:inherit;cursor:pointer}
.app[data-fortress-ui] .fui-register-row:hover{background:#F8F7F4}
.app[data-fortress-ui] .fui-register-row[aria-pressed=true],.app[data-fortress-ui] .fui-register-row[aria-selected=true]{background:#EEEDE9;box-shadow:inset 3px 0 var(--fui-interaction)}
.app[data-fortress-ui] .fui-register-name{font-weight:500;font-size:13px;display:block;overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-register-sub{font:11px var(--fui-font-mono);color:var(--fui-text-muted);display:block;margin-top:3px;overflow-wrap:anywhere}

/* STATUS ── a compact RECTANGULAR status label, tinted by tone. Descriptive, not interactive.
   Never colour alone: it always carries text. Tones map product states (critical ← overdue/
   expired; warning ← attention/awaiting-evidence; positive ← complete/current). */
.app[data-fortress-ui] .fui-status{font:11px/1.35 var(--fui-font-sans);padding:4px 8px;display:inline-block;white-space:normal;background:#EEF0F0;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-status[data-tone=critical]{background:var(--fui-status-critical-bg);color:var(--fui-status-critical-fg)}
.app[data-fortress-ui] .fui-status[data-tone=warning]{background:var(--fui-status-warning-bg);color:var(--fui-status-warning-fg)}
.app[data-fortress-ui] .fui-status[data-tone=positive]{background:var(--fui-status-positive-bg);color:var(--fui-status-positive-fg)}
.app[data-fortress-ui] .fui-urg{font:11px var(--fui-font-mono)}
.app[data-fortress-ui] .fui-urg[data-tone=critical]{color:var(--fui-status-critical-fg)}
.app[data-fortress-ui] .fui-urg[data-tone=warning]{color:var(--fui-status-warning-fg)}

/* CONTEXT NOTE ── a tinted panel that EXPLAINS an operational condition, blocker, risk or required
   action. Only then is it tinted; it is not a container for every message. */
.app[data-fortress-ui] .fui-context-note{border-left:2px solid var(--fui-rule-light);padding:12px 13px;background:#EFEEEB;font-size:12.5px;line-height:1.55}
.app[data-fortress-ui] .fui-context-note[data-tone=critical]{border-left-color:var(--fui-status-critical-fg);background:var(--fui-status-critical-bg)}
.app[data-fortress-ui] .fui-context-note[data-tone=warning]{border-left-color:var(--fui-status-warning-fg);background:var(--fui-status-warning-bg)}
.app[data-fortress-ui] .fui-context-note[data-tone=positive]{border-left-color:var(--fui-status-positive-fg);background:var(--fui-status-positive-bg)}
.app[data-fortress-ui] .fui-context-note strong{display:block;font-weight:500;margin-bottom:3px}
.app[data-fortress-ui] .fui-context-note .fui-meta{display:block;margin-top:7px;font:11px var(--fui-font-mono);color:var(--fui-text-primary)}

/* RECORD IDENTITY + SECTION ── who/what this record is, and a ruled section within an inspector. */
.app[data-fortress-ui] .fui-record-identity{border-bottom:1px solid var(--fui-rule-light);padding-bottom:14px}
.app[data-fortress-ui] .fui-record-identity h2{font-size:19px;line-height:1.22;letter-spacing:-.3px;font-weight:500;margin:0 0 5px;overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-record-type{font:11px var(--fui-font-mono);color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-tags{display:flex;align-items:center;gap:8px;margin-top:11px;flex-wrap:wrap}
.app[data-fortress-ui] .fui-section{padding:15px 0;border-bottom:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-section:last-child{border-bottom:0}
.app[data-fortress-ui] .fui-section h3{font:10px var(--fui-font-mono);letter-spacing:.9px;color:var(--fui-text-muted);text-transform:uppercase;margin:0 0 11px}
.app[data-fortress-ui] .fui-section p{margin:0 0 7px;font-size:12.5px;line-height:1.55;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-section p:last-child{margin-bottom:0}
.app[data-fortress-ui] .fui-section small{display:block;color:var(--fui-text-muted);font-size:11.5px;margin-top:2px}
.app[data-fortress-ui] .fui-section .miss{color:var(--fui-status-warning-fg)}
.app[data-fortress-ui] .fui-section .ok{color:var(--fui-status-positive-fg)}

/* RECORD PROGRESS ── an honest stepper. Marks are DRAWN, never typed: tick (done), stem+dot
   (blocked), empty ring (pending). Every step is a real field on the caller's side. */
.app[data-fortress-ui] .fui-record-progress{padding:15px 0}
.app[data-fortress-ui] .fui-record-progress h3{font:10px var(--fui-font-mono);letter-spacing:.9px;color:var(--fui-text-muted);text-transform:uppercase;margin:0 0 13px}
.app[data-fortress-ui] .fui-step{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:10px;align-items:start;position:relative;padding-bottom:13px}
.app[data-fortress-ui] .fui-step:last-child{padding-bottom:0}
.app[data-fortress-ui] .fui-step:not(:last-child)::before{content:'';position:absolute;left:9px;top:19px;bottom:0;width:1px;background:#C7CCCB}
.app[data-fortress-ui] .fui-stepmark{width:19px;height:19px;border-radius:50%;background:#fff;border:1px solid #A7B2B6;position:relative;z-index:1}
.app[data-fortress-ui] .fui-step[data-s=done] .fui-stepmark{background:var(--fui-status-positive-bg);border-color:#90C5B2}
.app[data-fortress-ui] .fui-step[data-s=blocked] .fui-stepmark{background:var(--fui-status-critical-bg);border-color:#DBA2A2}
.app[data-fortress-ui] .fui-step[data-s=done] .fui-stepmark::after{content:'';position:absolute;left:50%;top:45%;width:4px;height:8px;border:solid var(--fui-status-positive-fg);border-width:0 1.7px 1.7px 0;transform:translate(-50%,-55%) rotate(43deg)}
.app[data-fortress-ui] .fui-step[data-s=blocked] .fui-stepmark::before{content:'';position:absolute;left:50%;top:4px;width:2px;height:6px;background:var(--fui-status-critical-fg);transform:translateX(-50%)}
.app[data-fortress-ui] .fui-step[data-s=blocked] .fui-stepmark::after{content:'';position:absolute;left:50%;bottom:3.5px;width:2px;height:2px;background:var(--fui-status-critical-fg);border-radius:50%;transform:translateX(-50%)}
.app[data-fortress-ui] .fui-step strong{font-size:12.5px;font-weight:500;display:block;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-step small{display:block;color:var(--fui-text-muted);font-size:11.5px;line-height:1.45;margin-top:2px}
.app[data-fortress-ui] .fui-step time{font:10px var(--fui-font-mono);color:var(--fui-text-muted);white-space:nowrap}

/* SEARCHABLE COMBOBOX ── accessible input + listbox with clear, loading/empty/error states. */
.app[data-fortress-ui] .fui-combobox{position:relative}
.app[data-fortress-ui] .fui-combobox-field{display:flex;align-items:center;border:1px solid var(--fui-control-border);background:#fff}
.app[data-fortress-ui] .fui-combobox-field:focus-within{outline:3px solid var(--fui-focus-ring);outline-offset:2px}
.app[data-fortress-ui] .fui-combobox input{flex:1;border:0;outline:0;background:transparent;font:inherit;font-size:13.5px;color:var(--fui-text-primary);min-height:44px;padding:0 10px}
.app[data-fortress-ui] .fui-combobox-clear{border:0;background:transparent;color:var(--fui-text-muted);padding:0 10px;font-size:16px;line-height:1;align-self:stretch;cursor:pointer}
.app[data-fortress-ui] .fui-combobox-list{position:absolute;left:0;right:0;bottom:100%;margin-bottom:2px;padding:0;list-style:none;background:#fff;border:1px solid var(--fui-rule-light);max-height:230px;overflow-y:auto;z-index:5;box-shadow:0 -6px 18px rgba(10,19,34,.12)}
.app[data-fortress-ui] .fui-combobox-opt{padding:10px 12px;font-size:13px;color:var(--fui-text-primary);cursor:pointer;border-bottom:1px solid #EEEDEA}
.app[data-fortress-ui] .fui-combobox-opt:last-child{border-bottom:0}
.app[data-fortress-ui] .fui-combobox-opt[aria-selected=true],.app[data-fortress-ui] .fui-combobox-opt:hover{background:#EEF3F2}
.app[data-fortress-ui] .fui-combobox-opt .fui-sub{font:11px var(--fui-font-mono);color:var(--fui-text-muted);display:block;margin-top:1px}
.app[data-fortress-ui] .fui-combobox-note{font-size:11.5px;color:var(--fui-text-muted);padding:10px 12px}
.app[data-fortress-ui] .fui-combobox-note.err{color:var(--fui-status-critical-fg)}

/* DISCLOSURE ── a header toggle that reveals a light panel above the working area. */
.app[data-fortress-ui] .fui-disclosure-toggle{display:inline-flex;align-items:center;gap:8px;background:var(--fui-surface-shell);border:1px solid #33486A;color:#E7EDF2;padding:9px 13px;font:inherit;font-size:13px;font-weight:500;cursor:pointer}
.app[data-fortress-ui] .fui-disclosure-toggle:hover{background:var(--fui-surface-raised);border-color:#4C6489}
.app[data-fortress-ui] .fui-disclosure-toggle[aria-expanded=true]{background:var(--fui-surface-raised);border-color:var(--fui-interaction-on-dark);box-shadow:inset 0 -2px var(--fui-interaction-on-dark)}
.app[data-fortress-ui] .fui-disclosure-panel{background:var(--fui-surface-plate);border:1px solid var(--fui-rule-light);color:var(--fui-text-primary);padding:16px 18px}
.app[data-fortress-ui] .fui-disclosure-close{float:right;background:none;border:1px solid var(--fui-rule-light);color:var(--fui-text-muted);padding:4px 9px;font:inherit;font-size:12px;cursor:pointer}

/* PRIMARY ACTION ── a filled navy action, optionally with a supporting mode line. */
.app[data-fortress-ui] .fui-action{width:100%;display:flex;justify-content:space-between;align-items:center;gap:10px;text-align:left;background:var(--fui-surface-shell);color:#fff;border:1px solid var(--fui-surface-shell);padding:12px 14px;font-size:13.5px;font-weight:500;text-decoration:none;cursor:pointer}
.app[data-fortress-ui] .fui-action:hover{background:var(--fui-surface-raised);border-color:var(--fui-surface-raised)}
.app[data-fortress-ui] .fui-action .fui-action-mode{font:10px var(--fui-font-mono);color:#B7C6D4;font-weight:400;margin-top:2px;display:block}

/* ASSURANCE ── a slim, substantiated product-assurance footer. States a floor; silent when it can't. */
.app[data-fortress-ui] .fui-assurance{color:var(--fui-text-on-dark-muted);font:12px var(--fui-font-sans);line-height:1.5;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;padding:9px 2px 14px;border-top:1px solid var(--fui-rule-dark)}
.app[data-fortress-ui] .fui-assurance .fui-fig{font-family:var(--fui-font-mono);color:#C7D3DE}
.app[data-fortress-ui] .fui-assurance details{display:inline}
.app[data-fortress-ui] .fui-assurance summary{color:var(--fui-text-on-dark-muted);cursor:pointer;font-size:11.5px;text-decoration:underline;text-underline-offset:2px;list-style:none}
.app[data-fortress-ui] .fui-assurance summary::-webkit-details-marker{display:none}
.app[data-fortress-ui] .fui-assurance .fui-exp{display:block;color:var(--fui-text-on-dark-muted);font-size:11.5px;margin-top:5px}

/* ══ THE PAGE TEMPLATE ── B1 (design sweep D1, 22 Oct 2026) ═══════════════════════════════════════════════════════
   The six things every signed-in page was writing for itself — page container, page header, button, form controls, empty
   state, stage bar — so the values drifted (H1 14–32px at x=234–442, inputs 34–48px in eight border colours, button radius
   0–4px, five stage dialects). Values are the design review's reference spec (§1.1–1.10), measured from Today and
   Portfolio, with Marco's calls applied: C4 the kicker is the section name only (content, not CSS); C5 a control's label
   is DM Sans, sentence case, never mono uppercase; C6 a field's border is --fui-control-border (#8C939C, 3.10:1 on
   white); C7 the ring is #0B6E6E on a light surface and stays #73B9B2 on navy (the per-surface rule above draws it).
   GENERIC — a page still owns its composition. Classed selectors only: build-fortress-ui.mjs drops a bare h1 rule as
   board chrome, so the page title is .fui-page-head h1. */

/* PAGE ── the content column (.app > .body): fluid to a 24px gutter (16px on a phone), never a centred measure, so the
   H1 lands at the template's left edge (rail 210 + 24 + the header's 2px optical inset = x 236). */
.app[data-fortress-ui] .fui-page{max-width:none;width:auto;min-width:0;padding:0 24px 40px;color:var(--fui-text-on-dark)}

/* PAGE HEADER ── Today's and Portfolio's: kicker, H1, one summary, actions on the right. A record page uses the same
   header (kicker = parent section, H1 = the record's name) with .fui-back above the kicker. A notice never sits above
   the header: it is the summary's .more line, or a strip below it. */
.app[data-fortress-ui] .fui-page-head{display:flex;justify-content:space-between;align-items:flex-end;gap:24px;padding:24px 2px 16px}
.app[data-fortress-ui] .fui-page-head > :first-child{min-width:0}
.app[data-fortress-ui] .fui-kicker{margin:0 0 9px;font:11px/1.4 var(--fui-font-mono);letter-spacing:1.1px;text-transform:uppercase;color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] .fui-page-head h1{margin:0;font-size:32px;line-height:1.08;font-weight:400;letter-spacing:-.8px;color:var(--fui-text-on-dark);overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-page-sum{margin:9px 0 0;font-size:14px;line-height:1.55;color:#C2CEDA}
.app[data-fortress-ui] .fui-page-sum :is(b,strong){font-weight:500;color:var(--fui-text-on-dark)}
.app[data-fortress-ui] .fui-page-sum a{color:var(--fui-interaction-on-dark);text-decoration:underline;text-underline-offset:3px}
.app[data-fortress-ui] .fui-page-sum .more{display:block;margin-top:3px;font-size:12.5px;color:#93A6B7}
.app[data-fortress-ui] .fui-page-actions{flex:none;display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px}
.app[data-fortress-ui] .fui-back{display:inline-block;margin:0 0 10px;font-size:12px;line-height:1.4;color:var(--fui-text-on-dark-muted);text-decoration:none}
.app[data-fortress-ui] .fui-back:hover{color:var(--fui-text-on-dark);text-decoration:underline;text-underline-offset:3px}

/* BUTTON ── one family, four ranks, one height (§1.7): 36px (40px on a phone), square, 13px/500, a 1px border, 8px
   between buttons. Its colours follow the SURFACE it sits on, the way the focus ring does — custom properties set on the
   surface and inherited, so no selector has to out-rank another: the navy set by default, the plate set inside a light
   surface (.fui-data-plate, .fui-inspector, .fui-disclosure-panel, .fui-context-note). A button whose light surface is a
   page's own class says so itself with .fui-btn--on-plate (or .fui-btn--on-navy for the reverse). Disabled keeps its
   rank: a disabled primary is still the filled one, recessed to #33485F. One primary per view. .fui-action is not a size
   of this: it stays the one tall, full-width next-step action at an inspector's foot. */
.app[data-fortress-ui],.app[data-fortress-ui] .fui-btn--on-navy{
  --fui-btn-primary-bg:var(--fui-text-on-dark); --fui-btn-primary-fg:var(--fui-surface-shell); --fui-btn-primary-hover:#FFFFFF;
  --fui-btn-secondary-bg:transparent; --fui-btn-secondary-bd:#58708B; --fui-btn-secondary-fg:#D5DEE5;
  --fui-btn-secondary-hover-bg:transparent; --fui-btn-secondary-hover-bd:var(--fui-interaction-on-dark);
  --fui-btn-danger-bg:transparent; --fui-btn-danger-fg:var(--fui-status-critical-bg); --fui-btn-danger-hover-bg:rgba(165,45,45,.22);
  --fui-btn-link:var(--fui-interaction-on-dark);
  --fui-btn-off-bg:transparent; --fui-btn-off-bd:var(--fui-rule-dark); --fui-btn-off-fg:#7F93A6}
.app[data-fortress-ui] :is(.fui-data-plate,.fui-inspector,.fui-disclosure-panel,.fui-context-note),.app[data-fortress-ui] .fui-btn--on-plate{
  --fui-btn-primary-bg:var(--fui-surface-shell); --fui-btn-primary-fg:#FFFFFF; --fui-btn-primary-hover:var(--fui-surface-raised);
  --fui-btn-secondary-bg:#FFFFFF; --fui-btn-secondary-bd:#B5BABD; --fui-btn-secondary-fg:var(--fui-text-primary);
  --fui-btn-secondary-hover-bg:#F8F7F4; --fui-btn-secondary-hover-bd:var(--fui-control-border);
  --fui-btn-danger-bg:#FFFFFF; --fui-btn-danger-fg:var(--fui-status-critical-fg); --fui-btn-danger-hover-bg:var(--fui-status-critical-bg);
  --fui-btn-link:var(--fui-interaction);
  --fui-btn-off-bg:var(--fui-surface-inspector); --fui-btn-off-bd:var(--fui-rule-light); --fui-btn-off-fg:#9AA2AA}
.app[data-fortress-ui] .fui-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:36px;margin:0;padding:0 14px;
  border:1px solid transparent;border-radius:0;background:transparent;color:inherit;font:inherit;font-size:13px;font-weight:500;line-height:1.25;
  text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer}
.app[data-fortress-ui] .fui-btn--primary{background:var(--fui-btn-primary-bg);border-color:var(--fui-btn-primary-bg);color:var(--fui-btn-primary-fg)}
.app[data-fortress-ui] .fui-btn--primary:hover{background:var(--fui-btn-primary-hover);border-color:var(--fui-btn-primary-hover)}
.app[data-fortress-ui] .fui-btn--secondary{background:var(--fui-btn-secondary-bg);border-color:var(--fui-btn-secondary-bd);color:var(--fui-btn-secondary-fg)}
.app[data-fortress-ui] .fui-btn--secondary:hover{background:var(--fui-btn-secondary-hover-bg);border-color:var(--fui-btn-secondary-hover-bd)}
.app[data-fortress-ui] .fui-btn--danger{background:var(--fui-btn-danger-bg);border-color:var(--fui-status-critical-fg);color:var(--fui-btn-danger-fg)}
.app[data-fortress-ui] .fui-btn--danger:hover{background:var(--fui-btn-danger-hover-bg)}
.app[data-fortress-ui] .fui-btn--link{padding:0 2px;background:transparent;border-color:transparent;color:var(--fui-btn-link);text-decoration:underline;text-underline-offset:3px}
.app[data-fortress-ui] .fui-btn:is(:disabled,[aria-disabled=true]){cursor:not-allowed}
.app[data-fortress-ui] .fui-btn--primary:is(:disabled,[aria-disabled=true]){background:#33485F;border-color:#33485F;color:#C2CEDA}
.app[data-fortress-ui] :is(.fui-btn--secondary,.fui-btn--danger):is(:disabled,[aria-disabled=true]){background:var(--fui-btn-off-bg);border-color:var(--fui-btn-off-bd);color:var(--fui-btn-off-fg)}
.app[data-fortress-ui] .fui-btn--link:is(:disabled,[aria-disabled=true]){color:var(--fui-btn-off-fg);text-decoration:none}

/* FORM CONTROLS ── one box (§1.8): 36px (40px and 16px type on a phone, so iOS does not zoom), 13px DM Sans,
   padding 0 10px, square, white, the control border (C6). The ring is the shared per-surface ring above (C7). A select
   draws its own 8x4 mark — two gradients, as the shared select rule does — and keeps it: the mark is background-IMAGE
   and the fill is background-COLOR, so a page that sets the fill never wipes the mark (the shorthand did, on 19 pages);
   30px of right padding keeps a long option clear of it. A textarea is the same box, 8px 10px, at least 96px. */
.app[data-fortress-ui] :is(.fui-input,.fui-select,.fui-textarea){box-sizing:border-box;max-width:100%;margin:0;border:1px solid var(--fui-control-border);
  border-radius:0;background-color:#FFFFFF;color:var(--fui-text-primary);font:inherit;font-size:13px;line-height:1.4}
.app[data-fortress-ui] :is(.fui-input,.fui-select){height:36px;padding:0 10px}
.app[data-fortress-ui] .fui-select{-webkit-appearance:none;appearance:none;padding-right:26px;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--fui-text-muted) 50%),linear-gradient(135deg,var(--fui-text-muted) 50%,transparent 50%);
  background-position:calc(100% - 15px) center,calc(100% - 11px) center;background-size:4px 4px,4px 4px;background-repeat:no-repeat}
.app[data-fortress-ui] .fui-textarea{display:block;width:100%;min-height:96px;padding:8px 10px;resize:vertical}
.app[data-fortress-ui] :is(.fui-input,.fui-textarea)::placeholder{color:#7B8490;opacity:1}
.app[data-fortress-ui] :is(.fui-input,.fui-select,.fui-textarea):hover:not(:disabled){border-color:var(--fui-text-muted)}
.app[data-fortress-ui] :is(.fui-input,.fui-select,.fui-textarea)[aria-invalid=true]{border-color:var(--fui-status-critical-fg)}
.app[data-fortress-ui] :is(.fui-input,.fui-select,.fui-textarea):disabled{background-color:var(--fui-surface-inspector);border-color:var(--fui-rule-light);color:#7B8490;cursor:not-allowed}
/* On navy, in a refinement row (or marked .fui-select--on-navy): a select at the refinements' height, transparent, the
   on-dark text and mark. The border stays the control border (C6; it is 5.8:1 on navy, where the refinements' #3A506F is
   2.2:1). The list it opens is the browser's, so its options are restated in ink on white. */
.app[data-fortress-ui] :is(.fui-refinement-group .fui-select,.fui-select--on-navy){height:30px;padding:0 26px 0 10px;font-size:12px;
  background-color:transparent;color:var(--fui-text-on-dark);
  background-image:linear-gradient(45deg,transparent 50%,var(--fui-text-on-dark-muted) 50%),linear-gradient(135deg,var(--fui-text-on-dark-muted) 50%,transparent 50%);
  background-position:calc(100% - 14px) center,calc(100% - 10px) center}
.app[data-fortress-ui] :is(.fui-refinement-group .fui-select,.fui-select--on-navy):hover:not(:disabled){border-color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] :is(.fui-refinement-group .fui-select,.fui-select--on-navy) option{color:var(--fui-text-primary);background-color:#FFFFFF}

/* FIELD ── label above the control, 6px apart; help under it; an error under that. Fields stack 16px apart (a two-column
   grid is the page's: gap 16px 24px). A field is a plate component, so its label is ink. The label is C5: DM Sans
   12px/500, sentence case, no letter-spacing — never the mono uppercase a column head uses. */
.app[data-fortress-ui] .fui-field{display:flex;flex-direction:column;align-items:stretch;gap:6px;min-width:0;margin:0 0 16px}
.app[data-fortress-ui] .fui-field > label,.app[data-fortress-ui] .fui-label{display:block;font:500 12px/1.4 var(--fui-font-sans);letter-spacing:normal;text-transform:none;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-field :is(.fui-input,.fui-select,.fui-textarea){width:100%}
.app[data-fortress-ui] .fui-help{margin:0;font-size:12px;line-height:1.5;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-error{margin:0;font-size:12px;line-height:1.45;font-weight:500;color:var(--fui-status-critical-fg)}
/* CHECK ── a native checkbox or radio at 16px in the interaction teal (accent-color), its label beside it, aligned to
   the label's first line. The text takes its surface's colour, so a check reads on a plate and on navy alike. */
.app[data-fortress-ui] .fui-check{display:inline-flex;align-items:flex-start;gap:8px;font-size:13px;line-height:1.45;color:inherit;cursor:pointer}
.app[data-fortress-ui] .fui-check :is(input[type=checkbox],input[type=radio]){flex:none;width:16px;height:16px;margin:1px 0 0;
  -webkit-appearance:auto;appearance:auto;accent-color:var(--fui-interaction);cursor:pointer}

/* EMPTY / LOADING / ERROR ── inside the plate, never loose text on navy (§1.10): the sentence in muted type with its
   important clause in ink, then at most ONE action (a .fui-btn--primary, which the plate turns navy). The plate that
   holds it is at least 240px tall, so a page with nothing in it still has a work area rather than a void. */
.app[data-fortress-ui] .fui-empty{padding:26px 16px;font-size:13.5px;line-height:1.6;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-empty :is(b,strong){font-weight:500;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-empty p{margin:0}
.app[data-fortress-ui] .fui-empty p + p{margin-top:6px}
.app[data-fortress-ui] .fui-empty .fui-btn{margin-top:14px}
.app[data-fortress-ui] .fui-empty[data-tone=critical] :is(b,strong){color:var(--fui-status-critical-fg)}
.app[data-fortress-ui] .fui-data-plate:has(.fui-empty:not([hidden])){min-height:240px;height:auto}

/* STAGE BAR ── one stage indicator for every wizard, the gas-safety-record tab strip generalised: numbered stages along
   the plate head; the current one in ink on a teal underline; a reached stage's ring filled. Marks are drawn, never
   typed. role=tablist with role=tab buttons (aria-selected), or an <ol> of steps (aria-current=step). */
.app[data-fortress-ui] .fui-stagebar{display:flex;align-items:stretch;gap:2px;margin:0;padding:0 12px;list-style:none;overflow-x:auto;
  border-bottom:1px solid var(--fui-rule-light);background:var(--fui-surface-plate);scrollbar-width:none}
.app[data-fortress-ui] .fui-stagebar::-webkit-scrollbar{display:none}
.app[data-fortress-ui] .fui-stage{flex:none;display:inline-flex;align-items:center;gap:8px;margin:0;padding:14px 12px;border:0;border-bottom:2px solid transparent;
  background:transparent;color:#4C5766;font:inherit;font-size:12.5px;line-height:1.3;white-space:nowrap;text-decoration:none;cursor:pointer}
.app[data-fortress-ui] .fui-stage b{font:500 10px var(--fui-font-mono);letter-spacing:.06em;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-stage:hover{background:#F4F3F0}
.app[data-fortress-ui] .fui-stage:is([aria-selected=true],[aria-current=step]){color:var(--fui-text-primary);border-bottom-color:var(--fui-interaction);background:#EEF3F2}
.app[data-fortress-ui] .fui-stage:is([aria-selected=true],[aria-current=step]) b{color:var(--fui-interaction)}
.app[data-fortress-ui] .fui-stagedot{flex:none;width:8px;height:8px;border-radius:50%;border:1px solid #A7B2B6;background:transparent}
.app[data-fortress-ui] .fui-stage[data-s=done] .fui-stagedot{background:var(--fui-status-positive-fg);border-color:var(--fui-status-positive-fg)}
/* D4 (design sweep, B5) · A stage that carries its state ("None chosen", "2 to resolve") stacks its name over that
   state in .fui-stage-text, the state in muted 11px, so a wizard keeps the state line it already shows. An <ol> of
   steps is a statement, not a control: no hand cursor and no hover fill. On a phone the strip wraps (below), rather
   than scrolling stages off the edge with no cue (the gas-safety-record strip hid stages 04-05 at 390). */
.app[data-fortress-ui] .fui-stage-text{display:inline-flex;flex-direction:column;align-items:flex-start;gap:2px;min-width:0;text-align:left}
.app[data-fortress-ui] .fui-stage-text small{font-size:11px;line-height:1.3;color:var(--fui-text-muted)}
.app[data-fortress-ui] li.fui-stage{cursor:default}
.app[data-fortress-ui] li.fui-stage:not([aria-current=step]):hover{background:transparent}
/* D3 (design pass, 22 Oct · h4-23) · a strip of sibling PAGES is a <nav> of links in the stage bar: the page you are on
   (aria-current=page) is marked as the current stage. Additive; nothing above changes. */
.app[data-fortress-ui] a.fui-stage[aria-current=page]{color:var(--fui-text-primary);border-bottom-color:var(--fui-interaction);background:#EEF3F2}
/* D3 · a picker page's nothing-chosen list (.fui-facts inside its .fui-empty) stacks on a phone: the record, then its
   status line, so an address is not squeezed into a third of the row. Additive. */
@media (max-width:600px){
  .app[data-fortress-ui] .fui-empty .fui-facts-row{grid-template-columns:minmax(0,1fr);gap:2px}
  .app[data-fortress-ui] .fui-empty .fui-facts-row > :last-child{text-align:left;white-space:normal}}

/* FIGURE TILE ── D4 (design sweep, B4). A band of counts that are not views: the work-view strip's tile, drawn as a
   figure (a div, not a button), so a register can head its plate with "how many, of what" without pretending the
   numbers filter it. Same navy, rule, number and label as the view tile; on a phone the figures pair up two to a row
   on the band's own rule, an odd last figure taking the full row (no empty cell). */
.app[data-fortress-ui] .fui-work-views .fui-figure{flex:1 1 0;min-width:0;padding:13px 15px;min-height:66px;border-right:1px solid var(--fui-rule-dark);color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] .fui-work-views .fui-figure:last-child{border-right:0}

/* THE BRANCH PICKER ── ClearlineBranchFilter.mountFilter (clearline-config.js) draws label.cl-bf-lbl and a
   select.fui-select.cl-bf-sel into the page's container and marks it .cl-bf. Label and select sit on one line; the
   label is C5 (DM Sans, sentence case) in its surface's colour, and the refinement row's muted grey on Today. */
.app[data-fortress-ui] .cl-bf:not(.fui-refinement-group){display:inline-flex;align-items:center;gap:8px;min-width:0;max-width:100%}
.app[data-fortress-ui] .cl-bf .select-wrap{min-width:0;max-width:100%}
.app[data-fortress-ui] .cl-bf-lbl{flex:none;font:500 12px/1.4 var(--fui-font-sans);letter-spacing:normal;text-transform:none;color:inherit}
/* C24 · BEFORE RELYING ON THIS RECORD ── the agent's own instruction box on a review screen (clearlineRelyBoxHtml): a
   context note; its "Agent-declared" marker is the record's open circle, drawn (never a typed glyph). */
.app[data-fortress-ui] .cl-rely ul{margin:5px 0 0 17px;padding:0}
.app[data-fortress-ui] .cl-rely li{margin-bottom:3px;line-height:1.5}
.app[data-fortress-ui] .cl-rely-mark{display:inline-block;box-sizing:border-box;width:.72em;height:.72em;margin:0 .32em 0 .05em;border:1.5px solid currentColor;border-radius:50%;vertical-align:-.04em}
/* RS-26: the branch list could not be read — said in the muted ink of the row it sits in, never a silent gap */
.app[data-fortress-ui] .cl-bf-unavailable{font-size:12px;line-height:1.4;color:inherit;opacity:.85}
.app[data-fortress-ui] .fui-refinement-group .cl-bf-lbl{color:var(--fui-text-on-dark-muted)}

@media(max-width:900px){
  .app[data-fortress-ui] .fui-page{padding:0 16px 24px}
  .app[data-fortress-ui] .fui-page-head{flex-direction:column;align-items:flex-start;gap:14px;padding:18px 2px 14px}
  .app[data-fortress-ui] .fui-page-head h1{font-size:26px}
  .app[data-fortress-ui] .fui-page-actions{justify-content:flex-start}
  .app[data-fortress-ui] .fui-btn{min-height:40px}
  .app[data-fortress-ui] .fui-btn--link{min-height:36px}
  .app[data-fortress-ui] :is(.fui-input,.fui-select){height:40px;font-size:16px}
  .app[data-fortress-ui] .fui-textarea{font-size:16px}
  .app[data-fortress-ui] :is(.fui-refinement-group .fui-select,.fui-select--on-navy){height:36px;font-size:16px}
  .app[data-fortress-ui] .fui-stagebar{flex-wrap:wrap}
  .app[data-fortress-ui] .fui-work-views:has(> .fui-figure){flex-wrap:wrap;gap:1px;background:var(--fui-rule-dark)}
  .app[data-fortress-ui] .fui-work-views > .fui-figure{flex:1 1 calc(50% - 1px);min-height:60px;padding:11px 13px;border-right:0;background:var(--fui-surface-shell)}}

/* ══ THE RECORD PICKER ── B3 (design sweep D3, 22 Oct 2026) ═════════════════════════════════════════════════════════
   A page that works on one record — a property, a tenancy, an inventory, a pack, a month — chooses it in the HEAD of its
   work plate (§1.14), never in the header's right slot and never on the navy: the header holds page actions only. The
   head is the plate's top row (§1.5: 12px 16px, a hairline under it, its parts in one wrapping row). The picker is a C5
   label beside the shared .fui-select / .fui-input, or a .fui-combobox search, the control up to 480px; the page's own
   step (Open, Assemble, Load) sits after it. Before a choice the plate holds its .fui-empty under the head, so the page
   reads header → plate, never a sentence on the navy over a void. A search in the head is the shared control's height
   and opens its list downward, into the plate. An empty state's own heading is the plate's ink at 14px. A phone stacks
   the head: label over control, every part full width. */
.app[data-fortress-ui] .fui-plate-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;margin:0;padding:12px 16px;
  border:0;border-bottom:1px solid var(--fui-rule-light);border-radius:0;background:var(--fui-surface-plate);color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-picker{display:flex;align-items:center;gap:8px;flex:1 1 320px;width:auto;min-width:0;margin:0}
.app[data-fortress-ui] .fui-picker > .fui-label{flex:none;white-space:nowrap}
.app[data-fortress-ui] .fui-picker > :is(.fui-select,.fui-input,.fui-combobox){flex:1 1 auto;width:auto;min-width:0;max-width:100%}
.app[data-fortress-ui] .fui-plate-head .fui-combobox input{min-height:34px;font-size:13px}
.app[data-fortress-ui] .fui-plate-head .fui-combobox-list{top:100%;bottom:auto;margin:2px 0 0;padding:0;list-style:none;box-shadow:0 6px 18px rgba(10,19,34,.12)}
.app[data-fortress-ui] .fui-empty :is(h2,h3){margin:0 0 4px;font-size:14px;line-height:1.45;font-weight:500;letter-spacing:normal;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-empty[data-tone=critical] :is(h2,h3){color:var(--fui-status-critical-fg)}
@media(max-width:900px){
  .app[data-fortress-ui] .fui-plate-head{align-items:stretch}
  .app[data-fortress-ui] .fui-plate-head > *{flex:1 1 100%}
  .app[data-fortress-ui] .fui-picker{flex-direction:column;align-items:stretch;gap:6px}
  .app[data-fortress-ui] .fui-picker > .fui-label{white-space:normal}
  .app[data-fortress-ui] .fui-picker > :is(.fui-select,.fui-input,.fui-combobox){flex:none;width:100%}
  .app[data-fortress-ui] .fui-plate-head .fui-combobox input{min-height:38px;font-size:16px}}

/* >>> PUBLIC SHELL ── B7 (design sweep D5, 22 Oct 2026) ════════════════════════════════════════════════════════════
   One bar and one footer for every page a member of the public opens without the rail: sign in, forgot and reset
   password, the evidence verifier, the free-check upload and findings pages, and the tenant's inventory link (§1.14;
   review G1). There were four bars (two mark glyphs, 28 and 24px, three wordmark specs, 25/34px gutters, a 48px staff
   strip) and two pages with none. Now: a 64px shell-navy bar (56px on a phone) with the Gatehouse mark and the
   wordmark at the page gutter, a context label in 11px mono on the right (hidden at 560px and below) and an optional
   link after it; then the page's own work; then the company footer, pinned to the foot of a short page (the shell is
   a full-height flex column) and in normal flow under a long one.
   THE MARK IS DRAWN ONCE, HERE. .fui-pub-mark is a box in the bar's ink, masked by the full Gatehouse — merlons, the
   body with the doorway cut through, the six-bar portcullis (fortress-shell.js FORTRESS_MARK's geometry) — so a page
   carries an empty <span> and no copy of the drawing, and the doorway is the bar's own navy because it is a hole.
   A data: image, which every public page's policy already allows (img-src data:).
   LITERAL VALUES, NOT TOKENS: the --fui-* tokens live on .app[data-fortress-ui], and two of these pages are not inside
   one (the sign-in family's own root, and the findings page, which is the prospect's document and loads none of the
   signed-in stylesheet). The values are the tokens' own: #0A1322 app ground, #102036 shell, #26364F rule on dark,
   #F5F4F1 / #C2CEDA / #9EB1C0 text on dark. This block is also written on its own to fortress-public.css
   (build-fortress-ui.mjs), which is all the findings page loads of it. */
.fui-pub{display:flex;flex-direction:column;min-height:100vh;min-height:100dvh;box-sizing:border-box;background:#0A1322}
.fui-pub > .fui-pub-main{flex:1 0 auto;width:100%;min-width:0;box-sizing:border-box}
.fui-pub-bar{flex:none;display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:64px;margin:0;padding:0 24px;
  box-sizing:border-box;background:#102036;border-bottom:1px solid #26364F;color:#F5F4F1;
  font-family:'DM Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif}
.fui-pub-brand{display:flex;align-items:center;gap:11px;min-width:0;color:inherit;text-decoration:none}
.fui-pub-mark{flex:none;display:block;width:24px;height:24px;background-color:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath fill-rule='evenodd' d='M26 20h12v6H26zM44 20h12v6H44zM62 20h12v6H62zM26 26h48v54H26zM34 80V50a16 16 0 0 1 32 0v30z'/%3E%3Cpath d='M40.5 39h3v41h-3zM48.5 36h3v44h-3zM56.5 39h3v41h-3zM36.5 44h27v3h-27zM35.5 58h29v3h-29zM35.5 71h29v3h-29z'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath fill-rule='evenodd' d='M26 20h12v6H26zM44 20h12v6H44zM62 20h12v6H62zM26 26h48v54H26zM34 80V50a16 16 0 0 1 32 0v30z'/%3E%3Cpath d='M40.5 39h3v41h-3zM48.5 36h3v44h-3zM56.5 39h3v41h-3zM36.5 44h27v3h-27zM35.5 58h29v3h-29zM35.5 71h29v3h-29z'/%3E%3C/svg%3E") center/contain no-repeat}
.fui-pub-word{font-size:14px;font-weight:500;line-height:1;letter-spacing:.14em;white-space:nowrap}
.fui-pub-ctx{display:flex;align-items:center;gap:20px;min-width:0}
.fui-pub-label{font:400 11px/1.4 'JetBrains Mono',ui-monospace,monospace;letter-spacing:1.1px;text-transform:uppercase;color:#9EB1C0;white-space:nowrap}
.fui-pub-link{font-size:12px;line-height:1.4;color:#C2CEDA;text-decoration:none;white-space:nowrap}
.fui-pub-link:hover{color:#F5F4F1;text-decoration:underline;text-underline-offset:3px}
.fui-pub-link:focus-visible{outline:3px solid #73B9B2;outline-offset:2px}
/* THE FOOTER ── the company's lines and its four documents, in the signed-in footer's type (12px mono, links padded
   to a 4px touch row; .fortress-legal), muted on its own navy ground (so it reads the same under the findings page's
   paper stage): identity first, documents after, wrapping when narrow. The words are each page's own. */
.fui-pub-legal{flex:none;display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:4px 24px;margin:0;padding:16px 24px;
  box-sizing:border-box;border-top:1px solid #26364F;background:#0A1322;color:#9EB1C0;font:400 12px/1.6 'JetBrains Mono',ui-monospace,monospace;overflow-wrap:break-word}
.fui-pub-legal p{margin:0}
.fui-pub-legal a{display:inline-block;padding:4px 0;color:inherit;text-decoration:underline;text-underline-offset:2px}
.fui-pub-legal a:hover{color:#F5F4F1}
.fui-pub-legal a:focus-visible{outline:2px solid currentColor;outline-offset:2px}
.fui-pub-legal-links{display:flex;flex-wrap:wrap;gap:0 16px}
@media(max-width:900px){
  .fui-pub-bar{min-height:56px;padding:0 16px}
  .fui-pub-legal{padding:14px 16px}}
@media(max-width:560px){
  .fui-pub-label{display:none}}
@media(forced-colors:active){
  .fui-pub-mark{forced-color-adjust:none;background-color:CanvasText}}
@media print{
  .fui-pub{min-height:0;background:#fff}
  .fui-pub-legal{background:none}
  .fui-pub-legal,.fui-pub-legal a{color:#000;border-color:#000}}
/* <<< PUBLIC SHELL */

/* FILE CONTROL ── B7 (design sweep D5). A file input is never drawn by the browser ("Choose file  No file chosen" in
   the OS's grey): the input is hidden visually, never removed (it keeps its place in the tab order, its keyboard
   activation and the form's validation), and its <label> is drawn as a .fui-btn; the chosen file's name, or the
   control's empty line, sits beside it in .fui-file-name (fortress-shell.js keeps it current). Focus on the hidden
   input draws the ring on the button that stands for it. */
.app[data-fortress-ui] .fui-file{position:relative;display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;min-width:0}
.app[data-fortress-ui] .fui-file input[type=file]{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}
.app[data-fortress-ui] .fui-file input[type=file]:focus-visible + .fui-btn{outline:3px solid var(--fui-focus-ring);outline-offset:2px}
.app[data-fortress-ui] .fui-file-name{min-width:0;font-size:12px;line-height:1.45;color:var(--fui-text-muted);overflow-wrap:anywhere}

/* THE EDGE FADE ON A SIDEWAYS SCROLLER ── B9 (design sweep D5). A band or a refinement row that scrolls sideways on a
   phone used to cut its last chip mid-word with no sign there was more ("0 Bl…", "Entering cha…"). fortress-shell.js
   marks such a strip data-fui-hfade while anything is hidden past its right edge, and this fades its last 40px; the
   mark goes when the strip is scrolled to its end, so the last item is never left faded. */
.app[data-fortress-ui] [data-fui-hfade]{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 40px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 40px),transparent)}

/* MENU ── B9 / C9 (design sweep D5). A secondary button that opens a short list of page actions under it (Portfolio's
   phone header: Add property, then More for Import, Prepare a batch and Export). A disclosure, not an ARIA menu: the
   button carries aria-expanded and aria-controls, the list is ordinary links and buttons, so they keep their own
   roles. fortress-shell.js wires it (data-open on the menu while it is open): the first item takes focus on open, the arrow keys move through the items, Escape
   closes and returns focus to the button, and Tab out of it, a click outside it or choosing an item closes it. */
.app[data-fortress-ui] .fui-menu{position:relative;display:inline-flex}
.app[data-fortress-ui] .fui-menu-list{position:absolute;top:calc(100% + 4px);right:0;z-index:40;min-width:208px;margin:0;padding:4px 0;list-style:none;
  background:#FFFFFF;border:1px solid var(--fui-rule-light);box-shadow:0 8px 22px rgba(10,19,34,.22);color:var(--fui-text-primary);
  --fui-focus-ring:var(--fui-focus-ring-light)}
/* closed until the menu carries data-open — an attribute on the menu, not [hidden] on the list, because the shared
   [hidden]{display:none!important} would stop a page drawing the list inline where it wants it (Portfolio's desktop) */
.app[data-fortress-ui] .fui-menu:not([data-open]) > .fui-menu-list{display:none}
.app[data-fortress-ui] .fui-menu-item{display:flex;align-items:center;width:100%;min-height:40px;margin:0;padding:0 14px;box-sizing:border-box;border:0;
  background:transparent;color:var(--fui-text-primary);font:inherit;font-size:13px;line-height:1.3;text-align:left;text-decoration:none;cursor:pointer}
.app[data-fortress-ui] .fui-menu-item:hover{background:#F8F7F4}
.app[data-fortress-ui] .fui-menu-item:focus-visible{outline-offset:-3px}
/* ══ D0 · THE PAGE PATTERNS ── design pass 22 Oct 2026 (Marco: "draw the basis of the theme from the Today page and
   Review queue") ═════════════════════════════════════════════════════════════════════════════════════════════════════
   Eight patterns every signed-in page builds with, drawn from Today and the Review queue, so the pages are one product:
   the page that scrolls, the split view, KPI tiles, filter chips, the searchable select, compact empty states, one
   context note, and section heads (the footer is fortress-shell.js's .fortress-legal, with the statutory line above
   it). Usage, markup and the rules for each: docs/DESIGN-PATTERNS.md. GENERIC — a page still owns its composition. */

/* PAGE SCROLL ── the content column (.app > .body.fui-page) scrolls with the window. A page never locks it to the
   viewport (height:100vh + overflow:hidden): with a long header, notes and tiles above it, that squeezed the work area
   to one or two rows. Nothing above the split may shrink it; the page grows and scrolls instead. .fui-page-sum's notes
   (.more) are tight lines under the summary — the legacy .more padding is cancelled here. */
.app[data-fortress-ui] .fui-page-sum .more{padding:0}

/* SPLIT VIEW ── one plate: a list and an inspector side by side, each scrolling inside it. Its height is
   clamp(560px, 100vh - 140px, 920px), so at 1440x900 at least six list rows show and at 1280x800 at least five, and no
   header, note or tile above it can make it shorter. The list column is the wider by default; a page that needs a
   wider inspector (a document reader) sets --fui-split-cols. Markup:
     <section class="fui-split fui-data-plate">
       <div class="fui-split-list"> .fui-split-head · [column head] · .fui-split-body > .fui-split-scroll (+ .fui-fade) · .fui-split-foot </div>
       <aside class="fui-split-inspector fui-inspector"> … </aside></section>
   At 900px and below it stacks at its natural height and the page scrolls. */
.app[data-fortress-ui] .fui-split{display:grid;grid-template-columns:var(--fui-split-cols,minmax(0,1.4fr) minmax(340px,.9fr));
  height:clamp(560px,calc(100vh - 140px),920px);overflow:hidden;margin:0 0 12px}
.app[data-fortress-ui] .fui-split-list{min-width:0;min-height:0;display:flex;flex-direction:column;border-right:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-split-inspector{min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden}
.app[data-fortress-ui] .fui-split-head{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;padding:12px 16px;border-bottom:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-split-head > strong{flex:none;font-size:14px;font-weight:500;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-split-body{position:relative;flex:1 1 auto;min-height:0}
.app[data-fortress-ui] .fui-split-scroll{height:100%;overflow-y:auto;overflow-x:hidden}
.app[data-fortress-ui] .fui-split-foot{flex:none;padding:10px 16px;border-top:1px solid var(--fui-rule-light);font:11px/1.5 var(--fui-font-mono);color:var(--fui-text-muted)}
/* .fui-split--empty: nothing to work through (an agency with no records yet, or the list could not be read). The split
   hugs its one sentence — no tall blank list, no inspector describing nothing. Set it only for those two states, not
   for a filter that matches nothing (the split would jump as the agent filters). */
.app[data-fortress-ui] .fui-split--empty{height:auto;grid-template-columns:minmax(0,1fr)}
.app[data-fortress-ui] .fui-split--empty .fui-split-list{border-right:0}
.app[data-fortress-ui] .fui-split--empty .fui-split-inspector{display:none}
.app[data-fortress-ui] .fui-split--empty .fui-split-scroll{height:auto}

/* SEARCH FIELD ── a list's search: a magnifier and the input in one box, the controls' height (36px; 40px on a phone),
   the control border, the ring drawn on the box. <label class="fui-search"><span aria-hidden="true">⌕</span>
   <input type="search" placeholder="…" aria-label="…"></label>. In a flex head it takes the free width. */
.app[data-fortress-ui] .fui-search{display:flex;align-items:center;gap:7px;box-sizing:border-box;height:36px;flex:1 1 200px;min-width:150px;margin:0;padding:0 10px;
  border:1px solid var(--fui-control-border);background:#FFFFFF;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-search:focus-within{outline:3px solid var(--fui-focus-ring);outline-offset:2px}
.app[data-fortress-ui] .fui-search input{flex:1;min-width:0;height:100%;margin:0;padding:0;border:0;outline:0;background:transparent;font:inherit;font-size:13px;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-search input::placeholder{color:#7B8490;opacity:1}
/* the ring is the box's (above), never a second one on the input inside it */
.app[data-fortress-ui] :is(.fui-search,.fui-searchselect-field,.fui-combobox-field) input:focus-visible{outline:none}

/* KPI TILES ── .fui-work-views (above): one band of equal tiles, each <button type="button" aria-pressed="…"><strong>
   count</strong><span>label</span></button> (a count that does not filter is a .fui-figure div). Equal height by
   construction; the pressed tile is raised with the teal underline; 12px under the band. On a phone the tiles become
   one sideways-scrolling row of compact tiles, count and label on one line (the shell fades the edge). */
.app[data-fortress-ui] .fui-work-views + .fui-refine-row{margin-top:12px}

/* FILTER CHIPS ── Today's timing row. <div class="fui-refine-row"> holds one or more .fui-refinement-group (a mono
   .fui-lab, then .fui-refinement buttons, aria-pressed, each with its <b>count</b>); a group that cuts across the
   others is .fui-refinement-group--across, set apart by a rule. A row of filters is never a select. On a phone the row
   is one line that scrolls sideways; no chip shrinks until its label wraps. */
.app[data-fortress-ui] .fui-refine-row{display:flex;align-items:center;flex-wrap:wrap;gap:10px 14px;margin:0 0 12px}
.app[data-fortress-ui] .fui-refinement-group--across{padding-left:14px;border-left:1px solid var(--fui-rule-dark)}
/* .fui-refine-row--flow: the chips of every group flow as one line that wraps chip by chip (a group's box no longer
   takes a whole line when it does not fit), so a long timing set and the cross-cutting pair share the second line
   instead of taking three. The groups keep their role=group and names. No rule is drawn in the flow (it was left at
   the end of a line when the next group wrapped); the exception chip's dashed edge already sets it apart. A picker
   group (the branch filter, .cl-bf) stays one box. */
.app[data-fortress-ui] .fui-refine-row--flow{gap:8px 7px}
.app[data-fortress-ui] .fui-refine-row--flow > .fui-refinement-group:not(.cl-bf){display:contents}

/* SEARCHABLE SELECT ── ONE picker for a long list (FortressSearchSelect, clearline-config.js): it replaces the old
   "Type to narrow this list…" box over a native select. The select stays in the page, hidden, as the source of truth
   (its value, its change event, its options), and a search field stands in its place: the controls' height, the
   control border, the ring on the box. Typing narrows the list (every word must match); Down/Up move, Enter picks,
   Escape closes, Home/End jump; the list drops into the plate under the field. A select with 12 or more options is
   enhanced automatically; data-fui-searchselect enhances a shorter one, data-fui-native keeps one native. */
/* max-height:max-content — in a COLUMN flex field (label over control) the row basis below became the picker's HEIGHT
   (220px, then grown to the grid row): a blank gap of hundreds of px under every property picker in a two-column form
   (Marco, round 2: Damp "New case", Licensing "Add a licence", AML "new assessment"). Capped at its content, the basis
   still sizes it in a row and never stretches it in a column. */
.app[data-fortress-ui] .fui-searchselect{position:relative;display:block;box-sizing:border-box;flex:1 1 220px;width:100%;min-width:0;max-width:100%;max-height:max-content}
.app[data-fortress-ui] .fui-searchselect-native{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;padding:0!important;border:0!important;
  overflow:hidden!important;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;opacity:0;pointer-events:none}
.app[data-fortress-ui] .fui-searchselect-field{display:flex;align-items:center;box-sizing:border-box;height:36px;margin:0;padding:0 0 0 10px;
  border:1px solid var(--fui-control-border);background:#FFFFFF;color:var(--fui-text-muted);cursor:text}
.app[data-fortress-ui] .fui-searchselect-field:hover{border-color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-searchselect-field:focus-within{outline:3px solid var(--fui-focus-ring);outline-offset:2px}
.app[data-fortress-ui] .fui-searchselect-input{flex:1;min-width:0;height:100%;margin:0;padding:0;border:0;outline:0;background:transparent;
  font:inherit;font-size:13px;color:var(--fui-text-primary);text-overflow:ellipsis}
.app[data-fortress-ui] .fui-searchselect-input::placeholder{color:#5F6873;opacity:1}
.app[data-fortress-ui] .fui-searchselect-toggle{flex:none;align-self:stretch;width:30px;margin:0;padding:0;border:0;background-color:transparent;cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--fui-text-muted) 50%),linear-gradient(135deg,var(--fui-text-muted) 50%,transparent 50%);
  background-position:calc(100% - 15px) center,calc(100% - 11px) center;background-size:4px 4px,4px 4px;background-repeat:no-repeat}
.app[data-fortress-ui] .fui-searchselect-list{position:absolute;left:0;top:calc(100% + 2px);z-index:60;box-sizing:border-box;min-width:100%;max-width:min(560px,calc(100vw - 32px));
  max-height:300px;overflow-y:auto;margin:0;padding:4px 0;list-style:none;background:#FFFFFF;border:1px solid var(--fui-rule-light);
  box-shadow:0 8px 22px rgba(10,19,34,.18);color:var(--fui-text-primary);font-size:13px;--fui-focus-ring:var(--fui-focus-ring-light)}
.app[data-fortress-ui] .fui-searchselect-opt{padding:8px 12px;line-height:1.4;cursor:pointer;overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-searchselect-opt[aria-selected=true]{font-weight:500;box-shadow:inset 3px 0 var(--fui-interaction)}
.app[data-fortress-ui] .fui-searchselect-opt.is-active,.app[data-fortress-ui] .fui-searchselect-opt:hover{background:#EEF3F2}
.app[data-fortress-ui] .fui-searchselect-opt[aria-disabled=true]{color:#8A939C;cursor:default;background:transparent}
.app[data-fortress-ui] .fui-searchselect-group{padding:9px 12px 3px;font:10px/1.4 var(--fui-font-mono);letter-spacing:.7px;text-transform:uppercase;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-searchselect-none{padding:10px 12px;font-size:12.5px;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-searchselect.is-disabled .fui-searchselect-field{background:var(--fui-surface-inspector);border-color:var(--fui-rule-light);cursor:not-allowed}
.app[data-fortress-ui] .fui-searchselect.is-disabled :is(.fui-searchselect-input,.fui-searchselect-toggle){cursor:not-allowed;color:#7B8490}
/* on the navy (in a refinement row): the refinements' height, transparent, the on-dark text and mark */
.app[data-fortress-ui] .fui-searchselect--on-navy .fui-searchselect-field{height:30px;background:transparent;color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] .fui-searchselect--on-navy .fui-searchselect-input{font-size:12px;color:var(--fui-text-on-dark)}
.app[data-fortress-ui] .fui-searchselect--on-navy .fui-searchselect-input::placeholder{color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] .fui-searchselect--on-navy .fui-searchselect-toggle{background-image:linear-gradient(45deg,transparent 50%,var(--fui-text-on-dark-muted) 50%),linear-gradient(135deg,var(--fui-text-on-dark-muted) 50%,transparent 50%)}
/* the record picker's control (D3): the select's 480px */
.app[data-fortress-ui] .fui-picker > .fui-searchselect{flex:1 1 auto;width:auto}

/* EMPTY AND NOTHING-CHOSEN ── .fui-empty (above) is compact: one sentence, its key clause in ink, then at most one
   action. Where the page already holds the data it shows something useful instead of a void: a list page's inspector,
   before a choice, says what is waiting in .fui-facts (a short key/value list; a row may be a button that narrows the
   list). A plate that must hug its content sets .fui-data-plate--fit (no 240px floor). */
.app[data-fortress-ui] .fui-data-plate--fit:has(.fui-empty:not([hidden])){min-height:0}
.app[data-fortress-ui] .fui-facts{margin:12px 0 0;padding:0;list-style:none;border-top:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-facts-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 14px;align-items:baseline;box-sizing:border-box;width:100%;margin:0;
  padding:9px 2px;border:0;border-bottom:1px solid var(--fui-rule-light);background:transparent;color:var(--fui-text-primary);font:inherit;font-size:12.5px;line-height:1.45;text-align:left}
.app[data-fortress-ui] button.fui-facts-row{cursor:pointer}
.app[data-fortress-ui] button.fui-facts-row:hover{background:#F4F3F0}
.app[data-fortress-ui] .fui-facts-row > :last-child{font:11px/1.45 var(--fui-font-mono);color:var(--fui-text-muted);text-align:right;white-space:nowrap}
.app[data-fortress-ui] .fui-facts-row b{font-weight:500}

/* CONTEXT NOTE ── one note style. On a plate it is .fui-context-note (above): the tint, the tone on its left edge. On
   the navy — a note between the header and the work — it is .fui-context-note--on-navy: the shell navy, a hairline,
   the tone on the left edge only, never a light or amber block on the navy. A long explanation sits behind
   <details class="fui-disclose"><summary>What this means</summary>…</details>; two parallel explanations sit side by
   side in .fui-context-cols. A note never sits above the page header. */
.app[data-fortress-ui] .fui-context-note--on-navy{margin:0 0 12px;padding:11px 14px;background:var(--fui-surface-shell);border:1px solid var(--fui-rule-dark);
  border-left:3px solid #5E769A;color:#C2CEDA;--fui-focus-ring:var(--fui-interaction-on-dark)}
.app[data-fortress-ui] .fui-context-note--on-navy[data-tone=warning]{background:var(--fui-surface-shell);border-left-color:#E7C77A}
.app[data-fortress-ui] .fui-context-note--on-navy[data-tone=critical]{background:var(--fui-surface-shell);border-left-color:var(--fui-status-critical-bg)}
.app[data-fortress-ui] .fui-context-note--on-navy[data-tone=positive]{background:var(--fui-surface-shell);border-left-color:#8FD3BC}
.app[data-fortress-ui] .fui-context-note--on-navy :is(strong,b){color:var(--fui-text-on-dark)}
.app[data-fortress-ui] .fui-context-note--on-navy .fui-meta{color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] .fui-context-note--on-navy a,.app[data-fortress-ui] .fui-context-note--on-navy .fui-btn--link{color:var(--fui-interaction-on-dark)}
.app[data-fortress-ui] .fui-context-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:6px 28px;margin-top:2px}
.app[data-fortress-ui] .fui-context-cols > *{min-width:0}
.app[data-fortress-ui] .fui-disclose{margin-top:6px}
.app[data-fortress-ui] .fui-disclose > summary{display:inline;cursor:pointer;font-size:12px;text-decoration:underline;text-underline-offset:2px;list-style:none;color:inherit}
.app[data-fortress-ui] .fui-disclose > summary::-webkit-details-marker{display:none}
.app[data-fortress-ui] .fui-disclose[open] > summary{display:inline-block;margin-bottom:6px}

/* SECTION HEAD ── a heading row above a plate, or at the top of a panel: <div class="fui-section-head"><h2>Title</h2>
   <span class="fui-section-meta">…</span><div class="fui-section-actions">…</div></div>. 15px/500 in its surface's
   ink; the meta in 11px mono, muted; actions at the right. 24px above a section on the navy, 10px under the head. */
.app[data-fortress-ui] .fui-section-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 12px;margin:0 0 10px}
.app[data-fortress-ui] .fui-section-head :is(h2,h3){margin:0;font-size:15px;line-height:1.3;font-weight:500;letter-spacing:-.1px;color:inherit}
.app[data-fortress-ui] .fui-section-meta{font:11px/1.4 var(--fui-font-mono);color:var(--fui-text-on-dark-muted)}
.app[data-fortress-ui] :is(.fui-data-plate,.fui-inspector,.fui-disclosure-panel) .fui-section-meta{color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-section-actions{margin-left:auto;display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.app[data-fortress-ui] .fui-page > .fui-section-head{margin-top:24px}

/* THE LEGACY .act ON A SIGNED-IN PAGE ── the v19 .act is a 28px-high chip; a page that styles an a.act as a block
   action (a link with padding, inside a note) had its text clipped by that height (audit s22-gn7). On the signed-in
   layer an .act is as tall as its content, never less than 28px. */
.app[data-fortress-ui] .act{height:auto;min-height:28px}

/* THE ACCOUNT SUB-RAIL ── its items are one line each ("Licences and memberships" wrapped to two in the 210px rail): a
   little less side padding, a touch smaller type, and no wrap. */
.app[data-fortress-ui] .rail .rail-account a{white-space:nowrap}
@media(min-width:901px){.app[data-fortress-ui] .rail .rail-account a{padding-left:10px;padding-right:6px;font-size:13px}}

/* FOOTER ── every signed-in page ends the same way: the page's assurance line(s) (.fui-assurance — the statutory
   figures line, clearlineStatutoryFooter or the page's own #statutory-currency), then the legal footer fortress-shell.js
   appends (.fortress-legal). The statutory line is always ABOVE the legal footer, never after it. */
.app[data-fortress-ui] .stat-cur.fui-assurance{display:block;max-width:none;margin-top:12px;padding-top:9px}
/* a second assurance line follows the first under the same rule */
.app[data-fortress-ui] .fui-assurance ~ .fui-assurance{margin-top:0;padding-top:0;border-top:0}

/* SHORT WINDOWS NEVER TRAP THE WHEEL (Marco, round 2: "Portfolio … Landlords … don't scroll" at a ~590–723px tall
   window). At a short window the split's own scrollers filled the screen, so every wheel landed in the list or the
   inspector and the page never moved. Up to 820px tall the page scrolls instead: the list runs at its natural height
   with the page, and the inspector stays in view beside it (sticky, at most the window's height, scrolling only its own
   overflow and handing the wheel back to the page at its ends). Taller windows keep the plate-height split. */
@media(min-width:901px) and (max-height:820px){
  .app[data-fortress-ui] .fui-split{height:auto;overflow:visible;align-items:start}
  .app[data-fortress-ui] .fui-split-list{display:block;align-self:stretch}
  .app[data-fortress-ui] .fui-split-body{min-height:0}
  .app[data-fortress-ui] .fui-split-scroll{height:auto;overflow:visible}
  .app[data-fortress-ui] .fui-split .fui-fade{display:none}
  .app[data-fortress-ui] .fui-split-inspector{position:sticky;top:0;max-height:100vh;overflow-y:auto}}

@media(max-width:900px){
  .app[data-fortress-ui] .fui-split{display:block;height:auto;overflow:visible}
  .app[data-fortress-ui] .fui-split-list{display:block;border-right:0}
  .app[data-fortress-ui] .fui-split-inspector{display:block;overflow:visible}
  .app[data-fortress-ui] .fui-split-body{min-height:0}
  .app[data-fortress-ui] .fui-split-scroll{height:auto;overflow:visible}
  .app[data-fortress-ui] .fui-search{height:40px;flex-basis:100%}
  .app[data-fortress-ui] .fui-search input{font-size:16px}
  .app[data-fortress-ui] .fui-searchselect-field{height:40px}
  .app[data-fortress-ui] .fui-searchselect--on-navy .fui-searchselect-field{height:36px}
  .app[data-fortress-ui] :is(.fui-searchselect-input,.fui-searchselect--on-navy .fui-searchselect-input){font-size:16px}
  .app[data-fortress-ui] .fui-picker > .fui-searchselect{flex:none;width:100%}
  /* round 2 (D3-E): a phone never hides a tile or a chip past the edge — tiles two to a row, chips wrap */
  .app[data-fortress-ui] .fui-work-views:not(:has(> .fui-figure)){display:grid;grid-template-columns:repeat(2,minmax(0,1fr));border:0;background:transparent;gap:8px}
  .app[data-fortress-ui] .fui-work-views:not(:has(> .fui-figure)) > button{min-width:0;min-height:auto;padding:9px 12px;border:1px solid var(--fui-rule-dark);background:var(--fui-surface-shell)}
  .app[data-fortress-ui] .fui-work-views:not(:has(> .fui-figure)) > button[aria-pressed=true]{border-color:var(--fui-interaction-on-dark)}
  .app[data-fortress-ui] .fui-work-views:not(:has(> .fui-figure)) > button strong{display:inline;font-size:15px}
  .app[data-fortress-ui] .fui-work-views:not(:has(> .fui-figure)) > button span{display:inline;margin:0 0 0 7px;font-size:12px}
  .app[data-fortress-ui] .fui-refine-row{flex-wrap:wrap;gap:8px 10px}
  .app[data-fortress-ui] .fui-refine-row > .fui-refinement-group{flex:0 1 auto;flex-wrap:wrap;min-width:0}
  .app[data-fortress-ui] .fui-refine-row .fui-refinement{flex:none;white-space:nowrap}
  .app[data-fortress-ui] .fui-refinement-group--across{padding-left:10px}
  .app[data-fortress-ui] .fui-context-cols{grid-template-columns:minmax(0,1fr)}}
/* ══ D3 · F. CERTIFICATE CAPTURE ── design pass 25 Oct 2026 (Marco's live sweep: "Gas, EICR and EPC use three different
   layouts and steppers; unify them into one archetype"). Modelled on the Gas safety record after #245. ONE plate:
   the kit's .fui-stagebar across its top; under it .fui-capture = a form column of stage panels beside a 312px record
   position (.fui-inspector). A stage panel: .fui-capture-eyebrow ("Stage 01", mono), its question as a 16px h2,
   .fui-capture-lead, fields two by two (.fui-capture-grid; .fui-capture-full spans), then .fui-capture-actions
   ("Nothing … saved until …" + Back / Continue). A long single stage splits into .fui-capture-part blocks (an h3 each).
   The record position: .fui-capture-label + h2, .fui-capture-facts (the property across the top, the rest two by two),
   then .fui-record-progress "Where this record gets to", then ONE status boundary (.fui-capture-boundary: a
   .fui-context-note that folds behind its label). The property stage holds the page's one picker (.fui-combobox), the
   records due soonest (.fui-capture-due: .fui-empty + .fui-facts, a row chooses, the chosen row pressed) and the
   deep-link note. The chosen record names itself at the header's right (.fui-capture-selected); the scope line sits
   under the plate as .fui-assurance. Field hooks the shared scripts write into (.form-group, .form-label, .form-hint,
   .req) are drawn here inside .fui-capture only. */
.app[data-fortress-ui] .fui-capture{display:grid;grid-template-columns:minmax(0,1fr) 312px;align-items:stretch}
.app[data-fortress-ui] .fui-capture-form{min-width:0;padding:16px;border-right:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-capture-eyebrow{font:500 10px/1 var(--fui-font-mono);text-transform:uppercase;letter-spacing:.11em;color:var(--fui-text-muted);margin:0 0 9px}
.app[data-fortress-ui] .fui-capture-form h2{font-size:16px;font-weight:500;letter-spacing:-.01em;line-height:1.35;color:var(--fui-text-primary);margin:0 0 6px}
.app[data-fortress-ui] .fui-capture-lead{font-size:12.5px;line-height:1.6;color:var(--fui-text-muted);margin:0 0 16px}
.app[data-fortress-ui] .fui-capture-part{border-top:1px solid var(--fui-rule-light);padding:16px 0 0;margin:16px 0 0}
.app[data-fortress-ui] .fui-capture-part > h3{font-size:14px;font-weight:500;line-height:1.4;color:var(--fui-text-primary);margin:0 0 4px}
.app[data-fortress-ui] .fui-capture-part > h3 + .fui-capture-lead{margin-bottom:14px}
.app[data-fortress-ui] .fui-capture-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px 24px}
.app[data-fortress-ui] .fui-capture-full{grid-column:1 / -1}
.app[data-fortress-ui] .fui-capture .form-group{display:flex;flex-direction:column;min-width:0}
.app[data-fortress-ui] .fui-capture .form-label{display:block;margin:0 0 6px;font:500 12px/1.4 var(--fui-font-sans);letter-spacing:normal;text-transform:none;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-capture .form-group :is(.fui-input,.fui-select,.fui-textarea){width:100%}
.app[data-fortress-ui] .fui-capture .req{color:var(--fui-status-critical-fg);font-weight:500}
.app[data-fortress-ui] .fui-capture :is(.form-hint,.hint){font-size:11.5px;line-height:1.5;color:var(--fui-text-muted);margin-top:6px}
.app[data-fortress-ui] .fui-capture :is(.form-hint,.hint) b{color:var(--fui-text-primary);font-weight:500}
.app[data-fortress-ui] .fui-capture .fui-combobox input{min-height:34px;font-size:13px}
.app[data-fortress-ui] .fui-capture .fui-combobox-list{top:100%;bottom:auto;margin:2px 0 0;box-shadow:0 8px 20px rgba(10,19,34,.14)}
.app[data-fortress-ui] .fui-capture-form .fui-context-note{margin:18px 0 0}
.app[data-fortress-ui] .fui-capture-actions{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;border-top:1px solid var(--fui-rule-light);margin-top:16px;padding-top:16px}
.app[data-fortress-ui] .fui-capture-unsaved{font-size:12px;line-height:1.5;color:var(--fui-text-muted);flex:1 1 260px;min-width:0}
.app[data-fortress-ui] .fui-capture-acts{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.app[data-fortress-ui] .fui-capture-record{min-width:0;padding:16px}
.app[data-fortress-ui] .fui-capture-label{display:block;font:500 10px/1 var(--fui-font-mono);text-transform:uppercase;letter-spacing:.11em;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-capture-record > h2{font-size:16px;font-weight:500;letter-spacing:-.01em;color:var(--fui-text-primary);margin:7px 0 14px}
.app[data-fortress-ui] .fui-capture-facts{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:14px}
.app[data-fortress-ui] .fui-capture-facts > .fui-capture-fact:first-child{grid-column:1 / -1}
.app[data-fortress-ui] .fui-capture-fact{border-top:1px solid var(--fui-rule-light);padding:10px 0;min-width:0}
.app[data-fortress-ui] .fui-capture-fact > span:not(.fui-status){display:block;font:500 9.5px var(--fui-font-mono);text-transform:uppercase;letter-spacing:.07em;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-capture-fact > strong{display:block;margin-top:4px;font-size:12.5px;font-weight:500;color:var(--fui-text-primary);overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-capture-fact > strong.none{font-weight:400;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-capture-fact > small{display:block;margin-top:4px;font-size:11px;line-height:1.45;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-capture-fact > .fui-status{margin-top:6px}
.app[data-fortress-ui] .fui-capture-record .fui-record-progress{border-top:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-capture-boundary{margin-top:16px;color:var(--fui-text-primary)}
.app[data-fortress-ui] .fui-capture-boundary > summary{display:block;cursor:pointer;list-style:none;font:500 10px/1 var(--fui-font-mono);text-transform:uppercase;letter-spacing:.11em;color:var(--fui-text-muted);text-decoration:underline;text-underline-offset:3px}
.app[data-fortress-ui] .fui-capture-boundary > summary::-webkit-details-marker{display:none}
.app[data-fortress-ui] .fui-capture-boundary[open] > summary{margin-bottom:8px}
.app[data-fortress-ui] .fui-capture-boundary p{margin:0;font-size:12.5px;line-height:1.55}
.app[data-fortress-ui] .fui-capture-boundary p + p{margin-top:6px}
.app[data-fortress-ui] .fui-capture-due{margin:18px 0 0;border-top:1px solid var(--fui-rule-light)}
.app[data-fortress-ui] .fui-capture-due > .fui-empty{padding:14px 0 0;max-width:none}
.app[data-fortress-ui] .fui-capture-due .fui-facts{margin-top:10px}
.app[data-fortress-ui] .fui-capture-due .fui-facts-row > :first-child{overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-capture-due .fui-facts-row[aria-pressed=true]{background:#EEEDE9;box-shadow:inset 3px 0 var(--fui-interaction)}
.app[data-fortress-ui] .fui-capture-more{margin:8px 0 0;font-size:11.5px;line-height:1.5;color:var(--fui-text-muted)}
.app[data-fortress-ui] .fui-capture-selected{border-left:3px solid var(--fui-interaction-on-dark);padding:1px 0 1px 13px;min-width:0;flex:0 0 auto;max-width:min(380px,40%)}   /* it kept its words whole: shrinking beside a long summary split the postcode and the reference at 1024 */
.app[data-fortress-ui] .fui-capture-selected b{display:block;color:var(--fui-text-on-dark);font-size:13.5px;font-weight:500;overflow-wrap:anywhere}
.app[data-fortress-ui] .fui-capture-selected span{display:block;font:400 10.5px var(--fui-font-mono);color:var(--fui-text-on-dark-muted);margin-top:3px;letter-spacing:.04em;text-transform:uppercase}

@media(max-width:900px){
  .app[data-fortress-ui] .fui-capture{grid-template-columns:minmax(0,1fr)}
  .app[data-fortress-ui] .fui-capture-form{border-right:0;border-bottom:1px solid var(--fui-rule-light)}
  .app[data-fortress-ui] .fui-capture-grid{grid-template-columns:minmax(0,1fr)}
  .app[data-fortress-ui] .fui-capture-full{grid-column:auto}
  .app[data-fortress-ui] .fui-capture .fui-combobox input{min-height:38px;font-size:16px}
  .app[data-fortress-ui] .fui-capture-actions{flex-direction:column;align-items:stretch}
  .app[data-fortress-ui] .fui-capture-unsaved{flex:0 0 auto}   /* in the column its 260px basis became a 260px height: a blank band above the buttons */
  .app[data-fortress-ui] .fui-capture-acts{width:100%}
  .app[data-fortress-ui] .fui-capture-acts .fui-btn{flex:1 1 auto}
  .app[data-fortress-ui] .fui-capture-due .fui-facts-row{grid-template-columns:minmax(0,1fr)}
  .app[data-fortress-ui] .fui-capture-selected{max-width:none}
  .app[data-fortress-ui] .fui-capture-due .fui-facts-row > :last-child{text-align:left}}
