/* LEDGIOR — the interface, from the September 2026 design.
 *
 * Read this before changing a colour. The values are TAKEN from the delivered
 * screens (`portal-design/`), measured off the rendered DOM rather than eyeballed,
 * so a token here is what the designer actually drew and not an approximation of it.
 *
 * WHY A STYLESHEET AND NOT THE DESIGN'S OWN INLINE STYLES. The delivered files
 * carry ~366 `style="..."` attributes per screen, which is right for a compiled
 * artefact and wrong for a template somebody has to edit under time pressure on
 * the 20th. The last port produced exactly that and it is the reason the portal
 * templates are painful. One stylesheet, class names that say what a thing IS,
 * and the markup stays readable.
 *
 * The one rule that outranks appearance: a screen never computes a number
 * (`CLAUDE.md`). Nothing here can help with that, but everything here is in
 * service of a figure a reviewer can trust at a glance.
 */

/* ── Tokens ─────────────────────────────────────────────────────────────── */
:root {
  color-scheme: light;

  /* Ink. The design uses one family with tabular numerals rather than a
     separate serif for figures, so weight and colour carry the hierarchy. */
  --ink:        #0F1115;   /* headings, active nav, a figure that matters */
  --ink-2:      #4B5563;   /* idle nav, secondary body */
  --ink-3:      #6B7280;   /* labels, metadata, column heads. The workhorse */
  --ink-4:      #9CA3AF;   /* the quietest thing still meant to be read */
  --on-ink:     #C4C9D2;   /* body text ON an ink ground */
  --on-ink-2:   #C7CDD6;

  /* Grounds */
  --paper:      #FFFFFF;   /* the app itself */
  --desk:       #C9CBCD;   /* what the app floats on */
  --fill:       #EDEFF2;   /* a filled block inside the app */
  --subtle:     #F3F4F7;   /* a row hover, a quiet panel */
  --subtle-2:   #F1F3F6;   /* the active nav item, the chrome's underline */
  --wash:       #EFF4FF;   /* accent wash */

  /* THE RAIL'S OWN GROUND. The design pack shipped `--on-ink`,
     `--on-ink-2` and `--accent-lit` -- "text ON an ink ground", "accent ON an
     ink ground" -- and a white brand mark, and nothing in the console ever
     used any of them: the port kept the tokens for a dark surface and built
     everything on paper. These name that surface so the rail is themed from
     variables rather than from thirty scattered rgba() literals.
     `PROJECT-LOG.md` §4 item 311. */
  --rail-bg:    #1B1F27;   /* a shade off `--ink`, so the rail is a SURFACE
                              rather than a black hole beside white paper.
                              LIFTED from #14161B on 11 Sep -- "the black is
                              too black". #14161B sits at about 8% luminance,
                              which beside #FFFFFF paper is not a dark surface
                              but a hole; #1B1F27 is ~12% and still
                              unmistakably ink. The four below move with it
                              because the ladder between them is what makes a
                              control read as raised -- lifting only the
                              ground would flatten every one of them.
                              §4 item 317. */
  --rail-line:  #2E333D;   /* its internal rules */
  --rail-lift:  #242932;   /* a control sitting on it */
  --rail-on:    #323844;   /* the active nav item */

  /* Rules. Three weights and the design keeps to them. */
  --rule:       #E5E7EB;   /* the app's own edge */
  --rule-2:     #EDEFF2;   /* a block edge, the rail's border */
  --rule-3:     #F3F4F7;   /* between rows */

  /* The three facts colour is spent on, plus the accent that is identity. */
  --accent:     #2563EB;   /* Ledgior blue: identity, links, the client rule */
  --accent-ink: #1E40AF;   /* link hover */
  --accent-lit: #60A5FA;   /* accent ON an ink ground */
  --accent-2:   #93B4FF;
  --accent-3:   #BFD3FF;   /* the dotted "not yet" border */

  --good:       #16A34A;
  --good-lit:   #86EFAC;
  --good-ink:   #15803D;
  --good-wash:  #ECFDF3;

  --warn:       #B45309;
  --warn-wash:  #FEF6E7;

  --bad:        #E11D48;
  --bad-wash:   #FFE9EE;

  /* Type. One family. `tabular-nums` is global, which is what makes a column
     of money line up without a second typeface. */
  --font: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --t-display: 38px;  /* the one number a screen is about */
  --t-h1:      22px;
  --t-h2:      16px;
  --t-lead:    13.5px;
  --t-body:    13px;  /* everything an operator reads all day */
  --t-meta:    12.5px;
  --t-small:   12px;
  --t-label:   11.5px;
  --t-caps:    11px;  /* column heads and group headings, tracked +0.02em */
  --t-tiny:    10.5px;

  /* Rhythm */
  --r-sm: 2px;    /* a printed rule, a marker */
  --r:    9px;    /* a nav item, a control */
  --r-lg: 11px;   /* a panel, the client switcher */
  --r-xl: 22px;   /* the app card itself */
  --r-pill: 20px;

  --rail-w: 254px;
  --chrome-h: 62px;
  /* The floating grey inset around the PORTAL card only — the console is
     `desk--flush` (padding 0) and unaffected. Cut from 22px on the founder's
     "reduce the grey area": the client surface wastes less of every edge now,
     while the card's rounding/shadow keep it reading as a card. */
  --desk-pad: 8px;

  --lift: 0 30px 70px -34px rgba(17, 19, 24, .34);
  --lift-sm: 0 8px 20px -10px rgba(22, 28, 22, .5);
}

/* ── Font, self-hosted ──────────────────────────────────────────────────
 * Extracted from the delivered design bundles rather than linked from a CDN:
 * a client portal shows a person their own financial data, and a font request
 * hands their IP address to a third party on every page view for nothing.
 * One variable file per range covers 400-800. `U+20B9`, the rupee sign, is in
 * latin-ext — so BOTH files are needed and neither is optional.
 */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal; font-weight: 200 800; font-display: swap;
  src: url('/static/fonts/plus-jakarta-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
                 U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal; font-weight: 200 800; font-display: swap;
  src: url('/static/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Base ───────────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--desk);
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  font-size: var(--t-body);
  line-height: 1.5;
}
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-ink); text-decoration: underline; }
button { font-family: inherit; cursor: pointer; border: 0; background: none;
         color: inherit; text-align: left; font-size: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px;
                 border-radius: var(--r-sm); }
@keyframes sweep { 0% { transform: translateX(-110%); }
                   100% { transform: translateX(420%); } }
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ── The app card, floating on the desk ─────────────────────────────────── */
.desk { padding: var(--desk-pad); min-height: 100vh; }

/* THE CONSOLE FILLS THE SCREEN; THE PORTAL STAYS A CARD.
   `PROJECT-LOG.md` §4 item 282. The floating card reads well on a client
   surface somebody opens once a month, and wastes a strip of every edge on an
   operator's work surface -- which is a dense table read all day, on a screen
   the design spec already calls desktop-first. The founder asked for it
   connected on four sides.

   SCOPED WITH A MODIFIER RATHER THAN BY EDITING `.desk` AND `.app`, because
   BOTH shells use those two classes -- the portal's element is
   `class="app app--portal"`, which a grep for `class="app"` does not find.
   Changing the shared rule would have silently restyled the client portal
   from a change made to the console. */
.desk--flush { padding: 0; }
.desk--flush .app {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  /* Exactly the viewport, not `calc(100vh - padding)`: the panes inside
     already scroll on their own (`.content` is `overflow: auto`), so this
     keeps the scrolling model untouched and only removes the inset. */
  min-height: 100vh;
}

.app {
  display: flex;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--lift);
  min-height: calc(100vh - (var(--desk-pad) * 2));
}

/* ── Rail ───────────────────────────────────────────────────────────────── */
.rail {
  flex: 0 0 var(--rail-w);
  background: var(--rail-bg);
  /* No border: the colour change IS the edge, and a light rule against a
     dark ground reads as a seam. */
  border-right: 0;
  display: flex; flex-direction: column;
  padding: 22px 0 18px;
  color: var(--on-ink);
}
.rail__brand { padding: 0 20px 16px; }
.rail__mark { height: 19px; width: auto; display: block; }
.rail__word { font-size: 20px; font-weight: 600; letter-spacing: -.036em;
              line-height: 1; color: #FFFFFF; }
.rail__lockup { display: flex; align-items: center; gap: 10px; }

/* THE CLIENT PICKER, INSIDE THE SWITCHER'S DISCLOSURE. §4 items 286 and 312.
   `.filters` is laid out for a horizontal bar across a screen; in a 254px
   rail it has to stack, and the select has to be allowed to shrink
   (`min-width: 0`) or a long client name pushes it out of the column. */
.picker {
  display: flex; flex-direction: column; align-items: stretch; gap: 5px;
  margin: 0; padding: 11px 12px 12px; border-top: 1px solid var(--rail-line);
}
/* THE LABELS GO TO SCREEN READERS ONLY. The picker was 154px of a 900px rail
   -- more than the brand and the switcher together -- because "Find" and
   "Client" each took a line above their own control. Both already say what
   they are in the visible copy ("name…" and "— pick a client —"), so the
   label stays in the accessibility tree and leaves the layout. §4 item 311. */
.picker__label {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* Visually hidden, still in the accessibility tree -- for a live region that
   speaks to a screen reader without taking any space (the inbox announcer). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.picker select,
.picker input { width: 100%; min-width: 0; font: inherit;
                font-size: var(--t-small); padding: 7px 9px;
                border: 1px solid var(--rail-line); border-radius: var(--r);
                background: var(--rail-bg); color: #FFFFFF; }
.picker input::placeholder { color: var(--ink-3); }
.picker select:focus-visible,
.picker input:focus-visible { outline: 2px solid var(--accent-lit);
                              outline-offset: 1px; }
/* A submit button does not need the full width of the rail. */
.btn--pick { align-self: flex-start; margin-top: 2px; }
/* NO SILENT CAP. The picker shows at most `_CLIENT_PICKER_LIMIT` clients and
   this is the line that says so -- 12px and quiet, because it is a fact about
   the control rather than a warning. */
.picker__note { margin: 2px 0 0; font-size: var(--t-label); line-height: 1.45;
                color: var(--ink-4); }

.rail__env { margin-top: 6px; font-size: var(--t-label); font-weight: 500;
             color: var(--ink-4); }

/* The client switcher — the highest-risk element in the console. The accent
   bar down its left is the per-client marker peripheral vision catches. */
.switcher {
  margin: 0 14px 12px; width: calc(100% - 28px);
  background: var(--rail-lift); border: 1px solid var(--rail-line);
  border-radius: var(--r-lg);
  /* `block`, not `flex`: this is a <details> now, and the flex row it used to
     be is the <summary> below. §4 item 312. */
  display: block;
}
/* THE FACE OF THE CARD, and the control that opens the picker. The default
   disclosure triangle is removed in both engines -- `list-style` for the
   standard, the `-webkit-` pseudo-element for Safari -- because the card
   already says "Pick" or "Change" in words. */
.switcher__face {
  display: flex; align-items: center; gap: 11px; padding: 10px 12px;
  cursor: pointer; list-style: none; border-radius: var(--r-lg);
}
.switcher__face::-webkit-details-marker { display: none; }

/* AN EDITOR IS A ROW OF ITS OWN, NEVER A CONTROL INSIDE A CELL.
   §4 item 327, and it took three attempts to get here. Five controls drawn
   in every row made each one four lines tall and buried the names. Collapsing
   them into a per-cell <details> fixed that and introduced a worse one: the
   column was sized by its contents, so opening an editor widened it from 5rem
   to 14rem and re-wrapped every name in the table -- the list appearing to
   rearrange itself because somebody clicked one row. Pinning the column wide
   squeezed the names permanently instead, which is the same cost paid all the
   time rather than some of it.
   A full-width row under the one being edited owes nothing to any column, so
   the table keeps its shape whether an editor is open or not, and `.filters`
   -- a page-wide wrapping flex row -- is finally in the container it was
   written for. It is a plain link and a plain form: no JavaScript, which
   under `script-src 'self'` is a requirement and not a preference. */
tr.is-editing > td { border-bottom: none; }
td.rowedit { background: var(--wash); }
td.rowedit .filters { margin: 0; }
a.rowedit__open::before { content: "\270e\00a0"; }
.rowedit label {
  display: block;
  font-size: .82rem;
  color: var(--ink-2, inherit);
}
.switcher__face:hover { background: var(--rail-on); }
.switcher__face:focus-visible { outline: 2px solid var(--accent-lit);
                                outline-offset: 1px; }
.switcher__verb { flex: 0 0 auto; font-size: var(--t-label); font-weight: 600;
                  letter-spacing: .04em; text-transform: uppercase;
                  color: var(--accent-lit); }
.switcher[open] { background: var(--rail-bg); border-color: var(--rail-on); }
.switcher:hover { border-color: var(--accent); }
/* A client IS chosen: the card takes the accent, which is the identity cue
   the removed stripe used to carry. */
/* Both lifted with the rail (§4 item 317): the accent has to stay clearly
   ABOVE the ground it sits on, and against #1B1F27 the old #16233F had lost
   most of the separation that makes this card the thing the eye finds first. */
.switcher.is-set { background: #1D2E52; border-color: #3B5CA0; }
/* THE BAR IS GONE. A thick accent rule down the side of a rounded card is
   a stock generated-design motif and the founder named it on sight. What it
   was DOING still has to happen -- `CLAUDE.md` calls the switcher "the
   highest-risk element in the console" and the bar was the cue peripheral
   vision catches before reading does -- so the whole card now carries the
   accent instead of wearing a stripe. A filled block is a stronger
   peripheral signal than a 3px line, not a weaker one. §4 item 311. */
.switcher__mark { display: none; }
.switcher__body { flex: 1 1 0; min-width: 0; }
.switcher__name { display: block; font-size: var(--t-lead); font-weight: 600;
                  color: #FFFFFF; overflow: hidden; text-overflow: ellipsis;
                  white-space: nowrap; }
.switcher__code { display: block; font-size: var(--t-label);
                  color: var(--ink-4); letter-spacing: .02em; }
.switcher__icon { flex: 0 0 auto; font-size: var(--t-small); color: var(--ink-3); }

/* THE ONE SCROLLING REGION IN THE RAIL, and it must be able to reach every
   link. Measured on 11 Sep: 21 links and 8 group headers came to 1152px
   inside 515px, so 637px of the navigation was out of view at all times and
   the Inbox was never on screen. Regrouping to the design's five (plus
   Partner, which goes when the superadmin portal exists) and the two size
   changes below bring it inside the rail on a laptop.
   `PROJECT-LOG.md` §4 item 311. */
.nav { flex: 1 1 0; padding: 0 14px; display: flex; flex-direction: column;
       /* `min-height: 0` for §4 item 316's reason. It scrolls today only
          because `flex-basis: 0` and a rail of definite height happen to
          agree; stating it means the nav cannot stop scrolling the day
          something above it changes size. */
       gap: 1px; overflow-y: auto; min-height: 0;
       /* scroll-padding so a keyboard-focused link is never flush against
          the clipped edge of this region. */
       scroll-padding: 12px 0; }
/* A HEADING IS NOT A DESTINATION. It was 39px tall -- the same as a link
   somebody clicks -- for a 10px uppercase label. */
.nav__group { padding: 10px 10px 3px; font-size: var(--t-caps);
              font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
              color: #6E7683; }
.nav__group:first-child { padding-top: 2px; }
.nav__item {
  display: flex; align-items: center; gap: 9px; padding: 6px 11px;
  border-radius: var(--r); font-size: var(--t-body); font-weight: 500;
  color: var(--on-ink-2); background: transparent; text-decoration: none;
}
.nav__item:hover { background: var(--rail-lift); color: #FFFFFF;
                   text-decoration: none; }
.nav__item.is-on { background: var(--rail-on); color: #FFFFFF;
                   font-weight: 600; }
.nav__label { flex: 1 1 0; min-width: 0; }
.nav__count { flex: 0 0 auto; font-size: var(--t-small); padding: 1px 7px;
              border-radius: var(--r-pill); background: var(--rail-on);
              color: var(--on-ink); }
/* The one place a count is allowed to shout, because it is work nobody has
   picked up. */
.nav__count.is-alarm { background: var(--bad); color: #FFFFFF; }
/* WHY ELEVEN LINKS ARE NOT ON THE RAIL RIGHT NOW. Saying it is the difference
   between a navigation that adapts and one that has lost items. §4 item 312. */
.nav__note { margin: 10px 11px 0; font-size: var(--t-label); line-height: 1.5;
             color: var(--ink-4); }

/* PINNED, so the nav above it scrolls and the sign-out never does.
   `flex: 0 0 auto` states that explicitly rather than relying on the nav
   being the only `flex: 1` child. */
.rail__foot { flex: 0 0 auto; padding: 11px 20px 0;
              border-top: 1px solid var(--rail-line); margin: 10px 14px 0; }
.rail__who { display: block; font-size: var(--t-meta); font-weight: 600;
             color: #FFFFFF; text-decoration: none; }
.rail__who:hover { color: var(--accent-lit); text-decoration: none; }
.rail__role { font-size: var(--t-label); color: var(--ink-4); }
/* The sign-out button is the only button on the ink ground. */
.rail__foot .btn--ghost { background: transparent;
                          border-color: var(--rail-line);
                          color: var(--on-ink-2); }
.rail__foot .btn--ghost:hover { background: var(--rail-lift);
                                color: #FFFFFF; }

/* ── Scrolling ──────────────────────────────────────────────────────────────
 * "Natural scroll way, better scroll aesthetic", and the founder was looking
 * at a Windows default: a 17px trough with a raised thumb and an arrow button
 * at each end, drawn in system grey down the side of a dark rail. It is the
 * loudest thing on the screen and it is chrome, not content.
 *
 * TWO SYNTAXES, BOTH NEEDED AND NEITHER A FALLBACK FOR THE OTHER.
 * `scrollbar-width`/`scrollbar-color` is the standard and Firefox has only
 * that; `::-webkit-scrollbar` is what Chrome and Safari read, and a browser
 * that understands both prefers the standard. Declaring one alone leaves half
 * the browsers on the system default -- which is the state being fixed.
 *
 * OVERLAY, NOT INSET. `background: transparent` on the track means the thumb
 * floats over whatever is behind it, so the rail's ground runs to the edge and
 * a light pane keeps its own. The thumb is `currentColor` at low alpha rather
 * than a named grey, so one rule serves the ink rail and the paper panes and
 * there is no second colour to keep in step.
 */
* {
  scrollbar-width: thin;
  scrollbar-color: rgba(128, 138, 155, .38) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(128, 138, 155, .38);
  border-radius: 999px;
  /* The border is the gap: a transparent border with `background-clip:
     padding-box` insets the thumb without inventing a track to inset it into,
     so it reads as 6px of floating bar rather than 10px of filled channel. */
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: rgba(128, 138, 155, .62);
                                  background-clip: padding-box; }
/* THE ARROW BUTTONS GO. They are the single most dated part of a Windows
   scrollbar, nobody clicks them, and each one steals 17px from a 254px rail. */
::-webkit-scrollbar-button { display: none; height: 0; width: 0; }
::-webkit-scrollbar-corner { background: transparent; }

/* THE RAIL NEEDS ITS OWN, because a thumb tuned for grey-on-paper disappears
   on an ink ground -- the same alpha over #1B1F27 is nearly invisible. */
.rail *, .rail { scrollbar-color: rgba(190, 200, 216, .26) transparent; }
.rail ::-webkit-scrollbar-thumb, .rail::-webkit-scrollbar-thumb {
  background: rgba(190, 200, 216, .26); background-clip: padding-box; }
.rail ::-webkit-scrollbar-thumb:hover, .rail::-webkit-scrollbar-thumb:hover {
  background: rgba(190, 200, 216, .46); background-clip: padding-box; }

/* A SCROLL THAT ENDS WHERE THE BOX ENDS. Without `overscroll-behavior`,
   reaching the top of the thread hands the gesture to the page behind it and
   the whole console lurches -- which is most of what "should not be like
   this" is describing. `contain` stops the chain and leaves ordinary
   scrolling untouched; it is not `none`, because that would also disable the
   pull-to-refresh a touch device is entitled to. */
.nav, .content, .content--fill,
.inbox__list, .inbox__pane, .thread { overscroll-behavior: contain; }

/* Motion only where somebody asked for it -- `inbox.js` jumps the thread to
   the newest message on load, and that must be instant rather than a visible
   slide down a hundred bubbles. Smooth belongs on an anchor jump, so it is
   scoped to the honouring of `prefers-reduced-motion` and nothing else here
   opts in. */
@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; }
}

/* ── Main column ────────────────────────────────────────────────────────── */
.main { flex: 1 1 0; min-width: 0; background: var(--paper);
        display: flex; flex-direction: column; position: relative; }
/* The 3px accent stripe across the top of the main column is gone with the
   switcher's: the rail's own ground is what separates the shell now, and a
   coloured rule along an edge was the same motif lying down. §4 item 311. */
.main__accent { display: none; }
.chrome { flex: 0 0 var(--chrome-h); border-bottom: 1px solid var(--rule-2);
          display: flex; align-items: center; gap: 12px; padding: 0 22px; }
.chrome__client { font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.chrome__code { font-size: var(--t-label); color: var(--ink-3);
                letter-spacing: .02em; }
.chrome__spacer { flex: 1 1 0; }
.chrome__env { font-size: var(--t-caps); text-transform: uppercase;
               letter-spacing: .06em; color: var(--ink-3);
               border: 1px solid var(--rule); border-radius: var(--r-sm);
               padding: 2px 7px; }
.chrome__who { font-size: var(--t-meta); color: var(--ink-2); }
.content { flex: 1 1 0; overflow: auto; padding: 28px 26px 44px; }
/* A SCREEN THAT IS A PANE, NOT A PAGE -- the inbox and one thread. The column
   becomes flex so the pane can claim whatever is left under the page head
   without anybody measuring the page head. `min-height: 0` on the pane is the
   half people forget: a flex child defaults to `min-height: auto`, which is
   its CONTENT height, so a long thread would push the box past the viewport
   and take the composer with it -- the exact failure the fixed height was
   trying to prevent. `overflow: hidden` here, because the scrolling belongs
   to the list and the thread inside it. §4 item 312. */
.content--fill { display: flex; flex-direction: column; overflow: auto;
                 padding-bottom: 26px; }
.content--fill > * { flex: 0 0 auto; }
/* `overflow: auto` above and a real floor here, rather than `hidden` and
   `min-height: 0`. On a short window the pane would otherwise be squeezed to
   a few rows of thread with nothing able to scroll -- the page has to be the
   fallback, and when the pane fits, which is every ordinary window, no
   scrollbar appears at all. */
.content--fill .inbox { flex: 1 1 auto; height: auto; min-height: 340px; }

/* THE SCREEN'S OWN SCOPE CONTROLS -- which month, which financial year.
   `_period.html`. It is NOT the client picker: that is in the rail and there
   is exactly one of it. This bar is drawn only where the ROUTE defines a
   period or a year, so a screen that has neither draws nothing at all rather
   than an empty strip. §4 item 312. */
.scope { display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
         margin: 0 0 18px; }
.scope label { font-size: var(--t-label); font-weight: 600;
               letter-spacing: .04em; text-transform: uppercase;
               color: var(--ink-3); }
.scope select, .scope input { font: inherit; font-size: var(--t-small);
                              padding: 6px 9px; border: 1px solid var(--rule);
                              border-radius: var(--r); background: #FFFFFF;
                              color: var(--ink); }

/* ── Headings ───────────────────────────────────────────────────────────── */
.h1 { font-size: var(--t-h1); font-weight: 600; letter-spacing: -.025em;
      color: var(--ink); margin: 0; }
.h2 { font-size: var(--t-h2); font-weight: 600; letter-spacing: -.01em;
      color: var(--ink); margin: 0; }
.caps { font-size: var(--t-caps); font-weight: 600; letter-spacing: .02em;
        color: var(--ink-3); text-transform: none; }
.muted { color: var(--ink-3); }
.quiet { color: var(--ink-4); }
.lead { font-size: var(--t-lead); color: var(--ink-2); }
.page-head { display: flex; align-items: flex-start; gap: 14px;
             margin-bottom: 22px; flex-wrap: wrap; }
.page-head__sub { font-size: var(--t-meta); color: var(--ink-3);
                  margin-top: 4px;
                  /* A MEASURE. Eight screens open with a 190-270 character
                     paragraph and the content column is about 1180px, so each
                     ran as ONE line of roughly 190 characters -- two and a
                     half times any readable measure. This is a typography
                     fix and not an editorial one: the copy is the founder's
                     call, the line length is not. §4 item 312. */
                  max-width: 78ch; }

/* ── Panels and tiles ───────────────────────────────────────────────────── */
.panel { background: var(--paper); border: 1px solid var(--rule-2);
         border-radius: var(--r-lg); padding: 16px 18px; margin-bottom: 16px; }
.panel--fill { background: var(--subtle); border-color: transparent; }
.panel__head { display: flex; align-items: baseline; gap: 10px;
               margin-bottom: 12px; }

.tiles { display: grid; gap: 12px; margin-bottom: 20px;
         grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.tile { border: 1px solid var(--rule-2); border-radius: var(--r-lg);
        padding: 14px 16px; }
.tile__label { font-size: var(--t-caps); font-weight: 600; letter-spacing: .02em;
               color: var(--ink-3); }
.tile__value { font-size: var(--t-h1); font-weight: 600; letter-spacing: -.025em;
               color: var(--ink); margin-top: 6px; line-height: 1.15; }
.tile__value--big { font-size: var(--t-display); }
.tile__note { font-size: var(--t-label); color: var(--ink-3); margin-top: 4px; }
.tile.is-alarm .tile__value { color: var(--bad); }
.tile.is-good  .tile__value { color: var(--good-ink); }
/* A TILE THAT LINKS SOMEWHERE IS AN `<a>`, and the whole tile is the target
   rather than a "view" link inside it -- a 4px text target inside a 140px card
   is a control that looks clickable and is not. Inheriting the colour keeps
   the value black and the label grey; the underline would fight both. */
a.tile { text-decoration: none; color: inherit; display: block; }
a.tile:hover { border-color: var(--accent); text-decoration: none; }
a.tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Entity cards: a list drawn as one card per row ─────────────────────────
   The list → card redesign (`SUPERADMIN-AUDIT.md`, the founder's 2/10). One
   `.panel` per organisation or client, with a header (title + status pills +
   actions), a metrics strip, and any nested rows drawn flush. Reused by the
   organisation list, the client list and the profiles, so it lives here once
   rather than as inline styles a later screen forgets to match. */
.page-head__actions { margin-left: auto; display: flex; gap: 8px;
                      align-items: center; flex-wrap: wrap; }
.card-head { display: flex; align-items: flex-start; justify-content: space-between;
             gap: 12px 18px; flex-wrap: wrap; }
.card-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
              font-size: 1.05rem; font-weight: 600; color: var(--ink);
              line-height: 1.25; }
.card-title a { color: inherit; }
.card-meta { font-size: var(--t-meta); color: var(--ink-3); margin-top: 5px; }
.card-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.card-metrics { display: flex; gap: 26px; flex-wrap: wrap;
                margin-top: 14px; padding-top: 13px;
                border-top: 1px solid var(--rule-3); }
.card-metric__label { font-size: var(--t-caps); font-weight: 600;
                      letter-spacing: .02em; color: var(--ink-3); }
.card-metric__value { font-size: var(--t-body); color: var(--ink); margin-top: 3px; }
.card-metric__value .muted { font-weight: 400; }
/* A table nested inside a card: flush to the panel, header unshaded, and the
   last row's rule dropped so it does not double the panel's own edge. */
.card-table { margin-top: 14px; }
.card-table thead th { background: transparent; padding-top: 0; }
.card-table tbody tr:hover { background: transparent; }
.card-table tbody tr:last-child td,
.card-table tbody tr:last-child th { border-bottom: 0; padding-bottom: 0; }

/* ── Tables ─────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; border: 1px solid var(--rule-2);
              border-radius: var(--r-lg); }
table { width: 100%; border-collapse: collapse; font-size: var(--t-body); }
thead th { text-align: left; font-size: var(--t-caps); font-weight: 600;
           letter-spacing: .02em; color: var(--ink-3);
           background: var(--paper); border-bottom: 1px solid var(--rule-2);
           padding: 10px 12px; white-space: nowrap; }
tbody td { padding: 10px 12px; border-bottom: 1px solid var(--rule-3);
           vertical-align: top; }
/* A ROW HEADER IS NOT A COLUMN HEADER. Only `thead th` was ever styled, so a
   `<th>` used as a row label -- which is what it is for, and what the overview
   needs -- fell back to the browser default: centred, unpadded, and wrapping
   against a cell that had padding. It looked like a column that had lost its
   alignment. §4 item 312. */
tbody th { text-align: left; font-weight: 500; color: var(--ink-2);
           padding: 10px 12px; border-bottom: 1px solid var(--rule-3);
           vertical-align: top; }
tbody tr:last-child th { border-bottom: 0; }
/* A GROUP'S OWN ROW in a tree of groups and ledgers (the chart of accounts,
   the statements in Tally's shape, items 712-713): a quiet band, so the eye
   finds the group totals the way it does in Tally. */
tr.grouprow > td, tr.grouprow > th { background: var(--subtle); font-weight: 600; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--subtle); }
.num { text-align: right; white-space: nowrap; }
th.num { text-align: right; }
.neg { color: var(--bad); }
.pos { color: var(--good-ink); }
tr.total td { font-weight: 600; border-top: 1px solid var(--ink);
              background: var(--paper); }
tr.closing td { font-weight: 600; border-top: 3px double var(--ink); }
tr.is-alarm { background: var(--bad-wash); }
tr.is-alarm:hover { background: var(--bad-wash); }

/* ── Pills, chips, status ───────────────────────────────────────────────── */
.pill { display: inline-flex; align-items: center; gap: 5px;
        font-size: var(--t-small); font-weight: 500; padding: 2px 9px;
        border-radius: var(--r-pill); background: var(--subtle);
        color: var(--ink-3); white-space: nowrap; }
.pill--good { background: var(--good-wash); color: var(--good-ink); }
.pill--warn { background: var(--warn-wash); color: var(--warn); }
.pill--bad  { background: var(--bad-wash);  color: var(--bad); }
.pill--accent { background: var(--wash); color: var(--accent-ink); }

/* Severity is a RANK, not a colour: it orders a queue, and an order reads as
   a filled bar where a hue reads as a category. */
/* SEVERITY AS A RANK -- the design pack's own component, kept and RENAMED.
   `portal-design/ADAPTATION.md` §1: "severity is drawn as a rank (bars), not
   as a colour ... `.sev` in `ledgior.css`" -- and it pointed at a class that
   a later block in this same file redefined as coloured uppercase text. Same
   name, two components, and the text one wins on source order, so the bars
   were dead the day they were written and no template has ever used them.

   Nothing renders `.sev-rank` yet. It is kept rather than deleted because
   ADAPTATION says this is the design's intent and must not be lost; whether
   the queue moves from colour to rank is a decision for the founder, not a
   silent change to how every severity in the product reads.
   `PROJECT-LOG.md` §4 item 311. */
.sev-rank { display: inline-flex; gap: 2px; vertical-align: middle; }
.sev-rank i { width: 4px; height: 12px; border-radius: 1px;
              background: var(--rule); display: block; }
.sev-rank i.on { background: var(--ink-3); }
.sev-rank--critical i.on { background: var(--bad); }
/* The word beside the rank. Neutral, because the rank already carries the
   ordering -- only CRITICAL is coloured, and only because it is acted on. */
.sev-word { font-size: var(--t-small); color: var(--ink-3);
            margin-left: 7px; vertical-align: middle; }
.sev-word.is-critical { color: var(--bad); font-weight: 600; }

.dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%;
       background: var(--ink-4); margin-right: 6px; }
.dot--good { background: var(--good); }
.dot--warn { background: var(--warn); }
.dot--bad  { background: var(--bad); }

/* ── Controls ───────────────────────────────────────────────────────────── */
.btn { display: inline-flex; align-items: center; gap: 7px; height: 32px;
       white-space: nowrap; flex-shrink: 0;
       padding: 0 14px; border-radius: var(--r); font-size: var(--t-body);
       font-weight: 600; background: var(--subtle); color: var(--ink);
       border: 1px solid transparent; }
.btn:hover { background: var(--subtle-2); text-decoration: none; }
.btn--primary { background: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-ink); color: #fff; }
.btn--ghost { background: transparent; border-color: var(--rule-2);
              color: var(--ink-2); }
.btn--ghost:hover { background: var(--subtle); }
/* A reject is outlined, never filled: a filled danger control reads as a
   warning banner and gets clicked to make it go away. */
.btn--danger { background: transparent; border-color: var(--bad);
               color: var(--bad); }
.btn--danger:hover { background: var(--bad-wash); }
.btn:disabled, .btn[aria-disabled="true"] {
  background: transparent; border-color: var(--rule-2); color: var(--ink-4);
  cursor: not-allowed; }
.btn--sm { height: 26px; padding: 0 10px; font-size: var(--t-small); }

label { display: block; font-size: var(--t-label); font-weight: 500;
        color: var(--ink-3); margin-bottom: 5px; }
input, select, textarea {
  font: inherit; font-size: var(--t-body); width: 100%; height: 34px;
  padding: 0 10px; color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule); border-radius: var(--r);
}
/* A CONTROL IN A ROW SIZES TO ITS CONTENT, and the rule above is why it has
   to be said. `width: 100%` is right for a field stacked in a form and wrong
   for every horizontal control bar in this console -- and because it is an
   ELEMENT selector, a bar that styles `select` without mentioning `width`
   inherits it in silence. The inbox filter was the live instance: its
   `<select>` computed to 1134px, took a line of its own, pushed the Search
   button onto a third, and made a 40px bar 135px tall -- which on the one
   screen sized to the viewport came straight off the height of the thread.

   THIS IS THE THIRD TIME THAT RULE HAS LEAKED. §4 item 311 was
   `.filters input { min-width: 168px }` drawing a tick box 168 pixels wide;
   `.filters` had already reset `width` and reset the wrong property.
   `PROJECT-LOG.md` §4 item 312. */
.inbox-filter select, .inbox-filter input,
.scope select, .scope input,
.assign-strip select { width: auto; }
textarea { height: auto; padding: 8px 10px; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--wash); }
.field { margin-bottom: 12px; }
.field__hint { font-size: var(--t-label); color: var(--ink-3); margin-top: 5px; }
.stack { display: flex; flex-direction: column; gap: 10px; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
fieldset { border: 1px solid var(--rule-2); border-radius: var(--r-lg);
           padding: 14px 16px; margin: 0 0 16px; }
legend { font-size: var(--t-caps); font-weight: 600; letter-spacing: .02em;
         color: var(--ink-3); padding: 0 6px; }

/* ── Banners and notes ──────────────────────────────────────────────────── */
.banner { border-radius: var(--r-lg); padding: 12px 15px;
          font-size: var(--t-meta); margin-bottom: 16px; }
.banner--bad  { background: var(--bad-wash);  color: var(--bad); }
.banner--warn { background: var(--warn-wash); color: var(--warn); }
.banner--good { background: var(--good-wash); color: var(--good-ink); }
.banner--info { background: var(--wash); color: var(--accent-ink); }
.banner strong { font-weight: 600; }

/* The one emphasis device that is not a box. */
.note { border-left: 2px solid var(--rule); padding: 2px 0 2px 12px;
        color: var(--ink-3); font-size: var(--t-meta); margin: 10px 0; }
.note--accent { border-left-color: var(--accent); color: var(--ink-2); }

/* ── Empty states — four, and they must never look alike ────────────────── */
.empty { border: 1px dashed var(--rule); border-radius: var(--r-lg);
         padding: 30px 24px; text-align: center; color: var(--ink-3);
         font-size: var(--t-meta);
         /* A MEASURE, because the text is centred. Unbounded, an empty state
            on a per-tenant screen ran the full 1180px of the content column
            -- a single centred line about 150 characters wide, which is twice
            any readable measure and is most of what "unfinished" looks like
            on the thirteen screens that are nothing else. The box stays
            centred; inside a panel it simply fills. §4 item 312. */
         max-width: 62ch; margin-inline: auto; }
.panel .empty { max-width: none; }
.empty strong { display: block; color: var(--ink); font-size: var(--t-h2);
                font-weight: 600; margin-bottom: 6px; }
/* UNCONFIGURED is not EMPTY. This one is solid and loud on purpose: the two
   are the most expensive confusion in the console. */
.empty--unconfigured { border-style: solid; border-color: var(--bad);
                       background: var(--bad-wash); color: var(--bad); }
.empty--unconfigured strong { color: var(--bad); }

/* Something being read right now: motion and ink, never a fourth colour. */
.reading { position: relative; overflow: hidden; display: inline-block;
           min-width: 60px; height: 2px; background: var(--rule-3); }
.reading::after { content: ""; position: absolute; inset: 0 auto 0 0;
                  width: 30%; background: var(--accent);
                  animation: sweep 1.4s ease-in-out infinite; }

/* ── Utilities ──────────────────────────────────────────────────────────── */
.mono { font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.gstin { letter-spacing: .03em; text-transform: uppercase; }
.nowrap { white-space: nowrap; }
.mb-0 { margin-bottom: 0; }
.mt-16 { margin-top: 16px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.kv { display: grid; grid-template-columns: fit-content(min(190px, 40%)) minmax(0, 1fr); gap: 6px 16px;
      font-size: var(--t-meta); }
.kv dt { color: var(--ink-3); }
.kv dd { margin: 0; color: var(--ink); }

/* ── Filter chips ───────────────────────────────────────────────────────────
 * A row of scopes over one dataset: Everything, Breached, Critical, Assigned
 * to me. They are LINKS, not JavaScript — every scope is a URL, so an operator
 * can send a colleague the view they are looking at and the back button works.
 * The count beside them ("9 of 14") is rendered by the ROUTE, never here. */
.tabs { display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
        margin-bottom: 14px; }
.tabs a, .tabs button.tab { display: inline-flex; align-items: center; gap: 6px;
        height: 28px; padding: 0 12px; border-radius: var(--r-pill);
        font-size: var(--t-meta); font-weight: 500; color: var(--ink-2);
        background: transparent; border: 1px solid var(--rule-2); }
.tabs a:hover { background: var(--subtle); color: var(--ink);
                text-decoration: none; }
.tabs a.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }
.tabs__count { margin-left: auto; font-size: var(--t-meta); color: var(--ink-3); }

/* ── A proportion, drawn ────────────────────────────────────────────────────
 * An ageing bucket, a coverage figure, a spend against a cap. The width is an
 * inline style because it is DATA — the one place an inline style is right.
 * `--bar-fill` lets a caller mark an alarming proportion without a second
 * class per colour. */
.bar { height: 6px; border-radius: 3px; background: var(--rule-2);
       overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--bar-fill, var(--accent)); }
.bar--alarm { --bar-fill: var(--bad); }
.bar--good  { --bar-fill: var(--good); }
.bar-row { display: grid; grid-template-columns: 1fr 92px 44px; gap: 12px;
           align-items: center; font-size: var(--t-meta); padding: 7px 0;
           border-bottom: 1px solid var(--rule-3); }
.bar-row:last-child { border-bottom: 0; }

/* ── The gate ───────────────────────────────────────────────────────────────
 * A list of checks, each either clear or open, each naming what it measured.
 * The glyph carries the state as well as the colour, because a colour alone
 * is not readable to everyone and this list decides whether a return is filed.
 * `CLAUDE.md`: every check runs per head, never per total — so the rows are
 * per head and the screen does not sum them. */
.gate { display: flex; flex-direction: column; }
.gate__row { display: grid; grid-template-columns: 18px 1fr auto auto;
             gap: 12px; align-items: baseline; padding: 9px 0;
             border-bottom: 1px solid var(--rule-3); font-size: var(--t-meta); }
.gate__row:last-child { border-bottom: 0; }
.gate__mark { font-weight: 700; font-size: var(--t-small); }
.gate__row.is-clear .gate__mark { color: var(--good); }
.gate__row.is-open  .gate__mark { color: var(--bad); }
.gate__what { color: var(--ink); }
.gate__measure { color: var(--ink-3); }

/* ── Where a thing is in its own life ───────────────────────────────────────
 * Assembled -> reviewed -> filed. Three states and not two: we assemble, a
 * person reviews, a person files. Migration `0036`. */
.stepper { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
           font-size: var(--t-meta); }
.step { display: inline-flex; align-items: center; gap: 7px; color: var(--ink-4); }
.step__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--rule); }
.step.is-done { color: var(--ink-2); }
.step.is-done .step__dot { background: var(--good); }
.step.is-now { color: var(--ink); font-weight: 600; }
.step.is-now .step__dot { background: var(--accent);
                          box-shadow: 0 0 0 3px var(--wash); }
.step__arrow { color: var(--ink-4); }

/* ── Timeline ───────────────────────────────────────────────────────────────
 * Events that carry their own timestamp. Never assembled from `updated_at`
 * columns: a history invented from when a row last changed is a fabricated
 * history, and this panel is read as a record of what happened. */
.timeline { list-style: none; padding: 0; margin: 0; }
.timeline li { display: grid; grid-template-columns: 104px 1fr; gap: 14px;
               padding: 9px 0 9px 14px; font-size: var(--t-meta);
               border-left: 1px solid var(--rule-2); position: relative; }
.timeline li::before { content: ""; position: absolute; left: -3px; top: 15px;
               width: 5px; height: 5px; border-radius: 50%;
               background: var(--rule); }
.timeline li:first-child::before { background: var(--accent); }
.timeline time { color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* ── Evidence ───────────────────────────────────────────────────────────────
 * "What was considered" on an adjudication. Generated from what the screen
 * ACTUALLY rendered, so it cannot claim evidence nobody saw — a line whose
 * source did not render is drawn as absent, not omitted. */
.evidence { list-style: none; padding: 0; margin: 0; font-size: var(--t-meta); }
.evidence li { display: grid; grid-template-columns: 16px 1fr; gap: 10px;
               padding: 6px 0; color: var(--ink-2); }
.evidence li.is-absent { color: var(--ink-4); }
.evidence .ev__mark { color: var(--good); font-weight: 700; }
.evidence li.is-absent .ev__mark { color: var(--ink-4); font-weight: 400; }

/* ── A named answer ─────────────────────────────────────────────────────────
 * The adjudication choices. There is NO FREE-TEXT BOX: the rate of each answer
 * is the measurement of how good the engine is, and prose cannot be counted.
 * Each card carries the CONSEQUENCE, because that is what the operator is
 * actually choosing between. */
.choices { display: grid; gap: 10px; }
.choice { display: block; border: 1px solid var(--rule-2); border-radius: var(--r-lg);
          padding: 12px 14px; cursor: pointer; }
.choice:hover { border-color: var(--rule); background: var(--subtle); }
.choice input { width: auto; height: auto; margin-right: 8px; }
.choice__what { font-size: var(--t-body); font-weight: 600; color: var(--ink); }
.choice__then { display: block; font-size: var(--t-meta); color: var(--ink-3);
                margin-top: 4px; }
.choice:has(input:checked) { border-color: var(--accent); background: var(--wash); }

/* ── A document, in a list ──────────────────────────────────────────────────
 * Photographs are the primary input and they are bad. The thumbnail is a
 * fixed box so a skewed phone photo cannot set the row height. */
.thumb { width: 42px; height: 52px; border-radius: var(--r-sm);
         background: var(--fill); border: 1px solid var(--rule-2);
         object-fit: cover; display: block; }

/* ── A page with an aside ───────────────────────────────────────────────────
 * The adjudication screen and the client overview: evidence on the left, the
 * decision on the right, and the decision does not scroll away. */
.split { display: grid; grid-template-columns: minmax(0, 1fr) 384px; gap: 20px;
         align-items: start; }
.split > aside { position: sticky; top: 0; }
@media (max-width: 1180px) { .split { grid-template-columns: 1fr; }
                             .split > aside { position: static; } }

/* ── The client portal ──────────────────────────────────────────────────────
 * A HORIZONTAL NAV, not the console's rail. The design draws it that way and
 * it is right: a rail is for somebody who lives in a tool all day, and this
 * product's whole thesis is that a client never has to come here. Roomier
 * type and more air than the console for the same reason — an operator reads
 * this all day and a proprietor reads it twice a month.
 */
.app--portal { flex-direction: column; }
.phead { flex: 0 0 auto; display: flex; align-items: center; gap: 16px;
         padding: 18px 26px 14px; border-bottom: 1px solid var(--rule-3); }
.phead__brand { display: flex; align-items: center; gap: 9px; }
.phead__mark { height: 18px; width: auto; display: block; }
.phead__word { font-size: 18px; font-weight: 600; letter-spacing: -.036em; }
.phead__who { padding-left: 16px; border-left: 1px solid var(--rule-2); }
.phead__client { font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.phead__sub { font-size: var(--t-label); color: var(--ink-3); margin-top: 2px; }

.topnav { flex: 0 0 auto; display: flex; gap: 2px; flex-wrap: wrap;
          padding: 0 20px; border-bottom: 1px solid var(--rule-2); }
.topnav__item { display: inline-flex; align-items: center; gap: 7px;
                padding: 11px 12px 10px; font-size: var(--t-body);
                font-weight: 500; color: var(--ink-3);
                border-bottom: 2px solid transparent; margin-bottom: -1px; }
.topnav__item:hover { color: var(--ink); text-decoration: none; }
.topnav__item.is-on { color: var(--ink); font-weight: 600;
                      border-bottom-color: var(--accent); }
/* The one badge a client should ever see. It is a COUNT OF QUESTIONS, and it
   is the only thing on this shell drawn in the alarm colour — everything else
   here is theirs and settled. */
.topnav__badge { font-size: var(--t-small); font-weight: 600; padding: 1px 7px;
                 border-radius: var(--r-pill); background: var(--bad-wash);
                 color: var(--bad); }

.content--portal { padding: 26px 26px 8px; font-size: var(--t-lead); }

/* THE PORTAL READS BIGGER THAN THE CONSOLE, on purpose. An operator is in the
 * console for seven hours and wants density; a proprietor opens this twice a
 * month, often on a phone, usually because something needs them. Everything
 * below is the same COMPONENT as the console's — a tile is a tile — with more
 * air and a size up, so there is one design system and not two. */
.content--portal .h1 { font-size: 26px; }
.content--portal .tile__value { font-size: 26px; }
.content--portal .tile { padding: 16px 18px; }
.content--portal .panel { padding: 20px 22px; }
.content--portal table { font-size: var(--t-body); }
.content--portal td, .content--portal th { padding: 11px 14px; }

/* The one big sentence a screen is about. The design opens Home and Needs-you
 * with a statement rather than a heading, because the answer to "do I need to
 * do anything" should be readable before anything else is. */
.p-hero { font-size: 24px; font-weight: 600; letter-spacing: -.02em;
          line-height: 1.28; color: var(--ink); margin: 0 0 10px;
          max-width: 34ch; }
.p-hero--calm { color: var(--good-ink); }
.p-said { font-size: var(--t-lead); color: var(--ink-2); max-width: 62ch;
          margin: 0 0 18px; }

/* A ROW LIST, not a table. The client screens list suppliers, documents,
 * invoices and packs — things with a name, a note and one figure — and a
 * table's column heads say nothing a person needs here. It wraps on a phone;
 * a table does not. */
.p-list { border-top: 1px solid var(--rule-2); }
.p-row { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
         padding: 13px 2px; border-bottom: 1px solid var(--rule-3); }
.p-row__what { flex: 1 1 16ch; min-width: 0; }
.p-row__name { font-weight: 600; color: var(--ink); }
.p-row__note { font-size: var(--t-meta); color: var(--ink-3); margin-top: 2px; }
.p-row__figure { flex: 0 0 auto; font-variant-numeric: tabular-nums;
                 font-weight: 600; color: var(--ink); }
.p-row__state { flex: 0 0 auto; font-size: var(--t-meta); color: var(--ink-3);
                min-width: 12ch; text-align: right; }

/* The dated run of the month. Not a timeline — these have not happened yet,
 * and drawing a plan as history is a small lie that reads as a big one. */
.p-dates { list-style: none; margin: 0; padding: 0; }
.p-dates li { display: grid; grid-template-columns: 62px 1fr; gap: 14px;
              padding: 11px 0; border-bottom: 1px solid var(--rule-3);
              font-size: var(--t-meta); }
.p-dates b { font-size: var(--t-lead); color: var(--ink); font-weight: 600; }
.p-dates span { color: var(--ink-3); }

/* Two named answers and no free-text box — the same rule as the operator's
 * adjudication screen, for the same reason: the RATE of each answer is the
 * measurement, and prose cannot be counted. */
.p-answers { display: grid; gap: 12px; grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .p-answers { grid-template-columns: 1fr; } }
.p-answer { display: block; border: 1px solid var(--rule); border-radius: var(--r-lg);
            padding: 15px 17px; background: var(--paper); text-align: left; }
.p-answer__what { font-size: var(--t-lead); font-weight: 600; color: var(--ink);
                  display: block; }
.p-answer__then { display: block; font-size: var(--t-meta); color: var(--ink-3);
                  margin-top: 5px; }
.pfoot { flex: 0 0 auto; padding: 18px 26px 22px; margin-top: auto;
         border-top: 1px solid var(--rule-3); font-size: var(--t-meta);
         color: var(--ink-3); display: flex; flex-direction: column; gap: 4px; }

@media (max-width: 720px) {
  .phead { flex-wrap: wrap; }
  .phead__who { padding-left: 0; border-left: 0; }
  .topnav { padding: 0 12px; }
}

/* ── Sign in ────────────────────────────────────────────────────────────────
 * NO RAIL. A sign-in screen carrying the app's navigation implies a session
 * that does not exist, and the rail's client switcher is meaningless before
 * anyone has authenticated. */
.gate-page { min-height: 100vh; display: flex; align-items: center;
             justify-content: center; padding: var(--desk-pad); }
.gate-card { width: 100%; max-width: 392px; background: var(--paper);
             border: 1px solid var(--rule); border-radius: var(--r-xl);
             box-shadow: var(--lift); padding: 30px 30px 26px; }
.gate-card__brand { display: flex; align-items: center; gap: 10px;
                    margin-bottom: 22px; }
.gate-card__brand img { height: 19px; width: auto; }
.gate-card__word { font-size: 20px; font-weight: 600; letter-spacing: -.036em; }
.gate-foot { margin-top: 20px; padding-top: 16px;
             border-top: 1px solid var(--rule-3); font-size: var(--t-label);
             color: var(--ink-3); display: flex; flex-direction: column; gap: 6px; }

pre { margin: 0; padding: 11px; background: var(--subtle);
      border-radius: var(--r); overflow-x: auto; font-size: var(--t-small);
      font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

@media (max-width: 1024px) {
  .desk { padding: 0; }
  .app { border-radius: 0; border: 0; min-height: 100vh; }
  .rail { flex-basis: 210px; }
  .kv { grid-template-columns: 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * COMPATIBILITY — the class vocabulary the twenty-one existing console screens
 * already use.
 *
 * WHY THIS BLOCK EXISTS AND WHEN IT GOES. The new design lands on screens that
 * are wired to real data and working today. Re-skinning all twenty-one in one
 * change would mean twenty-one chances to break a figure an operator reads on
 * the 20th, so the brand arrives first and the screens are re-drawn one at a
 * time against the classes above. Every rule here maps an OLD name onto a NEW
 * token -- none of them invents a colour.
 *
 * The list was DERIVED by scanning `app/templates/*.html` for `class="..."`,
 * not remembered: a hand-written compatibility list is a guard that lists what
 * it guards. When a screen is re-drawn, its old classes leave with it, and
 * this block shrinks. It is finished when it is empty.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* Controls. The old screens write bare <button> and <button class="primary">. */
.content button:not(.btn) {
  display: inline-flex; align-items: center; gap: 7px; height: 32px;
  padding: 0 14px; border-radius: var(--r); font-size: var(--t-body);
  font-weight: 600; background: var(--subtle); color: var(--ink);
  border: 1px solid transparent;
}
.content button:not(.btn):hover { background: var(--subtle-2); }
.content button.primary { background: var(--accent); color: #fff; }
.content button.primary:hover { background: var(--accent-ink); }
.content button:disabled { background: transparent; border-color: var(--rule-2);
                           color: var(--ink-4); cursor: not-allowed; }

.err { background: var(--bad-wash); color: var(--bad); border-radius: var(--r-lg);
       padding: 12px 15px; font-size: var(--t-meta); margin-bottom: 16px; }

/* Stat strip -> the design's tiles. `.n` is the figure, `.l` the label. */
.stats { display: grid; gap: 12px; margin-bottom: 20px;
         grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.stat { border: 1px solid var(--rule-2); border-radius: var(--r-lg);
        padding: 14px 16px; }
.stat .n { display: block; font-size: var(--t-h1); font-weight: 600;
           letter-spacing: -.025em; color: var(--ink); }
.stat .l { display: block; font-size: var(--t-caps); font-weight: 600;
           letter-spacing: .02em; color: var(--ink-3); margin-top: 4px; }
.stat.alarm .n { color: var(--bad); }

/* Chips and severity. Severity is a WORD with weight, never a colour alone. */
.tag { display: inline-flex; align-items: center; font-size: var(--t-small);
       font-weight: 500; padding: 2px 9px; border-radius: var(--r-pill);
       background: var(--subtle); color: var(--ink-3); white-space: nowrap; }
.sev { font-size: var(--t-caps); font-weight: 600; letter-spacing: .02em; }
.sev.CRITICAL { color: var(--bad); }
.sev.HIGH     { color: var(--warn); }
.sev.MEDIUM   { color: var(--ink-2); }
.sev.LOW      { color: var(--ink-3); }
.pill.good { background: var(--good-wash); color: var(--good-ink); }

/* Tables the old screens build by hand. */
.totals td { font-weight: 600; border-top: 1px solid var(--ink); }
/* A WHOLE ROW TINTED PINK IS THE LOUDEST THING ON THE SCREEN, and on a queue
   where a fifth of the rows are breached it is most of the screen. The row
   already SAYS "overdue" in the SLA cell, in red, which is the fact somebody
   acts on; the tint repeated it across nine columns. A quiet ground and one
   red word reads as a product, and it keeps the colour meaning something.
   `PROJECT-LOG.md` §4 item 311. */
tbody tr.breached, tr.breached { background: var(--subtle); }
tbody tr.breached:hover { background: var(--fill); }
td.acct, td.party { color: var(--ink); }
td.amt { text-align: right; white-space: nowrap; }

/* Layout helpers. */
.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.grid { display: grid; gap: 12px; }
.inline { display: inline-flex; align-items: center; gap: 8px; }
.scroll { overflow-x: auto; }
.filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
           margin-bottom: 18px; }
.filters label { margin-bottom: 0; white-space: nowrap; }
/* A control in a filter bar is sized by its CONTENT, not by the row. The base
   rule is `width: 100%` because a form field in a stacked form should fill its
   column -- inherited here it made the client picker a full-width bar, which
   reads as the subject of the page rather than as a control on it. */
/* NOT `.filters input`, WHICH INCLUDES THE TICK BOXES. `min-width: 168px` was
   landing on every `input[type=checkbox]` in a filter bar, so the box rendered
   **168 pixels wide** with its label stranded that far to the right -- on
   `/admin/`, the screen an operator opens first. `label.check input` reset
   `width` and not `min-width`, so it lost. Name the types that are actually
   text fields. `PROJECT-LOG.md` §4 item 311. */
.filters select,
.filters input:not([type=checkbox]):not([type=radio]):not([type=submit]) {
  width: auto; min-width: 168px;
}
.filters input[type=checkbox], .filters input[type=radio] {
  width: auto; min-width: 0; flex: 0 0 auto; margin: 0;
}
.filters .btn, .filters button { flex: 0 0 auto; }
.pager { display: flex; gap: 8px; align-items: center; margin-top: 14px;
         font-size: var(--t-meta); color: var(--ink-3); }
label.check { display: inline-flex; align-items: center; gap: 6px;
              white-space: nowrap; margin-bottom: 0; font-weight: 500; }
label.check input { width: auto; min-width: 0; height: auto; flex: 0 0 auto; }
/* Was a 2px accent rule down the left. Same motif, third instance -- a
   filled block says "aside" without the stripe. */
.callout { background: var(--subtle); border-radius: var(--r);
           padding: 9px 12px; color: var(--ink-2);
           font-size: var(--t-meta); margin: 10px 0; }
.panel h2 { font-size: var(--t-caps); font-weight: 600; letter-spacing: .02em;
            color: var(--ink-3); margin: 0 0 12px; }
h1 { font-size: var(--t-h1); font-weight: 600; letter-spacing: -.025em;
     margin: 0 0 4px; }
h2 { font-size: var(--t-h2); font-weight: 600; letter-spacing: -.01em;
     margin: 0 0 10px; }
h3 { font-size: var(--t-lead); font-weight: 600; margin: 0 0 8px; }
p  { margin: 0 0 10px; }

/* ==========================================================================
   THE INBOX — conversations, as a person reads them
   `PROJECT-LOG.md` §4 item 275 and §7.11.

   TWO PANES ON A DESK, ONE COLUMN ON A PHONE. The list is the work queue and
   the thread is the work; an operator moves between them all day, so they are
   side by side rather than two page loads.

   NO COLOUR IS SPENT ON DECORATION HERE. The three facts colour carries in
   this console are good / warning / bad, and in a thread they mean exactly
   one thing each: a message that reached the client, a window about to close,
   a send that failed. A bubble tinted for prettiness would spend the only
   signal the screen has.
   ========================================================================== */

.inbox {
  display: grid;
  grid-template-columns: minmax(240px, 320px) 1fr;
  gap: 0;
  border: 1px solid var(--rule);
  border-radius: var(--r-lg, 14px);
  overflow: hidden;
  background: var(--paper);
  /* The pane scrolls, not the page: an operator reading a long thread must
     not lose the composer off the bottom of the window. */
  height: calc(100vh - 190px);
  min-height: 420px;
}
@media (max-width: 860px) {
  .inbox { grid-template-columns: 1fr; height: auto; min-height: 0; }
  /* ONE COLUMN MEANS THE PAGE SCROLLS, NOT THE PANES. Stacked, the list and
     the thread are each full width and as tall as their content, so holding
     the column to the viewport would hide the thread below the list with no
     way to reach it. */
  .content--fill { display: block; overflow: auto; }
  .content--fill .inbox { min-height: 0; }
}

/* `min-height: 0` ON BOTH PANES, AND IT IS THE WHOLE SCROLL BUG.
   A grid child and a flex child both default to `min-height: auto`, which is
   their CONTENT height -- so a pane holding a long thread GROWS instead of
   scrolling, `overflow-y: auto` never has anything to do, and the overflow
   goes to the page. The founder's report was "cannot scroll up chat": the
   newest message was visible because the PAGE had scrolled to the bottom of a
   very tall box, and the history above it sat off the top of the window with
   no scrollbar of its own to bring it back.

   `inbox.js` had been right the whole time -- it sets `thread.scrollTop =
   thread.scrollHeight` on load and re-pins on every new message -- and both
   lines were no-ops, because `scrollHeight` equals `clientHeight` on an
   element that grew to fit its content. A CSS default made working JavaScript
   do nothing, silently. `PROJECT-LOG.md` §4 item 316. */
.inbox__list {
  border-right: 1px solid var(--rule-2);
  overflow-y: auto; min-height: 0;
  background: var(--subtle);
}
.inbox__pane { display: flex; flex-direction: column;
               min-width: 0; min-height: 0; }

/* --- finding one conversation among a firm's hundred ------------------
   §4 item 278. It sits ABOVE the list rather than inside it: `#convo-list`
   is replaced whenever a message arrives, and a search box in there would
   lose what somebody was typing every time a client wrote in. */
.inbox-filter {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 12px;
}
.inbox-filter [hidden] { display: none; }
.inbox-filter input[type="search"] {
  flex: 1 1 220px; min-width: 0; font: inherit;
  font-size: var(--t-body); padding: 8px 12px; color: var(--ink);
  border: 1px solid var(--rule); border-radius: 999px; background: var(--paper);
}
.inbox-filter input[type="search"]:focus-visible { border-color: var(--accent); }
.inbox-filter select {
  font: inherit; font-size: var(--t-small); padding: 7px 10px;
  border: 1px solid var(--rule); border-radius: 999px;
  background: var(--paper); color: var(--ink);
}
.inbox-filter__chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--t-small); color: var(--ink-2);
  padding: 6px 12px; border: 1px solid var(--rule); border-radius: 999px;
  background: var(--paper); cursor: pointer; white-space: nowrap;
}
.inbox-filter__chip:has(input:checked) {
  border-color: var(--accent); color: var(--accent);
}

/* --- one conversation in the list ------------------------------------- */
.convo {
  display: block;
  padding: 11px 14px;
  border-bottom: 1px solid var(--rule-3);
  color: inherit;
  text-decoration: none;
}
.convo:hover { background: var(--paper); text-decoration: none; }
.convo.is-on { background: var(--paper); }
.convo.is-on .convo__who { color: var(--accent-ink); }
.convo__top { display: flex; align-items: baseline; gap: 8px; }
.convo__who {
  font-weight: 600; font-size: var(--t-body); color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.convo__when {
  margin-left: auto; font-size: var(--t-tiny); color: var(--ink-4);
  white-space: nowrap;
}
.convo__last {
  font-size: var(--t-small); color: var(--ink-3); margin-top: 2px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* THEY SPOKE LAST. Not "unread" -- nothing here records who has looked, and a
   badge that claimed to would be a column nothing writes. */
.convo__theirs {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); margin-right: 6px; vertical-align: middle;
}

/* --- the thread -------------------------------------------------------- */
/* NO RULED-PAPER TEXTURE. This carried a repeating 28px `linear-gradient`
   behind the bubbles -- decoration, with nothing in the file saying what it
   was for, and it is the shape the founder keeps naming on sight. It cost
   more than taste: with no conversation open the pane is empty, so the rules
   were all anybody saw, and a stack of faint horizontal lines across a blank
   panel reads as a table that failed to load. The bubbles carry their own
   grounds -- inbound `--fill`, outbound `--wash`, failed `--bad-wash` -- and
   a texture underneath is one more thing for them to fight.
   `PROJECT-LOG.md` §4 item 312. */
.thread {
  /* `min-height: 0` for the reason above: this is the element that scrolls,
     and without it it is the element that grows. */
  flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 18px 20px;
  background: var(--paper);
}
.thread__day {
  text-align: center; margin: 16px 0 12px;
  font-size: var(--t-tiny); color: var(--ink-4);
  text-transform: uppercase; letter-spacing: .06em;
}
.thread__day span {
  background: var(--fill); padding: 3px 10px; border-radius: 999px;
}

.msg { display: flex; margin: 3px 0; }
.msg--in  { justify-content: flex-start; }
.msg--out { justify-content: flex-end; }

.bubble {
  max-width: min(560px, 78%);
  padding: 8px 11px 6px;
  border-radius: 12px;
  font-size: var(--t-body);
  line-height: 1.45;
  /* A long unbroken string -- a URL, a GSTIN -- must stay inside the bubble
     rather than widening it, so this belongs on the box. */
  overflow-wrap: anywhere;
}

/* A MESSAGE IS SOMEBODY'S OWN WORDS: wrap them, never truncate, and keep the
   newlines they typed. `white-space: pre-wrap` lived on `.bubble` and had to
   move here -- that element also holds the TEMPLATE's indentation and the
   blank lines between its Jinja blocks, and pre-wrap draws all of it, so
   every bubble in the product was ~190px tall with its text pushed to the
   bottom-right by eight newlines and twelve spaces of leading indent.
   `PROJECT-LOG.md` §4 item 311. */
.bubble__body { white-space: pre-wrap; }
.msg--in  .bubble { background: var(--fill); border-top-left-radius: 4px; }
.msg--out .bubble {
  background: var(--wash); border: 1px solid var(--accent-3);
  border-top-right-radius: 4px;
}
.bubble--failed { background: var(--bad-wash); border-color: var(--bad); }
.bubble--card   { background: var(--paper); border: 1px dashed var(--accent-3); }

.bubble__meta {
  display: flex; align-items: center; gap: 6px; justify-content: flex-end;
  margin-top: 4px; font-size: var(--t-tiny); color: var(--ink-4);
}
.bubble__state { font-weight: 600; }
.bubble__state.is-good { color: var(--good-ink); }
.bubble__state.is-bad  { color: var(--bad); }
.bubble__kind {
  display: inline-block; font-size: var(--t-tiny); color: var(--ink-3);
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: 999px; padding: 1px 8px; margin-bottom: 4px;
}
.bubble__doc { display: block; margin-top: 5px; font-size: var(--t-small); }

/* --- the composer, and the window it depends on ------------------------ */
.composer { border-top: 1px solid var(--rule-2); padding: 12px 16px;
            background: var(--paper); }
.composer__row { display: flex; gap: 10px; align-items: flex-end; }
.composer textarea {
  flex: 1 1 auto; min-height: 44px; max-height: 160px; resize: vertical;
  font: inherit; font-size: var(--t-body); padding: 10px 12px;
  border: 1px solid var(--rule); border-radius: 10px; color: var(--ink);
}
.composer textarea:focus-visible { border-color: var(--accent); }
.composer textarea[disabled], .composer button[disabled] { opacity: .55; }

/* WHERE A SEND SAYS WHAT HAPPENED, WITHOUT THE PAGE GOING AWAY. §4 item 277.
   The banner at the top of the screen is the no-JavaScript answer, carried on
   the 303; this is the same words beside the box somebody is still typing in,
   which is where a person is looking. */
.composer__note { margin-top: 6px; font-size: var(--t-small);
                  color: var(--ink-3); }
.composer__note.is-bad { color: var(--bad); }

/* THE WINDOW IS THE ONE THING WHATSAPP ITSELF DOES NOT SHOW, and it is the
   whole reason an operator needs this screen rather than a phone. */
.window-strip {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 16px; font-size: var(--t-small);
  border-top: 1px solid var(--rule-2);
}
.window-strip.is-open   { background: var(--good-wash); color: var(--good-ink); }
.window-strip.is-closed { background: var(--warn-wash); color: var(--warn); }
.window-strip b { font-weight: 600; }

.inbox__head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; border-bottom: 1px solid var(--rule-2);
  background: var(--paper);
}
.inbox__head h2 { font-size: var(--t-h2); margin: 0; }
.inbox__head .quiet { font-size: var(--t-small); }

/* The live dot. `LEDGIOR-DESIGN-SPEC.md` §1.3: "connection state must be
   visible ... live / reconnecting / offline". An operator who does not know
   the page has gone quiet will believe an empty thread. */
.live-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--ink-4); vertical-align: middle;
}
.live-dot--live { background: var(--good); }
.live-dot--down { background: var(--warn); }
/* NO PULSE ANIMATION. A dot that moves for ever is a dot people stop seeing,
   and `prefers-reduced-motion` would have to switch it off anyway. */

/* The photograph a client actually sent. Bounded, because a bill shot on a
   modern phone is 4000px wide and would otherwise be the whole screen. */
.bubble__img {
  display: block; max-width: 100%; max-height: 320px;
  border-radius: 8px; margin-bottom: 6px; background: var(--fill);
}

/* Who is answering. A strip rather than a modal: assigning a conversation is
   a small, frequent, reversible act, and a dialog for it is a dialog people
   learn to dismiss. */
.assign-strip {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 16px; border-bottom: 1px solid var(--rule-3);
  background: var(--subtle); font-size: var(--t-small);
}
.assign-strip select { font: inherit; font-size: var(--t-small); }

/* ══════════════════════════════════════════════════════════════════════════
 * CONSOLE v2 — 24 Sep 2026, the founder's "1/10, make it MNC level".
 *
 * ONE LAYER, LAST IN THE FILE, so it wins on source order without touching
 * the rules above. The shell rules are scoped to `body.console`; the
 * component rules (type, cards, forms, tables, buttons, banners) are shared
 * on purpose, so the client portal gets the same finish.
 *
 *   - type up a step: 13px body and 11px labels read as a spreadsheet, not a
 *     product. 14px body, 13px labels, real 17px section headings;
 *   - a grey canvas with white cards, so a panel is a thing and not a line;
 *   - the sidebar collapses to icons (a cookie set by `/admin/ui/sidebar`,
 *     no script: the shells run none), its groups
 *     fold, and it becomes a drawer under 960px;
 *   - a top bar with a breadcrumb and an account menu, replacing the rail
 *     foot and the duplicated client name.
 * ══════════════════════════════════════════════════════════════════════════ */
:root {
  --t-body: 14px;  --t-meta: 13px;  --t-small: 12.5px; --t-label: 13px;
  --t-caps: 12px;  --t-h1: 24px;    --t-h2: 17px;      --t-lead: 15px;
  --canvas: #F5F6F8;
  --line: #E4E7EC;       /* a card edge */
  --line-2: #D0D5DD;     /* a field edge */
  --r: 8px; --r-lg: 12px;
  --shadow-card: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow-pop: 0 12px 32px -8px rgba(16, 24, 40, .22), 0 2px 6px rgba(16, 24, 40, .06);
  --side-w: 256px; --side-w-min: 68px; --top-h: 60px;
}

.ico { width: 18px; height: 18px; flex: 0 0 auto; fill: none; stroke: currentColor;
       stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/* ── Shell ─────────────────────────────────────────────────────────────── */
body.console { background: var(--canvas); }
body.console .shell { display: flex; min-height: 100vh; }
body.console .sidebar {
  position: sticky; top: 0; height: 100vh; flex: 0 0 var(--side-w);
  width: var(--side-w); background: var(--rail-bg); color: var(--on-ink);
  display: flex; flex-direction: column; overflow: hidden;
  transition: width .18s ease, flex-basis .18s ease; z-index: 30;
}
.sidebar__brand { display: flex; align-items: center; justify-content: space-between;
                  gap: 8px; padding: 18px 14px 14px 20px; }
.sidebar__lockup { display: flex; align-items: center; gap: 10px; color: #fff; min-width: 0; }
.sidebar__lockup:hover { text-decoration: none; color: #fff; }
.sidebar__mark { height: 20px; width: auto; display: block; }
.sidebar__word { font-size: 19px; font-weight: 600; letter-spacing: -.03em; white-space: nowrap; }
.sidebar__toggle, .topbar__menu {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--r); color: var(--ink-4); flex: 0 0 auto; }
.sidebar__toggle:hover { background: var(--rail-lift); color: #fff; }

body.console .switcher { margin: 0 12px 10px; width: auto; }
.switcher__face { gap: 10px; padding: 9px 10px; }
.switcher__avatar { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--rail-on); color: #fff; font-weight: 700; font-size: 13px; }
.switcher.is-set .switcher__avatar { background: var(--accent); }
.switcher__name { font-size: 13.5px; }
.switcher__code { font-size: 12px; }

.sidenav { flex: 1 1 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
           padding: 4px 10px 18px; scrollbar-width: thin;
           scrollbar-color: var(--rail-on) transparent; }
.sidenav::-webkit-scrollbar { width: 8px; }
.sidenav::-webkit-scrollbar-thumb { background: var(--rail-on); border-radius: 8px; }
.sidenav__group { margin-top: 6px; }
.sidenav__head { list-style: none; display: flex; align-items: center; justify-content: space-between;
  cursor: pointer; padding: 8px 10px 6px; border-radius: var(--r);
  font-size: 11.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-4); user-select: none; }
.sidenav__head::-webkit-details-marker { display: none; }
.sidenav__head:hover { color: var(--on-ink); }
.sidenav__chev { width: 14px; height: 14px; transition: transform .15s ease; }
.sidenav__group:not([open]) .sidenav__chev { transform: rotate(-90deg); }
.sidenav__item { display: flex; align-items: center; gap: 11px; height: 36px;
  padding: 0 10px; border-radius: var(--r); color: var(--on-ink);
  font-size: 13.5px; font-weight: 500; white-space: nowrap; }
.sidenav__item .ico { color: var(--ink-4); }
.sidenav__item:hover { background: var(--rail-lift); color: #fff; text-decoration: none; }
.sidenav__item:hover .ico { color: var(--on-ink); }
.sidenav__item.is-on { background: var(--rail-on); color: #fff; }
.sidenav__item.is-on .ico { color: var(--accent-lit); }
.sidenav__label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sidenav__count { flex: 0 0 auto; min-width: 22px; height: 20px; padding: 0 7px;
  border-radius: 10px; font-size: 11.5px; font-weight: 600; line-height: 20px; text-align: center;
  background: var(--rail-on); color: var(--on-ink); }
.sidenav__count.is-alarm { background: var(--bad); color: #fff; }
.sidenav__note { margin: 10px 10px 4px; padding: 10px 12px; border-radius: var(--r);
  border: 1px dashed var(--rail-line); font-size: 12.5px; line-height: 1.5; color: var(--ink-4); }

/* Collapsed: icons only, a tooltip from `title`, every item visible. */
html.rail-collapsed body.console .sidebar { flex-basis: var(--side-w-min); width: var(--side-w-min); }
html.rail-collapsed .sidebar__lockup { display: none; }
html.rail-collapsed .sidebar__brand { justify-content: center; padding: 16px 0 12px; }
html.rail-collapsed .switcher__body, html.rail-collapsed .switcher__verb,
html.rail-collapsed .switcher .picker { display: none; }
html.rail-collapsed .switcher__face { justify-content: center; padding: 8px 0; }
html.rail-collapsed .sidenav { padding: 4px 12px 18px; }
html.rail-collapsed .sidenav__head { font-size: 0; padding: 0; height: 1px; margin: 10px 4px 6px;
  background: var(--rail-line); pointer-events: none; }
html.rail-collapsed .sidenav__head .ico { display: none; }
html.rail-collapsed .sidenav__group:not([open]) > .sidenav__item { display: flex; }
html.rail-collapsed .sidenav__item { justify-content: center; padding: 0; position: relative; }
html.rail-collapsed .sidenav__label, html.rail-collapsed .sidenav__note { display: none; }
html.rail-collapsed .sidenav__count { position: absolute; top: 1px; right: 0; min-width: 16px;
  height: 16px; line-height: 16px; padding: 0 4px; font-size: 10px; }

/* ── Top bar ───────────────────────────────────────────────────────────── */
body.console .main { background: var(--canvas); min-height: 100vh; }
.topbar { position: sticky; top: 0; z-index: 20; height: var(--top-h); flex: 0 0 var(--top-h);
  display: flex; align-items: center; gap: 12px; padding: 0 28px;
  background: rgba(255, 255, 255, .92); backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--line); }
.topbar__menu { display: none; color: var(--ink-2); }
.topbar__menu:hover { background: var(--subtle); }
.crumbs { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 14px; }
.crumbs__group { color: var(--ink-3); white-space: nowrap; }
.crumbs__sep { width: 14px; height: 14px; color: var(--ink-4); }
.crumbs__page { color: var(--ink); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crumbs a { color: var(--ink-3); }
.topbar__spacer { flex: 1 1 auto; }
.topbar__client { display: inline-flex; align-items: center; gap: 2px; max-width: 300px;
  height: 32px; padding: 0 12px; border-radius: var(--r-pill); background: var(--wash);
  color: var(--accent-ink); font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; }
.topbar__client .muted { color: var(--accent); font-weight: 500; margin-left: 4px; }
.topbar__env { font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--warn); background: var(--warn-wash); border-radius: var(--r-pill); padding: 4px 10px; }

.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; }
.menu > summary::-webkit-details-marker { display: none; }
.usermenu__face { display: flex; align-items: center; gap: 8px; height: 38px; padding: 0 8px 0 4px;
  border-radius: var(--r-pill); color: var(--ink-2); }
.usermenu__face:hover, .usermenu[open] .usermenu__face { background: var(--subtle); }
.usermenu__face .ico { width: 16px; height: 16px; color: var(--ink-3); }
.usermenu__name { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.avatar { width: 30px; height: 30px; border-radius: 50%; display: inline-flex; align-items: center;
  justify-content: center; background: var(--ink); color: #fff; font-size: 12px; font-weight: 700; }
.menu__panel { position: absolute; right: 0; top: calc(100% + 8px); min-width: 240px; z-index: 40;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop); padding: 6px; }
.menu__who { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px 12px;
  border-bottom: 1px solid var(--line); margin-bottom: 6px; font-size: 13.5px; }
.menu__who .muted { font-size: 12.5px; }
.menu__item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 12px;
  border-radius: var(--r); color: var(--ink-2); font-size: 13.5px; font-weight: 500; }
.menu__item:hover { background: var(--subtle); color: var(--ink); text-decoration: none; }
.menu__item .ico { width: 16px; height: 16px; color: var(--ink-3); }
.menu form { margin: 0; }

body.console .content { padding: 28px 32px 56px; overflow: visible; }
body.console .content > * { max-width: 1440px; }
/* The inbox is a PANE: the column is the viewport and the pane takes what is
   left under the top bar. Flex, never a measured calc (§13.1, item 312). */
body.console .main:has(> .content--fill) { height: 100vh; }
body.console .content--fill { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.scrim { display: none; }
.nav-open { display: none; }
@media (max-width: 960px) {
  .nav-open { display: block; position: absolute; opacity: 0; pointer-events: none;
              width: 1px; height: 1px; }
  .nav-open:focus-visible ~ .shell .topbar__menu { outline: 2px solid var(--accent);
                                                   outline-offset: 2px; }
}
.topbar__menu, .sidebar__toggle { cursor: pointer; }

@media (max-width: 960px) {
  body.console .sidebar { position: fixed; left: 0; top: 0; bottom: 0; transform: translateX(-100%);
    transition: transform .2s ease; box-shadow: var(--shadow-pop); }
  .nav-open:checked ~ .shell .sidebar { transform: none; }
  .nav-open:checked ~ .shell .scrim { display: block; position: fixed; inset: 0; z-index: 25;
    background: rgba(15, 17, 21, .4); }
  html.rail-collapsed body.console .sidebar { width: var(--side-w); flex-basis: var(--side-w); }
  html.rail-collapsed .sidebar__lockup { display: flex; }
  .topbar { padding: 0 16px; }
  .topbar__menu { display: inline-flex; }
  .sidebar__toggle { display: none; }
  .usermenu__name, .topbar__env { display: none; }
  body.console .content { padding: 20px 16px 40px; }
}

/* ── Page head ─────────────────────────────────────────────────────────── */
.page-head { align-items: flex-end; gap: 16px; margin-bottom: 24px; }
.page-head__text { min-width: 0; }
.page-head__eyebrow { font-size: 12px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 6px; }
.h1 { font-size: var(--t-h1); font-weight: 650; letter-spacing: -.02em; line-height: 1.25; }
.h2 { font-size: var(--t-h2); }
.page-head__sub { font-size: 14px; color: var(--ink-3); margin-top: 6px; line-height: 1.55; }

/* ── Cards ─────────────────────────────────────────────────────────────── */
.panel { background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-card); padding: 20px 24px; margin-bottom: 20px; }
.panel--fill { background: var(--subtle); box-shadow: none; }
.panel__head { align-items: center; margin: -2px 0 14px; }
.panel__head h2, .panel__head .h2, .panel > h2, .panel > h3 {
  font-size: var(--t-h2); font-weight: 650; letter-spacing: -.01em; color: var(--ink);
  margin: 0; text-transform: none; }
.panel > h2, .panel > h3 { margin-bottom: 12px; }
.tile { background: var(--paper); border: 1px solid var(--line); box-shadow: var(--shadow-card);
  padding: 18px 20px; }
.tile__label { font-size: 13px; font-weight: 500; color: var(--ink-3); letter-spacing: 0; }
.tile__value { font-size: 28px; font-weight: 650; margin-top: 8px; }
.tile__note { font-size: 12.5px; margin-top: 6px; }
a.tile:hover { border-color: var(--accent); box-shadow: 0 4px 14px -6px rgba(37, 99, 235, .35); }
.tiles { gap: 16px; margin-bottom: 24px; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

/* ── Tables ────────────────────────────────────────────────────────────── */
.table-wrap { background: var(--paper); border-color: var(--line); box-shadow: var(--shadow-card); }
thead th { font-size: 12px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink-3); background: #F9FAFB; border-bottom: 1px solid var(--line); padding: 11px 14px; }
tbody td, tbody th { padding: 12px 14px; border-bottom-color: #F0F2F5; }
.card-table thead th { background: transparent; }
table { font-size: 14px; }

/* ── Buttons ───────────────────────────────────────────────────────────── */
.btn { height: 36px; padding: 0 16px; border-radius: var(--r); font-size: 14px; font-weight: 600;
  background: var(--paper); color: var(--ink); border: 1px solid var(--line-2);
  box-shadow: 0 1px 2px rgba(16, 24, 40, .05); transition: background .12s, border-color .12s; }
.btn:hover { background: var(--subtle); border-color: var(--line-2); }
.btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.btn--ghost { box-shadow: none; }
.btn--danger { background: var(--paper); border-color: #FDA4AF; color: var(--bad); box-shadow: none; }
.btn--danger:hover { background: var(--bad-wash); border-color: var(--bad); }
.btn--sm { height: 30px; padding: 0 12px; font-size: 13px; }
.btn .ico { width: 16px; height: 16px; }
.sidebar .btn--pick { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: none; }

/* ── Forms ─────────────────────────────────────────────────────────────── */
label { font-size: 13px; font-weight: 500; color: var(--ink-2); margin-bottom: 6px; }
input, select, textarea { height: 40px; padding: 0 12px; font-size: 14px; border-color: var(--line-2);
  border-radius: var(--r); background: var(--paper); transition: border-color .12s, box-shadow .12s; }
input[type=checkbox], input[type=radio] { width: 16px; height: 16px; padding: 0; accent-color: var(--accent); }
input[type=file] { height: auto; padding: 8px 10px; }
textarea { height: auto; padding: 10px 12px; line-height: 1.5; }
input:hover, select:hover, textarea:hover { border-color: #98A2B3; }
input:focus, select:focus, textarea:focus { border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, .12); }
.sidebar .picker input, .sidebar .picker select { height: 36px; }
.field { margin-bottom: 16px; }
.hint { font-size: 12.5px; color: var(--ink-3); margin-top: 6px; line-height: 1.5; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 20px; }
.form-grid .span-2 { grid-column: 1 / -1; }
.form-actions { display: flex; gap: 10px; align-items: center; margin-top: 20px;
  padding-top: 18px; border-top: 1px solid var(--line); }
@media (max-width: 720px) { .form-grid { grid-template-columns: 1fr; } }

/* ── Settings layout: what it is on the left, the form on the right ────── */
.settings { background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-card); margin-bottom: 20px; }
.setting { display: grid; grid-template-columns: minmax(200px, 300px) minmax(0, 1fr);
  gap: 24px 40px; padding: 26px 28px; border-bottom: 1px solid var(--line); }
.setting:last-child { border-bottom: 0; }
.setting__title { font-size: 15.5px; font-weight: 650; margin: 0; color: var(--ink); }
.setting__sub { margin: 6px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-3); }
.setting__body { min-width: 0; max-width: 560px; }
@media (max-width: 860px) { .setting { grid-template-columns: 1fr; gap: 14px; } }

/* ── Banners, notes, status ────────────────────────────────────────────── */
.banner { display: flex; align-items: flex-start; gap: 10px; border: 1px solid transparent;
  border-radius: var(--r-lg); padding: 12px 16px; font-size: 14px; line-height: 1.5; }
.banner > .ico { margin-top: 1px; }
.banner--bad  { border-color: #FECDD6; }
.banner--warn { border-color: #FCE3B4; }
.banner--good { border-color: #BBF7D0; }
.banner--info { border-color: #C7D7FE; }
.note { font-size: 13.5px; line-height: 1.55; }
.pill { font-size: 12.5px; padding: 3px 10px; font-weight: 600; }
.status { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; }
.status::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--ink-4); }
.status--good { color: var(--good-ink); } .status--good::before { background: var(--good); }
.status--warn { color: var(--warn); }     .status--warn::before { background: #F59E0B; }
.status--bad  { color: var(--bad); }      .status--bad::before  { background: var(--bad); }
.empty { background: var(--paper); border: 1px dashed var(--line-2); padding: 40px 28px; font-size: 14px; }
.kv { font-size: 14px; gap: 10px 20px; }

/* Numbered steps (second factor, onboarding). */
.steps { list-style: none; counter-reset: step; margin: 0; padding: 0; display: grid; gap: 18px; }
.steps > li { counter-increment: step; display: grid; grid-template-columns: 30px 1fr; gap: 14px; }
.steps > li::before { content: counter(step); width: 28px; height: 28px; border-radius: 50%;
  background: var(--wash); color: var(--accent-ink); font-weight: 700; font-size: 13px;
  display: inline-flex; align-items: center; justify-content: center; }
.steps__title { font-weight: 600; color: var(--ink); margin: 3px 0 4px; }
.steps__body { color: var(--ink-2); font-size: 13.5px; line-height: 1.55; }
.keybox { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 15px;
  letter-spacing: .08em; background: var(--subtle); border: 1px solid var(--line);
  border-radius: var(--r); padding: 12px 14px; margin: 10px 0 6px; word-break: break-all; }

/* ── Dashboard pieces ──────────────────────────────────────────────────── */
.tile--icon { position: relative; padding-top: 18px; }
.tile__ico { position: absolute; top: 16px; right: 16px; width: 36px; height: 36px;
  border-radius: 10px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--wash); color: var(--accent); }
.tile__ico--bad { background: var(--bad-wash); color: var(--bad); }
.tile__ico--warn { background: var(--warn-wash); color: var(--warn); }
.tile__ico--good { background: var(--good-wash); color: var(--good-ink); }
.dash { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr); gap: 20px; align-items: start; }
@media (max-width: 1100px) { .dash { grid-template-columns: 1fr; } }
.panel__link { margin-left: auto; display: inline-flex; align-items: center; gap: 2px;
  font-size: 13.5px; font-weight: 600; }
.panel__link .ico { width: 15px; height: 15px; }
.progress { display: flex; height: 10px; border-radius: 6px; background: var(--rule-2); overflow: hidden; }
.progress__seg { display: block; height: 100%; }
.progress__seg--good { background: var(--good); }
.progress__seg--accent { background: var(--accent); }
.legend { list-style: none; margin: 0; padding: 0; }
.legend li { display: grid; grid-template-columns: 12px 150px minmax(0, 1fr) auto; align-items: center;
  gap: 12px; padding: 11px 0; border-top: 1px solid #F0F2F5; font-size: 14px; }
.legend li:first-child { border-top: 0; }
.legend__key { width: 10px; height: 10px; border-radius: 3px; background: var(--rule); }
.legend__key--good { background: var(--good); }
.legend__key--accent { background: var(--accent); }
.legend__key--muted { background: var(--ink-4); }
.legend__key--bad { background: var(--bad); }
.legend__name { font-weight: 600; color: var(--ink); }
.legend__note { color: var(--ink-3); font-size: 13px; }
.legend strong { font-size: 16px; font-weight: 650; }
.actions { display: grid; gap: 8px; }
.action { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r);
  border: 1px solid var(--line); color: var(--ink); }
.action:hover { border-color: var(--accent); background: var(--wash); text-decoration: none; color: var(--ink); }
.action > .ico { color: var(--accent); width: 20px; height: 20px; }
.action strong { display: block; font-size: 14px; font-weight: 600; }
.action em { display: block; font-style: normal; font-size: 12.5px; color: var(--ink-3); }
.dash__client { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }

/* ── Profiles ──────────────────────────────────────────────────────────── */
.profile-head { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin-bottom: 24px; }
.profile-head__avatar { width: 56px; height: 56px; border-radius: 14px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #2563EB, #1E40AF); color: #fff; font-size: 22px; font-weight: 700; }
.profile-head__avatar--person { border-radius: 50%; background: var(--ink); }
.profile-head__text { min-width: 0; flex: 1 1 320px; }
.profile-head .h1 { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.profile-head__meta { display: flex; gap: 6px 16px; flex-wrap: wrap; margin-top: 6px; color: var(--ink-3); font-size: 14px; }
.profile-head__meta > span + span::before { content: "·"; margin-right: 16px; color: var(--ink-4); }
.profile-head .page-head__actions { margin-left: auto; }
.facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 24px; margin: 0; }
.facts dt { font-size: 12.5px; font-weight: 500; color: var(--ink-3); margin-bottom: 3px; }
.facts dd { margin: 0; font-size: 14px; color: var(--ink); font-weight: 500; }
.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--r); }
.toggle-row__title { font-weight: 600; color: var(--ink); }
.toggle-row form { margin: 0; flex: 0 0 auto; }
.logins { list-style: none; margin: 0 0 4px; padding: 0; border: 1px solid var(--line); border-radius: var(--r); }
.login { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-top: 1px solid var(--line); flex-wrap: wrap; }
.login:first-child { border-top: 0; }
.login__who { display: flex; flex-direction: column; min-width: 140px; flex: 1 1 auto; }
.login__who strong { font-size: 14px; }
.login__who .muted { font-size: 12.5px; }
.login__meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.login__menu .menu__panel { min-width: 280px; }
.login__menu > summary .ico { width: 14px; height: 14px; }
.avatar--soft { background: var(--wash); color: var(--accent-ink); }
.menu__form { display: grid; gap: 6px; padding: 10px 12px 8px; border-top: 1px solid var(--line); margin-top: 6px; }
.menu__form label { margin: 0; }
.menu__form .btn { justify-self: start; }
.subform { margin-top: 18px; padding: 16px; border-radius: var(--r); background: var(--subtle); }
.subform__title { font-weight: 600; margin-bottom: 12px; color: var(--ink); }
.subform .hint { margin-top: 10px; }

/* Legacy bare <button>s on screens not yet redrawn: the v2 button, and a
   menu item stays a menu item. */
.content button:not(.btn) { height: 36px; padding: 0 16px; background: var(--paper);
  border: 1px solid var(--line-2); box-shadow: 0 1px 2px rgba(16, 24, 40, .05); font-size: 14px; }
.content button:not(.btn):hover { background: var(--subtle); }
.content button.primary { background: var(--accent); border-color: var(--accent); }
.content button.menu__item { height: auto; padding: 9px 12px; background: transparent;
  border: 0; box-shadow: none; font-weight: 500; font-size: 13.5px; }
.content button.menu__item:hover { background: var(--subtle); }

.disclosure > summary { cursor: pointer; font-size: 13.5px; font-weight: 600; color: var(--accent); list-style: none; }
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before { content: "+ "; }
.disclosure[open] > summary::before { content: "\2212  "; }

.tile__of { font-size: 18px; font-weight: 500; color: var(--ink-4); }
.seat-rows { display: grid; gap: 10px; }
.seat-row { display: grid; grid-template-columns: 120px 140px 1fr auto; align-items: center; gap: 12px; margin: 0; }
.seat-row label { margin: 0; }
.cell-person { display: flex; align-items: center; gap: 10px; }
.cell-person .pill { margin-left: 6px; }
.profile-head__avatar .ico { width: 26px; height: 26px; color: #fff; }

/* ── Review queue ─────────────────────────────────────────────────────── */
.tiles--compact { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.tiles--compact .tile { padding: 14px 16px; }
.tiles--compact .tile__value { font-size: 24px; margin-top: 4px; }
.filterbar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px 16px; margin-bottom: 18px;
  padding: 16px 18px; background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-card); }
.filterbar__field { display: flex; flex-direction: column; min-width: 170px; flex: 1 1 170px; }
.filterbar__field--wide { flex: 2 1 240px; }
.filterbar__field label { margin-bottom: 6px; }
.filterbar__checks { display: flex; gap: 16px; align-items: center; height: 40px; }
.filterbar__checks .check { display: inline-flex; align-items: center; gap: 7px; margin: 0; font-size: 13.5px; color: var(--ink-2); white-space: nowrap; }
.filterbar__actions { display: flex; gap: 8px; margin-left: auto; }
.queue-item { font-weight: 600; color: var(--ink); }
.queue-item:hover { color: var(--accent); }
.queue-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin-top: 4px; font-size: 12.5px; color: var(--ink-3); }
.pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 18px 0 8px; }

/* ── Client overview ───────────────────────────────────────────────────── */
.hero { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 18px 22px; border-radius: var(--r-lg); margin-bottom: 20px; border: 1px solid transparent; }
.hero--calm { background: var(--good-wash); border-color: #BBF7D0; }
.hero--act { background: var(--wash); border-color: #C7D7FE; }
.hero__title { font-size: 17px; font-weight: 650; color: var(--ink); }
.hero--calm .hero__title { color: var(--good-ink); }
.hero__text { margin-top: 4px; font-size: 14px; color: var(--ink-2); }
.chart { display: flex; align-items: flex-end; gap: 14px; height: 200px; padding: 8px 4px 0;
  border-bottom: 1px solid var(--line); }
.chart__col { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; height: 100%; min-width: 0; }
.chart__bars { flex: 1 1 auto; width: 100%; display: flex; align-items: flex-end; justify-content: center; gap: 5px; }
.chart__bar { display: block; width: min(22px, 40%); min-height: 2px; border-radius: 5px 5px 0 0; }
.chart__bar--in { background: var(--accent); }
.chart__bar--out { background: #64748B; }  /* 3:1 or better on white (#H157) */
.chart__bar.is-neg { background: var(--bad); }
.chart__label { margin-top: 8px; margin-bottom: -26px; font-size: 12.5px; color: var(--ink-3); }
.chart__legend { display: flex; gap: 18px; margin-top: 34px; font-size: 13px; color: var(--ink-2); }
.chart__legend span { display: inline-flex; align-items: center; gap: 7px; }
.chart__key { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.chart__key--in { background: var(--accent); }
.chart__key--out { background: #64748B; }
.statrow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.statrow > div { padding: 12px 14px; border-radius: var(--r); background: var(--subtle); }
.statrow__v { font-size: 22px; font-weight: 650; color: var(--ink); }
.statrow__l { font-size: 12.5px; color: var(--ink-3); margin-top: 2px; }
@media (max-width: 720px) { .statrow { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.timeline-list { list-style: none; margin: 0; padding: 0; }
.timeline-list li { display: grid; grid-template-columns: 48px 1fr; gap: 10px; padding: 9px 0;
  border-top: 1px solid #F0F2F5; font-size: 13.5px; color: var(--ink-2); }
.timeline-list li:first-child { border-top: 0; }
.timeline-list b { color: var(--accent-ink); font-weight: 650; }

/* ── Item (flag) page ─────────────────────────────────────────────────── */
.item-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }
.item-head__text { min-width: 0; flex: 1 1 480px; }
.item-head__meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.factbar { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin-bottom: 20px; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-card); }
.factbar > div { padding: 14px 18px; border-left: 1px solid var(--line); display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.factbar > div:first-child { border-left: 0; }
.factbar span { font-size: 12.5px; color: var(--ink-3); }
.factbar strong { font-size: 14px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; }
.factbar em { font-style: normal; font-size: 12.5px; color: var(--ink-3); }
@media (max-width: 900px) { .factbar { grid-template-columns: repeat(2, minmax(0, 1fr)); } .factbar > div:nth-child(3) { border-left: 0; } }
.disclosure-panel > summary { cursor: pointer; font-weight: 600; color: var(--ink); list-style: none; }
.disclosure-panel > summary::-webkit-details-marker { display: none; }
.disclosure-panel > summary::before { content: "+ "; color: var(--accent); }
.disclosure-panel[open] > summary::before { content: "\2212  "; }
.codebox { margin: 0; padding: 12px 14px; background: #0F172A; color: #E2E8F0; border-radius: var(--r); font-size: 12.5px; line-height: 1.5; overflow: auto; max-height: 320px; }

.table-wrap--menus { overflow: visible; }
.row-menu { display: inline-block; vertical-align: middle; margin-left: 4px; text-align: left; }
.row-menu > summary { letter-spacing: .08em; }
.row-menu .menu__panel { min-width: 280px; white-space: normal; }
.seatbar { display: flex; flex-direction: column; gap: 5px; min-width: 110px; font-size: 13px; }

/* ── Sign in: split screen ─────────────────────────────────────────────── */
.gate-split { display: grid; grid-template-columns: minmax(360px, 44%) 1fr; min-height: 100vh; background: var(--canvas); }
.gate-brand { background: radial-gradient(120% 90% at 0% 0%, #22304F 0%, var(--rail-bg) 55%); color: var(--on-ink);
  display: flex; flex-direction: column; padding: 40px 48px; }
.gate-brand__lockup { display: flex; align-items: center; gap: 12px; color: #fff; font-size: 22px; font-weight: 600; letter-spacing: -.03em; }
.gate-brand__lockup img { height: 24px; width: auto; }
.gate-brand__body { margin: auto 0; max-width: 460px; }
.gate-brand__title { font-size: 32px; line-height: 1.2; font-weight: 650; letter-spacing: -.02em; color: #fff; margin: 0 0 28px; }
.gate-brand__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.gate-brand__list li { position: relative; padding-left: 28px; font-size: 15px; line-height: 1.5; color: var(--on-ink); }
.gate-brand__list li::before { content: ""; position: absolute; left: 0; top: 5px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 4px rgba(37, 99, 235, .25); }
.gate-brand__foot { font-size: 12.5px; color: var(--ink-4); }
.gate-split .gate-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 32px 20px; background: transparent; }
.gate-split .gate-card { max-width: 420px; padding: 36px; border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 20px 50px -24px rgba(16, 24, 40, .25); }
.gate-split .gate-card__brand { display: none; }
.gate-split .gate-foot { font-size: 13px; color: var(--ink-3); border-top: 1px solid var(--line); }
.btn--block { width: 100%; justify-content: center; height: 42px; margin-top: 6px; }
@media (max-width: 900px) {
  .gate-split { grid-template-columns: 1fr; }
  .gate-brand { display: none; }
  .gate-split .gate-card__brand { display: flex; }
}

.choice-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.choice-card { position: relative; display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 14px 14px 14px 40px;
  border: 1px solid var(--line-2); border-radius: var(--r); cursor: pointer; background: var(--paper); }
.choice-card input { position: absolute; left: 14px; top: 16px; }
.choice-card:has(input:checked) { border-color: var(--accent); background: var(--wash); box-shadow: 0 0 0 1px var(--accent) inset; }
.choice-card__title { font-weight: 600; color: var(--ink); font-size: 14px; }
.choice-card__note { font-size: 12.5px; color: var(--ink-3); }
@media (max-width: 720px) { .choice-cards { grid-template-columns: 1fr; } }

/* ══════════════════════════════════════════════════════════════════════════
 * INBOX v2: a messaging screen, not a table (§4 item 486).
 * Three panes: the conversation list, the thread, the client details. The
 * pane takes what is left of the viewport by FLEX, never a measured calc
 * (§13.1), and `min-height: 0` sits on every box in the scrolling chain,
 * because `min-height: auto` is what made the old thread grow instead of
 * scroll (§4 item 316).
 * ══════════════════════════════════════════════════════════════════════════ */
body.console .content--fill { padding: 14px 18px 16px; }
body.console .content--fill > .im { max-width: none; }
.im { flex: 1 1 auto; min-height: 0; display: grid;
      grid-template-columns: 340px minmax(0, 1fr);
      background: #fff; border: 1px solid var(--line); border-radius: var(--r-lg);
      box-shadow: var(--shadow-card); overflow: hidden; }
.im--thread { grid-template-columns: 340px minmax(0, 1fr) 300px; }

/* the list */
.im-list { display: flex; flex-direction: column; min-height: 0;
           border-right: 1px solid var(--line); background: #fff; }
.im-list__head { display: flex; align-items: center; justify-content: space-between;
                 padding: 14px 16px 8px; }
.im-list__title { margin: 0; font-size: 20px; font-weight: 650; letter-spacing: -.02em;
                  display: flex; align-items: center; gap: 8px; }
.im-search { display: flex; flex-direction: column; gap: 6px; padding: 4px 12px 8px; }
.im-search__row { position: relative; display: flex; gap: 6px; align-items: center; }
.im-search__ico { position: absolute; left: 10px; width: 16px; height: 16px; color: var(--ink-4);
                  pointer-events: none; }
.im-search__firm { width: 100%; height: 36px; border-radius: 18px; padding: 0 12px 0 32px;
  border: 1px solid var(--line); background: #fff; font-size: var(--t-small); }
.im-search__clear { align-self: flex-start; }
.im-group__scope { margin-left: auto; padding: 1px 8px; border-radius: 9px; background: #EEF4FF;
  color: var(--accent-ink); font-weight: 600; max-width: 55%; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.im-search input[type="search"] { flex: 1 1 auto; width: auto; min-width: 0; height: 36px;
  padding: 0 10px 0 32px; border-radius: 18px; border: 1px solid transparent;
  background: var(--subtle); font: inherit; font-size: var(--t-meta); }
.im-search input[type="search"]:focus-visible { background: #fff; border-color: var(--accent); outline: none; }
.im-search__label { width: auto; flex: 0 0 auto; max-width: 118px; height: 36px; border-radius: 18px;
  font-size: var(--t-small); padding: 0 8px; border: 1px solid var(--line); background: #fff; }
.im-search__clear { font-size: var(--t-small); flex: 0 0 auto; }
.im-search [hidden] { display: none; }
.im-tabs { display: flex; flex-wrap: wrap; gap: 6px 4px; padding: 2px 12px 10px; }
.im-tabs::-webkit-scrollbar { display: none; }
.im-tab { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; height: 30px;
  padding: 0 12px; border-radius: 15px; background: var(--subtle); color: var(--ink-2);
  font-size: var(--t-small); font-weight: 550; white-space: nowrap; }
.im-tab:hover { text-decoration: none; background: var(--fill); color: var(--ink); }
.im-tab.is-on { background: var(--ink); color: #fff; }
.im-tab__n { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; font-size: 11px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.08); color: inherit; font-weight: 650; }
.im-tab__n.is-hot { background: var(--accent); color: #fff; }
.im-tab.is-on .im-tab__n { background: rgba(255,255,255,.22); color: #fff; }
.im-group { display: flex; align-items: center; gap: 10px; padding: 0 16px 8px;
            font-size: var(--t-small); border-bottom: 1px solid var(--line); }
.im-group a { color: var(--ink-3); font-weight: 550; }
.im-group a.is-on { color: var(--accent); }
.im-list__rows { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
                 scrollbar-width: thin; }
.im-row { display: flex; gap: 12px; padding: 11px 14px; color: var(--ink);
          border-bottom: 1px solid var(--subtle); position: relative; }
.im-row:hover { background: var(--subtle); text-decoration: none; }
.im-row.is-on { background: #EEF4FF; }
.im-row.is-on::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
                        background: var(--accent); }
.im-row__main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.im-row__top { display: flex; align-items: baseline; gap: 8px; }
.im-row__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
                white-space: nowrap; font-weight: 550; font-size: 14.5px; }
.im-row__when { flex: 0 0 auto; font-size: 11.5px; color: var(--ink-4); }
.im-row__line { display: flex; align-items: center; gap: 5px; min-width: 0; }
.im-row__preview { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
                   white-space: nowrap; color: var(--ink-3); font-size: var(--t-meta); }
.im-row__meta { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--ink-4);
                min-width: 0; }
.im-row__who { margin-left: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
               max-width: 45%; }
.im-row.is-unread .im-row__name { font-weight: 700; }
.im-row.is-unread .im-row__preview { color: var(--ink); font-weight: 550; }
.im-row.is-unread .im-row__when { color: var(--accent); font-weight: 650; }
.im-badge { flex: 0 0 auto; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
            background: var(--accent); color: #fff; font-size: 11.5px; font-weight: 700;
            display: inline-flex; align-items: center; justify-content: center; }
.im-badge--dot { min-width: 10px; width: 10px; height: 10px; padding: 0; }
.im-star .ico { width: 13px; height: 13px; fill: #FBBF24; stroke: #D97706; }
.im-label { padding: 1px 7px; border-radius: 9px; background: var(--subtle); color: var(--ink-2);
            font-size: 11px; font-weight: 600; white-space: nowrap; }
.im-label--follow_up { background: #EEF4FF; color: #1E40AF; }
.im-label--awaiting_documents { background: #FEF6E7; color: #B45309; }
.im-label--query { background: #F3E8FF; color: #7E22CE; }
.im-label--payment { background: #ECFDF3; color: #15803D; }
.im-label--onboarding { background: #E0F2FE; color: #0369A1; }
.im-client { border-bottom: 1px solid var(--line); }
.im-client__head { display: flex; justify-content: space-between; align-items: baseline;
  padding: 10px 14px 4px; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; }
.im-client__name { font-weight: 700; color: var(--ink-2); }
.im-client .im-row { padding-left: 24px; }
.im-empty { display: flex; flex-direction: column; gap: 4px; padding: 28px 22px; text-align: center;
            color: var(--ink-3); font-size: var(--t-meta); }
.im-empty strong { color: var(--ink); font-size: 14.5px; }

/* avatars */
.im-avatar { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px; letter-spacing: .02em; color: #fff; background: #64748B; }
.im-avatar--lg { width: 40px; height: 40px; font-size: 15px; }
.im-avatar--xl { width: 64px; height: 64px; font-size: 24px; }
.im-avatar--0 { background: #2563EB; } .im-avatar--1 { background: #0D9488; }
.im-avatar--2 { background: #7C3AED; } .im-avatar--3 { background: #DB2777; }
.im-avatar--4 { background: #EA580C; } .im-avatar--5 { background: #0891B2; }
.im-avatar--6 { background: #65A30D; } .im-avatar--7 { background: #475569; }

/* the thread pane */
.im-pane { display: flex; flex-direction: column; min-width: 0; min-height: 0;
           background-color: #EFF1F4;
           background-image: radial-gradient(rgba(15,17,21,.045) 1px, transparent 1px);
           background-size: 18px 18px; }
.im-pane--blank { background-image: none; background-color: var(--subtle); justify-content: center; }
.im-head { display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: #fff;
           border-bottom: 1px solid var(--line); min-height: 64px; }
.im-back { display: none; color: var(--ink-3); transform: rotate(180deg); }
.im-head__who { flex: 1 1 auto; min-width: 0; }
.im-head__name { font-weight: 650; font-size: 15.5px; white-space: nowrap; overflow: hidden;
                 text-overflow: ellipsis; }
.im-head__sub { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 2px;
                font-size: var(--t-small); color: var(--ink-3); }
.im-head__actions form { display: flex; gap: 4px; margin: 0; }
.im-chip { padding: 1px 8px; border-radius: 10px; font-size: 11.5px; font-weight: 600;
           white-space: nowrap; }
.im-chip--good { background: var(--good-wash); color: var(--good-ink); }
.im-chip--warn { background: var(--warn-wash); color: var(--warn); }
.im-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 36px;
  height: 36px; border-radius: 50%; border: 0; background: transparent; color: var(--ink-3);
  cursor: pointer; padding: 0; }
.im-iconbtn:hover { background: var(--subtle); color: var(--ink); text-decoration: none; }
.im-iconbtn.is-on { color: var(--accent); background: #EEF4FF; }
.im-iconbtn.is-on .ico { fill: currentColor; fill-opacity: .15; }
.im-iconbtn--sm { width: 28px; height: 28px; }
/* The legacy `.content button:not(.btn)` gives every button a bordered pill;
   these are icon buttons and a send button, so they say so at a higher
   specificity rather than joining `.btn`. */
body.console .content button.im-iconbtn { height: 36px; padding: 0; border: 0; background: transparent; }
body.console .content button.im-iconbtn:hover { background: var(--subtle); }
body.console .content button.im-iconbtn.is-on { background: #EEF4FF; }
body.console .content button.im-send { height: 44px; padding: 0; border: 0; background: var(--accent); color: #fff; }
body.console .content button.im-send:hover { background: var(--accent-ink); }
.im-iconbtn--sm .ico { width: 16px; height: 16px; }
.im-toast { margin: 10px 16px 0; }

.im-thread { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
             padding: 14px 6% 18px; scrollbar-width: thin; }
.im-day { text-align: center; margin: 14px 0 8px; }
.im-day span { display: inline-block; padding: 4px 12px; border-radius: 8px; background: #fff;
  color: var(--ink-3); font-size: 11.5px; font-weight: 600; box-shadow: 0 1px 1px rgba(16,24,40,.06); }
.im-thread .msg { display: flex; margin: 3px 0; }
.im-thread .msg--in { justify-content: flex-start; }
.im-thread .msg--out { justify-content: flex-end; }
.im-thread .bubble { position: relative; max-width: min(72%, 560px); padding: 7px 10px 6px 11px;
  border-radius: 10px; border: 0; background: #fff; color: var(--ink); font-size: 14px;
  line-height: 1.45; box-shadow: 0 1px 1px rgba(16,24,40,.08); overflow-wrap: anywhere; }
.im-thread .msg--in .bubble { border-top-left-radius: 3px; background: #fff; }
.im-thread .msg--out .bubble { border-top-right-radius: 3px; background: #DCE8FF; color: #0B1B3F; }
.im-thread .bubble--card { background: #fff; border: 1px dashed #93B4F5; }
.im-thread .msg--out .bubble--card { background: #F3F7FF; }
.im-thread .bubble--failed { background: #FFE9EE; }
.im-thread .bubble--media { padding: 4px 4px 6px; }
.im-thread .bubble--media .bubble__body { display: block; padding: 4px 6px 0; }
.im-thread .bubble__img { display: block; max-width: 300px; max-height: 320px; width: 100%;
  object-fit: cover; border-radius: 8px; }
.im-thread .bubble__kind { display: flex; align-items: center; gap: 5px; font-size: 11.5px;
  font-weight: 650; color: var(--ink-3); margin-bottom: 2px; text-transform: none; letter-spacing: 0; }
.im-thread .bubble__kind .ico { width: 14px; height: 14px; }
.im-thread .bubble__file { display: flex; align-items: center; gap: 10px; padding: 8px;
  border-radius: 8px; background: rgba(15,17,21,.05); min-width: 220px; }
.im-thread .bubble__fileico { width: 34px; height: 34px; border-radius: 6px; background: #E11D48;
  color: #fff; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.im-thread .bubble__filename { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-weight: 550; font-size: var(--t-meta); }
.im-thread .bubble__doc { display: inline-flex; align-items: center; gap: 4px; margin-top: 5px;
  font-size: 12px; font-weight: 550; }
.im-thread .bubble__doc .ico { width: 13px; height: 13px; }
.im-thread .bubble__meta { float: right; display: inline-flex; align-items: center; gap: 4px;
  margin: 6px 0 -2px 12px; font-size: 11px; color: var(--ink-4); line-height: 1; }
.im-thread .msg--out .bubble__meta { color: #5B6B8C; }
.im-thread .bubble__err { display: block; clear: both; font-size: 11.5px; color: var(--bad); font-weight: 600; }
.im-tick { font-size: 11px; letter-spacing: -3px; color: var(--ink-4); font-weight: 700; padding-right: 3px; }
.im-tick.is-read { color: var(--accent); }
.im-tick.is-bad { color: var(--bad); letter-spacing: 0; }
.im-empty--thread { margin: auto; background: #fff; border-radius: 10px; max-width: 360px; }

/* the composer */
.im-compose { background: #F7F8FA; border-top: 1px solid var(--line); padding: 10px 16px 12px; }
.im-compose .composer { border: 0; padding: 0; background: transparent; }
.im-compose .composer__row { display: flex; gap: 10px; align-items: flex-end; }
.im-compose textarea { flex: 1 1 auto; width: auto; min-height: 44px; max-height: 160px; resize: none;
  padding: 11px 16px; border-radius: 22px; border: 1px solid var(--line); background: #fff;
  font: inherit; font-size: 14px; line-height: 1.4; }
.im-compose textarea:focus-visible { outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
.im-send { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; border: 0;
  background: var(--accent); color: #fff; display: inline-flex; align-items: center;
  justify-content: center; cursor: pointer; }
.im-send:hover { background: var(--accent-ink); }
.im-send[disabled] { opacity: .5; }
.im-compose .composer__hint { margin: 6px 4px 0; font-size: 11.5px; color: var(--ink-4); }
.im-compose .composer__note { margin: 6px 4px 0; }
.im-locked { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: 10px;
  background: #fff; border: 1px solid var(--line); color: var(--ink-2); font-size: var(--t-meta); }
.im-locked .ico { color: var(--ink-3); margin-top: 1px; }
.im-locked--warn { background: var(--warn-wash); border-color: #F6DDB0; color: #7A4A0A; }
.im-locked--warn .ico { color: var(--warn); }

/* the empty pane */
.im-hello { margin: auto; max-width: 460px; padding: 32px; text-align: center; color: var(--ink-3); }
.im-hello h2 { margin: 12px 0 6px; font-size: 19px; color: var(--ink); }
.im-hello p { margin: 0 0 12px; }
.im-hello__mark { display: inline-flex; width: 64px; height: 64px; border-radius: 50%;
  align-items: center; justify-content: center; background: #EEF4FF; color: var(--accent); }
.im-hello__mark .ico { width: 30px; height: 30px; }
.im-hello__stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 18px 0 8px; }
.im-hello__stats a { display: flex; flex-direction: column; gap: 2px; padding: 12px 6px; border-radius: 10px;
  background: #fff; border: 1px solid var(--line); color: var(--ink-3); font-size: 12px; }
.im-hello__stats a:hover { text-decoration: none; border-color: var(--accent); }
.im-hello__stats b { font-size: 22px; color: var(--ink); font-weight: 700; }
.im-hello__note { display: flex; gap: 8px; align-items: flex-start; text-align: left; padding: 10px 12px;
  border-radius: 10px; background: #fff; border: 1px solid var(--line); font-size: var(--t-small); }

/* the details pane */
.im-info { min-height: 0; overflow-y: auto; border-left: 1px solid var(--line); background: #FAFBFC;
           padding: 12px; display: flex; flex-direction: column; gap: 10px; scrollbar-width: thin; }
.im-info__card { background: #fff; border: 1px solid var(--line); border-radius: 10px; padding: 12px;
                 font-size: var(--t-meta); }
.im-info__who { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
                padding: 18px 12px; }
.im-info__name { font-weight: 650; font-size: 15.5px; }
.im-info__title { display: flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); margin-bottom: 8px; }
.im-info__title .ico { width: 14px; height: 14px; }
.im-info__foot { margin-top: 6px; font-size: 11.5px; color: var(--ink-4); }
.im-info__link { display: inline-flex; align-items: center; gap: 4px; margin-top: 8px; font-size: 12.5px;
                 font-weight: 550; }
.im-info__link .ico { width: 14px; height: 14px; }
.im-info__all { margin-top: 10px; width: 100%; justify-content: center; }
.im-info textarea { width: 100%; font: inherit; font-size: var(--t-meta); border-radius: 8px;
                    border: 1px solid var(--line); padding: 8px; resize: vertical; }
.im-inline { display: flex; gap: 6px; }
.im-inline select { flex: 1 1 auto; width: auto; min-width: 0; height: 32px; font-size: var(--t-small); }
.im-num { display: flex; align-items: center; gap: 6px; padding: 7px 8px; margin: 0 -8px; border-radius: 8px;
          color: var(--ink); }
.im-num:hover { background: var(--subtle); text-decoration: none; }
.im-num.is-on { background: #EEF4FF; }
.im-num__who { flex: 1 1 auto; min-width: 0; font-weight: 550; overflow: hidden; text-overflow: ellipsis;
               white-space: nowrap; }
.im-num__held { font-size: 11px; color: var(--ink-3); background: var(--subtle); padding: 1px 6px;
                border-radius: 8px; }
.im-file { display: flex; align-items: center; gap: 6px; padding: 5px 0; border-bottom: 1px solid var(--subtle); }
.im-file__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.im-file .muted { font-size: 11px; }

/* narrower windows */
@media (max-width: 1279px) {
  .im { grid-template-columns: 300px minmax(0, 1fr); }
  .im--thread { grid-template-columns: 300px minmax(0, 1fr) 270px; }
}
@media (max-width: 1080px) {
  /* A thread takes the list's place; the back arrow returns to it. */
  .im--thread { grid-template-columns: minmax(0, 1fr) 270px; }
  .im--thread .im-list { display: none; }
  .im--thread .im-back { display: inline-flex; }
}
@media (max-width: 760px) {
  body.console .main:has(> .content--fill) { height: auto; }
  body.console .content--fill { display: block; overflow: visible; padding: 10px; }
  .im, .im--thread { display: block; }
  .im-pane--blank { display: none; }
  .im--thread .im-pane { height: calc(100dvh - 90px); }
  .im-info { border-left: 0; border-top: 1px solid var(--line); }
}

/* ── Screens rebuilt in item 487: a panel that holds a table edge to edge ── */
.panel--flush { padding: 0; overflow: hidden; }
/* A panel whose rows carry a Manage menu: the menu must spill out of it, not be clipped by it (founder, 28 Sep: "when i click manage cannot see options"). */
.panel--menus { overflow: visible; }
.panel--flush > .panel__head { padding: 16px 20px 0; margin-bottom: 12px; }
.panel--flush > .panel__head .muted { margin-left: auto; font-size: var(--t-small); }
.table-wrap--flat { border: 0; border-radius: 0; box-shadow: none; }
.table-wrap--flat table { margin: 0; }
.tb__group th { background: var(--subtle); text-align: left; font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--ink-2); padding: 8px 12px; }
.tb__group .muted { font-weight: 600; margin-left: 4px; }
.tb tbody tr:not(.tb__group):hover td { background: #FAFBFD; }
/* Filter chips: every view a link (a colleague can be sent the URL). */
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 14px; }
.chip { display: inline-flex; align-items: center; height: 32px; padding: 0 14px; border-radius: 16px;
  background: var(--paper); border: 1px solid var(--line); color: var(--ink-2); font-size: var(--t-small);
  font-weight: 550; }
.chip:hover { text-decoration: none; border-color: var(--line-2); color: var(--ink); }
.chip.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }
.chips__count { margin-left: auto; font-size: var(--t-small); color: var(--ink-3); }
/* A document row: an icon, the name, and the line under it. */
.doclist__doc { display: flex; gap: 12px; align-items: flex-start; min-width: 240px; }
.doclist__ico { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 8px; background: #EEF4FF;
  color: var(--accent); display: inline-flex; align-items: center; justify-content: center; }
.doclist__sub { display: block; font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.doclist__warn { display: block; font-size: 12px; color: var(--warn); margin-top: 2px; }
tr.is-struck td { opacity: .6; }
.btn--sm .ico { width: 15px; height: 15px; }
/* A horizontal progress row: four steps a return (or anything) moves through.
   The state classes are read off stored facts; nothing here is computed. */
.steps--flow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; margin: 0 0 20px;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-card); overflow: hidden; counter-reset: step; }
.steps--flow > li { display: flex; flex-direction: column; gap: 2px; padding: 14px 16px 14px 52px;
  position: relative; border-right: 1px solid var(--line); grid-template-columns: none; }
.steps--flow > li:last-child { border-right: 0; }
.steps--flow > li::before { position: absolute; left: 14px; top: 14px; width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center; border-radius: 50%;
  background: var(--subtle); color: var(--ink-3); font-size: 12px; font-weight: 700; }
.steps--flow > li b { font-size: 14px; color: var(--ink-3); }
.steps--flow > li span { font-size: 12px; color: var(--ink-4); }
.steps--flow > li.is-done::before { content: "\2713"; background: var(--good); color: #fff; }
.steps--flow > li.is-done b { color: var(--ink); }
.steps--flow > li.is-now { background: #F5F8FF; }
.steps--flow > li.is-now::before { background: var(--accent); color: #fff; }
.steps--flow > li.is-now b { color: var(--accent-ink); }
.steps--flow > li.is-bad::before { content: "!"; background: var(--bad); color: #fff; }
.steps--flow > li.is-bad b { color: var(--bad); }
@media (max-width: 760px) { .steps--flow { grid-template-columns: 1fr 1fr; } }
/* A banner is a flex row only when it leads with an icon (icon + one span).
   The older banners hold bare text, <strong> and <em> side by side, and as
   flex items those split into columns mid-sentence; they read as prose. */
.banner:not(:has(> .ico)) { display: block; }
.tile--icon .tile__label { padding-right: 44px; }
/* Row actions sit on one line, right-aligned; a form inside is inline. */
.row-actions { display: inline-flex; gap: 6px; align-items: center; justify-content: flex-end; }
.row-actions form { margin: 0; }
.cell-clip { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Counts inside a flush panel, one row, any number of cells. */
.statrow--inset { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); padding: 0 20px 16px; }
.statrow--inset > div { display: flex; flex-direction: column; gap: 2px; }
.statrow--inset b { font-size: 22px; font-weight: 650; color: var(--ink); }
.statrow--inset span { font-size: 12.5px; color: var(--ink-3); }
.statrow--inset .is-good b { color: var(--good-ink); }
.statrow--inset .is-alarm b { color: var(--bad); }
.statrow-note { padding: 0 20px 14px; margin-top: -4px; }
/* Bank statements as cards: which account, which months, does it tie. */
.stmt-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; margin-bottom: 20px; }
.stmt-card { display: flex; flex-direction: column; gap: 3px; padding: 14px 16px; border-radius: var(--r-lg);
  background: var(--paper); border: 1px solid var(--line); box-shadow: var(--shadow-card); color: var(--ink); }
.stmt-card:hover { text-decoration: none; border-color: var(--line-2); }
.stmt-card.is-on { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37,99,235,.12); }
.stmt-card__top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.stmt-card__ico { width: 34px; height: 34px; border-radius: 8px; background: #EEF4FF; color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; }
.stmt-card__name { font-weight: 650; }
.stmt-card__period { font-size: var(--t-small); color: var(--ink-2); }
.stmt-card__meta { font-size: 12px; color: var(--ink-3); }
/* Journal (item 489): an entry's lines under its narration, and a row action
   that opens into a small form (a reason to reverse, to stop) without a page. */
.jlines { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 6px; }
.jline { display: inline-flex; gap: 6px; align-items: baseline; padding: 2px 8px; border-radius: 6px;
  background: var(--subtle); font-size: 12px; color: var(--ink-2); }
.jline b { font-weight: 650; color: var(--ink); }
.jform select, .jform input { width: 100%; }
.jform .is-missing { outline: 2px solid var(--bad); outline-offset: -2px; }
.rowmenu { position: relative; display: inline-block; text-align: left; }
.rowmenu > summary { list-style: none; cursor: pointer; }
.rowmenu > summary::-webkit-details-marker { display: none; }
/* In the flow, not floated: a table wrap scrolls and a flush panel clips, so
   an absolutely placed box on the last row would be cut off. */
.rowmenu__body { width: 260px; margin-top: 8px; display: flex; flex-direction: column; gap: 8px;
  padding: 12px; border-radius: var(--r-lg); background: var(--subtle); border: 1px solid var(--line); }
.rowmenu__body label { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.notes { display: flex; flex-direction: column; gap: 8px; margin: 0 0 20px; }
.form-actions .btn { white-space: nowrap; }
/* A segmented switch between two or three views of one screen (a return type). */
.seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: 8px; overflow: hidden; background: var(--paper); }
.seg__btn { display: inline-flex; align-items: center; height: 36px; padding: 0 14px; font-size: var(--t-small);
  font-weight: 600; color: var(--ink-2); }
.seg__btn + .seg__btn { border-left: 1px solid var(--line-2); }
.seg__btn:hover { text-decoration: none; color: var(--ink); background: var(--subtle); }
.seg__btn.is-on { background: var(--ink); color: #fff; }
/* Client requests (item 489): a queue of people, one row each. */
.reqlist { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.reqlist__row { display: flex; gap: 14px; align-items: flex-start; padding: 14px 20px; border-bottom: 1px solid var(--line); }
.reqlist__row:last-child { border-bottom: 0; }
.reqlist__row:hover { background: #FAFBFD; }
.reqlist__ico { flex: 0 0 auto; width: 36px; height: 36px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; background: #EEF4FF; color: var(--accent); }
.reqlist__ico.is-call { background: var(--good-wash); color: var(--good-ink); }
.reqlist__main { flex: 1 1 auto; min-width: 0; }
.reqlist__top { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.reqlist__kind { font-size: var(--t-small); color: var(--ink-2); }
.reqlist__text { margin: 4px 0 0; color: var(--ink-2); font-size: 13.5px; overflow-wrap: anywhere; }
.reqlist__meta { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 6px; font-size: 12px; color: var(--ink-3); }
.reqlist__meta span { display: inline-flex; align-items: center; gap: 4px; }
.reqlist__meta .ico { width: 13px; height: 13px; }
.reqlist__row > .btn { flex: 0 0 auto; align-self: center; }
/* Unknown senders (item 489): one row per person who wrote in. */
.qlist { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.qlist__row { display: flex; flex-direction: column; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--line); }
.qlist__row:last-child { border-bottom: 0; }
.qlist__who { display: flex; gap: 12px; align-items: center; }
.qlist__num { font-weight: 650; color: var(--ink); }
.qlist__meta { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center; font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.qlist__msg { align-self: flex-start; max-width: 640px; padding: 8px 12px; border-radius: 4px 12px 12px 12px;
  background: var(--subtle); border: 1px solid var(--line); overflow-wrap: anywhere; }
.qlist__type { display: block; font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3); }
.qlist__text { display: block; margin-top: 2px; color: var(--ink); }
.qlist__form { display: grid; grid-template-columns: minmax(200px, 2fr) minmax(140px, 1fr) minmax(160px, 1.4fr) auto;
  gap: 12px; align-items: end; }
.qlist__form label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
.qlist__form .btn { white-space: nowrap; }
@media (max-width: 900px) { .qlist__form { grid-template-columns: 1fr; } }
.qlist__row > .rowmenu { align-self: flex-start; }
.panel--flush > .pager { padding: 12px 20px; }
/* Client teams (item 492): one row per person on a client's team, and the
   add form with who, their chats, cover and why side by side. */
.teamlist { list-style: none; margin: 0 0 14px; padding: 0; border: 1px solid var(--line); border-radius: var(--r-lg); }
.teamlist__row { display: flex; gap: 12px; align-items: center; padding: 10px 14px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.teamlist__row:last-child { border-bottom: 0; }
.teamlist__row.is-lapsed { opacity: .6; }
.teamlist__who { flex: 1 1 200px; min-width: 0; }
.teamlist__chats { flex: 0 0 auto; }
.teamadd { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; align-items: end; }
.teamadd label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
.teamadd > .btn { justify-self: start; }
@media (max-width: 720px) { .teamadd { grid-template-columns: 1fr; } }
.checks { border: 0; padding: 0; margin: 12px 0; display: flex; flex-direction: column; gap: 6px; }
.checks legend { font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
.checks label { display: flex; gap: 8px; align-items: center; font-weight: 400; }
.checks input[type=checkbox] { width: auto; }
.im-people { list-style: none; margin: 4px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.im-people li { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 13px; }
.im-people form { margin: 0; }

/* Onboarding as a checklist (item 497): the overview row, and each step a
   folding panel that stays reachable once done. */
.obsteps { list-style: none; margin: 0 0 18px; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.obsteps a, .obsteps .step { display: inline-flex; align-items: center; gap: 8px; height: 34px; padding: 0 14px 0 6px;
  border-radius: 17px; border: 1px solid var(--line); background: var(--paper); color: var(--ink-2);
  font-size: var(--t-small); font-weight: 550; }
.obsteps a:hover { text-decoration: none; border-color: var(--line-2); color: var(--ink); }
.obsteps__n { width: 22px; height: 22px; border-radius: 50%; background: var(--subtle); color: var(--ink-3);
  display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; }
.obsteps .is-done .obsteps__n { background: var(--good); color: #fff; }
.obstep > summary { display: flex; align-items: center; gap: 12px; cursor: pointer; list-style: none; }
.obstep > summary::-webkit-details-marker { display: none; }
.obstep > summary .status { margin-left: auto; }
.obstep[open] > summary { margin-bottom: 14px; }
.obstep__n { width: 28px; height: 28px; border-radius: 50%; background: var(--ink); color: #fff; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; }
.obstep__t { font-size: var(--t-h3, 16px); font-weight: 650; color: var(--ink); }
.obstep__h { font-size: var(--t-body); margin: 18px 0 8px; }
.obstep__why { margin: 0 0 12px; color: var(--ink-2); }
.obsub { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--rule-2); }
.obsub > h2 { font-size: var(--t-body); }

/* The switcher is a link to the chooser page now (item 499), not a <details>. */
a.switcher { display: block; color: inherit; text-decoration: none; }
a.switcher:hover { text-decoration: none; }
a.switcher .switcher__face { display: flex; }

/* ── The client portal (item 505): the console's shell in the client's light.
   `body.console.portal` so every shell rule (drawer, sticky rail, topbar)
   applies, and only the colours change. */
body.portal .sidebar { background: var(--paper); color: var(--ink-2); border-right: 1px solid var(--line); }
body.portal .sidebar__lockup, body.portal .sidebar__lockup:hover { color: var(--ink); }
body.portal .sidenav__item { color: var(--ink-2); }
body.portal .sidenav__item .ico { color: var(--ink-4); }
body.portal .sidenav__item:hover { background: var(--subtle); color: var(--ink); }
body.portal .sidenav__item:hover .ico { color: var(--ink-2); }
body.portal .sidenav__item.is-on { background: #EEF4FF; color: var(--accent-ink, var(--accent)); font-weight: 600; }
body.portal .sidenav__item.is-on .ico { color: var(--accent); }
body.portal .sidenav__head--static { cursor: default; margin-top: 12px; }
body.portal .sidenav__head--static:hover { color: var(--ink-4); }
.pbiz { display: flex; align-items: center; gap: 10px; margin: 0 12px 12px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--canvas); }
.pbiz__avatar { flex: 0 0 auto; width: 32px; height: 32px; border-radius: 8px; background: var(--accent); color: #fff;
  display: inline-flex; align-items: center; justify-content: center; font-weight: 700; }
.pbiz__body { min-width: 0; display: flex; flex-direction: column; }
.pbiz__name { font-weight: 650; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pbiz__sub { font-size: 12px; color: var(--ink-3); font-family: var(--mono, monospace); }
.pside__foot { margin-top: auto; padding: 14px 16px 18px; font-size: 12px; line-height: 1.5; color: var(--ink-3);
  border-top: 1px solid var(--line); display: grid; gap: 6px; }
.topbar__title { font-weight: 600; color: var(--ink); }
body.portal .content > * { max-width: 1200px; }
.hero__list { margin: 8px 0 0; padding-left: 18px; display: grid; gap: 4px; font-size: 14px; color: var(--ink-2); }

.needlist { list-style: none; margin: 0; padding: 0; }
.needlist .needrow { padding: 14px 20px; border-top: 1px solid var(--rule-2); }
.needrow { display: flex; align-items: center; gap: 14px; }
.needrow__ico { flex: 0 0 auto; width: 36px; height: 36px; border-radius: 10px; background: var(--warn-wash); color: var(--warn);
  display: inline-flex; align-items: center; justify-content: center; }
.needrow__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.timeline-list li { grid-template-columns: 92px 1fr; }
.timeline-list b { white-space: nowrap; }

/* The day book's legs (item 502): Dr/Cr, the ledger, the amount. */
.legs { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; font-size: 13px; min-width: 260px; }
.legs li { display: grid; grid-template-columns: 24px 1fr auto; gap: 8px; }
.legs__side { color: var(--ink-4); font-weight: 600; }
.legs__amt { color: var(--ink-2); }

/* Portal reports and entries (item 505). */
.reports { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 16px; }
.report { display: flex; gap: 16px; align-items: flex-start; }
.report h2 { margin: 0 0 6px; font-size: 17px; }
.report__ico { flex: 0 0 auto; width: 42px; height: 42px; border-radius: 12px; background: #EEF4FF; color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; }
.report__body { min-width: 0; }
.report__list, .report__links { margin: 8px 0 14px; padding-left: 18px; display: grid; gap: 4px; color: var(--ink-2); }
.report__months { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.tiles--quiet .tile__value { font-size: 22px; }
.entrylist { list-style: none; margin: 0; padding: 0; }
.entrylist li { display: grid; grid-template-columns: minmax(64px, max-content) minmax(0, 1fr) auto; gap: 12px; align-items: baseline;
  padding: 10px 0; border-top: 1px solid var(--rule-2); }
.entrylist li:first-child { border-top: 0; }
.entrylist li > .tile__ico { position: static; align-self: start; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ── Page tabs (item 505) ─────────────────────────────────────────────────
 * Sibling pages of one area, underlined; `.tabs` above are filter pills. */
.pagetabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin: 0 0 20px;
  overflow-x: auto; scrollbar-width: none; }
.pagetabs a { padding: 10px 14px; font-size: var(--t-small); font-weight: 550; color: var(--ink-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap; }
.pagetabs a:hover { color: var(--ink); text-decoration: none; }
.pagetabs a.is-on { color: var(--ink); border-bottom-color: var(--ink); }
.acctlist { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.acct { border: 1px solid var(--line); border-radius: 14px; background: var(--paper); padding: 16px 18px; }
.acct.is-off { opacity: .6; }
.acct__head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.acct__name { font-weight: 600; }
.acct__num { font-family: var(--mono, monospace); color: var(--ink-3); font-size: var(--t-small); }
.acct__head .status { margin-left: auto; }

/* ── The organisation: hierarchy and matrices (item 505) ─────────────────── */
.orgtree { display: grid; gap: 18px; }
.orgtree__level { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; }
.orgtree__label { flex: 0 0 100%; font-size: var(--t-small); font-weight: 600; color: var(--ink-2); }
.orgtree__label .muted { font-weight: 400; }
.orgnode { display: inline-flex; flex-direction: column; gap: 2px; padding: 10px 14px; border: 1px solid var(--line);
  border-radius: 12px; background: var(--paper); color: var(--ink); min-width: 160px; font-size: var(--t-small); }
.orgnode:hover { border-color: var(--ink-3); text-decoration: none; }
.orgnode .muted { font-size: 12px; }
.orgnode--owner { border-color: var(--ink); }
.orgnode--small { min-width: 0; padding: 6px 10px; flex-direction: row; gap: 8px; align-items: baseline; }
.orgbranch { display: flex; flex-direction: column; gap: 8px; padding: 10px; border: 1px dashed var(--line); border-radius: 14px; }
.orgbranch__kids { display: flex; flex-wrap: wrap; gap: 6px; padding-left: 14px; border-left: 2px solid var(--line); }
table.matrix th.matrix__col { text-align: center; white-space: nowrap; font-size: 12px; }
table.matrix td.matrix__cell { text-align: center; }
table.matrix tr.matrix__group td { background: var(--subtle); font-weight: 600; font-size: var(--t-small); }
.mdot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--ink); vertical-align: middle; }
.mdot--chat { background: var(--ink); }
table.matrix td:first-child, table.matrix th:first-child { white-space: nowrap; }

.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.checklist li { display: flex; align-items: center; gap: 8px; font-size: var(--t-small); }
.checklist .ico { color: var(--good); flex: 0 0 auto; }

/* ── People and roles (Team accounts, item 513) ─────────────────────────── */
.peoplelist { list-style: none; margin: 0; padding: 0; }
.personrow { display: flex; align-items: center; gap: 14px; padding: 14px 20px; border-top: 1px solid var(--line); }
.personrow.is-off { opacity: .6; }
.personrow__who { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.personrow__meta { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 6px; font-size: var(--t-small); }
.personrow__menu .menu__panel { right: 0; left: auto; }
.chipnum { display: inline-flex; align-items: center; gap: 5px; padding: 2px 9px; border: 1px solid var(--line);
  border-radius: 999px; font-size: 12.5px; color: var(--ink-2); }
.chipnum .ico { width: 13px; height: 13px; }
.chipnum em { font-style: normal; color: var(--ink-3); }
.chipnum.is-off { text-decoration: line-through; opacity: .7; }
.capgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 6px 16px; margin-top: 12px; }
.capgrid__area { grid-column: 1 / -1; font-weight: 600; font-size: var(--t-small); color: var(--ink-2); margin-top: 8px; }
.capgrid__item { display: flex; align-items: center; gap: 8px; font-size: var(--t-small); font-weight: 400; }

/* ── The invoice composer's lines (item 505) ─────────────────────────────── */
.linegrid { display: grid; gap: 6px; }
.linegrid__head, .linegrid__row { display: grid; grid-template-columns: 3fr 1.2fr .8fr 1.2fr; gap: 8px; }
.linegrid__head span { font-size: 12px; font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; }
@media (max-width: 640px) { .linegrid__head { display: none; } .linegrid__row { grid-template-columns: 1fr 1fr; } }
/* Long role names wrap in a matrix header rather than running off it. */
table.matrix th.matrix__col { white-space: normal; max-width: 120px; line-height: 1.25; }

/* ── A form that opens when asked (`_ui.modal_close`, 25 Sep 2026) ──────────
 * The "Add" button at the top opens its form over the page, never a form
 * sitting open at the bottom. Native `popover`: no script, Esc and a click
 * outside close it. The hidden state is restated here because `.panel` and
 * `.settings` are author rules that would otherwise out-rank the browser's. */
.modal[popover]:not(:popover-open) { display: none; }
.modal[popover] { position: fixed; inset: 0; margin: auto; width: min(720px, calc(100vw - 32px));
  height: fit-content; max-height: calc(100dvh - 48px); overflow: auto;
  border: 1px solid var(--line); border-radius: 14px; background: var(--paper); color: var(--ink);
  box-shadow: 0 24px 64px rgba(16, 24, 40, .24); }
.modal[popover].panel { padding: 22px 24px 24px; }
.modal[popover].settings { padding: 0; }
.modal::backdrop { background: rgba(16, 24, 40, .45); }
.modal .setting { grid-template-columns: 1fr; gap: 14px; padding: 24px 24px 26px; border: 0; }
.modal .setting__body { max-width: none; }
.modal .panel__head, .modal .setting__intro { padding-right: 40px; }
.modal button.modal__x { position: absolute; top: 12px; right: 12px; z-index: 1; width: 32px; height: 32px;
  display: grid; place-items: center; padding: 0; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink-3); font-size: 24px; line-height: 1; cursor: pointer; }
.modal button.modal__x:hover { background: var(--subtle); color: var(--ink); }
.modal--confirm[popover] { width: min(480px, calc(100vw - 32px)); }
.confirm__msg { margin: 0 0 18px; color: var(--ink-2); line-height: 1.55; }
.confirm__actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.confirm__actions form { margin: 0; }
.confirm__form { display: flex; gap: 8px; align-items: center; flex: 1 1 100%; }
.confirm__form input { flex: 1; min-width: 0; }

/* ── The pages before the portal opens (item 525) ──────────────────────────
 * Setting up a sign-in, a forgotten password, the first sign-in. The founder:
 * a clear form over a blurred picture of the portal, "static not real, just a
 * theme". `.gp-*` draws that picture from plain boxes; nothing in it is data. */
body.gatepage { margin: 0; min-height: 100vh; background: var(--canvas); font-family: var(--font);
  color: var(--ink); overflow-x: hidden; }
.gatepage__backdrop { position: fixed; inset: -24px; display: flex; gap: 0; filter: blur(7px) saturate(.9);
  opacity: .75; pointer-events: none; }
.gp-side { width: 256px; flex: none; background: var(--paper); border-right: 1px solid var(--line);
  padding: 28px 20px; display: flex; flex-direction: column; gap: 14px; }
.gp-brand { height: 28px; width: 120px; border-radius: 8px; background: var(--ink); margin-bottom: 10px; }
.gp-card { height: 64px; border-radius: 12px; background: var(--canvas); border: 1px solid var(--line); }
.gp-nav { height: 14px; border-radius: 7px; background: #E3E6EC; }
.gp-nav:nth-child(3n) { width: 70%; } .gp-nav:nth-child(4n) { background: #DCE6FB; }
.gp-main { flex: 1; padding: 28px 36px; display: flex; flex-direction: column; gap: 22px; }
.gp-top { height: 44px; border-radius: 10px; background: var(--paper); border: 1px solid var(--line); }
.gp-title { height: 30px; width: 38%; border-radius: 8px; background: #D5D9E0; }
.gp-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.gp-tile { height: 118px; border-radius: 14px; background: var(--paper); border: 1px solid var(--line); }
.gp-tile:first-child { background: #EAF1FE; }
.gp-panels { display: grid; grid-template-columns: 2fr 1fr; gap: 18px; flex: 1; }
.gp-panel { border-radius: 14px; background: var(--paper); border: 1px solid var(--line);
  background-image: repeating-linear-gradient(180deg, transparent 0 46px, #EEF0F4 46px 47px); }
.gatepage__stage { position: relative; min-height: 100vh; display: grid; place-items: center; padding: 32px 16px;
  background: rgba(245, 246, 248, .35); }
.gatepage__card { width: min(480px, 100%); background: var(--paper); border: 1px solid var(--line);
  border-radius: 20px; padding: 32px 30px 28px; box-shadow: 0 30px 70px -30px rgba(16, 24, 40, .45); }
.gatepage__brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 17px; margin-bottom: 20px; }
.gatepage__brand img { width: 28px; height: 28px; }
.gatepage__card h1 { margin: 0 0 6px; font-size: 24px; letter-spacing: -.02em; }
.gatepage__lead { margin: 0 0 20px; color: var(--ink-2); line-height: 1.55; font-size: 14.5px; }
.gatepage__form { display: flex; flex-direction: column; gap: 14px; }
.gatepage__form label { margin: 0; }
.gatepage__form .btn { height: 44px; justify-content: center; font-size: 15px; }
.gatepage__agree { display: flex; gap: 10px; align-items: flex-start; font-size: 14px; color: var(--ink); font-weight: 500; }
.gatepage__agree input { width: 18px; height: 18px; margin-top: 1px; flex: none; }
.gatepage__foot { margin: 16px 0 0; font-size: 13px; color: var(--ink-3); line-height: 1.5; text-align: center; }
.gatepage__terms { max-height: none; line-height: 1.6; font-size: 14.5px; }
.gatepage__card--wide { width: min(820px, 100%); }
@media (max-width: 760px) { .gp-side { display: none; } .gp-tiles { grid-template-columns: 1fr 1fr; } }

/* PROVE YOUR EMAIL (item 525 slice B): the first and largest thing on the
   page until the address is proved, so it reads as a step, not a notice. */
.verifymail { padding: 16px 18px; border-width: 1.5px; }
/* The founder, 28 Sep: the X that hides it off the dashboard. */
.verifymail { position: relative; }
.verifymail__hide { position: absolute; top: 8px; right: 8px; margin: 0; }
.verifymail__hide .btn { font-size: 18px; line-height: 1; padding: 2px 8px; }
.verifymail__body { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
.verifymail__title { font-size: 17px; color: var(--ink, inherit); }
.verifymail__note { font-weight: 600; }
.verifymail__note--bad { color: var(--bad); }
.verifymail__forms { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 4px; }
.verifymail__code { display: flex; gap: 8px; align-items: center; }
.verifymail__code input { width: 13ch; box-sizing: border-box; height: 32px; min-height: 0; font: 600 17px/1 var(--mono, ui-monospace, monospace);
  letter-spacing: .18em; padding: 4px 9px; border: 1px solid var(--line, #d5d9e0);
  border-radius: var(--r-md, 8px); background: #fff; color: inherit; }

/* ASK FOR MORE (item 529): at the allowance, the door to Ledgior. */
.askmore { display: flex; flex-wrap: wrap; gap: 12px 18px; align-items: center; justify-content: space-between; padding: 14px 18px; }
.askmore__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 320px; }
.askmore__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.askmore__actions form { margin: 0; }

/* YOUR WHATSAPP (item 529 part 3): the person's own numbers, the link that
   connects a waiting one, and the QR a phone camera reads. */
.wa-open { display: flex; flex-wrap: wrap; gap: 18px; align-items: center; justify-content: space-between; padding: 18px 20px; }
.wa-open__text { flex: 1 1 320px; min-width: 0; }
.wa-open__text h2 { margin: 0 0 4px; font-size: 18px; text-transform: none; letter-spacing: 0; color: var(--ink); }
.wa-open__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.wa-qr { width: 148px; flex: none; background: #fff; padding: 6px; border-radius: var(--r-md, 8px); border: 1px solid var(--line); }
.wa-qr svg { display: block; width: 100%; height: auto; }
.wa-qr--sm { width: 120px; }
.wa-nums { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.wa-num { border: 1px solid var(--line); border-radius: var(--r-lg, 10px); padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.wa-num--pending { border-color: #FCE3B4; background: var(--warn-wash); }
.wa-num--off { opacity: .7; }
.wa-num__head { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.wa-num__connect { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.wa-num form { margin: 0; }
.wa-steps { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 3px; }
.chipnum.is-wait { border-style: dashed; }

/* ADD A PERSON, STEP BY STEP (item 529 part 2): numbered steps, the roles as
   cards that say what each may do, and the closing screen's next steps. */
.steps { display: flex; flex-direction: column; gap: 14px; max-width: 860px; }
.step { display: flex; gap: 16px; padding: 18px 20px; border: 1px solid var(--line); border-radius: var(--r-lg, 10px); background: var(--surface, #fff); }
.step__num { flex: none; align-self: flex-start; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; background: var(--wash); color: var(--accent-ink); }
.step__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.step__body h2 { margin: 0; font-size: 17px; text-transform: none; letter-spacing: 0; color: var(--ink); }
.step__body > p { margin: 0; }
.step__field { display: flex; flex-direction: column; gap: 4px; max-width: 420px; }
.steps__go { display: flex; justify-content: flex-end; }
.rolepick { border: 0; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }
.rolepick legend { font-weight: 600; margin-bottom: 6px; }
.rolepick__opt { position: relative; display: block; cursor: pointer; }
.rolepick__opt input { position: absolute; opacity: 0; }
.rolepick__card { display: flex; flex-direction: column; gap: 5px; height: 100%; padding: 12px 14px; border: 1.5px solid var(--line); border-radius: var(--r-md, 8px); }
.rolepick__opt input:checked + .rolepick__card { border-color: var(--accent, #2563EB); box-shadow: 0 0 0 3px var(--wash); }
.rolepick__opt input:focus-visible + .rolepick__card { outline: 2px solid var(--accent, #2563EB); outline-offset: 2px; }
.rolepick__card .status { align-self: flex-start; }
.rolepick__may { color: var(--ink-2); font-size: 13px; line-height: 1.45; }
.nextsteps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; max-width: 860px; }
.nextstep { padding: 16px 18px; border: 1px solid var(--line); border-radius: var(--r-lg, 10px); display: flex; flex-direction: column; gap: 8px; }
.nextstep p { margin: 0; }
.nextstep form { margin: 0; }

/* A WHATSAPP NUMBER: the searchable country box, then the number. */
.phonefield { display: inline-flex; gap: 6px; align-items: center; max-width: 100%; }
.phonefield__cc { width: 11ch; min-width: 0; }
.phonefield__num { width: 16ch; min-width: 0; }

/* The chosen client can be put down (25 Sep): a quiet link under the
   switcher, and the Dashboard above it, belonging to no client. */
body.console .switcher__clear { display: block; margin: -4px 12px 10px; padding: 4px 10px;
  font-size: var(--t-small, 13px); color: var(--on-ink-2, #b9c0cc); text-decoration: none; border-radius: var(--r); }
body.console .switcher__clear:hover { color: var(--on-ink, #fff); background: rgba(255,255,255,.06); }
body.console .sidenav--top { flex: 0 0 auto; margin-bottom: 6px; }
html.rail-collapsed body.console .switcher__clear { display: none; }

/* A review item in words, and the bill beside what was read (25 Sep). */
.plainwhy { font-size: var(--t-h3, 16px); color: var(--ink); margin: 0 0 6px; }
.billside { margin-top: 14px; align-items: start; }
.billside__img { display: block; max-width: 100%; max-height: 560px; margin: 6px 0;
  border: 1px solid var(--line); border-radius: var(--r); }

/* A client's question and its standard reply (#H205): what they asked and
   the reply on the left, the chat on the right. */
.answer { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 18px; align-items: start; }
.answer__main { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.answer__main .panel, .answer__chat { margin: 0; }
.answer__said { margin: 0 0 8px; padding: 10px 14px; border-left: 3px solid var(--accent, #2563EB);
  background: var(--wash); white-space: pre-wrap; }
.answer__numbers { list-style: none; margin: 0 0 10px; padding: 0; }
.stdreply__choices { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.stdreply__choice { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.stdreply__choice input { width: auto; margin-top: 4px; }
.stdreply__preview { padding: 10px 14px; border: 1px dashed var(--line); border-radius: var(--r); }
.stdreply__preview p { margin: 4px 0 0; }
.qthread { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px;
  max-height: 560px; overflow-y: auto; min-height: 0; }
.qthread__msg { display: flex; flex-direction: column; gap: 2px; max-width: 90%; padding: 8px 12px; border-radius: var(--r); }
.qthread__msg.is-in { align-self: flex-start; background: var(--wash); }
.qthread__msg.is-out { align-self: flex-end; border: 1px solid var(--line); }
.qthread__who { font-size: 12px; color: var(--ink-2); }
.qthread__body { white-space: pre-wrap; overflow-wrap: anywhere; }
@media (max-width: 900px) { .answer { grid-template-columns: minmax(0, 1fr); } }

/* Item 680: the expense heads list -- a row is dragged by its grip. */
.headrow { cursor: grab; }
.headrow.is-dragging { opacity: .45; }
.headrow__grip { color: var(--ink-3); letter-spacing: -2px; margin-right: 4px; }
.headorder__save { display: flex; gap: 12px; align-items: center; margin: 0 20px 12px; }
.headorder__save[hidden] { display: none; }
form.inline { display: inline; }
