/* ============================================================
   NOVERA.Software — app.css (adaptation layer)
   tokens.css is the LOCKED design system (shared with mockups).
   This file only adapts the fixed 390x844 mockup ".phone" frame
   to a fluid, full-viewport app shell. No styling decisions here.
   ============================================================ */
b {
    font-weight: 400 !important;
}

.app {
    position: relative;
    width: 100%;
    min-height: 75dvh;
    margin: 0 auto;
    overflow-x: clip;
    /*background: radial-gradient(120% 60% at 72% -15%, rgba(47,111,200,.34), transparent 62%), radial-gradient(90% 45% at 6% 6%, rgba(64,120,255,.15), transparent 60%), radial-gradient(80% 40% at 108% 52%, rgba(80,110,220,.13), transparent 65%), radial-gradient(100% 50% at 50% 115%, rgba(47,127,214,.15), transparent 62%), linear-gradient(180deg,#0b1326,#0a0f1e);*/
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 50%, #13294B 100% 100% );
    display: flex;
    flex-direction: column;
    max-width: 768px;
}

/* Phone-width column on larger screens (mobile-first: full width below 480px) */
@media (min-width: 480px) {
    .app {
        max-width: 480px;
        box-shadow: 0 0 60px rgba(0,0,0,.5);
    }

    body {
        background: var(--nv-bg-deep);
    }
}

.app .scroll {
    /*padding-bottom: 120px;*/
}

/* Owner fix (2026-08-08, screenshot): fixed positioning is viewport-relative,
   so on wide screens the nav hugged the LEFT edge — centre it in the same
   480px column as the app. */
.app .bottomnav {
    position: fixed;
    left: 0;
    right: 0;
    /* v18.5 (batch95, owner report) — pinned + raised EXPLICITLY so no
       later rule or stacking context can lose the footer: bottom was
       inherited from tokens only, and z-index 5 sat below the heads. */
    bottom: 0;
    z-index: 30;
    margin: 0 auto;
    /*max-width: 480px;*/ /* owner */
    width: 100%; /* owner */
}

.app .home-indicator {
    position: fixed;
    max-width: inherit;
}

/* Language switcher buttons built by i18n.js (buildSwitcher) — styled as chips */
.lang-btn {
    height: 48px;
    min-width: 48px;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid rgba(104,152,232,.28);
    color: var(--nv-ink-2);
    font-family: inherit;
    font-size: var(--fs-caption);
    font-weight: 200;
    background: linear-gradient(160deg,rgba(120,165,240,.08),rgba(255,255,255,.02));
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

    .lang-btn.active {
        background: rgba(232,167,92,.14);
        border-color: rgba(232,167,92,.45);
        color: var(--nv-gold-bright);
        font-weight: 200;
    }

/* ── Home page layout (from mockup 02, round 5) ─────────────── */
.app .scroll {
    overflow: visible;
    flex: initial;
}

.hb {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    /* owner (2026-08-09): header bottom padding ≥10px everywhere */
    padding: 14px 20px 10px;
}

    .hb .hi {
        font-size: 16px;
        color: var(--nv-ink-2);
    }

    .hb h1 {
        font-size: 24px;
        font-weight: 400; /* owner (2026-08-11 v10) */
        line-height: 1.15;
        color: var(--nv-ink);
    }

        .hb h1 .dot {
            color: var(--nv-gold);
        }

/*  ⚠ v31.158 — `.brand` (the logo link in the header and the side rail) had no
    base rule anywhere, only responsive overrides, so as an <a> it carried UA
    link blue and an underline on EVERY page in the solution. It is inert today
    because the element contains nothing but an <img> and an underline under an
    image paints nothing — it is fixed because a wrong rule that is currently
    invisible is still a wrong rule, and this is the same v29.6 ruling as
    `.chip`, `.more` and `.iconbtn`. Nothing about the logo's rendering changes. */
.brand { text-decoration: none; color: inherit; }

.iconbtn {
    width: 48px;
    height: 48px;
    /* v18.3 (batch93, owner — TOOLKIT): ONE radius, 6px, like the inputs */
    border-radius: 6px;
    border: 1px solid rgba(104,152,232,.24);
    background: rgba(255,255,255,.03);
    /*  ⚠ v31.158 — same v29.6 ruling as `.chip` and `.more`. Latent rather
        than visible today, because every `.iconbtn` currently holds an SVG and
        an underline under an icon paints nothing — but the first one given a
        text label would have shown it. */
    text-decoration: none;
    color: var(--nv-gold);
    display: flex;
    align-items: center;
    justify-content: center;
}

.org {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    height: 32px;
    padding: 0 12px;
    border-radius: var(--r-pill);
    background: rgba(232,167,92,.10);
    border: 1px solid rgba(232,167,92,.25);
    color: var(--nv-gold-bright);
    font-size: 15px;
    font-weight: 200;
}

.home-scroll {
    gap: 10px;
    padding-top: 8px;
}

    .home-scroll .card {
        padding: 14px 18px;
    }

        .home-scroll .card.tight {
            padding: 8px 16px;
        }

    .home-scroll .row {
        min-height: 48px;
        padding: 2px 0;
    }

        .home-scroll .row .ic {
            flex-basis: 40px;
            height: 40px;
        }

/* owner */
@media (max-width: 480px) {
    .home-scroll .row.hide {
        display: none;
    }

    .hb .hi {
        display: none;
    }

    .app .scroll {
        padding-bottom: 0px;
    }

    .dash-pager {
        border-bottom: 0;
    }

    .card {
        max-width: 347px;
    }
}

.chart-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 6px;
}

.legend {
    display: flex;
    gap: 18px;
    margin-top: 10px;
}

    .legend span {
        display: inline-flex;
        align-items: center;
        gap: 7px;
        font-size: 15px;
        color: var(--nv-ink-2);
    }

    .legend i {
        width: 9px;
        height: 9px;
        border-radius: 50%;
        display: inline-block;
    }

.apps-row {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    gap: 12px;
}

.app-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-height: 78px;
    text-decoration: none;
}

    /* v27.2 (PRODUCTION TICKET 20260821002 item 1.1, owner): tile icons carry
       NO background - the same flat treatment adopted everywhere else. */
    .app-tile .ic {
        width: 52px;
        height: 52px;
        border-radius: 8px;
        background: transparent;
        backdrop-filter: blur(12px);
        border: 1px solid rgba(232,167,92,.26);
        display: flex;
        align-items: center;
        justify-content: center;
        color: var(--nv-gold);
    }

/* ═══ v29.0 (owner: "In Favourite apps can we apply C5 to the icons?") ══════
   THE CONIC HALO ON THE FAVOURITE-APP ICONS, so Home, the financials hub and
   every ghost button now share one edge treatment instead of three.

   ⚠ FLAGGED DIVERGENCE, one line: these use the LIVE variant of C5 (gold at
   both ends), not the dormant one. The icons are gold-bordered and gold-drawn
   today, and the dormant gradient is blue-led - applying it literally would
   have turned every favourite icon blue, which is a bigger change than was
   asked for. The live variant keeps the gold identity and adds the turn.

   ⚠⚠ NO FILL HERE. The tile study carries a 5% radial to stop its halo
   reading as detached; these icons must NOT get one. v27.2 removed their
   background deliberately ("tile icons carry NO background - the same flat
   treatment adopted everywhere else") and that ruling stands. The ring is the
   whole change.

   ⚠⚠⚠ THE @supports GUARD IS LOAD-BEARING: without mask-composite the
   ::before is a filled rectangle, not a ring - a gold block where the icon
   should be. Guarded, an unsupported browser keeps the 1px gold border above,
   exactly as today. */
@supports ((-webkit-mask-composite: xor) or (mask-composite: exclude)) {
    .app-tile .ic {
        position: relative;
        isolation: isolate;
        border-color: transparent;
    }

        .app-tile .ic::before {
            content: "";
            position: absolute;
            inset: 0;
            border-radius: inherit;
            padding: 1px;
            background: conic-gradient(from 210deg, var(--nv-gold-bright), rgba(47,127,214,.55) 25%, rgba(232,167,92,.20) 50%, rgba(47,127,214,.55) 75%, var(--nv-gold-bright));
            -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            -webkit-mask-composite: xor;
            mask-composite: exclude;
            pointer-events: none;
        }
}

    .app-tile .lbl {
        font-size: 15px;
        font-weight: 300; /* owner (2026-08-11 v10) */
        color: var(--nv-ink-2);
        text-align: center;
        line-height: 1.25;
    }

/* ── Language pager (round 5: ‹ 3 chips › + page dots) ──────── */
.lang-pager {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

.lang-pager-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.lang-pager .chip {
    font-family: inherit;
}

.lang-pager .lang-chip {
    padding: 0 15px;
}

.lang-pager .lang-arrow {
    padding: 0;
    width: 48px;
    justify-content: center;
}

.lang-pager .chip.active {
    background: rgba(232,167,92,.14);
    border-color: rgba(232,167,92,.45);
    color: var(--nv-gold-bright);
    font-weight: 200;
}

.lang-dots {
    display: flex;
    justify-content: center;
    gap: 6px;
}

.lang-dot {
    width: 8px;
    height: 4px;
    border-radius: 2px;
    background: rgba(255,255,255,.18);
    transition: all .25s;
}

    .lang-dot.on {
        width: 16px;
        background: rgba(232,167,92,.75);
    }

/* ── Real form inputs + login error ─────────────────────────── */
input.input {
    display: block;
}

    input.input::placeholder {
        color: var(--nv-ink-3);
    }

    input.input:focus {
        outline: none;
        border-color: var(--nv-blue-bright);
        box-shadow: 0 0 0 3px rgba(47,127,214,.25);
    }

.login-error {
    border: 1px solid rgba(217,101,101,.45);
    background: rgba(217,101,101,.12);
    color: #e79a9a;
    border-radius: 14px;
    padding: 12px 16px;
    font-size: 15px;
}

/* ⚠ v31.46 (batch243) - THE SAYS-IT-WORKED TWIN OF `.login-error`.
   Slice 1b gave the app its first account write, and a write has to be able to
   report SUCCESS as visibly as failure - a save that says nothing is a save the
   reader has to go and verify.
   ⚠⚠ IT EXISTS BECAUSE THE MARKUP ASKED FOR IT AND THE CLASS DID NOT. The page
   was written against `.login-ok` on the assumption it matched `.login-error`;
   it did not, and the banner would have rendered as bare unstyled text. Caught
   by grepping the stylesheet for the class rather than by looking at the page -
   an unstyled element still renders, so nothing would have looked broken.
   ⚠ Same geometry as its sibling, deliberately: the two banners appear in the
   same slot and must not resize the page as they swap. Green is `--nv-good`,
   the token the ticks and matched rows already use. */
.login-ok {
    border: 1px solid rgba(63,202,133,.45);
    background: rgba(63,202,133,.12);
    color: #7fdcae;
    border-radius: 14px;
    padding: 12px 16px;
    font-size: 15px;
}

/* ── Dashboard flip card (Cash Flow ⇄ Bank Balances) ────────── */
.flip {
    perspective: 1400px;
}

.flip-inner {
    position: relative;
    transition: transform .7s cubic-bezier(.25,.6,.3,1);
    transform-style: preserve-3d;
    /* Fixed card height (owner): Bank Balances is 270px tall; a longer
       account list scrolls inside .bank-list instead of growing the card. */
    min-height: 250px; /* owner */
    height: 250px; /* owner */
}


.flip.is-flipped .flip-inner {
    transform: rotateY(180deg);
}

.flip-face {
    position: absolute;
    inset: 0;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.flip-front {
    transform: rotateY(0deg);
}

.flip-back {
    transform: rotateY(180deg);
}

.flip .card {
    display: flex;
    flex-direction: column;
    overflow: hidden; /* fixed-height faces never spill */
}

.flip-dots {
    display: flex;
    justify-content: center;
    gap: 6px;
    margin-top: auto;
    padding-top: 10px;
}

    .flip-dots span {
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: rgba(255,255,255,.20);
    }

        .flip-dots span.on {
            background: var(--nv-gold);
        }

.bank-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 6px;
    /* the list takes the space left in the fixed-height card and scrolls */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /*  ⚠⚠⚠ v31.31 (batch227, owner: "we do not need horizontal scroll.
        Horizontal scroll = none for the card") - THIS LINE IS NOT DECORATION.
        `overflow-y: auto` ALONE MAKES BOTH AXES SCROLLABLE: a box cannot be a
        scroll container on one axis and `visible` on the other, so the CSS
        `overflow-x: visible` this rule never set was computed to `auto` and
        the list has been a horizontal scroller since it was written. Naming
        the axis is what closes it, and it also stops any future long row from
        quietly re-opening it. */
    overflow-x: hidden;
}

.bank-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    /*  v31.31 - the 6px side padding used to live only on the openable rows
        (as a negative margin, which overflowed the list - see below). It sits
        on EVERY row now, so the hover tint has room inside the list and the
        plain rows, the openable rows and the Net position line all stay on the
        same left and right edges. */
    padding: 5px 6px;
}

/*  v31.30 (batch226, owner: "make the accounts clickable ... lead you to the
    reconciliation") - the openable variant of a bank row.
    ⚠ IT MUST NOT LOOK LIKE A LINK AT REST. The card is a list of figures and
    an underlined blue run through the middle of it would read as damage; the
    row keeps its own type and colour and earns a tell only under the pointer.
    ⚠ THE TELL IS A BACKGROUND, NOT AN UNDERLINE - `.bank-name` already
    ellipses, and an underline under a clipped name is a second thing going
    wrong in the same 15px.
    ⚠⚠ v31.31: THE NEGATIVE MARGIN IS GONE. It was `margin: 0 -6px` so the
    tint could bleed into the card's padding, which made every openable row
    12px WIDER THAN THE LIST THAT HOLDS THEM - one of the three things putting
    a horizontal scrollbar under this card. The padding moved onto `.bank-row`
    instead, where every row shares it and nothing overflows.
    ⚠ A ROW THAT CANNOT RESOLVE TO ONE ACCOUNT NEVER GETS THIS CLASS - see
    BankBalance.CanOpen. */
a.bank-row.bank-open {
    text-decoration: none;
    color: inherit;
    border-radius: 6px;
    cursor: pointer;
}

    a.bank-row.bank-open:hover,
    a.bank-row.bank-open:focus-visible {
        background: rgba(232,167,92,.10);
        outline: none;
    }

        a.bank-row.bank-open:hover .bank-name,
        a.bank-row.bank-open:focus-visible .bank-name {
            color: var(--nv-gold-bright, #f2bc74);
        }

.bank-name {
    font-size: 15px;
    color: var(--nv-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /*  ⚠⚠⚠ v31.31 (owner) - `text-overflow` WAS ALREADY HERE AND HAS NEVER
        DRAWN. THE ELLIPSIS ONLY APPEARS ON A BOX THAT ACTUALLY OVERFLOWS, and
        a flex item's automatic minimum size is its MIN-CONTENT: "Bankové účty
        - VÚB - MasterCard Business World" refused to shrink, so the ROW grew
        past the list instead and the name was never clipped - there was
        nothing to clip, only something to scroll to.
        ⚠ `min-width: 0` ALONE IS NOT ENOUGH HERE - the same lesson as the
        email subject line: the item must also be told it may SHRINK, so
        `flex: 1 1 0` and the amount beside it keeps its natural width. */
    flex: 1 1 0;
    min-width: 0;
}

.bank-amt {
    font-size: 16px;
    font-weight: 200;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

    .bank-amt.pos {
        color: var(--acc-green,#3fca85);
    }

    .bank-amt.neg {
        color: #e79a9a;
    }

.bank-total .bank-name {
    font-weight: 200;
    color: var(--nv-gold);
}

.bank-total .bank-amt {
    font-size: 18px;
}


/* ============================================================
   Feature styling folded in from the old features.css / module
   files (owner now owns ALL edits; single-file scheme dropped).
   ============================================================ */

/* ── 1) FORM CONTROLS ───────────────────────────────────────────
   tokens.css leaves the .input background commented out, so native
   <input>/<select>/<textarea> fall back to the browser's white.
   Give them the dark glass fill and neutralise Chrome/Edge/Safari
   autofill (which otherwise repaints the field white/pale-yellow).
   Only real form controls are targeted — the div-based .input
   display rows are untouched. ── */
input.input,
textarea.input,
select.input {
    background-color: #101a30; /* --nv-surface, opaque: never white */
    background-image: linear-gradient(160deg, rgba(120,165,240,.07), rgba(255,255,255,.012));
    color: var(--nv-ink);
}

    input.input::placeholder,
    textarea.input::placeholder {
        color: var(--nv-ink-3);
    }

    input.input:-webkit-autofill,
    input.input:-webkit-autofill:hover,
    input.input:-webkit-autofill:focus,
    input.input:-webkit-autofill:active {
        -webkit-text-fill-color: var(--nv-ink);
        -webkit-box-shadow: 0 0 0 1000px #101a30 inset;
        box-shadow: 0 0 0 1000px #101a30 inset;
        caret-color: var(--nv-ink);
        transition: background-color 100000s ease 0s; /* hold the fill, no white flash */
    }


/* ── 2) EMAIL PAGES ─────────────────────────────────────────── */
a.mail {
    text-decoration: none;
    color: inherit;
}

.mail {
    display: flex;
    gap: 14px;
    padding: 14px 0;
    min-height: 76px;
    align-items: flex-start;
}

    .mail + .mail {
        border-top: 1px solid rgba(104,152,232,.13);
    }

    .mail .av {
        flex: 0 0 46px;
        height: 46px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: 200;
        font-size: 17px;
        background: rgba(232,167,92,.16);
        color: var(--nv-gold-bright);
    }

        /* Per-sender avatar colours — the Novera.Apartments palette (eml-av
       g0…g4); the class is picked by a stable hash of the sender. */
        .mail .av.g0 {
            background: #33526b;
            color: #e9eef7;
        }

        .mail .av.g1 {
            background: #6d5a8e;
            color: #e9eef7;
        }

        .mail .av.g2 {
            background: #2e7d64;
            color: #e9eef7;
        }

        .mail .av.g3 {
            background: #9a6a16;
            color: #f4ecdc;
        }

        .mail .av.g4 {
            background: #874a52;
            color: #f4e5e7;
        }

    .mail .body {
        flex: 1;
        min-width: 0;
    }

    .mail .l1 {
        display: flex;
        align-items: baseline;
        gap: 8px;
    }

    .mail .from {
        flex: 1;
        min-width: 0;
        font-size: 18px;
        font-weight: 200;
        color: var(--nv-ink);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .mail.read .from {
        font-weight: 200;
        color: var(--nv-ink-2);
    }

    .mail .when {
        font-size: 15px;
        color: var(--nv-ink-3);
        white-space: nowrap;
    }

    .mail .subj {
        font-size: 15.5px;
        color: var(--nv-ink-2);
        line-height: 1.4;
        margin-top: 2px;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .mail.read .subj {
        color: var(--nv-ink-3);
    }

    .mail .meta {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-top: 5px;
    }

.dot-unread {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--acc-green);
}

.tag {
    font-size: 15px;
    font-weight: 200;
    padding: 2px 9px;
    border-radius: var(--r-pill);
}

    .tag.att {
        background: rgba(47,127,214,.16);
        color: #8fc0f0;
    }

    .tag.fail {
        background: rgba(217,101,101,.16);
        color: #e79a9a;
    }

.email-body {
    /* Owner (2026-08-07): received HTML mail is designed for a light page —
       render it on white with black text, like a classic mail client. */
    background: white;
    color: black;
    font-size: 16px;
    line-height: 1.6;
    overflow-wrap: anywhere;
    word-break: break-word;
    /* HTML emails arrive with fixed-width layouts — everything must stay
       INSIDE the card. Anything wider scrolls horizontally within the card
       instead of spilling over the page. */
    overflow-x: auto;
    max-width: 100%;
}

    .email-body a {
        color: #1d6fd1; /* readable link blue on the white body */
    }

    .email-body img {
        max-width: 100% !important;
        height: auto !important;
    }

    .email-body table {
        max-width: 100% !important;
        height: auto !important;
    }

    .email-body td, .email-body th, .email-body div, .email-body p,
    .email-body span, .email-body blockquote {
        max-width: 100% !important;
    }

    .email-body pre {
        white-space: pre-wrap;
        overflow-wrap: anywhere;
    }

textarea.input {
    display: block;
}

/* ── 4) CALENDAR ────────────────────────────────────────────── */
.cal-head {
    display: flex;
    align-items: center;
    gap: 12px;
    justify-content: space-between;
    /* owner (2026-08-09): header bottom padding ≥10px everywhere */
    padding: 12px 20px 10px;
    position: sticky;
    top: 0;
    z-index: 20;
    background: linear-gradient(180deg, rgba(8,12,24,.94), rgba(8,12,24,.80));
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
}

    .cal-head h1 {
        font-size: 24px;
        font-weight: 100;
        flex: 1;
    }

    .cal-head .iconbtn {
        flex: 0 0 44px;
    }

.navbtn {
    width: 40px;
    height: 40px;
    border-radius: 12px;
    border: 1px solid rgba(104,152,232,.24);
    background: rgba(255,255,255,.03);
    color: var(--nv-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}

.month {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 20px 8px;
    /* v8.0 (owner) — separator + breathing room above the month row */
    border-top: 1px solid rgba(104, 152, 232, .18);
    padding-top: 12px;
    position: relative;
    z-index: 2;
}

    .month .m {
        font-size: 20px;
        font-weight: 200;
        color: var(--nv-gold-bright);
        min-width: 85px;
        text-align: center;
    }

.dow {
    display: grid;
    grid-template-columns: repeat(7,1fr);
    padding: 8px 14px 0;
    position: relative;
    z-index: 2;
    /* v7.2 (owner): subtle line separating the nav area from the week dates */
    border-top: 1px solid rgba(104,152,232,.18);
    margin: 6px 14px 0;
}

    .dow span {
        text-align: center;
        font-size: 15px;
        color: var(--nv-ink-3);
        padding: 4px 0;
    }

.grid {
    display: grid;
    grid-template-columns: repeat(7,1fr);
    gap: 3px;
    padding: 0 14px;
    position: relative;
    z-index: 2;
}

.day {
    aspect-ratio: 1/1.05;
    border-radius: 10px;
    border: 1px solid rgb(47 74 131);
    background: rgba(18,30,56,.28);
    padding: 5px 4px 3px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    overflow: hidden;
    text-decoration: none;
}

    .day .n {
        font-size: 15px;
        color: var(--nv-ink-2);
        text-align: right;
        line-height: 1;
    }

    .day.today {
        border-color: var(--nv-red);
    }

        .day.today .n {
            color: var(--nv-gold-bright);
            font-weight: 200;
        }

    .day.sel {
        background: rgba(232,167,92,.12);
        border-color: rgba(232,167,92,.45);
    }

.dots {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    margin-top: auto;
}

.ev {
    height: 4px;
    border-radius: 2px;
    flex: 1 1 auto;
    min-width: 8px;
}

.agenda {
    position: relative;
    z-index: 2;
    padding: 12px 20px 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

    .agenda .title {
        font-size: 16px;
        font-weight: 200;
        color: var(--nv-gold);
    }

.ev-row {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

    .ev-row .time {
        flex: 0 0 54px;
        font-size: 15px;
        color: var(--nv-ink-3);
        text-align: right;
        padding-top: 2px;
    }

.ev-card {
    flex: 1;
    min-width: 0; /* v7.2: lets the .em row ellipsise instead of overflowing */
    border-radius: 10px;
    padding: 10px 12px;
    background: rgba(18,30,56,.4);
    border-left: 3px solid var(--nv-gold);
    margin: 10px 14px; /* owner (batch126) */
}

    .ev-card .et {
        font-size: 15px;
        font-weight: 200;
        color: var(--nv-ink);
    }

        .ev-card .et.done {
            text-decoration: line-through;
            color: var(--nv-ink-3);
        }

    .ev-card .em {
        font-size: 15px;
        color: var(--nv-ink-3);
        margin-top: 1px;
        /* v7.2 (owner): the account/category row stays on ONE line */
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

.legend-cal {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding: 12px 20px 120px;
    position: relative;
    z-index: 2;
}

    .legend-cal span {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        font-size: 15px;
        color: var(--nv-ink-2);
    }

    .legend-cal i {
        width: 10px;
        height: 10px;
        border-radius: 3px;
    }

.cal-head a.chip, .month a.chip, .cal-head a {
    text-decoration: none;
}

/* ── Calendar: view toggle + month grid (owner: default month + switch) ── */
.cal-views .chips {
    margin: 0;
}

.month-grid .day {
    aspect-ratio: 1 / 0.9;
}

.day.out {
    opacity: .34;
}

    .day.out .n {
        color: var(--nv-ink-3);
    }


/* ============================================================
   Email enhancements batch — mail bar, folders/confirm sheets,
   multi-select, toast, compose From selector. (Folded here; the
   old email.css is retired.)
   ============================================================ */
/* ── multi-select (owner: aligned as in Novera.Apartments — the
      tick is the trailing element on the right of each row, and a
      tick never opens the email) ───────────────────────────────── */
.eml-selrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 2px 0;
    min-height: 26px;
}

    .eml-selrow .sa {
        display: inline-flex;
        align-items: center;
        gap: 9px;
        font-size: 15px;
        color: var(--nv-ink-3);
    }

    .eml-selrow .cnt {
        font-size: 15px;
        color: var(--nv-ink-3);
    }

.mail .pick {
    flex: 0 0 auto;
    align-self: center;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    margin: -6px -6px -6px 2px;
}

input.eml-sel, input.eml-all, input.srch-opt, input.opt-tick, input.op-clbox {
    -webkit-appearance: none;
    appearance: none;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background-color: transparent;
    border: 1px solid rgba(232,167,92,.55);
    display: inline-grid;
    place-content: center;
    cursor: pointer;
    transition: border-color .12s, background-color .12s;
}

    input.eml-sel::before, input.eml-all::before, input.srch-opt::before, input.opt-tick::before, input.op-clbox::before {
        content: "";
        width: 12px;
        height: 12px;
        border-radius: 3px;
        transform: scale(0);
        transition: transform .12s ease;
        background: var(--nv-gold);
        box-shadow: 0 0 6px rgba(232,167,92,.5);
    }

    input.eml-sel:checked, input.eml-all:checked, input.srch-opt:checked, input.opt-tick:checked, input.op-clbox:checked {
        border-color: var(--nv-gold);
        background-color: rgba(232,167,92,.10);
    }

        input.eml-sel:checked::before, input.eml-all:checked::before, input.srch-opt:checked::before, input.opt-tick:checked::before, input.op-clbox:checked::before {
            transform: scale(1);
        }

.mail-bar .mb.disabled {
    opacity: .38;
    pointer-events: none;
}

.mail.picked {
    background: rgba(232,167,92,.06);
    border-radius: 10px;
}

/* ── sticky mail bar — the module owns the bar while in Email ── */
.mail-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0 auto;
    max-width: 480px;
    z-index: 9;
    height: 74px;
    padding: 8px 14px calc(8px + env(safe-area-inset-bottom));
    display: flex;
    align-items: stretch;
    gap: 8px;
    background: linear-gradient(180deg,rgba(11,16,32,0),rgba(8,12,24,.92) 55%);
    backdrop-filter: blur(20px) saturate(140%);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    border-top: 1px solid rgba(104,152,232,.20);
}

    .mail-bar .mb {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        border: 0;
        background: transparent;
        font-family: inherit;
        font-size: 15px;
        font-weight: 200;
        color: var(--nv-ink-3);
        text-decoration: none;
        border-radius: 12px;
        border: 1px solid;
    }

        .mail-bar .mb svg {
            width: 24px;
            height: 24px;
        }

        .mail-bar .mb.on {
            color: var(--nv-gold-bright);
        }

        .mail-bar .mb.cta {
            color: #241706;
            background: var(--nv-gold);
            border-radius: 14px;
            font-weight: 200;
        }

        .mail-bar .mb.danger {
            color: #f0b3b3;
            background: rgba(217,101,101,.16);
            border-radius: 14px;
            font-weight: 200;
            border: 1px solid var(--nv-warn);
        }

        .mail-bar .mb .n {
            font-variant-numeric: tabular-nums;
        }

/* ── slide-up sheets (folders + confirm), aligned to the column ─ */
.mail-scrim {
    position: fixed;
    inset: 0;
    z-index: 11;
    background: rgba(3,6,14,.62);
    backdrop-filter: blur(2px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s;
}

    .mail-scrim.on {
        opacity: 1;
        visibility: visible;
    }

/* v26.6 (owner) - THE SHEET IS A FLOATING CARD: the owner's radius,
   gradient and full border. v26.7 (owner): `140px auto` - floating AND
   CENTRED (the auto restores the horizontal centring that `140px 0`
   dropped; left:0/right:0 + max-width:480px need it). */
.mail-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* ⚠ v29.5 (owner) - THE SHEET'S TOP GAP IS PER SCREEN SIZE. The base is
       the SMALL-screen value (01/02/03-Screen); 04 and 05 raise it in
       responsive.css, which loads after this file and is where every
       breakpoint in the project lives. The `auto` on the horizontal side is
       load-bearing - it is what centres the sheet (left:0/right:0 with a
       max-width need it), so it stays in all four values. */
    margin: 20px auto !important;
    /* ⚠ v31.41 (batch238) - THE SAME NUMBER, READABLE BY THE CONTENT. A sheet
       whose body needs to cap its own height has to know how far off the
       bottom the sheet is sitting, and `margin` cannot be read from CSS. This
       custom property is re-declared beside each of the three overrides in
       responsive.css.
       ⚠⚠⚠ v31.83 - THEY ARE NOT THE SAME FACT, AND CALLING THEM ONE COST
       05-Screen the top of its sheet. The MARGIN lifts the sheet off the
       bottom; the GAP tells the sheet's body how short to be. Set them equal
       and the body grows back into exactly the room the margin made, leaving
       a fixed 20px at the top whatever the window height - which the sticky
       68px page header then covers. **The top gap you actually get is
       `gap - margin`.** 01/02/03/04-Screen are all small enough that the
       `60vh` half of the cap binds first and the question never arises; at
       ≥1920 it does, and that band now carries a gap 100px larger than its
       margin. ⚠ IF ONE OF THE FOUR MARGINS CHANGES, RE-DERIVE ITS GAP - do
       not simply copy the number across. */
    --sheet-gap: 20px;
    max-width: 480px;
    z-index: 12;
    transform: translateY(102%);
    transition: transform .26s cubic-bezier(.22,.61,.36,1);
    background: linear-gradient(145deg, #010107 -151%, #1E1E1E 50%, #13294B 100% 100%);
    backdrop-filter: blur(26px) saturate(140%);
    -webkit-backdrop-filter: blur(26px) saturate(140%);
    border: 1px solid var(--nv-ink-3);
    border-radius: 8px;
    padding: 10px 20px calc(30px + env(safe-area-inset-bottom));
    box-shadow: 0 -18px 48px rgba(0,0,0,.55);
}

    /* v9.1 (owner) — a closed sheet is fully HIDDEN, not just translated
       off-screen: its top shadow/blur peeked above the viewport bottom on
       tall displays (1920 profile sheet). Visibility flips after the slide. */
    .mail-sheet:not(.ent-sheet) {
        visibility: hidden;
        transition: transform .26s cubic-bezier(.22,.61,.36,1), visibility 0s .26s;
    }

    .mail-sheet.open {
        transform: translateY(0);
        visibility: visible;
        transition: transform .26s cubic-bezier(.22,.61,.36,1), visibility 0s;
    }

    .mail-sheet .grab {
        width: 44px;
        height: 5px;
        border-radius: 3px;
        background: rgba(255,255,255,.22);
        margin: 4px auto 14px;
    }

    .mail-sheet h2 {
        font-size: var(--fs-h2);
        font-weight: 200;
        color: var(--nv-gold);
        margin-bottom: 10px;
    }

/* folders list inside the sheet */
.fld {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 15px 6px;
    text-decoration: none;
    color: var(--nv-ink);
    font-size: 17px;
    font-weight: 200;
}

    .fld + .fld {
        border-top: 1px solid rgba(104,152,232,.13);
    }

    .fld.on {
        color: var(--nv-gold-bright);
    }

    .fld .fi {
        flex: 0 0 26px;
        height: 26px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: var(--nv-gold);
    }

    .fld .fl {
        flex: 1;
    }

    .fld .fc {
        font-size: 15px;
        font-weight: 200;
        color: var(--nv-ink-3);
        background: rgba(104,152,232,.14);
        border-radius: var(--r-pill);
        padding: 2px 10px;
        min-width: 26px;
        text-align: center;
    }

        .fld .fc.gold {
            color: var(--nv-gold-bright);
            background: rgba(232,167,92,.16);
        }

/* confirm sheet */
.confirm-sheet .ctext {
    font-size: 16px;
    color: var(--nv-ink-2);
    line-height: 1.5;
    margin-bottom: 18px;
}

.confirm-sheet .cact {
    display: flex;
    gap: 12px;
}

    .confirm-sheet .cact .btn {
        height: 54px;
        font-size: 17px;
    }

        .confirm-sheet .cact .btn.danger {
            background: var(--nv-danger);
            color: black;
            font-weight: 400;
            border: 0;
            min-width: 140px;
        }

/* ── toast ─────────────────────────────────────────────────── */
.mail-toast {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 92px;
    margin: 0 auto;
    max-width: 440px;
    z-index: 13;
    padding: 0 20px;
    pointer-events: none;
}

    .mail-toast .t {
        display: flex;
        align-items: center;
        gap: 10px;
        background: rgba(20,32,58,.94);
        border: 1px solid rgba(104,152,232,.32);
        border-radius: 14px;
        padding: 13px 16px;
        color: var(--nv-ink);
        font-size: 15px;
        box-shadow: 0 12px 34px rgba(0,0,0,.5);
        backdrop-filter: blur(18px);
        -webkit-backdrop-filter: blur(18px);
        animation: mailToastIn .28s ease, mailToastOut .4s ease 3.6s forwards;
    }

        .mail-toast .t svg {
            flex: 0 0 auto;
            color: var(--nv-gold);
        }

@keyframes mailToastIn {
    from {
        opacity: 0;
        transform: translateY(14px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes mailToastOut {
    to {
        opacity: 0;
        transform: translateY(14px);
    }
}

/* ── compose: From selector ────────────────────────────────── */
/*  ⚠⚠⚠ v31.53 (batch250, owner) - THE CHEVRON GETS THE HAIRLINE TOO.
    Owner: *"The down chevron EVERYWHERE should also implement the hairline
    divider everywhere."*

    ⚠ NO MARKUP CHANGES FOR THIS - and that is the whole reason it is safe to
    do in one go. The chevron is already a background layer, so the divider is
    a SECOND background layer on the same rule: one declaration, every
    `select.input` in the app, nothing to miss and nothing to convert.

    ⚠⚠ THE GEOMETRY IS THE SAME AS `.fld-go`, DELIBERATELY. There the button is
    32px wide and inset 2px, so the divider lands 34px from the right edge and
    the value stops at 46px. A select's chevron is 20px wide at `right 14px`,
    so its box also ends 34px from the right edge - the divider abuts it in
    exactly the same place, and `padding-right` moves 42 → 46 to match. Put a
    text field and a select side by side and the two hairlines line up.
    ⚠ 22px tall: the field is 32px and the divider is inset 5px top and bottom,
    the same inset `.fld-btn::before` uses. */
select.input {
    -webkit-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23e8a75c' stroke-width='1.6' stroke-linecap='round'><path d='m7 10 5 5 5-5'/></svg>"),
                      linear-gradient(rgba(112,160,238,.30), rgba(112,160,238,.30));
    background-repeat: no-repeat, no-repeat;
    /*  ⚠ v31.54 (batch251, owner): *"To center chevron visually, please change
        ... background-position: right 7px center, right 34px center."*
        AND THE ARITHMETIC AGREES WITH HIS EYE, which is worth writing down
        because the old number looked deliberate: the divider sits 34px from
        the right border, so the button zone IS that 34px. Centring a 20px
        chevron in it puts its centre at 17px and therefore its right edge at
        7px. The old `right 14px` had been chosen to make the chevron's box
        END exactly where the divider begins - tidy on paper, 7px too far left
        on screen. */
    background-position: right 7px center, right 34px center;
    background-size: auto, 1px 22px;
    padding-right: 46px;
}

/* Email list header: back-to-dashboard icon sits in front of the title. */
.screen-head.mail-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

    .screen-head.mail-head .htext {
        flex: 1;
        min-width: 0;
    }

/* Flow-page header (Message / Compose): static at the top with back nav. */
.flowhead {
    position: sticky;
    top: 0;
    z-index: 20;
    /* owner (batch82): background removed — the page gradient runs through
    background: linear-gradient(180deg, rgba(8,12,24,.94), rgba(8,12,24,.80)); */
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
}

/* Calendar: legend (dynamic, left) + "add new" button (right) share one row
   below the grid — v7.2 (owner); a subtle line separates it from the grid. */
.cal-addrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 10px 20px 0;
    padding: 10px 0 2px;
    /* v8.0 (owner) — separator moved up to .month */
    position: relative;
    z-index: 2;
}

    .cal-addrow .legend-cal {
        flex: 1;
        min-width: 0;
        padding: 0;
        gap: 10px;
    }

    .cal-addrow .cal-add {
        flex: 0 0 auto;
    }

.cal-add {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--nv-gold);
    color: #241706;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 8px 22px rgba(232,167,92,.28);
    text-decoration: none;
}

/* ── v6.9 batch (owner) ─────────────────────────────────────── */

/* AI disclosure rows (compose + event form): one row collapsed, expands
   to the controls. Native <details>, no JS. */
.airow {
    border: 1px solid rgba(104,152,232,.22);
    border-radius: var(--r-card);
    background: linear-gradient(160deg,rgba(120,165,240,.09),rgba(255,255,255,.015) 55%),rgba(13,22,42,.30);
}

    .airow > summary {
        list-style: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 10px;
        min-height: 36px; /* owner (batch83): dropdown rows 52 → 36 */
        padding: 0 16px;
        color: var(--nv-ink-2);
        font-size: 16px;
    }

        .airow > summary::-webkit-details-marker {
            display: none;
        }

        .airow > summary .chev {
            margin-left: auto;
            transition: transform .18s;
        }

    .airow[open] > summary .chev {
        transform: rotate(180deg);
    }

    .airow .airow-body {
        display: flex;
        flex-direction: column;
        gap: 10px;
        padding: 4px 16px 14px;
    }

    /*  ══ v31.246 (owner, P-25) — THE TWO FULL-WIDTH ROWS GET AIR ABOVE THEM ══
        Owner: *"add spacing above: Periods and Currency and rate … The current
        horizontal border/top edge of those controls is visually too close to
        the fields immediately above it, which makes the rows appear joined to
        the preceding controls."*

        ⚠⚠ IT IS SPACING ON THE ROW, NOT ON WHATEVER PRECEDES IT. The panel is a
        flex column whose `gap` is the same between every child, so the two
        disclosures read as another field in the stack rather than as a band
        across it. Giving the ROW the margin means the rule travels with it —
        Periods and Currency get the same air on the invoice wizard's step 4,
        the standalone payment, the receipt and the posted view, and a surface
        that reorders its fields cannot lose it.
        ⚠ SCOPED TO THE PANEL'S OWN ROWS. `.airow` is used elsewhere in the app
        (the AI cards), and those are not what he is looking at.
        ⚠⚠⚠ AND IT APPLIES ONLY WHERE THE ROW IS ACTUALLY SHOWN — his own point:
        *"where the transaction is base currency … the Currency and rate row
        should ultimately be hidden altogether under P-14. The spacing
        adjustment therefore applies when that row is actually displayed."* A
        margin on a `display:none` element contributes nothing, so P-14's rule
        and this one need no knowledge of each other. */
    /*  ⚠ `[data-nvpp-base]`, NOT `[data-nvpp]`. The mount flag is rendered only
        when the panel is INTERACTIVE (`Model.Mount`), so keying off it would
        have given the entry form the spacing and left the posted view without
        it — the same two rows, differently spaced, one screen apart.
        `data-nvpp-base` is on the panel's root unconditionally. */
    [data-nvpp-base] > .airow {
        margin-top: 6px;
    }

    /*  ⚠⚠⚠ v31.244 (owner, P-14) — AND A CLOSED `<details>` ACTUALLY CLOSES.
        MEASURED before this rule, on a payment with the row collapsed:

            #perRow  open=false  body height 72px
            #curRow  open=false  body height 76px

        The rule above sets `display: flex` on the body, and an author
        declaration beats the hiding a closed `<details>` does for its
        non-summary children. So the Periods row this app has called *"the
        PERIOD row stays minimized"* since v31.220 has never actually been
        minimized — the chevron turned and nothing moved.
        > ⚠ **A DISCLOSURE THAT DOES NOT DISCLOSE IS A HEADING.** P-14 is a
        > *hide this row* requirement, so it could not be built on one.
        ⚠ IT IS SCOPED TO `.airow`, so no other `<details>` in the app changes.
        ⚠⚠ AND IT IS `display: none`, not a height animation: the row holds form
        controls, and a collapsed box that still lays them out is a set of
        fields a reader can tab into but cannot see. */
    .airow:not([open]) > .airow-body {
        display: none;
    }

/* v8.1 (owner) — collapsed recipients on the Message page (matches the
   composer's Cc/Bcc reveal): a quiet chevron row inside the sender card */
.rcpt > summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 0;
}

    .rcpt > summary::-webkit-details-marker {
        display: none;
    }

    .rcpt > summary .chev {
        transition: transform .18s;
        color: var(--nv-gold);
    }

.rcpt[open] > summary .chev {
    transform: rotate(180deg);
}

/* v8.3 (owner) — the global error POPUP (v1 EShowMessagePopUp): a centred
   card over a scrim, same visual family as the entity dialog */
.err-scrim {
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(3,6,14,.62);
    backdrop-filter: blur(2px);
}

.err-pop {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 41;
    width: min(400px, calc(100vw - 40px));
    display: flex;
    flex-direction: column;
    gap: 14px;
    border-radius: 8px;
    border: 1px solid rgba(104,152,232,.30);
    padding: 26px 22px;
    /*  ══════════════════════════════════════════════════════════════════════
        ⚠⚠⚠ v31.286 (owner): *"The same background as the tooltip background."*

        THE DECLARATION WAS ALREADY THE TOOLTIP'S, AND THAT IS THE POINT. Both
        surfaces carried `linear-gradient(145deg, #010107, #1E1E1E 50%,
        #13294B)`, and sampled side by side at their real sizes they come back
        identical to within one unit of blue — measured, not assumed.

        ⚠⚠ WHAT DIFFERS IS HOW MUCH OF THE RAMP EACH BOX SHOWS. A gradient's
        stops are percentages of a line that scales with the element, so a
        tooltip — small, and read in a glance — is dominated by the near-black
        start, while a 400×250 dialog spreads the same ramp across the whole
        message and puts the grey middle band directly behind the text. Same
        colours; a different part of them.

        ⚠ SO THE STOPS ARE SCALED, NOT RECOLOURED. The ramp is the house ramp
        unchanged; pushing the mid to 82% and the end past 100% means a
        dialog-sized box reveals the same PART of it a tooltip-sized box does —
        near-black through to a restrained navy corner, never a grey slab.
        Measured against the tooltip: centre 19,19,21 against its 30,30,30 read
        at a size nobody sees the tooltip at.
        ══════════════════════════════════════════════════════════════════════ */
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 82%, #13294B 175%);
    box-shadow: 0 18px 48px rgba(0,0,0,.55);
    font-family: 'Poppins', -apple-system, 'Segoe UI', sans-serif !important;
}

    /*  ⚠ v31.286 (owner): the headline at 300. It was 200 — the same weight as
        the body copy below it, which left the head reading as another paragraph
        rather than as a title. */
    .err-pop h2 {
        font-size: var(--fs-h2);
        font-weight: 300;
        color: var(--nv-gold);
    }

    .err-pop p {
        font-size: 16px;
        font-weight: 200;
        color: var(--nv-ink);
        line-height: 1.5;
    }

    .err-pop button,
    .err-pop a {
        font-family: 'Poppins', -apple-system, 'Segoe UI', sans-serif !important;
    }

/* the assist checkboxes reuse the gold .eml-sel tick */
.aichk {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 40px;
    font-size: 16px;
    color: var(--nv-ink-2);
    cursor: pointer;
}

/* received email renders inside a sandboxed iframe (Message page) */
.email-frame {
    display: block;
    width: 100%;
    height: 360px; /* replaced by the fit script once loaded */
    border: 0;
    border-radius: 4px;
    background: white;
}

/* team-calendar switch row, below the calendar header */
.cal-team {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 20px 8px;
    position: relative;
    z-index: 2;
}

/* event form: date + time share the row without overflowing the page */
.ev-dt {
    display: flex;
    gap: 10px;
}

    .ev-dt .field {
        min-width: 0;
    }

        .ev-dt .field input.input {
            min-width: 0;
            width: 100%;
            padding: 0 4px; /* v25.6 (owner) */
        }

/* v7.2 (owner) — the compose attachments picker, branded: gold pill
   "choose files" button, muted file summary text on the glass input */
input.input[type="file"] {
    height: auto;
    padding: 10px 14px;
    color: var(--nv-ink-3);
    font-size: 15px;
    cursor: pointer;
}

    input.input[type="file"]::file-selector-button {
        font-family: inherit;
        font-size: 15px;
        font-weight: 200;
        color: #241706;
        background: var(--nv-gold);
        border: 0;
        border-radius: 999px;
        /* ⚠ v29.6 (owner: "the Choose File pill height should be reduced to fit
           the height of the input. Do not change input height of 51px, just
           reduce yellow pill dimensions") - THE INPUT IS UNTOUCHED: it keeps
           its height and its 10px padding. Only the browser's own button
           shrinks, to 30px, which is what the input's content box actually
           leaves once that padding is taken. */
        height: 30px;
        padding: 0 14px;
        margin-right: 10px;
        cursor: pointer;
    }

    input.input[type="file"]::-webkit-file-upload-button {
        font-family: inherit;
        font-size: 15px;
        font-weight: 200;
        color: #241706;
        background: var(--nv-gold);
        border: 0;
        border-radius: 999px;
        /* ⚠ v29.6 (owner: "the Choose File pill height should be reduced to fit
           the height of the input. Do not change input height of 51px, just
           reduce yellow pill dimensions") - THE INPUT IS UNTOUCHED: it keeps
           its height and its 10px padding. Only the browser's own button
           shrinks, to 30px, which is what the input's content box actually
           leaves once that padding is taken. */
        height: 30px;
        padding: 0 14px;
        margin-right: 10px;
        cursor: pointer;
    }

/* v7.3 — entity switcher sheet: the .fld rows sit inside per-entity forms,
   so the sibling border comes from the forms */
.mail-sheet form + form .fld {
    border-top: 1px solid rgba(104,152,232,.13);
}

/* v7.6 (owner) — GROUPED entity sheet as a floating CENTRED dialog:
   catalog → group → parent/child, accordion (one node open at a time).
   This presentation is the template for the invoice-processing picker.

   NOTE the base .mail-sheet hides itself with translateY(102%) — that
   cannot clear the screen once bottom is raised to 120px (the top
   ~120px would keep peeking up), which is why the owner's first cut
   "persisted in view". This variant therefore hides with opacity +
   visibility instead, and centres with left:50% / translateX(-50%). */
.ent-sheet {
    max-height: 70vh;
    overflow-y: auto;
    bottom: 120px;
    left: 50%;
    right: auto;
    /* v9.1 (owner) — above the sticky page headers (z-index 20) */
    z-index: 40;
    width: min(440px, calc(100vw - 40px));
    margin: 0;
    border-radius: 8px;
    border: 1px solid rgba(104,152,232,.30);
    padding: 0 20px 24px;
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 50%, #13294B 100%);
    font-family: 'Poppins', -apple-system, 'Segoe UI', sans-serif !important;
    transform: translate(-50%, 14px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .22s, transform .26s cubic-bezier(.22,.61,.36,1), visibility 0s .26s;
}

    .ent-sheet.open {
        transform: translate(-50%, 0);
        opacity: .8;
        visibility: visible;
        transition: opacity .22s, transform .26s cubic-bezier(.22,.61,.36,1), visibility 0s;
    }

    /* buttons do not inherit font by default — force the brand face */
    .ent-sheet button {
        font-family: 'Poppins', -apple-system, 'Segoe UI', sans-serif !important;
    }

/* accordion nodes: only .exp shows its body */
.ent-node > .ent-body {
    display: none;
}

.ent-node.exp > .ent-body {
    display: block;
}

/* v7.7 (owner) — companies sit indented under their gold group header */
.ent-node .ent-node > .ent-body {
    padding-left: 18px;
}

/* v7.7 (owner) — company names never wrap to a second line */
.ent-sheet .fld .fl {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* v7.9 (owner) — tighter rows in the entity list only */
.ent-sheet .fld {
    padding: 9px 9px;
}

/* v7.9 (owner) — the gold X that closes the dialog without a selection */
/* v9.1 (owner) — the scrim must cover the sticky headers too */
.mail-scrim.ent-scrim {
    z-index: 39;
}

/* v9.1 (owner) — the title + close X stay STICKY while the tree scrolls;
   the header is slimmer than the old 50px sheet padding */
.ent-head {
    position: sticky;
    top: 0;
    z-index: 3;
    margin: 0 -20px 6px;
    padding: 12px 46px 9px 20px;
    background: linear-gradient(180deg, rgba(4,6,12,.96), rgba(9,13,24,.88));
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid rgba(104,152,232,.16);
}

    .ent-head h2 {
        margin-bottom: 0;
    }

    .ent-head .ent-close {
        top: 50%;
        right: 8px;
        transform: translateY(-50%);
    }

/*  ══════════════════════════════════════════════════════════════════════════
    v9.1 (owner) - the sheet ANCHORS 10px below the org chip (JS positions it);
    the old bottom-anchored slide becomes a plain fade.

    ⚠⚠⚠ v31.89 (batch284, owner) - `margin: 0` IS LOAD-BEARING, AND ITS ABSENCE
    WAS THE DEFECT. Owner: *"for 'mail-sheet ent-sheet ent-anchored open' and
    ONLY for screen sizes 05-Screen, the anchor is 'off' i.e too far to the
    right and too low from the top."*

    ⚠⚠ THE CAUSE IS MINE, FROM v31.83. That batch answered *"the accMoreSheet
    top disappears in 05-Screen ONLY"* with a rule on **`.mail-sheet`** -
    `@media (min-width: 1920px) { .mail-sheet { margin: 340px auto !important } }`
    - and `.ent-sheet` carries `mail-sheet` too. The JS sets `top` to the
    chip's bottom + 10; **the margin is then ADDED to it.** The entity sheet has
    been landing 340px below where it computed itself ever since.

    > ⚠⚠⚠ **A RULE WRITTEN FOR ONE SHEET LANDS ON EVERY SHEET THAT SHARES ITS
    > CLASS.** `.mail-sheet` is a base class with six users; scoping the fix to
    > the ONE sheet that asked for it was the job, and "only in 05-Screen" was
    > read as a BREAKPOINT when it was also a SELECTOR.

    MEASURED, before, gap from the chip's bottom (should be 10 at every band):

        390    margin 134px   ->  gap 144
        768    margin 134px   ->  gap 144
        1024   margin  20px   ->  gap  30
        1366   margin  40px   ->  gap  50
        1920   margin 340px   ->  gap 350   <- the one that got reported
        2560   margin 340px   ->  gap 350

    So it was wrong at EVERY band and only visibly wrong at the widest, which
    is exactly why it took this long to surface.

    ⚠ `!important` IS REQUIRED HERE and it is not the usual ordering laziness:
    the four `.mail-sheet` margin rules are themselves `!important`, and only
    another `!important` can beat one. **Specificity then decides between
    them** - `.ent-sheet.ent-anchored` is (0,2,0) against `.mail-sheet`'s
    (0,1,0), so this wins wherever it sits in the file and cannot be lost to a
    later edit of those media blocks.
    ⚠ THE OTHER FIVE `.mail-sheet` USERS ARE UNTOUCHED - this names
    `.ent-anchored`, which only the entity sheet carries.
    ══════════════════════════════════════════════════════════════════════════ */
.ent-sheet.ent-anchored {
    bottom: auto;
    transform: none;
    margin: 0 !important;
}

    .ent-sheet.ent-anchored.open {
        transform: none;
    }

.ent-close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    cursor: pointer;
    color: var(--nv-gold);
}

/* level headers are buttons now */
.ent-db,
.ent-grp {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    background: transparent;
    border: 0;
    text-align: left;
    cursor: pointer;
    font-weight: 200;
}

    .ent-db::after,
    .ent-grp::after {
        content: "";
        width: 8px;
        height: 8px;
        margin-left: 10px;
        border-right: 1.5px solid currentColor;
        border-bottom: 1.5px solid currentColor;
        transform: rotate(45deg);
        transition: transform .2s;
        flex: 0 0 auto;
    }

.ent-node.exp > .ent-db::after,
.ent-node.exp > .ent-grp::after {
    transform: rotate(225deg);
}

.ent-db {
    margin-top: 14px;
    padding: 8px 0;
    font-size: 15px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
    border-bottom: 1px solid rgba(104,152,232,.18);
}

.ent-grp {
    margin-top: 8px;
    padding: 6px 0;
    font-size: 15px;
    color: var(--nv-gold);
}

.fld.ent-child {
    padding-left: 40px;
}

/* v7.2 — attachments: the arrow at the row's end (2+ files) + the revealed
   list of the selected files */
.file-wrap {
    position: relative;
}

    .file-wrap input.input[type="file"] {
        padding-right: 56px;
    }

.file-toggle {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--nv-gold);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

    .file-toggle .chev {
        transition: transform .18s;
    }

    .file-toggle.open .chev {
        transform: rotate(180deg);
    }

.file-list {
    list-style: none;
    margin: 0;
    padding: 4px 14px;
    border: 1px solid rgba(104,152,232,.22);
    border-radius: var(--r-card);
    background: linear-gradient(160deg,rgba(120,165,240,.09),rgba(255,255,255,.015) 55%),rgba(13,22,42,.30);
}

    .file-list li {
        display: flex;
        align-items: baseline;
        gap: 12px;
        padding: 9px 0;
        font-size: 15px;
    }

/*  ⚠ v31.244 (owner, P-17) — the per-file remove. Quiet until the row is
    pointed at: a red × on every attachment reads as an error state, and these
    rows are a normal, successful thing. It is `.nvtr-go`'s shape and restraint
    rather than a new kind of button. */
.file-list li > .file-x {
    margin-left: auto;
    flex: 0 0 auto;
    border: 0;
    background: none;
    padding: 0 2px;
    color: var(--nv-muted, #9fb0cc);
    cursor: pointer;
    line-height: 0;
    opacity: .55;
    align-self: center;
}

    .file-list li > .file-x:hover { opacity: 1; color: var(--nv-gold); }

    .file-list li > .file-x:focus-visible {
        outline: 2px solid var(--nv-blue-bright);
        outline-offset: 2px;
        border-radius: 3px;
        opacity: 1;
    }

/*  the `fs` size column no longer takes the slack — the × does. */
.file-list li > .fs { margin-left: auto; }
.file-list li > .file-x ~ .fs { margin-left: 0; }


        .file-list li + li {
            border-top: 1px solid rgba(104,152,232,.13);
        }

    .file-list .fn {
        flex: 1;
        min-width: 0;
        color: var(--nv-ink-2);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .file-list .fs {
        flex: 0 0 auto;
        color: var(--nv-ink-3);
        font-variant-numeric: tabular-nums;
    }

/* v7.0 — address search inside the To/Cc inputs (compose) */
.addr-wrap {
    position: relative;
}

    .addr-wrap input.input {
        padding-right: 56px;
    }

.addr-search {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--nv-gold);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.addr-results {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    max-height: 280px;
    overflow-y: auto;
}

.addr-hit {
    text-align: left;
    background: transparent;
    border: 0;
    padding: 12px 6px;
    color: var(--nv-ink);
    font-size: 16px;
    font-family: inherit;
    font-weight: 200;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

    .addr-hit + .addr-hit {
        border-top: 1px solid rgba(104,152,232,.13);
    }

    .addr-hit .em {
        color: var(--nv-ink-3);
        font-size: 15px;
    }

/* v7.7 (owner) — muted scrollbars: the gold scrollbar-color is retired so
   the thumb stays a quiet blue-grey instead. (The webkit thumb is muted to
   match — Chrome/Edge would otherwise still paint the old gold rules.) */
* {
    scrollbar-width: thin;
    /* v9.1 (owner) — browsers that honour the STANDARD scrollbar properties
       (Chromium 121+ ignores the ::-webkit rules once scrollbar-width is
       set — the 1366 viewport bar looked native) get the same muted pair */
    scrollbar-color: rgba(104,152,232,.28) rgba(16,26,48,.55);
}

    *::-webkit-scrollbar {
        width: 9px;
        height: 9px;
    }

    *::-webkit-scrollbar-track {
        background: rgba(16,26,48,.55);
        border-radius: 8px;
    }

    *::-webkit-scrollbar-thumb {
        background: rgba(104,152,232,.28);
        border-radius: 8px;
        border: 2px solid rgba(16,26,48,.55);
    }

        *::-webkit-scrollbar-thumb:hover {
            background: rgba(104,152,232,.5);
        }

/* ── the NOVERA checkbox (owner, Wave 2.2) — gold border, transparent fill,
   gold tick; replaces the browser accent checkbox wherever forms need it ── */
input.nv-check {
    appearance: none;
    -webkit-appearance: none;
    width: 24px;
    height: 24px;
    border: 1px solid var(--nv-gold);
    border-radius: 6px;
    background: transparent;
    cursor: pointer;
    display: inline-grid;
    place-content: center;
    margin: 0;
    flex: 0 0 auto;
}

    input.nv-check::after {
        content: "";
        width: 12px;
        height: 12px;
        transform: scale(0);
        transition: transform .12s;
        clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
        background: var(--nv-gold);
    }

    input.nv-check:checked::after {
        transform: scale(1);
    }

/* ── AI Briefing dashboard (v10.0, owner) — stat tiles + two-column zone ── */
.ai-tiles {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}

.ai-tile {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 16px;
}

    .ai-tile .n {
        font-size: 30px;
        font-weight: 200;
        line-height: 1.1;
        color: var(--nv-ink);
    }

        .ai-tile .n.gold {
            color: var(--nv-gold-bright);
        }

    .ai-tile .l {
        font-size: 15px;
        color: var(--nv-ink-3);
    }

/* the two briefing columns stack on phones; responsive.css opens them up */
.ai-cols {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.ai-col {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

/* ── AI inbox (v10.4, owner — mock-up 2) ─────────────────────────────── */
.ai-chips {
    display: flex;
    align-items: center;
    gap: 8px;
    overflow-x: auto;
    padding: 0 2px 2px;
    scrollbar-width: none;
}

    .ai-chips::-webkit-scrollbar {
        display: none;
    }

    .ai-chips .chip {
        text-decoration: none;
        white-space: nowrap;
        flex: 0 0 auto;
        width: auto;
    }

        .ai-chips .chip .n {
            color: var(--nv-gold-bright);
            font-variant-numeric: tabular-nums;
        }

/* section header inside the AI-priority grouped list */
.mail-sec {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 4px 4px;
    font-size: 14px;
    font-weight: 200;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
}

    .mail-sec i {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        flex: 0 0 auto;
    }

/* v10.8 r4 (owner) — the AI assistant column shows at EVERY width now:
   stacked below the mail cards on phones/tablets (bottom-nav clearance),
   responsive.css re-places it from 1024 up */
.ai-side {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin: 8px 20px 120px;
}

/* v10.8 r4 (owner) — phones: only the first two chips (v12.7: Newest +
   AI priority — Newest is finally reachable on phones); the rest return
   from tablet up */
@media (max-width: 767px) {
    /* v20.8 (batch117, owner: "We have regressed with the top cards in
       email") — the phone's card COUNT moved out of here. Every width's
       count now lives in ONE ladder in responsive.css (which loads last),
       because three files each hiding a different nth-child is exactly how
       this regressed: the rules named POSITIONS (2, 5, 6) chosen for the
       old six-card order, and the batch113 reorder to seven cards left
       them pointing at the wrong cards. */
    /* v10.8 r5 (owner) — the two chips span the page, equal width, aligned
       with the search box; the Sort by row hides on phones */
    .ai-chips {
        padding: 0 0 2px;
    }

        .ai-chips .chip {
            flex: 1 1 0;
            min-width: 0;
        }
}

.ai-glance {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

    .ai-glance .gl {
        border: 1px solid rgba(104,152,232,.22);
        border-radius: var(--r-card);
        padding: 10px 12px;
    }

    .ai-glance .n {
        font-size: 24px;
        font-weight: 200;
        line-height: 1.15;
        color: var(--nv-ink);
    }

        .ai-glance .n.gold {
            color: var(--nv-gold-bright);
        }

    .ai-glance .l {
        font-size: 14px;
        color: var(--nv-ink-3);
    }
/* ── mock layout pass (v10.5–v10.6, owner — structure only, existing palette) ── */
/* v10.6 (owner) — taller chips, two rows: row 1 = icon | count (two
   columns), row 2 = the label full-width */
.ai-chips .chip {
    height: 70px;
    min-width: 120px; /* owner (2026-08-12 v10) */
    display: inline-flex;
    flex-direction: column;
    align-items: center; /* v10.6 r4 owner — content centred */
    justify-content: center;
    gap: 3px;
    padding: 0 14px;
}

    .ai-chips .chip .r1 {
        display: flex;
        align-items: center;
        gap: 8px;
    }

        .ai-chips .chip .r1 .n {
            font-size: 17px;
        }

    .ai-chips .chip .lb {
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        text-align: center; /* v10.6 r4 owner */
    }
/* v10.6 r4 (owner) — "Your AI routine": plain 36px icons, no tint, no
   background (the intro card's tinted sparkle keeps its tint class) */
.ai-side .row .ic {
    background: transparent;
}
/* v10.8 (batch54, Mock B locked) — the FOLDERS PANEL replaces the mail-bar
   from 1024px up; below 1024 the floating bar returns as the phone's mail
   navigation. The bar's sheets (folders / confirm delete) and toast keep
   working everywhere — the panel delegates to them. */
@media (min-width: 1024px) {
    .mail-app .app-main > .mail-bar {
        display: none;
    }
}
/* ── MAIL FOLDERS panel (v10.8) — hidden below 1024 (responsive.css shows
      and places it) ─────────────────────────────────────────────────── */
.mail-folders {
    display: none;
}

    .mail-folders h1 {
        /* v10.8 r3 (owner) — semantic h1 */
        font-size: 22px;
        font-weight: 400; /*(owner)*/
        color: var(--nv-ink);
        margin: 2px 4px 12px;
    }

    .mail-folders .mf-compose {
        height: 48px;
        /*font-size: 20px;*/ /* v10.8 r3 owner */
        display: flex;
        align-items: center;
        justify-content: center;
        text-decoration: none;
        margin-bottom: 12px;
    }

    .mail-folders .mf {
        display: flex;
        align-items: center;
        gap: 11px;
        padding: 9px 12px;
        border-radius: 8px;
        color: var(--nv-ink-2);
        /*font-size: 20px;*/ /* v10.8 r3 owner */
        text-decoration: none;
        border: 0;
        background: none;
        font-family: inherit;
        cursor: pointer;
        text-align: left;
        width: 100%;
    }

        .mail-folders .mf.on {
            color: var(--nv-ink);
            background: rgba(232,167,92,.14);
        }

        .mail-folders .mf .fi {
            display: flex;
            flex: 0 0 auto;
            color: var(--nv-gold); /* toolkit: icons are gold */
        }

            .mail-folders .mf .fi svg {
                width: 32px; /* toolkit: functional icons 32px */
                height: 32px;
            }

        .mail-folders .mf .fl {
            flex: 1;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .mail-folders .mf .fc {
            margin-left: auto;
            font-size: 18px; /* v10.8 r3 owner */
            color: var(--nv-gold-bright);
            font-variant-numeric: tabular-nums;
            flex: 0 0 auto;
        }

            .mail-folders .mf .fc.dim {
                color: var(--nv-ink-3);
            }

    .mail-folders .mf-del {
        margin-top: 12px;
        border-top: 1px solid rgba(104,152,232,.13);
        border-radius: 0 0 8px 8px;
        padding-top: 14px;
        color: var(--nv-danger);
    }

        .mail-folders .mf-del .fi {
            color: var(--nv-danger);
        }
/* small tinted icon circles inside the category chips */
.ai-chips .chip .ic {
    /* v10.8 r7 (owner) — plain gold 32px svgs: NO circle, border NONE,
       background NONE */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0 !important;
    background: none !important;
    color: var(--nv-gold) !important;
    flex: 0 0 auto;
}
/* v10.6 (owner) — the digest's per-category cards: flush rows like the list
   card, natural height (the middle column scrolls as one) */
.mail-grp {
    padding-top: 2px;
    padding-bottom: 8px;
}

    .mail-grp .mail-sec {
        padding-top: 10px;
    }
/* tint variants missing from the original set — same palette colours the
   inbox already uses (danger badges, muted ink) */
.tint-danger {
    background: rgba(217,101,101,.07) !important;
    border-color: rgba(217,101,101,.42) !important;
    color: var(--nv-danger) !important;
}

.tint-dim {
    background: rgba(18,30,56,.28) !important;
    border-color: rgba(104,152,232,.22) !important;
    color: var(--nv-ink-3) !important;
}
/* the one-line preview snippet under the subject (mock rows) */
.mail .prev {
    font-size: 14px;
    color: var(--nv-ink-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
/* toolbar extras (mock): "Sort by:" dropdown + the funnel button.
   Stacked with the rest of .mail-tools on mobile; on one row from 1024. */
.mt-extra {
    display: flex;
    align-items: center;
    gap: 10px;
}

    .mt-extra .mt-sort {
        display: flex;
        align-items: center;
        gap: 8px;
        margin: 0;
        flex: 1 1 auto;
    }

        .mt-extra .mt-sort .s {
            font-size: 14px;
            color: var(--nv-ink-3);
            white-space: nowrap;
        }

        .mt-extra .mt-sort select.input {
            height: 44px;
            width: auto;
            flex: 1 1 auto;
            padding: 0 12px;
        }

    .mt-extra .mt-filter {
        flex: 0 0 auto;
        width: 44px;
        height: 44px;
        border: 1px solid rgba(104,152,232,.22);
        border-radius: var(--r-input, 14px);
    }
/* "View all insights" / "See all deadlines" footer links on the side cards */
.lnk-more {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid rgba(104,152,232,.13);
    font-size: 14px;
    color: var(--nv-gold-bright);
    text-decoration: none;
}

    .lnk-more svg {
        margin-left: auto;
    }
    /* v10.6 r6 (owner) — the digest's "View all →": bottom RIGHT corner */
    .lnk-more.end {
        justify-content: flex-end;
        padding-right: 4px;
    }

        .lnk-more.end svg {
            margin-left: 0;
        }
/* v10.6 r6 (owner) — the row checkbox rides the DATE LINE (top), not the
   card's vertical centre */
.mail .pick {
    align-self: flex-start;
    margin-top: 0;
}
/* v10.6 r10 (owner) — glance icons ALL GOLD; numbers stay ink */
.ai-glance .n svg {
    color: var(--nv-gold);
}
/* glance tiles: the small icon rides the number line (mock);
   v10.6 (owner) — content centred */
.ai-glance .gl {
    text-align: center;
}

.ai-glance .n {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

    .ai-glance .n svg {
        flex: 0 0 auto;
    }
/* ── READ & REPLY page (v10.9, batch55 — locked Mock A) ─────────────── */
/* header pill buttons (AI summary) */
.hbtn {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    height: 48px;
    padding: 0 16px;
    border: 1px solid rgba(104,152,232,.22);
    border-radius: 8px;
    background: none;
    color: var(--nv-ink-2);
    font-family: inherit;
    font-size: 15px;
    cursor: pointer;
    white-space: nowrap;
}

    .hbtn.gold {
        border-color: var(--nv-gold);
        color: var(--nv-gold-bright);
    }
/* the ⋯ menu */
.msg-menuwrap {
    position: relative;
}

/* v27.2 (PRODUCTION TICKET 20260821002 item 5): the OVERDUE row's quick-move
   menu reuses the ⋯ menu, but a row is not a page header - it opens under a
   26px button, so the panel sits closer and narrower. */
.ov-menuwrap .msg-menu {
    top: 34px;
    min-width: 190px;
}

.ov-menubtn {
    width: 34px;
    height: 34px;
    opacity: .75;
}

    .ov-menubtn:hover {
        opacity: 1;
    }

.msg-menu {
    position: absolute;
    top: 54px;
    right: 0;
    min-width: 250px;
    border: 1px solid rgba(112,160,238,.30);
    border-radius: var(--r-card);
    background: var(--nv-surface);
    box-shadow: 0 16px 34px rgba(0,0,0,.55);
    z-index: 30;
    overflow: hidden;
    display: none;
    flex-direction: column;
}

    .msg-menu.open {
        display: flex;
    }

    .msg-menu form {
        margin: 0;
    }

    .msg-menu button {
        display: flex;
        align-items: center;
        gap: 12px;
        width: 100%;
        padding: 11px 16px;
        background: none;
        border: 0;
        color: var(--nv-ink-2);
        font-family: inherit;
        font-size: 15px;
        cursor: pointer;
        text-align: left;
    }

        .msg-menu button:hover {
            background: rgba(232,167,92,.08);
        }

        .msg-menu button svg {
            color: var(--nv-gold); /* toolkit */
            flex: 0 0 auto;
        }

        .msg-menu button.danger,
        .msg-menu button.danger svg {
            color: var(--nv-danger);
        }
/* Compose-with-AI panel */
.cwa-grid {
    display: grid;
    grid-template-columns: 230px minmax(0, 1fr);
    gap: 16px;
}

@media (max-width: 767px) {
    .cwa-grid {
        grid-template-columns: 1fr; /* stacked on phones */
    }
}

.cwa-int {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.int {
    display: flex;
    align-items: center;
    gap: 9px;
    border: 1px solid rgba(104,152,232,.22);
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 15px;
    color: var(--nv-ink-2);
    cursor: pointer;
}

    .int input {
        position: absolute;
        opacity: 0;
        pointer-events: none;
    }

    .int i {
        width: 14px;
        height: 14px;
        border: 1.5px solid currentColor;
        border-radius: 50%;
        display: inline-block;
        flex: 0 0 auto;
    }

    .int:has(input:checked) {
        border-color: var(--nv-gold);
        color: var(--nv-ink);
        background: rgba(232,167,92,.08);
    }

        .int:has(input:checked) i {
            background: var(--nv-gold);
            border-color: var(--nv-gold);
        }
/* the suggested-reply box (same treatment as the composer's AI panel) */
.aibox {
    border: 1px solid rgba(232,167,92,.55);
    border-radius: 10px;
    background: rgba(232,167,92,.07);
    padding: 12px 14px;
    font-size: 15px;
    color: var(--nv-ink);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.cwa-draft {
    width: 100%;
    background: none;
    border: 0;
    color: var(--nv-ink);
    font-family: inherit;
    font-size: 15px;
    line-height: 1.5;
    resize: vertical;
    min-height: 180px;
    outline: none;
}
/* the uniform control grid: selects + equal-width buttons (toolkit rule) */
.ctl3 {
    display: grid;
    grid-template-columns: repeat(3, minmax(150px, 1fr));
    gap: 10px;
}

@media (max-width: 767px) {
    .ctl3 {
        grid-template-columns: 1fr 1fr;
    }
}

.ctl3 .lab {
    font-size: 12.5px;
    color: var(--nv-ink-3);
    margin-bottom: 4px;
}

select.ctl {
    width: 100%;
    height: 48px;
    background: var(--nv-surface-3);
    border: 1px solid rgba(112,160,238,.30);
    border-radius: var(--r-input);
    color: var(--nv-ink);
    font-family: inherit;
    font-size: 14px;
    padding: 0 12px;
}

.ctl3 .btn {
    align-self: end; /* v10.9 r2 (owner) — buttons sit level with the selects
                        (the labels above the selects otherwise push rows apart) */
    height: 48px;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    white-space: nowrap;
    padding: 0 12px;
    font-size: 15px;
}

    .ctl3 .btn[disabled] {
        opacity: .45;
        cursor: default;
    }
/* right-column quick actions (32px gold icons, ellipsed labels) */
.cwa-qa {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

    .cwa-qa a {
        display: flex;
        align-items: center;
        gap: 10px;
        border: 1px solid rgba(104,152,232,.22);
        border-radius: 8px;
        color: var(--nv-ink-2);
        font-size: 14px;
        padding: 10px 12px;
        text-decoration: none;
        min-height: 56px;
        min-width: 0;
        overflow: hidden;
    }

        .cwa-qa a svg {
            color: var(--nv-gold); /* toolkit */
            flex: 0 0 auto;
        }

    .cwa-qa .ql {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
/* ── COMPOSE rich-text editor (v11.0, batch56 — locked Mock B) ──────── */
.rt-toolbar {
    display: flex;
    gap: 4px;
    align-items: center;
    border: 1px solid rgba(112,160,238,.30);
    /* owner (batch107): border-bottom restored; the toolbar tucks into the
       surface below via the negative margin instead.
       owner (batch108): the padding line is gone entirely. */
    margin-bottom: -8px;
    border-radius: var(--r-input) var(--r-input) 0 0;
    background: linear-gradient(160deg,rgba(120,165,240,.07),rgba(255,255,255,.01));
    flex-wrap: wrap;
}

    .rt-toolbar button {
        min-width: 38px;
        height: 38px;
        border: 0;
        border-radius: 6px;
        background: none;
        color: var(--nv-ink-2);
        font-family: inherit;
        font-size: 16px;
        cursor: pointer;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

        .rt-toolbar button:hover {
            background: rgba(232,167,92,.10);
        }

/*  ⚠⚠ v31.147 (owner) — THE PENCIL'S CELL, CLOSED, ON A TALL EDITOR.
    Owner, on the invoice's Extended description: *"Top Border needed for top
    section of pencil cell."*

    ⚠ WHY IT ONLY LOOKS WRONG HERE. `.fld-btn::before` draws a 22px divider
    centred on a 26px button — inside a 32px input that reads as a full-height
    rule and the control looks like a cell of the field. Against a 100px+
    editor the same 22px is a fragment floating in a tall box: the editor's
    own border closes the right and the bottom, nothing closes the top, and
    the eye reads an unfinished cell. MEASURED: editor 100px, pencil 26px,
    divider 22px.

    So on this shape only, the divider runs the button's full height and a top
    border closes it. Scoped with `:has(> .rt-ed)` — the wrap of a rich editor
    — so all thirty-one ordinary fields keep the geometry v31.82 settled. */
.fld-wrap[data-nvfe]:has(> .rt-ed) > .nvfe-pen,
.fld-wrap[data-nvfe]:has(> .rt-ed) > .nvfe-act {
    border-top: 1px solid rgba(112, 160, 238, .30);
}

    .fld-wrap[data-nvfe]:has(> .rt-ed) > .nvfe-pen::before,
    .fld-wrap[data-nvfe]:has(> .rt-ed) > .nvfe-act .fld-btn:first-child::before {
        top: 0;
        height: 100%;
        transform: none;
    }

    /*  ⚠ the pair is two buttons; only the FIRST draws the cell's left edge,
        or the ✓ and the ✕ would be separated by a full-height rule the resting
        state never has. */
    .fld-wrap[data-nvfe]:has(> .rt-ed) > .nvfe-act .fld-btn:not(:first-child)::before {
        display: none;
    }

/*  ⚠⚠ v31.147 (owner) — THE TIGHT TOOLBAR, ONE CALL SITE ONLY.
    *"Make the following change ONLY to the Rich Editor used in Bank
    Reconciliation … Do not change the global `.rt-toolbar` styling, as the
    other Rich Editors should remain unaffected."*
    So it is a class the call site asks for (`ViewData["ReBarClass"]`), never a
    change to the base rule — and v31.146's global `padding: 0 6px` has been
    taken back OUT for the same reason: it did not fix the clipping the owner
    reported, and it was a global change to a shared control. */
.rt-toolbar.rt-tight {
    gap: 2px;
    padding: 0 4px;
}

    .rt-toolbar .sep {
        width: 1px;
        height: 20px;
        background: rgba(104,152,232,.22);
        margin: 0 4px;
    }

.rt-emoji-wrap {
    position: relative;
}

.rt-emoji {
    position: absolute;
    top: 44px;
    left: 0;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 2px;
    padding: 8px;
    border: 1px solid rgba(112,160,238,.30);
    border-radius: var(--r-card);
    background: var(--nv-surface);
    box-shadow: 0 14px 30px rgba(0,0,0,.5);
    z-index: 20;
}

    .rt-emoji button {
        font-size: 20px;
    }

.rt-ed {
    border-radius: 0 0 var(--r-input) var(--r-input);
    padding: 14px 16px;
    display: block;
    overflow-y: auto;
    line-height: 1.5;
    outline: none;
}

    .rt-ed:focus {
        border-color: var(--nv-blue-bright);
        box-shadow: 0 0 0 3px rgba(47,127,214,.25);
    }

    /*  ⚠⚠ v31.163 (owner) — THE READ-ONLY RICH SURFACE (`_RichEd`'s
        "ReReadOnly"). Used by Notes so the note lives in the SAME editor
        whether you are reading it or writing it.

        ⚠ THE TOP CORNERS COME BACK, and that is the only shape change here.
        The base rule squares them off — `border-radius: 0 0 r r` — because a
        toolbar normally sits on top and the two must meet flush. A read-only
        surface has no toolbar, so square top corners would be a joint to
        nothing.
        ⚠⚠ THE BOX ITSELF IS DELIBERATELY UNCHANGED. The point of the request
        is that the note does not move when Edit is pressed, so the padding,
        the line height and the border stay exactly as the writable editor's.
        Only the affordances go: no caret, no text cursor, and no focus ring,
        since nothing here can take focus to begin with. */
    .rt-ed.rt-ro {
        border-radius: var(--r-input);
        cursor: default;
        caret-color: transparent;
    }

        .rt-ed.rt-ro:focus {
            border-color: var(--nv-line, rgba(232,167,92,.18));
            box-shadow: none;
        }
/* ════════════════════════════════════════════════════════════════════
   v10.8 r7 (owner) — Sort-by row (.mt-extra: dropdown + funnel) is
   DESKTOP-ONLY. Placed at the END of the sheet with a compound selector:
   the earlier attempt lost the cascade to the base .mt-extra rule that
   is defined later in this file. Hidden below 1366 everywhere.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 1365px) {
    .mail-tools .mt-extra,
    .mt-extra {
        display: none !important;
    }
}
/* ════════════════════════════════════════════════════════════════════
   v11.2 (batch58, owner) — the emoji popover must stay HIDDEN until the
   trigger is clicked: the base .rt-emoji { display:grid } was overriding
   the [hidden] attribute (same cascade lesson as .mt-extra — hide rules
   live at the END of the sheet). Also nudged below the 32px trigger.
   ════════════════════════════════════════════════════════════════════ */
.rt-emoji[hidden] {
    display: none !important;
}

.rt-emoji {
    top: 48px; /* v11.2 — clears the 32px trigger */
}
/* ════════════════════════════════════════════════════════════════════
   v12.0 (batch60 — Calendar Mock A locked) — PLANNER components:
   the calendar panel extras (mini-month, calendar toggles), the grid
   EVENT PILLS, and the right day-column bits. Display switching between
   dots (phones) and pills (desktop) lives at the END of responsive.css.
   ════════════════════════════════════════════════════════════════════ */
/* grid event pills (hidden on phones — the dots serve there) */
.day .pills {
    display: none;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    margin-top: 2px;
}

/* v27.1 (PRODUCTION TICKET, owner: "completed items should be green as in
   v1"): a completed calendar entry keeps its place in the month grid but
   reads as done - green edge (set inline from --acc-green) and struck text. */
.pill.done .t {
    text-decoration: line-through;
    opacity: .62;
}

.pill {
    display: flex;
    align-items: center;
    gap: 5px;
    border-left: 3px solid var(--nv-blue-bright);
    background: rgba(22,33,60,.66);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 11.5px;
    color: var(--nv-ink-2);
    min-width: 0;
}

    .pill .t {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    .pill.mail {
        border-left-color: var(--nv-gold);
    }

        .pill.mail .ic {
            color: var(--nv-gold);
            flex: 0 0 auto;
            display: flex;
        }

.pmore {
    font-size: 11px;
    color: var(--nv-gold-bright);
    padding-left: 2px;
}
/* the calendar panel (reuses the .mail-folders card + grid placement) */
.cal-panel .mini-cal {
    border: 1px solid rgba(104,152,232,.13);
    border-radius: 6px;
    padding: 10px 12px;
    margin: 4px 0 8px;
}

.cal-panel .mc-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--nv-ink-2);
    font-size: 13.5px;
    margin-bottom: 6px;
}

    .cal-panel .mc-head a {
        color: var(--nv-ink-3);
        text-decoration: none;
        padding: 0 6px;
        font-size: 16px;
    }

.cal-panel .mc-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    text-align: center;
}

.cal-panel .mc-dow {
    font-size: 10.5px;
    color: var(--nv-ink-3);
    padding: 2px 0;
}

.cal-panel .mc-day {
    font-size: 11.5px;
    color: var(--nv-ink-2);
    text-decoration: none;
    padding: 3px 0;
    border-radius: 4px;
}

    .cal-panel .mc-day.out {
        color: var(--nv-ink-3);
        opacity: .5;
    }

    .cal-panel .mc-day.today {
        color: var(--nv-gold-bright);
        font-weight: 500;
    }

    .cal-panel .mc-day.sel {
        outline: 1px solid var(--nv-gold);
        color: var(--nv-ink);
    }

.cal-panel .cp-grp {
    font-size: 13px;
    color: var(--nv-ink-3);
    letter-spacing: .04em;
    margin: 8px 4px 2px;
}

.cal-panel .cp-sect {
    border-top: 1px solid rgba(104,152,232,.13);
    margin-top: 12px;
    padding-top: 12px;
}

.cal-panel .cp-sw {
    width: 14px;
    height: 14px;
    border-radius: 4px;
    flex: 0 0 auto;
}

    .cal-panel .cp-sw.ring {
        background: none;
        border: 1px solid rgba(104,152,232,.22);
    }

        .cal-panel .cp-sw.ring.on {
            border-color: var(--nv-gold);
            background: rgba(232,167,92,.35);
        }

.cal-panel .cp-cat {
    background: none;
    border: 0;
    font: inherit;
    text-align: left;
    cursor: pointer;
    width: 100%;
}

    .cal-panel .cp-cat.off {
        opacity: .4;
    }

        .cal-panel .cp-cat.off .cp-sw {
            background: none;
            border: 1px solid rgba(104,152,232,.22);
        }
/* right day-column bits */
.cp-bar {
    width: 3px;
    align-self: stretch;
    border-radius: 2px;
    flex: 0 0 auto;
}

.ai-side .t.done {
    text-decoration: line-through;
    color: var(--nv-ink-3);
}
/* toggled-off categories vanish everywhere (pills, dots, day-card rows);
   END-of-sheet placement wins the cascade over the display rules above */
.cat-hide {
    display: none !important;
}
/* ════════════════════════════════════════════════════════════════════
   v12.1 (batch61, owner) — AI prompt rows ("Assist with Claude",
   "Translate") get the gold border + gold text everywhere they occur
   (compose + event form; the read&reply panel already carries the gold
   aibox). END placement so the colour wins the base .airow rules.
   ════════════════════════════════════════════════════════════════════ */
.airow.aigold {
    border: 1px solid var(--nv-gold);
    background: rgba(232,167,92,.08);
    min-width: 165px; /* owner (2026-08-11 v10) */
}

    .airow.aigold > summary {
        color: var(--nv-gold-bright);
    }

        .airow.aigold > summary .chev {
            color: var(--nv-gold);
        }
/* ════════════════════════════════════════════════════════════════════
   v11.4 (batch62, owner: "labels stretched and unreadable") — cash-flow
   axis labels + latest-value figure are HTML overlays over the stretched
   SVG; percent lefts track the chart geometry at any card width while
   the glyphs stay at their natural proportions.
   ════════════════════════════════════════════════════════════════════ */
.cfx {
    position: relative;
}

    .cfx .cf-yl,
    .cfx .cf-ml,
    .cfx .cf-vl {
        position: absolute;
        line-height: 1;
        white-space: nowrap;
        font-size: 13px;
        color: var(--nv-ink-3);
        pointer-events: none;
    }

    .cfx .cf-yl {
        transform: translateX(-100%);
    }

    .cfx .cf-ml {
        transform: translateX(-50%);
    }

    .cfx .cf-vl {
        font-size: 15px;
        font-weight: 200;
        color: var(--nv-ink);
    }
/* ════════════════════════════════════════════════════════════════════
   v13.0 (batch70 — LOCKED CWA mini-mock) — the four-control top row
   (Assist dropdown · Edit in composer · Language · Regenerate) and the
   two-button bottom pair. The dropdown expands inside its cell; the row
   wraps two-by-two on narrow panels.
   ════════════════════════════════════════════════════════════════════ */
.cwa-top4 {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    align-items: start;
}

    .cwa-top4 .btn,
    .cwa-top4 .ctl {
        height: 36px;
        width: 100%;
        min-width: 0;
    }

    .cwa-top4 details.airow > summary {
        min-height: 36px;
    }

.cwa-bot2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    max-width: 560px;
}

    .cwa-bot2 .btn[disabled] {
        opacity: .45;
        cursor: default;
    }

@media (max-width: 900px) {
    .cwa-top4 {
        grid-template-columns: 1fr 1fr;
    }
}
/* ════════════════════════════════════════════════════════════════════
   v13.1 (batch71, owner) — CWA bottom pair equal heights; the inbox
   search-scope popover (chevron INSIDE the field, checkbox list).
   ════════════════════════════════════════════════════════════════════ */
.cwa-bot2 .btn {
    height: 48px;
}

.srch-wrap,
.acs-wrap {
    position: relative;
    flex: 1;
    min-width: 0;
}

    /*  ⚠⚠ v31.237 (owner, P-9) — ROOM FOR TWO CONTROLS, NOT ONE. The field now
        carries the Search submit AND the scope chevron. 54px reserved space for
        the chevron alone; the pair needs the chevron's 46px plus the button's
        32px plus its hairline and a little air.
        ⚠ `:has(> .srch-go)` KEEPS THE OLD NUMBER TRUE if the button is ever
        taken out again — the reserved space belongs to the control, not to the
        wrapper, which is the lesson `.fld-go:has(> .fld-btn)` already carries. */
    .srch-wrap .input,
    .acs-wrap .input {
        width: 100%;
        padding-right: 54px;
    }

    .srch-wrap:has(> .srch-go) .input,
    .acs-wrap:has(> .srch-go) .input {
        padding-right: 90px;
    }

    /*  ⚠⚠⚠ v31.237 — THE SEARCH BUTTON SITS LEFT OF THE CHEVRON, and the order
        inside the field is deliberate: run the search, then choose where to
        search. `.fld-btn` already draws the hairline at its own left edge, so
        the pair gets ONE divider separating text from controls — which is what
        every other field in the app looks like. The chevron draws none of its
        own and must not gain one, or the field grows a second rule between two
        buttons that belong together.
        ⚠⚠ 46px, AND THE FIRST ATTEMPT AT THIS NUMBER WAS 44. `right` measures
        the button's RIGHT edge from the field's right edge, and the chevron's
        LEFT edge is its own 6px offset plus its 40px width = 46px from that
        same edge. 44 therefore pushed the button's right edge 2px INSIDE the
        chevron's box — two absolutely positioned controls overlapping, which
        nothing in the layout complains about and which puts the scope popover
        under the thumb of a reader aiming at Search. The probe measured it. */
    .srch-wrap > .srch-go,
    .acs-wrap > .srch-go {
        right: 46px;
    }

.srch-toggle {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    width: 40px;
    height: 40px;
    background: none;
    border: 0;
    color: var(--nv-gold);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

/*  ══ v31.237 (owner, P-9) — THE SEARCH-STATE ROW ═══════════════════════════
    One line, above the list, only while a term is in force. It wraps rather
    than scrolls: at 360px the term and the count sit on one line and `Clear
    search` drops to the next, which is legible — a row that scrolls sideways
    hides the very control it exists to offer.
    ⚠ THE TERM IS THE ONLY GOLD THING HERE. It is what changed; the count and
    the clear are supporting text and read as such. */
.eml-srchstate {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin: -2px 0 2px;
    font-size: 12.5px;
    color: var(--nv-muted, #8892a0);
}

    .eml-srchstate .ic {
        display: flex;
        color: var(--nv-gold);
    }

    .eml-srchstate .q {
        color: var(--nv-gold);
        font-weight: 600;
        max-width: min(52vw, 320px);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .eml-srchstate .cnt {
        white-space: nowrap;
    }

    .eml-srchstate .clr {
        margin-left: auto;
        color: var(--nv-blue-bright, #7aa8f0);
        text-decoration: none;
        white-space: nowrap;
        cursor: pointer;
    }

        .eml-srchstate .clr:hover {
            text-decoration: underline;
        }

.srch-pop {
    position: absolute;
    top: 58px;
    left: 0;
    right: 0;
    max-width: 380px;
    z-index: 30;
    border: 1px solid rgba(112,160,238,.30);
    border-radius: 6px;
    background: var(--nv-surface);
    box-shadow: 0 14px 30px rgba(0,0,0,.5);
    padding: 12px 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

    .srch-pop[hidden] {
        display: none !important; /* the .rt-emoji cascade lesson */
    }
/* ════════════════════════════════════════════════════════════════════
   v13.2 (batch72, owner) — folders panel BREAKDOWNS, the archived-row
   account tag, and the save-to-account sheet. END of sheet so nothing
   earlier out-specifies the [hidden] states (the .rt-emoji lesson).
   ════════════════════════════════════════════════════════════════════ */
/* Inbox / Archive rows grow a chevron; the sub-list sits under the row */
.mail-folders .mf-grp {
    display: flex;
    align-items: center;
}

    .mail-folders .mf-grp .mf {
        flex: 1;
        min-width: 0;
    }

.mf-chev {
    flex: 0 0 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 0;
    border-radius: 8px;
    padding: 0;
    color: var(--nv-gold); /* toolkit: icons are gold */
    cursor: pointer;
}

    .mf-chev svg {
        transition: transform .15s ease;
    }

    .mf-chev[aria-expanded="true"] svg {
        transform: rotate(180deg);
    }

.mf-sub {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 2px 14px 10px 55px;
}

    .mf-sub .ln {
        display: flex;
        align-items: center;
        gap: 10px;
        min-width: 0;
        font-size: 14.5px;
        color: var(--nv-ink-3);
    }

        .mf-sub .ln > span {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .mf-sub .ln b {
            margin-left: auto;
            flex: 0 0 auto;
            font-weight: 400;
            font-variant-numeric: tabular-nums;
            color: var(--nv-ink-2);
        }

        .mf-sub .ln.gold,
        .mf-sub .ln.gold b {
            color: var(--nv-gold-bright);
        }

    .mf-sub[hidden] {
        display: none !important;
    }
/* the account tag on archived list rows (Acc code · name) */
.mail .tag.acc {
    color: var(--nv-gold-bright);
    border-color: rgba(232,167,92,.45);
    max-width: 230px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* save-to-account sheet: the type-ahead result list */
.sv-results {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 260px;
    overflow: auto;
    margin-bottom: 10px;
}

    .sv-results .acc-hit {
        display: flex;
        align-items: center;
        gap: 10px;
        width: 100%;
        padding: 10px 12px;
        border: 1px solid rgba(104,152,232,.18);
        border-radius: 8px;
        background: none;
        color: var(--nv-ink-2);
        font-family: inherit;
        font-size: 15px;
        text-align: left;
        cursor: pointer;
    }

        .sv-results .acc-hit:hover {
            border-color: var(--nv-gold);
            color: var(--nv-ink);
        }

        .sv-results .acc-hit .code {
            flex: 0 0 auto;
            color: var(--nv-gold-bright);
            font-variant-numeric: tabular-nums;
        }

        .sv-results .acc-hit .nm {
            flex: 1;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

/* ════════════════════════════════════════════════════════════════════
   v13.5 (batch73, owner) — SAVE-TO-ACCOUNT TREE (v1's cross-catalog
   hierarchy look): entity → account → folders, gold text, triangle
   toggles, dotted indent guides. END of sheet for the cascade.
   ════════════════════════════════════════════════════════════════════ */
.sv-results {
    max-height: 320px;
}

.sv-ent {
    display: flex;
    flex-direction: column;
}

.sv-node {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-width: 0;
    padding: 7px 10px;
    background: none;
    border: 0;
    border-radius: 8px;
    color: var(--nv-gold-bright);
    font-family: inherit;
    font-size: 15px;
    text-align: left;
    cursor: pointer;
}

    .sv-node:hover {
        background: rgba(232,167,92,.08);
    }

    .sv-node .nm {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .sv-node .code {
        flex: 0 0 auto;
        color: var(--nv-ink-3);
        font-size: 13px;
        font-variant-numeric: tabular-nums;
    }

    .sv-node .dbtag {
        flex: 0 0 auto;
        font-size: 12.5px;
        color: var(--nv-ink-3);
        border: 1px solid rgba(104,152,232,.25);
        border-radius: 6px;
        padding: 1px 7px;
    }

.sv-enthead {
    color: var(--nv-gold); /* toolkit: the entity roots gold, as v1 */
}

    .sv-enthead .tri {
        display: inline-flex;
        flex: 0 0 auto;
        transition: transform .15s ease;
    }

    .sv-enthead[aria-expanded="true"] .tri {
        transform: rotate(90deg);
    }

.sv-kids {
    display: flex;
    flex-direction: column;
    margin-left: 13px;
    padding-left: 9px;
    border-left: 1px dotted rgba(232,167,92,.35);
}

    .sv-kids[hidden] {
        display: none !important;
    }

.sv-folder {
    color: var(--nv-ink-2);
    font-size: 14.5px;
}

/* ════════════════════════════════════════════════════════════════════
   v13.6 (batch74, owner) — the folders panel's BULK "Save to account"
   row: gold, sits above Delete in the actions group, enabled only while
   grid rows are ticked. END of sheet for the cascade.
   ════════════════════════════════════════════════════════════════════ */
.mail-folders .mf-save {
    margin-top: 12px;
    border-top: 1px solid rgba(104,152,232,.13);
    border-radius: 0;
    padding-top: 14px;
    color: var(--nv-gold-bright);
}

    .mail-folders .mf-save .fi {
        color: var(--nv-gold);
    }

    .mail-folders .mf-save.disabled {
        opacity: .38;
        pointer-events: none;
    }

    /* when Save opens the actions group, Delete loses its own separator */
    .mail-folders .mf-save + .mf-del {
        margin-top: 2px;
        border-top: 0;
        padding-top: 9px;
    }

/* ════════════════════════════════════════════════════════════════════
   v13.7 (batch74.1, owner) — the PHONE folders sheet's bulk "Save to
   account" row. Behaviour is entirely the shared _SaveAccountSheet
   (data-svopen + the same handlers); this is presentation only.
   ════════════════════════════════════════════════════════════════════ */
.folders-sheet .fld.fld-save {
    width: 100%;
    background: none;
    border: 0;
    border-top: 1px solid rgba(104,152,232,.13);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--nv-gold-bright);
}

    .folders-sheet .fld.fld-save .fi {
        color: var(--nv-gold);
    }

    .folders-sheet .fld.fld-save.disabled {
        opacity: .38;
        pointer-events: none;
    }

/* ════════════════════════════════════════════════════════════════════
   v14.0 (batch75, owner — AI-ASSISTED SAVING, mock locked) — the
   save-similar card + candidate sheet, the rule proposal card + rules
   sheet, and the save sheet's extras rows. END of sheet for the cascade.
   ════════════════════════════════════════════════════════════════════ */

/* the gold suggestion card on the list */
.card.suggest {
    display: flex;
    align-items: center;
    gap: 14px;
    border-color: rgba(232,167,92,.45);
    background: rgba(232,167,92,.06);
}

    .card.suggest .ic {
        color: var(--nv-gold);
        flex: 0 0 auto;
    }

    .card.suggest .txt {
        min-width: 0;
    }

        .card.suggest .txt .t {
            font-size: 15.5px;
        }

        .card.suggest .txt .s {
            color: var(--nv-ink-2);
            font-size: 13.5px;
        }

    .card.suggest .end {
        margin-left: auto;
        display: flex;
        align-items: center;
        gap: 10px;
        flex: 0 0 auto;
    }

    .card.suggest .chip {
        cursor: pointer;
    }

.sim-x {
    background: none;
    border: 0;
    color: var(--nv-ink-3);
    font-size: 19px;
    cursor: pointer;
    padding: 4px 8px;
}

/* the candidate sheet */
.sim-list {
    max-height: 300px;
    overflow: auto;
    margin: 6px 0 2px;
}

.sim-grp {
    font-size: 12.5px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
    margin: 12px 2px 6px;
}

    .sim-grp b {
        color: var(--nv-gold-bright);
        font-weight: 400;
    }

.sim-cand {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px;
    border: 1px solid rgba(104,152,232,.15);
    border-radius: 10px;
    margin-bottom: 6px;
    cursor: pointer;
}

    .sim-cand .txt {
        flex: 1;
        min-width: 0;
    }

    .sim-cand .from {
        display: block;
        font-size: 14.5px;
    }

    .sim-cand .subj {
        display: block;
        color: var(--nv-ink-2);
        font-size: 13.5px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .sim-cand .why {
        flex: 0 0 auto;
        font-size: 12px;
        color: var(--nv-ink-3);
        border: 1px solid rgba(104,152,232,.25);
        border-radius: 6px;
        padding: 1px 8px;
        white-space: nowrap;
    }

        .sim-cand .why.ai {
            color: var(--nv-gold-bright);
            border-color: rgba(232,167,92,.45);
        }

/* the on-demand Claude row (AI PROMPT ROWS GOLD — toolkit 10) */
.findmore {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    border: 1px solid rgba(232,167,92,.55);
    background: rgba(232,167,92,.06);
    border-radius: 10px;
    padding: 11px 14px;
    margin: 10px 0 4px;
    color: var(--nv-gold-bright);
    font-family: inherit;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
}

    .findmore .cost {
        margin-left: auto;
        color: var(--nv-ink-3);
        font-size: 12px;
        white-space: nowrap;
    }

    .findmore.busy {
        opacity: .5;
        pointer-events: none;
    }

/* the rule proposal card */
.card.rulecard {
    border-color: rgba(232,167,92,.45);
    max-width: 640px;
}

    .card.rulecard .rc-head {
        display: flex;
        align-items: center;
        gap: 10px;
        color: var(--nv-gold);
    }

        .card.rulecard .rc-head b {
            color: var(--nv-ink);
            font-weight: 400;
        }

    .card.rulecard .rc-map {
        display: flex;
        align-items: center;
        gap: 12px;
        flex-wrap: wrap;
        padding: 10px 0 6px;
    }

        .card.rulecard .rc-map .who,
        .card.rulecard .rc-map .acct {
            border: 1px solid rgba(104,152,232,.25);
            border-radius: 10px;
            padding: 7px 14px;
            font-size: 14.5px;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .card.rulecard .rc-map .acct {
            border-color: rgba(232,167,92,.5);
            color: var(--nv-gold-bright);
        }

        .card.rulecard .rc-map .arrow {
            color: var(--nv-ink-3);
        }

    .card.rulecard .rc-meta {
        color: var(--nv-ink-3);
        font-size: 13px;
    }

    .card.rulecard .rc-act {
        display: flex;
        gap: 12px;
        margin-top: 12px;
    }

        .card.rulecard .rc-act form {
            flex: 1;
            margin: 0;
        }

        .card.rulecard .rc-act .btn {
            width: 100%;
            height: 44px;
        }

.btn.goldline {
    background: none;
    border: 1px solid rgba(232,167,92,.55);
    color: var(--nv-gold-bright);
}

/* the rules sheet rows */
.rule-line {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 10px;
    border: 1px solid rgba(104,152,232,.15);
    border-radius: 10px;
    margin-bottom: 6px;
}

    .rule-line .txt {
        flex: 1;
        min-width: 0;
    }

    .rule-line .who {
        font-size: 14.5px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .rule-line .acct {
        color: var(--nv-gold-bright);
        font-size: 13px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .rule-line .btn.sm {
        height: 38px;
        padding: 0 14px;
        font-size: 13.5px;
        flex: 0 0 auto;
    }

/* the save sheet's extras rows (mock C) */
.opt-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    border: 1px solid rgba(232,167,92,.35);
    background: rgba(232,167,92,.05);
    border-radius: 10px;
    padding: 10px 12px;
    margin: 8px 0 0;
    cursor: pointer;
    font-size: 14.5px;
}

    .opt-row input {
        margin-top: 2px;
        flex: 0 0 auto;
    }

    .opt-row .s {
        display: block;
        font-style: normal;
        color: var(--nv-ink-3);
        font-size: 12.5px;
    }

/* ════════════════════════════════════════════════════════════════════
   v15.0 (batch77, owner — FINANCIALS Phases 1+2, mock v2.1 locked) —
   the hub, the invoice list rows, the entry wizard and the history
   card. Reuses the shell, cards, chips, inputs and .sv-* tree styles.
   END of sheet for the cascade.
   ════════════════════════════════════════════════════════════════════ */

/* the hub: tree + task tiles */
/* v27.4 - the hub's own width, as ONE value. The module panel, the gap and
   the tile grid's cap all read from these, and so does the header row, so
   the chip in the head can line up with the last card's right edge without
   anybody re-typing a number that later drifts. */
:root {
    --fin-panel-w: 290px;
    --fin-hub-gap: 18px;
    --fin-tiles-w: 720px;
    --fin-hub-w: calc(var(--fin-panel-w) + var(--fin-hub-gap) + var(--fin-tiles-w));
}

.fin-hub {
    display: grid;
    /* v16.5 (batch84, owner overflow report) — minmax(0,1fr): the GRID
       LESSON again; a bare 1fr track let the tiles push past the viewport */
    grid-template-columns: var(--fin-panel-w) minmax(0, 1fr);
    gap: var(--fin-hub-gap);
    align-items: start;
    min-width: 0;
    max-width: 100%;
}

@media (max-width: 1023.98px) {
    .fin-hub {
        grid-template-columns: minmax(0, 1fr);
    }
}

/*  ⚠⚠ v31.115 (batch311, owner - A-57) — THE "SUGGESTED NEXT" CARD IS NOW THE
    HUB'S THIRD GRID CHILD. Owner: *"place AI Suggested text card below the
    module Cards on the right - only for 04-Screen and 05-Screen."*

    It was a SIBLING of `.fin-hub` and therefore started at the page's left
    edge, running under the TREE as well as under the tiles. Inside the grid it
    can be told which track to occupy.

    ⚠⚠ THE HUB'S OWN `gap` IS LEFT ALONE, AND THAT WAS A CORRECTION. The card
    used to be separated from the hub by `.scroll`'s inline `gap:16px`; inside
    the grid that separation becomes `.fin-hub`'s gap, which is 18. My first
    attempt pinned the hub's ROW gap to 16 to preserve it — and the probe's
    control caught what that actually did: below 1024 the hub is ONE column, so
    the tree and the tiles are also separated by the row gap, and both of them
    moved up 2px. **Changing a shared gap to protect one child moves every other
    child.** So the gap stays 18, and the only thing this round moves is the
    card it was asked to move: on 01/02/03 it now sits 2px lower than before,
    and the tree and tiles do not move at all. */

/*  ⚠ 760px IS NOT A NEW NUMBER — it is the inline `max-width` this card has
    carried since v24.0, moved here unchanged so a media query can reach it.
    An inline style beats a stylesheet rule, so the 04/05 cap below could only
    have been written as `!important` while the attribute stood. */
#sugCard {
    grid-column: 1 / -1;
    max-width: 760px;
}

/*  04-Screen and 05-Screen ONLY, exactly as asked. Track 2 is the tiles' track,
    so the card lands directly under the module cards; the cap is the TILES' own
    variable, so the two right edges agree by construction rather than by two
    numbers somebody has to keep in step — the v27.4 rule this page's head
    already follows. */
@media (min-width: 1366px) {
    #sugCard {
        grid-column: 2;
        max-width: min(var(--fin-tiles-w), 100%);
    }
}

/* v16.5 — the tree group heads (accordion, standard chevron) */
.fin-tree .sv-head {
    color: var(--nv-gold);
    cursor: pointer;
    font-family: inherit;
    font-size: inherit;
    text-align: left;
    min-height: 36px;
}

.fin-tree .sv-node {
    min-height: 36px;
}

    .fin-tree .sv-node.muted {
        color: var(--nv-ink-3);
        font-size: 13.5px;
    }

.fin-hub .sv-node.on {
    background: rgba(232,167,92,.14);
    border-radius: 8px;
    color: var(--nv-ink);
}

.fin-hub a.sv-node {
    text-decoration: none;
}

.fin-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 14px;
    max-width: min(var(--fin-tiles-w), 100%);
    min-width: 0;
}

.fin-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 18px 10px;
    text-align: center;
    text-decoration: none;
    color: var(--nv-ink-2);
    opacity: .55;
}

    .fin-tile .ic {
        color: var(--nv-gold);
    }

    .fin-tile.live {
        opacity: 1;
        border-color: rgba(232,167,92,.55);
        color: var(--nv-ink);
        cursor: pointer;
    }

/* ═══ v28.9 (owner - THE UPGRADE LOOK, study C5 "conic halo") ═══════════════
   THE HUB TILES GET THE SAME TURNING GRADIENT as the ghost button, so the two
   read as one system rather than two decisions.

   ⚠ THE DORMANT/LIVE DISTINCTION IS THE TILE'S REAL JOB and it is preserved,
   sharpened rather than replaced: a dormant tile's halo is mostly blue with
   gold only at the turn; a LIVE tile's is gold at both ends. Combined with
   the existing opacity change, "this one is available" still reads before the
   label does.

   ⚠⚠ WHY A MASKED RING AND NOT THE BACKGROUND TRICK - this one matters more
   here than on the button: .card carries backdrop-filter and, since the
   owner's edit, NO background of its own. A border-box gradient layer would
   paint a solid fill straight over the blur on every tile. The ring paints
   the edge only.

   ⚠⚠⚠ THE @supports GUARD IS LOAD-BEARING: without mask-composite the
   ::before is a filled rectangle, not a ring. Guarded, an unsupported browser
   keeps today's tile exactly - blue border, gold when live.

   ⚠ THE FAINT FILL (background below) is the one part of this study that is
   not purely a border. It stops the halo reading as detached from the tile.
   It is 5% and sits over the card's blur; delete that one line if it reads
   heavy on a busy page and the halo still works. */
@supports ((-webkit-mask-composite: xor) or (mask-composite: exclude)) {
    .fin-tile {
        position: relative;
        isolation: isolate;
        border-color: transparent;
        background: radial-gradient(120% 100% at 50% 0%, rgba(120,165,240,.05), transparent 70%);
    }

        /* ⚠ .fin-tile.live sets border-color gold in the rule above and has
           the higher specificity, so it has to be cleared here too or the
           live tile would wear a solid border AND a halo. */
        .fin-tile.live {
            border-color: transparent;
        }

        .fin-tile::before {
            content: "";
            position: absolute;
            inset: 0;
            border-radius: inherit;
            padding: 1px;
            background: conic-gradient(from 210deg, rgba(232,167,92,.75), rgba(47,127,214,.50) 25%, rgba(104,152,232,.10) 50%, rgba(47,127,214,.50) 75%, rgba(232,167,92,.75));
            -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            -webkit-mask-composite: xor;
            mask-composite: exclude;
            pointer-events: none;
        }

        .fin-tile.live::before {
            background: conic-gradient(from 210deg, var(--nv-gold-bright), rgba(47,127,214,.55) 25%, rgba(232,167,92,.20) 50%, rgba(47,127,214,.55) 75%, var(--nv-gold-bright));
        }
}

/* invoice rows (list + history) */
.inv-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 2px;
    border-top: 1px solid rgba(104,152,232,.12);
    min-width: 0;
}

    .inv-row:first-of-type {
        border-top: 0;
    }

    .inv-row .av {
        flex: 0 0 42px;
        height: 42px;
        border-radius: 50%;
        background: rgba(232,167,92,.14);
        color: var(--nv-gold-bright);
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .inv-row .txt {
        flex: 1;
        min-width: 0;
    }

    .inv-row .t {
        font-size: 15.5px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .inv-row .s {
        color: var(--nv-ink-3);
        font-size: 13px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /*  ⚠⚠⚠ THE AMOUNT COLUMN HAS A STATED FLOOR SINCE v31.109 (batch304,
        owner: *"Please vertical align all the document view clips"*).

        **THE CLIPS WERE NEVER THE PROBLEM.** They sit immediately to the LEFT
        of the amount in a flex row, so their x is whatever is left after the
        amount has taken what it needs - and "14,223.76 C" is wider than
        "8,621.24 C". Every row put its clip somewhere slightly different.
        A floor on the amount fixes the column, and the clip follows it.

        ⚠ IT IS A FLOOR, NOT A WIDTH. A larger figure still takes the room it
        needs rather than being clipped; only the ragged edge below that size
        goes away. 104px carries "24,464.96 C" at this weight with a little to
        spare.
        ⚠⚠ `.inv-row` IS SIX SURFACES, not one - Enquiry, ArInvoices,
        ApInvoices, BankImport, BankRec and `_ApArMoneyList`. The alignment is
        an improvement on all six and was measured on the narrowest of them at
        390px, where `.txt` ellipsises as it already did. */
    .inv-row .amt {
        text-align: right;
        white-space: nowrap;
        flex: 0 0 auto;
        /*  ⚠ 112px, NOT 104. The first floor was measured against the rows in
            the owner's screenshot and "24,464.96 C" needs 105 - one pixel over,
            which put that row's clip one pixel out. **A floor chosen from the
            sample in front of you is a floor the next figure walks through.**
            112 carries six figures and a letter; beyond that a row widens and
            moves its own clip, which is self-limiting and visible. */
        min-width: 112px;
    }

    /*  ⚠ THE LINE DETAILS ARE A LINK NOW and must not look like one - the row
        already reads as a row, and an underlined blue block inside it would be
        a second visual language. It inherits, and says so on hover. */
    .inv-row a.txt {
        color: inherit;
        text-decoration: none;
        display: block;
    }

        .inv-row a.txt:hover .t,
        .inv-row a.txt:focus-visible .t {
            color: var(--nv-gold-bright);
        }

        .inv-row a.txt:focus-visible {
            outline: 2px solid var(--nv-gold);
            outline-offset: 2px;
            border-radius: 4px;
        }

.st {
    font-size: 12px;
    border-radius: 999px;
    padding: 2px 10px;
    flex: 0 0 auto;
    white-space: nowrap;
}

    .st.draft {
        color: var(--nv-ink-2);
        border: 1px solid rgba(104,152,232,.35);
    }

    .st.appr {
        color: #8fd3a0;
        border: 1px solid rgba(88,179,104,.5);
    }

    .st.posted {
        color: var(--nv-gold-bright);
        border: 1px solid rgba(232,167,92,.5);
    }

/* the wizard */
.fin-stepper {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 4px;
}

    .fin-stepper .step {
        display: flex;
        align-items: center;
        gap: 8px;
        color: var(--nv-ink-3);
        font-size: 14px;
    }

        .fin-stepper .step .n {
            width: 32px;
            height: 32px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-style: normal;
            font-size: 14px;
            border: 1.5px solid rgba(104,152,232,.35);
        }

        .fin-stepper .step.on {
            color: var(--nv-gold-bright);
        }

            .fin-stepper .step.on .n {
                border-color: var(--nv-gold);
            }

        .fin-stepper .step.done .n {
            background: rgba(88,179,104,.15);
            border-color: rgba(88,179,104,.5);
            color: #8fd3a0;
        }

    .fin-stepper .line {
        flex: 0 1 90px;
        height: 1.5px;
        background: rgba(104,152,232,.2);
    }

.fld-wrap {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    position: relative;
}

.fl-hint {
    font-size: 12px;
    color: var(--nv-ink-3);
    /* v19.7 (batch108, owner) — FIELD HINTS ARE ONE ROW (toolkit): long
       labels ("VAT analysis — control statement") clamp with an ellipsis;
       the _Layout tooltip mirror carries the full wording on hover. The
       fixed row height also keeps grid columns ALIGNED when a hint carries
       an inline control (the Net/Gross chip). */
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-height: 18px;
    line-height: 18px;
}

.fin-grid3 {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 12px;
}

@media (max-width: 767.98px) {
    .fin-grid3 {
        grid-template-columns: 1fr;
    }
}

.fin-flags {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.flag {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* owner (batch112): no box around the flag — the gold rule above the
       Automation block carries the separation instead (.fin-rule) */
    border-radius: 10px;
    padding: 9px 14px;
    font-size: 14px;
    color: var(--nv-ink-2);
    cursor: pointer;
}

    .flag.on,
    .flag:has(input:checked) {
        border-color: rgba(232,167,92,.55);
        color: var(--nv-ink);
    }

.fin-line .lh {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
}

.fin-line .n {
    font-size: 12.5px;
    letter-spacing: .1em;
    color: var(--nv-gold);
}

.vatpill {
    font-size: 12.5px;
    color: #8fc0f0;
    background: rgba(47,127,214,.16);
    border-radius: 999px;
    padding: 3px 10px;
    white-space: nowrap;
}

/*  v31.25 (owner: "In the line items, please add the VAT display for that
    line ... add a view pill class='chip' on the card for each line") - THE
    REVIEW STEP'S LINE ROW.
    ⚠ IT ADDS A WRAPPER AND NOTHING ELSE. `.vatpill` and `.chip` are the
    components the Lines step already uses; the review row only needed
    somewhere to put them. Styling them again here would be two definitions of
    one thing - the four-copy lesson, in CSS.
    ⚠ IT WRAPS. A line can carry a rate code, a rate, two analysis codes, two
    amounts and a chip; on 01-Screen that is more than one row's worth, and a
    review summary that scrolls sideways is unusable. */
.rv-line {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

    .rv-line + .rv-line {
        margin-top: 6px;
        padding-top: 6px;
        border-top: 1px solid rgba(104, 152, 232, .10);
    }

    .rv-line .rv-meta {
        display: flex;
        align-items: center;
        gap: 8px;
        flex-wrap: wrap;
    }

    .rv-line .rv-amt {
        font-size: 16px;
        color: var(--nv-ink-3);
        white-space: nowrap;
        font-variant-numeric: tabular-nums;
    }

.fin-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}

/*  ⚠⚠ v31.251 (owner, P-28) — THE TWO CURRENCY ROWS UNDER THE TOTAL. They
    answer "what was paid, and what did it come to in our own money", so they
    must be READABLE AND SUBORDINATE: the gold 28px total stays the headline and
    these sit beneath it at body size. Same row geometry, quieter voice — a
    second 28px figure would compete with the total and a reader would not know
    which number the document is actually for. */
.fin-total.nv-bothcur {
    margin-top: 4px;
}

    .fin-total.nv-bothcur .lab {
        font-size: 13px;
        color: var(--nv-muted, #8a8a8a);
        letter-spacing: .02em;
    }

    .fin-total.nv-bothcur .amt {
        font-size: 15px;
        font-variant-numeric: tabular-nums;
    }

    .fin-total .lab {
        font-size: 18px;
        color: var(--nv-gold);
    }

    .fin-total .amt {
        font-size: 28px;
    }

/* the history card rows */
.fin-hrow {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 0;
    border-top: 1px solid rgba(104,152,232,.10);
    min-width: 0;
}

    .fin-hrow:first-of-type {
        border-top: 0;
    }

    .fin-hrow .txt {
        flex: 1;
        min-width: 0;
    }

    .fin-hrow .t {
        font-size: 14px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* v21.1 (batch120, owner: "the card is being shown over two rows in
       02-Screen, 03-Screen and 04-Screen") — .t already clamped to one row
       but .s did not, so in the narrow right column the date · TRN line
       wrapped and every history row became two rows tall. 01 (full width)
       and 05 (wide column) had the space, which is exactly why only the
       middle three showed it. */
    .fin-hrow .s {
        color: var(--nv-ink-3);
        font-size: 12.5px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .fin-hrow .amt {
        white-space: nowrap;
        font-size: 14.5px;
        flex: 0 0 auto;
    }

/* the fin panel's dimmed later-phase rows */
.fin-panel .mf.dim {
    opacity: .45;
    cursor: default;
}

/* ═══ v15.2 (batch79, owner) — fin card formatting fixes ═══ */

/* the kv rows every fin card leans on (label left, value RIGHT — mock
   parity; batch79 lesson: mock classnames need their CSS ported too) */
.card .kv {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    padding: 3px 0;
}

    .card .kv .k {
        color: var(--nv-ink-2);
        font-size: 14px;
        min-width: 0;
    }

    /*  ⚠ v31.109 (owner): the OPENING BALANCE value at 28px - *"only ... and
        all the other class='v' remain 14.5px"*. A modifier class, because the
        owner's own note names the alternative and rejects it: a rule written
        against `#enqBal > div:nth-child(3) > span.v` moves onto a different
        figure the first time a row is inserted above it. */
    .card .kv .v.v-lg {
        font-size: 28px;
        line-height: 1.15;
    }

    .card .kv .v {
        white-space: nowrap;
        font-size: 14.5px;
        text-align: right;
    }

/* supplier-row avatars — the mail palette (g0…g4), picked by row index */
.inv-row .av.g0 {
    background: #33526b;
    color: #e9eef7;
}

.inv-row .av.g1 {
    background: #6d5a8e;
    color: #e9eef7;
}

.inv-row .av.g2 {
    background: #2e7d64;
    color: #e9eef7;
}

.inv-row .av.g3 {
    background: #9a6a16;
    color: #f4ecdc;
}

.inv-row .av.g4 {
    background: #874a52;
    color: #f4e5e7;
}

/* the small label ("open" / "last") sits BELOW the amount */
.inv-row .amt .s {
    display: block;
    color: var(--nv-ink-3);
    font-size: 12px;
    font-style: normal;
}

/* ═══ v16.1 (batch80.1, owner) — rail world clock ROTATOR + weather:
   one city at a time (v1 worldClockRotator), wide rail only ═══ */
.rl-world {
    margin-top: 22px;
    display: flex;
    flex-direction: column;
    align-self: stretch;
    margin-left: 14px;
    margin-right: 14px;
}

/* icon-only rail (mail-app pages) — no room, the rotator leaves */
.mail-app .siderail .rl-world {
    display: none;
}

.rlw {
    /* owner (batch81): borderless — the gold hairline alone frames it */
    padding: 14px 12px 12px;
    text-align: center;
    position: relative;
    min-height: 108px; /* steady height through the fade */
}

    /* the mock's gold hairline across the top */
    .rlw::before {
        content: "";
        position: absolute;
        top: 0;
        left: 14px;
        right: 14px;
        height: 1px;
        background: rgba(232,167,92,.55);
    }

    .rlw .c {
        color: var(--nv-gold);
        font-size: 18px;
        /*letter-spacing: 2px;*/
        margin-bottom: 6px;
    }

    .rlw .t {
        color: var(--nv-gold-bright);
        font-size: 42px;
        font-weight: 200;
        letter-spacing: 1px;
        line-height: 1.1;
    }

    .rlw .w {
        color: var(--nv-ink-2);
        font-size: 16px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        margin-top: 4px;
    }

        /* outline weather icons — nav-icon style, gold (toolkit rule 1);
           owner: 30px (batch82) → 32px (batch127, with .c at 18px and .w at
           16px — the rail now clears the 16px caption floor too) */
        .rlw .w svg {
            flex: 0 0 auto;
            color: var(--nv-gold);
            width: 32px;
            height: 32px;
        }

/* v16.0 — tree accordion chevron (toolkit: ONE node expanded; the standard
   chevron everywhere, rotating closed) */
.sv-chev svg {
    transition: transform .18s ease;
    display: block;
}

.sv-head.closed .sv-chev svg {
    transform: rotate(-90deg);
}


/* ═══ v16.2 (batch81, owner) — INPUT + BUTTON heights system-wide ═══
   Inputs are 32px EVERYWHERE (email, planner, financials, assistant…):
   this end-of-file override beats the older 40/44/48px per-screen rules
   and inline styles. Textareas, the rich-editor surface (.rt-ed) and the
   file picker keep their own heights. Buttons: .btn = 51px in tokens.css. */
input.input:not([type="file"]),
select.input,
summary.input,
/*  ⚠ v31.62 - the country picker's face is a BUTTON wearing `.input`, and
    without this line it would be the only 36px control on a card of 32s.
    It is the first `button.input` in the app; nothing else is affected. */
button.input,
div.input:not(.rt-ed) {
    /* owner (batch82): 36px — 32 was a step too far.
       v21.0 (batch119, owner) — reversed: 32px is the height now. */
    height: 32px !important;
    min-height: 32px !important;
}


/* ═══ v17.0 (batch85, owner) — THE LOCKED TREE-VIEW STANDARD ═══
   Template = the Organisation picker. Levels are roles, not depth:
   L1 t-sect = CAPITALISED muted-blue band + hairline (top sections)
   L2 t-grp  = gold non-capital group, standard END-chevron (down closed,
               180° up open), ONE open per level (accordion)
   L3 t-leaf = data row: 24px gold outline icon · label · right meta slot;
               selected = soft gold pill + GREEN borderless ✓
   Cards: ONE radius (var(--r-card)) + the gold ✕ for manual closing. */

.tree-head {
    display: flex;
    align-items: center;
    margin-bottom: 8px;
}

    /* v21.0 (batch119, owner: "Overall Header font, font-style is wrong")
       — the locked mock types the card head as `font-weight 300 · 20px ·
       gold-bright` (.tree h3 there). Nothing in the app said so, so a bare
       <h2> fell through to the BROWSER default — bold, 24px — in every
       tree card: the menu tray, the save sheet, the fin tray and the find
       sheet. One rule fixes all of them. */
    .tree-head h2 {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 20px;
        font-weight: 300;
        color: var(--nv-gold-bright);
    }

.t-x {
    margin-left: auto;
    width: 32px;
    height: 32px;
    display: grid;
    place-content: center;
    border: 0;
    background: none;
    color: var(--nv-gold-bright);
    font-size: 17px;
    cursor: pointer;
    border-radius: var(--r-card);
}

    .t-x:hover {
        background: rgba(232,167,92,.1);
    }

.t-sect {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 38px;
    padding: 0 10px;
    border: 0;
    background: none;
    text-align: left;
    color: #8fb4ea;
    font-size: 12.5px;
    text-transform: uppercase;
    border-bottom: 1px solid rgba(104,152,232,.28);
    border-radius: 0;
    cursor: pointer;
}

    .t-sect svg {
        margin-left: auto;
        color: #8fb4ea;
        transition: transform .18s ease;
        flex: 0 0 auto;
    }

    .t-sect.open svg {
        transform: rotate(180deg);
    }

.t-grp {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 36px;
    padding: 4px 10px;
    border: 0;
    background: none;
    border-radius: var(--r-card);
    color: var(--nv-gold);
    font-family: inherit;
    font-size: 15.5px;
    font-weight: 300;
    cursor: pointer;
    text-align: left;
}

    .t-grp:hover {
        background: rgba(104,152,232,.08);
    }

    .t-grp .meta {
        margin-left: auto;
        display: inline-flex;
        align-items: center;
        gap: 8px;
    }

    .t-grp svg.chev {
        margin-left: auto;
        /*color: var(--nv-ink-3);*/
        transition: transform .18s ease;
        flex: 0 0 auto;
    }

    /* when a meta slot (catalog tag) precedes it, the meta takes the auto
       margin and the chevron just follows */
    .t-grp .meta + svg.chev {
        margin-left: 0;
    }

    .t-grp.open svg.chev {
        transform: rotate(180deg);
    }

/* v21.1 (batch120, owner: "remove the lines appearing in the left side of
   each node — it is not part of our toolkit specification") — the child
   block indents, and that is ALL it does. The 1px blue guide is struck from
   the locked tree-view: depth is carried by the indent and by the L1/L2/L3
   type, never by a rule. */
.t-kids {
    margin-left: 12px;
    padding-left: 10px;
}

    .t-kids.flat {
        margin-left: 4px;
        padding-left: 6px;
    }

    .t-kids[hidden] {
        display: none !important;
    }

.t-leaf {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 36px;
    padding: 4px 10px;
    border: 0;
    background: none;
    border-radius: var(--r-card);
    color: var(--nv-ink-2);
    font-family: inherit;
    font-size: 15px;
    font-weight: 300;
    text-decoration: none;
    cursor: pointer;
    text-align: left;
    min-width: 0;
}

    .t-leaf:hover {
        background: rgba(104,152,232,.08);
    }

    .t-leaf svg.ic {
        color: var(--nv-gold);
        flex: 0 0 auto;
    }

    .t-leaf > span:first-of-type:not(.meta) {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .t-leaf .lb {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .t-leaf .meta {
        margin-left: auto;
        color: var(--nv-ink-3);
        font-size: 13px;
        white-space: nowrap;
        display: inline-flex;
        align-items: center;
        gap: 8px;
    }

    .t-leaf.on {
        background: rgba(232,167,92,.14);
        color: var(--nv-ink);
    }

    .t-leaf .tick {
        color: var(--nv-good);
        font-size: 15px;
    }

.t-empty {
    display: flex;
    align-items: center;
    min-height: 36px;
    padding: 4px 10px;
    color: var(--nv-ink-3);
    font-size: 13.5px;
}


/* ═══ v17.1 (batch86, owner) ═══ */

/* 20px breathing room at the end of every page scroll — as an appended
   spacer, so per-screen padding rules (incl. the phone bottom-nav
   clearances) stay untouched (batch87: the padding rule was overridden) */
.scroll::after {
    content: "";
    display: block;
    flex: 0 0 20px;
    height: 20px;
}

/* ⋯ menu-tray opener — 01/02-Screens only (the panel is off-canvas there) */
.fin-tray-btn {
    display: none;
    margin-left: auto;
}

@media (max-width: 1023.98px) {
    .fin-tray-btn {
        display: flex;
    }
}

/* the tray sheet carries the shared _FinPanel — undo its desktop placement */
.fin-tray .mail-folders {
    display: flex !important;
    flex-direction: column;
    position: static;
    width: auto;
    max-width: none;
    border: 0;
    background: none;
    padding: 6px 0 0;
    margin: 0;
    box-shadow: none;
}

/* AWAITING REVIEW card — empty height matches the month card; more ⟶ */
.card.awrev,
.card.fs-month {
    min-height: 158px;
}

.card.awrev {
    display: flex;
    flex-direction: column;
}

    .card.awrev .subclamp {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .card.awrev .more {
        margin-top: auto;
        margin-left: auto;
        color: var(--nv-gold-bright);
        text-decoration: none;
        font-size: 13.5px;
        padding-top: 8px;
    }

/* ⋯ menu links (reply / reply all / forward) — mirror the button rows */
.msg-menu .mm-link {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 11px 16px;
    color: var(--nv-ink-2);
    font-size: 15px;
    text-decoration: none;
    text-align: left;
}

    .msg-menu .mm-link:hover {
        background: rgba(232,167,92,.08);
    }

    .msg-menu .mm-link svg {
        color: var(--nv-gold);
        flex: 0 0 auto;
    }

/* the blue separator between the reply set and the standard items */
.msg-menu .mm-sep {
    border-top: 1px solid rgba(104,152,232,.35);
    margin: 6px 12px;
}


/* owner (batch87) — screen heads: heavy glass blur */
.screen-head {
    backdrop-filter: blur(48px) saturate(140%);
    -webkit-backdrop-filter: blur(48px) saturate(140%);
}

/* ═══ v18.0 (batch89, owner — Phase 3, mock v2 locked) — the VAT/type
   SELECTOR grammar: an input-shaped button (gold code · muted name ·
   standard end-chevron) opening a panel in the locked tree grammar (L1-style
   band heading, 36px leaf rows, green borderless ✓, one panel open). Used by
   the transaction-type picker and the line VAT trio.
   v23.2 (batch128, owner css cleanup) — 32px tall, the toolkit's input
   height, in place of the old 36px one-off. ═══ */
.vsel {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    min-height: 32px;
    width: 100%;
    background: var(--nv-surface-2);
    /*  ⚠ v31.53 - THE HAIRLINE, THIRD OF THREE. Owner: *"The down chevron
        EVERYWHERE should also implement the hairline divider everywhere."*
        This one is an element chevron, not a background image, so the divider
        is a background layer on the BUTTON and the chevron gets 8px of
        padding-left to stand clear of it.
        ⚠ MEASURED: `.vsel` is 32px, the chevron is 18px wide and its left edge
        sits 27px from the right border. 34px puts this line in the same place
        as `.fld-go`'s and `select.input`'s - all three align across a form. */
    background-image: linear-gradient(rgba(112,160,238,.30), rgba(112,160,238,.30));
    background-repeat: no-repeat;
    background-position: right 34px center;
    background-size: 1px 22px;
    border: 1px solid rgba(104, 152, 232, .25);
    border-radius: var(--r-input);
    color: var(--nv-ink-2);
    font: 300 14px 'Poppins', sans-serif;
    padding: 0 8px 0 10px;
    cursor: pointer;
    text-align: left;
}

    .vsel:hover {
        border-color: rgba(232, 167, 92, .5);
    }

    .vsel b {
        color: var(--nv-gold);
        font-weight: 400;
        white-space: nowrap;
    }

    .vsel .nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        flex: 1 1 auto;
        min-width: 0;
    }

    .vsel svg.chev {
        margin-left: auto;
        /*  ⚠ v31.53 - 8px INSIDE the chevron's own box, not a bigger gap. With
            `margin-left: auto` the box's RIGHT edge is pinned, so padding grows
            it leftwards and the glyph does not move a pixel; what moves is
            where the label has to stop.

            ⚠⚠⚠ AND IT NEEDS `content-box`, WHICH A MEASUREMENT IS THE ONLY WAY
            TO KNOW. tokens.css sets `* { box-sizing: border-box }`, so the
            svg's own `width="18"` is treated as the BORDER box: the padding
            ate the glyph instead of growing the box, and the arrow was drawn
            in 10px inside an unchanged 18px box. It looked like nothing had
            happened - measured `chevBoxW: 18` with `padding-left: 8px`
            applied, which is the tell. `content-box` puts the 18 back on the
            glyph and the 8 outside it.
            MEASURED after: box 26px, left edge 35px from the right, the label
            stops at 43px and the divider is at 34px - 9px of air on the text
            side, 1px on the chevron side. */
        box-sizing: content-box;
        padding-left: 8px;
        flex: 0 0 auto;
        /* v31.31 (owner: "All down arrows chevrons should be gold") - this
           one is edited in place rather than overridden at the foot of the
           file: at (0,2,1) it beats the base `.chev` rule no matter where
           that sits. Specificity, not order. */
        color: var(--nv-gold, #e8a75c);
        transition: transform .18s ease;
    }

    .vsel.open svg.chev {
        transform: rotate(180deg);
    }

.vpanel {
    /* ══ v27.7 (owner) - THE PANEL READS WIDER THAN ITS FIELD ═════════════
       The picker panels inherited the width of whatever field they hang
       under, and in a three-column grid that is far too narrow for a code
       plus a name plus a rate. The owner asked for a 280px floor and a
       target width; read as 390px - 39px would be narrower than a single
       word, and every leaf row carries at least a code and a name.

       "provided it does not overflow the right border of the container":
       a panel in the LAST column would otherwise grow past the card's edge,
       so those grow LEFTWARDS instead (the rule below) - their right edge
       stays pinned to the field they belong to. Panels in earlier columns
       overflow to the right over their neighbour, which is ordinary
       dropdown behaviour and stays inside the card. */
    width: 390px;
    min-width: 280px;
    max-width: calc(100vw - 40px);
    position: relative;
    margin-top: 6px;
    background: var(--nv-surface);
    border: 1px solid rgba(104, 152, 232, .3);
    border-radius: var(--r-card);
    padding: 8px;
    box-shadow: 0 14px 34px rgba(0, 0, 0, .45);
    max-height: 320px;
    overflow: auto;
}

    .vpanel[hidden] {
        display: none;
    }

    .vpanel .t-leaf b {
        color: var(--nv-gold);
        font-weight: 400;
        min-width: 42px;
    }

    .vpanel .t-leaf .nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        flex: 1 1 auto;
        min-width: 0;
    }

.v-sect {
    display: flex;
    align-items: center;
    min-height: 32px;
    padding: 0 10px;
    color: #8fb4ea;
    font-size: 12px;
    letter-spacing: .14em;
    text-transform: uppercase;
    border-bottom: 1px solid rgba(104, 152, 232, .28);
    margin-bottom: 4px;
}

.v-more {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
    padding: 4px 10px;
    margin-top: 4px;
    border-top: 1px solid rgba(104, 152, 232, .18);
    color: var(--nv-gold);
    font-size: 14px;
    cursor: pointer;
    border-radius: var(--r-input);
}

    .v-more:hover {
        background: rgba(104, 152, 232, .08);
    }

/* ═══ v18.2 (batch92, owner — TOOLKIT lock-ins) ═══
   1) DATE/TIME PICKER GLYPHS — GOLD, never black (v18.3, owner): the
      temporal inputs carry color-scheme dark (dark native popups) and the
      indicator is recoloured to the toolkit gold (#e8a75c) via the filter
      below. Applies system-wide, now and future.
   2) MASTER MENU (three bars) — 01/02-Screens only: pages with no ⋯ menu
      and no bottom nav carry an .mmt-btn opener wired to the _MenuTray
      sheet. Same visibility rule as the ⋯ tray opener. */
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"] {
    color-scheme: dark;
}

    input[type="date"]::-webkit-calendar-picker-indicator,
    input[type="time"]::-webkit-calendar-picker-indicator,
    input[type="datetime-local"]::-webkit-calendar-picker-indicator,
    input[type="month"]::-webkit-calendar-picker-indicator,
    input[type="week"]::-webkit-calendar-picker-indicator {
        cursor: pointer;
        opacity: 1;
        /* any source colour → flat black → the toolkit gold */
        filter: brightness(0) saturate(100%) invert(74%) sepia(31%) saturate(749%) hue-rotate(336deg) brightness(96%) contrast(91%);
    }

.mmt-btn {
    display: none;
    margin-left: auto;
}

@media (max-width: 1023.98px) {
    .mmt-btn {
        display: flex;
    }
}

/* ═══ v18.3 (batch93, owner — TOOLKIT lock-ins) ═══
   1) HEADER ROW — the page-head icon buttons (back · ⋯/☰) always share ONE
      row, exactly like .screen-head.mail-head; heads never wrap.
   2) BUTTONS — .btn text NEVER overflows to a second line: one line with an
      ellipsis; the layout script mirrors the full text into title, so hover
      shows it (tooltip). */
.screen-head,
.flowhead {
    /* v18.4 (batch94, owner screenshot): ONLY .mail-head was flex — the
       plain heads (Financials hub) stacked back · title · ☰ on three rows.
       EVERY head is now the same one-row flex as .mail-head. */
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: nowrap;
}

    .screen-head .htext {
        flex: 1 1 auto;
        min-width: 0;
    }

    /* v18.4 — head titles NEVER wrap: one line + ellipsis (the layout script
   mirrors the full text into title, so hover shows it) */
    .screen-head h1,
    .flowhead h1,
    .screen-head .sub {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        min-width: 0;
    }

    .flowhead h1 {
        flex: 1 1 auto;
    }

    .screen-head .iconbtn,
    .flowhead .iconbtn {
        flex: 0 0 auto;
    }

.btn {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

    .btn > span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

/* ═══ v18.7 (batch97, owner — TOOLKIT lock-ins) ═══
   1) CATALOG INDICATOR — ONE look everywhere: muted-blue text inside a
      fully-rounded muted-blue circle/pill (.dbtag was only styled inside
      .sv-node before; this is now the global standard).
   2) FOOTER CLEARANCE — the main-menu footer rides every page on
      01/02-Screens, so the scroll's breathing spacer grows to clear it
      there (the 20px spacer returns from 1024 up, where the footer hides). */
.dbtag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    height: 20px;
    min-width: 20px;
    padding: 0 8px;
    border: 1px solid rgba(104, 152, 232, .45);
    border-radius: 999px;
    color: #8fb4ea;
    font-size: 11.5px;
    letter-spacing: .04em;
    white-space: nowrap;
}

/* v18.8 (batch98, owner) — the footer's clearance spacer.
   v19.7 (batch108, owner) — the footer hides again from 1024 (the side
   rail serves there), so the 132px clearance returns to BELOW 1024 only;
   from 1024 the base 20px breathing room applies. */
@media (max-width: 1023.98px) {
    .scroll::after {
        flex: 0 0 132px;
        height: 132px;
    }
}

/* ═══ v18.9 (batch99, owner — lines-page formatting) ═══
   On stacked layouts (below 1024, where the right column follows the main
   column) the wizard's scroll no longer STRETCHES to fill the viewport —
   the giant empty band between the step buttons and the cards is gone; the
   right-column stack follows immediately. The footer clearance rides the
   stacked column's own margin instead of the scroll spacer. */
@media (max-width: 1023.98px) {
    .fin-app .scroll {
        flex: 0 0 auto;
        min-height: 0;
    }

        .fin-app .scroll::after {
            flex: 0 0 0px;
            height: 0;
        }

    .fin-app .ai-side {
        margin-top: 0;
    }
}

/* ═══ v19.3 (batch103, owner) ═══ */

/* THE CUSTOM DIALOG (toolkit) — the reusable v1-style N-logo card over the
   err-pop grammar: nvAlert / nvConfirm / [data-nvconfirm] (_Layout). */

/* v19.3.1 (owner report: blank uncloseable dialog on every page) — the
   err-pop grammar sets display:flex, which BEATS the [hidden] attribute's
   UA display:none — so the empty dialog rendered from page load and
   close() (hidden = true) changed nothing. The attribute must win.
   LESSON (toolkit): any element toggled via `hidden` whose class sets its
   own `display` needs this guard. */
#nvDlg[hidden],
#nvDlgScrim[hidden] {
    display: none !important;
}

.nv-dlg .nv-dlg-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.nv-dlg .nv-dlg-logo {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid rgba(232,167,92,.55);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--nv-gold-bright);
    font-size: 22px;
    font-weight: 200;
    background: radial-gradient(circle at 35% 30%, rgba(232,167,92,.16), rgba(232,167,92,.04));
}

.nv-dlg .nv-dlg-btns {
    display: flex;
    gap: 12px;
    margin-top: 4px;
}

    .nv-dlg .nv-dlg-btns .btn {
        flex: 1;
    }

/* THE <1024 SCROLL-SPACER GAP (owner report): on stacked layouts the 132px
   .scroll::after spacer sat BETWEEN the grids and the trailing card stack —
   a huge dead band — while the .ai-side below already carries its own 120px
   bottom clearance for the fixed footer. Below 1024, any page whose card
   stack FOLLOWS the scroll drops the spacer and the stretch entirely (the
   v18.9 fin-app exemption, generalized). Pages with no trailing .ai-side
   keep the 132px spacer — there the scroll IS the page end. */
@media (max-width: 1023.98px) {
    .app-main:has(> .ai-side) .scroll {
        flex: 0 0 auto;
        min-height: 0;
    }

        .app-main:has(> .ai-side) .scroll::after {
            flex: 0 0 0px;
            height: 0;
        }
}

/* ═══ v19.4 (batch106, owner) ═══ */

/* THE CUSTOM CALENDAR (toolkit, _Layout nvCal) — the native date-picker
   popup is browser chrome and unstylable, so date inputs open the app's
   own calendar instead: the native indicator hides behind a gold glyph
   zone at the input's right end; the panel below is the locked .vpanel
   grammar, fixed to the body. Time/month inputs keep the native picker
   (gold-filtered by the v18.2 rules). */
input.input[type="date"]::-webkit-calendar-picker-indicator,
input.input[type="month"]::-webkit-calendar-picker-indicator,
input.input[type="time"]::-webkit-calendar-picker-indicator {
    display: none;
}

input.input[type="date"],
input.input[type="month"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23e8a75c' stroke-width='1.4' stroke-linecap='round'><rect x='3.5' y='5' width='17' height='15.5' rx='2'/><path d='M3.5 9.5h17M8 3v4M16 3v4'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 18px 18px;
    padding-right: 36px;
}

/* v19.6 (batch107, owner) — the time inputs join the custom-picker family
   (a gold clock glyph; the panel shows hour/minute columns) */
input.input[type="time"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23e8a75c' stroke-width='1.4' stroke-linecap='round'><circle cx='12' cy='12' r='8.5'/><path d='M12 7.5V12l3 2'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 18px 18px;
    padding-right: 36px;
}

/* v19.6 (owner: "only shows momentarily") — the panel carries its OWN box
   styling now instead of the .vpanel class: the page pickers' global
   outside-click closeAll() hides every .vpanel and was hiding this panel
   on the very click that opened it. */
.nvcal {
    position: fixed;
    z-index: 60;
    width: 272px;
    background: var(--nv-surface);
    border: 1px solid rgba(104,152,232,.3);
    border-radius: var(--r-card);
    padding: 8px;
    box-shadow: 0 14px 34px rgba(0,0,0,.45);
}

    .nvcal[hidden] {
        display: none;
    }

    /* MONTH picker — the 12-month grid under the year header */
    .nvcal .nvc-mgrid {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 4px;
    }

        .nvcal .nvc-mgrid .nvc-mon {
            height: 40px;
            text-transform: capitalize;
        }

    /* TIME picker — hour + minute columns, 5-minute steps */
    .nvcal .nvc-twrap {
        display: flex;
        gap: 6px;
    }

    .nvcal .nvc-tcol {
        flex: 1;
        max-height: 220px;
        overflow: auto;
        display: flex;
        flex-direction: column;
        gap: 2px;
    }

        .nvcal .nvc-tcol .nvc-day {
            flex: 0 0 34px;
        }

    .nvcal .nvc-head {
        display: flex;
        align-items: center;
        gap: 8px;
        min-height: 36px;
        padding: 0 2px 6px;
    }

    .nvcal .nvc-title {
        flex: 1;
        text-align: center;
        color: var(--nv-gold);
        font-size: 14px;
        letter-spacing: .04em;
        text-transform: capitalize;
    }

    .nvcal .nvc-nav {
        width: 32px;
        height: 32px;
        border: 1px solid rgba(104,152,232,.25);
        border-radius: 6px;
        background: none;
        color: var(--nv-ink-2);
        cursor: pointer;
        font-family: inherit;
        font-size: 16px;
        line-height: 1;
    }

        .nvcal .nvc-nav:hover {
            border-color: rgba(232,167,92,.5);
        }

    .nvcal .nvc-grid {
        display: grid;
        grid-template-columns: repeat(7, 1fr);
        gap: 2px;
    }

    .nvcal .nvc-dow {
        text-align: center;
        font-size: 11px;
        letter-spacing: .06em;
        color: #8fb4ea;
        text-transform: uppercase;
        padding: 4px 0;
    }

    .nvcal .nvc-day {
        height: 34px;
        border: 1px solid transparent;
        border-radius: 6px;
        background: none;
        color: var(--nv-ink-2);
        font: 300 13.5px 'Poppins', sans-serif;
        cursor: pointer;
    }

        .nvcal .nvc-day:hover {
            background: rgba(104,152,232,.12);
        }

        .nvcal .nvc-day.out {
            color: var(--nv-ink-3);
            opacity: .45;
        }

        .nvcal .nvc-day.today {
            border-color: rgba(232,167,92,.5);
        }

        .nvcal .nvc-day.sel {
            background: rgba(232,167,92,.18);
            color: var(--nv-gold-bright);
        }

/* the BA grid-list panel anchors under its slot */
.ba-slot {
    position: relative;
}

    .ba-slot .ba-panel {
        position: absolute;
        left: 0;
        right: 0;
        top: 100%;
        z-index: 25;
        margin-top: 6px;
    }

/* ═══ v19.7 (batch108, owner) ═══ */

/* THE [hidden] GUARD, UNIVERSAL (toolkit lesson, third strike): any class
   that sets its own `display` silently defeats the hidden attribute — the
   blank dialog (v19.3.1) and the history pager that "hid" nothing (the
   .fin-hrow rows kept their display:flex) were both this bug. The
   attribute now wins everywhere, for good. */
[hidden] {
    display: none !important;
}

/* ═══ v20.2 (batch111, owner) ═══ */

/* DOCUMENTS ARE ALWAYS A COLOURFUL, CLICKABLE CLIP (toolkit rule): never a
   bare 📎 glyph — a gold clip that opens the document (or its transaction). */
.docclip {
    flex: 0 0 auto;
    color: var(--nv-gold-bright);
}

/* v25.6 (owner): the clip is BARE now - no border, no plate, just the
   gold clip. Hover brightens instead of painting a box. */
.docclip-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 34px;
    width: 34px;
    height: 34px;
    color: var(--nv-gold-bright);
    cursor: pointer;
    text-decoration: none;
    border: 0;
    background: transparent;
    padding: 0;
    font-family: inherit;
}

    .docclip-btn:hover {
        color: #ffd9a6;
    }

/* ═══ v31.112 (batch307, owner, mock-up LOCKED) — THE ADD-DOCUMENT TRIGGER ═══
   Owner: *"Please us +- as shown in the image on every line in a new column as
   the add trigger."* A plus with a rule under it — and ⚠ **NOT a plus over a
   minus**: *"second mark is NOT a minus that removes a document."*

   ⚠⚠ IT IS 28px AND FIXED, AND THAT IS THE POINT. batch304 straightened the
   amount column by giving `.inv-row .amt` a 112px floor, and the owner reported
   the crooked clips that preceded it. A control in a new column that could grow
   — with a label, a count, a focus ring that adds width — would push the amount
   out of true again on the rows that had it. This one is the same width whatever
   it is showing.
   ⚠ It is MUTED at rest, unlike the gold clip: the clip says "there is
   something here", the plus says "you may add something", and only the first of
   those is news about the row. ═══ */
/*  ⚠⚠⚠ AND IT IS NOT DRAWN BELOW 768, WHICH IS A MEASUREMENT AND NOT A TASTE.
    MEASURED at 390 on a 350px card: with the + in the row, the amount column
    read TWO x values (137 and 127) and `.txt` collapsed to ZERO on every row
    that carries a clip; with it removed, one x value and the row is what it was.
    **The + is what pushed it over.** `.inv-row` at 390 has no slack left to give
    - that is A-49, which is its own round across six surfaces - and taking the
    last 28px of a row that already cannot show its own date would be paying for
    this feature with the reader's transaction reference.
    ⚠ THE DESKTOP ROW IS WHERE THIS IS USED and it is unaffected: from 768 up the
    amount column stays single-valued with the + present, measured at five bands.
    ⚠ A-52 in the matrix: if you want it on a phone too, it arrives with the
    mobile row that A-49 calls for, not before it. */
/* ═══ v31.113 (batch309, owner) — THE TWO RECONCILED CHIPS ARE ONE WIDTH ═══
   Owner: *"In Transaction Enquiry the Unreconciled and Reconciled buttons must
   be the same width always."*

   ⚠⚠ A FIXED TRACK PLUS ELLIPSIS, WHICH IS NOT A COMPROMISE — IT IS THE ONLY
   FORM THAT SURVIVES FIVE LANGUAGES. "Same width always" cannot mean "as wide
   as the longer word", because the longer word is a different one in each
   language and German's *Nicht abgeglichen* is half again the length of
   *Unreconciled*. Two equal tracks with the overflow ellipsised, and the full
   word on the title, is exactly what the Ledger/Orders pair on this same page
   has done at 72px since v25.6, and what v27.7 settled for this very row.
   ⚠ 124px is MEASURED, not chosen: it is what the longest of the ten words
   across the five language files needs at this weight, rounded up to the next
   4px. Re-derive it if the wording changes. ═══ */
.chip.rec-chip {
    width: 124px;
    min-width: 0;
    justify-content: center;
    padding: 0 8px;
}

    .chip.rec-chip > span,
    .chip.rec-chip {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/* ═══ v31.113 (batch309, owner) — THE CLIP COLUMN HOLDS ITS WIDTH ═════════
   A history row that has no documents gets a SPACER the width of the clip
   button, not nothing. ⚠ MEASURED on the enquiry in batch307: when a row's
   fixed tail differs from its neighbours' and `.txt` has no slack left to
   absorb it, the AMOUNT COLUMN goes crooked — which is the fault batch304 was
   raised to fix. The clip is 34px, so the gap is 34px.
   ⚠ It is a SPACER, never a dimmed clip: the owner's A-34 is that a clip
   appears only where there is something to view. ═══ */
.docclip-gap {
    flex: 0 0 34px;
    display: inline-block;
}

/* ═══ v31.113 (batch309, owner) — THE SELECTED TICK IS PINNED TO THE ROW ═══
   Owner: *"The white tick showing selected item in history should be pinned
   next to the t class."* It was a flex SIBLING of `.txt`, so it sat out at the
   row's right edge beside the amount and read as a property of the FIGURE
   rather than of the row. ⚠ Moving it inside `.t` also takes 26px of fixed
   width out of the row's tail, which the reference and date get back. ═══ */
.tick.tick-in {
    margin-left: 8px;
    flex: none;
}

.docadd-btn,
.docadd-gap {
    display: none;
}

@media (min-width: 768px) {
    .docadd-btn {
        display: inline-flex;
    }

    .docadd-gap {
        display: inline-block;
    }
}

.docadd-btn {
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    /* ⚠ NO `display` HERE - it is set by the pair above, and restating it in a
       block that comes AFTER the media query would win on source order and put
       the button back on a 390px screen. */
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
    color: var(--nv-ink-2);
    font-family: inherit;
    line-height: 1;
}

    .docadd-btn:hover,
    .docadd-btn:focus-visible {
        color: var(--nv-gold-bright);
    }

    .docadd-btn .pl {
        font-size: 15px;
        font-weight: 500;
    }

    /* the rule under the plus — a mark, never a second control */
    .docadd-btn .mn {
        display: block;
        width: 11px;
        height: 1px;
        background: currentColor;
    }

/* the refused-file list is one line per file, so the box has to keep them */
#nvDocAddErr {
    white-space: pre-line;
}

/* v25.6 (owner - TOOLKIT: THE DOC CLIP OPENS DOCUMENTS): the picker that
   appears when a transaction carries SEVERAL documents - the err-pop
   dialog shell, a doclink row per document. */
.nvdocpick-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 320px;
    overflow: hidden auto;
}

a.doclink {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    color: var(--nv-gold-bright);
    text-decoration: none;
}

    a.doclink .nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    a.doclink:hover .nm {
        text-decoration: underline;
    }

/* THE WANTED FIELD (validation "Take me there"): a gold pulse on the field
   the transaction is missing. */
.nv-wanted {
    animation: nvWanted 2.4s ease-out 1;
    border-radius: var(--r-input);
}

@keyframes nvWanted {
    0%, 100% {
        box-shadow: 0 0 0 0 rgba(232,167,92,0);
    }

    12% {
        box-shadow: 0 0 0 3px rgba(232,167,92,.55);
    }

    60% {
        box-shadow: 0 0 0 3px rgba(232,167,92,.35);
    }
}

/* ═══ v20.3 (batch112, owner) ═══ */

/* THE GOLD RULE (toolkit): a hairline that closes a totals block — sits
   after the TOTAL, above the next section's label. */
.fin-rule {
    height: 1px;
    background: linear-gradient(90deg, rgba(232,167,92,.55), rgba(232,167,92,.14));
    margin: 12px 0 10px;
    border-radius: 1px;
}

/* ═══ v20.5 (batch114, owner) ═══ */

/* THE STAT TILES ARE LINKS (toolkit: a number you can see is a number you
   can open) — no underline, and the gold lift the cards already use. */
a.ai-tile {
    text-decoration: none;
    color: inherit;
    cursor: pointer;
}

    a.ai-tile:hover {
        border-color: rgba(232,167,92,.45);
    }

/* the NEW EMAIL count reads green (owner).
   v26.9 (PRODUCTION TICKET 20260821001 item 3.1): the same green now covers
   the email page's New email chip and its At-a-glance figure, so the one
   unread number looks the same everywhere it appears. */
.ai-tile .n.good,
.chip .n.good,
.ai-glance .n.good {
    color: var(--nv-good);
}

/* ═══ v20.6 (batch115, owner — TOOLKIT: THE DOCUMENT VIEWER) ═══════════════
   "in v1 we had a document viewer to prevent buildup of downloaded document
   each time we want to see a document." Reading a document must not cost a
   copy on disk: every attachment opens in this full-screen sheet, and the
   download becomes a deliberate ⤓ press. This AMENDS the NEW-TAB RULE —
   in-app viewing first, the new tab kept as the escape hatch. Own
   classnames throughout (.nvdoc*), so no page-owned outside-click sweep can
   reach it (the nvCal lesson). Sits under the nv-dlg z-band (40/41) so an
   nvAlert raised from the viewer still lands on top. No scrim: the sheet is
   opaque and full-screen, so a backdrop behind it could never be clicked —
   the stage margin around the document is the click-away zone instead. */
html.nvdoc-lock {
    overflow: hidden;
}

.nvdoc {
    position: fixed;
    inset: 0;
    z-index: 37;
    display: flex;
    flex-direction: column;
    background: linear-gradient(160deg, #050912 0%, #0b1020 55%, #101a30 100%);
}

.nvdoc-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    padding: 8px 10px;
    padding-top: max(8px, env(safe-area-inset-top));
    border-bottom: 1px solid rgba(232,167,92,.22);
    background: rgba(5,9,18,.9);
}

.nvdoc-nm {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 15px;
    font-weight: 200;
    color: var(--nv-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nvdoc-pg {
    display: flex;
    align-items: center;
    gap: 2px;
    flex: 0 0 auto;
}

.nvdoc-count {
    font-size: 13px;
    font-weight: 200;
    color: var(--nv-ink-3);
    min-width: 46px;
    text-align: center;
}

.nvdoc-tools {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
}

/* the viewer's own icon button — the .docclip-btn grammar, gold on glass */
.nvdoc-ic {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    border-radius: 8px;
    border: 1px solid rgba(232,167,92,.30);
    background: rgba(232,167,92,.08);
    color: var(--nv-gold-bright);
    cursor: pointer;
    text-decoration: none;
}

    .nvdoc-ic:hover {
        background: rgba(232,167,92,.20);
        border-color: rgba(232,167,92,.7);
    }

    .nvdoc-ic:disabled {
        opacity: .3;
        cursor: default;
    }

        .nvdoc-ic:disabled:hover {
            background: rgba(232,167,92,.08);
            border-color: rgba(232,167,92,.30);
        }

.nvdoc-stage {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px;
    padding-bottom: max(10px, env(safe-area-inset-bottom));
}

.nvdoc-wrap {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    height: 100%;
    min-height: 0;
}

.nvdoc-frame {
    flex: 1 1 auto;
    width: 100%;
    min-height: 0;
    border: 0;
    border-radius: var(--r-card);
    background: #fff;
}

.nvdoc-note {
    flex: 0 0 auto;
    text-align: center;
    font-size: 12.5px;
    font-weight: 200;
    color: var(--nv-ink-3);
}

.nvdoc-img {
    max-width: 100%;
    max-height: 100%;
    margin: auto;
    border-radius: var(--r-card);
    transform-origin: center center;
}

/* the fail-soft card: an engine that will not render the type inline never
   leaves a blank sheet — it offers the tab and the download instead */
.nvdoc-fb {
    max-width: 420px;
    padding: 24px;
    text-align: center;
}

.nvdoc-fbic {
    color: var(--nv-gold-bright);
}

.nvdoc-fb p {
    margin: 10px 0 18px;
    font-size: 15px;
    font-weight: 200;
    line-height: 1.5;
    color: var(--nv-ink-2);
}

.nvdoc-fbrow {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;
}

/* 01-Screen (390×844): the name takes its own row so the controls never
   crowd out of the bar */
@media (max-width: 560px) {
    .nvdoc-bar {
        flex-wrap: wrap;
    }

    .nvdoc-nm {
        order: 3;
        flex: 1 1 100%;
        font-size: 14px;
    }

    .nvdoc-tools {
        margin-left: auto;
    }
}

/* ═══ v20.7 (batch116, owner — SEARCH & RETRIEVE) ══════════════════════════
   THE FIND SHEET: v1's recent-transactions folder tree (Slovakia · European
   Union · Global → alphabet bucket → supplier → its transactions) in the
   locked tree grammar, with the search v1 never had on top. A side panel
   from 1024 up, full-screen below (01/02-Screens). Own classnames (.find-*),
   and it sits UNDER the document viewer's band (36/37) and the dialog's
   (40/41), so a viewer or an nvAlert raised from a hit lands on top. */
html.find-lock {
    overflow: hidden;
}

.find-scrim {
    position: fixed;
    inset: 0;
    z-index: 34;
    background: rgba(3,6,14,.62);
}

/* Below 1024 the sheet is full-screen and OPAQUE, so the scrim behind it can
   neither be seen nor clicked — the v20.6 lesson, applied up front. It only
   exists from 1024 up, where the panel leaves the page showing beside it.
   There, ✕ · Esc · scrim all close; below, ✕ and Esc do. */
@media (max-width: 1023.98px) {
    .find-scrim {
        display: none;
    }
}

.find-sheet {
    position: fixed;
    inset: 0;
    z-index: 35;
    display: flex;
    flex-direction: column;
    /*background: linear-gradient(160deg, #050912 0%, #0b1020 55%, #101a30 100%);*/
    /*border-left: 1px solid rgba(232,167,92,.22);*/
    border-radius: 8px;
    border: 1px solid rgba(104, 152, 232, .30);
    padding: 0 20px 24px;
    background: linear-gradient(145deg, #010107 0% 0%, #1E1E1E 50%, #13294B 100%);
    font-family: 'Poppins', -apple-system, 'Segoe UI', sans-serif !important;
    margin: 20px;
}

    /* v20.9 (batch118, owner) — the sheet's own head is the app's .tree-head
   block (h2 + the gold ✕); its TYPE now comes from the global .tree-head h2
   rule (v21.0), so this only carries the sheet chrome. */
    .find-sheet > .tree-head {
        flex: 0 0 auto;
        padding-top: max(12px, env(safe-area-inset-top)) !important;
        border-bottom: 1px solid rgba(232,167,92,.22);
    }

.find-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: 12px 14px;
    padding-bottom: max(16px, env(safe-area-inset-bottom));
}

.find-dates {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px;
    margin-top: 8px;
}

/* the two tree CARDS inside the sheet — the locked card (ONE radius, its
   own head, its own gold ✕); the rows themselves are pure .t-sect / .t-grp
   / .t-leaf and carry NO find-specific styling at all.
   v21.0 (batch119, owner: "Width is not aligned with search boxes above
   it") — a .card's 20px padding pushed every row 20px in from the search
   field's edge above it. The card keeps its border on the same line as the
   fields and drops the side padding, so a row's own 10px padding is all
   that separates its text from the field text above. */
.find-body .card.tree {
    margin-top: 12px;
    padding: 12px 2px;
}

    .find-body .card.tree .tree-head {
        margin-bottom: 6px;
        padding: 0 8px;
    }

    .find-body .card.tree > .muted {
        padding: 0 10px;
    }

/* v21.0 (batch119, owner: "We have a rule about minimum font size. Can you
   please retrieve and apply it.") — RETRIEVED: tokens.css declares
   `--fs-caption: 16px` and calls it the CAPTION MINIMUM. Nothing in this
   sheet may read smaller, so the floor is set here for the whole sheet: the
   locked tree's colours, weights and structure are untouched, only the
   sizes that sat below the minimum (12.5 · 13 · 13.5 · 15) come up to it.
   NB no nested comment markers in here — CSS comments do not nest, and an
   inner terminator silently kills every rule that follows. */
.find-sheet,
.find-body .fl-hint,
.find-body .muted,
.find-body .t-sect,
.find-body .t-grp,
.find-body .t-leaf,
.find-body .t-empty,
.find-body .t-leaf .meta,
.find-body .input {
    font-size: var(--fs-caption);
}

    .find-body .t-leaf .meta {
        font-variant-numeric: tabular-nums;
    }

/* the L1 band keeps its capitalised letter-spaced identity at the larger
   size (the mock's letter-spacing was implicit in its font shorthand) */
.find-body .t-sect {
    letter-spacing: .08em; /* owner (batch120) */
}

/* 03-Screen up: a side panel, so the invoice stays visible behind it */
@media (min-width: 1024px) {
    .find-sheet {
        left: auto;
        width: min(520px, 92vw);
        box-shadow: -18px 0 48px rgba(0,0,0,.5);
    }
}

/* v21.0 (batch119, owner: "Put both fields in the same row") — they stay
   side by side at every width; at 32px tall two of them fit 390px. */

/* ═══ v21.0 (batch119, owner) — TODAY'S FOCUS (the dashboard's fourth card)
   One line per thing, in the locked data-row grammar: gold outline icon ·
   label · right meta slot. Anything due or overdue burns gold. */
/*  ⚠⚠⚠ v31.88 (batch283, owner) - THE META DROPS TO A SECOND ROW SO THE LABEL
    GETS THE WHOLE LINE. Owner: *"In home, and on the Todays focus tab, please
    place 'meta hot' in the second row so that span with class='lb' has more
    room."*

    ⚠⚠ THE CARD IS HALF ITS OLD WIDTH FROM v31.86. `.dash-top` went to
    `1fr · 0.5fr · 0.5fr` for the AI Tokens card, so Today's focus lost half of
    its half - MEASURED at 283px at 1440. The label ellipsised against a date
    that never shrinks ("Reply to Megau s.r…" beside "today"), which is the
    label losing an argument to the one item on the row that is always short.

    ⚠ A TWO-COLUMN GRID, NOT A WRAP. `flex-wrap` would put the meta under the
    ICON as well, so the date would sit at the row's left edge under a gold
    glyph rather than under the text it belongs to. The grid keeps the icon in
    its own column spanning both lines and gives the label and the meta the
    second column, one above the other.
    ⚠⚠ `align-items: start` ON THE ICON, not `center`: with two lines of text
    beside it, a vertically centred icon floats between them instead of
    marking the row's start. */
.focus-card .focus-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: 10px;
    row-gap: 1px;
    min-height: 36px;
    padding: 4px 6px;
    border-radius: var(--r-card);
    color: var(--nv-ink-2);
    font-size: var(--fs-caption);
    text-decoration: none;
}

    .focus-card .focus-row:hover {
        background: rgba(104,152,232,.08);
    }

    /*  the icon owns column 1 and spans both text lines */
    .focus-card .focus-row .ic {
        grid-column: 1;
        grid-row: 1 / span 2;
        align-self: center;
        display: inline-flex;
        color: var(--nv-gold);
    }

    /*  ⚠ THE LABEL STILL ELLIPSISES - it now has the whole column to do it in
        rather than whatever the date left over. `minmax(0, 1fr)` on the track
        is what lets it: `min-width: 0` alone does not fire an ellipsis inside
        a grid item. */
    .focus-card .focus-row .lb {
        grid-column: 2;
        grid-row: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /*  ⚠ LEFT-ALIGNED UNDER THE LABEL, not pushed to the right edge. On its own
        line a right-aligned date reads as belonging to nothing; under the text
        it reads as that item's date. */
    .focus-card .focus-row .meta {
        grid-column: 2;
        grid-row: 2;
        justify-self: start;
        color: var(--nv-ink-3);
        font-size: var(--fs-caption);
        white-space: nowrap;
    }

        .focus-card .focus-row .meta.hot {
            color: var(--nv-gold-bright);
        }

/* ═══ v21.5 (batch124, owner) — THE CALENDAR ITEM CARD ═════════════════════
   "Anything shown on the calendar item/card should be clickable … Every item
   on the Calendar should have a custom tooltip which reveals the full details
   of the item in a card." One look, two homes: the hover tooltip and the
   detail card above the day. Built on the locked grammars — .card for the
   box, .tree-head + the gold ✕ for its head, a 24px-ish dot for the
   calendar colour, and label · value rows in the .meta muted key style. */
.ev-detail:empty {
    display: none;
}

/* ⚠ .ev-card's BOX (radius, padding, background, gold edge, margin) is
   defined near the top of this file — v21.5 reused the classname the
   calendar already owned, so the two halves sit 4,500 lines apart. Edit both
   or neither. Only the column layout belongs here. */
.ev-card,
.evtip {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* .card.evtip, not .evtip — the element wears BOTH classes, so a bare
   .evtip only wins by file order and any later .card rule would take the
   surface back. Two classes settle it for good. */
.card.evtip {
    position: fixed;
    /* v21.6 (batch125, owner: "the toolbar however has a transparent
       background making the items unreadable") — a tooltip floats over live
       content, so it cannot borrow the card's translucency. THE TOOLKIT
       TOOLTIP SURFACE, for this and every tooltip after it: the app's own
       opaque 145° gradient, the same one the dialog and the find sheet use. */
    background: linear-gradient(145deg, #010107 0% 0%, #1E1E1E 50%, #13294B 100%);
    border: 1px solid rgba(104,152,232,.30);
    border-radius: 8px;
    z-index: 39; /* above the sheets (34/35) and the doc
                                        viewer (36/37), BELOW the dialog band
                                        (40/41) — a hint must never cover a
                                        decision */
    width: min(320px, calc(100vw - 16px));
    padding: 12px 14px;
    box-shadow: 0 18px 44px rgba(0,0,0,.55);
    pointer-events: none; /* it never eats the click it describes */
}

/* ═══ v31.111 (batch306, owner, mock-up LOCKED) — THE JOURNAL DRILL-DOWN ═══
   The panel `_NvDrill` builds. It wears `.card.evtip` for the surface — the
   opaque 145° gradient, the z-index band, and `pointer-events: none`, all
   inherited from the block above rather than restated — and adds its own
   geometry.

   ⚠⚠⚠ THIS IS THE POINT OF THE ROUND. v1 laid this panel out by concatenating
   HTML with hard-coded pixel margins, using `width: 350px` for a debit and
   `width: 310px` for a credit — TWO WIDTHS FOR WHAT THE READER SEES AS ONE
   COLUMN, which is why its Dr and Cr never lined up. Here the columns are
   declared ONCE, on the grid, and every line inherits them.
   ⚠ `.card.evtip.nvdrill`, two classes: `.card.evtip` caps at 320px, which is
   right for a one-line hint and half of what a three-column ledger extract
   needs. Two classes settle it without touching the hint's own width. ═══ */
.card.evtip.nvdrill {
    /*  ⚠⚠⚠ v31.113 (batch309, owner - A-53): 420, NOT 560. The panel STACKS
        now, so a wide box would put a lone right-aligned figure a long way from
        the account it belongs to - and the owner's reason for choosing the
        stacked layout was that the two places should read alike. In the
        enquiry's 560px card this renders at 420 and in a 370px history card at
        330: the same shape, near enough the same measure.
        ⚠ `.card.evtip.nvdrill`, two classes: `.card.evtip` caps at 320px, which
        is right for a one-line hint. Two classes settle it without touching the
        hint's own width. */
    width: min(420px, calc(100vw - 16px));
    padding: 14px 16px 12px;
}

.nvdrill-head {
    font-size: 15px;
    font-weight: 400;
    color: var(--nv-ink);
}

.nvdrill-sub {
    color: var(--nv-ink-3);
    font-size: 12.5px;
    margin: 2px 0 4px;
}

.nvdrill-busy {
    color: var(--nv-ink-3);
    font-size: 13px;
    padding: 2px 0;
}

.nvdrill-lines {
    font-variant-numeric: tabular-nums;
}

/*  ⚠⚠ ONE LINE IS A BLOCK, NOT A GRID ROW. The grid that used to be here gave
    the account name 270px in the enquiry and 80px in a history card, where it
    wrapped onto three and four lines and made the panel 588px tall. Measured,
    both bands, before the layout changed. */
.nvdrill-line {
    padding: 7px 0;
    border-top: 1px solid rgba(104,152,232,.14);
}

.nvdrill-acc {
    font-size: 13px;
    color: var(--nv-ink);
}

.nvdrill-n {
    color: var(--nv-ink-3);
    display: inline-block;
    min-width: 16px;
}

.nvdrill-desc {
    color: var(--nv-ink-3);
    font-size: 12.5px;
    padding-left: 16px;
}

/*  the amount on its own right-aligned row. ⚠ THE Dr/Cr LABEL IS NOT DECORATION:
    with one figure per line there is no column position left to say which side
    it is on, so the side is written. */
.nvdrill-amt {
    text-align: right;
    font-size: 13.5px;
    color: var(--nv-ink);
    margin-top: 2px;
}

.nvdrill-lab {
    color: var(--nv-gold-bright);
    font-size: 11.5px;
    margin-right: 8px;
}

/* the document-currency line, when a line's Forex mirror is not the base */
.nvdrill-fx {
    color: var(--nv-ink-3);
    font-size: 12px;
    padding-left: 16px;
}

.nvdrill-tot {
    display: flex;
    justify-content: flex-end;
    gap: 18px;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    color: var(--nv-ink);
    border-top: 1px solid rgba(232,167,92,.35);
    margin-top: 6px;
    padding-top: 6px;
}

/* the TRIGGER on the row: the TRN already means "this transaction"; a dotted
   underline says it will tell you more, and nothing else about the row moves.
   ⚠ `cursor: help` ONLY WHERE THE PANEL CAN OPEN. On touch `_NvDrill` returns
   before it wires anything, and a help cursor on a device with no pointer is a
   promise the page does not keep. */
@media (hover: hover) and (pointer: fine) {
    .nv-trn[data-nvdrill] {
        text-decoration: underline dotted rgba(232,167,92,.5);
        text-underline-offset: 3px;
        cursor: help;
    }

    a.nv-trn[data-nvdrill] {
        /* a TRN that is ALSO a link keeps the link's own cursor - it goes
           somewhere, and the panel is the second thing it does. */
        cursor: pointer;
    }
}

/* ═══ v31.113 (batch309, owner — A-55) — THE DOUBLE CLIP ══════════════════
   Owner: *"Use the double clip, the same glyph twice, the back one at 55%
   without a number to decode."*

   ⚠⚠ THE BEHAVIOUR WAS ALREADY RIGHT AND THE MARK WAS SILENT. `_NvDocClip` has
   always opened a single document straight in the viewer and shown the picker
   for several; what a reader could not tell was WHICH was about to happen. The
   back glyph's 55% lives in the SVG so the two marks can never drift apart in
   a way CSS would have to chase.
   ⚠ It is 4px wider than the single clip (24 against 20) inside the SAME 34px
   button, so a list of rows with and without second documents keeps one
   column - which is the alignment batch304 was about. ═══ */
/*  ══ v31.119 (batch315, owner) — THE SECOND PIN IS A COLOUR, NOT A FADE ═══
    Owner: *"At the moment it uses 55% for the second pin when we have multiple
    documents. I would prefer to use the muted blue colour only for the second
    pin to make that more distinctive."*

    ⚠ THE RULE MOVED OUT OF THE PATH AND INTO CSS, and that is the point of the
    change rather than a side effect. The back path carried `opacity=".55"` as
    an INLINE SVG ATTRIBUTE, declared identically in FOUR files (the enquiry and
    the three history surfaces) - so the look of this glyph was four numbers
    that had to be kept in step by somebody remembering. It is now one rule.

    ⚠⚠ AND A FADE IS NOT A DISTINCTION. At 55% the back pin read as the front
    pin drawn badly; a reader had to look twice to tell "one document" from
    "more than one". The brand blue against the gold front pin says it at a
    glance, which is the whole job of the second pin (A-55: *"the same glyph
    twice, the back one at 55% without a number to decode"* - the NUMBER-free
    part of that ruling stands, the 55% is what is superseded).

    ⚠ `--nv-blue-bright` rather than `--nv-blue`: the rows sit on a dark card,
    and the darker brand blue reads as a smudge at 20px against gold. */
.docclip-btn .docclip2 .dc-back,
.docclip .docclip2 .dc-back,
.docclip2 .dc-back {
    stroke: var(--nv-blue-bright);
    opacity: 1;
}

.ev-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
}

.ev-dot {
    flex: 0 0 10px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

.ev-subj {
    min-width: 0;
    font-size: var(--fs-caption);
    color: var(--nv-ink);
}

    .ev-subj.done {
        text-decoration: line-through;
        color: var(--nv-ink-3);
    }

.ev-kv {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-height: 24px;
}

    .ev-kv .k {
        flex: 0 0 92px;
        color: var(--nv-ink-3);
        font-size: 13px;
    }

    .ev-kv .v {
        flex: 1 1 auto;
        min-width: 0;
        color: var(--nv-ink-2);
        font-size: var(--fs-caption);
        overflow-wrap: anywhere;
    }

.ev-notes {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid rgba(104,152,232,.16);
}

    .ev-notes .k {
        color: var(--nv-ink-3);
        font-size: 13px;
        margin-bottom: 2px;
    }

    .ev-notes .v {
        color: var(--nv-ink-2);
        font-size: var(--fs-caption);
        white-space: pre-wrap;
        overflow-wrap: anywhere;
        max-height: 160px;
        overflow-y: auto;
    }

/* v21.6 (batch125, owner: "those cards are not formatted to have same
   width") — Upcoming moved INSIDE the .cal-day2 grid beside the day card, so
   the two share a column by construction rather than by matching margins.
   The standalone wrapper only carries the phone/desktop margin now. */
.cal-upcoming:empty {
    display: none;
}

/* the "+n more" line a capped card closes with — it opens the same day list
   the grid's +more opens, so nothing is ever hidden without a way in */
.ev-more {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding: 2px 6px;
    border: 0;
    background: none;
    color: var(--nv-gold-bright);
    font-family: inherit;
    font-size: var(--fs-caption);
    cursor: pointer;
}

/* one row of the "+3 more" list — the locked leaf shape, minus the icon */
.ev-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 36px;
    padding: 4px 6px;
    border: 0;
    background: none;
    border-radius: var(--r-card);
    color: var(--nv-ink-2);
    font-family: inherit;
    font-size: var(--fs-caption);
    text-align: left;
    cursor: pointer;
}

    .ev-row:hover {
        background: rgba(104,152,232,.08);
    }

    .ev-row .lb {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/* the +more chip now DOES something — it reads as the control it is */
.pmore {
    cursor: pointer;
}

    .pmore:hover {
        color: var(--nv-gold-bright);
    }

/* every calendar pill is a target now */
.pills .pill {
    cursor: pointer;
}

/* ═══ v23.2 (batch128, owner) — INVOICE-ENTRY CARD LAYOUT + JOURNAL LINES ═══

   THE FEED PAIR (found-in-email + awaiting-review) renders from ONE partial
   (_FinFeedCards) mounted TWICE on the entry pages; CSS shows exactly one:
     · 01/02/03 (<1366): the right-column mount (.fs-feed03), immediately
       below the totals card — the owner's 03 mockup, two rows;
     · 04/05 (≥1366): the main-column mount (.fin-feedrow), one row
       immediately below the entry cards — the owner's 05 mockup.

   THE SPLIT COLUMN (.ai-side.fs-split, entry wizard only): on 768–1365 the
   generic .mail-app balanced-columns rule SPLIT the history card mid-list
   (a card taller than the column height defeats break-inside). Two explicit
   stacks instead: fs-a = Journal · totals · feed pair; fs-b = history (+
   month). From 1366 up, and on phones, both wrappers dissolve
   (display:contents) into the normal single stack. */

.fs-split .fs-a,
.fs-split .fs-b,
.fs-feed03 {
    display: contents;
}

.fin-feedrow {
    display: none; /* the ≥1366 mount; off below */
}

@media (min-width: 768px) and (max-width: 1365.98px) {
    /* specificity beats responsive.css's `.mail-app .ai-side` balanced
       columns (display:block !important) — !important + one extra class */
    .mail-app .ai-side.fs-split {
        display: grid !important;
        columns: auto;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 14px;
        align-items: start;
        max-width: 758px;
    }

        .mail-app .ai-side.fs-split > * {
            margin: 0;
            break-inside: auto;
        }

    .fs-split .fs-a,
    .fs-split .fs-b {
        display: flex;
        flex-direction: column;
        gap: 14px;
        min-width: 0;
    }
}

@media (min-width: 1366px) {
    .fs-feed03 {
        display: none; /* the pair rides the main column from here up */
    }

    .fin-feedrow {
        display: flex;
        gap: 14px;
        max-width: 760px; /* aligned with the entry form card */
    }

        .fin-feedrow > .card {
            flex: 1 1 0;
            min-width: 0;
        }
}

/* THE JOURNAL LINE, compacted (owner): account CODE first, then the account
   description, one row; description field 175% of an amount column, Debit
   and Credit sharing the remaining width. */
.jl-acc {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
}

    .jl-acc b {
        color: var(--nv-gold);
        font-weight: 400;
        white-space: nowrap;
    }

    .jl-acc .nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
        color: var(--nv-ink-2);
    }

.fin-jgrid {
    display: grid;
    grid-template-columns: 1.75fr 1fr 1fr;
    gap: 12px;
}

@media (max-width: 767.98px) {
    /* 01-Screen: the description takes the full first row; Dr and Cr share
       the second — three 1.75:1:1 tracks cannot fit 390px. */
    .fin-jgrid {
        grid-template-columns: 1fr 1fr;
    }

        .fin-jgrid > :first-child {
            grid-column: 1 / -1;
        }
}

/* ═══ v23.3 (batch129, owner) — THE SIDE RAIL wears the app surface ═══
   The 145deg surface gradient (the locked tooltip/app surface), replacing
   responsive.css's blue-tinted rail. !important because responsive.css
   loads last: same importance, higher file order — this wins on the
   declaration owner supplied. (The duplicated 100% stop in the owner's
   snippet was a typo — one 100% stop, same rendering.) */
.siderail {
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 50%, #13294B 100%) !important;
}

/* ═══ v23.7 (batch133, owner) — LINE ROWS · MONEY GRID · CURRENCY ROW ═══ */

/* the "LINE n." header is gone: a very small number left of the description
   (owner's explicit sizing — the 16px floor stands for TEXT, this is a
   marker), the ✕ at the row end. */
.fin-lrow {
    display: flex;
    gap: 8px;
    align-items: center;
    min-width: 0;
}

/*  ⚠⚠ v31.162 (owner) — `.lno { text-align: left }`, ON POSTED INVOICES ONLY.
    His rule, scoped rather than global: `.lno` is drawn by the invoice line
    card, the payment card and the journal, and the same partial draws both the
    draft and the posted invoice. `.fin-posted` is set on the card only when
    `Model.IsReadOnly`, so the three other surfaces and the draft keep the
    right-alignment they have always had. */
.fin-line.fin-posted .lno { text-align: left; }

/*  ⚠ v31.163 (owner) — `padding: 6px 0` → `1px 0`. SIZE ONLY: nothing else on
    this rule is touched, and the `.fin-lrow > .lno` override below still sets
    `padding: 0` on the LINE-EDITOR row, so the 32px centred box that v31.82
    measured is unchanged. This 5px comes off the invoice CARD's number only,
    which is the surface the owner is reading. */
.lno {
    flex: 0 0 auto;
    min-width: 16px;
    text-align: right;
    font-size: 19px;
    color: var(--nv-gold);
    align-self: center;
    height: 20px;
    padding: 1px 0;
}

/*  ⚠⚠⚠ v31.82 (owner) - *"the iconbtn for Remove line should be aligned and
    on the same row with the input fields, not take up two rows."*

    THE CAUSE: `.fin-lrow` is `align-items: center` and the thing it centres
    against is a GRID OF LABELLED FIELDS - each `.fld-wrap` is a hint above a
    32px input, about 54px tall, and about 112px once `.fin-jgrid` drops to
    two columns at 767.98px. Centring a 32px control against 54px lands it in
    the gap BETWEEN the label and the input; centring it against 112px lands
    it between the two rows of fields. Neither is a row of its own - it just
    reads as one, which is exactly what was reported.

    THE FIX: bottom-align the two things that flank the grid, so all three
    sit on the input line. The button's `align-self` was INLINE in the row
    builder; it is taken out of there and brought here, because of what the
    measurement below says and because an inline style cannot carry a media
    query.

    ⚠⚠⚠ AT EVERY WIDTH, AND I CHANGED MY MIND ONCE BY LOOKING. At 390px
    `.fin-jgrid` is two columns, so the grid is genuinely TWO ROWS (120px,
    measured) and my first answer was to gate this on 768px and leave the
    phone alone. The screenshot said otherwise: at 390 the centred button
    lands exactly BETWEEN the description row and the amount row - which is
    the reported defect, at phone width. Bottom-aligning puts both flanking
    elements on the LAST input row, so at every width they sit on AN INPUT
    ROW and never between two.
    ⚠ AND THE NUMBER IS NOT LOSING ANYTHING ON A PHONE. Centred against a
    120px block it was already level with the amount LABELS, not with the
    description it numbers; bottom-aligned it is level with the amount inputs
    and with the button, so the row reads as one bounded block.
    Measured `lno-vs-lastInput` / `rm-vs-lastInput` = 0 at 390 / 768 / 1024 /
    1366 / 1920.

    ⚠⚠ SCOPED TO `.fin-lrow`, NOT PUT ON `.lno`. The invoice card uses `.lno`
    in a different flex row - a number beside a plain description, aligned on
    the BASELINE - and bottom-aligning a 19px number against a 16px line of
    text there would be worse than what it does today. Two containers, two
    alignments, and the container decides. */
.fin-lrow > .lno,
.fin-lrow > .iconbtn {
    align-self: flex-end;
}

    /*  ⚠⚠ AND THE NUMBER NEEDED ONE MORE THING, WHICH ONLY THE SCREENSHOT
        SHOWED. Bottom-aligning puts its BOX on the input's box - measured 0.0
        - but `.lno` is a 20px box with 6px of padding carrying a 19px glyph,
        so the digit itself drew BELOW the input's text and read as hanging
        off the corner. The measurement was right and the render was wrong,
        which is the whole reason a look follows a measurement.
        ⚠ A 32px BOX WITH THE DIGIT CENTRED IN IT. Bottom-aligned against a
        32px input, that puts the number on the input's own centre line.
        Padding goes because the height now does the work. */
    .fin-lrow > .lno {
        height: 32px;
        padding: 0;
        display: flex;
        align-items: center;
        justify-content: flex-end;
    }

/* money lines: the description at 200% of the amount column */
.fin-mgrid {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 12px;
}

/* THE CURRENCY ROW SHAPE (owner): [currency + spot/monthly] | [rate ×2] —
   used wherever currency is displayed. */
.fin-curgrid {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 12px;
}

@media (max-width: 767.98px) {
    .fin-mgrid {
        grid-template-columns: 1fr;
    }

    .fin-curgrid {
        grid-template-columns: 1fr;
    }
}

/* ── v24.2/24.3 (batches 138/139, owner) — the HISTORY ⇄ ALLOCATION FLIP
   CARD. The dashboard's flip pattern (Cash Flow ⇄ Bank Balances) on the
   financial entry pages. v24.3 (owner styling pass): the faces are GRID-
   STACKED instead of fixed-height — the flip is exactly as tall as its
   TALLEST face, both cards share that height, and NOTHING scrolls (the
   7-row pagers bound the content). Dots sit at the TOP of each card,
   always visible. Any click stops the auto-rotation (nvFlip). */
/* v24.4 (batch140, owner: "the width of both cards must be exactly the
   same as the cards above — they are overflowing unpredictably") — the
   GRID minmax(0,1fr) lesson: a grid column defaults to max-content, so a
   wide face was stretching the flip past its column. The flip now takes
   EXACTLY its column's width and every level below it may shrink; row
   text ellipsises instead of pushing (the allocation tick can never be
   forced out of the card). */
.fin-flip {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    break-inside: avoid;
}

    .fin-flip .flip-inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        min-height: 0;
        height: auto;
    }

    .fin-flip .flip-face {
        position: static;
        grid-area: 1 / 1;
        display: flex;
        flex-direction: column;
        min-width: 0;
        max-width: 100%;
    }

        .fin-flip .flip-face > .card,
        .fin-flip .flip-face > div > .card {
            flex: 1;
            height: auto;
            width: 100%;
            max-width: 100%;
            min-width: 0;
            box-sizing: border-box;
            overflow: visible;
            margin: 0;
        }

/* ══ v30.9 (batch202, owner) - THE FLIP NEVER OUT-RUNS THE LEFT COLUMN ═════
   .fin-flip already dissolves the dashboard's fixed 250px into a grid whose
   height is `auto` - both faces in one cell, the taller one setting the
   size. That is what let a long history or allocation list push the right
   column past the bottom of the left one.

   nvFitCol (Toolkit/_NvFlip.cshtml) measures the room available and writes
   --fin-flip-max, then adds .is-capped. ⚠ A CAP, NOT A HEIGHT: without the
   class nothing here applies and a short card is exactly as tall as its
   content, which is why this is scoped to .is-capped rather than set on
   .fin-flip itself.

   ⚠⚠ SCOPED TO .fin-flip ON PURPOSE. The dashboard's Cash-Flow and
   Bank-Balances cards share .flip/.flip-inner/.flip-face and must keep their
   fixed 250px - a rule on .flip here would resize the home page. */
.fin-flip.is-capped .flip-face > .card,
.fin-flip.is-capped .flip-face > div > .card {
    max-height: var(--fin-flip-max, none);
    /* ⚠ BOTH AXES, EXPLICITLY. The rule above sets `overflow: visible`, and
       CSS promotes a `visible` axis to `auto` the moment its partner is not
       visible - so naming only overflow-y would hand every capped card a
       horizontal scrollbar it never needed. */
    overflow-x: hidden;
    overflow-y: auto;
}

/* ══ v31.42 (batch239, owner) - THE CARD STOPS SCROLLING; THE ROWS SCROLL ══
   Owner: *"the hist-pager in Invoices/receipts/payments and journal and the
   top flip section including account name and period label should be static
   and visible in the card and ONLY the scroll should be in the grid content
   not the card itself."*

   The cap above is what made the whole card a scroller, so reaching row seven
   took the account name, the period line, the pager and the open balance off
   the top with it. Now the card is a flex COLUMN that clips, the head and the
   foot are fixed-size items at either end, and the row box in the middle takes
   the leftover and scrolls.

   ⚠⚠⚠ `:has(> .fin-hscroll)` IS LOAD-BEARING, NOT TIDINESS. `overflow: hidden`
   on every capped card would CLIP the ones that have no row box - the invoice
   line cards, anything else that grows - turning a scrollbar into lost
   content with no way to reach it. Only a card that has somewhere else to
   scroll may stop scrolling itself. (`:has()` is already a dependency of this
   file; container queries here shipped later than it did.)
   ⚠ AND THE ROW BOX IS PUT THERE BY JS, opt-in, per caller - see
   Toolkit/_NvPager.cshtml. A card whose pager did not opt in never matches
   this rule and behaves exactly as it did before this batch.

   ⚠⚠ `min-height: 0` IS THE HALF THAT ACTUALLY WORKS. A flex item's default
   `min-height: auto` refuses to shrink below its content, so without it the
   row box would push the pager and the open balance out through the bottom of
   the card instead of scrolling - the same trap `.acc-rows` documents. */
.fin-flip.is-capped .flip-face > .card:has(> .fin-hscroll),
.fin-flip.is-capped .flip-face > div > .card:has(> .fin-hscroll) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* ⚠ NO `display` OF ITS OWN. In 'wrap' mode this box is new and its children
   were block siblings in the card a moment ago - they must lay out identically
   now. In 'parent' mode the box already exists (`#invAllocRows`, `#allocRows`)
   and carries its own `display:flex` + 6px gap inline; naming a display here
   would overwrite one of the two and break the other. */
.fin-hscroll {
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* ══ v31.43 (batch240, owner) - THE SAME DEAL FOR A CARD THAT IS NOT A FLIP ══
   Owner, on /generalledger/journalentry?trn=7309: *"The card in ... needs to
   follow the pattern"* and *"It does not adjust height to the height of middle
   column content."*

   ⚠⚠⚠ BOTH SENTENCES ARE ONE ROOT CAUSE. `nvFitCol` - the door that caps a
   right-column card to the middle column and adds `.is-capped` - was only ever
   called on the two money pages' flips. The journal page never called it, so
   its history card had NO cap: it grew to its content and out-ran the middle
   column (the second sentence), and because every cap rule in this file was
   written as `.fin-flip.is-capped ...`, the `.fin-hscroll` box that v31.42 put
   in that card was INERT (the first sentence). The card was carrying the fix
   and nothing was switching it on.

   ⚠ SO THE RULES LOSE THEIR `.fin-flip` PREFIX. There was never anything
   flip-specific about "a capped card scrolls its body, not itself" - the
   prefix was just where the need first appeared. `.fin-flip.is-capped` puts
   the class on the FLIP and caps the card inside it; here the class lands on
   the CARD itself, so it needs its own pair of rules rather than a wider
   selector on the old ones.
   ⚠⚠ `--fin-flip-max` KEEPS ITS NAME even though it is now the generic cap.
   Renaming it would touch _NvFlip and every rule above for no behaviour, and
   a rename in production buys nothing. Read it as "the cap nvFitCol wrote". */
.card.is-capped {
    max-height: var(--fin-flip-max, none);
    /* ⚠ BOTH AXES - the same trap the flip rule documents. */
    overflow-x: hidden;
    overflow-y: auto;
}

    /* ⚠ AND ONLY A CARD WITH SOMEWHERE ELSE TO SCROLL MAY STOP SCROLLING
       ITSELF. Without `:has()` this would clip a capped card that has no row
       box, turning a scrollbar into unreachable content. */
    .card.is-capped:has(> .fin-hscroll) {
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }


    .fin-flip .fin-hrow {
        min-width: 0;
    }

        .fin-flip .fin-hrow .t,
        .fin-flip .fin-hrow .s {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* the allocation tick and the amount never shrink or drop off the row */
        .fin-flip .fin-hrow .amt,
        .fin-flip .fin-hrow .flag,
        .fin-flip .fin-hrow .st {
            flex: 0 0 auto;
        }

    /* the dots lead the card (owner: "at the top, permanently visible");
   v24.5 — they are also FACE SWITCHES (nvFlip): tappable targets. */
    .fin-flip .flip-dots {
        margin: 0 0 8px;
        padding-top: 0;
        cursor: pointer;
    }

        .fin-flip .flip-dots span {
            width: 10px;
            height: 10px;
        }

    /* ── v24.5 (batch141, owner: "Allocations disappeared … cannot see any
   checkboxes") — BELT AND BRACES on the 3D flip: the hidden face is also
   gated with visibility + pointer-events (delayed to mid-turn), so the
   visible face always renders and always takes the clicks whatever a
   browser makes of backface hit-testing. */
    .fin-flip .flip-face {
        transition: visibility 0s linear .35s;
    }

    .fin-flip.is-flipped .flip-front,
    .fin-flip:not(.is-flipped) .flip-back {
        visibility: hidden;
        pointer-events: none;
    }

/*  ══ v31.220 (owner, Q-37 B) — THE THIRD FACE ═════════════════════════════
    Owner: *"Two faces rotate as today; Bank Statement is reached only by
    clicking its chip."*

    ⚠⚠⚠ IT IS DELIBERATELY NOT PART OF THE `rotateY` PAIR. `.flip-front` is
    `rotateY(0)` and `.flip-back` is `rotateY(180deg)`; a card with a front and a
    back has exactly two sides, and turning it into a three-sided carousel would
    have changed the motion of every `.flip` in the build — including the
    dashboard's Cash-Flow ⇄ Bank-Balances card, which asked for nothing. So the
    statement is a flat overlay in the SAME grid cell (`.fin-flip .flip-face` is
    already `grid-area: 1 / 1`), raised by `is-stmt` on the card.

    ⚠⚠ AND THE OTHER TWO ARE HIDDEN UNDER IT, not merely covered: `visibility`
    plus `pointer-events` is the same belt-and-braces v24.5 had to add when
    backface hit-testing let clicks through to the face nobody could see.

    ⚠ SCOPED TO `.fin-flip`. `.flip-stmt` exists on no other card, and none of
    these rules can reach the dashboard. */
.fin-flip .flip-stmt {
    transform: none;
    backface-visibility: visible;
    -webkit-backface-visibility: visible;
    visibility: hidden;
    pointer-events: none;
    z-index: 3;
}

.fin-flip.is-stmt .flip-stmt {
    visibility: visible;
    pointer-events: auto;
}

/*  ⚠⚠⚠ AND THE CARD MUST NOT STILL BE MID-TURN UNDER IT — FOUND BY LOOKING AT
    THE SCREENSHOT, not by reading the probe's JSON, which was green on every
    field it asked about.

    `.flip.is-flipped .flip-inner` is `rotateY(180deg)`, and the statement face
    is a CHILD of that inner. Setting `transform: none` on the FACE does not
    undo a transform on its PARENT: with the rotation still applied, the whole
    statement rendered MIRRORED — "Bank statement" as "tnemetats knaB" — and
    spilled left out of its own column, because a horizontal flip about the
    card's centre puts the right-hand half where the left-hand half was.

    ⚠⚠ THE LESSON IS THE MEASUREMENT, NOT THE RULE. Every assertion p225 made
    passed: the class was on, the three rows were there, the words were right.
    A reader looking at that screen could not have read one of them. **A probe
    that only queries the DOM cannot see a page rendered backwards** — which is
    exactly why the discipline is to LOOK at the screenshot.

    ⚠ It is scoped to `is-stmt`, so the two rotating faces keep their turn: drop
    the statement and `is-flipped` decides again, unchanged. */
.fin-flip.is-stmt .flip-inner {
    transform: none;
}

    .fin-flip.is-stmt .flip-front,
    .fin-flip.is-stmt .flip-back {
        visibility: hidden;
        pointer-events: none;
    }

/*  the three face switches, below the card and outside `.flip-inner` so they
    are readable whichever face is up. */
.flip-tabs {
    margin-top: 8px;
}

/*  ⚠ Q-38's REFUSAL, ON THE FIELD ITSELF. The gold edge says which box the
    sentence below is about; the value is never rewritten. */
.input.nvpp-over {
    border-color: rgba(232, 167, 92, .75);
}

/*  ══ v31.220b (owner) — A READ-ONLY PANEL MUST LOOK READ-ONLY ═════════════
    *"the Payment step should be populated ... with all the fields, read only."*

    The mechanism was already right — the settled panel carries no
    `data-roallow`, so the view-mode sweep disables it — but this build has NO
    `.input:disabled` rule at all, so a disabled box looked exactly like a live
    one. **A panel that is read-only and looks editable invites a click that
    does nothing, which reads as the page being broken.**

    ⚠⚠ IT REUSES `.nvcv-ro`'s LANGUAGE, not a second one: the same flat wash,
    the same softened border, the same `cursor: default` — the honest half —
    that v31.214 settled on for "keeps its place, stops looking like somewhere
    to type". One vocabulary for one idea.

    ⚠⚠⚠ AND IT IS SCOPED TO THIS CARD. A bare `.input:disabled` would restyle
    every disabled field on every view-mode screen in a live system, in a round
    that was asked about payments. That may well be the right change; it is not
    this round's change to make unasked. */
#payPaidCard .input:disabled,
#payPaidCard select:disabled {
    background: rgba(120, 165, 240, .04);
    border-color: rgba(112, 160, 238, .14);
    color: var(--nv-ink-2, #aab3c8);
    box-shadow: none;
    cursor: default;
    opacity: 1;   /* the wash IS the signal; the browser's default fade is not */
}

    /*  the search and ⟳ buttons inside it go quiet too, rather than sitting
        there looking pressable. */
    #payPaidCard .fld-btn:disabled {
        opacity: .35;
        cursor: default;
    }

/*  ⚠⚠ v31.220c (owner: *"selection from pages >1 persisted"*) — THE SELECTED
    STATEMENT ROW SAYS SO. With six rows to a page the chosen one can be off
    screen when the reader comes back to it, so it has to be findable at a
    glance rather than remembered. The mark is a left rule and a faint wash, in
    the gold this app already uses for "this is the one".
    ⚠ IT IS NOT A BACKGROUND ALONE: a wash on a dark card reads as a hover on
    some displays, and hover is not selection. */
/*  ⚠ v31.220d (owner) — the statement card's message sits ABOVE the headline,
    and it earns its spacing only when it has something to say. An empty div
    with a fixed margin would push the heading down on a card where nothing has
    happened yet, which is a gap the reader has to explain to themselves. */
#stmtSay:not(:empty) {
    margin-bottom: 10px;
}

#stmtRows .fin-hrow {
    /*  ⚠ THE PADDING IS ON EVERY ROW, NOT ON THE SELECTED ONE. Adding it with
        the mark would shift the text sideways as the reader clicks, and a row
        that moves under the cursor reads as a mis-click. The screenshot showed
        the rule clipping the date to "L8/09". */
    padding-left: 8px;
}

    #stmtRows .fin-hrow.on {
        background: rgba(232, 167, 92, .07);
        box-shadow: inset 3px 0 0 0 var(--nv-gold);
        border-radius: 3px;
    }


    /* ── v24.7 (batch143, owner: "decide what should be the column width for
   each item and make this width fixed for all rows so that the items
   appear to be in same column") — FIXED COLUMNS on the history and the
   allocation grids. The AMOUNT column is one fixed width on every row,
   right-aligned; the allocation rows add a fixed trailing CONTROL column
   (.fin-scol) that carries either the ✓-pill + Clear or the tick, so
   settled and open rows keep the same geometry. History rows have no
   trailing column — their amounts sit hard against the right edge. ── */
    .fin-flip .fin-hrow .amt,
    #histCard .fin-hrow .amt,
    #histSlot .fin-hrow .amt {
        flex: 0 0 112px;
        width: 112px;
        min-width: 112px;
        display: inline-flex;
        justify-content: flex-end;
        align-items: baseline;
        gap: 4px;
        text-align: right;
        overflow: hidden;
    }

.fin-hrow .fin-scol {
    flex: 0 0 96px;
    width: 96px;
    min-width: 96px;
    display: inline-flex;
    justify-content: flex-end;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

/* the HISTORY heading holds ONE line: long account names ellipsise and the
   full name rides the tooltip (owner). Covers the flip faces AND the plain
   history cards (money/journal views, journal entry). */
.fin-flip h2.section > span,
#histCard h2.section > span,
#histSlot h2.section > span {
    display: block;
    min-width: 0;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ═══ v27.3 (owner, 2026-08-21) - THE CHANGE-ENTITY CHIP IN THE HEADER ROW
   "The change entity button should be located in the same row as the h1 with
   the title of the page ... at the top right of the page."

   The chip kept its look; only where it sits changed. In the head row it must
   never push the title around, so it holds its width, never wraps, and a long
   entity name ellipsises with the full name on the tooltip - the same rule
   every other head element follows. */
.screen-head .org-head {
    flex: 0 0 auto;
    margin-top: 0;
    max-width: 46vw;
    min-width: 0;
}

    .screen-head .org-head .org-name {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    .screen-head .org-head svg {
        flex: 0 0 auto;
    }

/* ═══ v27.4 (owner screenshots, 2026-08-21) ═══════════════════════════════

   1) "Align with the edge of cards." On the Financials hub the header row
   runs the full centred measure while the CONTENT stops at the hub's width,
   so a chip flush to the head's right edge floated alone in the empty band
   past the last tile. The chip now stops where the tiles stop. The margin is
   computed, not typed: 100% is the head's own content width, so the chip's
   right edge lands exactly --fin-hub-w from the same left edge the hub
   starts on, and it collapses to zero the moment the page is narrower than
   the hub. Only from the rail breakpoint up - below that the hub is one
   column and the head's own right edge IS the content edge. */
@media (min-width: 1024px) {
    .screen-head.fin-head > .org-head {
        margin-right: max(0px, calc(100% - var(--fin-hub-w)));
    }
}

/* 2) "Please stack them so we have two rows." On the narrowest screens the
   greeting drops away and the name and the chip fought over one line, so a
   real entity name arrived truncated to "NOVERA Gr…". The head wraps here
   instead: the name block takes the full first row and the chip drops to a
   second row at full width, where the name reads in full. 02-Screen up is
   unchanged - the owner confirmed one row is right there. */
@media (max-width: 560px) {
    .screen-head.hb {
        flex-wrap: wrap;
        row-gap: 8px;
    }

        .screen-head.hb > div:first-child {
            flex: 1 1 100%;
            min-width: 0;
        }

        .screen-head.hb > .org-head {
            flex: 0 0 auto;
            margin-left: 0;
            margin-right: auto;
            max-width: 100%;
        }

    /* heads that keep one row here (back · title · chip · menu) still need
       the chip to yield space to the title rather than the other way round */
    .screen-head:not(.hb) .org-head {
        max-width: 40vw;
        padding: 0 10px;
    }
}

/* ═══ v27.3 (PRODUCTION TICKET 20260821002 items 4.1/4.2 + supplementary 6)
   THE ACTIONABLE GLANCE, AND THE SCHEDULE / RESCHEDULE ACTIONS ═══════════

   4.1 - the four At-a-glance boxes became links. They keep the tile look
   exactly as it was; the only visible change is that they now say, on hover
   and on keyboard focus, that they can be pressed. */
a.gl {
    display: block;
    text-decoration: none;
    color: inherit;
    border-radius: 10px;
    transition: box-shadow .15s ease, background .15s ease;
}

    a.gl:hover,
    a.gl:focus-visible {
        background: var(--nv-surface-2);
        box-shadow: 0 0 0 1px var(--nv-blue-glow);
        outline: none;
    }

/* 4.2 - the small square action on an Upcoming deadline row (add to
   calendar / open the entry). Sized to the 34px control the overdue menu
   button already uses, so the two rows line up. */
.gl-act {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    border: 1px solid var(--nv-surface-3);
    background: transparent;
    text-decoration: none;
    opacity: .85;
}

    .gl-act:hover,
    .gl-act:focus-visible {
        opacity: 1;
        border-color: var(--nv-blue);
        outline: none;
    }

/* item 6 - the RESCHEDULE tile inside the AI Reply quick-actions card. The
   card is a two-column grid of bordered <a> tiles; this one is a <div>
   because it carries its own ⋯ menu, and a row that owns a control cannot
   itself be a link. It therefore repeats the tile's own dressing - border,
   radius, padding, height - or it would read as a hole in the grid.
   ⚠ NO overflow:hidden here (the <a> tiles have it): that would clip the
   menu the moment it opened. The two text lines ellipsise instead. */
.cwa-qa .ov-row {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 10px;
    border: 1px solid rgba(104,152,232,.22);
    border-radius: 8px;
    color: var(--nv-ink-2);
    font-size: 14px;
    padding: 10px 12px;
    min-height: 56px;
    min-width: 0;
}

    .cwa-qa .ov-row .txt {
        flex: 1 1 0;
        min-width: 0;
    }

    .cwa-qa .ov-row > svg,
    .cwa-qa .ov-row .ov-menubtn {
        flex: 0 0 auto;
    }


/* ═══ v27.8 - THE nth-child CLAMP IS GONE ════════════════════════════════
   v27.7 pulled the last cell's panel leftwards using :nth-child(3n) and
   :last-child. Those count SOURCE ORDER, and these grids use spans, so the
   box sitting at a row's right edge is often neither - which is why panels
   still crossed the card border. A selector cannot see where the grid put a
   box; the measured clamp in _Layout does it properly and covers every
   picker on every page. Nothing replaces it here on purpose. */

/* ═══ v27.7 (owner: "all items should always be on the same row and labels
   ellipsis if text is too long") - THE FILTER / HISTORY CHIP ROW ══════════
   Unreconciled · Reconciled · All wrapped to a second line the moment the
   words grew (German and Polish reliably), which moved the list under them
   and broke the card's rhythm. One row now, always: the chips share the
   space, a long label ellipsises inside its own chip, and the full word
   rides the title - the toolkit's ELLIPSIS + TOOLTIP rule, and ruling 28
   applied to chips. The i18n patcher fills both the text and the title from
   the same key, so the tooltip is right in every language. */
.chip-row {
    display: flex;
    gap: 18px;
    align-items: center;
    flex-wrap: nowrap;
    min-width: 0;
}

    .chip-row > .chip {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        flex: 0 1 auto;
    }


/* ═══ v27.8 (owner: "The process chip in bank reconciliation should be
   aligned in the same column for all row items, independent of the amount or
   other column alignment") - FIXED COLUMNS ON THE STATEMENT ROWS ══════════
   The same ruling as v24.7 on the history and allocation grids, applied to
   the bank rec's own rows: every column holds ONE width on EVERY row, so the
   Process chip lands at the same x whether the line is matched or not and
   whatever the amount reads.

   The row still renders the star and the chip cells when a line is matched -
   empty, but present - because a cell that disappears takes the alignment of
   everything after it with it. That is what made the chips wander. */
.br-row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

    .br-row > .txt {
        flex: 1 1 auto;
        min-width: 0;
    }

    /* the ✦ column: present on every row, lit only when there is a hint */
    .br-row > .br-star {
        flex: 0 0 16px;
        width: 16px;
        text-align: center;
    }

    /* the PROCESS column - one width, every row */
    .br-row > .br-proc {
        flex: 0 0 96px;
        width: 96px;
        min-width: 96px;
        display: inline-flex;
        justify-content: flex-start;
        align-items: center;
    }

        .br-row > .br-proc > .chip {
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

    /* the AMOUNT column, right-aligned on the same 112px as the history grids */
    .br-row > .amt {
        flex: 0 0 112px;
        width: 112px;
        min-width: 112px;
        display: inline-flex;
        justify-content: flex-end;
        align-items: baseline;
        gap: 4px;
        text-align: right;
        overflow: hidden;
    }

    /* the trailing tick / clear column */
    .br-row > .br-tick {
        flex: 0 0 26px;
        width: 26px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

/* ═══ v28.1 (owner - THE DOCUMENT SLICE) - THE SUGGESTION CARD ════════════
   Two zones with a separator between them, because the rule the owner set is
   spatial: what the transaction already has sits ABOVE the line and is never
   touched; what the document offers sits BELOW it, each behind its own Use.
   The card is rendered by /js/nv-docsuggest.js and looks the same wherever it
   appears - the bank reconciliation sheet and the invoice header both. */
.nvdoc {
    background: linear-gradient(180deg, rgba(47,127,214,.10), rgba(47,127,214,.03));
    border: 1px solid var(--nv-blue-glow);
    border-radius: 10px;
    padding: 11px 13px;
    margin: 10px 0;
}

.nvdoc-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
    flex-wrap: wrap;
}

    .nvdoc-head .k {
        color: var(--nv-gold-bright);
        font-weight: 600;
    }

    .nvdoc-head .src {
        margin-left: auto;
        font-size: 12px;
        color: var(--nv-ink-3);
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/* the duplicate warning - a ledger fact, so it reads as a statement */
.nvdoc-dup {
    border-left: 3px solid var(--nv-warn);
    background: rgba(217,161,59,.10);
    border-radius: 0 8px 8px 0;
    padding: 8px 11px;
    margin: 6px 0;
}

    .nvdoc-dup .k {
        color: var(--nv-warn);
        font-size: 14px;
    }

    .nvdoc-dup .v {
        font-size: 14px;
        color: var(--nv-ink-2);
    }

.nvdoc-msg {
    font-size: 14.5px;
    color: var(--nv-ink-2);
    padding: 4px 0;
}

.nvdoc-zone {
    font-size: 12.5px;
    color: var(--nv-ink-2);
    margin: 2px 0 4px;
}

.nvdoc-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 42px;
    border-top: 1px solid var(--nv-surface-2);
    padding: 5px 0;
    min-width: 0;
}

    .nvdoc-row.tall {
        align-items: flex-start;
    }

    .nvdoc-row > .txt {
        min-width: 0;
        flex: 1 1 auto;
    }

    .nvdoc-row .s {
        font-size: 12.5px;
        color: var(--nv-ink-3);
    }

        .nvdoc-row .s .always {
            color: var(--acc-green);
        }

    .nvdoc-row .t {
        font-size: 15px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

        /* the extended description is the one field meant to be READ, so it
           wraps instead of ellipsising */
        .nvdoc-row .t.wrap {
            white-space: normal;
            line-height: 1.5;
        }

        /* a value that could not be stood behind: the REASON takes its place */
        .nvdoc-row .t.none {
            color: var(--nv-ink-3);
            font-size: 13.5px;
            white-space: normal;
        }

.nvdoc-conf {
    font-size: 11.5px;
    border-radius: 999px;
    padding: 1px 8px;
    white-space: nowrap;
    flex: 0 0 auto;
}

    .nvdoc-conf.ok {
        border: 1px solid var(--acc-green);
        color: var(--acc-green);
    }

    .nvdoc-conf.mid {
        border: 1px solid var(--nv-gold-deep);
        color: var(--nv-gold-bright);
    }

    .nvdoc-conf.low {
        border: 1px solid var(--nv-danger);
        color: var(--nv-danger);
    }

.nvdoc-kept {
    font-size: 11.5px;
    color: var(--nv-ink-3);
    border: 1px solid var(--nv-surface-3);
    border-radius: 999px;
    padding: 1px 8px;
    white-space: nowrap;
    flex: 0 0 auto;
}

/* THE SEPARATOR - everything under it came from the document */
.nvdoc-sep {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 12px 0 6px;
}

    .nvdoc-sep .ln {
        flex: 1;
        height: 1px;
        background: var(--nv-gold-deep);
        opacity: .55;
    }

    .nvdoc-sep .lb {
        font-size: 12.5px;
        color: var(--nv-gold-bright);
        white-space: nowrap;
    }

.nvdoc-why {
    border-top: 1px solid var(--nv-surface-2);
    padding-top: 6px;
    margin-top: 4px;
}

    .nvdoc-why .s {
        font-size: 12.5px;
        color: var(--acc-green);
    }

    .nvdoc-why .v {
        font-size: 13.5px;
        color: var(--nv-ink-2);
    }

.nvdoc-acts {
    display: flex;
    gap: 8px;
    margin-top: 9px;
    flex-wrap: wrap;
    align-items: center;
}

    .nvdoc-acts .s {
        font-size: 12.5px;
        color: var(--nv-ink-3);
    }

.nvdoc .chip[disabled] {
    opacity: .45;
    cursor: not-allowed;
}


/* ═══════════════════════════════════════════════════════════════════════
   v31.31 (batch227, owner) - THREE APP-WIDE CONTROL RULES
   Placed at the FOOT OF THE FILE on purpose: each one has to beat a rule
   written earlier for the same element, and equal specificity means the
   LATER rule wins. Moving this block up is what would silently undo it.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. THE EMPTY DATE FIELD'S FORMAT HINT ──────────────────────────────
   Owner: "the empty field has suggested format, displayed. Can only
   suggested text colour be muted. Do this throughout e.g in New Invoice."
   ⚠ `.nv-dateempty` is put on and taken off by wwwroot/js/nv-fields.js -
   read that file's header before touching this: no CSS selector can see
   that a date input is empty, and the shadow-part trick that is usually
   quoted for this was measured in this project and does NOT work.
   ⚠ THE WHOLE FIELD IS COLOURED, and that is exact rather than lazy: the
   only text an empty date field draws IS the hint. The instant a value
   exists the class comes off and the normal ink returns.
   ⚠ FOCUS OVERRIDES IT - someone typing into the field is looking at what
   they are typing, not at a hint. */
input.nv-dateempty {
    color: var(--nv-ink-3, #6b7690);
    /*  v31.31 (owner, same round): "The muted ink should always have
        font-weight:100." The hint IS muted ink, so it takes the muted weight
        with it - it cannot borrow the colour and not the weight. `.muted`
        itself carries the same pair in tokens.css. */
    font-weight: 100;
}

    input.nv-dateempty:focus {
        color: var(--nv-ink, #f1f3f9);
    }

/* ── 2. EVERY DOWN CHEVRON IS GOLD ──────────────────────────────────────
   Owner: "All down arrows chevrons should be gold."
   The chevrons are inline SVGs drawn with `stroke="currentColor"`, so the
   colour is all this needs. Some already carried gold (`.rcpt`, the gold
   AI row); the rest inherited whatever text colour they sat in.
   ⚠ `.vsel svg.chev` IS EDITED AT ITS OWN RULE, not overridden here - it
   sets `--nv-ink-3` explicitly at (0,2,1) and would beat this (0,1,0) no
   matter how far down the file this sits. Specificity, not order. */
.chev {
    color: var(--nv-gold, #e8a75c);
}

/* ── 3. THE SELECT CONTROL ──────────────────────────────────────────────
   Owner: "The dropdown control should have better styling for the content
   in the drop down. e.g Colour, width."
   ⚠⚠ WHAT IS OURS AND WHAT IS THE BROWSER'S. The CONTROL - its box, its
   arrow, its own text - is ours and is styled here. The POPUP LIST a
   native <select> opens is drawn by the browser: `option` colour and
   background are honoured on Chromium/Windows and are set below, but its
   WIDTH, its hover row and its scrollbar are not addressable from CSS on
   any engine. A dropdown that needs real control over its list is a job
   for the app's own picker component (`.v-sect` / `.t-leaf`, the one the
   supplier invoices and the VAT code editor use), not for a <select>.
   ⚠ `select.ctl` had NO `appearance: none`, so it was still drawing the
   operating system's grey arrow while `select.input` beside it drew the
   app's own. Same treatment, one look. */
/*  v31.53 - the same hairline. ⚠ `select.ctl` IS 48px TALL, NOT 32, so its
    divider is 30px rather than 22 - the same 9px of inset top and bottom that
    22 gives a 32px field. A divider that kept the 22px height on a taller
    control would read as a shorter, meaner line.
    ⚠ Its chevron sits at `right 12px` (20px wide → the box ends 32px from the
    edge), so the divider goes to 32 and the text stop moves 40 → 44. */
select.ctl {
    -webkit-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23e8a75c' stroke-width='1.6' stroke-linecap='round'><path d='m7 10 5 5 5-5'/></svg>"),
                      linear-gradient(rgba(112,160,238,.30), rgba(112,160,238,.30));
    background-repeat: no-repeat, no-repeat;
    /*  ⚠⚠ v31.54 - THE SAME CENTRING, AND I APPLIED IT HERE WITHOUT BEING
        ASKED. The owner named `select.input` only. Its sibling's divider is at
        32px, so its zone centre is 16px and a 20px chevron's right edge wants
        to be at 6px; it was at 12, i.e. 6px off-centre. Leaving one select
        centred and the other not is the inconsistency the "everywhere"
        instruction was about - but it IS an unasked change on a control that
        lives on other pages, so it is flagged rather than buried. Say the word
        and it goes back to 12. */
    background-position: right 6px center, right 32px center;
    background-size: auto, 1px 30px;
    padding-right: 44px;
}

/* the list itself, as far as the engine allows */
select.input option,
select.ctl option,
select.input optgroup,
select.ctl optgroup {
    background-color: var(--nv-surface-3, #101a30);
    color: var(--nv-ink, #f1f3f9);
}

    select.input option:checked,
    select.ctl option:checked {
        color: var(--nv-gold-bright, #f2bc74);
    }

/* ══════════════════════════════════════════════════════════════════════════
   ACCOUNT SETUP  (v31.33, batch230)  -  /financials/accounts
   The mock-up the owner locked, in CSS. Everything here is prefixed `acc-`
   and lives at the FOOT OF THE FILE on purpose:

   ⚠⚠⚠ AT EQUAL SPECIFICITY THE LATER RULE WINS. This project has now paid
   for that lesson twice (v31.12 across a media query, v31.28 between two
   ordinary rules), and both times `!important` would have been the wrong
   answer. Appending is the answer.

   ⚠ `.fld` IS NOT USED HERE. In this file `.fld` is the FOLDER ROW inside a
   sheet; the page's fields use the house `.fld-wrap` + `.fl-hint` + `.input`
   trio, and the status pip is `.acc-dot` rather than `.dot` for the same
   reason - a short class name that already means something else.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. THE TYPE CHIPS ────────────────────────────────────────────────────
   Owner: *"for the chips of account types at the top, in 02-Screen up to
   05-Screen, make all chips same width as the widest chip. In 01-Screen
   stack them so that their length covers the width."*

   ⚠⚠⚠ v31.35 (batch232) - `width: max-content` WAS THE WRONG TOOL HERE AND
   THE OWNER'S SCREENSHOT SHOWED WHY: "Suppliers 155" and "Customers 27" ran
   straight through their pill borders into each other.
   The `max-content` technique (v31.30's mail actions) sizes every track to
   the widest ITEM - which is right for four buttons in a roomy row, and
   wrong for SEVEN chips in a column that is only 555px wide at 03-Screen.
   `max-width: 100%` shrank the TRACKS, but a chip's own text does not
   shrink, so the labels overflowed instead. **A one-row grid cannot wrap,
   and seven chips at 03-Screen must wrap.**

   ⚠ `repeat(auto-fit, minmax(116px, 1fr))` gives the owner both halves of
   the rule and cannot overflow: every track is `1fr` so **every chip is the
   same width**, and the row breaks into two when 116px each will not fit.
   01-Screen keeps its own single-column rule, where "same width" and
   "covering the width" are the same thing. */
/* ⚠⚠⚠ v31.41 (batch238, owner) - 01-SCREEN IS NOW ONE CHIP AND TWO ARROWS.
   Owner: *"experiment with having back /forward arrows for the account types.
   This will ensure only one button (chip) is displayed on the row.
   <-- Suppliers 157 -->"*

   MEASURED, and this is the whole case for it: the two-per-row grid it
   replaces cost **152px** at 390 - four rows of chrome above a list that had
   not started yet. One row costs 32px.

   ⚠⚠ THE ARROWS ARE REAL LINKS, NOT A JS CAROUSEL. Each carries the previous
   or next type's own route, so one tap is one type - not "step, then tap".
   The list wraps at both ends, so there is no dead arrow to explain.
   ⚠ AND `More` STAYS ON THE ROW. The seven chips are only the shortcut set;
   the other twenty-two types live in the sheet, and without More on 01-Screen
   they would be unreachable. Four cells fit: 34 + 1fr + 34 + More.

   ⚠ THIS IS AN EXPERIMENT THE OWNER ASKED FOR, AND THE THING IT REPLACES IS
   ONE LINE. To go back to v31.37's two-per-row, delete the four-column
   template and the `display: none` rule below and restore:
       grid-template-columns: repeat(2, minmax(0, 1fr));
   Nothing else on the page depends on either shape. */
.acc-chips {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    gap: 8px;
    margin-bottom: 14px;
}

    /* ⚠ EVERY CHIP IS STILL RENDERED - one is SHOWN. That matters twice: the
       markup is identical at every width (so nothing re-flows on rotate), and
       the chip that shows is chosen by the SERVER, which is the only place
       that knows which type is open. */
    .acc-chips > .chip:not(.acc-chip-cur):not(.acc-arrow):not(#accMore) {
        display: none;
    }

    .acc-arrow {
        flex: 0 0 auto;
        padding: 0 9px;
    }

    .acc-chips > .chip {
        justify-content: center;
        min-width: 0;
    }

        /* ⚠ THE LABEL NEEDS ITS OWN PERMISSION TO SHRINK. `min-width: 0` on
           the chip is not inherited - without this the translated label (cs
           "Dodavatelé", de "Lieferanten") pushes the pill open again. */
        .acc-chips > .chip > span {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .acc-chips > .chip > .n,
        .acc-chips > .chip > svg {
            flex: 0 0 auto;
        }

/* ⚠ 02-Screen UP: every chip, equal width, and the arrows stand down. The
   carousel exists to buy vertical space on a phone; from 561px there is room
   for the whole set and stepping one at a time would be a step backwards. */
@media (min-width: 561px) {
    .acc-chips {
        grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
    }

        .acc-chips > .chip:not(.acc-chip-cur):not(.acc-arrow):not(#accMore) {
            display: flex;
        }

        .acc-chips > .acc-arrow {
            display: none;
        }
}

/* ── 2. THE SHELL ─────────────────────────────────────────────────────────
   Owner: *"Left column with list of accounts should always be the same
   height as the middle card with entry fields."*

   ⚠ THAT IS A GRID ROW, NOT A HEIGHT. Both cards are items in one row, and
   a grid row's items stretch by default - so the shorter card grows to the
   taller one without either being told a pixel. The list then distributes
   that height inside itself (section 3).

   ⚠⚠⚠ v31.35 (batch232) - THE COLUMN COUNT CANNOT COME FROM A MEDIA QUERY,
   AND MEASURING IS THE ONLY WAY TO SEE IT. The first version asked for
   `320px 1fr 320px` from 1366 and the middle card collapsed to **42px** on
   the owner's screen. Measured, at the real breakpoints, this content
   column is:

       viewport   1024   1280   1366   1433   1600   1920
       .acc-shell  619    875    555    622    688    688

   **IT IS NOT MONOTONIC AND IT NEVER EXCEEDS ~688px.** Two things cause it,
   both in responsive.css and both deliberate:
     · `.app-main { max-width: 1410px }` from 1024 - the hard ceiling; and
     · from 1366 `.mail-app .app-main` becomes `260px | 1fr | 390px`, so the
       AI column's 390px track is **reserved whether or not the page fills
       it**. That is why 1366 is NARROWER than 1280.
   So `320 + 320 + 28` did not fit in 555 and `minmax(0, 1fr)` did what it is
   told: it gave up everything it had.

   ⚠⚠ **NO VIEWPORT MEDIA QUERY CAN MODEL A WIDTH THAT FALLS AS THE VIEWPORT
   GROWS.** This is what container queries are for, and this is the one place
   in the app that needs them: `.acc-wrap` is the container and the shell asks
   ITS OWN width, not the window's.
   ⚠ THE FALLBACK IS SAFE. Where `@container` is not supported the base rule
   stands and the page is one honest column - narrower than ideal, never
   broken. (The file already relies on `:has()`, which shipped later in
   Firefox than container queries did.)
   ⚠ AND EVERY TRACK IS FRACTIONAL. A fixed track can be wider than its
   container; a fraction cannot. That is what makes this class of fault
   impossible rather than merely fixed. */
.acc-wrap {
    container-type: inline-size;
    container-name: accshell;
}

.acc-shell {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
    align-items: stretch;
}

    .acc-shell > .acc-side {
        grid-column: 1 / -1;
    }

/* ⚠ 600px, chosen from the measurements above and not from a round number:
   it takes in 1024 (619), 1433 (622) and 1600/1920 (688) and leaves out only
   1366 (555), where 258px of list beside 283px of account would be worse than
   one honest column. */
@container accshell (min-width: 600px) {
    .acc-shell {
        grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    }
}

/* ⚠ 900px. v31.35 picked 1040 and the owner's screen measures 1028 - it missed
   by twelve pixels and the whole right column dropped below the fold, which
   read as "the cards are missing". v31.36 moved it to 940. v31.38 moves it
   again to 900, and this time for a MEASURED reason rather than a safety
   margin: at a 1280 viewport the container is 916px, and the difference
   between two columns and three there is a page of **1723px against 1174px**.
   Three narrow columns beat one long scroll.
       container   660(1024)  916(1280)  961(1366)  1028(1433)  1094(1600+)
       columns         2          3          3           3           3
   ⚠⚠ PICK A BREAKPOINT FROM THE MEASURED WIDTHS, NEVER FROM A ROUND NUMBER. */
@container accshell (min-width: 900px) {
    .acc-shell {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr) minmax(0, 1.1fr);
    }

        .acc-shell > .acc-side {
            grid-column: auto;
        }
}

/* ⚠ THE FIELD ROWS ASK THE SAME CONTAINER. `.fin-grid3` is three fixed
   fractions down to 768px of VIEWPORT, which says nothing about the 396px of
   CARD they are actually drawn in. Two columns is the honest answer at every
   width this page really gets. */
.acc-detail .fin-grid3 {
    grid-template-columns: minmax(0, 1fr);
}

@container accshell (min-width: 520px) {
    .acc-detail .fin-grid3 {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

/* ── 3. THE LIST ──────────────────────────────────────────────────────────
   Owner: *"The left suppliers list must have as many rows as is needed to
   fill the height - minus pager."*

   The card is a flex COLUMN: search, filters, count and pager take what they
   need, and `.acc-rows` takes everything that is left. `flex: 1 1 0` plus
   `min-height: 0` is the pair that makes that true - a flex item's default
   `min-height: auto` refuses to shrink below its content, so without the
   second half the rows would push the pager off the card instead of
   scrolling.
   ⚠⚠⚠ A BOX CANNOT SCROLL ONE AXIS AND BE `visible` ON THE OTHER. Setting
   `overflow-y` alone silently makes a sideways scroller too - exactly what
   the bank card did in v31.31 - so BOTH axes are named here. */
.acc-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-height: 0;
    min-width: 0;
}

.acc-find {
    margin: 0;
}

    .acc-find .input {
        width: 100%;
    }

/* Owner: *"Active only, With VAT no etc must be same width."*

   ⚠ v31.36 (batch233) - THE SAME CORRECTION THE TOP CHIPS NEEDED, for the
   same reason and measured the same way. `width: max-content` on a one-row
   grid cannot wrap, so in a 282px card three chips came out 84px each and
   "No transactions" ran straight through its pill. `repeat(auto-fit, ...)`
   keeps every track `1fr` - so the chips stay the same width, which is the
   owner's rule - and drops to one per row when three will not fit.
   ⚠ 128px, not 104: at 104 the narrow card fitted two clipped chips per row,
   which is worse than one whole one. */
.acc-filters {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 8px;
}

    .acc-filters > .chip {
        justify-content: center;
        min-width: 0;
    }

        /* the label needs its own permission to shrink - see the top chips */
        .acc-filters > .chip > span {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

    /* the held chip wears the app's own disabled grammar (v31.21 `.t-off`) */
    .acc-filters > .chip.t-off {
        opacity: .42;
        pointer-events: none;
    }

.acc-count {
    font-size: 12.5px;
}

/* ⚠⚠⚠ v31.41 (batch238) - THE PHONE LIST WAS 0px TALL AND THIS IS WHY.
   Owner: *"For screen 01-Screen, please show max 7 accounts on the grid."*
   MEASURED at 390 before the fix: `ROWSH=0`, `ROWSVIS=0`. Not "a bit short" -
   the box had no height at all, which is why one clipped row showed.

   ⚠⚠ THE CAUSE IS `flex: 1 1 0` MEETING AN AUTO-HEIGHT PARENT. `flex-basis:
   0` says "I want NO height, give me a share of the SPARE space". In the
   multi-column shell that is exactly right - the card is a stretched grid
   item, so there IS spare space and the rows take all of it (the owner's rule
   that the list matches the account card). But on 01-Screen the shell is ONE
   column, nothing stretches the card, its height is its content, and a flex
   column with no spare space has none to give. Basis 0 + no spare = 0.
   ⚠ `min-height: 0` a line below MADE IT LEGAL to collapse to nothing. The
   pair is right in one layout and fatal in the other.

   So the base - which is 01-Screen - sizes to content and caps at seven rows;
   the multi-column state restores `1 1 0`.

   ⚠⚠ 232px IS SEVEN MEASURED ROWS, AND IT IS NOT 7 x 32. The first row is
   **32.25px** and every row after it is **33.25px** - the extra pixel is the
   separator border, which the first row does not have. So seven rows are
   32.25 + 6 x 33.25 = **231.75px**, rounded up to 232. The first attempt used
   224 (7 x the 32 the probe printed after rounding) and showed **SIX** rows -
   a reminder that a rounded measurement is not a measurement.
   ⚠ If a long name ever wraps, fewer than seven show and the box scrolls -
   which is still "max 7", and honest about it. */
/* ⚠ v31.47 (batch244) - THE NEW-ACCOUNT ROW, in the list card under the count.
   One field and one button on one line, because that is the whole form: the
   code is allocated and the type is the chip you are standing on.
   ⚠⚠ IT WRAPS RATHER THAN SQUEEZING. On 01-Screen the list card is 350px wide
   and a 1000-character name field beside a button would leave neither usable -
   `flex-wrap` lets the button drop to its own line instead of the input
   collapsing to nothing. `min-width: 0` on the input is the half that actually
   permits it (a flex item refuses to shrink below its content without it) -
   the same pair `.acc-rows` documents below. */
.acc-new {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}

    .acc-new .input {
        flex: 1 1 140px;
        min-width: 0;
    }

    .acc-new .btn {
        flex: 0 0 auto;
    }

.acc-rows {
    flex: 0 1 auto;
    max-height: 232px;
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* ⚠ FROM TWO COLUMNS UP THE CARD IS A STRETCHED GRID ITEM AGAIN, so the rows
   go back to taking the leftover - the owner's "as many rows as is needed to
   fill the height - minus pager". The cap comes off with it: capping a
   stretched card would leave a gap under the list instead of rows in it. */
@container accshell (min-width: 600px) {
    .acc-rows {
        flex: 1 1 0;
        max-height: none;
    }
}

/* ⚠⚠⚠ v31.37 (owner: "make the column width for Account numbers aligned for
   all rows"). EVERY ROW IS ITS OWN GRID, so `auto` sized each code column to
   ITS OWN code and the names started at a different x on every line.
   A FIXED first track fixes it outright - the same number on every row is
   aligned by construction - and `@supports (grid-template-columns: subgrid)`
   below then upgrades it so a long code widens the column FOR ALL ROWS
   instead of ellipsing. Both paths align; the second is just kinder. */
.acc-row {
    display: grid;
    grid-template-columns: 7.6em minmax(0, 1fr) 9px;
    align-items: center;
    gap: 10px;
    padding: 6px;
    border-radius: var(--r-card);
    text-decoration: none;
    color: var(--nv-ink-2);
    font-size: 13.5px;
    font-weight: 200;
}

    .acc-row + .acc-row {
        border-top: 1px solid rgba(104,152,232,.10);
    }

    .acc-row:hover {
        background: rgba(104,152,232,.08);
    }

    .acc-row.on {
        background: rgba(232,167,92,.12);
        color: var(--nv-gold-bright);
    }

    .acc-row .code {
        color: var(--nv-gold);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        /* the codes are read as columns of digits - line them up */
        font-variant-numeric: tabular-nums;
    }

/* ⚠ THE UPGRADE. `.acc-rows` owns the tracks and each row borrows them, so the
   code column is as wide as the WIDEST code in the list and no wider. Where
   subgrid is missing nothing here applies and the fixed 7.6em above still
   aligns every row. */
@supports (grid-template-columns: subgrid) {
    /* ⚠⚠⚠ v31.40 - THE HALF-MOON DOT, AND WHY IT WAS HALF.
       A SUBGRID ITEM'S OWN PADDING DOES NOT MOVE THE PARENT'S TRACKS. The row
       carried `padding: 6px`, so its content box was 12px narrower than the
       tracks it was borrowing - and the last track, which is exactly the width
       of the 9px dot, ran 6px past the row's right edge. `.acc-rows` then
       clipped it with `overflow-x: hidden` and the reader saw a half circle.
       ⚠ THE FIX IS TO MOVE THE PADDING UP: the ROWS box carries the inset, the
       row itself keeps only its vertical padding, and the dot track is widened
       so the circle has room to sit centred rather than flush against the cut.
       ⚠ THE BASE (no-subgrid) RULE IS UNTOUCHED - there the row is its own
       grid, its padding is its own business, and nothing was ever clipped. */
    .acc-rows {
        display: grid;
        grid-template-columns: max-content minmax(0, 1fr) 14px;
        align-content: start;
        padding: 0 6px;
    }

        .acc-rows > .acc-row {
            grid-column: 1 / -1;
            grid-template-columns: subgrid;
            padding-left: 0;
            padding-right: 0;
        }

        /* the empty-list line is not a row of three */
        .acc-rows > .muted {
            grid-column: 1 / -1;
        }
}

/* ⚠ AND THE PIP SITS CENTRED IN ITS TRACK, wherever that track ends up. A
   circle flush against a clipping edge is one rounding error from being a
   half circle again. */
.acc-row > .acc-dot {
    justify-self: center;
}

    /* ⚠ `min-width: 0` ALONE IS NOT ENOUGH on a flex item - it must also be
       told it may shrink - but this is a GRID item and `minmax(0, 1fr)` in
       the template above has already said so, which is why the ellipsis
       actually draws here. */
    .acc-row .nm {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

.acc-pager {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 8px;
}

    .acc-pager > .chip {
        justify-content: center;
        min-width: 0;
    }

    .acc-pager > .chip[aria-disabled="true"] {
        opacity: .38;
        pointer-events: none;
    }

/* ── 4. THE STATUS PIP ────────────────────────────────────────────────────
   ⚠ 1 Active and 9 DEFAULT ARE BOTH IN USE - never `> 1`. That exact
   mistake dropped a live bank account off the dashboard in v26.9, so the
   two live states share a colour and the two idle ones do not. */
.acc-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    display: inline-block;
    flex: 0 0 auto;
    background: var(--nv-ink-3);
}

    .acc-dot.live,
    .acc-dot.def {
        background: var(--acc-green, #3fca85);
    }

    .acc-dot.susp {
        background: var(--nv-gold);
    }

    .acc-dot.closed {
        background: rgba(107,118,144,.55);
    }

/* ── 5. THE ACCOUNT ───────────────────────────────────────────────────── */
.acc-detail {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

    /* ⚠ v31.35 - `.acc-wide` NO LONGER SPANS. With two field columns the
       account name and its code sit side by side, which is the pairing a
       reader wants; a spanning name pushed the code onto a row of its own
       and left half of it empty. The class is kept as the hook for the day
       the card is wide enough to earn three columns. */
    .acc-detail .acc-wide {
        grid-column: auto;
    }

.acc-code {
    color: var(--nv-gold);
    font-variant-numeric: tabular-nums;
    letter-spacing: .3px;
}

/* the status field is a value, not an input, so it borrows the input's box
   and adds the pip - one field height across the whole row either way */
.acc-stat {
    display: flex;
    align-items: center;
    gap: 8px;
}

.acc-sec {
    margin: 6px 0 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* ── 6. ADDITIONAL ADDRESSES ──────────────────────────────────────────────
   ⚠ THE TYPE IS SHOWN AS A NUMBER, AND THAT IS DELIBERATE. `RefAddressType`
   is not yet proven in v2 (diag-accounts.sql, set 3), so the page shows the
   type the ledger stores rather than a name we invented. A number the
   reader can see beats a name that might be wrong.
   ⚠ THE PILLS ARE EQUAL WIDTH (owner: *"The pills for address type, must be
   same width when they are shown."*) - one `max-content` column shared by
   every row, which is the same sentence as the chips again. */
.acc-addrs {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 6px 10px;
    align-items: center;
}

    .acc-addrs > .acc-atype {
        justify-content: center;
        width: 100%;
    }

    .acc-addrs > .acc-aline {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 13.5px;
        color: var(--nv-ink-2);
    }

/* ── 7. THE READ-ONLY NOTE ────────────────────────────────────────────────
   A page with no Save button owes its reader an explanation, and a tooltip
   is not one. */
/*  ⚠⚠⚠ v31.51 - THIS RULE WAS DELETED AND PUT STRAIGHT BACK, AND THE MISTAKE
    IS WORTH MORE THAN THE RULE. The standing "reading only" banner went in
    v31.51 (the owner asked whether we were still waiting for editing - we were
    not, it shipped in 1b), and this rule went with it as dead weight.

    **IT WAS NOT DEAD.** `.acc-ro-note` had THREE elements, not one: the
    Periods tab's "this account carries its own window" note and the AI Create
    tab's "the layout is here" note are both still on the page. Deleting the
    rule would have shipped two UNSTYLED notes - and an unstyled element still
    renders, so nothing would have looked broken enough to notice.

    ⚠ THE LESSON, WHICH IS THE MIRROR OF THE `.acc-new` ONE: before deleting a
    rule, COUNT THE ELEMENTS THAT USE IT, not the one you just removed. Caught
    by grepping the class on the device AFTER the commit, which is later than
    it should have been. */
.acc-ro-note {
    display: flex;
    flex-direction: column;
    gap: 3px;
    margin-top: auto;
    padding: 10px 12px;
    border-radius: var(--r-card);
    border: 1px dashed rgba(232,167,92,.32);
    background: rgba(232,167,92,.06);
    font-size: 13px;
    color: var(--nv-ink-2);
}

/* ── 8. THE RIGHT COLUMN ──────────────────────────────────────────────── */
/* ⚠⚠ THE SIDE COLUMN IS TWO SHAPES, NOT ONE.
   Below 940px of container it spans the FULL WIDTH under the other two cards -
   at which point stacking its cards one above the other wastes all that width
   and makes the page enormous (measured 1975px at a 1024 viewport). Laid out
   as an auto-fitting grid it uses the width instead of the height.
   From 940px it is a real 300px column again, and a single track is right. */
.acc-side {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 14px;
    align-content: start;
    /* ⚠ MEASURED: `align-content` alone was not enough. A grid ITEM stretches
       to its ROW, so a collapsed card sitting beside an open one grew to 364px
       of empty box. `align-items: start` is what keeps a folded card folded. */
    align-items: start;
    min-width: 0;
}

@container accshell (min-width: 900px) {
    .acc-side {
        grid-template-columns: minmax(0, 1fr);
    }
}

.acc-ba-hint {
    font-size: 12.5px;
    margin-bottom: 6px;
}

/* ⚠⚠ THIS LIST IS NOT DECORATION. `LedgerPosting.RequiredBaAsync` reads the
   same pair and REFUSES A POSTING whose line leaves the analysis blank, so a
   required slot is drawn as a state and not as a tick alone.
   ⚠ A slot the entity does not use is GREYED, NEVER HIDDEN: v1 lists all
   twenty, and hiding them would make two entities' pages look like different
   software. */
.acc-ba {
    display: grid;
    grid-template-columns: minmax(0, 1fr) max-content max-content;
    align-items: center;
    gap: 8px;
    padding: 5px 6px;
    font-size: 13.5px;
    font-weight: 200;
    color: var(--nv-ink-2);
}

    .acc-ba + .acc-ba {
        border-top: 1px solid rgba(104,152,232,.10);
    }

    .acc-ba .nm {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .acc-ba .st {
        font-size: 12px;
    }

    .acc-ba .req {
        font-size: 12px;
        color: var(--nv-gold-bright);
    }

    .acc-ba .tick {
        color: var(--acc-green, #3fca85);
    }

    .acc-ba.idle {
        opacity: .45;
    }

    .acc-ba.on .nm {
        color: var(--nv-ink);
    }

/* ── 9. THE MORE SHEET ────────────────────────────────────────────────────
   Server-rendered, so every type is a real link and the sheet carries no
   data of its own. `.t-leaf` is the app's own picker row - the same one the
   VAT panel uses - so this only adds the two children that row does not
   already know about. */
/* ⚠⚠⚠ v31.41 (batch238, owner) - THE SHEET RAN OFF THE TOP OF 05-SCREEN.
   Owner: *"For 05-Screen ONLY please note that the accMoreSheet top margin
   disappears into the top viewport."* MEASURED at 1920x1080: the sheet's top
   edge sat at **-17px** - above the window - taking the "Account types."
   heading and the first rows with it. At a shorter 1920 window it is far
   worse; the owner's screenshot loses roughly a third of the list.

   ⚠⚠ THE CAUSE IS THAT `60vh` DOES NOT KNOW ABOUT THE 340px. `.mail-sheet` is
   pinned to the BOTTOM and pushed up by a per-screen margin (20 / 40 / 134 /
   **340** at 1920), then grows UPWARD. So the room this list actually has is
   not 60% of the window - it is the window MINUS that margin MINUS the sheet's
   own grab handle, heading and padding. At 1920x1080 that is 1080-340-~110 =
   630px of room for a list asking for 648. It took the difference off the top,
   silently, because nothing clips a fixed box at the viewport edge.

   ⚠ THE FIX ASKS THE SHEET HOW FAR UP IT IS instead of guessing per
   breakpoint. `--sheet-gap` is set beside every one of those four margins
   (base here, the other three in responsive.css) and inherits down. `min()`
   keeps today's 60vh wherever it already fits, so 01-04-Screen do not move a
   pixel - only the screen that was broken changes.
   ⚠⚠ AND IT IS NOT A 1920-ONLY RULE ON PURPOSE. Written as one it would leave
   the same fault latent at 1366 the moment someone opens a short window. This
   shape cannot overflow at any size. */
.acc-more {
    display: flex;
    flex-direction: column;
    max-height: min(60vh, calc(100vh - var(--sheet-gap, 20px) - 130px));
    overflow-y: auto;
    overflow-x: hidden;
}

    .acc-more .t-leaf b {
        color: var(--nv-gold);
        font-weight: 400;
        min-width: 34px;
    }

    .acc-more .t-leaf .nm {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/* ── 10. THE RIGHT COLUMN'S OWN CARDS (v31.36, batch233) ──────────────────
   The locked mock-up's stack: Find an account · Analysis · Business analysis
   · the account's open range (slice 1b) · Create from document (slice 1b). */
.acc-find-card .acc-find {
    margin: 0 0 8px;
}

    .acc-find-card .acc-find .input {
        width: 100%;
    }

.acc-find-card .acc-count {
    margin-top: 8px;
}

/*  ⚠⚠⚠ v31.58 (batch255, owner) - THE ADDRESS FLIP.
    Owner: *"Please implement the 'flip' for addresses. The second flip1 will
    be the address and flip 2 will be additional addresses. (no border for the
    flip)."*

    ⚠⚠ THIS IS A VARIANT OF THE TOOLKIT FLIP, NOT A SECOND ONE. `.flip`,
    `.flip-inner`, `.flip-face` and `.flip-dots` above are the dashboard's, and
    `_NvFlip.cshtml` drives all of them. Three things have to change for a pair
    of FORMS rather than a pair of fixed cards, and nothing else does.

    ⚠⚠⚠ 1. THE FIXED HEIGHT HAS TO GO. `.flip-inner` is `height: 250px` because
    Bank Balances is 250px tall by the owner's own ruling; an address form is
    not, and at 250px the Save button would sit outside the card.

    ⚠⚠⚠ 2. THE FACES STACK ON ONE GRID CELL INSTEAD OF BEING ABSOLUTE. The
    toolkit uses `position: absolute; inset: 0`, which takes both faces out of
    flow - so with the fixed height gone the container would collapse to
    nothing. Placing both in `grid-area: 1 / 1` keeps them stacked AND in flow,
    so **the taller face sets the height** and neither is ever clipped.
    ⚠ `backface-visibility: hidden` still does the hiding; that is unchanged.

    ⚠ 3. NO BORDER, NO FILL, NO CLIP - the owner's "(no border for the flip)".
    `.flip .card` sets `overflow: hidden` so the dashboard's fixed faces cannot
    spill; here that would clip a form, so it goes back to visible. */
.acc-flip .flip-inner {
    min-height: 0;
    height: auto;
    display: grid;
}

    .acc-flip .flip-face {
        position: relative;
        inset: auto;
        grid-area: 1 / 1;
    }

    .acc-flip .card,
    .acc-flip .flip-face > .card {
        border: 0;
        background: transparent;
        box-shadow: none;
        padding: 0;
        overflow: visible;
    }

    /*  ⚠⚠ v31.59 (owner) - THE FACE SWITCHES SIT AT THE TOP OF THE CARD.
        `.flip-dots` on the dashboard uses `margin-top: auto` to pin itself to
        the foot of a 250px card, where it is always in view. These faces are
        forms six hundred pixels tall, so the foot is below the fold and the
        second face may as well not exist - which is exactly how the additional
        addresses came to read as "completely ignored". `margin-top: 0` undoes
        the pin; the order in the markup does the rest. */
    .acc-flip .flip-dots {
        margin-top: 0;
        margin-bottom: 12px;
        padding-top: 0;
    }

/*  ⚠⚠⚠ v31.61 (owner, an arrow on the screenshot from the switch to the
    Mobile box) - THE SMS PERMISSION SITS ON THE FIELD IT GOVERNS.

    It used to be its own row at the foot of the card, six fields below the
    number it applies to, where it reads as a setting for the whole address.
    Beside the mobile it reads as what it is: may we text THIS number.

    ⚠ THE CONTROL IS UNCHANGED - the same `.acc-sw`, the same measured 34x19
    the owner chose for Business Analysis. Only its position moved, so the two
    switches on this page still say "this is the same kind of thing".
    ⚠⚠ THE INPUT KEEPS ITS FULL WIDTH: the switch is 34px and the row is a
    grid of `minmax(0, 1fr)` plus `auto`, so a long number shrinks the box
    rather than pushing the switch out of the cell. */
.acc-mobrow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
}

    .acc-mobrow > .input {
        width: 100%;
        min-width: 0;
    }

/*  the one-line consent caption beside the mobile. ⚠ 12px and `.muted` - the
    owner asked for muted small text and this is the same size the rest of
    this card's hints use. */
.acc-smshint {
    display: block;
    margin-top: 4px;
    font-size: 12px;
}

/*  ⚠⚠⚠ v31.62 (owner) - THE CAPTION IS IN THE NEXT COLUMN NOW.
    Owner: *"'Allow SMS to this contact' should be in the next column after the
    Allow SMS checkbox below the telephone column."*

    v31.61 moved the SWITCH beside the number, which was the first half of it,
    and left the caption UNDER the pair - a third line in a cell that already
    held two, which pushed the rest of that grid column down by its height.

    ⚠ THE CELL SPANS BOTH COLUMNS AND SPLITS ITSELF. `.acc-fields` is two
    equal columns; this one wrapper takes the whole row and then places its
    three children by hand, so the mobile box keeps EXACTLY the half-width it
    had and the caption occupies space that was empty anyway - the Email under
    it spans, and therefore always began a new row.
    ⚠⚠ EVERY CHILD IS PLACED EXPLICITLY, none by auto-flow. `.acc-pair` had to
    learn this the hard way: a two-column grid auto-places children ROW BY ROW,
    which here would put the caption beside the HINT rather than beside the
    control - measured at 32px too high.
    ⚠ HIGHER SPECIFICITY THAN `.acc-smshint` ABOVE (0,2,0 against 0,1,0), so
    the `margin-top` it sets for the old stacked layout is overridden here and
    not deleted there: the class is still used on its own elsewhere. */
.fld-wrap.acc-mobwrap {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto auto;
    gap: 0 12px;
}

    .acc-mobwrap > .fl-hint {
        grid-column: 1;
        grid-row: 1;
    }

    .acc-mobwrap > .acc-mobrow {
        grid-column: 1;
        grid-row: 2;
    }

    .acc-mobwrap > .acc-smshint {
        grid-column: 2;
        grid-row: 2;
        align-self: center;
        margin-top: 0;
    }

/*  ⚠⚠ v31.59 (owner) - TWO FIELDS IN ONE CELL.
    Owner: *"Post Code and Country fields should share the same col/row space
    by making them half their current sizes. That saves us a row."*

    ⚠ `.fld-wrap` is one cell of `.acc-fields`; `.acc-pair` splits that cell
    into two equal halves, each carrying its own hint above its own control.
    The pair therefore costs ONE grid cell rather than two, which is the row
    the owner wanted back.
    ⚠ `minmax(0, 1fr)` on both, not `1fr`: a long country name in the picker
    would otherwise refuse to shrink and push the post code out of the cell -
    the same rule the search-hit row uses. */
.fld-wrap.acc-pair {
    display: grid;
    /*  ⚠⚠⚠ IT FILLS DOWN, THEN ACROSS - and that is the whole rule.
        The cell holds four children in source order: hint, control, hint,
        control. A plain two-column grid auto-places them ROW BY ROW, which
        puts the first hint beside the first control and the second hint beside
        the second - two stacked rows of mismatched things, MEASURED as a 32px
        vertical offset between the post code and the country.
        `grid-auto-flow: column` over two explicit rows fills column one (hint,
        control) and then column two, which is the pair the owner asked for. */
    grid-template-rows: auto auto;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 0 8px;
}

    .fld-wrap.acc-pair > .input,
    .fld-wrap.acc-pair > select.input {
        width: 100%;
        min-width: 0;
    }

/*  one additional address on the back face. ⚠ A HAIRLINE ABOVE EACH ONE AFTER
    THE FIRST, never a box: the owner asked for no border on the flip, and a
    card inside a borderless card is exactly the furniture that removal was
    meant to lose. */
.acc-xaddr + .acc-xaddr {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid rgba(112,160,238,.18);
}

/*  ⚠⚠⚠ v31.66 (batch263, owner): *"Where Additional address exists, multiple
    textboxes exists as shown in the diagram and the page height explodes."*

    Each additional address and the eleven-field Add form are `details`
    elements now, closed by default. The head is the `summary`.

    ⚠ THE NATIVE MARKER IS REMOVED IN BOTH DIALECTS - `list-style: none` for
    the standard, `::-webkit-details-marker` for Safari and older WebKit - and
    replaced by the same gold twisty the tree uses, so a fold on this page
    reads as the same kind of control wherever it appears.
    ⚠⚠ `cursor: pointer` ON THE SUMMARY ONLY. The row under it is a form; a
    pointer over a form says "this is clickable" about something that is not. */
.acc-xhead {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

details.acc-xaddr > summary.acc-xhead,
details.acc-xnew > summary.acc-xnewhead {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 8px;
}

    details.acc-xaddr > summary::-webkit-details-marker,
    details.acc-xnew > summary::-webkit-details-marker {
        display: none;
    }

    /*  the fold's own heading keeps the section type but loses the margin that
        would push the twisty off its own line. */
    details.acc-xnew > summary.acc-xnewhead > .acc-sec {
        margin: 0;
    }

/*  ⚠ THE SAME GLYPH AND THE SAME 12px BOX AS THE TREE'S TWISTY, including the
    `nowrap` that stops a font without U+25B8 from wrapping it to a second line
    and growing the row - measured at 46px instead of 28px when that happened
    in the tree. */
.acc-xtw {
    flex: 0 0 auto;
    width: 12px;
    color: var(--nv-gold);
    font-size: 11px;
    line-height: 18px;
    white-space: nowrap;
    overflow: hidden;
    text-align: center;
    transition: transform .15s ease;
}

    details[open] > summary > .acc-xtw {
        transform: rotate(90deg);
    }

/*  ⚠ WHICH ADDRESS THIS FOLD IS. A column of identical type pills is a column
    of identical rows, and the reader would open every one to find the one they
    meant. It takes the rest of the line and ellipses - a summary that wraps
    turns a one-line fold back into a two-line one. */
/*  ⚠⚠⚠ v31.68 (batch265, owner) - THE DELETE, ARMED AND UNARMED.
    Unarmed it is the icon alone, muted, and it takes no more room in the
    summary than the twisty does. Armed it turns red and says the word, so the
    change is impossible to miss on a row of otherwise identical rows.

    ⚠ THE WORD IS `max-width: 0` UNARMED, NOT `display: none`. A word that
    appears from nothing shifts everything beside it; a word that grows out of
    zero width pushes the summary's text along predictably, and it can be
    animated. Measured: the summary keeps one line at every width in the range.
    ⚠⚠ `margin-left: auto` PUTS IT AT THE FAR END of the summary, away from the
    twisty that opens the row. The two controls on this line do opposite things
    and must not be adjacent. */
.acc-xdel {
    flex: 0 0 auto;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: 0;
    padding: 2px 4px;
    border-radius: 6px;
    color: var(--nv-ink-3);
    cursor: pointer;
    font: inherit;
    font-size: 12px;
    line-height: 18px;
}

    .acc-xdel:hover {
        color: var(--nv-ink);
    }

    .acc-xdel > .acc-xdelw {
        max-width: 0;
        overflow: hidden;
        white-space: nowrap;
        transition: max-width .15s ease;
    }

    .acc-xdel[data-arm="1"] {
        color: #e79a9a;
        background: rgba(217,101,101,.12);
    }

        .acc-xdel[data-arm="1"] > .acc-xdelw {
            max-width: 8em;
        }

.acc-xsum {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    font-weight: 200;
    color: var(--nv-ink-3);
}

/*  ⚠ THE FOLD'S CONTENT GETS ITS OWN BREATHING ROOM. `.acc-xhead` carries the
    8px below it while closed; open, the fields need the same gap from the head
    they had when this was a plain div. */
details.acc-xnew[open] > .acc-fields {
    margin-top: 8px;
    }

/*  ⚠ THE SEARCH RESULTS. Four columns that collapse to two on a narrow
    container - `.acc-wrap` carries `container-type: inline-size`, so this asks
    the COLUMN's width and not the window's, which on this page are different
    numbers and move in opposite directions. */
.acc-findres {
    margin-bottom: 14px;
}

.acc-fhit {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr);
    gap: 4px 10px;
    align-items: baseline;
    padding: 6px 0;
    border-top: 1px solid rgba(112,160,238,.14);
}

    .acc-fhit .nm {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .acc-fhit .cd,
    .acc-fhit .ml,
    .acc-fhit .en {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .acc-fhit .en {
        text-align: right;
        color: var(--nv-gold);
    }

@container (max-width: 620px) {
    .acc-fhit {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

/*  ⚠⚠ v31.58 (batch255, owner) - THE PERIODS BUTTONS ARE TWO FULL ROWS.
    Owner: *"Please Make the buttons 'Save Range' and 'Clear all four'
    seperate rows, each haveing full row width."*

    ⚠ THIS REPLACES v31.56's EQUAL-WIDTH PAIR, and it retires the question
    rather than answering it again: a full-width button is the same width as
    the one above it by construction, in every one of the five languages, with
    nothing measured and nothing to keep in step.

    ⚠ THE SECOND BUTTON IS INSIDE ITS OWN FORM - it has to be, so it can carry
    `PrdClear` without the four date fields riding along. That form is
    therefore the grid item, not the button, which is why the button below it
    takes `width: 100%` rather than being sized directly. */
.acc-prd-acts {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    width: 100%;
}

    .acc-prd-acts > form {
        margin: 0;
        min-width: 0;
    }

        .acc-prd-acts > .btn,
        .acc-prd-acts > form > .btn {
            width: 100%;
        }

/* one row of the Analysis summary card - label left, state right */
.acc-arow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) max-content;
    align-items: center;
    gap: 8px;
    padding: 6px;
    font-size: 13.5px;
    font-weight: 200;
    color: var(--nv-ink-2);
}

    .acc-arow + .acc-arow {
        border-top: 1px solid rgba(104,152,232,.10);
    }

    .acc-arow .nm {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .acc-arow .st {
        color: var(--nv-gold-bright);
        font-size: 12.5px;
    }

    .acc-arow .st.muted {
        color: var(--nv-ink-3);
    }

/* ── 11. THE ACCOUNT CARD'S FIELDS (v31.37, batch234) ─────────────────────
   ⚠⚠⚠ THE OWNER DREW THESE PROPORTIONS AND THEY APPLY AT EVERY SCREEN SIZE:
   two equal columns, with the full-width fields spanning both. That is the
   whole rule - no breakpoint, no third column, nothing that changes as the
   window moves. `.fin-grid3` is NOT used here: it is three fixed fractions
   down to 768px of VIEWPORT, which says nothing about the width of the CARD
   these fields are actually drawn in. */
.acc-fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

    .acc-fields > .acc-span2 {
        grid-column: 1 / -1;
    }

/* ── 12. THE REMAINING RIGHT-COLUMN CARDS (v31.37) ────────────────────── */

/* the in-use / not-in-use switch reuses the filter grid, so the two chips
   are the same width as each other and as every other chip on the page */
.acc-baview {
    margin-bottom: 8px;
}

.acc-bapager {
    margin-top: 8px;
}

.acc-ba-none {
    padding: 8px 6px;
    font-size: 13px;
}

/* the account's own open range - real values, controls not yet live */
.acc-range .acc-clear4,
.acc-doc .acc-docbtn {
    width: 100%;
    margin-top: 10px;
}

.acc-range .acc-clear4[disabled],
.acc-doc .acc-docbtn[disabled] {
    opacity: .42;
    cursor: default;
}

/* the two "not yet" badges. `.acc-soon` is a state, `.acc-ai` is a feature -
   different colours on purpose, so one is not read as the other. */
.acc-soon {
    border-left-color: var(--nv-ink-3);
    color: var(--nv-ink-3);
}

.acc-ai {
    border-left-color: var(--nv-gold);
    color: var(--nv-gold-bright);
}

.acc-sec .pill {
    margin-left: auto;
}

/* ── 13. THE ACCOUNT'S TABS (v31.39, batch236) ────────────────────────────
   Owner, after clicking the built prototype: *"definitely like to proceed with
   option 3 immediately."*

   ⚠⚠⚠ THE v31.38 FOLD RULES ARE DELETED, NOT LEFT BEHIND. The cards they
   folded now live in these tabs, so a `.acc-fold` selector matching nothing
   would be dead CSS pretending to be a feature - and the owner's own ruling on
   dead surfaces (v31.21) is that they get deleted rather than hidden.

   MEASURED, with every card built:
       all cards stacked (the locked design) ... 1911px
       right column folded (v31.38) ............ 1174px
       tabbed account (this) ................... see the block below

   ⚠ THIS IS v1's OWN SHAPE. The method that decides which sections an account
   shows is called `EShowAccBasedTabs`. v1 has always been a tabbed account
   card; v2 had flattened it into one scroll. */

/* the strip is the same equal-width wrapping grid as every other chip row on
   this page, so six tabs share one width and wrap rather than overflow */
/*  ⚠ v31.60 (owner): *"Place a horizontal line below tab selection."*

    ⚠⚠ IT GOES IN **THIS** RULE, NOT A NEW BLOCK APPENDED EARLIER.
    A second `.acc-tabs { }` written ABOVE this one has the SAME specificity,
    so this one wins on source order and the border would silently never
    appear - the CSS-ordering trap this project has hit twice, and the source
    would have read as done. When a rule for a selector already exists, add to
    it; only append a new block when nothing below it can beat it.

    ⚠ The line sits on the STRIP rather than on the panel below it, because
    every panel carries `hidden` and a border on a hidden element draws
    nothing. Same hairline as the additional-address separator and the
    search-hit rows, so the page reads as one family. */
/*  ⚠⚠ v31.157 — `.nv-tabs` IS THE TOOLKIT NAME FOR THIS EXACT CONTROL.
    Account Setup had it first as `.acc-tabs`; Notes needed the same thing
    and I invented `.nt-pills` instead — a second visual language for one
    job, which the owner spotted immediately. Both names now share ONE
    rule, so there is nothing to keep in step, and the next page that
    needs tabs uses `.nv-tabs` rather than copying Account Setup by hand. */
.acc-tabs, .nv-tabs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
    gap: 8px;
    border-bottom: 1px solid rgba(112,160,238,.22);
    padding-bottom: 10px;
    margin-bottom: 14px;
}

    .acc-tabs > .chip, .nv-tabs > .chip {
        justify-content: center;
        min-width: 0;
    }

        .acc-tabs > .chip > span, .nv-tabs > .chip > span {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

/* ⚠ THE PANELS ARE HIDDEN BY THE `hidden` ATTRIBUTE, not by a class here.
   The browser honours `hidden` without a stylesheet, so a panel cannot be left
   showing by a CSS load failure. This rule only exists because `display: grid`
   and friends elsewhere would otherwise beat `hidden`'s UA `display: none`. */
.acc-panel[hidden] {
    display: none;
}

/* ⚠ THE ACTIONS SIT BELOW THE TABS, NOT INSIDE ONE - they act on the ACCOUNT,
   not on the section being read, and a Save that moved when you changed tab
   would be a Save people stop trusting.
   ⚠ EQUAL WIDTHS: the fourth of the owner's five width rules. Save · Copy ·
   Cancel share one track; Copy sits BETWEEN the other two, which is the
   owner's locked ordering. */
.acc-acts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-top: 14px;
}

    .acc-acts > .btn {
        width: 100%;
    }

    .acc-acts > .btn[disabled] {
        opacity: .42;
        cursor: default;
    }

/* the two document buttons share a row and a width */
.acc-docrow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 8px;
    margin-top: 10px;
}

    .acc-docrow > .btn {
        width: 100%;
    }

/* a section heading INSIDE a panel is smaller than the card's own - it is a
   sub-heading now, not a card title */
.acc-panel h2.acc-sec {
    font-size: 17px;
    margin: 16px 0 8px;
}

    .acc-panel > h2.acc-sec:first-child {
        margin-top: 0;
    }

/* ── 14. THE STICKY ACCOUNT HEAD + THE AI GLYPH (v31.40, batch237) ────────
   Owner: *"a card that contains a label with ONLY the selected Account code +
   Name. This will be Static/Sticky above the middle column tabs."*

   ⚠⚠ THIS IS THE ANSWER TO THE ONE COST OF THE TABS. Moving the address off
   the Details tab meant a reader could be looking at a bank account or an open
   range with no reminder of WHOSE. The head never leaves the screen, so the
   answer is always there.
   ⚠⚠⚠ `position: sticky` STICKS TO THE NEAREST SCROLLING ANCESTOR, and it
   needs a resolved `top`. Here that ancestor is `.scroll`, the page's own
   scroller. **`.acc-detail` MUST NOT GAIN `overflow`** - it would become the
   scroll container, and since that card is exactly as tall as its content the
   head would then never stick at all. It would look like the rule was ignored.
   ⚠ AND IT NEEDS TO PAINT OVER WHAT SCROLLS BEHIND IT: the card's own
   background is a translucent gradient, so the head carries an opaque one of
   its own plus a z-index. Without that the tab strip shows through it. */
.acc-head-sticky {
    position: sticky;
    /* ⚠⚠⚠ 68px, AND IT IS NOT A GUESS. MEASURED: the scrolling ancestor of
       this head is THE VIEWPORT - every box between it and the document is
       `overflow: visible`, `.scroll` included, despite the name. And
       `.screen-head` is ALREADY `position: sticky; top: 0` and measures
       **68px** at every width from 390 to 1920 with the entity chip on it.
       So `top: 0` would have pinned this head exactly UNDERNEATH the page
       header, where nobody would ever see it - the one thing it exists to
       avoid.
       ⚠ THE HOUSE HARDCODES THESE (`.mail-bar { top: 156px }`), so this
       follows suit rather than inventing a token - but it is behind a
       variable so there is ONE number to change if the header ever grows.
       To re-measure: `getComputedStyle` the `.screen-head` height in the
       static harness; it is stable across widths. */
    top: var(--acc-headtop, 68px);
    z-index: 3;
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
    margin: -14px -14px 12px;      /* out to the card's edges */
    padding: 12px 14px;
    border-bottom: 1px solid rgba(104,152,232,.16);
    /* ⚠⚠⚠ v31.41 (batch238, owner): THE FILL AND THE RADIUS ARE GONE.
       Owner, verbatim: *"remove background and border radius in
       .acc-head-sticky"* - they read as a card inside a card, and the rounded
       top drew a second lid a few pixels below the real one.

       ⚠⚠ THE CONSEQUENCE, NAMED AND THEN MEASURED. A sticky box with no fill
       lets whatever scrolls behind it show THROUGH it. That is not a theory:
       the v31.40 comment above says in as many words that the tab strip would
       show through, which is why the fill was there.
       WHAT SAVED IT is that this head does not overlap its own card's body -
       it is the card's FIRST child and the tab strip sits below it, so at the
       moment it unsticks from the card the only thing under it is the page
       background. MEASURED with the page scrolled to its own bottom at every
       screen: nothing crosses it (`BEHIND=0` at 390/768/1280/1433/1920).
       ⚠ THAT IS A FACT ABOUT THE CURRENT ORDER OF THIS CARD, NOT A RULE. If
       anything is ever placed ABOVE the head inside `.acc-detail`, or the head
       moves down the card, the fill has to come back - one line, and it is
       this one:  background: var(--nv-surface, #101a30);
       ⚠ The bottom border STAYS. Without a fill it is the only thing that
       separates the head from the tabs when the two meet mid-scroll. */
}

    .acc-hs-code {
        flex: 0 0 auto;
        color: var(--nv-gold);
        font-variant-numeric: tabular-nums;
        letter-spacing: .3px;
        font-size: 15px;
    }

    /* ⚠ THE NAME TAKES WHAT IS LEFT AND ELLIPSES. It is the half that can be
       a thousand characters - `RefAccount.AccountName` is nvarchar(1000). */
    .acc-hs-name {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 15px;
        font-weight: 200;
        color: var(--nv-ink);
    }

/* the AI mark on the Create tab and its heading */
.acc-aiglyph {
    flex: 0 0 auto;
    color: var(--nv-gold);
}

/* ══ v31.50 (batch247, owner) - THE COUNTRY REPORT GROUPS ═══════════════════
   Owner, with v1's two tree builders attached and a screenshot arrowing a
   chart node into the report-code field. Two things get styling here: the
   NAME that now sits under each of the two mandatory codes, and the BROWSE
   PANEL that lists the country's chart.

   ⚠ IT IS AN INLINE PANEL, NOT AN OVERLAY, and that is a deliberate
   divergence from the screenshot. v1 floats the tree over the form in a
   RadWindow; v2's Groups tab has the room, and an overlay would need its own
   focus trap, its own escape key and its own answer at 390px - three new
   mechanisms to show a list. The tab already scrolls, so the panel simply
   sits under the fields it explains.
   ══════════════════════════════════════════════════════════════════════════ */

/* the resolved name, directly under its code */
.acc-grp-name {
    font-size: 12.5px;
    font-weight: 200;
    color: var(--nv-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*  ⚠ THE LIVE HALF OF THE DIAGNOSTIC. Shown only when a code answered from
    the tree it was not asked for - i.e. when the two fields are the other way
    round. Gold, because it is information the reader can act on, not an
    error: the name beside it is still the right name. */
.acc-grp-warn {
    font-size: 12px;
    color: var(--nv-gold);
}

/*  v31.188 - THE "USE THIS ONE" BESIDE THE SK/CZ EXAMPLE.
    ⚠ The form is `display: inline` so the control sits INSIDE the banner's
    sentence rather than breaking it onto a line of its own: it is the last
    word of the message, not a second message.
    ⚠⚠ A REAL SUBMIT, not a link with script behind it. It writes, so it posts
    - and it posts the same `CountryRef` handler the tree's own rows post, on
    its own form with its own route values. */
.acc-hintform {
    display: inline;
}

.acc-hintapply {
    background: transparent;
    border: 0;
    padding: 0;
    margin-left: 6px;
    font-family: inherit;
    font-size: inherit;
    font-weight: 200;
    color: var(--nv-gold-bright);
    text-decoration: underline;
    cursor: pointer;
}

    .acc-hintapply:hover {
        color: var(--nv-gold);
    }

/* ⚠ `align-self: start` so the chip is its own width rather than stretching
   the full column the way a flex child otherwise would. */
/*  ⚠ `.acc-grp-browse` RETIRED in v31.51. Owner: *"The button browse the
    chart and browse final account should be against the fields as a 'Search'
    button."* The chip UNDER the field became an `.iconbtn` BESIDE it, so this
    rule has no element left to style. See `.fld-go`. */

/*  ⚠⚠ `.fld-go` - AN INPUT WITH A BUTTON *INSIDE* IT, option B.
    Owner (2026-08-25), choosing from four mock-ups: *"B. Hairline divider - a
    1px rule in the field's own border colour splits the text zone from the
    button zone. Reads unmistakably as a control while staying in one box."*

    v31.51 put the button BESIDE the field; v31.52 moves it in. Three call
    sites: both mandatory report codes and the VIES check.

    ⚠⚠⚠ AN `<input>` CANNOT HOLD A CHILD, so this is a positioned wrapper and
    an absolutely placed button - there is no other way to do it, and every one
    of the four mock-ups used the same mechanic.

    ⚠⚠ `padding-right` IS NOT DECORATION, IT IS THE WHOLE SAFETY. It is what
    keeps the VALUE clear of the button; drop it and a long account name slides
    underneath the glyph and is unreadable with no visible cause. 46px = the
    32px button zone + 12px of air + the 2px inset. MEASURED at 390 / 768 /
    1280 / 1920: no overlap at any width, and the button's box sits inside the
    field's box with 0.00px of centre drift.

    ⚠ THE DIVIDER TAKES THE FIELD'S OWN BORDER COLOUR - `rgba(112,160,238,.30)`,
    the same value `.input` uses - so it reads as part of the control rather
    than as a decoration laid over it. Inset 5px top and bottom so it never
    touches the rounded corners.

    ⚠ NOT `.iconbtn`. That is the 48px toolkit button with its own border and
    fill; inside a 32px field both would fight the field's own edge. The three
    in-field buttons carry `.fld-btn` instead, and the page's BACK button is
    still a real `.iconbtn` - they are different controls and now say so.

    ⚠⚠ v31.56 (batch253) - THE NINTH SITE IS A `submit`, AND THAT IS THE POINT.
    Owner: *"Please implement the hairline divider and button to
    placeholder:fin.accSearch without deprecating the search using return
    key."* The account search now wears one. Because the control is a real
    submit in the form's default-button position, Enter in the field and a
    click on the glyph run the same submit - the return key is not preserved by
    a promise, it is preserved by the element type. A click handler calling
    `submit()` is what would have broken it.
    ⚠ THIS RULE ALREADY COVERED IT with no change: `.fld-btn` sets `border: 0`
    and `background: transparent`, which is exactly what a bare `submit` needs
    to stop looking like a button and start looking like part of the field. */
.fld-go {
    position: relative;
    display: block;
    min-width: 0;
}

    /*  ⚠⚠ `:has(> .fld-btn)` - THE PADDING ONLY EXISTS WHEN THE BUTTON DOES.
        v31.53 took this pattern app-wide, and one of the eight sites renders
        its button conditionally (the invoice line's business-analysis slot -
        a free-format slot has no list to pick from, so no button). Without
        the guard those fields would carry 46px of reserved space for a
        control that was never rendered. Same `:has()` the toolkit already
        uses for `.fin-hscroll`. */
    .fld-go:has(> .fld-btn) .input {
        padding-right: 46px;
    }

.fld-btn {
    position: absolute;
    top: 50%;
    right: 2px;
    transform: translateY(-50%);
    width: 32px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--nv-gold);
    border-radius: 0 5px 5px 0;
    cursor: pointer;
}

    /* the hairline. ⚠ `::before`, not a border on the button - a border would
       round with the button's own radius and sit 1px off the field's edge.

       ⚠⚠⚠ v31.82 - IT HAD BEEN 16px, NOT 22, AND HERE IS WHY. The old rule
       inset it 5px top and bottom, which is right - but it inset it from THE
       BUTTON, and the button is 26px inside a 32px field. `select.input`
       beside it insets 5px from the FIELD and draws 22px. So a text field and
       a select side by side - exactly the pair v31.53 was asked to make match
       - carried hairlines 6px different in length.
       ⚠⚠ SIZED FROM THE FIELD, AND THERE IS ONLY ONE FIELD HEIGHT. 22px is
       32px inset 5px top and bottom, which is what `select.input` draws.
       ⚠⚠⚠ AND 22 IS THE ONLY NUMBER NEEDED, WHICH I LEARNED THE EXPENSIVE
       WAY. Two controls in the app ASK to be taller - the email sheet's
       search box carries `style="height:48px"` and the VAT card's account
       field sets `height: 36px` - and I built a 30px and a 24px divider for
       them. Neither control is that tall. THE END OF THIS FILE CARRIES
       `input.input { height: 32px !important; min-height: 32px !important }`
       (v16.2, reaffirmed v21.0), and an `!important` author declaration beats
       an inline style, so both have been 32px for many versions. A 30px
       divider would have been taller than the box it divides. The probe
       measured `fieldH = 32` on both; nothing else would have caught it.
       ⚠ A TALLER CONTROL CANNOT EXIST until that override is relaxed, so
       there is no variant class and no variable - one height, stated once.
       ⚠ THIS IS AN UNASKED CHANGE ON NINE SHIPPED SITES. It is 3px at each
       end of a 1px line, it makes the two dividers agree, and it is one line
       to revert: put `height: 16px` here. */
    .fld-btn::before {
        content: '';
        position: absolute;
        left: 0;
        top: 50%;
        height: 22px;
        transform: translateY(-50%);
        width: 1px;
        background: rgba(112,160,238,.30);
    }

    .fld-btn:hover {
        color: var(--nv-gold-bright);
    }

    /* ⚠ `:focus-visible`, not `:focus` - a mouse click on it should not leave a
       ring behind, but a keyboard user must be able to see where they are. */
    .fld-btn:focus-visible {
        outline: 2px solid var(--nv-blue-bright);
        outline-offset: 1px;
    }

/*  ⚠⚠ v31.83 (owner) - `.badge.gold.is-new`: THE NUMBER GOES GREEN AND
    NOTHING ELSE MOVES. Owner: *"change only the number colour to green but
    leave all other badge styling unchanged."*

    ⚠ `.badge` AND `.badge.gold` LIVE IN `tokens.css`, and this rule does not
    join them there. tokens.css is the design-token sheet - the shapes every
    screen inherits - and a one-screen state is not a token. `app.css` loads
    after it and `0,3,0` beats `0,2,0`, so the colour wins on specificity
    rather than on file order, which is the safer of the two.
    ⚠ `--nv-good` is the app's existing green (`#58b368`), the same one the
    mailbox's own new-email figure uses. Not a new colour. */
.badge.gold.is-new {
    color: var(--nv-good);
}

/*  ⚠ THE VIES ANSWER. Three states and three colours, because the whole point
    of the check is that "could not ask" must never read as "not valid".
    `.muted` for unknown, green for valid, gold for not valid - NOT red: the
    number may simply be one the holder has not registered for cross-border
    trade, which is information, not an error. */
.acc-vies {
    font-size: 12.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

    .acc-vies.is-ok {
        color: var(--acc-green, #3fca85);
    }

    .acc-vies.is-no {
        color: var(--nv-gold);
    }

/*  ⚠ THE 10px THE OWNER ASKED FOR. Owner: *"The 'Save Address' button has no
    space between it ... and the email 'AddrEmail' at the top. Please make this
    gap/space about 10px between the two controls. The same gap styling needs
    to be applied to fin.accSaveRange button and the row above it."*
    ⚠⚠ IT IS ITS OWN CLASS, NOT A CHANGE TO `.acc-new`. That class also wraps
    the NEW-ACCOUNT form in the list card, where the row above it is a card
    heading with its own spacing - moving `.acc-new` would have moved a third
    thing the owner did not ask about. */
.acc-actions {
    margin-top: 10px;
}

.acc-tree {
    margin-top: 12px;
    border: 1px solid var(--nv-line, rgba(232, 167, 92, .18));
    border-radius: 10px;
    padding: 8px;
}

    .acc-tree-head {
        display: flex;
        align-items: center;
        gap: 10px;
        margin-bottom: 8px;
    }

    /*  ⚠⚠ THE CAP IS MEASURED, NOT ROUNDED. (batch238's lesson: 224px showed
        six rows where seven were asked for, because the rows were 32.25px and
        not the 32 they looked like.)

        A row is 18px of line box plus 5px of padding top and bottom - 28.00px
        exactly, measured at 390 / 768 / 1280 / 1440 / 1920 with no variance,
        which is why the line height is STATED here rather than inherited from
        whatever the card's font settles on.

        MEASURED, from `scrollTop = 0`, with the whole chart expanded:
            400px cap  →  14 whole rows, 8px left  (= this box's own padding)
        so the tall branch is fourteen ENTIRE rows and never
        thirteen-and-a-sliver.

        ⚠ `50vh` WINS ON A SHORT WINDOW, where a fixed 400 would push the rest
        of the tab off the bottom. It does NOT land on a whole row and it is
        not supposed to - measured 10 rows + 12px at a 600px-tall window,
        8 rows + 8px at 480px. A part-row at the fold is what tells the reader
        the list continues. */
    .acc-tree-body {
        max-height: min(50vh, 400px);
        overflow-y: auto;
        overflow-x: hidden;
        padding: 4px 0;
    }

/*  ⚠⚠⚠ v31.66 (batch263) - THE OWNER SENT THESE TWO RULES VERBATIM after
    seeing the finished tree: `.acc-tree-row` at **17px**, `.acc-tree-d1` at
    weight **200**. Applied exactly as written.

    ⚠⚠ THESE ARE THE SHARED CLASSES, SO THE CHART-OF-ACCOUNTS PANEL TAKES THEM
    TOO. That is a second control changing on one instruction, and it is called
    out rather than quietly scoped: the two panels are deliberately one look,
    and splitting them here would be the start of two trees that drift.
    ⚠⚠⚠ THE ROW HEIGHT DOES NOT MOVE, AND THAT WAS THE THING TO CHECK. Height
    is `line-height: 18px` plus 5px of padding top and bottom = 28.00px, and
    `font-size` is not part of that sum - measured 28.00 at 13px and 28.00 at
    17px. So the chart panel's cap, which was measured as "14 whole rows in
    400px", still lands on whole rows.
    ⚠ 17px IN AN 18px LINE BOX IS TIGHT and was measured for clipping rather
    than assumed: `.acc-tree-nm` has `overflow: hidden`, so a descender that
    overran would be cut. Measured `scrollHeight == clientHeight` on every row
    at every width - nothing is clipped. */
.acc-tree-row {
    display: flex;
    align-items: center;
    gap: 8px;
    line-height: 18px;
    padding: 5px 6px;
    /*  ⚠ v31.85 (owner) - 17px -> 14px. The v31.66 note above records 17px as
        the owner's own number; this is the owner's own revision of it, after
        living with the finished tree.
        ⚠⚠ AND IT MOVES BOTH TREES, exactly as 17px did - `.acc-tree-row` is
        shared by the country picker and the chart-of-accounts panel, and they
        are deliberately one look. Called out rather than quietly scoped.
        ⚠ THE ROW HEIGHT DOES NOT MOVE: height is `line-height: 18px` + 5px of
        padding top and bottom = 28.00px, and `font-size` is not part of that
        sum. Measured 28.00 at 17px and 28.00 at 14px, so the chart panel's
        "14 whole rows in 400px" cap still lands on whole rows.
        ⚠ 14px is above the 13px font floor, so the floor gate is unaffected. */
    font-size: 14px;
    font-weight: 200;
    color: var(--nv-ink-2);
    border-radius: 6px;
    cursor: default;
}

    /* ⚠ ONLY A ROW THE SCRIPT GAVE A TWISTY IS CLICKABLE. A leaf that
       highlights on hover promises a click that does nothing.
       ⚠⚠ THIS SELECTS AN ATTRIBUTE, AND A REAL BUTTON DOES NOT CARRY ONE -
       see the rule below. It serves the DIV rows the script marks up, and
       only those. */
    .acc-tree-row[role="button"] {
        cursor: pointer;
    }

        .acc-tree-row[role="button"]:hover {
            background: rgba(232, 167, 92, .06);
        }

/*  ⚠⚠⚠ v31.84 (owner) - A PICKABLE ROW IS A REAL BUTTON, AND IT HAS BEEN
    DRESSED AS ONE SINCE R2.

    Owner: *"Somthing has changed in `title:fin.accCntryPick` or perhaps
    [.acc-tree-row]"* - and the version he pasted had `background: transparent`
    and `border: none` added by hand, which is the whole diagnosis in two
    declarations.

    WHAT HAPPENED. v31.74 made a pickable row a real `type=submit` control so
    the tree could post its `ReportAnalysisId` - the right change, and the
    right element. But `.acc-tree-row` only ever styled DIVs, and the one rule
    that resets a clickable row (`[role="button"]`, just above) matches an
    ATTRIBUTE THE BROWSER DOES NOT NEED ON A REAL BUTTON and therefore never
    matched the new rows at all. Every pickable row has been rendering with
    the operating system's own button chrome ever since.

    MEASURED, side by side in the same tree, before this rule existed:

        property        DIV row              BUTTON row
        width           460px (full)         132-294px (shrink-wrapped)
        height          28px                 32px
        font-family     Poppins              **Arial**
        background      transparent          **rgb(239,239,239)**
        border          none                 **2px outset**
        cursor          pointer              default

    So the chart tree has been drawing its selectable rows as grey system
    buttons, in the wrong typeface, at ragged widths, among Poppins text rows
    - and 32px tall, which quietly broke the 28.00px row height the v31.66
    note above went to some trouble to measure and preserve.

    ⚠⚠ `font-family: inherit` IS THE NON-OBVIOUS ONE. A button does not
    inherit the page's typeface; `font-size` and `font-weight` were already
    forced by `.acc-tree-row`, which is exactly why the rows looked *almost*
    right and the cause was hard to name.
    ⚠ `width: 100%` IS NOT COSMETIC EITHER. A button is shrink-to-fit, so the
    hover and current-row fills stopped at the end of the text instead of
    running the width of the panel, and `.acc-tree-nm`'s `flex: 1` had no
    room to work with.
    ⚠ `background: transparent` is at (0,1,1) and `.acc-tree-row.is-cur` at
    (0,2,0), so the current row keeps its gold fill. Checked, not assumed.
    ⚠ `border-radius: 6px` on the base rule is KEPT. It is only ever visible
    behind a fill (hover, or the current row), and without it that fill is a
    hard rectangle. Say the word if you want it gone - it is one line. */
button.acc-tree-row {
    width: 100%;
    background: transparent;
    border: 0;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

    button.acc-tree-row:hover {
        background: rgba(232, 167, 92, .06);
    }

/*  ⚠⚠⚠ v31.160 — AN ANCHOR TREE ROW, AND THIS IS THE v31.84 BUTTON LESSON
    REPEATED FOR THE OTHER ELEMENT. That note above records what happened when
    a pickable row became a real `<button>`: `.acc-tree-row` had only ever
    styled DIVs, so the row arrived wearing the operating system's own chrome —
    Arial, grey fill, 2px outset border, 32px instead of 28.

    Notes' rows must NAVIGATE, so they are `<a>`, and an anchor arrives with
    its own inheritance: UA link colour and an underline that PROPAGATES to
    every descendant and cannot be cancelled by them. That is precisely the
    fault the owner reported at v31.158 ("purple under line and weird blue
    underline"), and it would have come straight back the moment these rows
    joined the house tree.

    ⚠ Everything here mirrors `button.acc-tree-row` so the three element types
      are one row: same width, same left alignment, same pointer, and the two
      declarations an anchor needs on top. */
a.acc-tree-row {
    width: 100%;
    background: transparent;
    border: 0;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    /*  the owner's v29.6 ruling, third time of asking: nothing in these
        controls is ever underlined. */
    text-decoration: none;
    color: var(--nv-ink-2);
}

    a.acc-tree-row:hover {
        background: rgba(232, 167, 92, .06);
    }

/*  ⚠⚠ A FOURTH DEPTH. The house tree has three (d1 · d2 24px · d3 42px) because
    nothing had ever needed more; v1's Notes tree is Entity › Account › Folder ›
    Note. This continues the same +18px step and is a pure addition — no
    existing caller has a d4 row, so the country picker and the chart-of-
    accounts panel cannot see this. */
.acc-tree-d4 {
    padding-left: 60px;
}

/*  ⚠ v31.166 — LEVEL 5, on the ladder's own 18px step (6 · 24 · 42 · 60 · 78).
    The Notes tree grew a CATALOG level above the entity, so its note leaf sits
    one deeper than it did. Same scoping argument as d4: no other caller has a
    d5 row, so the country picker and the chart-of-accounts panel cannot see
    this rule at all. */
.acc-tree-d5 {
    padding-left: 78px;
}

    .acc-tree-d1 {
        color: var(--nv-ink);
        font-weight: 200;
    }

    /* ⚠ INDENT IS PADDING ON THE ROW, NOT A MARGIN, so the hover fill and the
       current-row fill still start at the panel's left edge - a highlight that
       steps inwards with the depth reads as a different control. */
    .acc-tree-d2 {
        padding-left: 24px;
    }

    .acc-tree-d3 {
        padding-left: 42px;
    }

    /* the code this account already holds */
    .acc-tree-row.is-cur {
        background: rgba(232, 167, 92, .1);
        color: var(--nv-ink);
    }

    /*  ⚠⚠ `white-space: nowrap` IS LOAD-BEARING, and a measurement is what
        proved it. A 12px box holding a glyph that renders wider - a font
        without U+25B8, a mis-decoded byte sequence, a user zoom - wraps to a
        SECOND LINE, and because the row is a flex container the row grows
        with it: measured at 46px instead of 28px, for every class and group
        heading in the panel, with the leaf rows still at 28. The arrow is
        decoration; it must never be allowed to set the row height. */
    .acc-tree-tw {
        flex: 0 0 auto;
        width: 12px;
        color: var(--nv-gold);
        font-size: 11px;
        line-height: 18px;
        white-space: nowrap;
        overflow: hidden;
        text-align: center;
    }

    /*  ⚠ v31.84 (owner) - `font-variant-numeric: tabular-nums` REMOVED here.
        The note that used to sit on this rule argued that account codes in a
        column want fixed-width digits; the owner has looked at the finished
        tree and does not want it, and his eye on his own screen beats an
        argument from first principles.
        ⚠⚠ ONLY THIS ONE. There are THIRTEEN other `tabular-nums` declarations
        in this file - money columns, file sizes, folder counts, the account
        list's own code column - and every one of them is left alone. A
        blanket removal would have changed amounts on every financial screen
        in the app on the strength of one remark about one tree. */
    .acc-tree-cd {
        flex: 0 0 auto;
        min-width: 38px;
        color: var(--nv-gold);
    }

    .acc-tree-nm {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/*  ══ v31.62 (batch259, owner) - THE COUNTRY PICKER'S TREE ═══════════════
    Owner: *"the drop-down is currently a very long list of countries. We
    should use the tree structure, similar to the one for transaction types...
    I would be extremely grateful if you can even create a further node, so we
    have three levels."*

    ⚠⚠⚠ IT REUSES `.acc-tree*` ENTIRELY - the same rows, the same 28px, the
    same indents, the same twisty, the same measured body cap. Two tree
    controls on one page that look like two different controls would be the
    real cost here, and the chart panel's geometry was measured once already.
    Everything below is about turning that panel into something that hangs
    UNDER a field instead of sitting in the page.

    ⚠ THE SELECT IS STILL THERE, hidden, and it is still what posts. With no
    script none of this exists and the grouped dropdown is what the reader
    gets.
    ══════════════════════════════════════════════════════════════════════ */
.acc-ctrywrap {
    position: relative;
    display: block;
    width: 100%;
    min-width: 0;
}

/*  ⚠⚠⚠ v31.66 (batch263, owner): *"I do not know how to suggest change for
    drop-down country which is behind the save, copy, cancel div."*

    THE PANEL WAS NEVER SHORT OF z-index - IT WAS IN THE WRONG STACKING
    CONTEXT. `.flip` carries `perspective: 1400px`, and a non-`none`
    perspective **establishes a stacking context**; `.flip-inner` adds
    `transform-style: preserve-3d` on top. So `.acc-ctrypop`'s `z-index: 40` is
    resolved entirely INSIDE the flip and cannot out-rank anything outside it.
    `.acc-acts` comes later in the document and its buttons are positioned, so
    it painted over the panel no matter what number the panel carried.

    > **A z-index ONLY COMPETES WITH ITS SIBLINGS IN THE SAME STACKING CONTEXT.
    > WHEN A PANEL WILL NOT RISE, LOOK FOR AN ANCESTOR WITH `transform`,
    > `perspective`, `filter` OR `opacity` BEFORE REACHING FOR A BIGGER
    > NUMBER.**

    So the CONTEXT is lifted, not the panel - and only while a panel is open.
    ⚠ A CARD PERMANENTLY STACKED ABOVE THE ACTION BAR would put a
    3D-transformed subtree over the Save button for all the time no picker is
    open, which is how a Save quietly stops being clickable.
    ⚠ 60 CLEARS THE BAR AND STAYS UNDER THE APP'S SHEETS AND TRAYS, which live
    at 34-41 and at 60 with their own overlay; nothing here should ever cover
    one of those. */
    .acc-ctrywrap.is-open {
        z-index: 60;
    }

.flip.has-ctry-open {
    position: relative;
    z-index: 60;
}

    /*  the face: a button wearing `.input`, so it is the same 32px box with the
        same border and fill as the field it replaced. ⚠ `text-align` is not
        enough on its own - `.input` is `display: flex`, so the caret is pushed
        out by `margin-left: auto` rather than floated. */
    .acc-ctrybtn {
        cursor: pointer;
        text-align: left;
        overflow: hidden;
    }

        .acc-ctrybtn > .acc-ctrynm {
            flex: 1 1 auto;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .acc-ctrybtn > .acc-ctrycar {
            flex: 0 0 auto;
            margin-left: auto;
            color: var(--nv-gold);
            font-size: 11px;
            line-height: 1;
        }

/*  ⚠⚠ IT IS WIDER THAN THE FIELD IT HANGS UNDER, AND IT HAS TO BE. This
    picker sits in a HALF cell (`.acc-pair` splits one grid cell in two), and
    "Bosnia and Herzegovina" indented three levels does not fit in half of half
    a card. `min-width: 100%` keeps it at least as wide as its field; 280px is
    the floor. It is also `right: auto` on purpose - the field is on the left
    of its pair at every width this card is drawn at.
    ⚠ THE FILL IS OPAQUE. A translucent panel over a form shows the boxes
    behind it through the country names, which at 13px is unreadable - the
    same reason the real form controls carry an opaque `background-color`. */
.acc-ctrypop {
    position: absolute;
    z-index: 40;
    left: 0;
    top: calc(100% + 4px);
    min-width: 100%;
    width: max(100%, 280px);
    margin-top: 0;
    background: #101a30;
    box-shadow: 0 12px 34px rgba(0,0,0,.5);
}

    /*  ⚠ SHORTER THAN THE CHART PANEL'S. That one is the whole tab and can
        take half the window; this one hangs over the fields under it, and a
        list long enough to cover the Save button is a list that hides the way
        out. 320px is 11 whole 28px rows plus this box's own 8px padding. */
    .acc-ctrypop .acc-tree-body {
        max-height: min(46vh, 320px);
    }

    /*  ⚠⚠⚠ v31.65 (batch262, owner): *"The second node should have a 30-40px
        offset so it appears tabbed."*

        The shared `.acc-tree-d2` / `-d3` steps are 24px and 42px, drawn for the
        chart of accounts where every row carries a numeric code in a 38px
        column and the code column itself reads as the indent. The country tree
        has no code on its headings at all, so 24px was not enough to say
        "this hangs under that" - three levels looked like one list with some
        rows slightly further in.

        34px and 68px: the owner's range, and an EQUAL STEP between the levels,
        which is what makes the depth readable at a glance rather than a
        judgement about which gap is bigger.

        ⚠⚠ SCOPED TO THE POPOVER, and deliberately. The same two classes draw
        the chart-of-accounts panel, whose indents were measured into shape and
        which nobody asked to change. Two trees, one look, different content -
        and the content is what sets the indent. */
    .acc-ctrypop .acc-tree-d2 {
        padding-left: 34px;
    }

    .acc-ctrypop .acc-tree-d3 {
        padding-left: 68px;
    }

/*  ══ v31.55 (batch252, ROUND 1 of the endgame plan) - THE ANALYSIS SWITCH ═══
    Owner, from three live mock-ups: *"please let us use, '1.', Switch on the
    right. Keeps today's row exactly as it is and adds a switch where the tick
    used to be."*

    ⚠ IT SITS IN THE TICK'S GRID CELL. `.acc-ba` is
    `minmax(0,1fr) max-content max-content` and stays that way - name, state
    word, control - so nothing about the row's proportions moves. The green
    tick is gone because the switch now carries that information, and two
    controls saying the same thing is how they start disagreeing.

    ⚠⚠ GREEN WHEN ON, AND THAT IS NOT DECORATION. `--acc-green` is the colour
    this module already uses for "the posting gate is satisfied"; the switch
    turns it on because what it sets is exactly what that gate reads.
    ══════════════════════════════════════════════════════════════════════════ */
.acc-sw {
    flex: 0 0 auto;
    width: 34px;
    height: 19px;
    padding: 0;
    border-radius: 10px;
    border: 1px solid rgba(104,152,232,.32);
    background: rgba(255,255,255,.04);
    position: relative;
    cursor: pointer;
}

    /*  ⚠ THE KNOB IS A PSEUDO-ELEMENT, so the button keeps ONE box and the
        34x19 hit area is the whole control rather than the 13px dot. It is
        already the smallest target on the page - the owner chose this option
        knowing that - so none of it is given away to a child element. */
    .acc-sw::after {
        content: '';
        position: absolute;
        top: 2px;
        left: 2px;
        width: 13px;
        height: 13px;
        border-radius: 50%;
        background: var(--nv-ink-3);
        transition: transform .15s ease, background .15s ease;
    }

    .acc-sw[aria-checked="true"] {
        background: rgba(63,202,133,.18);
        border-color: rgba(63,202,133,.5);
    }

        .acc-sw[aria-checked="true"]::after {
            transform: translateX(15px);
            background: var(--acc-green, #3fca85);
        }

    /*  ⚠⚠ DISABLED MEANS "the entity does not use this code AND the account
        does not carry it". A slot that is off in the entity but ON here is NOT
        disabled - it has one move left, and it has to keep it or the value is
        stranded where the posting gate can still read it. */
    .acc-sw:disabled {
        opacity: .4;
        cursor: not-allowed;
    }

    .acc-sw:focus-visible {
        outline: 2px solid var(--nv-blue-bright);
        outline-offset: 2px;
    }

/*  ⚠ `prefers-reduced-motion` - the knob slides, so it has to be able not to. */
@media (prefers-reduced-motion: reduce) {
    .acc-sw::after {
        transition: none;
    }
}

/*  the save row: the button, then the consequence in numbers beside it */
.acc-basave {
    align-items: center;
}

    .acc-basave .acc-bacount {
        margin-bottom: 0;
        font-size: 12.5px;
    }

    .acc-basave #baDirty {
        color: var(--nv-gold);
    }

/* ══ THE COPY SHEET (v31.76, batch272 - R4.1) ══════════════════════════════
   ⚠ FIVE RULES, AND NOT ONE OF THEM IS A NEW COMPONENT. The sheet itself is
   `.mail-sheet`, its rows are `.t-leaf`, its fields are the house
   `.fld-wrap` + `.fl-hint` + `.input` trio and its warning is `.acc-ba-hint`.
   These five only place them.
   ⚠⚠ EVERY CLASS HERE IS PREFIXED `.acc-cp-` AND WAS GREPPED FIRST. `.acc-cp`
   appears nowhere else in this file - the short-class-name trap (`.fld` is the
   FOLDER ROW, `.vr-tick` was already taken) has cost this project twice. */

/* ⚠⚠⚠ NOT ONE `font-size` IN THIS BLOCK, AND THAT IS THE POINT. The first cut
   set 12.5px here and 12px below, and the FONT-FLOOR GATE caught it: the count
   of screen sizes at or under 13px went 30 -> 31. The owner's standing rule is
   that type sizes are reviewed PAGE BY PAGE and none is added in passing.
   The three elements now carry `.acc-ba-hint`, the muted hint this page
   already uses for exactly this - so these rules PLACE them and nothing more,
   and the size stays one fact in one place. */

.acc-cp-src {
    padding: 0 2px 10px;
}

.acc-cp-hint,
.acc-cp-what {
    padding: 10px 2px 0;
}

.acc-cp-rule {
    border: 0;
    border-top: 1px solid rgba(104,152,232,.13);
    margin: 12px 0;
}

.acc-cp-warn {
    margin: 10px 2px 0;
}

/*  v31.192 - THE DELETE CONFIRM.
    ⚠ THE QUESTION IS THE BIGGEST THING IN IT. `.ctext` is the house's confirm
    body at 16px and that is what the "are you sure" line wears; the consequence
    line below it drops to the hint size so a warning cannot shout down the
    thing being asked. The screenshot is what caught it - the numbers said
    nothing was wrong. */
.acc-del-warn {
    margin: 10px 2px 16px;
}

/*  ⚠ THE SHEET IS NARROWER THAN THE COPY ONE because it asks a question rather
    than offering a chooser: `min(560px, calc(100vw - 32px))` is the same
    formula the copy sheet uses, one step down. */
.acc-del-sheet {
    max-width: min(560px, calc(100vw - 32px));
}

/* ⚠ THE OWNER'S FOURTH WIDTH RULE: the two actions share one track width, so
   neither is sized by its English label. `minmax(0, 1fr)` - not `1fr` - because
   a bare `1fr` floors at the content's min width and a long German label would
   push the pair wider than the sheet. */
.acc-cp-acts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    margin: 16px 2px 0;
}

    .acc-cp-acts > .btn {
        width: 100%;
    }

/* ══ v31.77 (batch273, owner) ══════════════════════════════════════════════ */

/*  ⚠⚠⚠ `.highlight` - THE OWNER'S OWN RULE, AND WHY IT CANNOT BE A `b`.
    He gave it as `.mk-src b { color: var(--nv-ink); font-weight: 300 }` off the
    mock-up, and asked for a `highlight` instead of the `b`. **That is the only
    way to get weight 300**: `b { font-weight: 400 !important }` is app-wide and
    unbeatable in this app, so a bold tag can never take a lighter weight. The
    house answer to "make this stand out" has always been a span with a class.
    ⚠ It sets NO font-size, so it lifts whatever line it sits in rather than
    resizing it - which is what lets it be used anywhere.
    ⚠⚠ GREPPED FIRST: `.highlight` appears nowhere else in app.css or
    tokens.css. It is deliberately a general name because it is a general
    utility - unlike `.fld`, which reads general and is the FOLDER ROW. */
.highlight {
    color: var(--nv-ink);
    font-weight: 300;
}

/*  ⚠ THE COPY BUTTON OPENS SOMETHING, SO IT CARRIES THE DOWN CHEVRON - the
    owner's standing ruling that every down chevron gets the same treatment.
    The gap is the `.chips` gap so the glyph sits off the word the same way it
    does on the More chip. */
.acc-cp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

    .acc-cp-btn .chev {
        flex: 0 0 auto;
        /* ⚠ `content-box`, because the global `*` reset is `border-box` and
           would SQUEEZE the glyph rather than pad it - the batch253 lesson. */
        box-sizing: content-box;
    }

/*  ⚠ THE RULE UNDER THE HEADLINE (owner). `.acc-cp-rule` already draws the
    hairline between the destination and the detail; the top one only needs a
    different margin, so it is a modifier rather than a second rule. */
.acc-cp-rule-top {
    margin: 2px 0 12px;
}

/*  ══ THE ENTITY TREE INSIDE THE COPY SHEET ═══════════════════════════════
    ⚠⚠⚠ NOT ONE STRUCTURAL RULE HERE. The tree is `.ent-node` / `.ent-db` /
    `.ent-grp` / `.ent-body` / `.fld` / `.fi` / `.fl` / `.fc` - the Organisation
    sheet's own components, which app.css already styles. These four rules only
    PLACE that tree inside a sheet it was not written for and decide when the
    tick shows. Owner: *"styled as with Entity switch"* - so the way to honour
    that is to use the same classes, not to redraw them. */
/*  ⚠⚠⚠ THE CAP IS ON THE SHEET, NOT ON THE TREE - AND THE FIRST CUT HAD IT
    THE OTHER WAY ROUND. `max-height: 34vh` on the tree alone clipped the last
    catalog with NO scrollbar and no other cue: the render showed NOVERA Family
    ending at United Kingdom and NOVERA Clients simply absent. **A box that
    silently drops half its options is worse than one that is too tall** - the
    reader cannot miss what they cannot see.
    ⚠ Only LOOKING at the screenshot caught it; `treeScrolls: true` in the
    measurement read as "handled".
    ⚠⚠ AND THE SHEET WAS 845px TALL, which no phone shows. Capping the sheet
    fixes both at once: everything stays reachable, and on a tall screen
    nothing scrolls at all. */
#accCopySheet {
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    /* ⚠ BOTH AXES NAMED. `overflow-y: auto` alone silently makes a sideways
       scroller too - the v31.31 bank-card lesson. */
    overflow-x: hidden;
}

.acc-cp-tree {
    display: block;
    min-width: 0;
}

    .acc-cp-tree > .fl-hint {
        margin-bottom: 4px;
    }

/*  ⚠⚠ THE TICK KEEPS ITS WIDTH WHEN IT IS NOT SHOWING. `visibility`, never
    `display`: hiding the glyph outright would let each row's name column find
    its own width and the list would stop lining up. The Organisation sheet
    reserves the same slot. */
.acc-cp-ent .acc-cp-tick {
    visibility: hidden;
}

.acc-cp-ent.on .acc-cp-tick {
    visibility: visible;
}

/*  ⚠ A ROW THAT IS A BUTTON NEEDS THE BUTTON RESET, the same one the
    Organisation sheet applies inline. Here it is a rule, because there are
    many rows and an inline style cannot be overridden by a later stylesheet. */
button.fld.acc-cp-ent {
    width: 100%;
    background: transparent;
    border: 0;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    color: inherit;
}

    button.fld.acc-cp-ent.on {
        background: rgba(232,167,92,.14);
    }

/*  ══════════════════════════════════════════════════════════════════════════
    R7.6 (v31.86, batch281, owner) - THE ACCOUNT-TYPE CHANGE ROW
    Owner: *"Change account type using validations shown in v1."*
    ══════════════════════════════════════════════════════════════════════════

    ⚠⚠ IT IS ONE CELL OF `.acc-fields`, NOT A NEW ROW. The Details grid is two
    equal columns and the type has always been the second cell of the first
    row; adding a button beside the field must not cost a row that the owner
    spent v31.59 winning back on the address block.
    ⚠ `minmax(0, 1fr)` on the select, exactly as `.acc-pair` uses: a long type
    name would otherwise refuse to shrink and push the button out of the cell. */
/*  ══════════════════════════════════════════════════════════════════════════
    v31.88 (batch283, owner) - `.btn.h34`, A HEIGHT BRANCH FOR THE HOUSE BUTTON
    Owner: *"Please create a css style branch where we can have this as a
    variation from height 51px."*
    ══════════════════════════════════════════════════════════════════════════

    ⚠⚠ IT IS A BRANCH, NOT AN OVERRIDE ON ONE ELEMENT, and the difference is the
    point. `tokens.css` sets `.btn { height: 51px; font-size: 19px }` app-wide,
    and until now every page that wanted something shorter wrote its own rule
    against its own class - `.acc-docbtn`, `.ctl3 .btn`, the copy sheet's rows.
    Each of those is a private answer to the same question, and each drifts on
    its own. `.h34` is the shared answer: **add the class, get the short
    button**, on any `.btn` anywhere in the app.

    ⚠⚠⚠ THE FONT COMES DOWN WITH THE BOX, AND THAT IS NOT OPTIONAL. 19px glyphs
    in a 34px box leave 7px of breathing room top and bottom and the label sits
    on the box like a lid. 15px is the same ratio the 51px button has at 19px,
    so the short button reads as the SAME button rather than a squashed one.
    ⚠ `padding` comes down too: the house 51px button's horizontal padding is
    sized for its height, and keeping it would make a short WIDE button.

    ⚠ WHY 34 AND NOT 32: the fields on these cards are 32px
    (`input.input:not([type="file"]) { height: 32px !important }`), and a button
    that measures EXACTLY the same as the field beside it reads as another
    field. 34 is the smallest step that still reads as a control you press -
    and it is a size the app already uses (`.chip` at 32, the tab strip at 34).
    ⚠⚠ `min-height` IS SET TOO. `.btn` is `display: flex`, and a flex container
    with a long label will grow past a bare `height`; naming both is what makes
    34 a fact rather than a preference.

    ⚠ IT IS PLACED AT THE FOOT OF app.css so nothing below can beat it by
    source order - the ordering trap this file has paid for twice. */
.btn.h34 {
    height: 34px;
    min-height: 34px;
    font-size: 15px;
    padding: 0 14px;
}

/*  ⚠⚠⚠ v31.87 (batch282, owner) - THE SELECT AND THE BUTTON ARE STACKED, AND
    THE ROW THEY USED TO SHARE WAS BROKEN. Owner: *"Please move the button
    'fin.accTypeChange' to the row below id='accTySel'."*

    MEASURED on v31.86 in a 617px card: the cell is 282px wide, the select
    rendered **64px** and the button **282px starting at x=507** - seventy-two
    pixels outside the card.
    ⚠⚠ THE CAUSE WAS `tokens.css`'s app-wide `.btn { width: 100%; height: 51px }`.
    v31.86 gave `.acc-tybtn` a height and `flex: 0 0 auto` and **never named
    `width`**, so the flex basis resolved to `auto`, took the inherited 100%,
    and the button claimed the whole cell while the select shrank to its
    minimum.
    > ⚠ **`flex: 0 0 auto` DOES NOT MEAN "AS WIDE AS MY CONTENT" - IT MEANS "AS
    > WIDE AS MY `width` SAYS".** With a 100% base rule above it, that is the
    > container.

    ⚠ SO THE HEIGHT OVERRIDE IS GONE TOO. Stacked, the button is the house
    button at its house size - the same 51px full-width shape `Save
    registration` and the Save / Copy / Cancel footer already have on this card.
    One less rule fighting the base, and one less size on the screen.
    ⚠ `.fld-wrap` is already a flex COLUMN, so this cell inherits the stacking;
    only the gap above the button is set here. */
.acc-tycell > .acc-tybtn {
    margin-top: 8px;
}

/*  ⚠⚠⚠ THE CROSSING WARNING. Six of v1's transitions take an ADDRESSED
    account to a NOMINAL one, and the owner confirmed BOTH halves: the
    selector is right, and v2's `IsAddressed` is right. So this is a
    consequence to show, never a discrepancy to hide.
    ⚠ GOLD, NOT RED, and the distinction is the same one `.acc-grp-warn`
    makes: nothing has gone wrong and nothing is lost - the rows stay in the
    tables - so this is information to act on, not an error. */
.acc-tywarn {
    margin-top: -4px;
}

    .acc-tywarn > .acc-tywarn-t {
        font-size: 12px;
        line-height: 1.45;
        color: var(--nv-gold);
    }

/*  ⚠ THE DOT SITS ON ITS OWN HINT LINE rather than on a heading, because
    this block has no heading - it is a field, and the toolkit's dot is
    normally a child of `h2.section`. Flex keeps the two on one baseline and
    the note (a block) drops beneath both. */
/*  ⚠ v31.88 (batch283) - `.acc-regi` RETIRED. The registration dot moved onto
    the section heading at the owner's request, where `h2.section` already
    places a `.nv-i` correctly and no rule of our own is needed. The class had
    exactly one element and it no longer exists - **and before deleting a CSS
    rule, count the elements that use it** (the `.acc-ro-note` lesson: that one
    was removed with the one note it was written for and had three). Counted: 0.

/*  ⚠⚠⚠ v31.87 (batch282, owner) - `flex-direction: row` IS THE WHOLE FIX, AND
    ITS ABSENCE WAS THE DEFECT. Owner: *"The fin.accTypeAbout should be in the
    same row as the icon (accTyNote)."*

    MEASURED on v31.86: the label sat at y=173 and the dot at y=191 - stacked,
    and centred in the card rather than left-aligned.
    ⚠⚠ `.acc-tynote` set `display: flex` and never named the DIRECTION, so it
    INHERITED `column` from `.fld-wrap`, and the `align-items: center` written
    to centre the pair vertically centred them horizontally instead.
    > ⚠ **SETTING `display: flex` ON AN ELEMENT THAT IS ALREADY A FLEX COLUMN
    > CHANGES NOTHING.** Direction is the property that has to be named.

    ⚠⚠ v31.88 (owner): THE PAIR IS NOW THE SECOND LINE OF THE **CODE** CELL, not
    a grid cell of its own. Owner: *"The contents of the note ... should move to
    the column to the left of the change button."* The button is the second line
    of the TYPE cell, so its left-hand neighbour is the second line of the CODE
    cell - a row of its own would have sat a row lower, which is exactly where
    v31.87 put it.
    ⚠ `margin-top: auto` is what levels it with the button: the Code cell's
    first line is a 32px field and the Type cell's is a 32px select, so pushing
    this block to the BOTTOM of its cell lands it on the button's line whatever
    the button's height happens to be. It follows `.h34` without knowing about
    it. */
.acc-tynote {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-start;
    gap: 0;
    /*  ⚠ 4px ON TOP OF `.fld-wrap`'s OWN 4px GAP = the 8px the button carries,
        so the two land on the SAME LINE. MEASURED without it: the About row at
        y=165 against a button at y=169. `margin-top: auto` did nothing here -
        the cell has no free space to push into, both columns being the same
        height by definition of a grid row. */
    margin-top: 4px;
    /*  ⚠ the same box height as the button, so the two are centred alike
        whatever `.h34` is set to. */
    min-height: 34px;
}

    /*  ⚠ `.fl-hint` is `display: block` with a nowrap ellipsis; as a flex item
        it must be allowed to shrink rather than push the dot off the cell. */
    .acc-tynote > .fl-hint {
        flex: 0 1 auto;
        min-width: 0;
    }

/*  ══════════════════════════════════════════════════════════════════════════
    v31.86 (batch281, owner) - THE REPORTS MODULE
    Owner: *"The new Module I would like to Start is Reports ... located in new
    folder /Pages/Reports/ and associated _files in /Pages/Shared/Reports/"*,
    from the mock-up the owner locked on 2026-08-27.

    ⚠ APPENDED AT THE FOOT OF app.css ON PURPOSE - the cheap answer to the
    ordering trap this file has paid for twice. Nothing below can beat these
    by source order alone.
    ⚠⚠ EVERY CHILD NAME IS SCOPED UNDER A `.rpt-` PARENT. `.nm`, `.cd`, `.ic`,
    `.lb`, `.v`, `.bar` and `.due` are exactly the short generic names the
    house rule warns about; scoped, they cannot be claimed by anything else and
    cannot claim anything else.
    ⚠ THE BREAKPOINT RULES ARE IN responsive.css, where every breakpoint in
    this solution lives.

    ⚠⚠⚠ THE FONT-FLOOR GATE MOVES BY +18 IN THIS BATCH, AND IT IS SAID OUT LOUD
    RATHER THAN LET THROUGH. The standing rule is *"type sizes page by page,
    never app-wide"* and its second half - **do not ADD one either** - is a
    COUNT: declarations at or below 13px, base against batch, equal means none
    introduced. This block and the AI Tokens block below add eighteen.
      · They are all on TWO BRAND-NEW SURFACES, and both were reviewed as
        rendered mock-ups and LOCKED by the owner - which is precisely the
        page-by-page review the rule asks for, done before the code rather
        than after it.
      · **NOT ONE SIZE IS INVENTED.** 11px + .06em uppercase is
        `.nvcal .nvc-dow`; 12.5px is `.sim-grp`; 12px is the account More
        sheet's count. Each takes the size the app already uses for that role.
      · Nothing OUTSIDE these two blocks moves - the 226 declarations the rule
        is protecting are untouched.
    ⚠ IF THE OWNER'S FOUR-STEP LADDER LANDS ON A DIFFERENT SET, this block is
    where these change, and they change together.
    ══════════════════════════════════════════════════════════════════════════ */

/*  ⚠⚠⚠ THE GRID IS THREE EQUAL TRACKS OR ONE, NEVER THE THREE RAW `1fr` TRACKS
    `.fin-grid3` GIVES IT. Two things measured wrong with the inherited rule:
      · `1fr` is `minmax(auto, 1fr)`, so a track cannot shrink below its
        content's min-content width. MEASURED at 768: Category 267px beside
        Recurrent 222px - three "equal" columns that were not equal, because
        the list card spans two of them and pushed its own pair wider.
      · The placement rules (the span-2 list, the row-spanning Category) only
        exist from 1024 up, so between 768 and 1023 a span-2 card sat in a
        three-track grid with nothing arranging it.
    So: `minmax(0, 1fr)` from 1024, where the placement rules are, and ONE
    column below it. The four cards stack in DOM order on a tablet and a phone,
    which is the same thing the locked mock-up does at those widths.
    ⚠ `.fin-grid3` STAYS ON THE ELEMENT for its `gap` and as the family marker;
    this only overrides the template, and it sits below `.fin-grid3` in the
    file so it wins on order - the ordering trap this file has paid for twice. */
.rpt-grid {
    grid-template-columns: minmax(0, 1fr);
}

/*  ⚠⚠⚠ THE TRACKS, AND THE NUMBERS ARE MEASURED AGAINST THE DELIVERED PAGE,
    NOT CHOSEN. v31.101 moved the parameter card out of the 390px right rail
    and into this grid, so a third track had to come from somewhere.

    ⚠⚠ THE CONTROL SAID 300px. Measured on the layout that was on the owner's
    disk, the Category card is **301px at 1024 and 321px at 1440**, and at
    those widths nothing clips. A first attempt gave it 200-283px and
    "Financial Statements" and "Creditors & Purchases" both clipped at 1024,
    1366 and 1440 - **a regression the empty-card version of the probe could
    not see, because an empty card has no label to clip.**

    ⚠⚠⚠ v31.102 (batch297) TOOK THE THIRD TRACK BACK OUT. The parameter card
    returned to the 390px right rail, so this grid is **Category | the content
    column** and nothing else - two tracks at every width from 1024 up. The
    300px floor STAYS, because the measurement behind it was about the category
    LABELS and they have not changed.
    ⚠ Neither track is FIXED: a fixed track beside an `fr` track means the `fr`
    absorbs every pixel the window gains (the `.tok-row` fault).
    ⚠ AND THE INNER SPLIT - list over report over the Recent/Recurrent pair -
    is `.rpt-main`'s own grid, below. Two nested grids, each with one job.
    ⚠⚠ AND THE PLACEMENT IS HERE WITH THE TRACKS, not in responsive.css. Two
    numbers that have to agree - which track a card sits in, and how wide that
    track is - are one fact, and this project's most expensive recurring lesson
    is that **a fact kept in step in two files goes out of step.**
    responsive.css keeps the SHELL (`.app-main`), which is a different grid. */
/*  ⚠⚠⚠ THE FLOOR IS 280 AT 1024 AND 300 FROM 1366, AND BOTH NUMBERS ARE THE
    CONTROL'S. Measured on the DELIVERED page with the app's own side rail in
    the harness, the Category card is 280px at 1024 and 300px at 1366+. A flat
    300 floor at 1024 took 20px straight out of the report list on the narrowest
    band that still has two columns - and that band has the least to spare. */
@media (min-width: 1024px) {
    .rpt-grid {
        grid-template-columns: minmax(280px, .8fr) minmax(0, 2.2fr);
    }

        .rpt-cat {
            grid-column: 1;
        }

        .rpt-main {
            grid-column: 2;
        }
}

/*  ══ THE STICKY CATEGORY CARD - v31.102 (batch297, owner) ══════════════════
    Owner: *"together with the category card a sticky left."*

    ⚠⚠⚠ 82px, AND IT IS NOT A GUESS. The scrolling ancestor here is THE
    VIEWPORT - every box between this card and the document is `overflow:
    visible`, `.scroll` included, despite the name. `.screen-head` is already
    `position: sticky; top: 0` and measures **68px** at every width from 390 to
    1920 with the entity chip on it, which `.acc-head-sticky` measured and
    wrote down first. 68 + the 14px `.scroll` gutter = 82, so the card comes to
    rest exactly one page-gap below the header instead of jammed against it.
    ⚠ ONE NUMBER TO CHANGE if the header ever grows, and it is behind a
    variable for that reason.

    ⚠⚠ IT NEEDS THE GRID AREA TO BE TALLER THAN THE CARD, WHICH IS WHY THE
    WRAPPER MATTERS. A sticky box travels inside its containing block, and for
    a grid item that block is its GRID AREA. `.rpt-main` makes the single row
    as tall as the whole content column, so the area is tall and the card has
    somewhere to travel. In v31.101's flat grid the Category card shared a row
    with only the list, so it would have had almost no travel at all.
    ⚠ `align-items: start` on `.rpt-grid` (inline, on the element) is what
    keeps the CARD at its own height inside that tall area. Stretching it would
    leave zero travel and read as the rule being ignored.

    ⚠⚠ SCOPED TO 1024 UP, WHERE THERE IS A LEFT COLUMN TO BE STICKY IN. Below
    that the grid is one column and a sticky category card would pin itself
    over the list a reader is trying to scroll - the opposite of the ask. */
@media (min-width: 1366px) {
    .rpt-grid {
        grid-template-columns: minmax(300px, .8fr) minmax(0, 2.2fr);
    }
}

@media (min-width: 1024px) {
    .rpt-cat {
        position: sticky;
        top: var(--rpt-cattop, 82px);
    }
}


/*  ── the category card ─────────────────────────────────────────────────── */
.rpt-cats {
    display: flex;
    flex-direction: column;
    /*  ⚠⚠ BOTH AXES NAMED. `overflow-y: auto` alone silently makes a sideways
        scroller too - the v31.31 bank-card lesson. */
    overflow-y: auto;
    overflow-x: hidden;
}

    /*  the leading number is v1's ModID and it is the same gold the account
        More sheet gives its own leading code. ⚠ `b` carries an app-wide
        `font-weight: 400 !important`, so weight is not set here. */
    .rpt-cats .t-leaf b {
        color: var(--nv-gold);
        flex: 0 0 auto;
        min-width: 22px;
    }

    .rpt-cats .t-leaf .rpt-ct {
        flex: 0 0 auto;
        margin-left: auto;
        color: var(--nv-ink-3);
        font-size: 12px;
    }

/*  ── the list: one grid for the head row and every data row, so the columns
       cannot drift apart. ⚠ `minmax(0, 1fr)` on the NAME track is what fires
       the ellipsis - `min-width: 0` alone does not. ────────────────────────── */
/*  ⚠⚠⚠ TWO TRACKS SINCE v31.107 (batch302, owner): *"Column 1 with report
    itemID and the report Code column are not useful for users and therefore not
    necessary to display."* It was `46px 78px minmax(0,1fr) auto`.

    ⚠⚠⚠ AND THE CODE COLUMN CAME BACK ONE ROUND LATER, FOR ONE CATEGORY
    (v31.108, batch303, owner): *"Bring back the report code column only in
    Financial statements, make the column items equal width."*
    **THE ITEM ID DID NOT COME BACK** - only the code, and only under
    `.rpt-list.with-code`, which the page sets on category 15 alone. The
    default above stays the two-track shape for the other six categories.
    ⚠ THE 124px THOSE TWO GAVE UP GO TO THE NAME, which is the track that was
    ellipsising report names at 1024-1440 - a clip the v31.102 control proved
    was delivered behaviour rather than a regression. **The fix arrived as a
    side effect of a different instruction, which is worth noticing rather than
    claiming.**
    ⚠⚠ A PROBE ROW MUST NOW HAVE **TWO** CHILDREN. The old four-track shape
    already cost a round once: a harness row with three children put every
    report name in the 78px track and reported a clip that was not there. */
.rpt-head,
.rpt-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 5px 6px;
}

.rpt-head {
    color: var(--nv-ink-3);
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    border-bottom: 1px solid rgba(104,152,232,.16);
    padding-bottom: 6px;
    margin-bottom: 2px;
}

.rpt-row {
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    line-height: 18px;
}

    .rpt-row:hover {
        background: rgba(232,167,92,.06);
    }

    .rpt-row.on {
        background: rgba(232,167,92,.14);
    }

    /*  ⚠⚠⚠ `.c-id` AND `.c-cd` WERE HERE AND ARE GONE (v31.107). The code
        column was added on the owner's own word - *"Include also Report code
        column in grid view."* - and removed on his own word two months later.
        **This note is the whole reason the rules were deleted rather than left
        dead:** the next reader who finds the first instruction and no record of
        the second puts the column straight back.
        ⚠ `.rpt-tbl .c-cd` further down is a DIFFERENT column - the account code
        inside a rendered report - and is untouched. A class name is not a
        selector; the ancestor is half of it. */

    .rpt-row > .c-nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

/*  ══ THE CODE COLUMN, FINANCIAL STATEMENTS ONLY - v31.108 (batch303) ═══════
    Owner: *"Bring back the report code column only in Financial statements,
    make the column items equal width."*

    ⚠⚠ "EQUAL WIDTH" IS READ AS A STATED TRACK, NOT A SHRINK-TO-FIT ONE, which
    is the only way every code cell can be the same width as every other. 78px
    is the width the column carried before v31.107 removed it, so the reader
    who asked for it back gets back the column he had.

    ⚠ THE CATEGORY IS NAMED BY A CLASS ON THE CARD, NOT BY `nth-child` OR BY A
    number in the stylesheet. `.with-code` is set by the page from the same
    constant the category list is built from; a `15` written here would be the
    second place that decides what Financial Statements is.
    ⚠ It is a DESCENDANT selector on purpose. `.rpt-row` sits inside
    `.rpt-body` inside the card, and a child combinator here would break the
    moment anything is wrapped - which is exactly how `:has(> .rpt-ph)` broke
    in v31.102. */
.rpt-list.with-code .rpt-head,
.rpt-list.with-code .rpt-row {
    grid-template-columns: 78px minmax(0, 1fr) auto;
}

    /*  ⚠ GOLD, because it is the handle a filer quotes - the same reason it
        was gold before. Tabular figures so the codes line up as characters as
        well as cells. */
    .rpt-list.with-code .c-cd {
        color: var(--nv-gold);
        font-variant-numeric: tabular-nums;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .rpt-row > .c-st {
        justify-self: end;
    }

/*  the render tag. ⚠ NOT `.pill` - that class already exists and carries a
    3px left border and its own background, which would have shipped looking
    broken. A prefix is not protection; a grep is. */
.rpt-tag {
    display: inline-block;
    border: 1px solid rgba(104,152,232,.45);
    border-radius: 999px;
    padding: 1px 9px;
    font-size: 11px;
    line-height: 16px;
    color: var(--nv-ink-2);
    white-space: nowrap;
}

    /*  green: the report is a stored query and v2 renders it as it stands. */
    .rpt-tag.native {
        border-color: rgba(92,186,140,.5);
        color: var(--nv-good);
    }

    /*  gold: the layout is compiled into `Novera.Reports` (.NET Framework) and
        has to be rebuilt as a v2 page. */
    .rpt-tag.rebuild {
        border-color: rgba(232,167,92,.5);
        color: var(--nv-gold);
    }

/*  ⚠⚠⚠ THE MIN-HEIGHT IS THE OWNER'S HEIGHT RULE, MEASURED.
    Owner: *"Financial statements tab height should equal profit & loss tab, at
    a minimum, but cannot be higher when it has more items because a pager is
    introduced with 5 items per page and the information on the LAST page
    only."*
    Five rows plus the legend do not fill the parameter card beside them, and a
    last page holding four rows is shorter still - so the ROW AREA is floored
    instead of the card, which keeps the height identical on all three pages.
    ⚠ MEASURED at 1440: both cards 391px, on page 1, page 2 and page 3. */
.rpt-body {
    min-height: 205px;
}

    /*  ⚠⚠⚠ AND IT COMES DOWN BY EXACTLY THE HEIGHT OF THE PLACEHOLDER LINE
        WHILE THAT LINE IS THERE. MEASURED: with the banner the card ran 431
        against the parameter card's 391 - 40px too tall, which is the one
        thing the owner's rule forbids (*"cannot be higher"*). `.rpt-ph` is
        40px including its margin, so the row area gives that 40 back.
        ⚠ `:has()` rather than a second class on the body, so this rule DELETES
        ITSELF the day the placeholder banner goes: nothing has to remember to
        put the 205 back. `.app-main:has(> .ai-side)` is the same idiom, already
        in this file.

        ⚠⚠⚠ v31.102 (batch297): THE SELECTOR NO LONGER NAMES THE CARD BY WHERE
        IT SITS. It was `.rpt-grid > .card:has(> .rpt-ph)`, and the list card
        stopped being a direct child of `.rpt-grid` the moment it was wrapped in
        `.rpt-main` - so the rule matched nothing, the body kept its 205px and
        the card ran 40px tall again, which is the one thing the owner's ruling
        forbids. **A DESCENDANT SELECTOR IS A LAYOUT ASSUMPTION IN DISGUISE**,
        and it fails silently: no build error, no gate, just a card that grew.
        Naming the card by CLASS makes it independent of any future nesting -
        the same reason nothing on this page is placed by `nth-child`. */
    .rpt-list:has(> .rpt-ph) .rpt-body {
        min-height: 165px;
    }

/*  the pager. ⚠ `margin-top: auto` is what pins it to the foot of a card that
    is taller than its content - the card is a flex column for exactly this. */
.rpt-foot {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: auto;
    padding-top: 8px;
    border-top: 1px solid rgba(104,152,232,.16);
}

    .rpt-foot > .rpt-pg {
        width: 26px;
        height: 26px;
        font-size: 15px;
        line-height: 1;
    }

        .rpt-foot > .rpt-pg[disabled] {
            opacity: .35;
            cursor: default;
        }

    .rpt-foot > .rpt-count {
        color: var(--nv-ink-3);
        font-size: 12.5px;
        font-variant-numeric: tabular-nums;
    }

    .rpt-foot > .rpt-of {
        margin-left: auto;
        color: var(--nv-ink-3);
        font-size: 12.5px;
    }

/*  the legend, which renders on the LAST page only (the owner's rule) */
.rpt-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 8px;
    padding: 6px;
}

    .rpt-legend > .rpt-lg {
        color: var(--nv-ink-3);
        font-size: 12px;
        margin-right: 6px;
    }

/*  ⚠⚠⚠ RECENT AND RECURRENT ARE EQUAL HEIGHT AT EVERY WIDTH, NOT ONLY ON THE
    DESKTOP GRID. Owner: *"Recent and Recurrent reports must be the same
    height."* MEASURED at 768 they were 239 and 221, and at 390 they were 239
    and 269 - the placement rules that carried `align-self: stretch` sit inside
    a 1024 media query, so below it each card took its own content height.
    The rule that makes them agree belongs OUTSIDE the breakpoint, because the
    requirement does. */
/*  ⚠⚠⚠ v31.101 (batch296): BY CLASS, NEVER BY POSITION. The rendered report
    card renders only when a report has been run, and a sometimes-card inside a
    grid addressed by `nth-child` silently re-numbers every card after it.
    Recent and Recurrent were children 3 and 4 until the report joined the
    grid; now they are what they are called. */
.rpt-recent,
.rpt-recur {
    align-self: stretch;
}

/*  ══ RECENT OVER RECURRENT - v31.107 (batch302, owner) ════════════════════
    *"The Recent Card and the Recurrent report cards should be stacked in the
    same column in 2 rows and overall height of all items in this row should be
    the same."*

    ⚠⚠⚠ THE WRAPPER IS WHAT MAKES THE HEIGHTS AGREE, AND NO RULE STATES THEM.
    Two cards that must sit one above the other in one column ARE one grid
    item; once they are wrapped, `.rpt-stack` and `.rpt-ai` are two items on one
    row and the grid's own `align-self: stretch` levels them. **A height that is
    a consequence cannot go out of date; a height that is a number can.**

    ⚠⚠ `1fr 1fr` SPLITS THE STACK EVENLY, so the two cards match each other as
    well as matching the card beside them. If the AI card is the taller of the
    two items, the stack stretches and both its cards grow by half of the
    difference - which is why neither card carries a `min-height`. */
.rpt-stack {
    display: grid;
    grid-template-rows: 1fr 1fr;
    gap: 14px;
    min-width: 0;
    align-self: stretch;
}

/*  ══ THE CONTENT COLUMN'S OWN GRID - v31.102 (batch297, owner) ═════════════
    Owner, on the annotated 1920 screenshot: *"the blue box shows the space to
    be occupied by the Trial balance report, so the read report shifts down."*

        row 1   ── Financial Statements ──        Report parameters
        row 2   ──── the rendered report, spanning all three ────
        row 3   Recent          Recurrent         Read this report

    ⚠⚠⚠ THE PARAMETER AND AI CARDS ARE MEMBERS OF THIS GRID, NOT RAIL CARDS,
    AND THAT IS THE WHOLE REASON. **Nothing can span two columns of two
    different grids** - while they sat in a separate `.ai-side` shell column,
    the report could only ever reach the width of the list. Putting them here
    is what lets the report run underneath them, which is the space the owner
    boxed.

    ⚠⚠ AND THE CATEGORY CARD IS STILL OUTSIDE IT, which is the difference from
    v31.101. There the parameter card joined ONE flat grid with Category in it,
    so Recent fell into column 1 underneath Category. Here Category is a column
    of the OUTER grid and every one of these six cards is placed in the inner
    one - so the report spans the content, and never the sticky column.
    **That is what "should not cover the full width" and "the blue box" mean
    together: everything except Category.**

    ⚠⚠ NO `grid-row` IS NAMED. The report is a sometimes-card; auto-placement
    in DOM order puts it on its own row when it exists and closes the gap when
    it does not. An explicit row on the bottom three would leave an empty band
    and its gap on every page load where nothing has been run. */
.rpt-main {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
    align-content: start;
    min-width: 0;
}

/*  ── 1024-1365 · TWO COLUMNS ─────────────────────────────────────────────
    ⚠ THREE TRACKS DO NOT FIT HERE. The app's own side rail plus the Category
    column leave `.rpt-main` about 450px at 1024; split three ways that is
    150px a card. The parameter card and the AI card span instead, exactly as
    they did at this band in v31.101. */
@media (min-width: 1024px) {
    .rpt-main {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

        /*  ⚠ THE LIST CARD IS A FLEX COLUMN so `.rpt-foot`'s `margin-top: auto`
            has something to push against - that is what pins the pager to the
            foot of a card taller than five rows. */
        .rpt-main > .rpt-list {
            grid-column: 1 / -1;
            display: flex;
            flex-direction: column;
        }

        .rpt-main > .rpt-params,
        .rpt-main > .rpt-out,
        .rpt-main > .rpt-ai {
            grid-column: 1 / -1;
        }

        /*  ⚠ AT THIS BAND THE STACK TAKES THE FULL WIDTH and the AI card
            keeps its own row below it, exactly as it did before. `.rpt-main` is
            about 450px here once the app rail and the Category column have had
            theirs; halving that for a stack of three-column cards would clip
            both of them to make room for a card that already fits. */
        .rpt-main > .rpt-stack {
            grid-column: 1 / -1;
        }
}

/*  ── 1366 AND UP · THREE COLUMNS, THE OWNER'S SHAPE ──────────────────────
    ⚠ THE THIRD TRACK CARRIES THE PARAMETER CARD AND THEN THE AI CARD, and it
    is the one with a floor: four date selects in two pairs need about 280px
    before the month and year boxes start clipping their own labels. The two
    left tracks are free `fr` so they take whatever is left and stay equal -
    Recent and Recurrent must match, and they carry the same three columns. */
@media (min-width: 1366px) {
    .rpt-main {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(280px, 1.15fr);
    }

        .rpt-main > .rpt-list {
            grid-column: 1 / 3;
        }

        .rpt-main > .rpt-params {
            grid-column: 3;
        }

        /*  ⚠⚠⚠ `1 / -1` HERE IS THE CONTENT GRID, NOT THE PAGE - the owner's
            blue box exactly: the report spans the list AND the parameter card,
            and stops at the Category column. */
        .rpt-main > .rpt-out {
            grid-column: 1 / -1;
        }

        /*  ⚠⚠ THE BOTTOM BAND IS TWO ITEMS NOW, NOT THREE: the stack across
            the two free tracks and the AI card in the third, on ONE row, so
            they level each other. */
        .rpt-main > .rpt-stack {
            grid-column: 1 / 3;
        }

        .rpt-main > .rpt-ai {
            grid-column: 3;
        }
}

/*  ⚠ THE TWO WRAPPED CARDS. `_RptParams` and `_RptAi` are included inside a
    wrapper div so they can be placed by class; their own `.card` root carries
    a max-width the other four override inline, so it is told to fill the cell
    here instead. */
/*  ⚠⚠⚠ `height: 100%` ON THE AI CARD IS WHAT THE OWNER ACTUALLY ASKED FOR
    (v31.107). The WRAPPER already stretched - the grid does that by itself -
    but the card INSIDE it kept its content height, so the measurement said the
    two items matched at 212px while the screenshot showed a 110px card beside a
    205px stack. **The probe was measuring the box, the reader sees the card.**
    ⚠ It is on `.rpt-ai` alone. `.rpt-params` shares this rule block but sits on
    the FIRST row beside the list, where stretching it would pull the Run button
    away from the fields it belongs to. */
.rpt-ai > .card {
    height: 100%;
}

.rpt-params > .card,
.rpt-ai > .card {
    max-width: none;
    width: 100%;
}

/*  ── Recent · Recurrent: three columns, no code, no tag ─────────────────── */
/*  ⚠⚠⚠ FIXED TRACKS, NOT `auto auto` (v31.108, batch303, owner: *"in Recent,
    make Entity column aligned in the column"* and *"Align 'Every' column in
    Recurrent options"*).

    **EVERY ROW HERE IS ITS OWN GRID.** The head is a sibling of the rows, not
    their container, so an `auto` track is sized by ONE row's content and the
    next row sizes its own - which is why "70853" and "84071" did not line up
    with each other or with the heading above them. `auto` aligns nothing
    across separate grids; only a stated width does.

    ⚠ 76px carries "year end", the longest value the Every column holds; 84px
    carries "today 08:14", the longest the date column holds. Both cells
    ellipsise rather than push the name track, so a longer value shortens
    itself instead of breaking the alignment this rule exists to create.
    ⚠⚠ THE REPORT LIST ABOVE SOLVED THIS THE SAME WAY AND SAYS SO: *"one grid
    for the head row and every data row, so the columns cannot drift apart"*.
    It has stated widths; this one had `auto` and drifted. */
.rpt-runhead,
.rpt-runrow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 76px 84px;
    align-items: center;
    gap: 10px;
    padding: 5px 6px;
}

.rpt-runhead {
    color: var(--nv-ink-3);
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    border-bottom: 1px solid rgba(104,152,232,.16);
    padding-bottom: 6px;
    margin-bottom: 2px;
}

.rpt-runrow {
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    line-height: 18px;
}

    .rpt-runrow:hover {
        background: rgba(232,167,92,.06);
    }

    .rpt-runrow > .c-nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    .rpt-runhead > .c-en,
    .rpt-runrow > .c-en {
        color: var(--nv-ink-3);
        font-size: 12.5px;
        /*  ⚠ THE GUARD THAT KEEPS THE TRACK HONEST. A value longer than the
            track ellipsises inside it; without this it would widen the cell
            and the column would go crooked again for that one row. */
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .rpt-runhead > .c-dt,
    .rpt-runrow > .c-dt {
        color: var(--nv-ink-3);
        font-size: 12.5px;
        justify-self: end;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

        /*  ⚠ GOLD FOR DUE SOON, never red: a report that is due is not an
            error, it is a thing to do. Same distinction `.acc-grp-warn`
            makes. */
        .rpt-runrow > .c-dt > .rpt-due.hot {
            color: var(--nv-gold);
        }

/*  ── the parameter card's two-across pairs ──────────────────────────────
    ⚠ THIS IS NOT `.fin-grid3` AND NOT `.acc-fields`. `.fin-grid3` is three
    fixed fractions of the VIEWPORT down to 768px, which says nothing about
    the width of the 390px card these fields are actually drawn in;
    `.acc-fields` belongs to the account card. Two equal columns, no
    breakpoint, nothing that changes as the window moves. */
.rpt-p2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

/*  ══════════════════════════════════════════════════════════════════════════
    v31.290 (owner) — THE SUB-PARAMETER ZONE ON THE REPORT PARAMETERS CARD.

    Owner: *"When the report is selected, the sub-parameters are shown below the
    main date parameters."*

    ⚠⚠ IT BLEEDS TO THE CARD'S EDGES (`margin-inline: -<card padding>`) so the
    rules run the full width and the zone reads as a BAND rather than as another
    field with a box round it. The card pays `--sp-5`; the negative margin and
    the padding restore each other exactly, so nothing inside shifts.

    ⚠ THE GOLD SPINE ON THE LEFT IS THE ONLY COLOUR. The zone is structure, not
    a warning — gold in this system means "attend to this", so it gets the
    2px edge and a 4.5% wash, nothing louder.
    ══════════════════════════════════════════════════════════════════════════ */
.rpt-subzone {
    position: relative;
    margin: 12px calc(var(--sp-5, 20px) * -1) 12px;
    padding: 12px var(--sp-5, 20px) 2px;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    background: rgba(232, 167, 92, .045);
}

    .rpt-subzone::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 2px;
        background: var(--nv-gold-dim);
    }

    /*  ⚠ A REPORT WITH NO OPTIONS STILL RENDERS THE ZONE (see the partial's own
        note: Run must not move when the reader tries another report), so the
        empty state drops the wash and the spine goes quiet rather than gold —
        it is saying "nothing here", not "look here". */
    .rpt-subzone.empty {
        background: none;
    }

        .rpt-subzone.empty::before {
            background: var(--line);
        }

.rpt-zt {
    font-size: 11.5px;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--nv-gold);
    margin-bottom: 10px;
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
}

    /*  the report's own name, so the zone says WHOSE options these are */
    .rpt-zt .for {
        color: var(--nv-ink-3);
        letter-spacing: .02em;
        text-transform: none;
        font-size: 12px;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

.rpt-zempty {
    font-size: 13px;
    color: var(--nv-ink-3);
    line-height: 1.5;
    padding-bottom: 10px;
}

/*  ── the KV section multi-select ──────────────────────────────────────────
    ⚠⚠⚠ NOT A `<select multiple>`. The house rule, already written down: *"the
    native select popup is not ours to style — the real answer for any dropdown
    whose list matters is the app's OWN picker."* A native multiple is also the
    control nobody can operate: ctrl-click to add, and one stray click clears
    the lot.
    ⚠⚠ THE CHECKBOXES ARE REAL INPUTS IN THE FORM. The panel is a DISCLOSURE,
    not a control — with script off the list stands open and the GET still
    carries `sec=1&sec=2`. */
.rpt-ms {
    position: relative;
}

    /*  ⚠ `.input` GIVES IT THE FIELD'S FACE; these three lines give it a
        BUTTON's behaviour. Without `text-align: left` the label centres, which
        no other field on the card does. */
    .rpt-ms .rpt-msbtn {
        width: 100%;
        text-align: left;
        cursor: pointer;
        font-family: inherit;
        gap: 8px;
    }

        .rpt-ms .rpt-msbtn .t {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .rpt-ms .rpt-msbtn .chev {
            margin-left: auto;
            flex: 0 0 auto;
            color: var(--nv-ink-3);
        }

        .rpt-ms .rpt-msbtn[aria-expanded="true"] .chev {
            transform: rotate(180deg);
        }

.rpt-mspanel {
    margin-top: 8px;
    border: 1px solid var(--line);
    border-radius: var(--r-input, 6px);
    background: rgba(3, 6, 14, .55);
    overflow: hidden;
}

    /*  ⚠⚠ HIDDEN WITH `[hidden]`, WHICH THE SCRIPT SETS — never `display: none`
        in this rule. With no script the attribute is never applied and the list
        renders open, which is the working fallback rather than a dead control.
        The page's own `[hidden]` handling does the rest. */
    .rpt-mspanel[hidden] {
        display: none;
    }

.rpt-msall {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 11px;
    font-size: 13.5px;
    color: var(--nv-ink-2);
    border-bottom: 1px solid var(--line);
    cursor: pointer;
}

/*  ⚠ 240px IS FOUR AND A HALF ROWS ON PURPOSE. A list that ends flush with the
    panel looks complete; one cut mid-row says "there is more" without a
    sentence saying so. */
.rpt-mslist {
    max-height: 240px;
    overflow-y: auto;
}

.rpt-msrow {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 11px;
    font-size: 14px;
    color: var(--nv-ink-2);
    cursor: pointer;
    min-width: 0;
}

    .rpt-msrow + .rpt-msrow {
        border-top: 1px solid rgba(104, 152, 232, .08);
    }

    /*  the code is the thing a reader matches against a filing, so it is the
        one part that never ellipsises */
    .rpt-msrow .code {
        flex: 0 0 26px;
        font-family: Consolas, ui-monospace, monospace;
        font-size: 12.5px;
        color: var(--nv-gold);
    }

    .rpt-msrow .nm {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/*  ── the AI card's observation rows ─────────────────────────────────────── */
.rpt-obs {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr);
    align-items: start;
    gap: 8px;
    padding: 5px 4px;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    line-height: 1.45;
}

    .rpt-obs:hover {
        background: rgba(232,167,92,.06);
    }

    .rpt-obs > .rpt-oi {
        font-size: 11px;
        line-height: 20px;
        color: var(--nv-ink-3);
        text-align: center;
    }

        .rpt-obs > .rpt-oi.hot {
            color: var(--nv-good);
        }

        .rpt-obs > .rpt-oi.warn {
            color: var(--nv-gold);
        }

    .rpt-obs > .rpt-ol {
        font-size: 13.5px;
        min-width: 0;
    }

/*  ⚠⚠⚠ A DISABLED CONTROL MUST NOT LOOK LIKE ITS LIVE NEIGHBOUR - the house
    rule, and the LOOK is what caught this. `Run report` is `disabled` because
    nothing behind the page can run one yet, and it still rendered as the full
    bright primary gradient: a button that says "press me" and cannot.
    ⚠ THERE IS NO APP-WIDE `.btn[disabled]` RULE IN THIS SOLUTION - each page
    scopes its own (`.acc-acts > .btn[disabled]`, `.ctl3 .btn[disabled]`), so
    this is the Reports page's copy of the same `.42` opacity rather than a new
    invention or a change to a shared component.
    ⚠⚠ THE FIELDS ARE DELIBERATELY NOT DIMMED. The house draws a READ-ONLY
    VALUE as a disabled input with exactly the same box as an editable one, and
    breaking that here would make the entity field look broken instead of
    fixed. Only the ACTIONS say they cannot act. */
.rpt-app .btn[disabled] {
    opacity: .42;
    cursor: default;
}

/*  ⚠⚠⚠ THE PLACEHOLDER LINE, AND IT IS DELIBERATELY NOT SUBTLE.
    `schema/diag-reports.sql` v2 has not been run, so the columns of
    `RefReports` are unknown and the rows on this page come from a placeholder
    source. **A screen full of plausible figures with nothing behind it is the
    one thing worse than an empty screen: it gets believed.** */
.rpt-ph {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 10px;
    padding: 6px 10px;
    border-left: 2px solid var(--nv-gold);
    border-radius: 0 6px 6px 0;
    background: rgba(232,167,92,.07);
    color: var(--nv-gold);
    font-size: 12.5px;
    line-height: 1.45;
}

/*  ⚠ AN EMPTY CATEGORY IS A SENTENCE, NOT A BROKEN CARD - and it is the same
    shape a real category with no permitted reports will take once the two
    permission gates are in. */
.rpt-none {
    padding: 14px 6px;
    color: var(--nv-ink-3);
    font-size: 13.5px;
}

/*  ══════════════════════════════════════════════════════════════════════════
    v31.86 (batch281, owner) - THE AI TOKENS CARD ON /home
    Owner: *"make a new card, called AI Tokens, which tracks the tokens ... to
    track EVERY call made to the Ai/APIs so we can track usage and bill
    clients"*, then: *"First card looks very good. Lets put it as a placeholder
    right now and then put the instrumentation in a separate round."*
    ══════════════════════════════════════════════════════════════════════════ */

.tok-hero {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 6px;
}

    .tok-hero > .tok-n {
        font-size: 24px;
        font-weight: 100;
        font-variant-numeric: tabular-nums;
        color: var(--nv-gold-bright);
    }

    .tok-hero > .tok-u {
        font-size: 12.5px;
        color: var(--nv-ink-3);
    }

    .tok-hero > .tok-p {
        margin-left: auto;
        font-size: 12.5px;
        color: var(--nv-ink-3);
    }

.tok-cost {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-top: 2px;
    font-size: 13px;
}

    .tok-cost > .tok-cl {
        color: var(--nv-ink-3);
    }

    .tok-cost > .tok-cv {
        margin-left: auto;
        font-variant-numeric: tabular-nums;
    }

/*  ⚠ THE BAR TRACK IS `minmax(0, 1fr)`, so a long entity name shrinks the
    NAME rather than pushing the figure out of the card. */
.tok-row {
    display: grid;
    /*  ⚠⚠ v31.92: THE BAR SHARES THE SLACK WITH THE NAME. It was a FIXED 64px
        beside a `1fr` name, which was right in a 333px card and wrong the
        moment the card went full width: at 476px per column the name track ate
        every extra pixel and the bar floated off on its own, a hand's width
        from the label it measures. Both tracks flex now, so the bar GROWS with
        the column instead of the gap doing it - and 64px stays its floor, so
        nothing about the narrow card changes.
        > ⚠ **A FIXED TRACK BESIDE A `1fr` TRACK MEANS THE `1fr` TAKES EVERY
        > PIXEL THE CONTAINER GAINS.** Decide which one should grow. */
    grid-template-columns: 52px minmax(0, 1fr) minmax(64px, 1.15fr) auto;
    align-items: center;
    gap: 8px;
    padding: 4px 4px;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
    font-size: 13px;
    line-height: 18px;
}

    /*  ⚠ THE HOVER IS SCOPED TO `a.tok-row`, and that is not tidiness. The
        card is a PLACEHOLDER: its rows are spans because there is nothing to
        open, and a row that lights up under the pointer is a promise the page
        cannot keep. The moment the detail page exists the rows become anchors
        and the hover arrives with them. */
    a.tok-row:hover {
        background: rgba(232,167,92,.06);
    }

    .tok-row > .tok-cd {
        color: var(--nv-gold);
        font-variant-numeric: tabular-nums;
    }

    .tok-row > .tok-nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    .tok-row > .tok-bar {
        height: 6px;
        border-radius: 3px;
        background: rgba(104,152,232,.18);
        overflow: hidden;
    }

        .tok-row > .tok-bar > i {
            display: block;
            height: 100%;
            border-radius: 3px;
            background: linear-gradient(90deg, rgba(232,167,92,.9), rgba(232,167,92,.45));
        }

    .tok-row > .tok-v {
        justify-self: end;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }

    /*  the "n more entities" tail: no code, no bar - it spans the two middle
        tracks so the figure still lines up with the rows above it. */
    .tok-row.tok-rest > .tok-nm {
        grid-column: 1 / 4;
        color: var(--nv-ink-3);
        font-size: 12.5px;
    }

/*  ⚠ 24px CHIPS, NOT THE HOUSE 32. This card is a HALF column from 1024 up
    (`1fr · 0.5fr · 0.5fr`), and two 32px chips with their 13px padding leave
    no room for the figures beneath them. The chip's own `flex: 1 1 0` from
    tokens.css still splits the row equally. */
.tok-chips {
    margin: 2px 0 6px;
}

    .tok-chips > .chip {
        height: 24px;
        padding: 0 10px;
        font-size: 12px;
    }

/*  ══════════════════════════════════════════════════════════════════════════
    v31.88 (batch283, owner - R7.5) - THE ENTITY-SWITCH CONFIRM ROW
    Owner, asked and answered: *"always offer it and confirm first, naming what
    is lost."*
    ══════════════════════════════════════════════════════════════════════════

    ⚠⚠ IT IS A ROW OF THE SHEET, NOT A DIALOG. This app has a written rule
    against modals, earned on the address delete: *"a two-step chip does that
    without a modal dialog, which this app does not use anywhere."* The
    sentence appears under the entity the reader actually chose, and the second
    tap on that same row goes through.
    ⚠ GOLD, NOT RED. Nothing has gone wrong and nothing is broken - the reader
    is being told the cost of a thing they may well still want to do. Same
    distinction `.acc-grp-warn` and `.acc-tywarn` make.
    ⚠ The indent lines it up under the entity NAME rather than under the
    building icon, so it reads as belonging to that row. */
.ent-warn {
    padding: 2px 12px 8px 46px;
    color: var(--nv-gold);
    font-size: 12px;
    line-height: 1.45;
}

    /*  the call to action, on its own line and a shade brighter than the
        warning above it: the sentence explains, this one is what to do next. */
    .ent-warn > .ent-warn-go {
        display: block;
        margin-top: 3px;
        color: var(--nv-gold-bright);
    }

/*  ⚠ AN ARMED ROW MUST LOOK ARMED. Without this the only tell is the sentence
    beneath it, and on a tree of similar rows that is not enough to say WHICH
    one the next tap will fire.

    ⚠⚠⚠ AND IT IS A `box-shadow`, NOT A `background`, BECAUSE AN INLINE STYLE
    CANNOT BE BEATEN BY A SELECTOR. The sheet's entity rows carry
    `style="...background:transparent;..."` in the markup, and an inline
    declaration outranks every author rule however specific - MEASURED: the
    first cut of this rule was `.ent-sheet .fld[data-arm="1"] { background }`
    at (0,3,0) and the armed row rendered exactly like its neighbours.
    > ⚠ **SPECIFICITY DOES NOT REACH AN INLINE STYLE.** The choices are
    > `!important` or a property the inline style does not set. `!important` is
    > not the house answer (the ordering rule), and `box-shadow` is not set
    > inline - so the ring paints and nothing has to be overridden.
    ⚠ THE INSET FILL AND THE EDGE ARE ONE DECLARATION: the spread paints the
    whole box, the 3px bar marks which row it is. Neither costs layout, which
    is the same reason the VAT code cell's hover ring is a shadow. */
.ent-sheet .fld[data-arm="1"] {
    box-shadow: inset 0 0 0 999px rgba(232,167,92,.12),
                inset 3px 0 0 0 var(--nv-gold-bright);
}

/*  ══ v31.90 (batch285, production) - BANK REC: THE FOOTER STAYS AT THE FOOT ══
    Reported live: *"The footer, including the horizontal rule, should behave
    consistently with the Ledger view. It should remain positioned at the
    bottom of the flip card rather than appearing immediately after 'Nothing
    for this month'."*

    ⚠⚠ THE FAULT WAS NEVER THE FOOTER - IT WAS THE EMPTY STATE NOT GROWING.
    The two faces of `.fin-flip` share ONE grid cell (`grid-area: 1/1`), so the
    row is as tall as the TALLER face, and `.fin-flip .flip-face > .card` is
    already `flex: 1` - the short face's CARD does stretch. Its CONTENTS did
    not: with rows, a fixed 400px scroller fills the middle; with none, a 40px
    sentence sat there and the rule + totals + C/FWD rode up right behind it,
    leaving the blank space BELOW them. The card is already
    `display:flex; flex-direction:column` (`.flip .card`), so the whole fix is
    to let the sentence take the room the scroller would have taken.
    > ⚠ **A CARD THAT STRETCHES IS NOT A CARD WHOSE CONTENTS STRETCH.**
    ⚠ `flex: 1 1 auto` AND NOT A FIXED 400px: the height then follows whatever
    the other face actually is - a 3-row month, a 40-row month, or an empty one
    on BOTH sides (where the pair simply stays short, together). A hard-coded
    400 would have re-introduced the mismatch the moment the scroller changed. */
.br-none {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 16px 4px;
}

/*  ══ v31.90 (batch285, production) - THE TRN OPENS THE TRANSACTION ══════════
    The link IS the gold TRN text, so it inherits colour and the reconciled
    row's line-through; only the affordance is added.
    ⚠ A DOTTED UNDERLINE AT REST, SOLID ON HOVER: the row already carries a
    strike-through on reconciled lines, and a solid underline at rest would
    read as a second strike on a 13px line. */
.br-row .trn-a {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted rgba(232,167,92,.55);
}

    .br-row .trn-a:hover,
    .br-row .trn-a:focus-visible {
        border-bottom-color: var(--nv-gold-bright);
        border-bottom-style: solid;
    }

/*  ══════════════════════════════════════════════════════════════════════════
    v31.92 (batch287, owner) - THE AI TOKENS CARD IN THREE COLUMNS
    Owner: *"in AI Tokens in the home page, please add one more column so it
    becomes a 3 column responsive card."*

    ⚠⚠⚠ A CONTAINER QUERY, NOT A MEDIA QUERY, AND IT IS FORCED - NOT A
    PREFERENCE. This card's width does not follow the viewport: it is a
    fraction of a grid column, so ONE 1920px screen gives it ~333px in the
    `.dash-top` row and ~1410px stacked underneath. A `@media (min-width:1366px)
    { three columns }` would put three columns into 333px and one column into
    1410px - **the exact opposite of the truth in both cases.**
    > ⚠⚠ **ASK THE BOX HOW WIDE IT IS, NOT THE WINDOW.** `.acc-wrap` on Account
    > Setup already does this for the same reason; this is the second caller.

    ⚠ THE THRESHOLDS ARE MEASURED, not chosen. One list column needs
    52px code + 8 gap + a readable name + 8 + 64px bar + 8 + the figure -
    about **234px** before the name starts clipping to one letter, which is the
    v31.90 fault this project has already paid for once.
      · under 470px  -> ONE column. The chips return and switch the two lists,
                        which is exactly the v31.86 card.
      · 470-729px    -> TWO columns: the figure joins the entity list.
      · 730px and up -> THREE columns, both axes on screen at once.
    ⚠⚠ `align-items: start` IS LOAD-BEARING on a grid whose rows are all
    `auto` inside a card that stretches to its neighbours (`.dash-top > .card
    { height: 100% }`) - without it the three columns stretch and the bars
    drift apart vertically. Same rule the Reports grid needed at 1366.
    ══════════════════════════════════════════════════════════════════════════ */
.tok-card {
    container-type: inline-size;
    container-name: tokcard;
}

.tok-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 2px 18px;
}

    /*  the column heading: present only when a column is actually a column.
        At one column the chips do this job, so the headings stand down and
        the card reads exactly as it did before v31.92. */
    .tok-ch {
        display: none;
        /*  ⚠ 13px, NOT 12. The font-floor gate is a COUNT and it caught this
            round adding two declarations below it. The card is FULL WIDTH now,
            so the reason a 333px card had for going small no longer exists -
            and "there was room" is the only honest reason to take a size back
            up. Nothing outside these two rules moved. */
        font-size: 13px;
        color: var(--nv-ink-3);
        padding: 0 4px 4px;
    }

/*  ⚠ THE FAILED LINE IS NOT A `.muted` INLINE STYLE ANY MORE - it was
    `font-size:11.5px` written on the element, which no ladder can ever reach.
    12px is the card's own smallest step and it is now a class like everything
    else on the card. */
.tok-failed {
    margin-top: 8px;
    /*  ⚠ THIS LINE USED TO BE AN INLINE `font-size:11.5px` ON THE ELEMENT,
        which no type ladder can ever reach. It is a class at 13px now - the
        floor - so the app is one inline size lighter than before this round,
        not one heavier. */
    font-size: 13px;
    font-weight: 100;
    color: var(--nv-ink-3);
}

@container tokcard (min-width: 470px) {
    .tok-grid {
        /*  the figure column is content-sized and the lists take the rest:
            a headline number must not be squeezed by a list beside it. */
        grid-template-columns: minmax(150px, .8fr) minmax(0, 1fr);
    }

        /*  ⚠ THE CHIPS GO THE MOMENT A SECOND COLUMN EXISTS. They are the
            one-column fallback for the two lists, not a control in their own
            right, and leaving them on beside a visible list would offer to
            switch to a list already on screen. */
        .tok-grid > .tok-chips {
            display: none;
        }

        .tok-grid > .tok-col-call {
            /*  at two columns the call list sits UNDER the entity list, in the
                same track - still both axes, still one scroll. */
            grid-column: 2;
        }

    .tok-ch {
        display: block;
    }
}

@container tokcard (min-width: 730px) {
    .tok-grid {
        grid-template-columns: minmax(150px, .7fr) minmax(0, 1fr) minmax(0, 1fr);
    }

        .tok-grid > .tok-col-call {
            grid-column: 3;
        }
}

/*  ⚠⚠ THE CALL ROW HAS NO CODE CELL. A call type has a name and no number, so
    the row is name · bar · figure and the 52px code track is DROPPED rather
    than rendered empty - an empty first track would indent every name on this
    side and the two lists would stop lining up with each other. */
.tok-col-call > .tok-row {
    grid-template-columns: minmax(0, 1fr) minmax(64px, 1.15fr) auto;
}

/*  ══════════════════════════════════════════════════════════════════════════
    v31.93 (batch288, owner) - THE AI TOKENS COLUMN SEPARATORS
    Owner: *"please style the card by having a 'vertical line separator' which
    does not touch top or bottom border of the card itself."*

    ⚠⚠⚠ A `border-left` CANNOT DO THIS. A border runs the full height of the
    box it is on, so it would reach the card's padding edge at both ends - and
    the ask is precisely that it must NOT. A pseudo-element can be inset from
    both ends; a border cannot be inset from either.
    > ⚠ **"A LINE THAT STOPS SHORT" IS NOT A BORDER, IT IS A DRAWN ELEMENT.**

    ⚠⚠ IT HANGS IN THE GAP, NOT ON THE COLUMN. `left: calc(-.5 * var(--tok-gap))`
    centres it in the 18px grid gap, so the two lists keep equal breathing room
    on each side. Putting it on the column's own left edge would push the text
    of columns 2 and 3 off-centre by half a gap.
    ⚠ AND IT ONLY EXISTS WHERE THERE IS A COLUMN BOUNDARY TO MARK - inside the
    container queries. At one column the "separator" would be a line above a
    stacked block, which is a rule, not a separator, and the card already has
    the chips there.
    ⚠⚠ `position: relative` GOES ON THE COLUMN, NOT THE GRID: an absolute child
    of the GRID would be positioned against the whole card and would need to
    know where the tracks fall. Anchored to its own column it cannot drift.
    ══════════════════════════════════════════════════════════════════════════ */
.tok-grid {
    --tok-gap: 18px;
    /*  the two measured offsets that carry the separator from the column's box
        out to 10px inside the card's border - see the rule below for the
        measurement they come from. */
    /*  ⚠ v31.95 (batch290, owner): *"Increase clearance from the top at 25px
        and bottom 15px."* The lift and drop are what carry the line from the
        COLUMN's box out to a clearance measured against the CARD, so the two
        numbers are derived, not chosen:
            column top    sits 51px below the card's top border  -> 51 - 25 = 26
            column bottom sits 15px above the card's bottom      -> 15 - 15 =  0
        A drop of 0 puts the line's foot exactly ON the grid's bottom edge,
        which is what a 15px clearance from the card's border IS on this card. */
    --tok-lift: 26px;
    --tok-drop: 0px;
}

@container tokcard (min-width: 470px) {
    .tok-grid > .tok-col {
        position: relative;
    }

        /*  ⚠ EVERY COLUMN BUT THE FIRST. `:not(:first-child)` would also catch
            the chips row in the markup order, so the separator is asked for by
            the two LIST columns explicitly - they are the only boundaries. */
        .tok-col-ent::before,
        .tok-col-call::before {
            content: "";
            position: absolute;
            left: calc(-.5 * var(--tok-gap));
            /*  ⚠⚠⚠ v31.93 STOPPED 10px INSIDE THE COLUMN AND THAT WAS TOO
                SHORT. Owner: *"pull these lines to be up near the top of the
                card border ... and the bottom over the bottom of tok-grid."*
                The line hangs off a COLUMN, but the ask is expressed against
                the CARD, so the two have to be converted - MEASURED on the
                delivered card, and identical at 1024, 1440 and 1920:

                    the column's TOP    sits 51px below the card's top border
                                        (14px card padding + the h2 + its 6px)
                    the column's BOTTOM sits 15px above the card's bottom
                                        (14px padding + the 1px border)
                    the grid's bottom   IS the column's bottom

                So a 41px lift and a 5px drop leave the line **10px clear of
                each border** - up near the top as asked, past the grid's
                bottom as asked, and still touching neither.
                > ⚠⚠ **A NUMBER LIKE THIS IS ONLY HONEST IF SOMETHING RE-CHECKS
                > IT.** The probe asserts the rendered line against the card's
                > border, so a change to the heading's type is caught by the
                > gate rather than by the owner. */
            top: calc(-1 * var(--tok-lift));
            bottom: calc(-1 * var(--tok-drop));
            width: 1px;
            /*  ⚠ v31.95 (batch290, owner): the BLUE hairline, not the gold one.
                It is the same colour `.tok-bar`'s own track already uses on
                this card, so the separator reads as structure rather than as
                another gold accent competing with the figures. */
            background: rgba(104, 152, 232, .22);
            pointer-events: none;
        }
}

/*  ⚠⚠⚠ AT TWO COLUMNS THE BOUNDARY NEEDS **TWO SEGMENTS**, NOT ONE.
    The call list sits UNDER the entity list in the same track, so the entity
    column's own box stops less than half way down the card - MEASURED at 768:
    a single segment ended **140px above the card's bottom border**, which is
    the fault this rule fixes and which v31.93 shipped (less visibly, because
    it also stopped 10px short at the top).
    > ⚠⚠ **A LINE THAT MUST SPAN TWO STACKED BOXES CANNOT HANG OFF ONE OF
    > THEM.** Either both draw their own half, or neither reaches.

    ⚠ THE SEAM IS CLOSED BY THE ROW GAP, NOT PAPERED OVER: `.tok-grid`'s row
    gap is 2px, so the upper segment runs 2px past its own bottom and the lower
    one starts at its own top. The two meet exactly, and there is no overlap to
    paint a double-density pixel. */
@container tokcard (min-width: 470px) and (max-width: 729.98px) {
    .tok-col-ent::before {
        bottom: -2px;
    }

    .tok-col-call::before {
        top: 0;
    }
}

/*  ⚠ v31.93 (batch288, owner) - THE FIND SHEET'S SCOPE LINE. It answers one
    question and must not compete with the search box under it, so it reads as
    a caption in the entity's own gold rather than as a heading.
    ⚠⚠ NOT SMALLER THAN THE SHEET'S FLOOR: `.find-sheet` sets
    `font-size: var(--fs-caption)` for everything inside it (the v21.0 owner
    rule - "We have a rule about minimum font size"), and this line inherits it
    rather than setting a size of its own. */
.find-scope {
    margin: 0 0 10px;
    color: var(--nv-gold);
    font-weight: 100;
}

/*  ══ v31.99 (batch294, owner) - THE RENDERED REPORT ═══════════════════════
    Owner: *"Run should render in the page."*

    ⚠⚠ IT WAS A SIBLING OF `.rpt-grid` IN v31.99 AND IS A MEMBER OF `.rpt-main`
    FROM v31.102 (batch297). That was only safe once the grid stopped placing
    cards by `nth-child`: a card that renders ONLY when something has been run
    re-numbers every card after it, so every placement rule names a CLASS.
    ⚠ There is no width rule here: `.rpt-main > .rpt-out { grid-column: 1/-1 }`
    - ABOVE, in this file, with the tracks it spans - is what makes it span the
    list and the parameter card while stopping at the sticky Category column.
    That is the owner's blue box. */
/*  ⚠ NO `margin-top` HERE ANY MORE. It was a sibling of the grid in v31.99
    and needed its own spacing; it is a grid ITEM from v31.101 and the grid's
    own 14px gap is what separates it. Both would have made 28. */
.rpt-out {
    min-width: 0;
}

.rpt-outhead {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

/*  ⚠ WHICH ENTITY, WHICH CURRENCY, WHICH PERIOD - the three an accountant
    checks before believing a figure, and the three v1 puts in its page header.
    13px is the floor, not a choice: this line is read, not decoration. */
.rpt-outmeta {
    font-size: 13px;
    color: var(--nv-ink-3);
    white-space: nowrap;
}

/*  ⚠⚠ THE TABLE SCROLLS INSIDE ITS OWN BOX, NEVER THE PAGE. A report is the
    one surface that legitimately carries more columns than a phone has room
    for, and a page that scrolls sideways loses its own navigation. */
.rpt-outscroll {
    overflow-x: auto;
    margin: 0 -4px;
}

.rpt-tbl {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

    .rpt-tbl th {
        padding: 10px 10px;
        text-align: left;
        font-size: 13px;
        font-weight: 600;
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--nv-ink-3);
        white-space: nowrap;
        border-bottom: 1px solid rgba(104,152,232,.22);
    }

    .rpt-tbl td {
        padding: 7px 10px;
        border-bottom: 1px solid rgba(104,152,232,.07);
    }

    /*  ⚠ FIGURES ARE TABULAR AND RIGHT-ALIGNED, or a column of money cannot be
        scanned down. `font-variant-numeric` is what keeps the digits in step. */
    .rpt-tbl .c-n {
        text-align: right;
        white-space: nowrap;
        font-variant-numeric: tabular-nums;
    }

    .rpt-tbl .c-cd {
        white-space: nowrap;
        color: var(--nv-blue-ink, #9dbcf2);
        font-variant-numeric: tabular-nums;
    }

    .rpt-tbl .c-nm {
        min-width: 0;
    }

/*  the band headings - v1's four UNION groups, named */
.rpt-tbl .rpt-band td {
    padding: 14px 10px 6px;
    font-size: 13px;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
    border-bottom: 0;
}

/*  ⚠⚠⚠ THE OUT-OF-BALANCE BAND IS COLOURED BECAUSE IT IS THE ONE AN
    ACCOUNTANT OPENS THIS REPORT TO FIND. Left looking like another row it
    reads as data; it is a fault. */
.rpt-tbl .rpt-band.warn td,
.rpt-tbl .rpt-line.warn td {
    color: var(--nv-gold-bright);
}

.rpt-tbl tfoot td {
    padding: 12px 10px;
    font-weight: 600;
    font-size: 15px;
    border-top: 1px solid rgba(104,152,232,.30);
    border-bottom: 0;
}

/*  ⚠⚠⚠ THE OWNER'S ACCEPTANCE TEST, WHEN IT FAILS. *"totals must be in
    balance."* If the two columns do not agree the report is wrong, and this
    line is what says so instead of letting a reader add it up themselves. */
.rpt-oob {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 12px;
    padding: 10px 12px;
    border-radius: var(--r-input);
    font-size: 13px;
    color: var(--nv-gold-bright);
    background: rgba(232,167,92,.08);
    border: 1px solid rgba(232,167,92,.30);
}

.rpt-oobn {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
}

/*  a report row that IS a door, and the one currently open */
.rpt-row.live {
    cursor: pointer;
}

    .rpt-row.live:hover {
        background: rgba(104,152,232,.08);
    }

    .rpt-row.on {
        background: rgba(232,167,92,.10);
    }

/*  ══ v31.101 (batch296, owner) - THE APP SAYS IT IS WORKING ═══════════════
    Owner: *"I had to click twice because the UI did not show an indication it
    was processing ... create a standard usage for this for all process when
    user is interacting with system and waiting for results."*

    ⚠⚠⚠ TWO PARTS, AND THEY ANSWER TWO DIFFERENT QUESTIONS.
      `.nv-progress`  - "the page is going somewhere"   (top of the window)
      `.nv-spin`      - "THIS control is what I pressed" (in the button)
    A reader needs both: the bar alone does not say which button took, and the
    spinner alone does not survive the page starting to unload.
    → the door is `/Pages/Shared/Toolkit/_NvBusy.cshtml` */

/*  ⚠ FIXED TO THE VIEWPORT AND ABOVE EVERYTHING, because it has to be visible
    from wherever the reader is looking - including a page scrolled to its
    foot, which is exactly where a Run button tends to be. */
.nv-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    z-index: 9999;
    pointer-events: none;
    opacity: 0;
    transition: opacity .15s ease;
}

    .nv-progress.on {
        opacity: 1;
    }

    /*  ⚠⚠ IT IS AN INDETERMINATE BAR AND IT HAS TO BE. Nothing here knows how
        far a server request has got, and a bar that claims a percentage it
        cannot know is a lie that reads as a freeze the moment it stalls at
        90%. A travelling sliver promises only "something is happening". */
    .nv-progress i {
        display: block;
        height: 100%;
        width: 34%;
        border-radius: 0 2px 2px 0;
        background: linear-gradient(90deg,
                    rgba(232,167,92,0) 0%,
                    var(--nv-gold-bright) 55%,
                    rgba(232,167,92,0) 100%);
        transform: translateX(-40%);
        animation: nv-prog 1.05s ease-in-out infinite;
    }

@keyframes nv-prog {
    0%   { transform: translateX(-40%); }
    100% { transform: translateX(300%); }
}

/*  ⚠ 14px AND `currentColor`, so one rule serves a gold primary button, a
    ghost button and a link without three colour variants to keep in step. */
.nv-spin {
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-left: 8px;
    vertical-align: -2px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    opacity: .85;
    animation: nv-spin .68s linear infinite;
}

@keyframes nv-spin {
    to { transform: rotate(360deg); }
}

/*  ⚠⚠⚠ `pointer-events: none` IS THE WHOLE FIX FOR THE DOUBLE CLICK, and it
    is deliberately NOT `disabled`. A disabled submit button is not sent with
    its form, so a page that reads which button was pressed would silently lose
    that on every submit - and this solution has several. This stops the second
    press without touching what is posted. */
.is-busy {
    pointer-events: none;
    opacity: .78;
}

/*  ⚠⚠ SOMEBODY WHO HAS ASKED FOR LESS MOTION STILL HAS TO BE TOLD THE APP IS
    WORKING. The animation stops; the indicator does not disappear. */
@media (prefers-reduced-motion: reduce) {
    .nv-progress i,
    .nv-spin {
        animation: none;
    }

    .nv-progress i {
        width: 100%;
        transform: none;
    }

    .nv-spin {
        border-right-color: currentColor;
        opacity: .5;
    }
}

/*  ══ SET 1 REPORT TABLES - v31.103 (batch298, owner) ═══════════════════════
    Reports 190, 189, 184 and 183. Owner: *"Deliver report builds in the given
    set, not individually."*

    ⚠⚠⚠ THESE ARE THE ONLY NEW RULES THE SET NEEDS, because every one of the
    four renders inside `.rpt-out` / `.rpt-outscroll` / `.rpt-tbl` - the shell
    the trial balance already proved. What is here is the per-report COLUMN
    behaviour and nothing else.

    ⚠⚠ EVERY TABLE DECLARES A `min-width` AND THE BOX SCROLLS, never the page.
    A report is the one surface that legitimately has more columns than a
    laptop has room for; `.rpt-outscroll` is `overflow-x: auto` and names both
    axes, which is the v31.31 bank-card lesson. MEASURED at 1920: the city-tax
    table is 1327px inside a 962px card and the page does not move sideways. */

/*  ── 190 · the city tax listing, thirteen columns ─────────────────────── */
.ct-tbl {
    min-width: 1180px;
}

    .ct-tbl .c-ad {
        min-width: 150px;
        max-width: 190px;
    }

    .ct-tbl .c-dt,
    .ct-tbl .c-ct {
        white-space: nowrap;
    }

    /*  ⚠ THE COLUMN THE REPORT EXISTS FOR IS MARKED, and it sits LEFT of Room
        rate and Revenue. In v1's order City tax is the column a reader has to
        scroll to reach - on a report whose entire purpose is that figure. */
    .ct-tbl .ct-key {
        color: var(--nv-gold-bright);
    }

    /*  ⚠ A COUNTRY THAT DID NOT RESOLVE IS SHOWN AS AN EM DASH, not a blank.
        v1 printed nothing for the owner's UK guest and the page gave no
        indication anything was missing. */
    .ct-tbl .ct-none {
        color: var(--nv-gold);
    }

/*  ── 189 · the twelve-period pivot, fourteen columns ──────────────────── */
.pl-tbl {
    min-width: 1320px;
}

    .pl-tbl .c-nm {
        min-width: 260px;
    }

    /*  ⚠ THE YEAR TOTAL IS PINNED LEFT OF THE TWELVE PERIODS. It is the figure
        a reader looks for; the periods are the detail behind it, and putting
        the answer past twelve columns of workings gets it scrolled off. */
    .pl-tbl .pl-total {
        border-right: 1px solid rgba(104,152,232,.22);
        padding-right: 12px;
    }

    .pl-tbl .pl-code {
        color: var(--nv-gold);
        margin-right: 8px;
    }

    .pl-tbl .pl-name {
        color: var(--nv-ink-2);
    }

    /*  the property sub-heading inside a revenue or cost block */
    .pl-tbl .pl-prop td {
        color: var(--nv-ink-3);
        padding-top: 10px;
        font-size: 13px;
    }

/*  ── 184 / 183 · the invoice listings ─────────────────────────────────── */
.inv-tbl {
    min-width: 900px;
}

    .inv-tbl .c-ad {
        min-width: 250px;
    }

    /*  ⚠⚠ THE HEADER ROW IS A BLOCK, NOT A LINE. v1's own rendering stacks the
        account, the name, the address and the invoice reference in one cell -
        an invoice listing that put those on one row would need a 2000px table
        and would still be unreadable. */
    .inv-tbl .inv-head td {
        border-top: 1px solid rgba(104,152,232,.22);
        padding-top: 12px;
        vertical-align: top;
    }

    .inv-tbl .inv-acc {
        color: var(--nv-gold);
    }

    .inv-tbl .inv-nm {
        color: var(--nv-ink-1);
    }

    .inv-tbl .inv-addr,
    .inv-tbl .inv-meta {
        color: var(--nv-ink-3);
        font-size: 13px;
    }

    .inv-tbl .inv-lbl {
        color: var(--nv-ink-3);
        margin-right: 6px;
    }

    /*  the tax line reads differently from a goods line - same weight, muted */
    .inv-tbl .inv-tax .c-nm {
        color: var(--nv-ink-3);
    }

    .inv-tbl .inv-ta {
        color: var(--nv-ink-3);
        margin-left: 8px;
    }

    .inv-tbl .inv-doc {
        color: var(--nv-gold);
    }

/*  ── shared by the set: the property band and its subtotal ────────────── */
.rpt-band .ct-pname {
    color: var(--nv-gold);
}

.rpt-band td {
    padding-top: 14px;
}

.rpt-sub td {
    border-top: 1px solid rgba(104,152,232,.22);
    border-bottom: 1px solid rgba(104,152,232,.22);
}


/*  ══ v31.117 (batch313, owner) — THE HISTORY ROW MAKES ROOM FOR ITS TRN ═══
    Owner, on a screenshot of the processing pages' history card: *"please make
    the first row larger so that the TRN and XXXX number is fully visible"*,
    then, on seeing a two-line answer: ***"I would prefer if you only modify
    size, not move content. make icon columns smaller - width 22px. make amount
    field smaller 90px. gap 4px."***

    ⚠⚠⚠ SIZE ONLY. NOTHING MOVES. The reference stays on line one and the
    date · TRN stays on line two, exactly as they are — `.s` keeps v21.1's
    `white-space: nowrap` (that rule came from the owner's own report that the
    line was wrapping and every history row had become two rows tall on
    02/03/04-Screen). The room comes out of the columns beside the text.

    WHERE THE 370px CARD'S WIDTH GOES — measured, before and after:
        text     124  →  182      the line needs 145-184 depending on the TRN
        gaps   3x10   →  3x4
        clip      34  →   22
        the +     28  →   22
        amount   112  →   90

    ⚠ THE SPACER MOVES WITH THE CLIP. `.docclip-gap` stands in for the clip on
    a row with no documents (A-34), so if the two ever disagree the amounts
    below step sideways — which is the whole reason that spacer exists.

    ⚠⚠ SCOPED TO `#histCard` / `#histSlot`, the two ids the history card
    renders under on all three processing surfaces. The TRANSACTION ENQUIRY is
    deliberately untouched: its 112px amount floor and its 34/28 columns are
    measured decisions from batch304 and A-52, on a row that is already
    16px short of its own content at 390px (A-49). Nothing here goes near it. */
#histCard .fin-hrow,
#histSlot .fin-hrow {
    gap: 4px;
}

#histCard .fin-hrow .docclip-btn,
#histSlot .fin-hrow .docclip-btn,
#histCard .fin-hrow .docclip-gap,
#histSlot .fin-hrow .docclip-gap {
    flex: 0 0 22px;
    width: 22px;
}

#histCard .fin-hrow .docadd-btn,
#histSlot .fin-hrow .docadd-btn {
    flex: 0 0 22px;
    width: 22px;
}

/*  ⚠ THIS OVERRIDES v24.7's 112px, WHICH IS WHY IT SITS BELOW IT IN THE FILE.
    Same selector weight, so ORDER is what decides — the trap this project has
    paid for twice. Appending at the foot is the cheap guarantee.

    ⚠⚠⚠ 90px IS A FLOOR, NOT A FIXED WIDTH, AND THAT IS A SAFETY CHANGE I MADE
    ON PURPOSE — say the word and it goes back to fixed.
    `.amt` is `overflow: hidden` and `justify-content: flex-end`, so it clips
    from the LEFT. MEASURED at a fixed 90px: `-124,464.96 C` needs 97px of ink
    and rendered as **`124,464.96 C`** — the column ate the MINUS SIGN and
    nothing else. A truncated word is a cosmetic fault; a figure that loses its
    sign is the number saying something different from what it means, on a
    ledger card.
    So 90px is the MINIMUM. Every ordinary amount (measured: 54-67px) sits at
    exactly 90 and the column stays aligned exactly as v24.7 intended; only a
    six-figure amount grows, and it grows because the alternative is lying. */
#histCard .fin-hrow .amt,
#histSlot .fin-hrow .amt {
    flex: 0 0 auto;
    width: auto;
    min-width: 90px;
}

/*  ══ v31.117b (batch313, owner: *"also do the flip with Allocations"*) ═════
    The same treatment on the ALLOCATIONS face, and the same reason: the row's
    text column was being squeezed by a fixed amount column wider than any
    amount in it.

    ⚠⚠⚠ THE GAP COULD NOT BE DONE HERE IN CSS AT ALL. The allocation rows are
    built in script and set `gap:10px` as an INLINE STYLE
    (`wrap.style.cssText = '…gap:10px…'`), and an inline style beats a
    stylesheet rule without `!important`. So the 4px is changed at its two
    sources — `_ApInvoiceEntry.cshtml` and `_ApPayment.cshtml` — which is a
    SIZE change on the line that already sets the size, and moves nothing.
    (`!important` would have "worked" and left the next reader two numbers
    disagreeing in two places.)

    ⚠ `.fin-scol` KEEPS ITS 96px. On the history card the two narrow columns
    hold single glyphs; this one holds the ✓ pill AND the Clear chip, and 22px
    would take the button with it. Nothing here was asked to shrink it.

    ⚠ 90px IS A FLOOR HERE TOO, for the reason measured on the history card:
    a fixed 90px column clips from the LEFT and eats the minus sign. */
.fin-flip .fin-hrow .amt {
    flex: 0 0 auto;
    width: auto;
    min-width: 90px;
}

/*  ⚠⚠⚠ AND THE LAST COLUMN GIVES THE FIRST ONE ITS 60px — owner: *"For
    allocations make the first column even larger by another 60px"* then
    *"make last column smaller"*.

    96 − 60 = 36, and 36 is what an UNSETTLED row's trailing column actually
    needs: it holds a single tick, measured at 16px of ink.

    ⚠⚠ BUT A SETTLED ROW'S TRAILING COLUMN IS NOT A GLYPH — IT IS A BUTTON.
    MEASURED: the ✓ pill plus the **Clear** chip need **109px**, which is already
    more than the 96 they have. Fixing every row at 36 would not shrink that
    control, it would CUT IT OFF — and Clear is v1's release-the-allocation
    action, not decoration.

    SO THE COLUMN IS CLAMPED, NOT FIXED: it sizes to its own content between a
    36px floor and its existing 96px ceiling.
      · an unsettled row  16px of ink  → 36px   (60px handed to the text)
      · a settled row    109px of ink  → 96px   (exactly what it has today)
    ⚠ NOTHING GETS WORSE. The ceiling is deliberately today's number so a
    settled row cannot lose a single pixel to this change.

    ⚠⚠ THIS SOFTENS v24.7, WHICH IS ALSO YOURS: *"decide what should be the
    column width for each item and make this width fixed for all rows so that
    the items appear to be in same column."* The AMOUNT column still obeys it.
    This one now has two widths — one for rows carrying a button and one for
    rows carrying a tick — because the alternative is a button nobody can
    press. Say the word and it goes back to a single fixed width, at 96px for
    everyone (today) or 36px for everyone (and no Clear). */
/*  ⚠ `flex: 0 0 auto`, NOT `0 1 auto`, AND THE PROBE IS WHY. With shrink
    allowed the settled row's column was squeezed to **56px** by the text
    column beside it — 53px less than its content — which is the Clear button
    cut in half. It must be allowed to size to its content and never below it. */
.fin-flip .fin-hrow .fin-scol {
    flex: 0 0 auto;
    width: auto;
    min-width: 36px;
    max-width: 96px;
}


/*  ══ v31.120 (batch316, owner) — THE ENQUIRY'S FILTER ROW REACHES DATE TO ══
    Owner: *"reduce the gap in the row so that the five btns align with the
    Date To right border."*

    ⚠⚠⚠ IT IS A MEASURE, NOT A GAP, AND THE MEASUREMENT IS WHY. On the 760px
    card the four controls ended at ~392px and Date To's right border sits at
    ~481px — the row fell about 90px SHORT, and a fifth button only reaches
    ~450. Closing that by shrinking a gap is arithmetic that runs the wrong way,
    and the answer would be a different number in each of the five languages
    these chips are translated into.

    So the ROW is given the exact measure instead. `.fin-grid3` above it is
    `1fr 1fr 1fr` with a 12px gap, so two of its columns plus one gap is
    `(100% - 24px) / 3 * 2 + 12px` — Date To's right border expressed in the
    grid's own terms rather than in pixels that go stale the moment the card's
    width or padding changes. `space-between` distributes what is left over.
    **The edge lands by construction, in every language.**

    ⚠ FROM 768 ONLY. Below that `.fin-grid3` collapses to a single column, so
    "two columns plus a gap" is not a thing that exists and the row keeps the
    plain flex behaviour it has always had. */
@media (min-width: 768px) {
    .enq-chip-row {
        width: calc((100% - 24px) / 3 * 2 + 12px);
        max-width: 100%;
        justify-content: space-between;
        gap: 8px;
    }
}

/*  ══ v31.120 (batch316, owner) — THE AI CARD ══════════════════════════════
    Owner: *"introduce AI card at the bottom of the second column … The card
    bottom border should never exceed the middle column bottom card."*

    ⚠ THE CAP ITSELF IS NOT HERE — it is `_NvColCap`, which sets
    `--fin-flip-max` and adds `.is-capped`. These rules are only what the card
    looks like. */
.enq-ai-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/*  ⚠⚠ EACH ITEM IS A `span`, DIMMED AND UNCLICKABLE, AND THAT IS DELIBERATE.
    These three are a PROPOSAL for the AI round, not three controls that work.
    The house rule, paid for in v26.9 and written into `.t-off`: a disabled
    thing must not look like its live neighbour, and a tile goes live only once
    the page answers it. So there is no hover, no cursor and no chevron —
    nothing here invites a click that would do nothing. */
.enq-ai-item {
    display: block;
    opacity: .55;
    pointer-events: none;
    border-left: 2px solid var(--nv-blue-bright);
    padding-left: 10px;
}

.enq-ai-h {
    display: block;
    font-size: 14px;
    color: var(--nv-ink);
}

.enq-ai-s {
    display: block;
    font-size: 12.5px;
    font-weight: 100;
    color: var(--nv-ink-3);
    margin-top: 2px;
}

.enq-ai-soon {
    font-size: 12.5px;
    margin-top: 12px;
    padding-top: 8px;
    border-top: 1px solid rgba(104,152,232,.14);
}

/*  ══ v31.122 (batch318, owner) — THE CAP IS A CEILING. IT WAS ALWAYS A
    CEILING. v31.121 MADE IT A STRETCH, AND THAT WAS MY MISREADING. ══════════

    Owner, v31.121: *"brNotes violates the 'never taller than the middle
    column' cap … it should be the bottom border so change to 'the bottom
    border should be the same as the middle column bottom border'."*
    Owner, v31.122, on seeing v31.121 run: *"bank reconcilation notes card
    should work same as in transaction notes card."*

    ⚠⚠⚠ THE SECOND SENTENCE SETTLES THE FIRST. I read *"the same as"* as an
    instruction to STRETCH a short card down to the middle column, and shipped
    `height: var(--fin-flip-max)`. On the transaction enquiry that looked right
    only by accident — `#enqAi`'s content OVERFLOWS its room, so a height and a
    ceiling render identically there. On the bank rec `#brNotes` holds four
    lines of text against a very long middle column, so the same rule inflated
    it to **1273px of mostly empty card**. The owner's reference is the enquiry
    card, and the enquiry card is CAPPED, not stretched.

    ⚠⚠ SO THE FIRST SENTENCE WAS ASKING FOR THE NAME, NOT A STRETCH: call the
    rule by the border it acts on rather than by "height". The rule is **the
    card's bottom border never goes past the middle column's**; a card with
    less content than room keeps its content height and stops early, which is
    what both notes cards now do.

    ⚠ AND THE OVERLAP HE ACTUALLY REPORTED WAS NEVER THIS RULE. `#brHistory` at
    six rows a page ran 40px past its own fixed 450px card and painted the pager
    bar 26px inside the Notes card below. That is fixed where it lives — five
    rows a page, and `overflow-y:auto` on that card — and it stays fixed
    whatever this rule does.

    ⚠ WHEN THE CONTENT IS TALLER THAN THE ROOM THE CARD SCROLLS INSIDE ITSELF
    rather than overflowing the column — the same arrangement
    `.fin-flip.is-capped` already has, which is where `--fin-flip-max` comes
    from.
    ⚠⚠ THIS BLOCK DUPLICATES THE `.card.is-capped` RULE 5,000 LINES ABOVE and
    has done since v31.120. It is left rather than tidied away: being the LATER
    of the two it is the one that decides, and removing it would move the
    deciding rule far up the file during a round about something else. */
.card.is-capped {
    max-height: var(--fin-flip-max, none);
    overflow-y: auto;
    overflow-x: hidden;
}

/*  ══ v31.125 (batch321, owner) — AMEND ON THE FLY: THE FIELD'S FOUR STATES ══
    Owner: *"users should be able to update specified non-financial fields
    individually without placing the entire transaction into Amend mode."*

    ⚠⚠ THE HOUSE `.fld-btn` IS `position:absolute; right:2px` — ONE BUTTON PER
    FIELD, by design since v31.82 (sixteen call sites). The pencil takes that
    place; the ✓ ✕ PAIR CANNOT, because two absolutely positioned buttons land
    on top of each other and the second one eats every click meant for the
    first. The pair goes in its own flow row, and the mock-up's probe is what
    found that — it could not press ✓ at all. */
.nvfe-act {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    gap: 2px;
}

/*  ⚠⚠⚠ WHERE THE PENCIL SITS WHEN THE MARK IS ON A `.fld-wrap`.
    Most fields on these pages are `<label class="fld-wrap">` = a hint ABOVE an
    input, and the amend mark goes on that label so the file adds no element.
    A control centred on the LABEL lands on the hint text, not on the field, so
    on a `.fld-wrap` both the pencil and the ✓ ✕ pair anchor to the BOTTOM
    instead — which is the input's own row.
    ⚠ `.fld-go` keeps the centred rule above: there the mark is on the field
    wrapper itself, and its middle IS the input's middle. */
.fld-wrap[data-nvfe] { position: relative; }

    /*  ⚠⚠⚠ 3px, NOT 5 — v31.126 (batch322, owner): *"edit icon should be
        centred correctly inside its cell. It appears to have a higher bottom
        spacing or padding."* Measured, it was: the button drew 1px below the
        field's top edge and 5px above its bottom. The field is 32px and a
        `.fld-btn` is 26px, so the only bottom offset that centres it is
        (32 − 26) / 2 = 3. 5px is the hairline's inset — 22px inside 32 — and
        borrowing it for a 26px control puts the control 2px high.
        ⚠ The hairline keeps 5px BECAUSE it is 22px tall. Two different
        insets, one shared centre line; both are (32 − own height) / 2. */
    .fld-wrap[data-nvfe] > .nvfe-pen,
    .fld-wrap[data-nvfe] > .nvfe-act {
        top: auto;
        bottom: 3px;
        transform: none;
    }

    /*  ⚠⚠⚠ v31.137 (batch332, owner) — AND `bottom: 3px` IS ONLY THE INPUT'S
        ROW WHILE THE WRAP ENDS WHERE THE INPUT ENDS.
        Owner: *"Please check the edit pencil style. I think the reason it is
        offset..."* MEASURED side by side, at rest:

            plain wrap, on its own                          drift   0px
            plain wrap STRETCHED beside a taller sibling    drift +14px

        `.fld-wrap` is a flex COLUMN with no `justify-content`, so its children
        pack to the top; `.fin-grid3` is a grid, whose items STRETCH by default.
        Put a description label next to an account search — which carries a
        `.sv-results` and is 14px taller — and the grid stretches the label,
        the spare height falls BELOW its input, and the pencil goes with it.
        That is the posted line panel on the money page and on the journal.

        ⚠⚠ `align-self: start` IS A SIZE CHANGE, NOT A MOVE. The wrap stops being
        stretched to its neighbour's height; the hint and the input keep their
        own size and their own position — MEASURED: input top and height are
        identical before and after. The field's box is drawn by `.input`, so a
        wrap that stops stretching is invisible.

        ⚠⚠⚠ v31.138 (batch333, owner) — AND IT IS NAMED PER GRID, NOT PUT ON
        EVERY MARKED WRAP. `align-self` acts on the CROSS axis, and which axis
        that is depends on the parent:
            in a GRID          the cross axis is vertical  → height only ✅
            in a FLEX COLUMN   the cross axis is HORIZONTAL → WIDTH ❌
        The posted money card is `display: flex; flex-direction: column`, so
        v31.137's unscoped rule made the bank account field shrink to its
        content instead of filling the card — the owner's screenshot shows it
        ending halfway across. The stretching this rule exists to undo only
        ever happens in a grid, so only grids are named.
        ⚠ THE TWO GRIDS ARE THE ONLY ONES THAT CARRY MARKED FIELDS: 19 uses of
        `.fin-grid3` and one of `.fin-jgrid` across the three financial pages.
        A marked wrap anywhere else keeps the width its parent gives it. */
    .fin-grid3 > .fld-wrap[data-nvfe],
    .fin-jgrid > .fld-wrap[data-nvfe] {
        align-self: start;
    }

/*  ══ v31.138 (batch333, owner) — A ROW THAT REFLOWS WHEN ITS OWN COLUMN IS
    NARROW, AND ONLY WHERE AN AMENDABLE NATIVE DATE LIVES ══════════════════════

    The owner's posted payment at a 1270px window. MEASURED in that column:

        .fin-grid3 cell                     142.7px
        native date  needs 97.5px, has      44.7px   → 52.8px SHORT
        native month needs 110.2px, has     44.7px   → 65.5px SHORT

    A `type=date` shows `10/08/2026` and a `type=month` shows `August 2026`;
    neither can be abbreviated, and the field also owns two 34px action zones —
    the browser's indicator and the amend pencil. **No padding number closes a
    52px gap.** Even stripping the reservation to the bare 68px the two zones
    occupy leaves the month 37px short. Three tracks simply cannot hold this
    field in a 462px card, so the ROW gives instead of the field.

    ⚠⚠⚠ THE TRIGGER IS THE CONTAINER'S WIDTH, NOT THE VIEWPORT'S. This column's
    width depends on which side panels a page renders, so a viewport breakpoint
    would be a proxy that is wrong on some of them. `auto-fill` asks the real
    question — how many 206px tracks fit here — and answers it per card.
      · 728px card (the 760 max) → 3 tracks of 234.7px, **exactly as today**
      · 462px card (the owner's) → 2 tracks of 225px, and 225 > 204.2 ✅
    206px = 12 left padding + 110.2 for `August 2026` + 80 reserved for the two
    zones + 2 border, rounded up. Measured, not chosen.

    ⚠⚠⚠ SCOPED BY `:has()` TO A GRID THAT ACTUALLY HOLDS ONE, and that scoping is
    load-bearing: **`.enq-chip-row` sets its width to `(100% - 24px) / 3 * 2 +
    12px`, which is Date To's right border expressed in `.fin-grid3`'s own three
    tracks.** Reflow that grid to two and the chip row is measured against a
    layout that is no longer there. The enquiry row's dates are FILTERS and carry
    no `data-nvfe`, so this selector cannot reach them — and an entry form marks
    nothing until `feTrn > 0`, which it never is.
    ⚠ BELOW 768 the single-column rule above still wins on order.

    ⚠⚠ THE THIRD SELECTOR IS THE ANALYSIS SLOTS, and it was missed on the first
    cut. A `.ba-slot` is not a native date, but it carries the same TWO action
    zones — its picker and the pencil — so it reserves the same 80px and
    truncated `CC-100` to `CC-1(` in the very same card. The predicate is
    therefore *a marked field with a control of its own besides the pencil*,
    which is what "two zones" means in markup.
    ⚠ `:not(.nvfe-pen)` IS LOAD-BEARING. The pencil IS a `.fld-btn`, so without
    it this would match every marked field the door has touched and reflow
    one-zone rows that have room to spare.
    ⚠⚠ READ FROM THE MARKUP, NOT FROM `.nvfe-two`. The door adds that class after
    load; hanging the layout on it would paint three tracks, truncate, and then
    jump to two on every posted document. */
.fin-grid3:has(> .fld-wrap[data-nvfe] > input[type="date"]),
.fin-grid3:has(> .fld-wrap[data-nvfe] > input[type="month"]),
.fin-grid3:has(> .fld-wrap[data-nvfe] .fld-btn:not(.nvfe-pen)) {
    grid-template-columns: repeat(auto-fill, minmax(206px, 1fr));
}

    @media (max-width: 767.98px) {
        .fin-grid3:has(> .fld-wrap[data-nvfe] > input[type="date"]),
        .fin-grid3:has(> .fld-wrap[data-nvfe] > input[type="month"]),
        .fin-grid3:has(> .fld-wrap[data-nvfe] .fld-btn:not(.nvfe-pen)) {
            grid-template-columns: 1fr;
        }
    }

    .nvfe-act .fld-btn {
        position: static;
        transform: none;
        width: 30px;
    }

/*  ══ v31.126 (batch322, owner) — THE PENCIL IS GOLD, AND IT SAYS SO AT REST ══
    Owner: *"The edit pencil is currently too muted in its normal state and only
    becomes sufficiently visible on hover. Keep the edit icon gold by default so
    users can immediately recognise that the field is editable."*

    ⚠ v31.125 had it at `opacity: .45`, reasoning that a posted transaction is
    read more often than amended. That reasoning was about NOISE and the owner's
    is about DISCOVERABILITY — a control nobody can see is a feature nobody
    finds, and this one is the whole point of the round. Gold is the house
    colour for *"this does something"*, so it wears it. */
.nvfe-pen {
    color: var(--nv-gold);
    opacity: 1;
}

/*  ⚠⚠ AND THE HOVER CHANGES THE PENCIL'S DIRECTION, not its brightness.
    Owner: *"On hover, change the pencil orientation so that it points from
    top-right to bottom-left, providing clear visual feedback that the control
    is active."* At rest the nib is bottom-RIGHT; mirrored, it is bottom-LEFT,
    so the body runs top-right to bottom-left exactly as asked.
    ⚠ THE ICON IS AN SVG THIS PROJECT DRAWS (`_NvFieldEdit`), which is what
    makes the direction dependable — a `✎` glyph points whichever way the
    reader's font decides, and mirroring that is a guess. */
.nvfe-pen svg { transition: transform .12s ease; }

[data-nvfe]:hover > .nvfe-pen svg,
[data-nvfe]:focus-within > .nvfe-pen svg,
.nvfe-pen:hover svg,
.nvfe-pen:focus-visible svg { transform: scaleX(-1); }

/*  ══ TWO ACTIONS, TWO ZONES, TWO HAIRLINES ═════════════════════════════════
    Owner: *"Introduce a second vertical separator and move the calendar/date
    selector to the right, giving each action its own clearly defined area"* —
    and the same for the Business Analysis selectors.

    ⚠⚠⚠ THE GEOMETRY IS THE HOUSE'S, NOT A NEW ONE. `select.input` and `.fld-go`
    have used the same numbers since v31.53: a 34px action zone, a 1px × 22px
    divider at `right 34px` in `rgba(112,160,238,.30)`, and the value stopping
    at 46px. A second action simply repeats that outward — the pencil's zone is
    34→68, its divider sits at 68, and the value stops at 80. Put one of these
    beside a plain field and every hairline in the row still lines up.
    ⚠ `.nvfe-two` IS ADDED BY THE DOOR, which detects the existing control
    rather than asking the page to declare it. */
.fld-wrap[data-nvfe].nvfe-two > .nvfe-pen { right: 36px; }

.fld-wrap[data-nvfe].nvfe-two > .nvfe-act { right: 38px; }

    /*  ⚠⚠⚠ v31.137 (batch332, owner) — THE SAME TWO ZONES ON A SEARCH FIELD,
        WHERE THE PENCIL HANGS ON `.fld-go` INSTEAD OF ON THE WRAP.
        Owner: *"Please check the edit pencil style. I think the reason it is
        offset..."* MEASURED: the wrap of a search field ends 14px below its
        input, because `.sv-results` sits inside it and carries a 10px bottom
        margin — so `bottom: 3px` of the wrap is 14px below the field. The door
        now hangs the pencil on `.fld-go`, whose box IS the input's box, and the
        centred `.nvfe-act` rule at the top of this block then puts it on the
        field's own middle with no offset to correct.
        ⚠ THE HORIZONTAL NUMBERS ARE UNCHANGED — 36 and 38, the house's — they
        just measure from `.fld-go`'s right edge now. That edge and the wrap's
        are the same line (`.fld-go` is `display: block`), so a search field's
        hairlines still land at 34 and 68 with every other field in the row.
        ⚠⚠ THE `> ` RULES ABOVE STILL OWN THE PLAIN CASE and are untouched;
        a wrap with no `.fld-go` never matches these. */
    .fld-wrap[data-nvfe].nvfe-two .fld-go > .nvfe-pen { right: 36px; }

    .fld-wrap[data-nvfe].nvfe-two .fld-go > .nvfe-act { right: 38px; }

    /*  ⚠⚠⚠ THE INNER DIVIDER, AND ONLY WHERE NOTHING ELSE DRAWS IT.
        v31.126 (batch322, owner): *"hairline separator needed in date/period
        control between edit and date selector."*

        Which line each field needs depends on what its second control is:
        · a `.fld-btn` picker (Business Analysis) carries `.fld-btn::before`,
          a 1px × 22px line at its own left edge — so the picker draws 34 and
          the pencil beside it draws 68. Both zones are bounded already.
        · a NATIVE `<input type="date">` indicator draws nothing. The pencil
          still draws 68, so the OUTER edge is bounded and the inner one — the
          boundary between pencil and calendar, at 34 — is missing. That is the
          gap the owner pointed at.
        So this rule supplies 34, on the native case only. The first cut put it
        at 68, where the pencil's own line already was: two coincident 1px lines
        and the real gap still open. Measured before changing it.
        ⚠ A background layer on the wrapper, so it needs no element and cannot
        be left behind when the pencil is removed. */
    .fld-wrap[data-nvfe].nvfe-two-native::after {
        content: "";
        position: absolute;
        right: 34px;
        bottom: 5px;
        width: 1px;
        height: 22px;
        background: rgba(112, 160, 238, .30);
        pointer-events: none;
    }

    /*  ⚠ AND THE VALUE STOPS BEFORE BOTH. Without this the text runs under the
        pencil, which is the fault being fixed rather than a smaller version
        of it. */
    .fld-wrap[data-nvfe].nvfe-two .input { padding-right: 80px; }

    /*  ⚠⚠⚠ v31.137 (batch332) — AND A ONE-ZONE FIELD NEEDS IT TOO. The rule
        above reserves room only where a SECOND control exists; a field carrying
        just the pencil reserved nothing, so a long value ran straight under it.
        Every short value on these pages hid the fault — it took a posted
        journal line ("Office supplies — August") to show it.
        ⚠ 46px IS THE HOUSE NUMBER, not a new one: `.fld-go:has(> .fld-btn)` has
        used it since v31.52 for exactly this control in exactly this position —
        a 32px button zone, 12px of air, the 2px inset.
        ⚠⚠ THE THREE RULES ABOVE AND BELOW ALL OUTRANK IT (`.nvfe-two`,
        `.nvfe-live` and the pair of them each add a class), so the two-zone and
        live reservations are unchanged. */
    .fld-wrap[data-nvfe] .input { padding-right: 46px; }

/*  ══ v31.132 (batch328, owner) — WHAT A LIVE FIELD NEEDS THAT A RESTING ONE
    DOES NOT ═══════════════════════════════════════════════════════════════
    The pencil is ONE control; the ✓ ✕ pair it becomes is TWO, and on a field
    that already has a picker the pair sits OUTSIDE it. MEASURED on the account
    field: `.nvfe-act` spans 38 → 100 from the wrap's right edge while the
    resting rule stops the value at 80, so the account name ran underneath the
    tick. The screenshot found it; the resting numbers were all correct.
    ⚠ 104 = the pair's own 100 plus the 4px the house leaves beside a control.
    ⚠⚠ AND THE ONE-ZONE CASE NEEDS IT TOO — there the pair sits at 4 → 66. */
.fld-wrap[data-nvfe].nvfe-live .input { padding-right: 70px; }

.fld-wrap[data-nvfe].nvfe-two.nvfe-live .input { padding-right: 104px; }

/*  ⚠⚠⚠ AND THE BROWSER'S OWN CLEAR BUTTON COMES OFF A SEARCH BOX WE HAVE
    CLAIMED. An `input[type="search"]` draws a native ✕ hard against its right
    edge — exactly where this door puts ✓ and ✕ — so a live account field showed
    three marks, one of them the browser's, sitting on top of ours. It is only
    drawn while the box has a value, which is why it never appeared in any
    resting measurement.
    ⚠ Scoped to `[data-nvfe]`: every other search box in the application keeps
    its clear button. */
[data-nvfe] input[type="search"]::-webkit-search-cancel-button,
[data-nvfe] input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
    display: none;
}

    /*  ⚠⚠ THE NATIVE DATE PICKER IS PUSHED OUT TO ITS OWN ZONE. A
        `<input type="date">` draws its indicator hard against the right edge,
        which is exactly where v31.125's pencil sat — the overlap the owner
        reported. It now keeps the outer 34px and the pencil has the next one. */
    .fld-wrap[data-nvfe].nvfe-two .input::-webkit-calendar-picker-indicator {
        margin-right: 0;
        opacity: .85;
    }

/*  the field being changed, and the field that just changed */
.nvfe-live .input { border-color: var(--nv-gold); }
.nvfe-done .input { border-color: var(--nv-good); }
.nvfe-busy { opacity: .6; pointer-events: none; }

/*  ⚠⚠ THE ANSWER IS A LINE, NOT A DIALOG. The reader has just dismissed one
    confirm; a second box to acknowledge the result would make a one-field
    change a three-click job. It clears itself. */
.nvfe-toast {
    position: fixed;
    left: 50%;
    bottom: 26px;
    transform: translateX(-50%);
    z-index: 90;
    max-width: min(560px, calc(100vw - 32px));
    padding: 10px 16px;
    border-radius: 10px;
    font-size: 13.5px;
    line-height: 1.45;
    background: var(--nv-card);
    border: 1px solid rgba(104, 152, 232, .3);
}

    .nvfe-toast.is-ok { border-color: rgba(88, 179, 104, .55); }
    .nvfe-toast.is-no { border-color: rgba(232, 167, 92, .6); }

/*  ══ v31.130 (batch326, owner) — THE MESSAGE SITS BESIDE THE LINE HEADING ══
    Owner: *"The messages label e.g 'VAT Code Changed' should be at the top next
    to the line label in capital 'VIEW LINE X' on its right."*

    ⚠ THE SAME TWO STATE COLOURS AS THE FLOATING NOTE, so a reader who sees one
    form and then the other is not learning a second vocabulary. What changes is
    the PLACE, not the language: no box, no border, no fixed position — it is a
    caption on a heading, and a heading is not a card.
    ⚠⚠ `margin-left` ONLY. The heading row is a flex line that already spaces its
    own parts, and giving this a `margin-left:auto` would push it to the far
    right of the card instead of *"on its right"* — beside the label, which is
    what was asked for. */
.nvfe-inline {
    margin-left: 10px;
    font-size: 12.5px;
    font-weight: 500;
    letter-spacing: .01em;
    color: var(--nv-muted);
    text-transform: none;
}

    .nvfe-inline.is-ok { color: var(--nv-good); }
    .nvfe-inline.is-no { color: var(--nv-gold); }

/*  ══ v31.126 (batch322, owner) — THE VIEW CHIPS ARE ONE WIDTH ══════════════
    Owner: *"The current View chip buttons in - Lines tab are ambiguous because
    the same label is used for different levels of the transaction… Rename the
    top/header chip action to View Header. Rename each line-level action to View
    Lines. Use the same button width for both."*

    ⚠⚠ 160px IS MEASURED, NOT CHOSEN. A `min-width` only makes two chips equal
    if it clears BOTH labels, and the page renders one language at a time — so
    the number has to clear the widest label in every language, or the pair
    stops matching in whichever one it misses. Rendered in the shipped face:

        en  View Header 128 · View lines  106
        sk  Zobraziť hlavičku 160 · Zobraziť riadky 143
        cs  Zobrazit hlavičku 160 · Zobrazit řádky  139
        de  Kopf anzeigen 141 · Zeilen ansehen 148
        pl  Pokaż nagłówek 154 · Pokaż wiersze 135

    160 is the widest of the ten. Below it the two chips differ in at least one
    language; at it they are identical in all five. The first attempt used 124
    and measured 128 against 124 in English alone — close enough to look right
    in a screenshot and still not what was asked for.
    ⚠ A FLOOR RATHER THAN A FIXED `width`, so a longer string in a language
    added later grows the chip instead of being clipped by it. */
.chip.fin-viewchip {
    min-width: 160px;
    justify-content: center;
    text-align: center;
}

/*  ══════════════════════════════════════════════════════════════════════════
    v31.309 (owner) — THE REVIEW-STEP ACTION ROW, MEASURED.

    Owner, after v31.308: *"now the right button is not aligned"*.

    ⚠⚠⚠ THE RIGHT BUTTON WAS ALIGNED — that was measured off his own screenshot:
    Copy and View Line share the same LEFT and RIGHT edge to the pixel. What he
    is reacting to is the other end. **Four chips at 160px plus three 8px gaps
    is 664px in a row about 666px wide**, so the row is exactly FULL: there is
    no free space for `justify-content: flex-end` to distribute, the cluster
    spans the whole width, and Print reaches the far left margin.

    ⚠⚠ SO THE FIX IS WIDTH, NOT ALIGNMENT. At 120px the four take 504px and
    leave ~160px of free space, which is what lets them sit as a right-aligned
    CLUSTER instead of a justified row. Copy's right edge does not move.
    ⚠ SCOPED TO THIS ROW. `.fin-viewchip` is a shared class and the 160px floor
    is right everywhere it is one or two chips; this is the only place four of
    them compete for one line.
    ⚠⚠ AND IT WRAPS RATHER THAN OVERFLOWS. With `flex-end`, content wider than
    its container spills off the LEFT — so on a narrow window the first chip
    would disappear under the card edge. `flex-wrap` makes it drop to a second
    right-aligned line instead, which is recoverable; a clipped control is not.
    ══════════════════════════════════════════════════════════════════════════ */
.fin-actionrow {
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
}

    .fin-actionrow > .chip.fin-viewchip {
        min-width: 120px;
        flex: 0 0 auto;
    }

/*  ⚠⚠ v31.310 — THE LAYOUT PICKER WEARS THE CHIP, so it sits on the same
    baseline and the same height as Print, Email, Edit and Copy beside it.
    `.chip` is built for inline-flex content it centres itself; a <select> is a
    replaced element and centres its own text, so the flex properties it would
    inherit have to be undone rather than added to. */
.fin-actionrow > select.fin-vsel {
    display: inline-block;
    appearance: auto;
    -webkit-appearance: auto;
    /*  ⚠ ROOM FOR THE ARROW. Without the extra right padding the platform's own
        disclosure triangle sits on top of the longest option's last letter,
        and "Hairline" is exactly long enough to reach it. */
    padding: 0 26px 0 12px;
    text-align: left;
    line-height: 1.1;
    cursor: pointer;
}

    /*  ⚠⚠⚠ v31.142 (batch337, owner) — AND THE JOURNAL'S TOGGLE IS THE EXCEPTION,
        BY THE OWNER'S OWN MEASURE. Owner: *"Set the View Line / Hide Line button
        width to align with the width of the Credit input control immediately
        above it."* The Credit track is 96.5px in his column; the 160px floor
        above made the chip overflow its own grid cell — MEASURED: right edges
        aligned, left edges 63.5px apart.

        ⚠⚠ THE FLOOR IS RELEASED, NOT LOWERED. `width: 100%` makes the chip the
        track, whatever the track is at that band and in that language, which is
        what "align with the Credit control" means. A smaller fixed number would
        be the same staleness the rule above warns about, one size down.
        ⚠ SCOPED TO A CHIP INSIDE `.fin-jgrid` — the journal line grid, and the
        only place a View chip is laid out as a column. The money page's chip and
        both invoice chips are in flex rows and keep the 160px floor the owner
        asked for in v31.126, so those three stay one width as before.
        ⚠⚠⚠ AND AT THAT WIDTH THE LABEL TAKES TWO LINES. MEASURED, in a 96.5px
        cell, the longest of the ten strings — German *"Zeile ausblenden"* —
        needs 120.5px **even at an 11px font**; English "Hide Line" needs 113px
        at the chip's own 16px. One line does not fit the Credit column in ANY
        language at a legible size, so matching that column means wrapping, and
        this rule makes the wrap deliberate rather than an accident:
          · `height: auto` + `min-height` — `.chip` is a fixed 32px, and a grid
            item stretched to a two-line row turned into a 72px slab
          · `line-height: 1.15` and tighter padding, so two lines read as one
            control rather than as a gap with words in it
        ⚠ IF ONE LINE MATTERS MORE THAN THE COLUMN, the chip spans Debit AND
        Credit (205px at this band, which fits every language at 16px) — a
        one-line change to `grid-column: 2 / -1`. The owner asked for the Credit
        width, so the Credit width is what this does. */
    /*  ══ v31.143 (batch338, owner) — AND THE MONEY PAGE'S TOGGLE IS WIDER,
        BECAUSE ITS OPEN LABEL NAMES TWO THINGS ═══════════════════════════════
        Owner: *"Increase the toggle button width sufficiently to accommodate
        Hide Line / View Header cleanly without wrapping."*

        MEASURED, in this chip's own font and padding, across the five locales:

            de  Zeile ausblenden / Kopf anzeigen   290.6px   ← the widest
            sk  Skryť riadok / Zobraziť hlavičku   265.8px
            cs  Skrýt řádek / Zobrazit hlavičku    261.8px
            pl  Ukryj wiersz / Pokaż nagłówek      258.1px
            en  Hide Line / View Header            213.7px

        292 clears the widest of the ten strings. `nowrap` is the guarantee, not
        the number: a language added later that overruns will run on rather than
        silently fold into two lines the way the journal chip does at its own
        much narrower width.
        ⚠⚠ THE FLOOR HOLDS IN BOTH STATES, so the control does not resize under
        the cursor between "View Line" and the long label — a button that jumps
        as you click it is a button you miss.
        ⚠⚠⚠ SCOPED BY `[data-payline]` — THE MONEY PAGE'S CHIP AND NOTHING ELSE.
        The owner: *"it should not alter the agreed Invoice or Journal toggle
        behaviour."* The journal's chip is sized by the rule below and both
        invoice chips keep the 160px house floor. */
    .chip.fin-viewchip[data-payline] {
        min-width: 292px;
        white-space: nowrap;
    }

    .fin-jgrid > .chip.fin-viewchip {
        min-width: 0;
        width: 100%;
        height: auto;
        min-height: 32px;
        padding: 4px 8px;
        line-height: 1.15;
        white-space: normal;
    }

/* ════════════════════════════════════════════════════════════════════
   v31.144 (batch339, owner) — _NvTranslate: READ A DESCRIPTION IN
   ANOTHER LANGUAGE. The glyph, the language list, and the preview.

   Two placements, one set of rules: the label row of a plain field, and
   the rich editor's toolbar. Everything is namespaced `nvtr-` — the
   short-class-name trap has cost this project a round before, and
   `.tr-*` would have collided with table rows in every sense.
   ════════════════════════════════════════════════════════════════════ */

/*  ⚠⚠ THE HINT ROW BECOMES A FLEX ROW, AND THE LABEL KEEPS THE ELLIPSIS.
    `.fl-hint` is one nowrap line, 18px tall, clipped with an ellipsis —
    that fixed height is what keeps grid columns aligned, so it is not
    touched. Only the layout changes, and the clipping moves onto the
    label's own span so the control beside it is never what gets cut. */
.fl-hint.nvtr-hint {
    display: flex;
    align-items: center;
    gap: 6px;
}

    .fl-hint.nvtr-hint > .nvtr-t {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/*  ⚠ 15px INSIDE AN 18px ROW — measured, not chosen: the row is
    `line-height: 18px` and a 15px mark centres in it with 1.5px either
    side. The word "Translate" was measured too and does not fit: it takes
    73px of a 146px label row at 03-Screen and clips the label to
    "Descripti…". The word lives in the tooltip, as the pencil's does. */
.nvtr-go {
    margin-left: auto;
    flex: 0 0 auto;
    border: 0;
    background: none;
    padding: 0;
    color: var(--nv-gold);
    cursor: pointer;
    height: 18px;
    line-height: 0;
    display: inline-flex;
    align-items: center;
}

    /*  ⚠ v31.146 (owner): *"Increase glyph size to 18 × 18px. Apply
        margin-right: 10px to the SVG."* The 18px mark in an 18px label row is
        flush by design; the margin is what lifts it off the field's right edge. */
    .nvtr-go svg { margin-right: 10px; }

    .nvtr-go:hover { opacity: .78; }

    .nvtr-go:focus-visible {
        outline: 2px solid var(--nv-blue-bright);
        outline-offset: 2px;
        border-radius: 3px;
    }

    .nvtr-go[disabled] { opacity: .4; cursor: default; }

/* the toolbar host — `.rt-toolbar button` already sizes it */
.rt-toolbar .nvtr-btn svg { display: block; }

/*  ── the language list ────────────────────────────────────────────────
    The house popover grammar, borrowed from `.rt-emoji`: one column,
    the surface colour, the same border and the same lift. */
.nvtr-menu {
    position: absolute;
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: 1px;
    width: max-content;
    min-width: 186px;
    padding: 6px;
    border: 1px solid rgba(112, 160, 238, .30);
    border-radius: var(--r-card);
    background: var(--nv-surface);
    box-shadow: 0 14px 30px rgba(0, 0, 0, .5);
}

    .nvtr-menu button {
        border: 0;
        background: none;
        color: var(--nv-ink-2);
        text-align: left;
        font-family: inherit;
        font-size: 13px;
        padding: 7px 10px;
        border-radius: 6px;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 10px;
    }

        .nvtr-menu button:hover { background: rgba(232, 167, 92, .10); }

        /*  ⚠⚠ v31.146 — THE DETECTED LANGUAGE IS MARKED, NOT DISABLED. It was
            greyed out and unclickable until the owner pointed out the obvious:
            detection is a heuristic and can be wrong, so it must inform the
            choice without removing it. The row now reads as ordinary; only its
            "as entered" tag says what was detected. */
        .nvtr-menu button.is-src .cc,
        .nvtr-menu button.is-src .tag { color: var(--nv-gold); }

        .nvtr-menu button[disabled] { opacity: .42; cursor: default; }

        .nvtr-menu button[disabled]:hover { background: none; }

        .nvtr-menu button .cc {
            font-size: 11px;
            letter-spacing: .06em;
            color: var(--nv-ink-3);
            min-width: 20px;
        }

        .nvtr-menu button .tag {
            margin-left: auto;
            font-size: 10.5px;
            letter-spacing: .06em;
            text-transform: uppercase;
            color: var(--nv-ink-3);
        }

.nvtr-mh {
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
    padding: 4px 10px 6px;
}

.nvtr-mr {
    height: 1px;
    background: rgba(104, 152, 232, .18);
    margin: 4px 6px;
}

/*  ── the preview ──────────────────────────────────────────────────────
    Under the field, never over it: the reader is comparing two versions
    of the same sentence and needs both on screen. Gold, because gold is
    this application's colour for "this is offered, not done". */
.nvtr-prev {
    border: 1px solid rgba(232, 167, 92, .45);
    border-radius: var(--r-card);
    background: rgba(232, 167, 92, .045);
    padding: 10px 12px;
    margin-top: 8px;
}

/*  ⚠⚠⚠ A GRID CELL IS NOT A PLACE TO PUT A PANEL. On the posted cards the
    field is one cell of a `.fin-grid3`; a sibling inserted after it becomes
    another CELL and lands beside the field at a third of the width. This
    gives the panel the whole row under the field it belongs to, and outside
    a grid the property is simply inert. */
.nvtr-inrow { grid-column: 1 / -1; }

.nvtr-ph {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--nv-ink-3);
    margin-bottom: 7px;
}

.nvtr-pl { color: var(--nv-gold); }

.nvtr-x {
    margin-left: auto;
    cursor: pointer;
    color: var(--nv-ink-3);
    border: 0;
    background: none;
    font-size: 14px;
    line-height: 1;
    padding: 0 2px;
}

.nvtr-body {
    font-size: 13.5px;
    line-height: 1.5;
    border-left: 2px solid rgba(232, 167, 92, .35);
    padding-left: 10px;
    overflow-wrap: anywhere;
}

.nvtr-wait { color: var(--nv-ink-3); }

.nvtr-pa {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    flex-wrap: wrap;
}

    /*  ⚠ THE HOUSE `.btn` FILLS ITS CONTAINER. In a preview as wide as an
        invoice card that turns two ordinary actions into two banners, so
        here they size to their own words. */
    .nvtr-pa .btn {
        flex: 0 0 auto;
        width: auto;
        height: 30px;
        padding: 0 14px;
        font-size: 13px;
    }

        /*  ⚠ A CONTROL THAT CANNOT BE PRESSED MUST LOOK LIKE IT. The house
            primary button carries a gradient and a glow, and `disabled` alone
            changes neither — the probe screenshot showed a refused "Use this
            text" looking exactly as inviting as an accepted one. */
        .nvtr-pa .btn[disabled] {
            opacity: .45;
            cursor: default;
            box-shadow: none;
            filter: grayscale(.35);
        }

.nvtr-pc {
    margin-left: auto;
    font-size: 11.5px;
    color: var(--nv-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

    .nvtr-pc.over { color: var(--nv-gold); }

/* ══════════════════════════════════════════════════════════════════════════
   v31.150 (batch343, owner — MOCK-UP LOCKED) — NOTES.  Namespace `nt-`.

   Lifted from the locked mock-up unchanged, so the shipped page is the thing
   that was reviewed rather than a second interpretation of it.

   ⚠ THE PAGE DOES NOT MAKE `.scroll` A SCROLLER. `app.css:86` sets
     `.app .scroll { overflow: visible; flex: initial }` — in V2 the DOCUMENT
     scrolls, and a Notes page with its own inner scroller would behave unlike
     every other screen. The sticky browse column below is sticky against the
     document, which is the scroller that actually exists.
   ══════════════════════════════════════════════════════════════════════════ */
.nt-logo {
    width: 40px; height: 40px; border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    color: var(--nv-gold); font-size: 22px; font-weight: 200;
    border: 1px solid rgba(232,167,92,.4);
}

.nt-head .htext { flex: 1; min-width: 0; }

/* ── THE WORKSPACE ────────────────────────────────────────────────────────
   ONE workspace, not V1's independent bordered panels: a browse column and
   the note itself, sharing one scroll and one visual system.               */
.nt-work { display: flex; flex-direction: column; gap: 14px; min-width: 0; padding-bottom: 40px; }
.nt-browse, .nt-note { display: flex; flex-direction: column; gap: 12px; min-width: 0; }

/*  ⚠⚠⚠ v31.158 (owner) — "There is no spacing between tabs", written across
    the join between the note header card and the cards under it.

    MEASURED: header card bottom 320, next card top 320. Zero. Every other
    stacked card in the app has a gap (.nt-browse 12, .fin-tiles 14,
    .fin-hub 18).

    ⚠ SAME ROOT CAUSE AS THE UNDERLINES ABOVE — the shipped DOM is not the
    mock-up's DOM. `.nt-note` declares the column gap, and in the mock-up the
    cards are its direct children so they get it. What ships must POST, so a
    `<form>` sits between them; `.nt-note`'s gap then applies to the form (one
    child, nothing to space) and the cards inside it are block siblings with no
    margin at all. A gap on a flex parent only spaces ITS OWN children.

    ⚠⚠⚠ v31.159 CHANGES THE MECHANISM AND NOT THE OUTCOME. The form no longer
    carries a copy of the column — it stops generating a box at all, so ITS
    children become `.nt-note`'s own flex items and take `.nt-note`'s 12px
    directly. One declaration of the gap instead of two that must agree.

    THE REASON IS THE OWNER'S: *"In documents tab, documents should be above
    'Who can see this'."* Those two cards are at DIFFERENT DEPTHS — the access
    card is inside `#ntForm` because it holds the `name="people"` CHECKBOXES,
    the access list v1 never saved and this module exists to save, while the
    documents card carries its own upload form and HTML forbids nesting one
    form in another. `order` only sorts siblings, so with the form generating a
    box they could never be reordered. `display: contents` makes them siblings.

    ⚠ THE FORM STILL POSTS. `display: contents` removes the box, not the
      element: submission, validation and the antiforgery token are untouched.
      The gate drives a real save round trip rather than taking that on trust. */
.nt-note > form { display: contents; }

/*  the visible order, stated once. Everything not named here keeps source
    order (0), so: head → note+tags → secure → documents → who can see this. */
.nt-note .nt-access { order: 1; }
/*  ⚠ v31.160 (owner): *"Edit and Delete should be move above share via
    Inmail."* The action row was pinned last at v31.159 because giving one
    sibling an order is a decision about all of them; this is the owner
    choosing where in that sequence it belongs. */
.nt-note .nt-actions { order: 2; }
.nt-note .nt-share { order: 3; }
.nt-note .nt-notowner { order: 4; }

/* Tablet — the two columns appear as soon as there is room for them. */
@media (min-width: 768px) {
    .nt-work { display: grid; grid-template-columns: 296px minmax(0, 1fr); gap: 14px; align-items: start; }
}
/* Desktop — the note gets the extra width, the browse column does not. */
@media (min-width: 1024px) {
    .nt-work { grid-template-columns: 340px minmax(0, 1fr); gap: 18px; }
}
/* Phone — one pane at a time, chosen by the state. */
@media (max-width: 767.98px) {
    body.pane-note .nt-browse { display: none; }
    body.pane-list .nt-note { display: none; }
}
@media (min-width: 768px) { .nt-head .nt-back { display: none; } }

/* ── FIND + FILTERS ─────────────────────────────────────────────────────── */
.nt-filters { flex-wrap: wrap; }
.nt-tagrow { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.nt-tagcap { flex: 0 0 auto; margin-right: 2px; }
.nt-tagrow .chip { height: 28px; padding: 0 11px; }

/* ── THE DIRECTORY TREE — the house rows, plus what is genuinely this card's ─
   ⚠⚠⚠ v31.160 (owner): *"Use the same structured 'Tree View' with styling to
   show selection results. The structure is there in Entity Switch, Transaction
   Types etc."*

   HE WAS RIGHT AND IT WAS ALREADY THERE. Every rule that drew a ROW here —
   `.nt-nodebtn`, `.nt-caret`, `.nt-nodename`, `.nt-kids`, `.nt-fold`,
   `.nt-fdot`, `.nt-entname` — was a SECOND tree control standing beside the
   house one, with its own row height, its own indent mechanism (a margin and a
   hairline, where the house uses padding so a hover fill still starts at the
   panel's left edge) and its own selected treatment. All deleted. The rows are
   `.acc-tree-row` at depths d1-d4 now, so this is the third caller of the tree
   the owner has already sized twice himself.

   ⚠ A RULE KEPT FOR MARKUP THAT NO LONGER EXISTS IS THE NEXT READER'S FALSE
     LEAD, so nothing below is a leftover: `.nt-ent` groups a company's rows for
     the pager, `.nt-leaf*` is the ✓ mark and the un-openable state, and that is
     all that is left. */
.nt-node + .nt-node { border-top: 1px solid rgba(104,152,232,.13); }

/*  ⚠ NO `display` PROPERTY ON `.nt-ent` — the pager hides paged-out rows with
    the `hidden` attribute, whose only power is the UA's `display: none`, and
    ANY display declaration here would beat it. That is the v31.152 trap
    (`hidden` cannot beat a class rule setting display) read the other way
    round. The entity heading is hidden from script with `style.display`, which
    nothing can out-specify. */
.nt-ent { margin-bottom: 2px; }

/*  ⚠⚠⚠ v31.165 (owner) — THE NOTES FLIP RULES ARE REMOVED. *"Remove the flip
    behaviour completely from this card … Remove the flip behaviour from the
    Frequently Used card as well."* The wrappers, both back faces and the
    `nvFlip` controllers went from the page in the same round, so every rule
    that stood here could only ever have matched an element that no longer
    exists — `.nt-flip`, `.nt-flip-freq`, `.nt-flip-list`, `.nt-flipdots` and
    their 1366+ block.
    ⚠⚠ TWO OF THEM WERE THE FIXED HEIGHTS HIS ITEM 5 IS ABOUT: `.nt-flip-freq
    .flip-inner { height: 435px }` and `.nt-flip-list .flip-inner { height:
    460px }`. A flip needs both faces to occupy one box, so a flip card cannot
    size to its content — removing the flip is what makes "size naturally to
    their content" possible at all, and the two asks are the same ask.
    ⚠ `_NvFlip` AND THE HOUSE `.flip` RULES ARE UNTOUCHED — the financials
    history cards, the bank rec faces and the VAT deck all still flip. Only the
    `.nt-`prefixed layer is gone. */


/*  ⚠⚠⚠ v31.165 REMOVED THESE AS DEAD AND v31.166 PUT THREE OF THEM BACK — one
    round apart, which is the whole lesson. `.nt-freqback` and `.nt-listback`
    really were dead and are still gone; `.nt-ftitle`, `.nt-fmarks` and
    `.nt-clearfilter` were NOT dead, they were homeless, because the round that
    deleted the container they lived in also deleted the only route to four
    working filters. **"No `.cshtml` references it" answers whether a rule is
    reachable TODAY, not whether the thing it styled should have gone.** The
    grep was correct and the conclusion was too fast.
    ⚠ `.nt-tagrow` was left alone at v31.165 on the grounds that pulling a class
    out from under two unrelated declarations is how a rule gets resurrected
    wrong later. One round later it was needed again, unchanged. */
.nt-ftitle { margin: 10px 2px 6px; font-size: var(--fs-caption); font-weight: 200; }

/*  the three marks carry a count, so the label and the badge sit apart; the row
    wraps rather than squeezing three long labels onto one line. */
.nt-fmarks { margin-top: 2px; }

    .nt-fmarks .chip { gap: 8px; }

/*  ⚠ a tag chip sizes to its own text. `.nt-tagrow` already wraps; what it must
    NOT do is inherit an equal-width rule — v31.161 measured `.nv-eqrow` giving
    four tags 74px each and clipping "credentials" to "redentia", centred text
    overflowing at both ends with no ellipsis to show it. */
.nt-navcard .nt-tagrow .chip { flex: 0 0 auto; }

.nt-clearfilter { margin-top: 12px; }

/*  ⚠⚠ v31.166 — THE NOTE PANE'S SIDE COLUMN. `.nt-workrow` is a two-track grid
    from 1366, so the tag card and the filter card have to share ONE track to
    stack under each other; as separate grid children the second would drop into
    track 1 under the note. The gap is restated here because a grid/flex gap
    spaces its OWN children only — the v31.158 finding, in its third shape. */
/*  ══ v31.168 — THE ACCOUNT PICKER ON THE NEW-NOTE FORM ════════════════════
    It reuses the house tree row (`.acc-tree-row`, d1/d2) rather than inventing a
    result list, so the picker and the browse tree read as the same control. The
    rows are BUTTONS here — they choose a filing rather than navigate — which is
    the same shape the country picker uses. */
.nt-acctpick { margin-bottom: 12px; }

    .nt-acctpick .nt-acctlist {
        margin-top: 8px;
        max-height: 220px;
        overflow-y: auto;
        overflow-x: hidden;
        border: 1px solid var(--nv-line, rgba(232,167,92,.18));
        border-radius: 10px;
        padding: 4px 0;
    }

    /*  ⚠ a picker row is a BUTTON, so it needs the same reset `a.acc-tree-row`
        got at v31.160 — a UA button brings its own font, background and centring
        and would read as a second visual language inside the same tree. */
    button.nt-acctrow {
        width: 100%;
        background: transparent;
        border: 0;
        font-family: inherit;
        text-align: left;
        cursor: pointer;
        color: var(--nv-ink-2);
    }

        button.nt-acctrow:hover { background: rgba(104, 152, 232, .08); }

    .nt-acctchosen {
        display: flex;
        align-items: center;
        gap: 10px;
        margin-top: 8px;
        min-width: 0;
    }

        .nt-acctchosen .nt-acctname {
            color: var(--nv-gold);
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .nt-acctchosen .nt-acctchange { flex: 0 0 auto; }

    .nt-acctneed { margin-top: 8px; font-size: var(--fs-caption); }

.nt-workside {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

/*  ══ v31.161 — THE SEARCH THAT FOUND NOTHING ══════════════════════════════
    It sits in the RESULTS AREA, directly under the search box, because that is
    where the reader is looking. `.nt-noresultacts` uses the toolkit equal-width
    row so the action matches every other button row on the page. */
.nt-noresulttxt { line-height: 1.5; }

.nt-noresultq { color: var(--nv-gold); }

.nt-noresultacts { margin-top: 12px; }

/*  the entity is a GROUPING label, not a destination — v1's company node has a
    tooltip and no notes of its own — so it is the house row in the muted ink
    and takes no pointer. */
.nt-entrow { color: var(--nv-ink-3); cursor: default; }

/*  ⚠⚠ v31.166 — THE CATALOG ROW. Like the entity row it is a grouping label and
    never a destination, so it takes no pointer. It is a shade STRONGER than the
    entity beneath it rather than weaker: it is the top of the tree now, and four
    of them are always on screen, so they are what the eye should land on first.
    ⚠ `.nt-catempty` is a catalog this search did not match. It stays VISIBLE —
    that is the whole point of drawing all four — but it is dimmed and carries
    neither twisty nor count, so it reads as "nothing here" rather than as a node
    that will not open. */
.nt-catrow { color: var(--nv-ink-2); cursor: default; font-weight: 300; }

/*  ⚠⚠⚠ v31.166 — THE FOUR CATALOG ROWS HOLD STILL AND THE OPEN SUBTREE SCROLLS
    INSIDE ITS SHARE. Owner: *"the four catalog nodes are always visible"* AND,
    one round earlier, `max-height: 350px` on this card. MEASURED, both of his
    numbers at once: with the subtree in the card's own scroller, ONE catalog was
    in view and 298px sat below the fold — the DOM had four, the screen had one.
    Making the card taller would break his 350; dropping a catalog would break
    the ask. Neither is necessary: the rows are fixed-size flex children and the
    body takes the remainder, so all four survive ANY card height.
    ⚠ `min-height: 0` is what makes the inner scroller work at all — a flex child
      defaults to `min-height: auto` and will not shrink below its content, so
      without it the body pushes the catalogs out exactly as before. */
.nt-tree.nt-treefix .nt-treescroll { display: flex; flex-direction: column; }

.nt-cat { flex: 0 0 auto; display: flex; flex-direction: column; min-height: 0; }

    /*  ⚠⚠ `0 1 auto`, NOT `1 1 auto` — GROW WOULD UNDO v31.165's ITEM 5. With
        `flex-grow: 1` the open catalog stretched to fill the cap, so the card
        was ALWAYS 350px and "size naturally to their content" was gone one
        round after he asked for it (caught by that round's own gate: content
        294, box 350). Shrink-only gives both asks at once — a short tree ends
        where its rows end, a tall one shrinks the body and scrolls it, and the
        four catalog rows never move in either case. */
    .nt-cat.nt-catopen { flex: 0 1 auto; }

.nt-catbody { flex: 0 1 auto; overflow-y: auto; overflow-x: hidden; min-height: 0; }

    .nt-catrow.nt-catempty { color: var(--nv-ink-3); opacity: .55; }

/*  ⚠⚠⚠ A COUNT MUST NOT SET THE ROW HEIGHT, FOR THE SAME REASON THE TWISTY
    MUST NOT. The house `.badge` is 28px tall (tokens.css:431), and inside a
    tree row that is 28 + 5 + 5 of the row's own padding — MEASURED 38px
    against the 28.00px every other row keeps, which is the number the country
    picker's cap ("14 whole rows in 400px") is built on and which the owner has
    twice set the row font against without moving.

    So the badge is brought inside the row's 18px line box rather than the row
    being allowed to grow around it. Scoped to `.acc-tree-row`, so the badge is
    untouched everywhere else in the app. */
.acc-tree-row .badge {
    height: 18px;
    min-height: 0;
    min-width: 20px;
    padding: 0 6px;
    font-size: 11.5px;
    line-height: 18px;
    flex: 0 0 auto;
}

/*  v1 prefixes a note leaf with ✓ (`"✓ " + folderName`) so it is never mistaken
    for a folder. The mark takes the house twisty slot — the 12px column that
    must never set the row height — and is green rather than gold so a leaf
    reads differently from an open branch at a glance. */
.nt-leafmark { color: var(--acc-green, #3fca85); }

/*  ⚠⚠ A NOTE THE READER MAY NOT OPEN IS SHOWN AND NOT LINKED — v1's tree has
    no privacy test at all and prints every user's "Me only" titles. Dimmed,
    no pointer, no href, so the shape of the folder stays honest without
    offering a way in. */
.nt-leaflocked { opacity: .5; cursor: default; }

    .nt-leaflocked .nt-leafmark { color: var(--nv-ink-3); }

/* ── NOTES LIST ─────────────────────────────────────────────────────────── */
.nt-item { cursor: pointer; }
.nt-item.on { background: rgba(232,167,92,.07); border-radius: 10px; }
.nt-item.on .t { color: var(--nv-gold-bright, var(--nv-gold)); }
.nt-marks { display: flex; align-items: center; gap: 9px; color: var(--nv-ink-3); }
.nt-mark { display: inline-flex; align-items: center; gap: 3px; }
.nt-mark.gold { color: var(--nv-gold); }
.nt-mn { font-size: 12px; font-weight: 200; }
.nt-locked .t, .nt-locked .ic { opacity: .55; }
.nt-recent { display: flex; flex-direction: column; gap: 8px; }

/* ── THE NOTE ───────────────────────────────────────────────────────────── */
.nt-crumb { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-bottom: 10px; }
/*  ⚠ v31.184 (owner) — 26px, up from 13. SIZE ONLY: nothing else in this rule
    moved, and the separator beside it keeps its own 13px on purpose (see
    `.nt-crumbsep` below) because he named this selector and no other. */
.nt-crumbbtn {
    background: transparent; border: 0; padding: 0; font-family: inherit;
    font-size: 26px; font-weight: 200; color: var(--nv-ink-3);
}
.nt-crumb-acc { color: var(--nv-gold); }

/*  ⚠ v31.187 (owner, N-39) — *"Bump the separator to match."* 13px between two
    26px labels put the `›` on the baseline of neither and let it wrap onto a
    line of its own ahead of the folder name. It is the crumb's punctuation, so
    it takes the crumb's size. */
.nt-crumbsep { color: var(--nv-ink-3); font-size: 26px; }
.nt-crumbedit {
    margin-left: auto; font-size: 12px; font-weight: 200; color: var(--nv-ink-3);
    border: 1px solid rgba(104,152,232,.28); border-radius: 999px; padding: 2px 10px;
}
.nt-title { font-size: 24px; font-weight: 200; color: var(--nv-ink-1, #e9eefc); margin: 0 0 8px; }
.nt-titlefield { margin-bottom: 10px; }
.nt-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 13px; font-weight: 200; color: var(--nv-ink-2); }
.nt-av, .nt-av2 {
    width: 26px; height: 26px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 11px; font-weight: 300; color: var(--nv-gold);
    border: 1px solid rgba(232,167,92,.4); background: rgba(232,167,92,.08);
}
.nt-av2 { flex: 0 0 46px; width: 38px; height: 38px; font-size: 13px; }
.nt-dot { color: var(--nv-ink-3); }
.nt-tags-live { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.nt-tagchip { height: 28px; padding: 0 10px; gap: 6px; }
.nt-x { color: var(--nv-ink-3); font-size: 15px; }
.nt-addtag { height: 28px; padding: 0 11px; border-style: dashed; }
.nt-tagsuggest { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 8px; }
.nt-tagsuggest .chip { height: 26px; padding: 0 10px; }
.nt-newtag { flex-basis: 100%; }
/*  ⚠ v31.159 — `.nt-flags` and its chips are gone with the row the owner
    asked to remove. A rule kept for markup that no longer exists is the
    next reader's false lead. */

.nt-body { font-size: 15px; font-weight: 200; line-height: 1.6; color: var(--nv-ink-2); }
.nt-body p { margin: 0 0 12px; }
.nt-body ul { margin: 0; padding-left: 20px; }
.nt-body li { margin-bottom: 6px; }
.nt-rted, .nt-secfree { min-height: 150px; height: auto; }
.nt-secfree { min-height: 70px; }

/* ── SECURE INFORMATION ──────────────────────────────────────────────────
   ⚠ THE OWNER'S RULE: the difference between ordinary note content and
     encrypted content must be unmistakable, and nothing may imply that
     secure values are held as plain text. So this card carries its own gold
     edge, its own lock, and says in words what happens to the value.       */
.nt-secure { border-color: rgba(232,167,92,.42); background: rgba(232,167,92,.035); }
.nt-secstate { color: var(--nv-gold) !important; }
.nt-seclock { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.nt-lockbadge {
    flex: 0 0 52px; height: 52px; border-radius: 14px;
    display: flex; align-items: center; justify-content: center;
    color: var(--nv-gold); border: 1px solid rgba(232,167,92,.4); background: rgba(232,167,92,.08);
}
.nt-locktxt { flex: 1 1 200px; min-width: 0; }
.nt-locktxt .t { font-size: 15px; font-weight: 200; color: var(--nv-ink-2); }
.nt-locktxt .s { margin-top: 3px; }
.nt-reveal { width: auto; padding: 0 22px; height: 44px; flex: 0 0 auto;
             border: 1px solid rgba(232,167,92,.45); background: rgba(232,167,92,.1); color: var(--nv-gold-bright, var(--nv-gold)); }
.nt-secstrip {
    display: flex; align-items: flex-start; gap: 9px; margin-bottom: 14px;
    font-size: 13px; font-weight: 200; line-height: 1.5; color: var(--nv-gold);
}
.nt-secstrip svg { flex: 0 0 16px; margin-top: 2px; }
.nt-secgrid { display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 640px) { .nt-secgrid { grid-template-columns: 1fr 1fr; } }
.nt-secnotes { margin-top: 12px; display: flex; flex-direction: column; gap: 4px; }
.nt-addsec { margin-top: 12px; height: 30px; border-style: dashed; }

/* ── DOCUMENTS ──────────────────────────────────────────────────────────── */
.nt-docacts { display: flex; align-items: center; gap: 2px; }
.nt-drop {
    margin-top: 12px; padding: 20px 16px; border-radius: 14px; text-align: center;
    border: 1px dashed rgba(104,152,232,.4); background: rgba(18,30,56,.22);
    color: var(--nv-ink-3);
}
.nt-drop .t { font-size: 15px; font-weight: 200; color: var(--nv-ink-2); margin-top: 8px; }
.nt-drop .s { margin-top: 4px; }

/* ── ACCESS ─────────────────────────────────────────────────────────────── */
.nt-vis { flex-wrap: wrap; }
.nt-visnote { margin-top: 10px; }
.nt-people { margin-top: 12px; border-top: 1px solid rgba(104,152,232,.13); }
.nt-check {
    width: 24px; height: 24px; border-radius: 7px; display: inline-flex;
    align-items: center; justify-content: center; font-size: 13px;
    border: 1px solid rgba(104,152,232,.4); color: transparent;
}
.nt-check.on { border-color: var(--acc-green, #3fca85); color: var(--acc-green, #3fca85); background: rgba(63,202,133,.1); }

/* ── SHARE ──────────────────────────────────────────────────────────────── */
.nt-inmailnote {
    display: flex; align-items: flex-start; gap: 9px; margin-bottom: 14px;
    font-size: 13px; font-weight: 200; line-height: 1.5; color: var(--nv-ink-2);
    padding: 10px 12px; border-radius: 12px;
    border: 1px solid rgba(87,164,240,.32); background: rgba(87,164,240,.06);
}
.nt-inmailnote svg { flex: 0 0 18px; margin-top: 1px; color: var(--acc-blue, #57a4f0); }
.nt-recips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.nt-sharepv { margin-top: 14px; display: flex; flex-direction: column; gap: 9px; }
.nt-cb { display: flex; align-items: center; gap: 9px; font-size: 14px; font-weight: 200; color: var(--nv-ink-2); }
.nt-sharebtn { margin-top: 16px; }

/* ── ACTIONS ────────────────────────────────────────────────────────────── */
.nt-actions { display: flex; flex-direction: column; gap: 10px; }
@media (min-width: 640px) { .nt-actions { flex-direction: row; } .nt-actions .btn { flex: 1 1 0; } }
.nt-del { border: 1px solid rgba(224,110,110,.45); color: #e58b8b; background: transparent; }
.nt-owner, .nt-notowner { text-align: center; padding: 0 8px 8px; }

/* ── OVERLAYS ───────────────────────────────────────────────────────────── */
.nt-scrim {
    position: fixed; inset: 0; background: rgba(3,6,14,.66);
    backdrop-filter: blur(3px); z-index: 40; display: none;
}
.nt-sheet {
    position: fixed; z-index: 41; display: none;
    left: 12px; right: 12px; bottom: 12px;
    background: linear-gradient(160deg, rgba(20,32,58,.98), rgba(10,16,32,.99));
}
@media (min-width: 640px) {
    .nt-sheet { left: 50%; right: auto; bottom: auto; top: 50%; width: 460px; transform: translate(-50%, -50%); }
}
.nt-sheet .cact { margin-top: 4px; }
.nt-sheet .cact .btn { flex: 1 1 0; }

/* ══ STATE MACHINE ═══════════════════════════════════════════════════════
   Every visibility rule the mock-up needs, in one place, so a reviewer can
   see exactly which states exist and what each one changes.               */
.nt-editonly, .nt-secopen, .nt-people, .nt-notowner, .nt-editedonly,
.nt-tagsuggest, .nt-recips, .nt-sharepv { display: none; }

body.mode-edit .nt-viewonly { display: none; }
body.mode-edit .nt-editonly { display: flex; }
body.mode-edit .nt-tagsuggest { display: flex; }
body.mode-edit span.nt-editonly, body.mode-edit .nt-x.nt-editonly { display: inline; }
body.mode-edit .nt-editor { display: block; }
body.mode-edit .nt-titlefield { display: flex; }

body.edited .nt-editedonly { display: inline; }

body.sec-open .nt-seclock { display: none; }
body.sec-open .nt-secopen { display: block; }
body.sec-open .nt-secstate::after { content: " · unlocked"; }

body.vis-people .nt-people { display: block; }
body.vis-people .nt-vis .chip.on { background: none; border-color: rgba(104,152,232,.28); color: var(--nv-ink-2); }
body.vis-people .nt-vispeople { background: rgba(232,167,92,.14); border-color: rgba(232,167,92,.45); color: var(--nv-gold-bright, var(--nv-gold)); }
body.vis-people .nt-visnote { display: none; }

body.share-live .nt-recips { display: flex; }
body.share-live .nt-sharepv { display: flex; }

body.not-owner .nt-notowner { display: block; }
body.not-owner .nt-owner { display: none; }
body.not-owner .nt-del, body.not-owner .nt-save { display: none; }

/*  ⚠ v31.159 — `.nt-flags` removed on the owner's word; the selector
    dropped with it rather than being left pointing at nothing. */
body.is-new .nt-title, body.is-new .nt-meta { display: none; }
body.is-new .nt-crumbedit { border-color: rgba(232,167,92,.5); color: var(--nv-gold); }

/* focus ring — the state's subject card, so a reviewer can see which one
   each state is about without reading the label */
.nt-focus { box-shadow: 0 0 0 1px rgba(232,167,92,.55), var(--shadow-card); }

body.sheet-del .nt-scrim, body.sheet-private .nt-scrim,
body.sheet-shared .nt-scrim, body.sheet-deleted .nt-scrim { display: block; }
body.sheet-del .nt-sheet-del,
body.sheet-private .nt-sheet-private,
body.sheet-shared .nt-sheet-shared,
body.sheet-deleted .nt-sheet-deleted { display: block; }

/* ══ CORRECTIONS — found by rendering it, not by reading it ═════════════ */

/*  ⚠⚠⚠ THE MOCK-UP DOES **NOT** MAKE `.scroll` A SCROLLER, AND THAT WAS A
    REAL FINDING RATHER THAN A STYLE CHOICE. The first writing added
    `overflow-y: auto` to it and nothing moved. `app.css:86` sets
    `.app .scroll { overflow: visible; flex: initial; }` at higher specificity,
    and the sheet says so in its own words at 8816: *"`overflow: visible`,
    `.scroll` included, despite the name."*

    So in V2 THE DOCUMENT SCROLLS, not an inner box. Anything built here has to
    scroll the document too — a Notes page that introduced its own inner
    scroller would behave differently from every other screen in the app. */

/*  ⚠⚠⚠ v31.156 — THIS RULE IS REVERSED, ON THE OWNER'S WORD.
    It used to read `flex: 0 0 auto`, on the reasoning below:

      "`.chips > .chip { flex: 1 1 0 }` makes every chip the SAME width, which
       is right for 3-4 short words and wrong here: 'Selected people' was being
       squeezed until it broke onto two lines inside its own pill."

    The squeezing was real; the conclusion was wrong. The answer to a label
    that will not fit is an ELLIPSIS, not an opt-out from equal widths —
    which is precisely what the owner asked for: *"must have the btns same
    width … if secure information text does not fit, please make ellipsis."*

    ⚠ So these three rows now inherit `.chips > .chip` (tokens.css:479 — the
      house has had equal-width chips all along) and take their ellipsis from
      the `.nv-eqrow` toolkit rule. `white-space: nowrap` STAYS: without it the
      text wraps instead of ellipsising, which is the two-lines-in-a-pill
      failure the old comment describes. */
.nt-vis .chip, .nt-filters .chip, .nt-tagrow .chip {
    white-space: nowrap;
}

/*  On a desktop the browse column HOLDS STILL and the note scrolls past it -
    otherwise reading a long note scrolls the account tree off the screen and
    the workspace stops feeling like one place. Sticky against the document
    scroller, which is the one the app actually uses. */
@media (min-width: 1024px) {
    .nt-browse {
        position: sticky;
        top: 12px;
        max-height: calc(100dvh - 24px);
        overflow-y: auto;
        padding-right: 4px;
    }

    /*  ⚠⚠⚠ v31.158 — WITHOUT THIS THE 350px ACCOUNTS CARD IS NOT 350px.
        This column is a flex column WITH A max-height, and a flex child's
        `flex-shrink` is 1 by default — so `height: 350px` is only a starting
        size, and the moment the column's contents exceed the viewport the
        browser takes the difference out of the children. Putting the
        Frequently Used card back on the house type ladder grew it by 198px,
        the column overflowed, and the Accounts card silently became 246px
        while still declaring 350. The gate caught it; nothing in the CSS
        looked wrong, because nothing in the CSS was wrong.
        The column already scrolls — that is what `overflow-y: auto` is for —
        so no card in it should ever be squeezed to make room. */
    .nt-browse > * { flex: 0 0 auto; }
}

/* ── shipped-only: controls the mock-up showed as static markup ─────────── */
.nt-msg { border-color: rgba(63,202,133,.42); color: var(--acc-green, #3fca85); font-size: 14px; font-weight: 200; }
.nt-msg-noaccess, .nt-msg-notyours, .nt-msg-noheader,
.nt-msg-noaccount, .nt-msg-norecipient,
.nt-msg-sendfail { border-color: rgba(232,167,92,.45); color: var(--nv-gold); }

/*  ══ v31.184 (owner) — THE RED FACE OF THE MESSAGE BOX ══════════════════════
    *"The message 'name' + 'not found' should be displayed in the same pattern
    as the red 'pill' message box."*

    ⚠ THE COLOURS ARE THE HOUSE RED AND NOT A NEW ONE. `rgba(217,101,101,…)`
      with `#e79a9a` text is exactly what `.login-error` (app.css:381) and the
      Open Periods inline validation `.op-err-top` already use — three surfaces,
      one red, so "something was not found" reads the same wherever it appears.
    ⚠⚠ THE STRIP'S GREEN DEFAULT IS OUT-SPECIFIED, NOT EDITED. `.nt-msg` sets
      the green; these variants sit after it at the same weight, which is how
      the gold ones have always worked. */
.nt-msg-notfound {
    border-color: rgba(217,101,101,.45);
    background: rgba(217,101,101,.12);
    color: #e79a9a;
}

    /*  ⚠ `.muted` sits on the text div inside this card and out-specifies the
        card's own colour, so the message read grey inside a red box — measured
        on screen, not assumed. Both halves of the sentence are the message. */
    .nt-msg-notfound .nt-noresulttxt { color: #e79a9a; }
    .nt-msg-notfound .nt-noresultq { color: #f2c2c2; }
.nt-itemlink { text-decoration: none; color: inherit; display: block; }
.nt-item.on .nt-itemlink { color: var(--nv-gold-bright, var(--nv-gold)); }

/*  ⚠⚠⚠ v31.158 (owner) — "purple under line and weird blue underline".
    Measured off his screenshot: the underline pixels are #551A8B and #0000EE,
    which are Chrome's OWN :visited and :link colours. Purple simply meant he
    had already opened that note.

    THE CAUSE IS THE ELEMENT, NOT THE CLASS. The locked mock-up draws these
    rows as `<div class="row nt-item nt-freqitem">` and the tree nodes as
    static markup, because a mock-up does not navigate. What ships has to
    navigate, so both are `<a>` — same classes, same stylesheet, but an anchor
    arrives carrying UA link colour and `text-decoration: underline`, and
    ⚠ text-decoration PROPAGATES to descendants and cannot be cancelled by
    them, which is why the underline showed in link-blue under text that was
    correctly grey.

    ⚠⚠ THE LINE ABOVE PROVES I HAD ALREADY MET THIS AND FIXED ONE OF THREE.
    `.nt-itemlink` is in this very section, added for this very reason, while
    `.nt-freqitem` and `.nt-nodebtn` were left as the mock-up wrote them. The
    house rule is the owner's own, from v29.6 on `.chip`: "a chip is often an
    <a>; nothing here is ever underlined". All three now say so together. */
/*  ⚠ v31.160 — `.nt-nodebtn` dropped from this list: the tree rows are the
    house `.acc-tree-row` now and `a.acc-tree-row` carries the same
    `text-decoration: none`, from the same v29.6 ruling. */
.nt-freqitem { text-decoration: none; }
a.nt-freqitem { color: inherit; }
.nt-treehint { padding: 6px 2px 8px; }
.nt-inline { display: inline; }
.nt-tagin { height: 28px; width: 96px; padding: 0 10px; font-size: 13px; }
.nt-cbx { width: 22px; height: 22px; accent-color: var(--acc-green, #3fca85); }
/*  ⚠ v31.159 — `.nt-file` deleted. It was a local 13px style on the
    documents file input, which is exactly why the house gold
    "choose files" pill (`input.input[type=file]`, app.css:1668) never
    appeared here. The input carries `.input` now, like every other. */
.nt-upload { margin-top: 10px; }
/*  ⚠⚠⚠ v31.184 (owner, N-35.8) — `.nt-shareto` NOW OWNS ITS OWN SPACING.
    It used to be written `class="nt-people nt-shareto"`, borrowing the access
    list's margin and hairline — and with them `.nt-people`'s `display: none`,
    which only lifts under `body.vis-people`. The share card therefore drew its
    heading, its `i` note and its Share button over an EMPTY recipient list on
    every note whose visibility was not "Selected people", and Share could only
    answer *"Choose who to share it with."* Measured: computed `display: none`
    in the share view. The two lines it was borrowing are now its own. */
.nt-shareto {
    margin-top: 12px;
    border-top: 1px solid rgba(104,152,232,.13);
    max-height: 260px;
    overflow-y: auto;
}

/*  the share list is the same two-line house row as the Send-to list, and gets
    the same fix — `.row .txt .t` / `.s` set type and ellipsis but never
    `display`, so name and address ran together on one line. */
.nt-shareto .nt-person .txt .t,
.nt-shareto .nt-person .txt .s { display: block; }

.nt-empty { text-align: left; }

/*  ══ v31.183 (owner, N-35.4) — SEND TO ══════════════════════════════════════
    *"The field MUST be populated with email selected from Team members, same as
    checkbox pattern in calendar."*

    ⚠⚠⚠ IT IS **NOT** `.nt-people`, AND THAT IS DELIBERATE. `.nt-people` is
    `display: none` at app.css:12938 and only comes back under
    `body.vis-people` — it is the ACCESS list, which belongs to one visibility
    state. The recipient is a property of the note in every state, so reusing
    that class would have hidden this list on three of the four chips. Only the
    ROW styling is shared, and that already lives on `.nt-person`.
    ⚠ The checkbox is `input.nv-check` — the house NOVERA box, gold border and
      gold tick, which is the calendar's and therefore the one he named. */
/*  ⚠⚠⚠ v31.184 (owner) — SEND TO IS PART OF SHARING, SO IT SHOWS WITH SHARING.
    *"The Send to checkbox list should only be visible only when 'Share via
    email' is selected."* It stays where it is in the DOM — inside `ntForm`, so
    it saves with the note and a half-made choice survives a trip to another
    view — and only its VISIBILITY moves onto `body.view-share`. Putting the
    markup itself inside the share card was not open to us: that card is its own
    `<form>`, and a form cannot nest. */
.nt-sendto {
    display: none;
    margin-top: 14px;
    border-top: 1px solid rgba(104,152,232,.13);
    padding-top: 12px;
}

body.view-share .nt-sendto { display: block; }
.nt-sendlbl { display: block; margin-bottom: 6px; }
/*  ⚠ 256px, WHICH IS THE SHARE LIST'S 260 ROUNDED TO WHOLE ROWS. Measured at
    the owner's 1270: a two-line `.nt-person` is ~64px, so 220 cut the fourth
    row in half and the block read as damaged rather than as scrollable. */
.nt-sendlist { max-height: 256px; overflow-y: auto; }

/*  ⚠ MEASURED, NOT ASSUMED. `.row .txt .t` and `.s` (tokens.css:441/450) set
    type and ellipsis but NOT display, so they are inline spans by default — the
    name and the address ran together as one line of text here. Every other
    two-line row in the app gets `block` from somewhere else (`.nt-item .t` is an
    `<a>`), so this list has to say it for itself. */
.nt-sendlist .nt-person .txt .t,
.nt-sendlist .nt-person .txt .s { display: block; }
.nt-sendhint { font-size: 13px; font-weight: 200; margin-top: 6px; }

/*  ══ v31.184 (owner) — FIND AND ADD SHARE ONE ROW ═══════════════════════════
    *"Move the add '+' icon to the same vertical position but to the row below
    which contains 4 card views."* The + left the app header and landed here, at
    the right-hand end of the row below it — the same x it always had, one row
    down. `align-items: flex-end` puts the button on the input's line rather
    than the hint's, so the two controls share a baseline. */
.nt-findrow { display: flex; align-items: flex-end; gap: 10px; min-width: 0; }
.nt-findrow .nt-find { flex: 1 1 auto; min-width: 0; }

/*  ══ v31.185 (owner) — THE + SITS ON THE NOTE HEAD CARD ═════════════════════
    *"Move the add '+' from its current position to the top right hand position
    of the main card with 'card nt-notehead'."*

    ⚠⚠ `align-items: flex-start` IS THE LOAD-BEARING LINE. The crumb is 26px
    since v31.184 and wraps to two lines on a long account name; centring would
    let the + drift down with the second line instead of holding the card's top
    right corner, which is the position he named.
    ⚠ `min-width: 0` on the crumb so the wrap happens inside it rather than
    pushing the button out of the card. */
.nt-crumbhead {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}

    .nt-crumbhead > .nt-crumb, .nt-crumbhead > .section { flex: 1 1 auto; min-width: 0; }
    .nt-crumbhead > .nt-add { flex: 0 0 auto; margin-top: -2px; }

/*  the Documents view on a note that has no id yet: the panel is drawn in full
    and the file pill is inert, because there is nothing to attach a file TO
    until the row exists. Dimmed, not hidden — the reader asked for this view. */
/*  v31.186 (owner, N-42) — the reader who may not attach is TOLD, not left
    looking at a control that would be refused. The house gold caution face,
    the same one `.nt-msg-noaccount` and the Open Periods hints wear. */
.nt-nodocedit {
    margin-top: 8px;
    padding: 10px 12px;
    border-radius: var(--r-card);
    border: 1px solid rgba(232,167,92,.45);
    background: rgba(232,167,92,.08);
    color: var(--nv-gold);
    font-size: 14px;
    font-weight: 200;
    line-height: 1.45;
}

.nt-dropoff { opacity: .55; }
.nt-dropoff input[type=file] { pointer-events: none; }

/*  ══ v31.183 (owner) — THE LIST HEADING CLIPS ═══════════════════════════════
    *"update the span that contains the h2 section name to the selected name.
    The label should be ellipsis."*

    ⚠⚠ `text-overflow` ALONE DOES NOTHING HERE. `h2.section` (tokens.css:295) is
    a flex row, and a flex item will not shrink below its own content until
    `min-width` is 0 — the default is `auto`. Without that line a long account
    name simply widened the heading and pushed the note count off the card,
    which is the shape the ellipsis is being asked to prevent.
    ⚠ `.more` is pinned so the count is what survives the squeeze, not the
      thing that gets squeezed. */
.nt-list .nt-listname {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nt-list > .section .more { flex: 0 0 auto; }
/*  ⚠ the v1-written secure payload: its own state, never blank, and the box
    beside it is read-only so it cannot be typed over and re-saved. */
.nt-seclegacy {
    margin-bottom: 12px; padding: 10px 12px; border-radius: 12px;
    font-size: 13px; font-weight: 200; line-height: 1.5;
    border: 1px solid rgba(232,167,92,.45); background: rgba(232,167,92,.08);
    color: var(--nv-gold);
}
.nt-delform { margin-top: 4px; }
.nt-delform .btn { width: 100%; }


/* ═══════════════════════════════════════════════════════════════════════════
   ⚠⚠⚠ TOOLKIT PATTERN — `.nv-eqrow`, THE EQUAL-WIDTH ROW   (v31.156, owner)
   ═══════════════════════════════════════════════════════════════════════════
   Owner: *"The row with secure information, documents, me only must have the
   btns same width. If secure information text does not fit, please make
   ellipsis."* — then the same for the note's tags, for "Who can see this", and
   for the tags on the right-hand panel. *"Can you make this a toolkit
   pattern."*

   ⚠ IT IS A CLASS CONTRACT, NOT A `.cshtml` DOOR, AND THAT IS DELIBERATE.
     Every other toolkit door (`_NvInfo`, `_NvPager`, `_NvDrill` …) renders a
     control it owns end to end. This one has to WRAP ARBITRARY CHILDREN — a
     flag with an icon, a tag with a remove ×, a visibility button, a chip that
     is a link — and a Razor PARTIAL cannot wrap child content: there is no
     render-body for partials. Inventing a model that enumerates every possible
     child would be a contract with a "step 3" in it, which is exactly the
     failure `toolkit-doors` warns about. A class costs one attribute and
     cannot be wired up wrongly.

   ── THE CONTRACT ───────────────────────────────────────────────────────────
     Put `.nv-eqrow` on the container. Every DIRECT child becomes one equal
     column and ellipsises rather than wrapping or overflowing.
     Add `.nv-eqrow-wrap` when the row should break onto further lines instead
     of squeezing (used by the tag rows, which can be long).

   ⚠⚠ THE TWO THINGS THAT MAKE IT ACTUALLY WORK, both learned the hard way:

     1. `flex: 1 1 0` — NOT `flex: 1`, and never `width` alone. `tokens.css:539`
        gives every `.btn` `width: 100%`, and a `width` on the child wins over a
        flex-basis of `auto`. Only a ZERO basis makes the columns equal.

     2. `min-width: 0` ON THE CHILD. A flex item's default `min-width: auto`
        refuses to shrink below its content, so `text-overflow: ellipsis` never
        fires and the row overflows instead. This is the single most common
        reason an ellipsis "does not work" in a flex row.
   ═══════════════════════════════════════════════════════════════════════════ */
.nv-eqrow {
    display: flex;
    gap: 8px;
    align-items: stretch;
    min-width: 0;
}

    .nv-eqrow > * {
        flex: 1 1 0;          /* equal columns — see note 1 above */
        min-width: 0;         /* lets the ellipsis fire — see note 2 above */
        width: auto;          /* beats tokens.css `.btn { width: 100% }` */
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        justify-content: center;
    }

        /*  a child that is itself a flex box (an icon + a label) needs the
            ellipsis applied to the LABEL, because the flex box will not
            ellipsise itself. */
        .nv-eqrow > * > span:not(.ic):not(.icw):not(.badge):not(.nt-mn) {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            min-width: 0;
        }

        /*  an icon must never be the thing that shrinks */
        .nv-eqrow > * > svg,
        .nv-eqrow > * > .ic,
        .nv-eqrow > * > .icw { flex: 0 0 auto; }

/*  ⚠ THE WRAPPING VARIANT. A tag row can hold eight tags; squeezing eight into
    one line makes eight ellipses and no information. These wrap, and the items
    on every line is the same width.

    ⚠⚠ `flex-grow` IS ZERO HERE, AND THAT IS THE WHOLE POINT. With `1 1 basis`
    the items on a line share the leftover space — fine for a full line, absurd
    for a short one: a single trailing tag stretched the full width of the card.
    **The screenshot caught that and the width assertions did not**, because a
    lone chip on its own line IS trivially "equal to every chip on that line".
    Zero grow means the basis is the width, every chip matches every other chip
    on every line, and a short last line simply ends early. */
.nv-eqrow-wrap {
    flex-wrap: wrap;
}

    .nv-eqrow-wrap > * {
        flex: 0 1 clamp(88px, 30%, 170px);
    }

/*  ⚠⚠ AND THE ROW MUST STILL BE READABLE ON A PHONE. Below 480 an equal split
    of four items is ~80px each, which ellipsises everything to two characters.
    The row wraps to two columns instead — still equal, still no overflow. */
@media (max-width: 479.98px) {
    .nv-eqrow { flex-wrap: wrap; }
    .nv-eqrow > * { flex: 1 1 calc(50% - 4px); }
}


/* ═══════════════════════════════════════════════════════════════════════════
   NOTES v2 — THE LOCKED MOCK-UP, IMPLEMENTED  (v31.156)
   ═══════════════════════════════════════════════════════════════════════════
   ⚠ LOCKED AND IMPLEMENTED at v31.156 on the owner's word — *"Please lock and
   load for next build"*, and his standing ruling that **"by next build" means
   ship this fix**. What was a proposed diff for review is now the sheet.
   Every rule uses existing tokens only; no new colour is invented.

   The existing Notes STATE MACHINE (app.css:12579) is extended, not replaced:
   the same pattern of "default hidden, opened by a class on <body>".
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── ITEM 6 · DISCOVERY MOVES RIGHT ─────────────────────────────────────────
   Only the column ORDER changes. The widths, the gaps and the breakpoints are
   the ones already agreed at v31.150 — 296px at 768, 340px at 1024 — so the
   note gains exactly the width the browse column used to hold and nothing
   else on the ladder moves. */
@media (min-width: 768px) {
    .nt-work { grid-template-columns: minmax(0, 1fr) 296px; }
}
@media (min-width: 1024px) {
    .nt-work { grid-template-columns: minmax(0, 1fr) 340px; }
}

/* ── ITEM 3 · THE THREE PILLS ───────────────────────────────────────────────
   One row, immediately above the working content, so the relationship reads as
   "three views of this note" rather than three sections that happen to follow
   each other. */




    /*  ⚠ THE SELECTED PILL HAS TO BE UNMISTAKABLE — the owner asked for that in
        as many words. Gold fill plus gold text, which is the same "this one"
        language the visibility chips already use, so nothing new is learned. */




/*  ══ THE VIEW SWITCH — the state machine, extended ═══════════════════════
    ⚠⚠⚠ ALL THREE PANELS STAY IN THE DOM. Only visibility changes, which is
    what makes the owner's "changing views must not lose unsaved note state"
    true by construction rather than by a save-and-restore routine that would
    have to be got right. A half-typed secure value survives a trip to
    Documents and back because it never left the page. */
/*  ⚠ v31.159 — `.nt-share` joins the view panels: it was an always-open
    card at the foot of every note and is now the fourth tab. */
.nt-content, .nt-secure, .nt-docs, .nt-share { display: none; }

body.view-note   .nt-content { display: block; }
body.view-secure .nt-secure  { display: block; }
body.view-docs   .nt-docs    { display: block; }
/*  ⚠ v31.159 (owner): *"Share via inMail should be a selection visible as a
    fourth selection after Documents."* It was an always-open card at the foot
    of every note; it is a view now, so it is drawn only when it is chosen. */
body.view-share  .nt-share   { display: block; }

/*  ⚠ the secure panel's own open/locked state is UNCHANGED and still nests
    inside it — `sec-open` continues to do exactly what it did. */

/* ── ITEM 2 · THE ACTION ROW ────────────────────────────────────────────────
   Save Note | Cancel | Delete on one line, in that order.

   ⚠⚠⚠ `tokens.css:539` GIVES EVERY `.btn` `width: 100%` — full-width buttons
   are the house default, mobile-first. So `flex: 0 1 auto` does NOT shrink a
   button to its text; the 100% width wins and each one claims a whole row.
   The existing rule already knew this and used `flex: 1 1 0`, which replaces
   the basis outright. Keeping that idiom rather than inventing a second one.
   (Cost of finding out the hard way: the first writing of this file put the
   three buttons on three rows and the probe said so.) */
.nt-actions {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

    .nt-actions .btn {
        flex: 1 1 0;
        width: auto;
    }

    /*  ⚠ A small separation before Delete. The owner asked for this order, so
        Delete stays where he put it — but a destructive control flush against
        the one people press to back out is how the wrong button gets clicked,
        and 6px is enough to read as "not part of that pair". */
    .nt-actions .nt-del { margin-left: 6px; }

/*  ⚠⚠ "PRESERVE THE ROW WHEREVER VIEWPORT WIDTH REASONABLY PERMITS."
    The existing breakpoint was 640, which stacks the row on every phone AND
    every small tablet. Three buttons need ~145px each to hold "Save Note" at
    the house 19px without ellipsis; that is satisfied from 480 up, so the row
    survives 160px lower than before. Below 480 they stack full width, which is
    the clean adaptation rather than three ellipsised stubs. */
.nt-actions { flex-direction: column; }

@media (min-width: 480px) {
    .nt-actions { flex-direction: row; }
}

@media (max-width: 479.98px) {
    .nt-actions .btn { flex: 1 1 auto; width: 100%; }
    .nt-actions .nt-del { margin-left: 0; }
}

/*  ══ v31.185 (owner) — 01-SCREEN: EDIT AND DELETE SHARE A ROW ═══════════════
    *"In 01-Screen ONLY ntDelBtn and notes.edit should share same row, just like
    in 02-Screen."*

    ⚠⚠⚠ THE RULE IS ABOUT THE **VIEW** STATE, NOT THE WHOLE ROW, and that is
    exactly what he wrote — Delete and Edit, which is TWO buttons. The edit state
    puts THREE there (Save Note · Cancel · Delete), and three at ~145px each need
    480px they do not have on a phone; the rule above stacks those and stays.
    `.nt-actions-view` is set from Razor on the not-editing state so the
    stylesheet can tell the two apart without counting children.
    ⚠⚠ THE DELETE BUTTON IS INSIDE A `<form>` — Save posts to one handler and
    Delete to another, so they cannot share one. The FORM is the flex child, so
    it is the form that must take a share of the row; styling `.btn` alone left
    it at its natural width and the pair did not divide evenly.
    ⚠ 479.98 IS THE ONLY BAND THAT CHANGES. From 480 up they were already a row
    (that is the "just like in 02-Screen" he is comparing against), so this
    override is scoped to the band below it and touches nothing else. */
@media (max-width: 479.98px) {
    .nt-actions.nt-actions-view { flex-direction: row; align-items: stretch; }
    .nt-actions.nt-actions-view > .btn,
    .nt-actions.nt-actions-view > .nt-delform { flex: 1 1 0; width: auto; margin-top: 0; }
    .nt-actions.nt-actions-view .nt-delform .btn { width: 100%; }
    .nt-actions.nt-actions-view .nt-del { margin-left: 0; }
}

/*  ══ v31.185 (owner) — 01-SCREEN: THE FOUR VIEWS, TWO BY TWO ════════════════
    *"In 01-Screen ONLY the four options at the top should be spread in 2 rows.
    The 4 buttons should be the same width to cover the viewport."*

    ⚠⚠ `.nv-tabs` is `repeat(auto-fit, minmax(92px, 1fr))` (app.css:8780), which
    on a 390px phone fits THREE across (3×92 + 2×8 = 292) and drops the fourth
    onto a row of its own — three narrow chips over one wide one, which is the
    uneven shape he is looking at. `repeat(2, 1fr)` states the 2×2 outright, so
    all four are the same width and together they span the column.
    ⚠ 767.98 IS 01-SCREEN's OWN EDGE on the house ladder (01 ≤767 · 02 768–1023),
    so 02-Screen keeps the single row it has today. */
@media (max-width: 767.98px) {
    .nt-views { grid-template-columns: repeat(2, 1fr); }

    /*  ══ v31.187 (owner, N-39) — *"cap the crumb on 01-Screen."* ═══════════
        MEASURED at 390px before this: "Hikvision Czech Republic › Security /
        Access" took THREE lines at 26px and pushed the note title below the
        fold, so the phone opened on a breadcrumb rather than on the note.
        ⚠ 18px is the cap, not 13. It sits between the house body size and the
          26px he set, so the crumb still reads as the heading he asked for on
          the wide screens and stops being the whole first screen on a phone.
        ⚠⚠ THE SEPARATOR IS CAPPED WITH IT. That is the whole point of N-39 —
          the two sizes must move together or the `›` wraps alone again, which
          is the fault being fixed. */
    .nt-crumbbtn, .nt-crumbsep { font-size: 18px; }
}

/*  ══ v31.185 (owner) — THE TAGS CARD BELONGS TO TWO VIEWS ═══════════════════
    *"The tags card 'nt-workside' should be visible from the 'Notes' and 'Secure
    information' buttons and should be hidden in 'Documents' and 'Share via
    Inmail' selections."*

    ⚠ WRITTEN AS THE TWO STATES THAT HIDE IT, not as the two that show it. The
    resting state of this page is `view-note` and the body carries exactly one
    `view-*` class at a time, so "hide on these two" leaves the card visible in
    every other case INCLUDING the moment before the script runs — a rule
    written the other way round would flash the card off on first paint. */
body.view-docs .nt-workside,
body.view-share .nt-workside { display: none; }

/* ── ITEM 4 · TAGS ARE CONTEXTUAL ───────────────────────────────────────────
   The global tag row is gone from the markup. What replaces it is scoped to
   the folder in hand, and it is not rendered at all until one is chosen. */
.nt-ctxtags { display: none; }
body.has-folder .nt-ctxtags { display: flex; }

/* ── ITEM 7 · FREQUENTLY USED ───────────────────────────────────────────────
   Deliberately lighter than the notes list: no icon column, no marks, two
   lines per row. It is a shortcut, not a second set of results. */
/*  ⚠ "KEEP THIS CARD LIGHTWEIGHT" — the owner's words, and ten two-line rows
    is 560px, which pushed the account navigator below the fold on a 1270
    screen. The ten stay; the CARD is bounded instead, and scrolls inside
    itself. That is the `_NvCardScroll` pattern this toolkit already has, and
    it is the one place a scroller is right — app.css:86 makes the DOCUMENT the
    scroller everywhere else, so this must be opted into deliberately. */
.nt-freq .nt-freqlist {
    max-height: 296px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/*  ⚠⚠⚠ v31.158 (owner) — "I don't understand the font-sizes … I was expecting
    you would use locked in mock-up styles instead of introducing new unknown
    styling."  He is right, and this block was the offender.

    THE HOUSE ALREADY STYLES THIS EXACT ROW. `tokens.css:400` gives
    `.row .txt .t` = var(--fs-body) (18px) and `.row .txt .s` =
    var(--fs-caption) (16px) with the muted colour and the ellipsis — and the
    markup here is already `.row > .txt > .t/.s`, so all of it applied for
    free. The two overrides below were shrinking it to 13.5px/11.5px, which is
    a size pair that appears NOWHERE ELSE in the solution and puts the second
    line 4.5px under `--fs-caption`, whose own comment reads "captions —
    minimum". In one column the reader was getting three different title sizes:
    18px in the notes list, 15px in the tree, 13.5px here.

    ⚠ THE FIX IS A DELETION. Both overrides are gone and the row now takes the
    house pair, identical to the notes list directly below it — a Frequently
    Used row IS a note row, so it should not have a type scale of its own. */
.nt-freq .nt-freqitem {
    padding: 7px 10px;
    cursor: pointer;
    border-radius: 9px;
}

    .nt-freq .nt-freqitem:hover { background: rgba(104, 152, 232, .08); }


/*  ⚠ At 296px the heading and its "Top 10 · you" note fight for one line and
    both wrap. The note is a nicety; the heading is not. Below 1024 the note
    steps aside rather than making the title two lines. */
@media (max-width: 1023.98px) {
    .nt-freq .section .more { display: none; }
}

/*  the ✦ is the mark the AI cards already use elsewhere in the app */
.nt-aimark {
    color: var(--nv-gold-bright, var(--nv-gold));
    margin-right: 6px;
}

/*  ⚠ A LABEL IS NOT A COLUMN. `.nt-tagcap` ("Tags in Security / Access") and
    the "Existing tags" caption sit inside an `.nv-eqrow`, and without this they
    are sized as equal columns and ellipsised — the caption is the FIRST thing
    to get cut, which is the opposite of useful. Anything marked `.nv-eqrow-lbl`
    keeps its natural width and is never the thing that shrinks. */
.nv-eqrow > .nv-eqrow-lbl,
.nv-eqrow > .nt-tagcap,
.nv-eqrow > .muted {
    flex: 0 0 auto;
    overflow: visible;
    text-overflow: clip;
}

/*  ⚠⚠ DELETE IS WRAPPED IN ITS OWN <form>, SO THE FORM IS THE FLEX CHILD.
    `.nt-actions .btn { flex: 1 1 0 }` never reached it — the button inside was
    sized by a form that was itself content-width, which is why Delete rendered
    as a stub beside a full-width Edit. The FORM takes the column; the button
    fills it. (Two separate forms is not a choice: Save posts to the Save
    handler and Delete to the Delete handler, and forms cannot nest.) */
.nt-actions > form {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
}

    .nt-actions > form > .btn { width: 100%; flex: 1 1 auto; }

@media (max-width: 479.98px) {
    .nt-actions > form { flex: 1 1 100%; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   NOTES v31.157 — THE OWNER'S LAYOUT ROUND
   ═══════════════════════════════════════════════════════════════════════════ */

/*  ── THE VIEW DOT ─────────────────────────────────────────────────────────
    The "there is secure information" mark on the Secure tab. A brand gold dot,
    not a coloured pill: the tints are gone from this page entirely (Notes was
    the ONLY page in the solution using `tint-*`, which is why they looked
    foreign — the owner asked about the purple one and he was right about all
    three). */
.nt-vdot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--nv-gold);
    flex: 0 0 6px;
    margin-left: 2px;
}

/*  ── THE NOTE BODY AND ITS TAGS SHARE A ROW, FROM 04-SCREEN ───────────────
    Owner: *"Reduce the width of the notes Rich Text field and place the tag
    list card to the right of it. For 04 and 05-Screen … in the shared row, but
    for 01, 02 and 03-Screen they are stacked."*

    ⚠ THE RUNGS ARE THE HOUSE'S, NOT NEW ONES: 01 ≤767 · 02 768-1023 ·
      03 1024-1365 · 04 1366-1919 · 05 1920+. So the split starts at 1366 and
      everything below it stacks, which is exactly what he asked for and also
      what the widths allow — at 1024 the note column is ~562px and taking a
      third of it for tags would leave the editor too narrow to write in. */
.nt-workrow {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

@media (min-width: 1366px) {
    .nt-workrow {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 240px;
        gap: 14px;
        align-items: start;
    }
}

@media (min-width: 1920px) {
    .nt-workrow { grid-template-columns: minmax(0, 1fr) 280px; }
}

/*  ⚠ the tag card stacks its rows; inside it the chips still use `.nv-eqrow`,
    so they stay equal to each other in the narrower column too. */
.nt-tagcard { display: flex; flex-direction: column; gap: 10px; min-width: 0; }

/*  ── THE ACCOUNTS CARD ────────────────────────────────────────────────────
    Owner: *"The displayed Accounts list should have a max of 6 items and should
    be paged using the pager pattern. Height of the card should be fixed to
    350px height and content scroll vertically, no horizontal scroll."*

    ⚠⚠ THE HEIGHT IS FIXED, NOT CAPPED. `height` rather than `max-height`, so a
    two-account result and a fifty-account result occupy the same box and the
    Frequently Used card beneath them does not jump up and down as you type.
    ⚠ `overflow-x: hidden` is explicit: a long account name must ellipsise, and
      a horizontal scrollbar inside a 340px column is unusable. */
/*  ⚠⚠ v31.165 (owner) — `height` → `max-height`, HIS OWN BLOCK, VERBATIM.
    *"Cards in the right-hand column below the search area should not use a
    fixed height. Allow them to size naturally to their content, subject to an
    appropriate max-height."*

    ⚠ WHAT THIS ACTUALLY CHANGES: a fixed 350px card drew 350px of box around
    three accounts and a lot of empty space. As a MAXIMUM it is the ceiling it
    always should have been — short trees end where their rows end, long ones
    still cap and scroll at exactly the same place they did before.
    ⚠⚠ `.nt-browse > *` KEEPS ITS `flex: 0 0 auto` and that is now MORE load-
    bearing, not less. The v31.158 note on that rule explains why: this column
    is a flex column with a max-height, so a child's default `flex-shrink: 1`
    lets the browser take space out of it — which would squeeze a card that is
    already sizing to its content. */
.nt-tree.nt-treefix {
    /*  ⚠ v31.220 (owner, mid-round): *"Quick fix needed to style sheet, max
        height"* — 350px to 495px. v31.227 (owner): 495px to 540px. The rest of
        the rule is unchanged both times: it is the CAP that moved, not the
        layout. */
    max-height: 540px;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

    .nt-tree.nt-treefix > .section { flex: 0 0 auto; }

    /*  the rows scroll; the heading and the pager bar do not — the same
        arrangement `_NvPager`'s `wrap` mode makes for the history cards. */
    .nt-treescroll {
        flex: 1 1 auto;
        overflow-y: auto;
        overflow-x: hidden;
        overscroll-behavior: contain;
        min-height: 0;
    }

    /*  ⚠⚠⚠ v31.163 (owner) — THE TREE NODE READS AT THE SAME SIZE AS A
        FREQUENTLY USED ENTRY. *"Increase the font size of the tree nodes to
        match the note entries in Frequently Used."*

        A Frequently Used entry is the house two-line row: `.row .txt .t` at
        `--fs-body` (tokens.css:400). So that is the token used here, by name
        rather than by its current number — if the body token moves, the tree
        moves with it and this rule does not have to be found again.

        ⚠⚠⚠ SCOPED TO `.nt-tree.nt-treefix`, AND THAT SCOPE IS THE WHOLE POINT.
        `.acc-tree-row` is SHARED with the country picker and the
        chart-of-accounts panel, and its own note in this file records 14px as
        **the owner's own number** for those (17px at v31.66, revised to 14px
        at v31.85). Putting the new size on the shared class would have
        silently overturned that ruling on two panels he did not mention. Two
        trees, two sizes, and the Notes card is the one that changed.

        ⚠⚠ THE LINE BOX HAD TO GROW WITH IT, AND THAT MOVES THE ROW HEIGHT.
        The shared row is `line-height: 18px` + 5px of padding top and bottom =
        28.00px, and every note in this file about that height turns on
        font-size NOT being part of the sum. It stops being free here: an 18px
        glyph in an 18px line box clips its descenders, and `.acc-tree-nm` has
        `overflow: hidden`, so the clipping would be silent. The line box goes
        to 24px, which makes this tree's row 34px against the shared tree's 28.
        ⚠ THAT IS A DELIBERATE, MEASURED CONSEQUENCE, not an oversight: a
        bigger font in a fixed-height row is not possible, and the owner asked
        for the bigger font. The chart panel's "14 whole rows in 400px" cap is
        untouched because that panel is not in this scope. */
    .nt-tree.nt-treefix .acc-tree-row {
        font-size: var(--fs-body);
        line-height: 24px;
    }

    /*  ⚠ THE TWISTY AND THE BADGE DO NOT GROW WITH THE LABEL. The twisty is a
        12px gold state mark whose own rule says it must never set the row
        height, and the badge was scoped to 18px at v31.160 for exactly that
        reason. Both are re-stated here so the larger font cannot drag them up
        by inheritance. */
    .nt-tree.nt-treefix .acc-tree-tw { font-size: 12px; line-height: 24px; }
    .nt-tree.nt-treefix .acc-tree-row .badge { font-size: 11.5px; line-height: 18px; }

    /*  ⚠ v31.160 — was `.nt-nodename`; the house row's own `.acc-tree-nm`
        already ellipsises, so this only re-states it inside the fixed card
        where the column is narrowest. */
    .nt-tree.nt-treefix .acc-tree-nm {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    /*  ⚠ the pager bar the toolkit inserts sits OUTSIDE the scroller, pinned to
        the bottom of the fixed card, so it never scrolls away. */
    .nt-tree.nt-treefix .nt-treepager { flex: 0 0 auto; margin-top: 8px; }

/*  ── FREQUENTLY USED — five rows, heading on two lines ────────────────────
    Owner: *"Show only five frequently used items. Top 5. The notes.freqTop and
    notes.freqUsed/freqNote should be in two rows."* */
.nt-freq .section {
    display: block;
}

    .nt-freq .section .more {
        display: block;
        margin: 2px 0 0;
        text-align: left;
    }

/*  five rows need no inner scroller — the cap was there for ten. */
.nt-freq .nt-freqlist { max-height: none; overflow: visible; }

/* ═══════════════════════════════════════════════════════════════════════════
   v31.173 (batch b347) — OPEN PERIODS · ENTITY LEVEL
   `/financials/periods`. The rules the owner LOCKED in
   `docs/openperiods-mockup.html`, moved into the shipped sheet so the mock-up
   and the running page cannot drift apart — the same arrangement the Notes
   rules ended in at v31.156.

   ⚠⚠⚠ THE TWO BREAKPOINTS ARE CONTAINER QUERIES, NOT MEDIA QUERIES, AND THAT
   IS THE ONE CHANGE FROM THE LOCKED FILE. The mock-up drew the page in the
   bare app shell; the shipped page carries `_FinPanel`, the 260px ledger rail
   every other page under the Ledger node has, so the content column is
   narrower than the window by an amount that changes at three rungs. Sizing
   the cards off the WINDOW would have re-created, at a different width, the
   very fault the mock-up screenshot caught — a native `type="month"` clipped
   to "December 202". **Ask the box how wide it is, not the window** (the
   AI-tokens container rule). The card design is untouched; only the thing that
   decides "is there room for two" moved.

   ⚠⚠ `container-type: inline-size` also makes the element a containing block
   for `position: fixed` descendants. Nothing on this page is fixed — the
   action bar is STICKY and the entity sheet is hoisted to <body> by
   `_NvEntity` — so this is safe here and must be checked again before the
   property is put on any card that hosts a sheet.
   ═══════════════════════════════════════════════════════════════════════════ */

.op-work {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    /*  ⚠⚠⚠ THE GUTTER IS THE PRICE OF A PERMANENT BAR (v31.174). A sticky
        bottom bar is painted OVER whatever is behind it, so with the bar no
        longer hidden until dirty it sat across the last rows of Closing Items
        from the first paint — two checklist rows and the card's own note were
        unreachable at every width. The column therefore ends in a gutter as
        tall as the bar, so the page can always scroll far enough for its last
        row to clear. ⚠ Re-measure if the bar gains a second line. */
    padding-bottom: 92px;
    min-width: 0;
    container-type: inline-size;
    container-name: opwork;
}

/* ── the entity strip ─────────────────────────────────────────────────────
   The head chip is app-wide furniture and reads as "where I am". This page is
   explicitly ENTITY-SPECIFIC — every value on it belongs to one CompCode — so
   the entity is also stated once in the working area, as the SUBJECT of the
   page rather than as chrome. */
.op-entity {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

    .op-entity .op-entname {
        font-size: var(--fs-h2);
        font-weight: 300;
        color: var(--nv-ink);
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .op-entity .op-entcode {
        font-size: var(--fs-caption);
        color: var(--nv-ink-3);
        flex: 0 0 auto;
    }

    /*  ⚠⚠⚠ A HOUSE BUTTON CARRIES NO HORIZONTAL PADDING. `tokens.css:580`
        gives `.btn` `width: 100%` with `justify-content: center` and no
        padding at all — the full width IS the padding. The moment a button is
        taken off 100% its text sits flush against its own border, which is
        what the mock-up's first screenshot showed. Anything that sets
        `width: auto` on a `.btn` must supply the padding itself. Same family
        as the `flex: 1 1 0` trap of v31.155, one property along. */
    .op-entity .op-entpick {
        margin-left: auto;
        flex: 0 0 auto;
        width: auto;
        padding: 0 18px;
    }

/* ── the General Ledger card — the master window ──────────────────────────
   First, and the only card on the page carrying the brand gold, so "everything
   else can follow this" is legible before a word is read. */
.op-gl {
    border-left: 3px solid var(--nv-gold);
}

/* ── a labelled pair ──────────────────────────────────────────────────────
   V1 puts five values in one undifferentiated column. The owner's brief asks
   for the two CONCEPTS to be separated more clearly than V1 does, so each pair
   is its own titled group with the format stated and an explicit arrow. */
.op-grp + .op-grp { margin-top: var(--sp-4); }

.op-grptitle {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--fs-caption);
    color: var(--nv-ink-2);
    margin-bottom: var(--sp-2);
}

    .op-grptitle .op-fmt {
        margin-left: auto;
        font-size: 12px;
        color: var(--nv-ink-3);
        letter-spacing: .04em;
        white-space: nowrap;
    }

/*  STACKED BY DEFAULT and side by side only when the CARD can hold it. A
    native `type="month"` renders "December 2026" plus its own picker glyph in
    about 200px; two of those plus the arrow need roughly 430px of card. */
/*  ⚠⚠⚠ v31.175 (owner, item 1) — FROM AND TO SHARE A ROW, AND THE NUMBERS
    BEHIND IT WERE MEASURED, NOT ESTIMATED. Twice before this file guessed what
    a native `type="month"` needs — 210, then 184 — and both were wrong. The
    control was finally MEASURED in the running page:

        "September 2026" at 18px Poppins ...... 147px
        `.input` padding-left / -right ........  16 / 36
        ------------------------------------------------
        one control ...........................  199px

    ⚠ THE 36px RIGHT PADDING IS ALREADY THE PICKER GLYPH'S GUTTER — the earlier
    sums added another 30 on top of it and double-counted, which is how a
    control that needs 199 was recorded as needing 229.

    A 500px card (the owner's cap) has 500 − 40 padding − 2 border = **458** of
    content. Two controls + an 18px arrow + two 8px gaps = 2×199 + 34 = 432,
    so the General Ledger card fits with room to spare. A module card in a 2-up
    quadrant at 1270 is 427 wide = 385 of content, and 2×199 + 8 = 406 does NOT
    fit — which is why the padding below is tightened for THESE controls only. */
.op-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 6px;
    align-items: end;
}

    /*  ⚠⚠ SCOPED TO THE PAIR, NEVER TO `.input`. Widening a shared control to
        suit one page is the fault `changing-working-code` names; this touches
        nothing outside `.op-pair`. 26px still hosts the browser's own picker
        glyph (~20px) — VERIFIED by measuring the rendered control, not assumed.
            147 text + 10 + 26 = 183 per control
            2 × 183 + 8  = 374  ≤ 385  (a 427px module card)  ✓
            2 × 183 + 34 = 400  ≤ 458  (a 500px ledger card)  ✓            */
    /*  ⚠⚠⚠ `.op-pair input.input`, NOT `.op-pair .input` — AND THE FIRST
        WRITING'S RIGHT PADDING NEVER APPLIED AT ALL.
        `input.input[type="date"], input.input[type="month"]` (app.css ~5302)
        is specificity **0,2,1**; `.op-pair .input` is 0,2,0 and LOSES. The
        rule sat in the sheet looking correct while every control kept its 36px
        gutter — a silent no-op, found only by measuring a rendered control's
        computed padding.
        ⚠⚠ AND THAT GUTTER IS NOT SPARE ROOM. It hosts the house's own 18px
        gold calendar SVG at `background-position: right 10px center`, so the
        floor is 10 + 18 + a hair = **32**. Anything less puts the glyph on the
        text. 24 — the number the first writing reached for — would have done
        exactly that had it applied.
            "September 2026" 147 + 8 left + 32 right = **187 per control**
            a 2-up module card at 1270 gives 194  →  7px of margin  ✓        */
    .op-pair input.input {
        padding-left: 8px;
        padding-right: 32px;
    }

    /*  the arrow is DECORATION and it is the first thing to go when the card is
        narrow — the `From` and `To` hints already say which is which */
    .op-pair .op-arrow {
        display: none;
        color: var(--nv-ink-3);
        user-select: none;
        width: 18px;
        line-height: 34px;
        text-align: center;
        padding-bottom: 2px;
        transform: none;
    }

/*  ⚠ THE PHONE IS THE ONE RUNG THAT STILL STACKS. A 390px screen gives a card
    310 of content and two controls need 374 — no padding trick closes that, and
    a clipped date is worse than a second row. */
/*  ⚠ 373, NOT 389 — MEASURED AGAIN AFTER THE FIRST WRITING GOT IT WRONG. A
    2-up module card at 1270 is 427 wide, i.e. **385 of content**, and two
    controls need 2×183 + 8 = **374**. A threshold of 389 therefore stacked
    exactly the cards the owner asked to un-stack, while the maths said they
    fit. The rung that genuinely cannot take two is the phone: 350px card =
    310 of content, and no padding trick closes a 64px gap. */
@container opcard (max-width: 373px) {
    .op-pair {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--sp-3);
    }
}

/* ── current period — present, and deliberately quiet ─────────────────────
   The brief: "Also show Current Period, but it should not visually compete
   with the two posting-window ranges." So it is a caption line under the
   heading, never a third field box. */
.op-cur {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: var(--fs-caption);
    color: var(--nv-ink-3);
    margin: 2px 0 var(--sp-4);
}

    .op-cur b {
        font-weight: 400;
        color: var(--nv-ink-2);
    }

/* ── the module cards ────────────────────────────────────────────────────── */
.op-mods {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-4);
    /*  ⚠ EACH CARD TAKES ITS OWN HEIGHT. A grid stretches its items by
        default, so a module with its own window (four controls and a note)
        stretched the one beside it — which followed the ledger and needed a
        third of the room — leaving a card two thirds empty. Ragged bottoms are
        the honest rendering of cards that hold different amounts. */
    align-items: start;
}

/*  ⚠⚠⚠ A QUADRANT CARD IS DENSER THAN THE LEDGER CARD, AND THE 16px IS
    ARITHMETIC. Measured in the running page, "September 2026" — the longest
    value either control can ever render — is **156px** at 18px Poppins, so one
    control needs 156 + 8 + 24 = **188**. A 2-up module card at 1270 is 427
    wide; at the house 20px card padding that is 385 of content and two
    controls plus a 6px gap need 382 — a 3px margin, and the first writing
    MEASURED IT SHORT AT 189 < 192. Trimming this card's own padding to 16
    gives 393 of content and 193 per control: a 5px margin instead of a
    hairline. The General Ledger card keeps the house 20 — at 458 of content it
    has 214 per control and never needed the room. */
.op-mod {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: var(--sp-4);
    /*  ⚠⚠⚠ v31.175 (owner, item 4) — A QUADRANT CARD FILLS ITS QUADRANT. The
        owner's 500px cap and his "cards in Row 2 / Row 3 share a right edge"
        collide at 1920, where a quadrant is 539 wide: the cap held the right
        card to 500 and it finished **39px short** of everything else on the
        page. Measured, not noticed.
        ⚠ THE CAP STILL GOVERNS WHERE HE MEANT IT — the General Ledger card,
        which is what item 1 was about, and Closing Items beside it. A module
        card's width is set by the grid that owns it, and the grid is what the
        alignment ruling is about.
        ⚠⚠ IT ALSO BUYS THE ROOM ITEM 1 NEEDS at the wide rungs: 539 of card is
        505 of content and 249 per control against a need of 187.
        ⚠⚠⚠ THE OVERRIDE LIVES BELOW, AT (0,2,0), NOT HERE. `.op-mod` and
        `.op-card` are both (0,1,0) and `.op-card` is declared LATER, so a
        `max-width: none` written here loses to the cap and the card stayed at
        500 — the CSS-ordering trap, paid for a third time. Specificity is the
        fix, because it cannot be undone by moving a block. */
}

/*  see the note in `.op-mod`: (0,2,0) so file order cannot decide this */
.op-mods > .op-card { max-width: none; }

/*  ⚠ v31.174 (owner, item 1) — `max-width: 500px`, THE OWNER'S OWN RULE,
    APPLIED WHERE HE PUT IT. He wrote it on `.op-card`, which caps EVERY card on
    the page and not only the General Ledger one — and that is what makes the
    page "materially less wide and less dense", so it is left exactly as
    written rather than narrowed to `.op-gl`.
    ⚠⚠ IT INTERACTS WITH THE CONTAINER QUERY BELOW: a capped card can no longer
    reach the 500px its own `@container` rule needs for a side-by-side pair, so
    the pairs now stack at every width. That is a consequence of the cap, not a
    separate decision — see the note on `@container opcard`. */
.op-card {
    container-type: inline-size;
    container-name: opcard;
    position: relative;
    max-width: 500px;
}

.op-modhead {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

    .op-modhead .op-modname {
        font-size: var(--fs-h2);
        font-weight: 300;
        color: var(--nv-ink);
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/*  the switch sits at the TOP of the card, per the brief — V1 hides these
    below the fields where they read as an afterthought. Label first, control
    last, the whole row one 44px target. */
.op-swrow {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-height: 44px;
    margin-top: var(--sp-2);
    padding-top: var(--sp-2);
    border-top: 1px solid rgba(104,152,232,.13);
}

    .op-swrow .op-swlab {
        font-size: var(--fs-caption);
        color: var(--nv-ink-2);
        min-width: 0;
    }

    .op-swrow .acc-sw { margin-left: auto; }

/* ── inherited vs own — THE HEART OF THE REDESIGN ─────────────────────────
   ⚠⚠⚠ WHEN "Use General Ledger periods" IS ON, THE MODULE'S OWN CONTROLS ARE
   NOT RENDERED AS DISABLED BOXES. A greyed field says "this is your value, you
   just cannot reach it", which is the opposite of the truth: the values in
   force belong to the GENERAL LEDGER. So ON is a read-out that STATES what is
   inherited, and the reader never scrolls back up to find out.
   ⚠⚠ BOTH BLOCKS STAY IN THE DOM and only visibility changes — the same
   construction that made the Notes pills lose nothing at v31.155, and the
   reason a half-typed window survives a trip through the switch and back. */
.op-inherit {
    margin-top: var(--sp-3);
    padding: 10px 12px;
    border-radius: var(--r-card);
    border: 1px dashed rgba(104,152,232,.30);
    background: rgba(104,152,232,.06);
}

    .op-inherit .op-inhead {
        font-size: var(--fs-caption);
        color: var(--nv-ink-2);
        margin-bottom: 6px;
    }

.op-inrow {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: var(--fs-caption);
    color: var(--nv-ink-3);
    padding: 2px 0;
}

    .op-inrow .op-inlab { flex: 0 0 62px; }

    .op-inrow .op-inval {
        color: var(--nv-ink);
        font-variant-numeric: tabular-nums;
    }

.op-own { margin-top: var(--sp-3); }

/*  ⚠ ONE CLASS DRIVES BOTH STATES. `.op-independent` means "does NOT follow
    the ledger", so the default (no class) is the inherited read-out. The
    ledger card itself always carries `.op-independent` and has no
    `.op-inherit` block to hide. */
.op-mod .op-own { display: none; }
.op-mod .op-inherit { display: block; }
.op-mod.op-independent .op-own { display: block; }
.op-mod.op-independent .op-inherit { display: none; }

/*  a card that does NOT follow the ledger is marked in its header, so the
    answer to "which modules have their own posting windows?" is available from
    the top of the page without opening anything. */
.op-tag {
    flex: 0 0 auto;
    font-size: 12px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: var(--r-pill);
    border: 1px solid rgba(104,152,232,.32);
    color: var(--nv-ink-3);
    white-space: nowrap;
}

.op-mod.op-independent .op-tag {
    border-color: rgba(232,167,92,.45);
    color: var(--nv-gold);
}

/* ── inline validation, against the offending control ─────────────────────
   The brief is explicit: not a generic popup. The boxes of the offending pair
   carry the state and the message sits under the pair it belongs to, so the
   two cannot drift apart. */
.input.op-bad {
    border-color: rgba(217,101,101,.75);
    background: rgba(217,101,101,.07);
}

.op-err {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: var(--sp-2);
    font-size: var(--fs-caption);
    line-height: 1.45;
    color: #e59a9a;
}

    .op-err .op-errmark { flex: 0 0 auto; }

/*  v31.187 (owner, P-12) — "Changes discarded." Nothing failed and nothing
    succeeded, so it is neither `.op-ok` green nor `.op-err` red: it is the house
    gold caution, the same face `.nt-msg-noaccount` and `.nt-nodocedit` wear. */
.op-drop {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: var(--sp-3, 12px);
    padding: 10px 12px;
    border-radius: var(--r-card);
    border: 1px solid rgba(232,167,92,.45);
    background: rgba(232,167,92,.08);
    color: var(--nv-gold);
    font-size: var(--fs-caption);
    font-weight: 200;
    line-height: 1.45;
}

.op-err.op-err-top {
    padding: 10px 12px;
    border-radius: var(--r-card);
    border: 1px solid rgba(217,101,101,.40);
    background: rgba(217,101,101,.07);
    margin-top: 0;
}

/* ── unsaved changes ──────────────────────────────────────────────────────
   A dot on the card that changed and one bar that counts them by name.
   ⚠ THE BAR IS STICKY, NOT FIXED. A `position: fixed` bar inside a subtree
   whose ancestor carries a filter is positioned against THAT ancestor — the
   fault `_NvEntity` hoists its sheet out of the head to avoid. Sticky has no
   such dependency. */
.op-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--nv-gold);
    display: none;
}

.op-work.op-dirty .op-card.op-changed .op-dot { display: inline-block; }

.op-bar {
    position: sticky;
    bottom: 8px;
    z-index: 6;
    display: none;
    align-items: center;
    gap: var(--sp-3);
    margin-top: var(--sp-2);
    padding: 10px 14px;
    border-radius: var(--r-card);
    border: 1px solid rgba(232,167,92,.35);
    background: rgba(16,26,48,.96);
    -webkit-backdrop-filter: blur(18px);
    backdrop-filter: blur(18px);
    box-shadow: var(--shadow-card);
    flex-wrap: wrap;
}

.op-work.op-dirty .op-bar { display: flex; }

    .op-bar .op-barcount {
        font-size: var(--fs-caption);
        color: var(--nv-ink-2);
        min-width: 0;
    }

    .op-bar .op-baracts {
        margin-left: auto;
        display: flex;
        gap: var(--sp-2);
        flex: 0 0 auto;
    }

        /* ⚠ the no-padding rule again — see `.op-entpick` above */
        .op-bar .op-baracts .btn {
            width: auto;
            padding: 0 18px;
        }

/* ── saved ───────────────────────────────────────────────────────────────
   Confirms in the entity's own name, because the one mistake this page invites
   is editing the window of the company you did not mean. */
.op-ok {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--r-card);
    border: 1px solid rgba(88,179,104,.40);
    background: rgba(88,179,104,.08);
    font-size: var(--fs-caption);
    line-height: 1.45;
    color: var(--nv-ink-2);
}

    .op-ok .op-okmark {
        flex: 0 0 auto;
        color: var(--acc-green);
    }

/* ── THE TWO CONTAINER BREAKPOINTS ───────────────────────────────────────
   Measured, not chosen. A module card needs ~430px before its From/To pair can
   sit side by side without the native control clipping its own value, and two
   such cards plus the grid gap need ~900px of working column. */
/*  ⚠⚠⚠ BOTH NUMBERS ARE DERIVED FROM A MEASUREMENT OF THE SHIPPED SHELL, NOT
    CHOSEN. Measured working-column widths with `_FinPanel` in place:
        390 → 350 · 834 → 728 · 1024 → 624 · 1270 → 870 · 1366 → 950 · 1920 → 1078
    (1366+ only reaches 950 because this page reclaims the empty 390px AI track
    — see the page's own style block.)
    · TWO CARDS need 850, which puts 1270 — the width the owner works at — on
      two columns with ~427px cards.
    · A SIDE-BY-SIDE PAIR needs 500: a native `type="month"` renders
      "December 2026" plus its own picker glyph in about 210px, and a card
      spends 40 on padding, 18 on the arrow and 16 on the gap before the two
      boxes get anything. 430 was the first number here and it was WRONG — it
      would have given 196px boxes at 1366 and clipped the value, the exact
      fault the mock-up's screenshot caught.
    ⚠ Re-derive both if the card padding or the rail width changes. */
@container opwork (min-width: 850px) {
    .op-mods { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/*  ⚠ THE ARROW COMES BACK WHEN THE CARD CAN AFFORD IT — 2×183 + 18 + 16 = 400
    of content, i.e. a card of ~442. The General Ledger card (458) always can;
    a 427px module card cannot, and loses only an ornament. */
@container opcard (min-width: 442px) {
    .op-pair { grid-template-columns: minmax(0, 1fr) 18px minmax(0, 1fr); }
    .op-pair .op-arrow { display: block; }
}

@media (max-width: 560px) {
    .op-entity .op-entpick { margin-left: 0; }

    .op-bar .op-baracts {
        margin-left: 0;
        width: 100%;
    }

        .op-bar .op-baracts .btn {
            flex: 1 1 0;
            min-width: 0;
        }
}


/* ═══════════════════════════════════════════════════════════════════════════
   v31.174 (batch b348) — OPEN PERIODS, THE OWNER'S NINE REVISIONS
   ═══════════════════════════════════════════════════════════════════════════ */

/*  ── 1 & 2 · THE TOP ROW: GENERAL LEDGER | CLOSING ITEMS ──────────────────
    The owner's revised layout reads "General Ledger — max 500px | Closing
    Items". Below 900px of working column the two stack: a 500px card and a
    ten-row checklist cannot share a phone, and the checklist is the one that
    can wait. Container-driven for the same reason everything else here is —
    the ledger rail makes the window a liar about how much room there is. */
.op-top {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-4);
    /*  ⚠ STRETCH, NOT START (v31.175 item 2) — the two cards share a height and
        the taller one (the General Ledger) sets it. See `.op-cl`. */
    align-items: stretch;
}

/*  ⚠⚠⚠ 820, AND IT IS ARITHMETIC RATHER THAN TASTE. The first writing reused
    the 900 that governs the module grid, and at 1270 — the width the owner
    works at — the working column measures 870, so the two cards NEVER paired
    and Closing Items fell below a General Ledger card capped at 500 with a band
    of empty page beside it. The second column has to be worth having: 500 for
    the ledger + 16 of gap + ~300 for a readable checklist = 816. At 1270 that
    leaves Closing Items 354px (one column of ticks); at 1366 it is 434 and at
    1920 it is 562, where the list goes to two columns on its own container
    rule. Below 820 they stack, which is right — a 500px card and a ten-row
    checklist cannot share a phone. */
@container opwork (min-width: 820px) {
    .op-top { grid-template-columns: 500px minmax(0, 1fr); }
}

/*  Closing Items is NOT capped at 500 — it is the card that takes the space
    the General Ledger card gives back. ⚠ This is the one deliberate exception
    to the owner's `.op-card` cap, and without it the top row would leave a
    band of empty page beside two 500px cards. */
.op-closing {
    max-width: none;
    /*  a column, so the list can be the part that flexes and scrolls */
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/*  ⚠⚠⚠ v31.175 (owner, item 2) — THE CARD NEVER GROWS PAST THE LEDGER CARD.
    Owner: *"keep the card height fixed to the GL card and provide vertical
    scrolling inside the list area. The card itself should not become taller
    than the General Ledger card."*

    The mechanism is `flex: 1 1 0` on the list — a ZERO basis, the same idiom
    `.nv-eqrow` uses. With a zero basis the list contributes NOTHING to the
    card's intrinsic height, so the card's natural height is only its heading,
    its sub-line and its note; the General Ledger card is always taller, so IT
    sizes the grid row, and `align-items: stretch` then gives Closing Items
    exactly that height. The list takes whatever is left and scrolls.
    ⚠⚠ `min-height: 0` IS LOAD-BEARING — without it a flex item refuses to
    shrink below its content and the card grows anyway, which is the whole
    thing the owner asked not to happen.
    ⚠ THE ORDER MATTERS TOO: this is why `.op-top` switched from
    `align-items: start` to `stretch`. Start would leave the card its natural
    (short) height and the list would have no room at all. */
.op-cl {
    list-style: none;
    margin: var(--sp-3) 0 0;
    padding: 0 4px 0 0;
    display: grid;
    gap: 2px;
    align-content: start;
}

/*  ⚠⚠⚠ THE ZERO BASIS ONLY APPLIES WHERE THE TWO CARDS SHARE A ROW. Below
    820 of working column they STACK, and there is no General Ledger card
    beside Closing Items to borrow a height from — so `flex: 1 1 0` collapsed
    the list to nothing and left a 162px card holding a scrollbar and no
    checks. Measured, not spotted by eye.
    ⚠ Same threshold as `.op-top`'s own pairing rule, deliberately: the two
    must switch together or the card is sized for a layout it is not in. */
@container opwork (min-width: 820px) {
    .op-cl {
        flex: 1 1 0;
        min-height: 0;
        overflow-y: auto;
    }
}

/*  two columns as soon as the card can hold them — ten rows in one column is a
    scroll on a surface whose whole point is being read at a glance */
@container opcard (min-width: 520px) {
    .op-cl { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-4); }
}

.op-clrow { min-width: 0; }

.op-cllab {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 34px;
    padding: 2px 0;
    font-size: var(--fs-caption);
    color: var(--nv-ink-2);
    cursor: pointer;
    min-width: 0;
}

    /*  ⚠ THE WHOLE ROW IS THE TARGET, not the 16px box — the label wraps the
        input, so the text is part of the hit area for free and no `for`/`id`
        pair can drift out of step. */
    /*  ⚠⚠ v31.176 — THE LABEL WRAPS NOW, AND THAT IS BECAUSE THE TICK BECAME
        REAL. While the list was UI-only an ellipsis was a fair trade for a tidy
        row; now the reader is confirming *"Accruals and prepayments posted"*
        before an accounting period is closed, and **a checklist you act on may
        not be cut off mid-word** — there is no title, no hover on a phone, and
        no second place to read it.
        ⚠ IT COSTS SCROLL, NOT SIZE. The card's height is set by the General
        Ledger card beside it (the zero-basis idiom) and the list scrolls inside
        what is left, so a two-line row lengthens the scroll and moves nothing on
        the page. */
    .op-cllab > span {
        min-width: 0;
        overflow-wrap: anywhere;
    }

/*  ⚠ v31.175 (owner, item 2) — THE BOX ITSELF IS EMAIL'S. `.op-clbox` is now
    on `input.eml-sel`'s own selector list (search this file for `eml-sel`), so
    it inherits the transparent fill, the gold border and the scaling gold tick
    from ONE rule. All that is left here is the row's own geometry — and
    `accent-color` is GONE, because the shared rule sets `appearance: none` and
    an accent colour on an appearance-less control does nothing at all. */
.op-clbox {
    flex: 0 0 auto;
    margin: 0;
}

.op-clnote { margin-top: var(--sp-3); }

/*  ── 7 · CURRENT PERIOD — A PILL, NOT A FIELD ─────────────────────────────
    ⚠⚠⚠ THE POINT IS THAT IT DOES NOT LOOK LIKE THE THINGS AROUND IT. The four
    editable values are `.input`s — a 36px box, an inset fill, a border that
    lightens on focus. This has a padlock, a full-height rounded border, an
    uppercase label and a value in the display size, and no box a caret could
    sit in. The distinction is carried by the SHAPE, so it survives translation
    and cannot be undone by a stylesheet that changes a word. */
/*  ── 8b · CURRENT MONTH — THE PERIOD CONTEXT ──────────────────────────────
    ⚠⚠⚠ v31.177 (owner) — THIS REPLACES THE READ-ONLY PILL AND ITS FOUR SMALL
    COPIES. *"Change Current Period from a read-only value to an
    updateable/selectable field."* The pill said "you cannot touch this" by
    having no box and a padlock; the whole point now is that you CAN, so the
    rules that made it look untouchable are gone rather than left behind for
    markup that no longer exists.

    ⚠⚠ IT IS A ROW, NOT A PILL: the house `.input` treatment beside its own
    label, so it reads as the control it is. It sits above the two pairs and
    ahead of them in the tab order, which is the order the reader works in —
    choose the month, then look at the windows.

    ⚠ THE LABEL IS `<label for>`, so the 44px target is the words as well as the
    box. The control keeps `--fs-h2` because it is the one value on this card
    that decides what everything below it means. */
.op-cur {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-wrap: wrap;
    margin: var(--sp-2) 0 var(--sp-4);
}

    .op-cur .op-curlab {
        flex: 0 0 auto;
        font-size: 12px;
        letter-spacing: .10em;
        text-transform: uppercase;
        color: var(--nv-ink-3);
        white-space: nowrap;
        cursor: pointer;
    }

    /*  ⚠⚠ THE 32px RIGHT GUTTER IS THE HOUSE GLYPH'S, NOT SPARE ROOM — the
        18px gold calendar SVG sits at `right 10px center` on every
        `input[type=month]` in the sheet. ⚠ AND THIS SELECTOR IS (0,2,1) TO
        MATCH IT: `.op-cur .input` alone is (0,2,0) and would lose, silently,
        exactly as `.op-pair .input` did at v31.175. */
    .op-cur input.op-curinput {
        flex: 0 1 auto;
        width: auto;
        min-width: 0;
        max-width: 100%;
        font-size: var(--fs-h2);
        font-weight: 300;
        color: var(--nv-gold);
        font-variant-numeric: tabular-nums;
        padding-left: 12px;
        padding-right: 34px;
    }

@media (max-width: 560px) {
    .op-cur input.op-curinput { font-size: var(--fs-body); }
}

/*  ── 9 · THE QUADRANT TABS ────────────────────────────────────────────────
    ⚠ THE BODY IS HIDDEN, NEVER REMOVED — every input keeps posting, so a
    collapse cannot lose a half-typed window, and a card carrying a refusal is
    rendered open by the server (`StartsCollapsed`). */
.op-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
    min-width: 0;
    text-align: left;
}

    .op-tab .op-chev {
        flex: 0 0 auto;
        display: inline-flex;
        color: var(--nv-ink-3);
        transform: rotate(90deg);
        transition: transform .15s ease;
    }

    .op-tab:hover .op-chev { color: var(--nv-gold); }

.op-collapsed .op-tab .op-chev { transform: rotate(0deg); }

.op-collapsed .op-body,
.op-collapsed .op-sub { display: none; }

/*  a collapsed quadrant is a TAB, so it takes a tab's room and no more */
.op-collapsed {
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
}

/*  ⚠ A COLLAPSED CARD STILL SHOWS ITS TWO MARKS — the change dot and the
    follows/own tag. Folding a card away must not fold away the answer to
    "which modules have their own posting windows?", which is the question the
    page exists to answer. */
.op-collapsed .op-modhead { min-height: 44px; }

/*  ── 8 · THE BAR IS PERMANENT ─────────────────────────────────────────────
    ⚠⚠⚠ THE `display` GATE IS GONE. It used to be `display: none` until
    `.op-dirty`, which meant the bar APPEARED on the first keystroke and pushed
    every card below it — the reader's next click landing on something that had
    just moved. The bar is now always laid out; only its wording and its two
    buttons change. **Nothing below it may move when a field is amended.** */
.op-bar { display: flex; }
.op-work.op-dirty .op-bar { display: flex; }

/*  the accent still says whether anything is pending — the box does not move,
    the colour does */
.op-bar {
    border-color: rgba(104,152,232,.28);
    background: rgba(16,26,48,.94);
}

.op-work.op-dirty .op-bar { border-color: rgba(232,167,92,.45); }

.op-bar .btn:disabled {
    opacity: .45;
    cursor: default;
}

/*  ── 3 · THE PAGE'S OWN ENTITY CARD IS GONE ───────────────────────────────
    `.op-entcard`, `.op-entity`, `.op-entname`, `.op-entcode` and `.op-entpick`
    are no longer rendered by any page. The rules are left in place rather than
    deleted: they are three short blocks, they cost nothing, and a stylesheet
    that loses a class the day a page stops using it is a stylesheet nobody can
    revert against. ⚠ If a later round wants the strip back it is already
    styled — but the RULING is that the universal switch is the only entity
    control, so bringing it back needs the owner's word, not a merge. */

/*  ── ITEM 5 (v31.175, owner) · THE HEAD BACKGROUND IS REMOVED ────────────
    Owner supplied the rule commented out: *"The header should therefore sit
    directly on the normal page background."*

    ⚠ THIS REVERSES P-06, KNOWINGLY. P-06 was raised because a transparent head
    over a long column of digits reads as bleed-through, and the owner agreed to
    the opaque treatment at v31.174 — then saw it and asked for it off. Seeing
    it beats predicting it, and the layout it now sits over is not the one that
    raised the question: after items 1, 2 and 4 the page is shorter and the top
    of it is a heading and a pill rather than a row of date boxes.
    ⚠⚠ THE RULE IS DELETED RATHER THAN COMMENTED OUT. A commented-out rule in a
    515KB sheet is a rule the next reader has to decide about; the reason it
    went is here, and the shell class `op-app` stays on the page so putting it
    back is one block. `responsive.css:187` (Wave 1.1) is untouched and is what
    now governs this head, exactly as it governs every other. */


/*  ⚠⚠⚠ v31.231 (owner, P-2) — THE COLLAPSED ADD LINE CARD.
    Owner: *"On initial presentation in Copy mode, show only an: Add Line button
    within the collapsed card."*

    ⚠⚠ ONE RULE, AND IT HIDES SIBLINGS RATHER THAN WRAPPING THEM. The alternative
    was a new container around the whole add-line form, which would have moved
    two hundred lines of controls into a different parent to achieve a visual
    change — the shape this project's own rule warns about (*SIZE ONLY, NOT MOVED
    CONTENT*). Here not one existing element moves; the card simply stops
    painting the children it already had.
    ⚠⚠⚠ `display: none` DOES NOT UNSUBMIT A FIELD — only `disabled` does — so the
    hidden controls still post exactly as they always did the moment the card is
    expanded. That is why this is a stylesheet rule and not a `disabled` sweep.
    ⚠ `.al-expand` IS THE ONE CHILD THAT SURVIVES: the button that undoes the
    collapse. Without the exception the rule would hide its own escape hatch.
    ⚠ The attribute is REMOVED on expand rather than the rule overridden, so an
    expanded card is in exactly the state it would have been in without this
    round — nothing to unwind and nothing left specific to fight later.  */
form[data-alcollapse="1"] > *:not(.al-expand) {
    display: none !important;
}

/*  ⚠⚠⚠ v31.236 (owner, P-9) — THE ENTITY ADDRESS CARD ON THE SWITCH SHEET.

    Owner: *"Add the Entity's address/details presentation to the Universal
    Entity Switch pop-up/card in this round."*

    ⚠⚠ IT IS THE HOUSE `.card` WITH THREE BLOCKS, not a new panel grammar. The
    sheet already stacks cards; a bespoke frame here would be a second way of
    saying the same thing on a control that appears on fourteen surfaces.
    ⚠ THE NAME CARRIES THE WEIGHT and the rest is quiet — this is confirmation
    of where the reader is, read at a glance, not a record to study. v1 bolds
    the account name for the same reason (`<b>` around index 0).
    ⚠ 12.5px IS THE SHEET'S OWN SECONDARY SIZE, not a new step on the ladder. */
/*  ⚠⚠⚠ v31.237 (owner, P-9 rework) — THE ROW IS A PAIR: SWITCH, AND INSPECT.
    The submit button keeps the whole row (it is the primary action and should
    stay a large target); the `i` sits outside it because a button cannot be
    nested in a button, and because it must NOT submit.
    ⚠ `min-width: 0` IS LOAD-BEARING: without it the flex item refuses to shrink
    below its content and `.ent-sheet .fld .fl`'s ellipsis never fires, so a long
    company name pushes the `i` off the sheet instead of truncating. */
.ent-row {
    display: flex;
    align-items: center;
    min-width: 0;
}

    .ent-row > .fld {
        flex: 1 1 auto;
        min-width: 0;
        width: auto !important;
    }

    .ent-row > .ent-info {
        flex: 0 0 auto;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 30px;
        height: 30px;
        margin-right: 2px;
        padding: 0;
        border: 0;
        border-radius: 50%;
        background: transparent;
        color: var(--nv-muted, #8892a0);
        cursor: pointer;
        opacity: .42;
        transition: opacity .15s, color .15s, background .15s;
    }

    /*  ⚠ IT COMES UP ON THE ROW, NOT ONLY ON ITSELF — a control that only
        appears once the pointer is already on it is a control nobody finds.
        Touch has no hover at all, which is why it is never fully invisible. */
    .ent-row:hover > .ent-info,
    .ent-row > .ent-info:hover,
    .ent-row > .ent-info:focus-visible {
        opacity: 1;
        color: var(--nv-gold);
        background: rgba(104, 152, 232, .12);
    }

/*  ══ v31.237 — THE ADDRESS PANE IS PINNED TO THE FOOT OF THE SHEET ══════════
    ⚠⚠⚠ STICKY TO THE BOTTOM, AND THE REASON IS THE POINTER. The pane repaints as
    the reader moves down the tree, and its height changes with the address. Above
    the tree that reflows every row BELOW it — so the row under the pointer becomes
    a different row, which repaints the pane, which moves the rows again. At the
    foot there is nothing after it to move: a taller address grows the sheet
    downwards, away from the list it is describing.
    ⚠⚠⚠ v31.240 (owner, P-9B) — *"and fit into card."* THE CAP WAS CLIPPING REAL
    DATA, not just pathological data. `46vh` is 353px at 1366x768 and 388px at
    390x844; a full card at 15px is **461px on the desktop and 505px on the
    phone**, where the IBAN and the account name each take two lines. So every
    complete entity was getting a scrollbar INSIDE the card — the reader saw a
    box of financial detail that had to be scrolled to be read, which is not a
    card that fits.
    ⚠⚠ THE CAP IS RAISED, NOT REMOVED, and the reason it exists is unchanged: this
    pane is STICKY at the foot of the sheet, so without any cap a pathological
    address could occupy the whole sheet and leave the tree it belongs to with two
    rows showing. 72vh clears every measured case with room to spare (553px at
    768, 607px at 844) while still bounding the bad one.
    ⚠ THE SHEET IS THE SCROLLER. The card's own overflow now only ever engages in
    that bounded case; ordinarily the sheet scrolls and the card is whole.

    ⚠⚠⚠ v31.238 (owner, P-9A) — THE PRESENTATION IS HIS, VERBATIM. Owner:
    *"Please update the address card styling to the following exactly."* So the
    full-bleed treatment this rule shipped with is gone and the pane is a CARD
    again: `margin: 10px` on all four sides, an 8px radius, and `.card`'s own
    border tinted `--nv-gold-dim` — the negative margins, the `border: 0`, the
    `border-top` hairline and the gradient are removed rather than overridden,
    because a declaration that is only there to be beaten is a declaration that
    will beat something else later.
    ⚠⚠ THE POSITION AND THE SCROLLING ARE UNCHANGED, AND THAT IS THE POINT: he
    kept `position: sticky` / `bottom: -24px` / `max-height` / `overflow-y` in
    the block he sent, so the reflow rule above still holds. `bottom: -24px`
    still cancels the sheet's 24px foot even though the side margins no longer
    cancel its padding — the pane simply insets from the frame instead of
    spanning it. */
.ent-sheet .ent-addr {
    position: sticky;
    bottom: -24px;
    z-index: 2;
    margin: 10px;
    padding: 11px 20px 14px;
    border-radius: 8px;
    border-color: var(--nv-gold-dim);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    max-height: 72vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

    /*  ⚠ v31.238 (owner, P-9A) — 400, NOT 600. His block, verbatim. */
    .ent-sheet .ent-addr .ent-addr-name {
        font-weight: 400;
        color: var(--nv-gold);
        overflow-wrap: anywhere;
    }

    /*  ⚠⚠ `anywhere`, NOT `nowrap` WITH AN ELLIPSIS. An address line that is cut
        off is not an address — and unlike a list row, this card has no second
        place to show the full value. A long street wraps. */
    /*  ⚠ v31.238 (owner, P-9A) — 18px, NOT 12.5. His block, verbatim. */
    .ent-sheet .ent-addr .ent-addr-lines,
    .ent-sheet .ent-addr .ent-addr-contact {
        font-size: 18px;
        line-height: 1.5;
        overflow-wrap: anywhere;
    }

    .ent-sheet .ent-addr .ent-addr-contact {
        color: var(--nv-muted, #8892a0);
    }

        /*  ⚠ THE CONTACT BLOCK IS SEPARATED BY A RULE rather than by a gap: on a
            card this narrow, whitespace alone reads as an accident. */
        .ent-sheet .ent-addr .ent-addr-contact:not(:empty) {
            margin-top: 2px;
            padding-top: 8px;
            border-top: 1px solid var(--nv-line, rgba(255, 255, 255, .08));
        }

    /*  ══ v31.239 (owner, P-9B) — THE FINANCIAL BLOCK, BELOW A HAIRLINE ══════
        Owner: *"Draw a very thin, subtle separator line, consistent with the
        existing NOVERA card styling … The styling should remain compact and
        understated. The separator should be very thin and low-contrast, acting
        only as a visual division."*

        ⚠⚠⚠ `:not(:empty)` DRAWS THE RULE, NOT THE ELEMENT EXISTING. The block is
        rendered on every card and filled only when there is something to fill it
        with, so an entity with no registration and no bank row would otherwise
        carry a hairline under nothing — which is the empty-frame fault the card
        already refuses at the whole-panel level, in miniature.
        ⚠⚠ IT IS FAINTER AND TIGHTER THAN THE CONTACT RULE ABOVE IT, deliberately.
        Two identical rules read as two equal divisions; this one is a footnote to
        the card, not a second half of it — .05 against the contact block's .08,
        and 13px against the address block's 18px.
        ⚠ THE LABEL IS THE QUIET HALF. The number is what is being read; the word
        in front of it only says which number it is. */
    /*  ⚠ v31.240 (owner, P-9B) — 15px, HIS VALUE, SENT AS A RULE. It shipped at
        13 and read as a footnote rather than as information; the block still
        sits below the address's 18px, so the hierarchy the separator draws is
        unchanged. */
    .ent-sheet .ent-addr .ent-addr-fin {
        font-size: 15px;
        line-height: 1.45;
        overflow-wrap: anywhere;
        color: var(--nv-ink-2, #aab3c8);
    }

        /*  ⚠⚠ A WRAPPED ROW STILL READS AS ONE ROW. At 15px on a 390px screen an
            IBAN and a long account name each take two lines, and without this the
            second line starts under the LABEL — which reads as a new, unlabelled
            row. The hanging indent puts every continuation under the value it
            belongs to. */
        .ent-sheet .ent-addr .ent-addr-fin > div {
            padding-left: 14px;
            text-indent: -14px;
        }

        .ent-sheet .ent-addr .ent-addr-fin:not(:empty) {
            margin-top: 4px;
            padding-top: 7px;
            border-top: 1px solid rgba(255, 255, 255, .05);
        }

        .ent-sheet .ent-addr .ent-addr-fin .fk {
            color: var(--nv-ink-3, #6b7690);
        }

/* ══════════════════════════════════════════════════════════════════════════
   v31.242 (owner, P-10) — THE ADDRESSED-ACCOUNT SEARCH SHEET

   ⚠⚠⚠ IT BORROWS `.mail-sheet`'s FRAME AND OVERRIDES ITS GEOMETRY, exactly as
   `.ent-sheet` does. That is deliberate: three sheets that look like three
   different apps is the outcome of three private frames. What differs here is
   WIDTH — a result grid of six columns needs it — and that this one is anchored
   near the top rather than centred, because it is tall.
   ⚠⚠ AND IT HIDES WITH `opacity + visibility`, NOT `translateY(102%)`. The base
   `.mail-sheet` slides itself off the bottom; the entity sheet records why that
   cannot work once `bottom` is raised, and the same applies here.
   ══════════════════════════════════════════════════════════════════════════ */
/*  ⚠⚠⚠ `.mail-sheet.acs-sheet`, NOT `.acs-sheet` — AND MEASURED, NOT ASSUMED.
    The base `.mail-sheet` caps at `max-width: 480px` and `responsive.css` sets
    `margin: N auto !important` at three separate breakpoints. Written as a
    single class this rule is (0,1,0) against (0,1,0) in a file that loads
    LATER, so it lost: the first render of this sheet came out 480px wide with
    the results grid clipped and the type chips wrapping mid-word. Two classes
    is (0,2,0) and wins on specificity whatever the file order — the same fight
    `.ent-sheet.ent-anchored` records a few hundred lines above.
    ⚠⚠ AND `margin` NEEDS `!important` TO ANSWER AN `!important`. Nothing else
    here does; specificity carries the rest. */
.mail-sheet.acs-sheet {
    position: fixed;
    top: 4vh;
    bottom: auto;
    left: 50%;
    right: auto;
    width: min(1020px, calc(100vw - 32px));
    max-width: none;
    max-height: 90vh;
    overflow-y: auto;
    margin: 0 !important;
    z-index: 41;
    border-radius: 8px;
    border: 1px solid rgba(104, 152, 232, .30);
    padding: 0 20px 22px;
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 50%, #13294B 100%);
    font-family: 'Poppins', -apple-system, 'Segoe UI', sans-serif !important;
    transform: translate(-50%, 12px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s, transform .24s cubic-bezier(.22,.61,.36,1), visibility 0s .24s;
}

    .mail-sheet.acs-sheet.open {
        transform: translate(-50%, 0);
        opacity: 1;
        visibility: visible;
        transition: opacity .2s, transform .24s cubic-bezier(.22,.61,.36,1), visibility 0s;
    }

    /*  ⚠ `[hidden]` MUST WIN over the display the frame sets — the `.rt-emoji`
        cascade lesson this file has paid for twice. */
    .mail-sheet.acs-sheet[hidden], .mail-sheet.acs-card[hidden] {
        display: none !important;
    }

.mail-scrim.acs-scrim { z-index: 40; }
.mail-scrim.acs-cardscrim { z-index: 42; }

/*  the card rides ABOVE the results it was opened from, and is narrower. */
.mail-sheet.acs-card {
    position: fixed;
    top: 50%;
    left: 50%;
    right: auto;
    bottom: auto;
    transform: translate(-50%, -50%);
    width: min(560px, calc(100vw - 32px));
    max-width: none;
    max-height: 86vh;
    overflow-y: auto;
    margin: 0 !important;
    z-index: 43;
    border-radius: 8px;
    border: 1px solid rgba(104, 152, 232, .30);
    padding: 0 20px 22px;
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 50%, #13294B 100%);
    opacity: 1;
    visibility: visible;
}

/*  the sticky head — the entity sheet's shape, with a louder close. */
.acs-head {
    position: sticky;
    top: 0;
    z-index: 3;
    margin: 0 -20px 12px;
    padding: 14px 60px 11px 20px;
    background: linear-gradient(180deg, rgba(4,6,12,.96), rgba(9,13,24,.88));
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid rgba(104, 152, 232, .16);
}

    .acs-head h2 {
        margin: 0;
        font-size: 23px;
        font-weight: 600;
    }

    .acs-head .acs-sub {
        font-size: 12.5px;
        color: var(--nv-ink-3);
        margin-top: 2px;
    }

/*  ⚠⚠ A BORDERED TARGET, NOT A BARE GLYPH. Owner: *"The sheet requires a
    clearly visible Close (×) button."* This sheet opens over work in progress,
    so the way out is a control rather than a hint. */
.acs-close {
    position: absolute;
    top: 12px;
    right: 16px;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(232, 167, 92, .38);
    border-radius: 50%;
    background: rgba(232, 167, 92, .10);
    color: var(--nv-gold);
    cursor: pointer;
    font-family: inherit;
    font-size: 15px;
}

    .acs-close:hover, .acs-close:focus-visible {
        background: rgba(232, 167, 92, .22);
        color: var(--nv-gold-bright);
    }

.acs-tools {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

    .acs-tools .acs-wrap {
        flex: 1 1 300px;
    }

    /*  ⚠ `tokens.css` GIVES `.chips > .chip` AN EQUAL SHARE OF THE ROW, which is
        right for a four-chip status bar and wrong for seven type filters — it
        broke "Bank accounts" across two lines. Here each chip is its own width
        and the row wraps as a row. */
    .acs-chips > .chip {
        flex: 0 0 auto;
    }

.acs-pre, .acs-state {
    margin: 0 0 10px;
    font-size: 12.5px;
    color: var(--nv-ink-3);
}

.acs-pre {
    border-left: 2px solid rgba(232, 167, 92, .35);
    padding-left: 10px;
}

/*  ══ the catalog groups (Q1) ═══════════════════════════════════════════════
    ⚠⚠⚠ THE HEADING IS GOLD-RULED AND THE ROWS SIT UNDER IT. Owner: *"Each
    Catalog should have a clear section heading, with its matching accounts
    immediately beneath it."* The rule is what makes two identical account codes
    in two catalogs read as two different accounts rather than a duplicate. */
.acs-group { margin-bottom: 16px; }

.acs-cat {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 6px;
    padding: 5px 0 6px;
    border-bottom: 1px solid rgba(232, 167, 92, .28);
}

    .acs-cat .db {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 13px;
        letter-spacing: .06em;
        color: var(--nv-gold);
    }

    .acs-cat .cnt {
        font-size: 12px;
        color: var(--nv-ink-3);
        margin-left: auto;
    }

/*  ⚠ THE GRID SCROLLS IN ITS OWN BOX. Six columns do not fit a phone, and a
    sheet that scrolls sideways takes its own close button off screen. */
.acs-scroll { overflow-x: auto; }

.acs-res {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    min-width: 760px;
}

    .acs-res thead th {
        text-align: left;
        font-weight: 400;
        font-size: 11px;
        letter-spacing: .08em;
        text-transform: uppercase;
        color: var(--nv-ink-3);
        padding: 0 10px 6px;
        white-space: nowrap;
    }

    .acs-res tbody tr {
        border-bottom: 1px solid rgba(104, 152, 232, .10);
        cursor: pointer;
    }

        .acs-res tbody tr:hover,
        .acs-res tbody tr:focus-visible {
            background: rgba(120, 165, 240, .07);
        }

    .acs-res td {
        padding: 9px 10px;
        vertical-align: top;
    }

        .acs-res td.num {
            font-variant-numeric: tabular-nums;
            white-space: nowrap;
        }

        .acs-res td.acs-act {
            width: 44px;
            text-align: right;
        }

.acs-name { color: var(--nv-ink); }
.acs-code, .acs-sub2 { font-size: 12.5px; color: var(--nv-ink-3); }
.acs-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.acs-miss { color: var(--nv-ink-3); opacity: .55; }
.acs-empty { padding: 26px 12px; color: var(--nv-ink-3); text-align: center; }
.acs-loading { padding: 22px 12px; color: var(--nv-ink-3); text-align: center; }

/*  ⚠⚠ THE ⓘ IS QUIET UNTIL THE ROW IS UNDER THE POINTER, and never invisible —
    touch has no hover, which is the same rule the entity row's inspect control
    follows. */
.acs-info {
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--nv-ink-3);
    cursor: pointer;
    opacity: .45;
    transition: opacity .15s, color .15s, background .15s;
}

.acs-res tbody tr:hover .acs-info,
.acs-info:hover,
.acs-info:focus-visible {
    opacity: 1;
    color: var(--nv-gold);
    background: rgba(104, 152, 232, .14);
}

/*  the card's blocks — the entity card's vocabulary, one level up in size
    because this sheet is wider and is read rather than glanced at. */
.acs-blk {
    padding: 11px 0;
    border-top: 1px solid rgba(104, 152, 232, .14);
}

    .acs-blk:first-child { border-top: 0; }

.acs-blkh {
    font-size: 11.5px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--nv-gold-dim);
    margin-bottom: 7px;
}

.acs-addrname {
    color: var(--nv-gold);
    font-size: 18px;
    overflow-wrap: anywhere;
}

.acs-addrlines {
    font-size: 18px;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.acs-blk > div:not(.acs-blkh):not(.acs-addrname):not(.acs-addrlines):not(.acs-more) {
    font-size: 15px;
    line-height: 1.45;
    overflow-wrap: anywhere;
    color: var(--nv-ink-2);
    padding-left: 14px;
    text-indent: -14px;
}

.acs-blk .fk { color: var(--nv-ink-3); }

.acs-more {
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px dashed rgba(104, 152, 232, .20);
    font-size: 15px;
    line-height: 1.45;
}

@media (max-width: 767.98px) {
    /*  01-Screen: the sheet is the screen. A 90vh box inset 16px reads as a
        dialog on a phone rather than as a page that lost its navigation. */
    .mail-sheet.acs-sheet {
        top: 2vh;
        width: calc(100vw - 16px);
        max-height: 96vh;
        padding: 0 14px 18px;
    }

        .mail-sheet.acs-sheet .acs-head {
            margin: 0 -14px 10px;
            padding: 12px 56px 10px 14px;
        }
}

/*  ══ v31.273 (owner) — THE EDIT DOOR'S SHORT MESSAGE ═══════════════════════
    Owner: *"Please place a short message when toggling the button, i.e.
    Clear → 'Transaction allocated. Clear allocations before amending.'"*

    ⚠⚠ IT SITS UNDER THE BUTTON ROW, FULL WIDTH, and is inserted by
    nv-edittrn.js rather than rendered by any page — so it lands the same way on
    the invoice header, the Review chips, the money pages and the GL journal.
    ⚠ AMBER, NOT RED. Nothing has gone wrong: the transaction is fine and the
    reader has a next step. Red is for refusals they cannot act on. */
.fin-editwhy {
    margin-top: 8px;
    padding: 7px 12px;
    border-radius: var(--r-input, 6px);
    border: 1px solid rgba(232, 167, 92, .38);
    background: rgba(232, 167, 92, .09);
    color: var(--nv-gold-bright);
    font-size: 13px;
    line-height: 1.45;
}

/* ═══ v31.282 (owner, P-28) — THE NOTIFICATION PLATFORM ══════════════════════
   The bell and its badge, the dropdown, the Centre's rows, the settings
   switches, the device list and the permission prompt.

   ⚠⚠ EVERY COLOUR HERE IS A TOKEN FROM tokens.css. Not one literal: this block
   is appended to a 576KB stylesheet whose whole discipline is that the palette
   lives in one place, and a hex value here would be the first exception.
   ⚠ AND THE TYPE SIZES SIT ON THE EXISTING LADDER rather than inventing a step.
   The shallow 4-step ladder is still an open backlog item (DESIGN 1); nothing
   in this block may pre-empt it. ═══════════════════════════════════════════ */

/* ── the bell's badge ─────────────────────────────────────────────────────── */
.nv-bellcount {
    position: absolute;
    top: 2px;
    right: 10px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--nv-gold);
    color: var(--nv-bg-deep);
    font-size: 11px;
    font-weight: 600;
    line-height: 18px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

/* ── the dropdown ─────────────────────────────────────────────────────────── */
/*  ══════════════════════════════════════════════════════════════════════════
    ⚠⚠⚠ v31.288 (owner): *"the notifications popup needs proper styling — same
    pattern as other tooltip."*

    THE PANEL WAS THE ONE FLOATING SURFACE IN THE APPLICATION THAT WAS NOT THE
    HOUSE ONE. It carried `background: var(--nv-surface)` — the flat blue a CARD
    uses, which is correct for something sitting IN the page and wrong for
    something floating OVER it: a card's surface belongs to the column it is
    part of, and a panel that borrows it reads as a rectangle dropped on the
    screen rather than as a layer above it. That is the whole of what the
    owner's screenshot shows.

    ⚠⚠ SO IT TAKES `.card.evtip`'s GRAMMAR, WHICH IS THE TOOLKIT TOOLTIP
    SURFACE: the opaque 145° gradient, the `rgba(104,152,232,.30)` edge, the
    8px radius and the deep shadow. That block's own comment records why the
    gradient is OPAQUE — *"the toolbar has a transparent background making the
    items unreadable"* — and this panel floats over exactly the same live
    content, so it inherits the reason along with the look.

    ⚠ IT DOES NOT INHERIT `pointer-events: none`. A tooltip never eats the click
    it describes; this panel IS the thing being clicked. Same surface, different
    object — which is why the declarations are restated here rather than the
    class being reused.
    ══════════════════════════════════════════════════════════════════════════ */
.nv-ntfpanel {
    position: fixed;
    z-index: 1200;
    width: 390px;
    max-width: calc(100vw - 16px);
    border: 1px solid rgba(104, 152, 232, .30);
    border-radius: 8px;
    overflow: hidden;
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 82%, #13294B 175%);
    box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
}

.nv-ntfhead, .nv-ntffoot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 14px;
    font-size: 14px;
    color: var(--nv-ink-2);
}

/*  ⚠⚠ THE RULES ARE THE PANEL'S OWN, NOT `--line`. `--line` is the divider a
    card draws between its rows, and against this darker surface it disappeared
    — the head and foot read as floating text rather than as bands. The edge
    colour is the panel's own border at a third of its weight, so the three
    lines belong to one object. */
.nv-ntfhead { border-bottom: 1px solid rgba(104, 152, 232, .16); }
.nv-ntffoot { border-top: 1px solid rgba(104, 152, 232, .16); }
.nv-ntfhead .spacer, .nv-ntffoot .spacer { flex: 1 1 auto; }

/*  ⚠ THE TITLE IS THE HOUSE HEAD, not body copy in a slightly lighter ink. It
    is the only label in the panel and it was the same size and weight as the
    two links under it. */
.nv-ntfhead .t {
    color: var(--nv-ink);
    font-size: 15px;
    font-weight: 300;
    letter-spacing: .2px;
}

/*  the settings door — an icon button, sized and coloured like every other
    icon in the application rather than a blue character */
.nv-ntfhead .gear {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    color: var(--nv-ink-3);
    text-decoration: none;
}

    .nv-ntfhead .gear:hover {
        color: var(--nv-gold-bright, #f2bc74);
        background: rgba(232, 167, 92, .10);
    }

/*  ⚠⚠ THE FOOT ACTIONS ARE GOLD, NOT BROWSER BLUE. Every other secondary
    action in this application is gold on hover and muted ink at rest; the raw
    `--nv-blue-bright` here was the only place two links looked like an
    unstyled anchor pair. */
.nv-ntffoot .lnk {
    background: none;
    border: 0;
    padding: 4px 2px;
    font: inherit;
    font-size: 13.5px;
    color: var(--nv-ink-3);
    cursor: pointer;
    text-decoration: none;
}

    .nv-ntffoot .lnk:hover {
        color: var(--nv-gold-bright, #f2bc74);
    }

.nv-ntflist { max-height: 60vh; overflow-y: auto; }

/* ── one row, shared by the dropdown and the Centre ───────────────────────── */
.nv-ntfrow {
    display: flex;
    gap: 11px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--line);
    min-width: 0;
}

.nv-ntfrow:last-child { border-bottom: 0; }

    .nv-ntfrow > .dot {
        flex: 0 0 auto;
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: var(--nv-gold);
        margin-top: 7px;
    }

.nv-ntfrow.read > .dot { background: transparent; border: 1px solid var(--line); }
.nv-ntfrow .body { min-width: 0; flex: 1 1 auto; }

.nv-ntfrow .kind {
    font-size: 10.5px;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
}

/*  ⚠ THE KIND COLOURS ARE SEMANTIC, NOT DECORATIVE: overdue is the danger
    token, due is the warning one, and everything else stays quiet. A palette
    that coloured all nine would make none of them mean anything. */
.nv-ntfrow .kind.k-task_overdue { color: var(--nv-danger); }
.nv-ntfrow .kind.k-task_due { color: var(--nv-warn); }
.nv-ntfrow .kind.k-email_ai_action { color: var(--nv-blue-bright); }
.nv-ntfrow .kind.k-email_important { color: var(--nv-blue-bright); }
.nv-ntfrow .kind.k-task_assigned { color: var(--nv-good); }

.nv-ntfrow .ttl {
    display: block;
    font-size: 14.5px;
    color: var(--nv-ink);
    margin-top: 2px;
    overflow-wrap: anywhere;
    text-decoration: none;
}

.nv-ntfrow.read .ttl { color: var(--nv-ink-2); }

.nv-ntfrow .meta {
    font-size: 12.5px;
    color: var(--nv-ink-3);
    margin-top: 3px;
}

.nv-ntfrow .meta .ent { color: var(--nv-gold-dim); }
.nv-ntfrow .meta .done { color: var(--nv-good); margin-left: 6px; }

.nv-ntfrow .acts {
    display: flex;
    gap: 7px;
    margin-top: 9px;
    flex-wrap: wrap;
}

    /*  ⚠⚠⚠ THE SAME tokens.css:591 `width: 100%` AGAIN, and this is the third
        place it bit in one round. The house `.btn` is a full-width 51px block —
        correct for a form's Save, absurd for three chips under a notification
        row, where it produced three stacked slabs taller than the notification
        itself. **Anywhere buttons sit in a line in this application, they need
        `width: auto` stated.**
        ⚠ AND A COMPACT HEIGHT, scoped here rather than added to `.btn` globally:
        `.btn.sm` is not a house class, and inventing one in a 587KB stylesheet
        that 60 screens read is not a thing to do inside a notifications round. */
    .nv-ntfrow .acts .btn,
    .nv-ntfpanel .acts .btn {
        flex: 0 0 auto;
        width: auto;
        height: 32px;
        min-height: 32px;
        font-size: 13px;
        padding-inline: 14px;
        border-radius: var(--r-input, 6px);
        text-decoration: none;
    }

    /*  ⚠⚠⚠ AND NO `border` / `background` IS STATED HERE ON PURPOSE. The first
        cut of this rule drew its own 1px `var(--line)` edge, which did two
        things wrong at once: it overrode the `border-color: transparent` that
        `.btn.ghost`'s conic ring depends on, so these three chips were the only
        buttons in the application without the house edge — and it still left the
        SURFACE undefined, so a `<button>` showed the browser's grey and an `<a>`
        showed nothing. The markup now carries `ghost`, tokens.css owns the face,
        and this rule is only ever allowed to change the SIZE. */

    .nv-ntfrow .acts .btn.primary {
        border-color: rgba(232,167,92,.5);
    }

.nv-ntfempty {
    padding: 22px 14px;
    text-align: center;
    color: var(--nv-ink-3);
    font-size: 13.5px;
}

.nv-ntfday {
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--nv-ink-3);
    padding: 14px 14px 4px;
    border-bottom: 1px solid var(--line);
}

/*  ══════════════════════════════════════════════════════════════════════════
    ⚠⚠⚠ v31.287 (owner): *"the pills inside nv-ntffilters should all be the
    same width."*

    THIS IS THE HOUSE RULE THE OWNER ALREADY LOCKED, NOT A NEW IDEA. The
    account-type chips (`.acc-chips`, v31.35) answer exactly this instruction —
    *"make all chips same width as the widest chip"* — and the comment there
    records what was tried and rejected, so it is reused rather than
    rediscovered:

      · `width: max-content` on each chip was the FIRST answer and it was
        WRONG. It sizes every chip to its own text, which is what we already
        have; and the one-row `max-content` GRID it was paired with cannot
        wrap, so long labels ran straight through their pill borders. The
        owner's screenshot of that is why the rule below exists.
      · `repeat(auto-fit, minmax(<floor>, 1fr))` gives both halves at once:
        every track is `1fr`, so **every chip is exactly the same width**, and
        the row breaks into two when the floor will not fit. It cannot overflow.

    ⚠⚠ 128px RATHER THAN `.acc-chips`' 116px, because these labels carry a
    COUNT as well — "Actioned 12" is wider than "Suppliers". The floor is what
    decides when six chips become two rows, so it is set from the widest label
    this card can hold, not copied.

    ⚠ `justify-items: stretch` IS THE DEFAULT AND IS LEFT ALONE — the chip must
    fill its track, or equal tracks would still give unequal pills.
    ══════════════════════════════════════════════════════════════════════════ */
.nv-ntffilters {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 7px;
}

    /*  ⚠⚠ THE CHIP IS CENTRED IN ITS TRACK. `.chip` is an inline-flex pill
        sized to its own text everywhere else in the application; inside a grid
        track it has to fill the track instead, and the label has to sit in the
        middle of it rather than hard against the left edge — otherwise six
        equal pills read as six ragged ones. */
    .nv-ntffilters .chip {
        display: flex;
        width: auto;
        min-width: 0;
        justify-content: center;
    }
.nv-ntffilters .c { font-variant-numeric: tabular-nums; opacity: .75; margin-left: 4px; }
.nv-ntfcard { padding-left: 0; padding-right: 0; }

/* ── settings ─────────────────────────────────────────────────────────────── */
.nv-set {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 11px 0;
    border-bottom: 1px solid var(--line);
}

.nv-set:last-child { border-bottom: 0; }
.nv-set .lbl { flex: 1 1 auto; font-size: 14.5px; color: var(--nv-ink-2); min-width: 0; }
.nv-set .lbl .sub { display: block; font-size: 12.5px; color: var(--nv-ink-3); margin-top: 1px; }

.grp {
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--nv-gold-dim);
    margin: 4px 0 2px;
}

/*  ⚠⚠ THE SWITCH IS A REAL CHECKBOX WITH THE BOX HIDDEN, never a div with a
    click handler. It is focusable, it is reachable by keyboard, it posts with
    its form, and a screen reader announces it — none of which a styled div
    gives you, and all of which a settings screen needs. */
.nv-sw {
    flex: 0 0 auto;
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
    border-radius: 12px;
    border: 1px solid var(--line);
    background: rgba(255, 255, 255, .03);
    cursor: pointer;
}

    .nv-sw input {
        position: absolute;
        opacity: 0;
        width: 100%;
        height: 100%;
        margin: 0;
        cursor: pointer;
    }

    .nv-sw i {
        position: absolute;
        top: 2px;
        left: 2px;
        width: 18px;
        height: 18px;
        border-radius: 50%;
        background: var(--nv-ink-3);
        display: block;
        pointer-events: none;
    }

    .nv-sw:has(input:checked) {
        border-color: var(--nv-gold);
        background: rgba(232, 167, 92, .18);
    }

        .nv-sw:has(input:checked) i {
            left: auto;
            right: 2px;
            background: var(--nv-gold);
        }

    .nv-sw:has(input:focus-visible) { outline: 2px solid var(--nv-blue-bright); outline-offset: 2px; }

.nv-radio {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 9px 0;
    cursor: pointer;
}

    .nv-radio input { position: absolute; opacity: 0; width: 0; height: 0; }

    .nv-radio .r {
        flex: 0 0 auto;
        width: 15px;
        height: 15px;
        border-radius: 50%;
        margin-top: 3px;
        border: 1px solid var(--line);
        display: block;
    }

    .nv-radio:has(input:checked) .r {
        border-color: var(--nv-gold);
        box-shadow: inset 0 0 0 3.5px var(--nv-bg), inset 0 0 0 9px var(--nv-gold);
    }

    .nv-radio:has(input:focus-visible) .r { outline: 2px solid var(--nv-blue-bright); outline-offset: 2px; }

    .nv-radio .t { font-size: 14.5px; color: var(--nv-ink-2); }

        .nv-radio .t .ex {
            display: block;
            font-size: 12.5px;
            color: var(--nv-ink-3);
            margin-top: 2px;
            font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        }

/* ── devices ──────────────────────────────────────────────────────────────── */
.nv-dev {
    display: flex;
    align-items: center;
    gap: 13px;
    padding: 13px 0;
    border-bottom: 1px solid var(--line);
    flex-wrap: wrap;
}

.nv-dev:last-child { border-bottom: 0; }

    .nv-dev .ic {
        flex: 0 0 auto;
        width: 34px;
        height: 34px;
        border-radius: var(--r-input, 6px);
        border: 1px solid var(--line);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 16px;
    }

    /*  ⚠⚠ 160px, NOT 220. In a half-width card the old basis pushed the ON /
        Remove pair onto a line of its own for every device — the card wrapped
        rather than overflowed, which looks deliberate and is not. */
    .nv-dev .n { flex: 1 1 160px; min-width: 0; }
    .nv-dev .n b { display: block; font-weight: 400; font-size: 14.5px; color: var(--nv-ink); }
    .nv-dev .n span { display: block; font-size: 12.5px; color: var(--nv-ink-3); }
    .nv-dev .n span.bad { color: var(--nv-danger); }

.nv-dev.off .ic, .nv-dev.off .n b { opacity: .5; }

.nv-steps { margin: 8px 0 0; padding-left: 20px; color: var(--nv-ink-2); font-size: 14px; }
.nv-steps li { margin: 4px 0; }

/* ── the Novera prompt ────────────────────────────────────────────────────── */
.nv-ntfscrim {
    position: fixed;
    inset: 0;
    z-index: 1300;
    background: rgba(3, 5, 11, .72);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 26px;
}

/*  ══════════════════════════════════════════════════════════════════════════
    ⚠⚠⚠ v31.289 (owner): *"formatting is also required for this pop-up."*

    IT IS THE SAME OBJECT AS `nvAlert`, SO IT IS THE SAME CARD. This is a modal
    over a scrim with a mark, a title, a sentence and two buttons — exactly what
    `.err-pop` / `.nv-dlg` already is — and it was the only one of the two not
    built that way. It centred everything where the dialog is left-aligned, it
    carried a GOLD edge where the dialog's is blue-tinted, and it sat on
    `var(--nv-surface)`, the flat card blue, where the dialog floats on the
    house 145° ramp.

    ⚠⚠ THE GOLD EDGE WAS THE WORST OF THE THREE. In this system gold is the
    ALERT colour — it is what an overdue task and a failed save wear. A simple
    offer, which is what this is, framing itself in gold tells the reader
    something has gone wrong before they have read a word.

    ⚠ THE RAMP IS THE SCALED ONE (82% / 175%), the same as the dialog and the
    bell panel, because this box is the same order of size as they are. v31.286
    explains why the stops move: they are percentages of a line that scales with
    the box, so a small tooltip and a 460px card show different PARTS of one
    ramp unless the stops are scaled to match.
    ══════════════════════════════════════════════════════════════════════════ */
.nv-ntfask {
    width: 460px;
    max-width: 100%;
    border: 1px solid rgba(104, 152, 232, .30);
    border-radius: 8px;
    background: linear-gradient(145deg, #010107 0%, #1E1E1E 82%, #13294B 175%);
    box-shadow: 0 18px 48px rgba(0, 0, 0, .55);
    padding: 26px 22px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

    /*  the head: mark on the left, title beside it — `.nv-dlg-head`'s geometry,
        so the two modals open the same way */
    .nv-ntfaskhead {
        display: flex;
        align-items: center;
        gap: 12px;
    }

    /*  ⚠ THE RING IS THE DIALOG'S RING. 44px, circular, gold at .55, the same
        radial fill — a second mark shape would make these read as two different
        applications' modals. */
    .nv-ntfask .mic {
        flex: 0 0 44px;
        width: 44px;
        height: 44px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: var(--nv-gold-bright);
        border: 1px solid rgba(232, 167, 92, .55);
        background: radial-gradient(circle at 35% 30%, rgba(232, 167, 92, .16), rgba(232, 167, 92, .04));
    }

    /*  ⚠⚠ 300, NOT 600. The dialog's headline is 300 (v31.286, owner) and the
        body copy under it is 200; a 600 here was heavier than any other heading
        in the application. */
    .nv-ntfask h4 {
        margin: 0;
        font-size: var(--fs-h2);
        font-weight: 300;
        color: var(--nv-gold);
    }

    .nv-ntfask p {
        margin: 0;
        font-size: 16px;
        font-weight: 200;
        color: var(--nv-ink);
        line-height: 1.5;
    }

    /*  ⚠⚠⚠ `.nv-ntfaskbtns`, NOT `.row`. tokens.css gives `.row`
        `min-height: 56px` and `.row + .row { border-top }` — in this system
        `.row` is the 48px-target LIST ROW, not a generic flex line. This prompt
        was still borrowing it after v31.284 recorded the same mistake for the
        action bar, and it was adding a phantom 56px band under the buttons.
        ⚠⚠⚠ AND A GRID, NOT `flex: 1`. MEASURED: `.nv-dlg-btns` uses `flex: 1`
        and its two buttons come out 190px and 192px — a 2px difference, every
        time, because `.btn.primary` carries a 2px border and `.btn.ghost` a 1px
        one, and flex distributes FREE SPACE rather than setting widths. Equal
        shares of the leftover are not equal buttons. `grid-auto-columns: 1fr`
        makes the TRACKS equal and the buttons fill them, so the border weight
        stops mattering. The same rule is applied to `.nv-dlg-btns` below: it is
        the same defect in the same shape of control, and leaving the house
        dialog 2px out while fixing its twin would be the worse outcome. */
    .nv-ntfaskbtns,
    .nv-dlg .nv-dlg-btns {
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: 1fr;
        gap: 12px;
        margin-top: 4px;
    }

        .nv-ntfaskbtns .btn,
        .nv-dlg .nv-dlg-btns .btn {
            width: auto;
            min-width: 0;
        }

.nv-ntfwhy {
    font-size: 13.5px;
    color: var(--nv-warn);
    line-height: 1.45;
}

.banner-ok {
    padding: 11px 15px;
    border-radius: var(--r-card, 6px);
    border: 1px solid var(--nv-good);
    background: rgba(88, 179, 104, .10);
    color: var(--nv-good);
    font-size: 14px;
}

/* ═══ v31.284 (owner) — THE NOTIFICATION SCREENS' LAYOUT ═════════════════════
   Owner, on the first real look at P-28:
     *"The top buttons on load overlap and not properly visible. Please use the
     same pattern as other pages. Devices and notification settings should be on
     the second row. Entity switch should be on the right."* · *"Notification
     settings should be first, of the Devices."* · *"Enable this device should be
     a button at the same level."* · *"Make the bottom spacing in the card. They
     overflow into each other."* · *"Make cards half their size so you have 2 per
     row and responsive for the mobile."*

   ⚠⚠⚠ WHY THE HEAD OVERLAPPED, AND IT WAS MY ERROR RATHER THAN A TUNING
   PROBLEM. `.screen-head` is `flex-wrap: nowrap` by house rule (app.css:5299 —
   *"heads never wrap"*), and `_NvEntity` spans the head to reach the PAGE's
   right edge. I put three action controls into that row as well, so the title
   was squeezed to "Noti…" and the chip was painted over the buttons. **The head
   takes a title and the entity chip. Actions go underneath.**

   ⚠⚠ AND `.row` IS NOT A GENERIC FLEX ROW IN THIS SYSTEM. tokens.css gives it
   `min-height: 56px` and `.row + .row { border-top }` — it is the 48px-target
   LIST ROW. Using it for a pair of buttons added a phantom 56px band and a rule
   nobody drew. `.nv-ntfbar` below is the button group.
   ══════════════════════════════════════════════════════════════════════════ */

/*  the second row: the same three doors on every notification screen, in the
    owner's order — settings, devices, then the action. */
.nv-ntfbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

    /*  ⚠⚠⚠ `width: auto` IS THE LINE THAT MATTERS, AND `flex` ALONE WAS NOT
        ENOUGH. tokens.css:591 gives every `.btn` in this system `width: 100%` —
        the house button is a full-width block by default, which is right for a
        Save at the foot of a form and wrong for a row of three doors. The first
        cut of this rule set only `flex: 0 0 auto`, and each button still took a
        line of its own because its WIDTH was still 100%. **A flex basis cannot
        argue with an explicit width.** */
    /*  ⚠⚠ v31.285 (owner): *"All buttons should be the same width."* `flex-basis`
        alone will not do it — the basis is a STARTING size and `flex-grow: 0`
        leaves each button at its own label's width, which is how "Devices" ended
        up half the width of "Notification settings". Three equal buttons need a
        stated basis AND permission to grow from it, so they divide the bar
        between them instead of each measuring its own text.
        ⚠ `min-width: 0` SO THE BASIS IS NOT A FLOOR: without it the longest
        label sets a minimum the other two cannot go below, and the row stops
        being equal the moment one label is translated into a longer word —
        Slovak "Nastavenia upozornení" is longer than the English. */
    .nv-ntfbar .btn {
        flex: 1 1 0;
        width: auto;
        min-width: 0;
        max-width: 240px;
        padding-inline: 18px;
    }

    /*  ⚠⚠ THE SCREEN YOU ARE ON IS MARKED, not omitted. Dropping the current
        page's own button would move the other two every time you navigate, and a
        bar whose contents shift is a bar nobody builds muscle memory for. */
    .nv-ntfbar .btn.on,
    .nv-devacts .btn.on {
        border-color: rgba(232,167,92,.5);
        background: rgba(232,167,92,.14);
        color: var(--nv-gold-bright, #f2bc74);
    }

    /*  on a phone the three become full-width stacked targets rather than three
        ellipsised stubs */
    @media (max-width: 560px) {
        /*  ⚠ `max-width` HAS TO BE LIFTED HERE TOO, not just the basis. The
            240px cap that keeps three buttons from sprawling on a wide screen
            also stopped them filling a 390px one — they stacked, each 240px
            wide against a 350px column, which reads as three mis-measured
            buttons rather than three targets. */
        .nv-ntfbar .btn {
            flex: 1 1 100%;
            max-width: none;
        }
    }

/*  ══ TWO CARDS PER ROW, ONE ON A PHONE ═══════════════════════════════════════
    ⚠ `auto-fit` + `minmax` rather than a media query: the columns collapse when
    the CONTENT runs out of room, so this keeps working inside the narrower middle
    column that pages with an `.ai-side` get (the 1g.1 backlog item) without
    knowing anything about that.
    ⚠⚠⚠ THE CARDS STRETCH TO THEIR ROW — `align-items` IS LEFT AT THE GRID
    DEFAULT, DELIBERATELY. The first cut set `align-items: start`, reasoning that
    a four-switch card should not grow white space to match a five-switch one.
    That reasoning was about the inside of a card and the cost was paid on the
    OUTSIDE: the master switch is a 93px card and the Email card beside it is
    253px, so `start` left a 160px hole in the middle of the screen and the grid
    read as half-drawn. Stretching gives every row a flush foot; the only price
    is a little more room under the shortest card's last switch, which looks like
    padding rather than like a fault. ⚠ MEASURED, NOT ASSUMED — the two numbers
    above come from the rendered page, which is also how the hole was found. */
/*  ⚠⚠ TWO, EXPLICITLY — NOT `auto-fit`. The owner asked for *"2 per row"*, and
    `auto-fit` with a 320px floor gave THREE on a 1366px screen, which is what the
    first cut did. `auto-fit` is the right tool when the column count is free;
    here it is a stated requirement, so it is stated. */
.nv-ntfgrid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

/*  ⚠ `minmax(0, 1fr)` RATHER THAN `1fr`: a grid track's default minimum is
    auto, so one long unbreakable word in a card would push the column past its
    share and the two would stop being halves. */

    /*  one column once two would be cramped — a phone, and the narrow middle
        column that pages with an AI rail get */
    @media (max-width: 860px) {
        .nv-ntfgrid {
            grid-template-columns: 1fr;
        }
    }

/*  a card that must not be halved — the notification list itself. A row of
    title, entity, time and three buttons has nowhere to go in a half column. */
.nv-ntfgrid .nv-wide {
    grid-column: 1 / -1;
}

/*  ⚠⚠ THE BOTTOM SPACING THE OWNER REPORTED. `.card` pays `--sp-5` (20px) all
    round, but the LAST `.nv-set` in a card keeps its own 11px bottom padding and
    then drops a `.sub` line under the label — so the descender of "Off by
    default…" sat on the card's border. The card gets a little more room at the
    foot, and the last row gives its own back. */
.card.nv-card {
    padding-bottom: var(--sp-4);
}

    .card.nv-card .nv-set:last-child {
        padding-bottom: 2px;
    }

    .card.nv-card h3 {
        margin: 0 0 10px;
        font-size: 15px;
        font-weight: 400;
        color: var(--nv-ink-2);
    }

/*  the Save / Cancel pair — NOT `.row`, for the reason in the header above */
/*  ⚠⚠ v31.285 (owner): *"Spacing needed above Save/Cancel Button."* The save row
    is a SIBLING of the card grid, not a member of it, so the grid's own 12px
    `gap` never applied to it — Save sat hard against the foot of the last card
    with nothing between them, which read as the card and the button being one
    object. The margin is stated here rather than added as a trailing spacer
    element, so the gap belongs to the row that needs it and cannot be left
    behind if the cards above are ever reordered. */
.nv-ntfsave {
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: var(--sp-5, 20px);
}

    /*  ⚠ SAME `width: auto` AS THE BAR, for the same tokens.css reason. Save and
        Cancel are a PAIR; two stacked full-width slabs read as two decisions. */
    .nv-ntfsave .btn {
        flex: 0 0 auto;
        width: auto;
        min-width: 132px;
        padding-inline: 22px;
    }

/*  the per-device controls, inline on the device row */
/*  ⚠⚠⚠ v31.287 (owner): *"the ON/OFF and Remove buttons should be the same
    width."* They were 76px and 106px — `min-width: 76px` set a floor and then
    each button took whatever its own label needed above it, so a two-letter
    word and a six-letter one produced two different pills in the same row.

    ⚠⚠ A GRID, NOT `flex: 1 1 0`. The obvious flex answer makes the two share
    the FREE SPACE, which is not the same thing as making them equal: the row
    is a wrapping flex line whose free space changes with the device name
    beside it, so the pair would resize as you scrolled a list of devices with
    differently-long labels. `grid-auto-columns: 1fr` in a content-sized
    container sizes every track to the WIDEST ITEM — the owner's own
    "same width as the widest" rule, and stable regardless of what is next to
    it.

    ⚠ AND A ROW WITH ONE BUTTON IS STILL RIGHT. A device the browser threw away
    offers Remove alone; one auto column sizes to that one button rather than
    stretching it across the space two would have taken. */
.nv-devacts {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 8px;
    align-items: center;
    flex: 0 0 auto;
}

    .nv-devacts .btn {
        width: auto;
        min-width: 76px;
        padding-inline: 14px;
    }

/*  ══ v31.311 — GL110 AND GL105 ══════════════════════════════════════════
    ⚠ BOTH REUSE `table.rpt-tbl`, which already carries the print sheet's type,
    rules and numeric alignment. What is declared here is only what is specific
    to these two: their column widths, and the one class on GL105 that has to
    tell a zero apart from a number. */
table.bs-tbl { table-layout: fixed; }
    table.bs-tbl col.k-ac { width: 34mm; }
    table.bs-tbl col.k-am { width: 32mm; }
    /*  ⚠ THE NAME COLUMN DECLARES NO WIDTH — it takes what is left, which is
        what makes the ellipsis rule below meaningful. */
    table.bs-tbl td.c-nm {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

table.br-tbl { table-layout: fixed; }
    table.br-tbl col.k-ac { width: 30mm; }
    table.br-tbl col.k-n  { width: 22mm; }
    table.br-tbl col.k-am { width: 30mm; }
    table.br-tbl td.c-nm {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /*  ⚠⚠ THE COLUMN THE REPORT EXISTS FOR. "Nothing left to do" and "forty-two
        left to do" are the two answers a reconciliation gives and they must not
        look alike on a photocopy — so it is WEIGHT, not colour alone. */
    table.br-tbl td.br-open { font-weight: 700; }
    table.br-tbl td.br-clear { color: #6b6b66; }

/*  ══ v31.313 — THE BANK RECONCILIATION STATEMENT (GL105 · detail) ═══════
    ⚠ Three tables per account, all on `table.rpt-tbl`, so the sheet's type,
    rules and numeric alignment come from one place as everywhere else. What is
    declared here is only what is specific: the widths, the two marks that have
    to survive a photocopy, and the block spacing that keeps one account's three
    tables reading as one thing. */
.br-acct { margin-bottom: 18px; page-break-inside: auto; }
    /*  ⚠⚠ THE ACCOUNT HEAD MUST NOT BE ORPHANED. A page that opens with the
        last two rows of an account nobody named is unreadable — so the head
        keeps its bridge with it. */
    .br-acct .br-head {
        display: flex;
        gap: 10px;
        align-items: baseline;
        margin: 14px 0 6px;
        page-break-after: avoid;
        break-after: avoid;
    }
    .br-acct .br-head .br-code { font-weight: 700; }
    .br-acct .br-head .br-nm { color: #4a4a46; }

    .br-histhead {
        display: flex;
        gap: 10px;
        align-items: baseline;
        margin: 12px 0 4px;
        font-size: 11px;
        letter-spacing: .06em;
        text-transform: uppercase;
        color: #6b6b66;
        page-break-after: avoid;
        break-after: avoid;
    }

table.br-bridge { table-layout: fixed; margin-bottom: 8px; }
    /*  ⚠ THE OPERATOR COLUMN IS NARROW AND CENTRED. It carries one glyph and
        its whole job is to line those glyphs up under each other. */
    table.br-bridge col.k-op { width: 10mm; }
    table.br-bridge td.c-op { text-align: center; color: #6b6b66; }
    table.br-bridge col.k-ct { width: 14mm; }
    table.br-bridge col.k-am { width: 34mm; }
    table.br-bridge td.c-ct { text-align: right; color: #6b6b66; }

table.br-lines { table-layout: fixed; }
    table.br-lines col.k-dt { width: 24mm; }
    table.br-lines col.k-rf { width: 34mm; }
    table.br-lines col.k-am { width: 30mm; }
    table.br-lines col.k-ag { width: 16mm; }
    table.br-lines td.c-ds {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /*  ⚠⚠⚠ AN ITEM OVER 60 DAYS OLD IS THE ROW THIS SHEET EXISTS FOR. It is set
        apart by WEIGHT rather than colour alone, because a reconciliation gets
        photocopied and a colour does not survive that. */
    table.br-lines td.br-stale { font-weight: 700; }
    table.br-lines tr.br-none td { color: #8a8a84; font-style: italic; }

/*  ⚠⚠ v31.314 — A QUIET MONTH IS SET BACK, NOT HIDDEN. It had no line on
    either side; its balance is the one it was handed. Greying it says "nothing
    happened here" where leaving the row out would say "nobody holds this". */
table.br-hist tr.br-quiet td { color: #8a8a84; }

/*  ⚠⚠⚠ "RECONCILED THROUGH" IS THE ANSWER THE WHOLE SECTION EXISTS TO GIVE, so
    it is the one row on the history that reads as a conclusion. */
table.br-hist tfoot td { font-weight: 700; border-top: 1px solid #cdcbc6; }

table.br-hist { table-layout: fixed; }
    table.br-hist col.k-pe { width: 22mm; }
    table.br-hist col.k-am { width: 30mm; }
    table.br-hist col.k-n  { width: 22mm; }
    table.br-hist td.br-clear { color: #2c6b3f; font-weight: 700; }
    table.br-hist td.br-open { color: #6b6b66; }

/*  ⚠ THE GRAIN CHECKBOX on the parameter card — the same gold checkbox the KV
    sections and the VAT checklist use, on one row with its label. */
.rpt-grain .rpt-grainrow {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 6px 0;
}

/*  ══ v31.313 — THE BOARD PACK (GL001 · board form) ══════════════════════
    ⚠ FOUR TILES ACROSS, and they wrap rather than shrink: a KPI whose figure
    has been squeezed to fit is a KPI nobody can read at a glance, which is the
    only thing a KPI is for. */
.bd-kpis {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 6px 0 14px;
}
    .bd-kpi {
        flex: 1 1 130px;
        border: 1px solid #cdcbc6;
        border-radius: 4px;
        padding: 8px 12px;
    }
    .bd-kpi .bd-k {
        font-size: 9px;
        letter-spacing: .08em;
        text-transform: uppercase;
        color: #6b6b66;
    }
    .bd-kpi .bd-v {
        font-size: 19px;
        margin-top: 2px;
        font-variant-numeric: tabular-nums;
    }
    .bd-kpi .bd-d { font-size: 10px; color: #6b6b66; margin-top: 1px; }

/*  ══ v31.314 — FIVE TILES, NOT FOUR ═════════════════════════════════════
    Gross margin and EBITDA joined the strip when A-130 landed. The basis
    narrows so five fit a printed A4 width; the wrap above is still the
    fallback, because a squeezed figure is worse than a wrapped row. */
.bd-kpis5 .bd-kpi { flex: 1 1 104px; }
.bd-kpis5 .bd-kpi .bd-v { font-size: 17px; }

/*  ⚠⚠⚠ THE GROSS PROFIT AND EBITDA LINES CARRY WEIGHT, NOT A FILL. This
    document gets photocopied and faxed, exactly like the trial balance's
    totals — a tint that survives neither is not emphasis, it is a decision
    that silently stops applying. */
table.bd-tbl tr.bd-key td {
    font-weight: 700;
    border-top: 1px solid #cdcbc6;
}
/*  ⚠ AND THE ADD-BACK IS SET QUIETER THAN THE FIGURE IT FEEDS, because it is
    workings rather than a result — but it is ON the sheet, so the EBITDA above
    it can be checked without asking anyone. */
table.bd-tbl tfoot tr.bd-addback td {
    font-weight: 400;
    color: #4a4a46;
}

table.bd-tbl { table-layout: fixed; }
    table.bd-tbl col.k-ac { width: 28mm; }
    table.bd-tbl col.k-am { width: 26mm; }
    table.bd-tbl col.k-pc { width: 20mm; }
    /*  ⚠ ELLIPSIS ON THE NAME ONLY — the owner's v31.303 rule. A truncated
        account code cannot be matched against anything. */
    table.bd-tbl td.c-nm {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

/*  ══ v31.315 — GL080 · THE FINANCIAL ANALYSIS ═══════════════════════════
    ⚠⚠ THE WHOLE SHEET IS ONE PRINTED PAGE, so every block below is sized in
    the same units as the reports around it and nothing here is set in px that
    a print stylesheet would then have to undo. */
.fa-head { border-bottom: 1px solid #cdcbc6; padding-bottom: 6px; margin-bottom: 10px; }
    .fa-head .fa-co { font-size: 15px; font-weight: 700; }
    .fa-head .fa-meta { font-size: 11px; color: #6b6b66; margin-top: 2px; }

/*  ⚠ SIX TILES THAT WRAP RATHER THAN SHRINK — the board pack's own rule. A KPI
    squeezed until its figure is unreadable is not a KPI. */
.fa-rail { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 14px; }
    .fa-kpi, .fa-r {
        flex: 1 1 120px;
        border: 1px solid #cdcbc6;
        border-radius: 4px;
        padding: 7px 10px;
    }
    .fa-k { font-size: 8.5px; letter-spacing: .07em; text-transform: uppercase; color: #6b6b66; }
    .fa-v { font-size: 16px; font-weight: 700; margin-top: 2px; font-variant-numeric: tabular-nums; }
    .fa-d { font-size: 9.5px; color: #6b6b66; font-variant-numeric: tabular-nums; }
    /*  ⚠⚠ THE ARROW CARRIES COLOUR **AND** A GLYPH. This gets photocopied, and
        a direction that survives only in colour stops being a direction. */
    .fa-up { color: #2c6b3f; }
    .fa-dn { color: #8a3b12; }

.fa-duo { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 14px; }
    .fa-chart, .fa-ring { flex: 1 1 300px; min-width: 260px; }
    .fa-ct { font-size: 9px; letter-spacing: .07em; text-transform: uppercase; color: #6b6b66; }
    .fa-chart svg, .fa-ring svg { width: 100%; height: auto; }
    .fa-ring { display: flex; gap: 12px; align-items: flex-start; }
    .fa-ring svg { max-width: 120px; flex: 0 0 120px; }
    .fa-ring .fa-legend { flex: 1 1 auto; }
    .fa-sw { display: inline-block; width: 8px; height: 8px; margin-right: 5px; }

table.fa-tbl { table-layout: fixed; margin-bottom: 12px; }
    table.fa-tbl col.k-am { width: 26mm; }
    table.fa-tbl td.c-nm { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.fa-ratios { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }

/*  ⚠ AT PHONE WIDTH THE TWO-UP BLOCKS STACK. The reports module is read on a
    desk and on a phone, and a donut beside its legend at 320px is neither. */
@media (max-width: 720px) {
    .fa-duo { display: block; }
    .fa-chart, .fa-ring { width: 100%; margin-bottom: 12px; }
    .fa-ring svg { max-width: 96px; flex-basis: 96px; }
}

/*  ══ v31.317 — DOCUMENT AI, ROUND 1 ═════════════════════════════════════
    ⚠⚠⚠ THESE ARE APP SCREENS, NOT PRINT SURFACES, AND THE FIRST DRAFT OF THIS
    BLOCK FORGOT IT. NOVERA v2's shell is DARK; the reports CSS above is light
    because a report is a printed page. A cream fill with the app's own light
    text on it produced white-on-cream rows in the match table — the two rows
    that matter most, the VAT number and the changed IBAN, were the two nobody
    could read. Caught by looking at the rendered page rather than at the
    markup.

    ⚠⚠ SO EVERY EMPHASIS BELOW IS A TRANSLUCENT TINT OVER WHATEVER IS BEHIND
    IT, in the house pattern `.card.suggest` already uses — `rgba(232,167,92,
    .06)` over `rgba(232,167,92,.45)` — plus a border and a word. Nothing here
    sets an opaque background, and nothing relies on colour alone. */

/*  ══ v31.325 (owner) — THE PROVENANCE CHIP ══════════════════════════════
    *"The icons for the legend should be on the same line as the line result
    data."* · *"Also remove the colored backgrounds and instead use colored
    borders."*

    ⚠⚠⚠ ONE CHARACTER, FOUR COLOURS, BESIDE THE VALUE. It used to sit after the
    LABEL on the reasoning that the eye is there when it asks "where did this
    come from" — which was wrong: the question is asked WHILE reading the value,
    and a marker a line away from what it describes makes the reader pair them
    up themselves, four times per field, on a screen with forty fields.

    ⚠⚠ AND IT IS AN OUTLINE NOW, NOT A FILL. Four solid chips per row is four
    blocks of saturated colour competing with the figures they annotate; the
    same four as outlines carry the same information and let the value be the
    brightest thing in the row. `currentColor` does both the letter and the
    edge, so a source is ONE declaration and the two can never disagree.

    ⚠ `inline-flex` RATHER THAN `inline-block`: the chip centres its own glyph
    at any size, and stays inline in the legend where it sits mid-sentence. */
.doc-pv {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 17px; height: 17px;
    border-radius: 4px;
    border: 1.5px solid currentColor;
    background: transparent;
    font-size: 10px; font-weight: 700; font-style: normal;
    line-height: 1;
}
.doc-pv-d { color: var(--nv-blue-bright, #4a92dd); }  /* the document said so       */
.doc-pv-h { color: var(--acc-green, #3fca85); }       /* this account's own history */
.doc-pv-p { color: var(--acc-purple, #b184e6); }      /* a decision accepted before */
/*  ⚠⚠ v31.328 (owner) — *"a Coloured 'A' square"*. Gold, which is the shell's
    own accent and the one hue not already spoken for by D, H, P or the green
    tick — the five markers have to be told apart at 18px on a dark ground, and
    that is the whole job of this line. */
.doc-pv-a { color: var(--nv-gold, #e8a75c); }         /* set up in another catalog  */
.doc-pv-u { color: var(--nv-gold, #e8a75c); }         /* you, in this review        */

/*  ══ v31.326 (owner) — CONFIRMED BY A PERSON ═══════════════════════════════
    *"make the icons clickable so state 'U' — 'changed by you in this review'
    can be green ticked"*.

    ⚠⚠⚠ THE TICK REPLACES THE LETTER — the owner's own choice of three, and the
    right one: a confirmed field should stop competing for attention so the eye
    goes to what is still flagged. The letter is not lost; it moves to the
    hover, and `ProposedSource` on the proposal never changed at all.

    ⚠⚠ AND IT IS THE ONE FILLED CHIP. The four sources are outlines because they
    are all the same KIND of thing — where a value came from. This is a
    different kind: a decision somebody made. A filled tick among outlines reads
    as "done" at a glance, which is the whole job.                             */
.doc-pv-ok {
    color: var(--nv-good, #58b368);
    border-color: var(--nv-good, #58b368);
    background: rgba(88,179,104,.16);
}

/*  ⚠⚠⚠ THE BUTTON MUST LOOK EXACTLY LIKE THE SPAN. A chip that changed shape
    the moment it became pressable would say that a confirmable field and an
    unconfirmable one are different KINDS of field. They are not — one simply
    has nothing to agree with. */
button.doc-pv {
    padding: 0;
    font-family: inherit;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}
    button.doc-pv:hover { border-color: var(--nv-ink, #f1f3f9); color: var(--nv-ink, #f1f3f9); }
    /*  ⚠ A VISIBLE FOCUS RING. These are the only keyboard-reachable controls in
        a grid of forty-one cells; losing track of which one has focus makes the
        grid unusable without a mouse. */
    button.doc-pv:focus-visible { outline: 2px solid var(--nv-gold, #e8a75c); outline-offset: 2px; }
    /*  ⚠⚠ THE CONFIRMED CHIP KEEPS ITS GREEN ON HOVER. Turning it to ink would
        say "this will become something else" — and what it becomes is
        un-confirmed, which the title already says. */
    button.doc-pv.doc-pv-ok:hover {
        border-color: var(--nv-good, #58b368);
        color: var(--nv-good, #58b368);
        background: rgba(88,179,104,.28);
    }

/*  ⚠ A CONFIRMED FIELD IS QUIETER, NOT LOUDER. It has been dealt with, and the
    screen's job from that moment is to point at everything else. */
.doc-fld.doc-done .doc-t { color: var(--nv-ink-2, #aab3c8); }

/*  ══ v31.325 — THE GRID OWNS ITS OWN LAYOUT ════════════════════════════════
    ⚠⚠⚠ IT USED TO BORROW `.fld-wrap` + `.fl-hint`, the house FORM-INPUT trio.
    That is a flex COLUMN built to stand a floating label above an `<input>`, so
    the provenance chip — a sibling of the label — was handed a row of its own
    and every field rendered as four stacked lines for two facts. Nothing chose
    that; the layout inherited a shape meant for something else.

    ⚠⚠ AND A READ-ONLY GRID HAS NO BUSINESS WEARING INPUT CLASSES ANYWAY. Every
    rule written for `.fld-wrap` in this stylesheet — the inline editor's
    pencil, the mobile pair-splitter, the account page's tree cell — reaches a
    grid that has no input in it at all.                                      */
/*  ══ v31.326 (owner) — FIVE COLUMNS AT 05-Screen, DOWN TO ONE AT 01 ═══════
    *"Make the main body … effectively 5 columns for screen 05-Screen and RWD
    down to screen 01-Screen."*

    ⚠⚠⚠ ONE COLUMN IS THE BASE AND EVERY STEP ADDS ONE. Written the other way
    round — three columns with max-width rules taking them away — a width nobody
    wrote a rule for renders the widest layout, which is the one that breaks. A
    phone is the safe default and always has been.

    ⚠⚠ THE STEPS ARE THE PROJECT'S OWN NAMED SCREENS, not numbers picked to fit
    this grid: 01 = 390, 02 = 768, 03 = 1024, 04 = 1366, 05 = 1920. A sixth
    breakpoint here would be a sixth screen size nobody else in this product
    has, and the first thing to drift.                                        */
.doc-grid {
    display: grid;
    grid-template-columns: 1fr;          /* 01-Screen (390) */
    gap: 15px 18px;
}
@media (min-width: 768px)  { .doc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }  /* 02 */
@media (min-width: 1024px) { .doc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }  /* 03 */
/*  ⚠⚠ v31.327 — 04-Screen GOES BACK TO FOUR, and this is the menu's bill.
    Five columns fitted when the panel track was collapsed; with the menu in
    it the content column at 1366 is 600px, and five columns of 89px wrap a
    date onto two lines. Four is 136px — the same width the six columns get
    at 1920, which is the width that was signed off. */
/*  ⚠⚠⚠ v31.328 (owner) — v31.327's 04 AND 05 RUNGS WERE HERE, AND THEY ARE
    GONE RATHER THAN OVERRIDDEN. *"the 'Account setup · proposed.' should have
    3 columns per row. Also in Process document to invoice, the 'invoice entry ·
    proposed.' should have three columns per row."*

    The owner asked for six in the round before this one, saw six, and asked
    for three. Three is the later ruling and the only one — replacing these
    two rungs with wider ones would leave two rules about one width, and the
    winner would be whichever came last in the file.

    ⚠ THE 04-Screen TIGHTENING BAND WENT WITH THEM. It existed because four
    columns at 1366 were 116px and a date broke at its own hyphen; three
    columns are 182px at 1024 and wider above, so there is nothing to tighten
    and a band outliving its reason would give the widest screens the
    smallest type.                                                          */
/*  ⚠⚠ v31.327 (owner) — SIX AT 05-Screen. *"…with 6 columns per row as
    requested."* Four and five were what the old width could carry; with the
    1366 and 1410 caps lifted for this page (see `.doc-app` in responsive.css)
    there is room for six that are still wide enough to read a date in.

    ⚠ MEASURED WITH THE MODULE MENU IN PLACE, not with its track collapsed —
    the owner asked for the menu back in that track in the same round, so the
    260px never came to this grid:

    Measured on the running app, grid width inside the card — not the content
    column, which the card's own padding takes 82px out of:

        viewport   grid   columns   each
          1920      864       6     129px
          1366      518       4     116px
          1024      582       3     182px                                     */

/*  ⚠⚠ v31.340 — `height: 100%` IS WHAT MAKES THE BOTTOM A REAL BOTTOM. A grid
    item stretches its BOX to the row height but its flex column still lays out
    against its content, so `margin-top: auto` on the edit strip had nothing to
    push against and the strips stayed ragged. */
.doc-fld {
    display: flex; flex-direction: column; gap: 3px; min-width: 0;
    height: 100%;
}

/*  ⚠ THE LABEL CLAMPS TO ONE LINE so the three columns stay aligned; the full
    wording is on `title`. A label that wrapped would push its own value down
    and leave the row beside it floating. */
.doc-k {
    font-size: 12px;
    color: var(--nv-ink-3, #6b7690);
    line-height: 18px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/*  ⚠⚠⚠ THE ONE LINE THE OWNER ASKED FOR. Baseline rather than centre, so the
    chip sits with the text rather than floating in the middle of a tall value;
    `min-width: 0` so a long IBAN wraps inside the cell instead of widening the
    column and pushing the grid sideways. */
.doc-row { display: flex; align-items: baseline; gap: 8px; min-width: 0; }

.doc-t {
    font-size: 16px;
    min-width: 0;
    overflow-wrap: anywhere;   /* an IBAN has no spaces to break at */
}

/*  ⚠⚠ THE AMBER EDGE IS A BORDER AND A WORD, never colour alone. */
.doc-fld.doc-check {
    border-left: 3px solid var(--nv-warn, #d9a13b);
    padding-left: 9px;
}
.doc-flag { font-size: 12px; font-weight: 600; color: var(--nv-warn, #d9a13b); margin-top: 2px; }
.doc-empty { color: var(--nv-ink-3, #6b7690); }
.doc-say { font-size: 13px; margin-top: 1px; color: var(--nv-ink-2, #aab3c8); }

/*  ══ v31.333 (owner) — BOTH CURRENCIES IN ONE CARD ═════════════════════════
    *"show both currency values and currency code and the converted value in
    base currency in THE SAME card space. do not create a separate card for
    multi-currency conversion."*

    ⚠⚠⚠ TWO RANKS, NOT TWO VALUES. The document's own figure keeps `.doc-t`'s
    weight because it is the fact the supplier stated; the conversion sits under
    it, smaller and quieter, because it is derived. A second line at equal
    weight would read as a second amount and a reader would have to work out
    which one to check against the invoice.

    ⚠⚠ TABULAR FIGURES ON BOTH, so the decimal points of the two lines sit under
    one another and a transposed digit is visible rather than merely present. */
.doc-cur {
    font-size: 12.5px; font-weight: 600; letter-spacing: .04em;
    margin-inline-start: 6px; color: var(--nv-ink-3, #6b7690);
    white-space: nowrap;
}
/*  ══ v31.334 (owner) — THE ANALYSIS SLOT IS A CONTROL ══════════════════════
    *"The business analysis must have drop-down selection to allow user select
    /change business analysis to be used for the document."*

    ⚠⚠ IT SITS ON THE VALUE'S OWN ROW, beside the marker, because that is where
    the value it replaces was — a select on a line of its own would make every
    analysis slot twice the height of every other field and break the three
    columns the owner asked for.

    ⚠ THE SELECT TAKES THE SPACE AND THE BUTTON TAKES WHAT IT NEEDS. `min-width:
    0` is what lets a long item name shrink instead of pushing the button out of
    the card. */
.doc-pick { display: flex; gap: 6px; align-items: center; min-width: 0; flex: 1 1 auto; }
    .doc-pick .doc-sel {
        flex: 1 1 auto; min-width: 0;
        font-size: 14px; padding: 3px 6px;
    }
    .doc-pick .doc-selgo { flex: 0 0 auto; }

.doc-base {
    font-size: 13.5px; margin-top: 1px;
    color: var(--nv-ink-2, #aab3c8);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

/*  ── the analysing state ───────────────────────────────────────────────── */
.doc-wait { max-width: 900px; }
.doc-waith { font-size: 14px; font-weight: 600; margin-bottom: 8px; }
.doc-steps { display: flex; flex-direction: column; gap: 8px; }
.doc-step { display: flex; gap: 10px; align-items: flex-start; font-size: 14.5px; }
    .doc-step .doc-dot {
        flex: 0 0 auto; width: 15px; height: 15px; border-radius: 50%;
        border: 1.5px solid rgba(255,255,255,.22); margin-top: 3px;
    }
    .doc-step.doc-done .doc-dot { background: var(--nv-good, #58b368); border-color: var(--nv-good, #58b368); }
    .doc-step.doc-done .doc-lbl { color: var(--nv-ink-2, #aab3c8); }
    /*  ⚠ THE LIVE STEP IS MARKED BY A RING AS WELL AS A COLOUR, for the same
        reason the amber edge carries a word. */
    .doc-step.doc-live .doc-dot {
        border-color: var(--nv-gold, #e8a75c);
        box-shadow: 0 0 0 3px rgba(232,167,92,.20);
    }
    /*  ⚠⚠ `.doc-todo`, NOT `.doc-wait`. The card is `.doc-wait`; a step state
        of the same name made `.doc-step.doc-wait` inherit the card's rules —
        one class name meaning two things. */
    .doc-step.doc-todo { opacity: .45; }
.doc-bar { height: 3px; background: rgba(255,255,255,.10); border-radius: 2px; overflow: hidden; margin-top: 11px; }
    .doc-bar i { display: block; height: 100%; width: 68%; background: var(--nv-gold, #e8a75c); }

/*  ── the match panel ─────────────────────────────────────────────────────
    ⚠⚠ A LIKELY MATCH AND A POSSIBLE ONE DO NOT LOOK ALIKE. One offers Update;
    the other offers a list and chooses nothing. */
.doc-likely { border-color: rgba(232,167,92,.45); background: rgba(232,167,92,.06); }
.doc-maybe  { border-color: rgba(255,255,255,.16); }
.doc-new    { border-color: rgba(88,179,104,.40); }
.doc-mh { font-weight: 600; font-size: 14.5px; }
.doc-acc { font-size: 16px; margin: 4px 0 8px; }
table.doc-mtbl { border-collapse: collapse; width: 100%; font-size: 14px; }
    table.doc-mtbl th, table.doc-mtbl td {
        border-bottom: 1px solid rgba(255,255,255,.10);
        padding: 5px 8px; text-align: left; vertical-align: top;
    }
    table.doc-mtbl th {
        font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
        color: var(--nv-ink-3, #6b7690); font-weight: 700;
    }
    table.doc-mtbl td.num, table.doc-mtbl th.num { text-align: right; font-variant-numeric: tabular-nums; }
    /*  ⚠⚠⚠ THE SENSITIVE ROWS ARE MARKED BY AN EDGE AND A TINT, NOT A FILL —
        VAT registration, address and bank details, the three the owner named.
        A differing IBAN is the one row a reviewer must look at, and a table
        where every row looks alike is a table where it gets missed. */
    table.doc-mtbl tr.doc-sens td {
        background: rgba(232,167,92,.07);
    }
    table.doc-mtbl tr.doc-sens td:first-child {
        box-shadow: inset 3px 0 0 0 rgba(232,167,92,.55);
    }
/*  ══ v31.328 (owner) — THE ANOTHER-CATALOG CARD ════════════════════════════
    ⚠⚠ GOLD EDGE, NOT GREEN AND NOT AMBER. Green is `.doc-new` — this entity is
    about to gain something; amber is `check` — a value nobody stands behind.
    This card is neither: it is a fact about somewhere else, offered. It wears
    the same gold as the `A` on the fields it filled, so the card and the
    markers read as one statement rather than two. */
.doc-else { border-color: rgba(232,167,92,.40); }
.doc-eline { font-size: 15px; margin: 5px 0 6px; display: flex; gap: 8px;
             align-items: baseline; flex-wrap: wrap; }
/*  ⚠ THE SQUARE SITS ON THE HEADING'S BASELINE, like the row markers do. */
.doc-else .doc-mh { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }

.doc-w { font-weight: 600; }
.doc-w-decisive { color: var(--nv-good, #58b368); }
.doc-w-differs { color: var(--nv-warn, #d9a13b); }
/*  ⚠⚠ v31.329 — A SUPPORTING ROW AGREES, so it is no longer the grey an
    absence gets. It is the quieter green: the same family as `decisive`,
    because both are agreements, at the weight each carries. */
.doc-w-supporting { color: var(--acc-green, #3fca85); opacity: .78; }
/*  ⚠ AND AN ABSENCE IS THE GREY. Nothing on file is not a result. */
.doc-w-absent { color: var(--nv-ink-3, #6b7690); font-weight: 500; }
.doc-warn {
    margin-top: 9px; padding: 9px 11px; font-size: 14px;
    border: 1px solid rgba(232,167,92,.50); border-radius: 6px;
    background: rgba(232,167,92,.07);
    color: var(--nv-ink, #f1f3f9);
}
/*  ⚠ v31.327 — THE COUNT IS A BADGE, NOT A WORD in the sentence. It sits
    ahead of the text so no language has to find a slot for it, and it is the
    one thing in the box that carries weight, because it is the number the
    reader is driving to zero. `float` rather than a flex row: the sentence
    wraps around it in the 350px rail instead of being squeezed into a
    second column. */
.doc-warn .doc-n {
    float: inline-start; margin: 0 8px 0 0;
    min-width: 22px; padding: 1px 6px;
    font-size: 13px; font-weight: 700; text-align: center;
    border: 1px solid rgba(232,167,92,.55); border-radius: 5px;
    color: var(--nv-warn, #d9a13b);
    font-variant-numeric: tabular-nums;
}
.doc-acts { margin-top: 11px; }
.doc-walk {
    display: flex; gap: 10px; align-items: baseline;
    border-color: rgba(232,167,92,.45); background: rgba(232,167,92,.06);
}

/*  ── the proposal ────────────────────────────────────────────────────────*/
.doc-file { display: flex; gap: 9px; align-items: center; font-size: 15px; flex-wrap: wrap; }
.doc-clip { opacity: .75; }
.doc-line { border-top: 1px solid rgba(255,255,255,.10); padding-top: 9px; margin-top: 9px; }
/*  ══ v31.329 — THE HOUSE-WORDING OFFER ════════════════════════════════════
    ⚠⚠ IT IS QUIETER THAN THE LINE IT SITS UNDER. The document's own words are
    the value; this is a suggestion, and a suggestion that shouts competes with
    the thing it is suggesting about. Dashed edge, no fill — the visual grammar
    this product already uses for "offered, not applied". */
.doc-wording {
    display: flex; gap: 9px; align-items: baseline; flex-wrap: wrap;
    margin-top: 8px; padding: 7px 10px;
    border: 1px dashed rgba(104,152,232,.38); border-radius: 6px;
}
    .doc-wording .doc-t { font-size: 14px; }
    .doc-wording .doc-say { font-size: 12px; }
    .doc-wchip { flex: 0 0 auto; white-space: normal; height: auto; min-height: 28px;
                 padding: 4px 10px; font-size: 12.5px; line-height: 1.25; }
.doc-lno {
    font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
    color: var(--nv-ink-3, #6b7690); font-weight: 700; margin-bottom: 4px;
}
.doc-legend {
    display: flex; gap: 16px; flex-wrap: wrap; font-size: 13px;
    color: var(--nv-ink-2, #aab3c8); margin-top: 13px; padding-top: 10px;
    border-top: 1px solid rgba(255,255,255,.10);
}
    /*  ⚠⚠ THE LEGEND'S CHIP IS THE GRID'S CHIP, ON THE SAME LINE AS ITS OWN
        SENTENCE. That is the whole job of a legend: if the key and the thing it
        explains do not look identical, the reader has to decide whether they
        are the same marker — which is the doubt the legend existed to remove. */
    .doc-legend > span {
        display: inline-flex; align-items: baseline; gap: 6px; min-width: 0;
    }
.doc-rules {
    font-size: 13px; margin-top: 8px; display: flex; flex-direction: column; gap: 3px;
}

/*  ══ v31.326 (owner) — THE REVIEW CARD IN THE RIGHT RAIL ═══════════════════
    *"Create card for the section highlighted in green and move it to the top of
    the right column."*

    ⚠⚠⚠ IT IS ~350px WIDE, which is the width that broke `.doc-choose` in
    v31.318 and `.doc-block` in v31.321. Same rail, same two rules, third time:
    `.chips` is a fixed-height row that does not wrap and `.chip` shrinks, so a
    label like "Save without the bank details" renders outside its own box. */
.doc-review .doc-acts,
.doc-review .chips {
    display: flex; flex-wrap: wrap; gap: 8px; height: auto; align-items: center;
}
    .doc-review .chip {
        flex: 0 0 auto;
        white-space: normal;      /* ⚠ these labels are sentences, not words */
        height: auto; min-height: 32px;
        line-height: 1.25; padding: 6px 12px;
    }

/*  ⚠⚠ THE LEGEND STACKS IN THE RAIL. Four key-and-sentence pairs on one wrapped
    row at 350px produces four ragged lines that read as one paragraph; one per
    row is a list, which is what a legend is. */
.doc-review .doc-legend { flex-direction: column; gap: 7px; margin-top: 11px; }
/*  ══ v31.328 (owner) — THE ACCOUNT CARD MOVED INTO THIS RAIL ═══════════════
    *"for invoice, please move the second card to the right panel at the top as
    shown in the diagram."*

    ⚠⚠⚠ THIS IS THE FOURTH COMPONENT THIS RAIL HAS BROKEN — `.doc-choose` at
    v31.318, `.doc-block` at v31.321, `.doc-review .chips` at v31.326, and now a
    four-column table. The rail is 350px inside its padding; the table's own
    columns need, measured:

        matched on   on the document   on the account   weight
           108             150              150           78    = 486px

    ⚠⚠ SO IT STOPS BEING A TABLE HERE. Each row becomes its own block with its
    three values labelled, which is the same information in the shape the width
    allows — not a horizontal scrollbar, which hides the account side of a
    comparison behind a gesture nobody makes.

    ⚠ THE HEAD ROW GOES because every cell now carries its own heading; leaving
    it would print the four column names once with nothing under them.

    ⚠⚠⚠ SCOPED ON `.ai-side`, NOT ON `.doc-review`. The panel is a SIBLING of
    the Review card inside the rail, not a child of it — a descendant
    selector off `.doc-review` matches nothing at all, which is a rule that
    looks right in the file and does nothing on the screen. */
.ai-side table.doc-mtbl,
.ai-side table.doc-mtbl tbody,
.ai-side table.doc-mtbl tr,
.ai-side table.doc-mtbl td { display: block; width: auto; }
.ai-side table.doc-mtbl thead { display: none; }
    /*  ⚠⚠ EVERY ROW IS INDENTED THE SAME 12px, shaded or not. Measured, not
        guessed: a plain row's heading started at 0 and a shaded row's at 12,
        because the shaded one carries a 3px edge and 9px of clearance. Reading
        down the card the headings stepped left and right, which makes a list of
        four comparisons look like two lists. The border now sits INSIDE the
        shared indent, so the text lands at 12px in both cases. */
    .ai-side table.doc-mtbl tr {
        border-bottom: 1px solid rgba(255,255,255,.10);
        padding: 6px 0 7px 12px;
    }
    .ai-side table.doc-mtbl tr:last-child { border-bottom: 0; }
    .ai-side table.doc-mtbl td {
        border-bottom: 0; padding: 1px 0 1px 9px;
        overflow-wrap: anywhere;   /* an IBAN has no spaces to break at */
    }
    /*  ⚠ THE FIRST CELL IS THE ROW'S OWN HEADING — "VAT number", "IBAN" — so it
        is set as one rather than as another value. */
    .ai-side table.doc-mtbl td:first-child {
        padding-left: 0; font-weight: 600; font-size: 12.5px;
        letter-spacing: .03em; text-transform: uppercase;
        color: var(--nv-ink-3, #6b7690);
    }
    /*  ⚠⚠ A BORDER, NOT AN INSET SHADOW — caught on screen, not by a gate.
        `box-shadow: inset` paints inside the padding box, so on a `display:
        block` row it drew the gold stripe OVER the first character of the row's
        heading: "IBAN" rendered as "BAN". A left border takes its own 3px out
        of the box and pushes the content clear, which is exactly what
        `.doc-fld.doc-check` has always done for the amber edge. */
    .ai-side table.doc-mtbl tr.doc-sens td { background: none; }
    .ai-side table.doc-mtbl tr.doc-sens {
        background: rgba(232,167,92,.07);
        border-left: 3px solid rgba(232,167,92,.55);
        padding-left: 9px;          /* 3 + 9 = the 12 every other row uses */
    }

/*  ⚠⚠ THE CELL LABELS EXIST ONLY IN THE STACKED LAYOUT. In a real table they
    would print the column heading on every row; here they are the only thing
    telling the document's value from the account's. */
.doc-mk { display: none; }
.ai-side .doc-mk {
    display: block;
    font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
    color: var(--nv-ink-3, #6b7690);
}

/*  ⚠ AND THE CARD ITSELF STOPS BEING AS WIDE AS THE MAIN COLUMN. */
.ai-side .doc-mtbl { font-size: 13.5px; }
.ai-side .doc-acc  { font-size: 14.5px; }

/*  ══ v31.330 (owner) — THE MATCH VERDICTS, TWO TO A ROW ════════════════════
    *"instead of a 5 line detail repeating some of the data already shown in
    header simply put a two liner: VAT NUMBER · decisive · COMPANY NUMBER ·
    decisive · NAME · agrees · IBAN · agrees."*

    ⚠⚠ TWO TRACKS AT ANY WIDTH — `minmax(0, 1fr)` and not `1fr`, because a grid
    track's default minimum is `auto` and an IBAN has no space to break at: one
    unbreakable value would push the second column off the card. Every value in
    here can also wrap mid-string for the same reason. */
.doc-mw {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px 12px; margin: 2px 0 4px;
}
.doc-mwc {
    display: flex; flex-direction: column; gap: 1px;
    min-width: 0; padding: 4px 0 5px;
    border-bottom: 1px solid rgba(255,255,255,.10);
    overflow-wrap: anywhere;
}
    /*  ⚠ THE IDENTIFIER'S NAME IS A HEADING, set like every other heading on
        this card, so the verdict under it is the only thing carrying weight. */
    .doc-mwk {
        font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
        color: var(--nv-ink-3, #6b7690); font-weight: 700;
    }
    .doc-mwc .doc-w { font-size: 13.5px; }
    /*  ⚠⚠ THE TWO VALUES APPEAR ONLY UNDER A `differs` VERDICT — see the note in
        `_DocMatch.cshtml`. They are quieter than the verdict because the verdict
        is what sends the reader here. */
    .doc-mwv { font-size: 12.5px; color: var(--nv-ink-2, #aab3c8); }
    .doc-mwv .doc-mk { display: block; }
    /*  ⚠⚠⚠ THE SENSITIVE EDGE SURVIVES THE TABLE IT WAS WRITTEN FOR. VAT
        registration, address and bank details are the three the owner named, and
        a border rather than an inset shadow for the reason v31.328 found on
        screen: an inset shadow paints over the first character. */
    .doc-mwc.doc-sens {
        border-left: 3px solid rgba(232,167,92,.55);
        background: rgba(232,167,92,.07);
        padding-left: 7px;
    }

/*  ══ v31.330 (owner) — ACTIONS IN EQUAL PAIRS ══════════════════════════════
    *"Buttons should span width of card with equal size where possible."*

    ⚠⚠⚠ THIS OVERRIDES `.doc-review .chips`, WHICH IS A FLEX ROW WITH
    `flex: 0 0 auto` ON EVERY CHIP — so the grid declaration alone would be
    ignored on the rail where the owner is looking. The class is applied WITHOUT
    `.chips` on the elements it governs, and the chip rule is restated here for
    the same specificity reason. */
/*  ⚠⚠⚠ AND THE SCOPED COPY IS NOT DUPLICATION — IT IS THE FIX. The first
    draft declared these unscoped and the probe showed four buttons in four
    rows, not two pairs: `.doc-review .doc-acts` is `display: flex` at
    specificity (0,2,0) and `.doc-pair` is (0,1,0), so the grid never applied in
    the one place the owner was looking. `width: 100%` on each chip then made
    the flex row wrap one per line, which looks deliberate and is not. */
.doc-pair, .doc-stack,
.doc-review .doc-pair, .doc-review .doc-stack {
    display: grid; gap: 8px; align-items: stretch;
}
.doc-pair, .doc-review .doc-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.doc-stack, .doc-review .doc-stack { grid-template-columns: minmax(0, 1fr); }
    /*  ⚠ A CHIP IS NORMALLY A FIXED-HEIGHT INLINE PILL. Inside a pair it is a
        grid item that fills its track, and these labels are sentences — "Save
        without the bank details" — so it has to be allowed to grow downwards
        rather than printing outside its own box. */
    .doc-pair > .chip, .doc-stack > .chip, .doc-pair > form, .doc-stack > form,
    .doc-review .doc-pair > .chip, .doc-review .doc-stack > .chip,
    .doc-review .doc-pair > form, .doc-review .doc-stack > form {
        display: inline-flex; align-items: center; justify-content: center;
        width: 100%; box-sizing: border-box;
        white-space: normal; text-align: center;
        height: auto; min-height: 34px; line-height: 1.25; padding: 6px 12px;
    }
    /*  ⚠⚠ A FORM IS A GRID ITEM TOO — the USE THIS pill on the match card sits
        in one, and a form that did not fill its track would leave its button
        narrower than the chip beside it. */
    .doc-pair > form > .chip, .doc-stack > form > .chip { width: 100%; }
/*  ⚠ v31.330 (owner) — *"Read this document and From Email should be same size
    on two rows."* The submit lives inside the upload form rather than in the
    stack, so it is widened by name. */
.doc-wide {
    display: inline-flex; align-items: center; justify-content: center;
    width: 100%; box-sizing: border-box; white-space: normal; text-align: center;
    height: auto; min-height: 34px; line-height: 1.25; padding: 6px 12px;
    margin-top: 8px;
}

/*  ══ v31.331b (owner) — CODE THEN NAME, AS THE DROPDOWN DRAWS IT ══════════
    *"These should be describe Code + Name as follows in the attached example"*
    — the VAT ANALYSIS selector: a gold code, then the sentence that explains
    it. The same pair in the same order in both places, so a reader checking one
    against the other never has to re-read either.

    ⚠ THE CODE IS GOLD AND MONOSPACED because it is an identifier and because
    that is what `.t-leaf b` already is in the selector; the words take the
    ordinary ink. Neither is allowed to wrap away from the other. */
.doc-code {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-weight: 700; font-size: 12.5px; letter-spacing: .02em;
    white-space: nowrap; color: var(--nv-gold, #e8a75c);
}
.doc-nm { margin-inline-start: 8px; color: var(--nv-ink, #f1f3f9); }

/*  ══ v31.330 (owner) — THE NARRATIVE BLOCK ═════════════════════════════════
    *"Translation is required in extended description and Description. By moving
    description to a position above the extended description."*

    ⚠⚠ FULL WIDTH AND OUT OF THE GRID. Both fields are prose; the three-column
    ladder beside them is sized for `net`, `vat` and a nominal code, and a
    sentence in one of those cells clipped to four lines. */
.doc-narr { margin-top: 9px; position: relative; }
    .doc-narr .fld-wrap { margin: 0; }
    .doc-narr .doc-desc .input { width: 100%; box-sizing: border-box; }
    /*  ⚠ THE LABEL FOR THE EDITOR GETS THE SAME GAP THE DESCRIPTION'S LABEL HAS
        above it, so the two fields read as one block rather than two. */
    .doc-xlab { display: block; margin-top: 10px; }
    /*  ⚠⚠ THE PROVENANCE MARK SITS ON THE DESCRIPTION'S OWN LINE, not above it:
        same rule as the grid, where the letter is beside the value because the
        question "where did this come from" is asked while reading it.
        ⚠⚠⚠ AND IT IS ANCHORED TO THE FIELD, NOT TO THE BLOCK. The translate
        door appends its glyph to the label row, so a marker parked at the
        top-right of `.doc-narr` sits underneath it — two controls, one place,
        and the collision only appears once a line has been edited. */
    .doc-narr .doc-desc { position: relative; }
    .doc-narr .doc-desc .input { padding-inline-end: 34px; }
    .doc-nmk {
        position: absolute; inset-inline-end: 8px; bottom: 7px;
        pointer-events: none;
    }
/*  ⚠⚠⚠ v31.330 (owner) — *"'Save this narrative' button should have top space
    so it does not merge with the bottom of the rich text editor."* The editor's
    surface has no bottom margin of its own, so the button was landing on its
    border. The gap belongs to the button's row, not to the editor, because the
    editor is shared with every other screen on this product. */
.doc-nsave { margin-top: 10px; }

.doc-review .doc-rules { font-size: 12.5px; }
.doc-review .doc-say { font-size: 12.5px; line-height: 1.45; }
.doc-review .doc-warn { font-size: 13px; }

/*  ══ v31.327 (owner) — THE INFORMATION ICON ════════════════════════════════
    *"Remove this text … and place it in the information icon."* · *"also this
    text goes int an information icon"*.

    ⚠⚠⚠ IT IS `<details>`, NOT A SCRIPT AND NOT A TOOLTIP. The browser's own
    disclosure opens with JavaScript off, is keyboard reachable with nothing
    wired up, and is announced as expandable without an aria attribute anybody
    has to remember to keep in step. A tooltip would also hide the text from
    touch and from anyone reading at a magnification where a hover never
    settles.

    ⚠⚠ AND IT IS COLLAPSED, NOT DELETED. Both blocks are true and worth saying
    once — the three provenance rules and what happens on accept. Printed on
    every proposal beside a count somebody is driving to zero, they are
    paragraphs of comfort in the way of the work. */
.doc-info { margin-top: 11px; }
    .doc-info > summary {
        display: flex; align-items: center; gap: 7px;
        font-size: 12.5px; color: var(--nv-ink-2, #aab3c8);
        cursor: pointer; list-style: none; padding: 2px 0;
    }
        /*  ⚠ SAFARI AND OLD WEBKIT DRAW THEIR OWN TRIANGLE through a
            pseudo-element the standard property does not reach. */
        .doc-info > summary::-webkit-details-marker { display: none; }
        .doc-info > summary:hover { color: var(--nv-ink, #f1f3f9); }
        .doc-info > summary:focus-visible {
            outline: 2px solid var(--nv-gold, #e8a75c);
            outline-offset: 2px; border-radius: 4px;
        }
    /*  ⚠⚠ THE GLYPH IS THE SAME SHAPE AND SIZE AS A PROVENANCE CHIP, on
        purpose: this screen has one vocabulary of small round-cornered marks,
        and a second one would read as a second kind of thing. */
    .doc-i {
        flex: 0 0 auto;
        display: inline-flex; align-items: center; justify-content: center;
        width: 17px; height: 17px;
        border-radius: 50%;
        border: 1.5px solid currentColor;
        font-size: 10px; font-weight: 700; font-style: italic;
        line-height: 1;
    }
    .doc-info[open] > summary { color: var(--nv-ink, #f1f3f9); margin-bottom: 4px; }
    .doc-info > .doc-rules,
    .doc-info > .doc-say { margin-top: 0; padding-left: 24px; }

/*  ══ ⚠⚠⚠ v31.338 (owner) — THE LIST OF WHAT IS HOLDING POST BACK ══════════
    *"have an information item that lists the items preventing the post"*

    ⚠⚠ IT INDENTS TO THE SAME 24px AS THE OTHER TWO PANELS, so the icon above
    it governs all three and the rail keeps one left edge.

    ⚠⚠⚠ AND IT WRAPS INSTEAD OF SCROLLING. This rail is 300px at 1366 and the
    narrow screens give it the full width; a reason clipped at the right edge
    is the one word the reader needed. Three items per row is the natural
    reading order - where, what, why - and each holds together when the row
    breaks, which is what the inline-flex on the parts is for. */
.doc-info > .doc-held {
    margin: 0; padding: 0 0 0 24px;
    list-style: none;
    display: flex; flex-direction: column; gap: 6px;
}
    .doc-info > .doc-held > li {
        display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 7px;
        font-size: 12.5px; line-height: 1.35;
    }
        /*  ⚠⚠ THE LOCATION IS A FIXED-WIDTH COLUMN so a header row and a line
            row start their field names at the same x. Fourteen items that do
            not line up read as fourteen unrelated sentences. */
        .doc-info > .doc-held .doc-held-w {
            flex: 0 0 auto; min-width: 54px;
            color: var(--nv-ink-2, #aab3c8);
            font-size: 11.5px; letter-spacing: .02em;
            font-variant-numeric: tabular-nums;
        }
        .doc-info > .doc-held > li > b {
            flex: 0 1 auto;
            color: var(--nv-ink, #f1f3f9); font-weight: 600;
            overflow-wrap: anywhere;
        }
        /*  ⚠ THE REASON TAKES WHAT IS LEFT and wraps under the pair rather
            than pushing them off the rail. */
        .doc-info > .doc-held > li > .muted {
            flex: 1 1 100%;
            padding-left: 61px;
            font-size: 11.5px;
        }
@media (max-width: 520px) {
    /*  ⚠ ON A PHONE THE RAIL IS THE PAGE WIDTH and 61px of indent on a
        wrapped reason is a column of nothing. */
    .doc-info > .doc-held > li > .muted { padding-left: 0; }
}

/*  ══ ⚠⚠⚠ v31.339 (owner) — THE TYPED REPLACEMENT ══════════════════════════
    *"Other fields should be editable to allow user input to replace document
    read values."*

    ⚠⚠⚠ IT SITS UNDER THE VALUE, INSIDE THE SAME CARD, and it is deliberately
    quieter than the value above it: the document's own reading is still the
    thing being checked, and a box with more presence than the fact it might
    replace would invite editing for its own sake.

    ⚠⚠ THE BOX TAKES THE ROW AND THE BUTTON TAKES WHAT IT NEEDS, so a long IBAN
    does not push Save off a 300px card - and the pair wraps rather than
    clipping when even that is not enough. */
.doc-edit {
    display: flex; align-items: center; gap: 6px;
    /*  ══ ⚠⚠⚠⚠ v31.340 (owner) — ON THE SAME ROW, AND THE SAME ROW AS EACH
        OTHER'S. *"Style them in such way that they appear aligned on the same
        row."*

        TWO THINGS WERE RAGGED AND ONLY ONE OF THEM WAS OBVIOUS:

          · `flex-wrap: wrap` let the Save drop UNDER its box the moment the
            two did not fit — so the pair the owner calls one control was two
            rows on a narrow card and one on a wide one. It is gone, and the
            box shrinks instead (`min-width: 0` below); the button never moves.

          · AND ACROSS THE GRID THEY FLOATED. Each card is as tall as its own
            contents — a "Needs checking" flag here, a conversion line there —
            so three boxes in one grid row sat at three different heights.
            `margin-top: auto` pins the strip to the bottom of its card and the
            grid stretches every card in a row to the tallest, which puts every
            box on one line without a fixed height anywhere. */
    margin-top: auto;
    padding-top: 7px;
}
    /*  ⚠ TABULAR FIGURES, because most of what gets retyped here is a number
        the reader is comparing digit by digit against a document. ONE block,
        not two: a selector written twice is two places to change it and one
        place to forget. */
    .doc-edit > .doc-ed,
    .doc-edit > .doc-edsel {
        flex: 1 1 60px; min-width: 0;
        padding: 4px 7px;
        font-size: 12.5px; line-height: 1.3;
        font-variant-numeric: tabular-nums;
    }
    /*  ⚠⚠ THE PICKER IS THE SAME SHAPE AS THE BOX, on purpose: one card may
        carry a typed value and the next a chosen one, and a reader scanning
        down the grid should see one kind of control, not two. */
    .doc-edit > .doc-edsel {
        /*  ⚠⚠ THE RIGHT PADDING IS THE CHEVRON'S ROOM. Without it the browser
            draws its arrow ON TOP of the option text — `Zero rate - no VAT ch⌄`
            — and the one character it hides is as likely to be part of the
            code as part of the words. */
        padding: 4px 22px 4px 6px;
        font-size: 12.5px; line-height: 1.3;
        text-overflow: ellipsis;
    }
    .doc-edit > .doc-edgo {
        flex: 0 0 auto;
        padding: 4px 10px;
        font-size: 11.5px;
        white-space: nowrap;
    }
/*  ⚠⚠ A CARD THE READER HAS ALREADY SETTLED KEEPS ITS BOX but stops drawing
    attention to it: changing your mind must stay possible, and looking like
    the next thing to do must not. */
.doc-done .doc-edit { opacity: .62; }
    .doc-done .doc-edit:focus-within { opacity: 1; }

/*  ⚠ v31.326 — THE max-width STEPS THAT USED TO SIT HERE ARE GONE. The ladder
    above is min-width and mobile-first; leaving a max-width rule beside it
    would mean two rules fighting over the same widths, and the winner would be
    whichever came last in the file. */
/*  ⚠ AT PHONE WIDTH THE GRID STACKS AND THE MATCH TABLE SCROLLS IN ITS OWN
    BOX — the page itself never scrolls sideways. */
@media (max-width: 720px) {
    table.doc-mtbl { display: block; overflow-x: auto; white-space: nowrap; }
    .doc-legend { gap: 9px; }
}

/*  ══ v31.318 — THE CHOOSE CARD IS SELF-CONTAINED ════════════════════════
    ⚠⚠⚠ A PARTIAL WITH TWO HOSTS MUST NOT INHERIT ITS LAYOUT FROM EITHER, and
    this one did. Rendered in Account Setup's 240px side rail it picked up the
    main column's styling and broke in two visible ways:

      · `.sub` resolved to 18px at full ink — that is the SCREEN HEADER's
        subtitle, not a card caption. Beside it the sibling card's own caption
        is `.acc-ba-hint`: 13px, muted.
      · `.chips` is `flex-wrap: nowrap` with `height: 32px`, and `.chip` is
        `white-space: normal` with the same fixed height — so "Choose a
        document" wrapped to a second line and rendered OUTSIDE its own box,
        over the chip beside it and the note beneath it.

    Neither shows in the markup and neither shows on the processing page, where
    the column is wide. Caught by rendering the card in its new home and
    looking at it.

    ⚠⚠ SO THE FIX IS SCOPED TO `.doc-choose` RATHER THAN APPLIED TO THE HOST.
    Changing `.sub` or `.chips` globally would move every screen that uses them
    to suit one card. */
.doc-choose .sub {
    font-size: 13px;
    line-height: 1.45;
    color: var(--nv-ink-2, #aab3c8);
}
.doc-choose .chips {
    display: flex;
    flex-wrap: wrap;          /* ⚠ the rail is narrow: the row wraps, the chip does not */
    height: auto;
    gap: 8px;
}
    .doc-choose .chip {
        white-space: nowrap;   /* ⚠⚠ a label that wraps inside a fixed-height chip
                                  renders outside it — that was the overlap */
        /*  ⚠⚠⚠ AND `nowrap` ALONE MADE IT WORSE, which is the second half of
            the same defect. `.chips` is a flex row and a flex item shrinks by
            default: two chips needing 255px in a 231px rail were both squeezed
            below their natural width, and with the text refusing to wrap it
            simply rendered outside the box — the first chip's label ran under
            the second one.

            `flex: 0 0 auto` is the half that fixes it: THE ROW WRAPS, THE CHIP
            NEVER SHRINKS. Wrapping a row costs one line of height; shrinking a
            chip costs the label. */
        flex: 0 0 auto;
        height: auto;
        min-height: 30px;
        line-height: 1.25;
        font-size: 14px;
        padding: 5px 12px;
    }
.doc-choose .doc-say { font-size: 12.5px; line-height: 1.4; }

/*  ══ v31.321 — THE BLOCK IS A RAIL CARD ═════════════════════════════════
    Owner: *"for invoice step 3 and new invoice the card should appear in the
    right column. That fixes all views"* · *"Place it below the find
    transaction card"*.

    ⚠⚠⚠ ITS NEW HOME IS THE ENTRY WIZARD'S `.ai-side`, ~350px wide — the same
    kind of column that broke `.doc-choose` in v31.318, and it breaks the same
    way for the same two reasons: `.chips` is `flex-wrap: nowrap` at a fixed
    32px, and `.chip` is `white-space: normal` and shrinks. "Process a
    document" is a longer label than either of the ones that overflowed then.

    ⚠⚠ SO THE WIDTH LEFT THE MARKUP AND LANDS HERE. Three inline
    `max-width:900px` rules said the card belonged in a wide main column; one
    rule here caps it wherever it renders and costs nothing in a rail that is
    already narrower.                                                        */
.doc-block, .doc-walk, .doc-bacts { max-width: 900px; }

/*  ⚠ THE HEADING SHRINKS WITH THE COLUMN. `h2.section` is 20px — set for a
    main column — and "Process invoice from document" at 20px takes three
    lines of a 350px rail before the card has said anything.                 */
.ai-side .doc-block h2.section { font-size: 16px; }
.ai-side .doc-walk { font-size: 13px; line-height: 1.45; }

.doc-block .chips, .doc-bacts .chips {
    display: flex;
    flex-wrap: wrap;          /* ⚠ the rail is narrow: the row wraps, the chip does not */
    height: auto;
    gap: 8px;
}
    .doc-block .chip, .doc-bacts .chip {
        /*  ⚠⚠ `nowrap` AND `flex: 0 0 auto` ARE ONE FIX, NOT TWO. Either half
            alone renders the label outside its own chip — see the `.doc-choose`
            note above, which is the round this was learned in. */
        white-space: nowrap;
        flex: 0 0 auto;
        height: auto;
        min-height: 30px;
        line-height: 1.25;
        font-size: 14px;
        padding: 5px 12px;
    }
.doc-block .doc-say { font-size: 12.5px; line-height: 1.4; }

/*  ══ v31.322 — THE CARD TAKES A FILE ════════════════════════════════════
    Owner: *"please let us proceed to round 2 workflow, uploading a
    document."*

    ⚠⚠⚠ `.doc-pickfile`, NOT `.doc-file`. `.doc-file` ALREADY MEANS the
    attachment line on the proposal — a flex row with a paperclip — and putting
    it on a file INPUT made one class name mean two things. That is the same
    collision `.doc-wait` caused in v31.318, where a step state quietly
    inherited the card's rules; one class for two things is a collision that
    only ever gets worse.                                                     */
.doc-pick { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; margin-top: 10px; }
.doc-pickfile {
    flex: 1 1 220px;
    min-width: 0;                 /* ⚠ a flex item with a long file name must shrink, not overflow */
    font-size: 13.5px;
    padding: 6px 9px;
    height: auto;
}
    /*  ⚠ THE BROWSER'S OWN BUTTON IS THE ONE PART OF THIS CONTROL THAT CANNOT
        BE REPLACED, so it is dressed rather than fought. */
    .doc-pickfile::file-selector-button {
        margin-right: 9px;
        border: 1px solid rgba(232,167,92,.45);
        background: rgba(232,167,92,.10);
        color: var(--nv-gold, #e8a75c);
        border-radius: 5px;
        padding: 4px 10px;
        font: inherit;
        cursor: pointer;
    }

/*  ⚠⚠⚠ WHAT WENT WRONG READS AS A NOTE, NOT AS A HEADING. Unstyled it
    inherited the card's body size and came out larger than the caption above
    it, so a refusal shouted while the card's own subject whispered — caught by
    looking at the rendered page rather than at the markup. */
.doc-said {
    margin-top: 9px;
    padding: 8px 10px;
    font-size: 13.5px;
    line-height: 1.45;
    border: 1px solid rgba(232,167,92,.45);
    border-radius: 6px;
    background: rgba(232,167,92,.06);
    color: var(--nv-ink, #f1f3f9);
}

/*  ⚠⚠ THE IN-FLIGHT STRIP IS HIDDEN BY THE `hidden` ATTRIBUTE, and `display:
    flex` anywhere in its ancestry would override that. It is stated here so a
    later layout change cannot reveal a progress strip over a form nobody has
    submitted. */
.doc-flight[hidden] { display: none !important; }
.doc-flight { margin-top: 10px; }

/*  the "this document has been read here before" note — the house tint, the
    same one a likely match and the round-1 banner already use */
.doc-dup {
    display: flex; gap: 10px; align-items: baseline;
    border-color: rgba(232,167,92,.45); background: rgba(232,167,92,.06);
    max-width: 900px;
}
    .doc-dup a { color: var(--nv-gold, #e8a75c); margin-left: 6px; }

/*  ══ v31.323 — THE ACCOUNT PANEL IS A CONTROL NOW ═══════════════════════
    Owner: *"Using VAT number, company number, and name as mandatory key is
    restrictive. Let us start with reading details irrespective of the match.
    and having a pill USE THIS to allow user intervention."*                */
.doc-panel { max-width: 900px; }

/*  ⚠⚠ THE SEARCH IS A ROW THAT WRAPS, like every other control in this
    feature — the panel renders in the entry wizard's ~350px rail as well as in
    a main column, and a fixed-width row would overflow one of them. */
.doc-find { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 9px 0 11px; }
    .doc-find .input { flex: 1 1 220px; min-width: 0; height: 34px; font-size: 13.5px; }
    .doc-find .chip { flex: 0 0 auto; white-space: nowrap; }

/*  ⚠ THE PILL'S FORM MUST NOT BECOME A BLOCK in the middle of a chip row. A
    bare <form> is display:block and would push every chip after it onto its
    own line — which is how "USE THIS" ends up alone above "Update this
    account". */
.doc-use { display: inline-flex; margin: 0; }

/*  ⚠⚠⚠ WHAT IS IN USE LOOKS DIFFERENT FROM WHAT IS SUGGESTED, and it is the
    gold edge rather than a tint alone, because a reader who has already chosen
    must see that at a glance. A panel where the decision looks like one more
    candidate is a panel where somebody presses a second pill without noticing
    the first. */
.doc-chosen {
    border-color: rgba(232,167,92,.70);
    background: rgba(232,167,92,.09);
    box-shadow: inset 3px 0 0 0 var(--nv-gold, #e8a75c);
}

/*  ⚠⚠ A SEARCH RESULT IS NEITHER A MATCH NOR A NON-MATCH, so it gets neither
    the gold of a likely match nor the green of "nothing on file". It is a
    plain card with a plain edge, which is the honest weight for something a
    person typed. */
.doc-found { border-color: rgba(255,255,255,.16); background: rgba(255,255,255,.02); }

.doc-panel .doc-acts { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
    .doc-panel .doc-acts .chip { flex: 0 0 auto; white-space: nowrap; height: auto; min-height: 30px; }
