/*!
 * Nativa Theme — CLIENT PORTAL
 *
 * The signed-in panel, drawn in the same yellow and ink as the Nativa landing
 * page: the brand colour is the whole page surface, and the content floats on
 * top of it as one rounded card with a thin gutter of that surface on three
 * sides. The sidebar is not a panel — it is simply the part of the surface the
 * card does not cover, which is why nothing here paints it.
 *
 * WHAT THIS SHEET IS AND IS NOT
 * —————————————————————————————
 * It is NOT a standalone stylesheet. The product keeps emitting its compiled
 * bundle on this surface on purpose (see PORTAL-CONTRACT.md §1): claiming
 * `standalone` would make this package the owner of the confirmation dialog, the
 * 419 interceptor, the confetti and ~900 lines of legal prose — copies of core
 * behaviour that would not hear about a core fix. So this sheet does two jobs:
 *
 *   1. It declares the `nv-*` design system the screens this package REPLACES
 *      are written in (the shell and the sixteen pages).
 *   2. It BRIDGES the product's own `--color-*` tokens to Nativa values, so the
 *      pieces that stay the core's — toasts, the session-expired modal, the
 *      celebration modal, the confirmation dialog, the notification bell, the
 *      footer, the legal page — come out in this palette without this package
 *      owning a single line of their markup.
 *
 * SCOPE
 * —————
 * Everything hangs off `html[data-theme='nativa']`, which the client layout
 * writes (components/layouts/client.blade.php). Scoping matters even though the
 * product only links this file while Nativa is the chosen design: the same file
 * is linked on the SIGN-IN page next to auth.css, where the product's own shell
 * is in charge, and an unscoped `body { background }` there would paint the
 * sign-in page brand-yellow.
 *
 * Tailwind v4 emits its own tokens inside a cascade layer, and a layered
 * declaration loses to an unlayered one wherever it sits, so the bridge below
 * wins by being outside a layer — not by being late in the file.
 *
 * COLOUR IS THE OPERATOR'S
 * ————————————————————————
 * Nativa NEVER declares `--brand`. Every accent here paints with `var(--brand)`,
 * which the shell seeds LAST in the <head> from the panel's own Branding, so a
 * reseller who picks their colour gets this design in their colour. The literals
 * after each `var()` are the shade Nativa was drawn with and only ever show on a
 * panel that has no brand seed at all.
 *
 * Link: public/parts/00-base.css — the landing's copy of the same ramp
 *       PORTAL-CONTRACT.md       — what the package may and may not replace
 */

/* ── Poppins, served from the package (SIL Open Font License 1.1) ─────────── */
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/poppins-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/poppins-400-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('fonts/poppins-500-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('fonts/poppins-500-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('fonts/poppins-600-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('fonts/poppins-600-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/poppins-700-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Nativa Poppins';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/poppins-700-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ══════════════════════════════════════════════════════════════════════════
   1 · TOKENS
   ══════════════════════════════════════════════════════════════════════════
   Declared on the root element so auth.css — which already reads this ramp on
   the sign-in page — keeps working unchanged. Only the BRIDGE in §2 is narrowed
   to the portal.
   ────────────────────────────────────────────────────────────────────────── */
html[data-theme='nativa'] {
    --nv-brand: var(--brand, #f7c600);
    --nv-on-brand: var(--color-on-primary, #1b1b1b);
    --nv-light: #ffe27a;
    --nv-deep: #a87f00;
    --nv-deeper: #7a6200;

    /* THE BRAND AS A TEXT COLOUR ON PAPER. Measured, not chosen: the factory
       brand on the white card is 1.61:1 and --nv-deep is 3.68:1 — both below the
       4.5 a 13px label needs, so a money figure and a link to the terms were
       legible only to someone who already knew what they said.

       It is a MIX and not one of the fixed shades above for the reason this
       package repeats everywhere: --nv-deep is a mustard literal, so an operator
       who brands his panel blue would get his links in our yellow. Mixing toward
       the surface's own ink keeps his hue and lands at 5.42:1.

       45% and not 35%: the darker mix measures better (7.09) and stops reading as
       the brand at all, which defeats the point of an accent. This is the lightest
       mix that still clears 4.5. */
    --nv-brand-ink: color-mix(in srgb, var(--nv-brand) 45%, var(--nv-ink));

    /* Seven steps, not four: the reference's neutral ramp is seven and sharing
       texts between four of them is how 47 labels came out in the neighbouring
       grey on the landing. Same ramp here so the two surfaces agree. */
    --nv-ink: #1b1b1b;
    --nv-ink-2: #4a4a4a;
    --nv-ink-3: #5f5f5f;
    --nv-ink-4: #6b6b6b;
    --nv-ink-5: #656565;
    --nv-ink-6: #6b6b6b;
    --nv-ink-7: #727272;

    /* ── The light ramp, mixed from ONE seed ──────────────────────────────
       --nv-surface-seed is the colour the operator can set in Admin › Website ›
       Client Portal. Until this existed the six tones below were six literals,
       so "let me change the panel's background" had no answer that did not end
       with five shades disagreeing with the one that moved.

       THE MIX TARGETS LOOK ARBITRARY AND ARE NOT. Each is the colour that,
       mixed with the DEFAULT seed at the stated percentage, lands exactly on the
       literal this design has always used — #dbd9d3 at 35% over #fdf6dc is
       #f1ecd9 to the byte. That is the whole point: a panel whose operator never
       opens the screen renders the same bytes it rendered before, and an update
       does not repaint anybody. Verified in the browser against the old values,
       not by arithmetic alone.

       They are LITERALS and never var(--nv-brand) on purpose: tying the ramp to
       the brand would re-tint every existing panel the day it updates, which is
       the same repaint by another route. */
    --nv-white: #fff;
    --nv-paper: var(--nv-surface-seed, #fdf6dc);
    --nv-paper-2: color-mix(in srgb, #fff 35%, var(--nv-paper));
    /* The ONE tone in this ramp mixed toward the BRAND rather than a literal,
       and the exception is what it IS: --nv-soft is the raised chip, the hovered
       pill, the help card — a wash of the panel's own colour over the paper, not
       a shade of the paper. Tied to a fixed amber it came out beige on a panel
       whose operator set a blue background (measured: #eeecd6 over #e6f0fa,
       which reads as dirty rather than as a tint). 12% lands within one unit per
       channel of the literal this design always used, so the default is
       unchanged to the eye. */
    --nv-soft: color-mix(in srgb, var(--nv-brand) 12%, var(--nv-paper));
    --nv-line: color-mix(in srgb, #dbd9d3 35%, var(--nv-paper));
    --nv-line-2: color-mix(in srgb, #cccbc2 35%, var(--nv-paper));

    /* The "ink chip": a dark SURFACE carrying brand-coloured text (primary
       button, avatar, pressed pills, message bubbles). It must NOT be --nv-ink:
       that token flips to near-white in dark mode and the yellow on top drops to
       ~1.4:1 — the pair inverts itself and the label disappears. This one stays
       dark in both modes, so the chip only ever gets deeper. */
    --nv-chip-ink: #1b1b1b;
    --nv-on-chip-ink: var(--nv-brand);

    /* Status stays semantic and never borrows the brand: a green that follows a
       yellow brand would report success in the same colour as a warning. Each
       one travels with the colour that goes ON it, because a solid chip whose
       background flips in dark mode takes its own label down with it. */
    --nv-ok: #0f7a3f;
    --nv-ok-bg: #e6f6ec;
    --nv-warn: #8a5f00;
    /* Its ink, for the same reason --nv-on-bad has one: a solid amber chip is
       only as good as the label on it. Measured on this amber: white 5.65:1,
       the product's dark ink 3.14 — so white, and it flips in the dark layer. */
    --nv-on-warn: #fff;
    --nv-warn-bg: #fdf3d6;
    --nv-bad: #c1252f;
    --nv-on-bad: #fff;
    --nv-bad-bg: #fdeaec;
    --nv-info: #2563c9;
    --nv-info-bg: #e8f0fd;

    /* ── The surface ──────────────────────────────────────────────────────
       The page IS the brand colour, and the sidebar is the part of it the card
       does not cover. Everything on it derives from the operator's own
       on-primary rather than from a literal, which is what makes this work on a
       brand that is dark as well as on one that is light: a reseller who picks
       navy gets pale sidebar text, one who picks yellow gets ink. Hard-coding
       the ink the design was drawn with would have made every dark-branded
       panel's navigation unreadable. */
    --nv-side-bg: var(--nv-brand);
    --nv-side-text: var(--nv-on-brand);
    /* 82% and not 72%: at 72 the five section labels in the menu (ORDERS,
       CATALOGUE, SUPPORT, FINANCE, MORE) measured 4.28:1 on the brand surface,
       under the 4.5 an 11px capitalised label needs. Pre-existing — it was not
       introduced by the dark-mode work, it was found by sweeping the light mode
       afterwards, which is the half that usually goes unmeasured. */
    --nv-side-muted: color-mix(in srgb, var(--nv-on-brand) 82%, transparent);
    --nv-side-hover: color-mix(in srgb, var(--nv-on-brand) 9%, transparent);
    --nv-side-line: color-mix(in srgb, var(--nv-on-brand) 14%, transparent);
    --nv-side-card: color-mix(in srgb, var(--nv-on-brand) 8%, transparent);
    /* The three solid marks ON the surface — the logo tile, the help badge and
       the help button. ONE pair rather than three copies of it, because the pair
       INVERTS between modes and three hand-written copies is how one of them
       gets left behind: here the surface IS the brand, so a mark that has to
       stand out on it wears the on-brand ink as its background. In the dark
       layer the surface is no longer the brand and the pair flips back. */
    --nv-side-chip-bg: var(--nv-on-brand);
    --nv-side-chip-ink: var(--nv-brand);
    /* The active row is painted with the CARD's own colour so it reads as a tab
       cut out of the content. The same value in both modes — that is the whole
       trick, and it is why no second rule is needed for dark. */
    --nv-side-active-bg: var(--nv-paper);
    --nv-side-active-text: var(--nv-ink);

    --nv-shadow-sm: 0 4px 14px rgba(0, 0, 0, .05);
    --nv-shadow: 0 10px 30px rgba(0, 0, 0, .05);
    --nv-shadow-md: 0 12px 30px rgba(0, 0, 0, .1);

    --nv-r-card: 16px;
    --nv-r-ctl: 11px;
    --nv-r-pill: 999px;
    /* The radius of the active nav row AND of the two concave corners that cut
       into the surface around it — ONE number, or the curves stop matching. */
    --nv-bite: 14px;

    --nv-side-w: 248px;
    --nv-top-h: 68px;
    /* The gutter of brand surface left visible around the floating card, and its
       corner radius — both measured off the reference screen. */
    --nv-app-gutter: 8px;
    --nv-r-app: 18px;

    --nv-font: 'Nativa Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;

    /* The shell paints the <body> from an INLINE style so the page never flashes
       the browser default, and an inline declaration beats every stylesheet. The
       product's answer to that is this indirection: declaring the variable is
       the supported way for a design to own that surface, so the backdrop
       follows light/dark from here instead of from a static manifest value that
       could not know which mode the visitor is in. */
    --rf-shell-bg: var(--nv-side-bg);
    --rf-shell-text: var(--nv-side-text);
}

/* Dark: the night palette. The canvas is near-black, the cards are charcoal,
   and the accent is the purple used on the marketing reference — button fill
   #BD0EDC, glow and links #CE6BFF. Light mode keeps the operator's own brand.
   ──────────────────────────────────────────────────────────────────────────
   #BD0EDC as TEXT on #151515 measures about 3.7:1, under the 4.5 a label needs,
   so links, the active row and the balance icon use the lighter #CE6BFF (6.2:1
   on the card). The saturated purple stays on fills, where white on top clears
   4.9:1. */
html.dark[data-theme='nativa'] {
    --nv-brand: #bd0edc;
    --nv-on-brand: #ffffff;
    --nv-light: #f4b2ff;
    --nv-deep: #ce6bff;
    --nv-deeper: #f4b2ff;

    /* Sidebar under the card, card under the raised bars. Literals, so a yellow
       brand in light mode does not tint the night surfaces back to amber. */
    --nv-paper: #16111c;
    --nv-paper-2: #241a2e;
    --nv-white: #1c1524;
    --nv-soft: color-mix(in srgb, #bd0edc 16%, #1c1524);
    --nv-line: #5c2e78;
    --nv-line-2: #7a3d9a;

    --nv-ink: #ffffff;
    --nv-ink-2: #f5f5f5;
    --nv-ink-3: #d8d8d9;
    --nv-ink-4: #b7b7b8;
    --nv-ink-5: #b7b7b8;
    --nv-ink-6: #b7b7b8;
    --nv-ink-7: #9a9a9b;

    --nv-ok-bg: #16301f;
    --nv-warn-bg: #332a10;
    --nv-bad-bg: #37191d;
    --nv-info-bg: #16233a;
    --nv-ok: #5ed08b;
    --nv-warn: #e7b53d;
    /* --nv-warn went light here, so its on-colour flips with it (measured
       9.29:1 against this amber). Same move as --nv-on-bad below. */
    --nv-on-warn: #2a1f05;
    /* #f2778a until the surfaces moved: on the lighter card it measured 4.49 on
       the required-field asterisk — a hundredth under, which is still under. */
    --nv-bad: #f5858f;
    /* --nv-bad went light here, so its on-colour has to flip with it. */
    --nv-on-bad: #2a0d12;
    --nv-info: #6fa4f5;

    /* The "ink chip" becomes the BRAND here, and this is a reversal of what the
       light layer does on purpose.
       In light mode the chip is a near-black slab carrying brand-coloured text,
       and it works because everything around it is cream. Kept in the dark it
       became the QUIETEST thing on the screen — measured on Add Funds, the
       button that takes the customer's money was #0f1111 on a card of #1b2025,
       which is to say a button that is darker than the page it sits on. Same for
       a chosen quick-amount and for an avatar.
       It cannot flip to --nv-ink (near-white here) for the reason the light note
       gives: the brand-coloured label on top would drop to ~1.4:1. The brand
       itself does not have that problem — it is stable across modes, it measures
       11:1 on this card, and it is what already marks the active nav row — so in
       the dark the chip IS the brand and its on-colour is the brand's. */
    --nv-chip-ink: var(--nv-brand);
    --nv-on-chip-ink: var(--nv-on-brand);

    /* Saturated purple fails as small text on the card. The glow colour is the
       one that still reads as the accent and clears 4.5. */
    --nv-brand-ink: #ce6bff;

    /* ── The surface, in the dark ─────────────────────────────────────────
       The deepest step of the ramp, so the card reads as lifted off it rather
       than as a hole cut into it. Its text no longer derives from --nv-on-brand
       (which is the ink that goes on the BRAND, and the surface is no longer the
       brand here): on a yellow-branded panel that token is near-black, and every
       nav label would have gone out with the lights. It derives from the card's
       own ink instead, which is already the answer to "legible on a dark
       surface" and which flips with the mode on its own. */
    --nv-side-bg: #0e0b16;
    --nv-side-text: #ffffff;
    --nv-side-muted: #b7b7b8;
    --nv-side-hover: color-mix(in srgb, var(--nv-ink) 10%, transparent);
    --nv-side-line: color-mix(in srgb, var(--nv-ink) 14%, transparent);
    --nv-side-card: color-mix(in srgb, var(--nv-ink) 8%, transparent);
    /* The active row keeps being painted with the CARD's colour — that is the
       whole "tab carved out of the content" geometry and it must not change —
       but its LABEL becomes the brand. In light mode the row is legible because
       cream against yellow is already a contrast; here the two surfaces are two
       steps of the same dark ramp, so without an accent the row you are standing
       on would be the quietest thing in the menu. */
    --nv-side-active-bg: #241a2e;
    --nv-side-active-text: #ce6bff;
    /* The pair inverts: the surface is no longer the brand, so a solid mark on
       it wears the brand and puts the on-brand ink on top. Left as it was, the
       logo tile on a yellow-branded panel would have been near-black on
       near-black — the buyer's own initial, invisible. */
    --nv-side-chip-bg: var(--nv-brand);
    --nv-side-chip-ink: var(--nv-on-brand);

    --nv-shadow-sm: 0 4px 14px rgba(0, 0, 0, .35);
    --nv-shadow: 0 10px 30px rgba(0, 0, 0, .35);
    --nv-shadow-md: 0 12px 30px rgba(0, 0, 0, .45);
}

/* Inside the signed-in shell only. Login keeps the operator's brand. */
html.dark[data-theme='nativa'] body:has(.nv-shell) {
    --brand: #bd0edc;
    --color-primary: #bd0edc;
    --color-on-primary: #ffffff;
}

html.dark[data-theme='nativa'] .nv-btn-primary,
html.dark[data-theme='nativa'] .nv-btn-brand {
    border-color: #ce6bff;
    box-shadow: 0 0 18px rgba(189, 14, 220, .35);
}

html.dark[data-theme='nativa'] .nv-shell {
    background:
        radial-gradient(880px 420px at 88% -8%, rgba(189, 14, 220, .22), transparent 58%),
        radial-gradient(640px 360px at 0% 100%, rgba(104, 9, 121, .34), transparent 60%),
        #0e0b16;
}

html.dark[data-theme='nativa'] .nv-card {
    border-color: #5c2e78;
    box-shadow: 0 0 0 1px rgba(189, 14, 220, .22), 0 14px 32px rgba(24, 0, 36, .35);
}

/* ══════════════════════════════════════════════════════════════════════════
   2 · THE BRIDGE — the product's own tokens, in Nativa's palette
   ══════════════════════════════════════════════════════════════════════════
   The pieces this package deliberately does NOT own (PORTAL-CONTRACT.md §5)
   paint from `--color-*`. Re-pointing those at the ramp above is what makes the
   confirmation dialog, the toasts, the bell and the footer come out in this
   design without a line of their markup being copied here.

   `body:has(.nv-shell)` and not the root element, and the reason is a screen
   that is already shipped: this same file is linked on the SIGN-IN page beside
   auth.css, which was written against the product's own `--color-*`. Moving
   those tokens there would repaint an approved screen as a side effect of
   dressing the panel. `:has()` answers exactly the question that matters — is
   the portal shell on this page — and it reaches the four hosts, which are
   siblings of the shell at body level and would be out of range of any selector
   scoped to the shell itself.
   ────────────────────────────────────────────────────────────────────────── */
html[data-theme='nativa']:has(.nv-shell) {
    height: 100%;
    max-width: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: pan-x pan-y;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}
html[data-theme='nativa'] body:has(.nv-shell) {
    height: 100%;
    max-width: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    --color-bg: var(--nv-paper);
    --color-surface: var(--nv-white);
    --color-surface-2: var(--nv-paper-2);
    --color-border: var(--nv-line);
    --color-text: var(--nv-ink);
    --color-text-muted: var(--nv-ink-4);
    --color-text-subtle: var(--nv-ink-6);

    --color-primary-soft: var(--nv-soft);
    --color-primary-500: var(--nv-brand);
    --color-primary-600: var(--nv-deep);
    --color-primary-700: var(--nv-deeper);

    --color-success: var(--nv-ok);
    --color-warning: var(--nv-warn);
    /* The pair travels together: this package moves the fill, so it owes the
       ink. Without it the product's fallback stays dark and the impersonation
       badge reads 3.14:1 on this amber. */
    --color-on-warning: var(--nv-on-warn);
    --color-danger: var(--nv-bad);
    --color-info: var(--nv-info);

    /* --nv-bad turns LIGHT on a dark card (that is the right call there), so the
       product's own white-on-danger count came out at 2.7:1 in the bell. This
       package already computes the ink that goes on top of it, so handing it
       over is the whole fix — measured 6.68:1. In light mode --nv-on-bad IS
       white, so nothing moves. Needs core ≥ 1.9.0, and costs nothing below it:
       an older core simply ignores a variable it does not read. */
    --color-on-danger: var(--nv-on-bad);

    --shadow-1: var(--nv-shadow-sm);
    --shadow-2: var(--nv-shadow);
    --shadow-3: var(--nv-shadow-md);

    /* Vibrant's own signature tokens. The base skin is vibrant, so its
       stylesheet is the one compiled into the page; leaving these on turquoise
       and purple would have put two foreign accents inside a yellow panel. */
    --rf-primary: var(--nv-brand);
    --rf-accent: var(--nv-deep);
    --rf-topbar-bg: var(--nv-white);
    --rf-topbar-muted: var(--nv-ink-4);
}

/* ══════════════════════════════════════════════════════════════════════════
   3 · BASE — scoped to the shell, never to the document
   ══════════════════════════════════════════════════════════════════════════
   Inside `:where()` so a reset can never outrank a component rule, which is the
   rule that already cost this package a tinted button on the landing twice.
   ────────────────────────────────────────────────────────────────────────── */
:where(html[data-theme='nativa'] .nv-shell) {
    font-family: var(--nv-font);
    color: var(--nv-ink);
    -webkit-font-smoothing: antialiased;
}

:where(html[data-theme='nativa'] .nv-shell) a { color: inherit; text-decoration: none; }

/* `color` is not part of `font`, and the UA sheet forces `buttontext` on a
   <button>. Without this, every card that is a button (.nv-pay, .nv-tk) paints
   its heading black — invisible on a dark surface. `cursor` is here because
   Tailwind v4's preflight stopped setting it. */
:where(html[data-theme='nativa'] .nv-shell) button { color: inherit; cursor: pointer; }

:where(html[data-theme='nativa'] .nv-shell) h1,
:where(html[data-theme='nativa'] .nv-shell) h2,
:where(html[data-theme='nativa'] .nv-shell) h3,
:where(html[data-theme='nativa'] .nv-shell) h4,
:where(html[data-theme='nativa'] .nv-shell) p { margin: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   4 · THE SHELL
   ══════════════════════════════════════════════════════════════════════════
   One viewport tall and it does NOT scroll: what scrolls is the content inside
   the card (.nv-content). This is the product's own arrangement (`.rf-imp-shell`)
   and it is the only one in which the frame survives — with the page scrolling,
   the card's 8px top gutter leaves the window on the first wheel turn and the
   bar ends up glued to the edge of the browser. That is the border that
   "disappears".

   dvh after vh: on a phone the URL bar changes the viewport and vh is frozen at
   the largest size, so the last rows would sit under it. vh stays first as the
   fallback for engines that do not know dvh.
   ────────────────────────────────────────────────────────────────────────── */
.nv-shell {
    display: flex;
    height: 100vh;
    height: 100dvh;
    max-width: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: pan-x pan-y;
    background: var(--nv-side-bg);
}

.nv-side {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--nv-side-w);
    background: transparent;
    color: var(--nv-side-text);
    display: flex;
    flex-direction: column;
    z-index: 40;
    transition: transform .22s ease;
}

.nv-side-brand { display: flex; align-items: center; gap: 10px; padding: 20px 18px 18px; min-width: 0; }

/* The fallback tile when the operator has not uploaded a logo — which is the
   state every installation is born in. It carries the on-brand ink, never a
   literal white: on a light brand a white initial is ~1:1 and the first letter
   of the buyer's own business is simply not on the screen. */
.nv-side-logo {
    width: 34px; height: 34px;
    border-radius: 10px;
    background: var(--nv-side-chip-bg);
    color: var(--nv-side-chip-ink);
    display: grid; place-items: center;
    font-weight: 700; font-size: 16px;
    flex-shrink: 0;
}
.nv-side-logo svg { width: 19px; height: 19px; }
.nv-side-logoimg { max-height: 40px; max-width: 150px; width: auto; object-fit: contain; display: block; }
.nv-side-name { font-weight: 600; font-size: 15.5px; letter-spacing: -.2px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The scrollbar is hidden, not absent: it still scrolls. A visible track steals
   9px off the inline end of the nav, and that is exactly the width that kept the
   active row from touching the card — the merge is the whole point.
   The top padding is not cosmetic either: the active row's upper notch is drawn
   at -14px, so with less air than the bite the scroll box clips it, and the
   entry that loses it is the FIRST one, which is the one that is active on
   arrival. */
.nv-side-nav { flex: 1; overflow-y: auto; overscroll-behavior: none; padding: 16px 12px 10px; scrollbar-width: none; }
.nv-side-nav::-webkit-scrollbar { width: 0; height: 0; }

.nv-side-sec {
    font-size: 10.5px; text-transform: uppercase; letter-spacing: .09em;
    color: var(--nv-side-muted); padding: 13px 10px 5px; font-weight: 600;
}

.nv-side-item {
    display: flex; align-items: center; gap: 11px;
    padding: 11px 10px;
    border-radius: var(--nv-r-ctl);
    position: relative;
    font-size: 13.5px; font-weight: 500;
    color: var(--nv-side-text);
    margin-bottom: 2px;
    transition: background .14s ease, color .14s ease;
}
.nv-side-item:hover { background: var(--nv-side-hover); }
.nv-side-item-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nv-side-item i, .nv-side-item svg { width: 18px; height: 18px; flex-shrink: 0; }

/* The active row "bites" the card. This is the product's own geometry, copied
   from the Vibrant skin (`.rf-imp-nav-item-active`) so the two shells answer the
   same way: flush inline end, 14px radius on the START side only, and TWO
   CONCAVE corners above and below. The concave pair is what makes it read as a
   rounded tab carved out of the content; with the radius alone the row looks
   boxed in. They are radial gradients and not shapes, so the surface shows
   through the curve whatever colour it is — brand, light or dark — with no
   second rule. The nav has 12px of side padding and the negative end margin
   gives it back, so the row reaches the card.
   The end padding is NOT the row's own 10px: the negative margin pushes the row
   12px further than the others, so that much is spent just reaching the card
   edge and anything less leaves the label sitting on the seam. 34px = the 12px
   the margin took back, plus the 22px of air the label needs to read as a tab
   carved out of the content rather than as text clipped by it. */
.nv-side-item[aria-current='page'] {
    background: var(--nv-side-active-bg);
    color: var(--nv-side-active-text);
    font-weight: 600;
    margin-inline-end: -12px;
    padding-inline-end: 34px;
    border-start-start-radius: var(--nv-bite);
    border-end-start-radius: var(--nv-bite);
    border-start-end-radius: 0;
    border-end-end-radius: 0;
}
.nv-side-item[aria-current='page']::before,
.nv-side-item[aria-current='page']::after {
    content: '';
    position: absolute;
    inset-inline-end: 0;
    width: var(--nv-bite); height: var(--nv-bite);
    pointer-events: none;
}
.nv-side-item[aria-current='page']::before {
    top: calc(var(--nv-bite) * -1);
    background: radial-gradient(circle at top left, transparent var(--nv-bite), var(--nv-side-active-bg) var(--nv-bite));
}
.nv-side-item[aria-current='page']::after {
    bottom: calc(var(--nv-bite) * -1);
    background: radial-gradient(circle at bottom left, transparent var(--nv-bite), var(--nv-side-active-bg) var(--nv-bite));
}

/* In Arabic the sidebar is on the other side, so the curve has to open the other
   way: the gradient's origin corner is the only thing here that is not already a
   logical property. */
html[dir='rtl'] .nv-side-item[aria-current='page']::before {
    background: radial-gradient(circle at top right, transparent var(--nv-bite), var(--nv-side-active-bg) var(--nv-bite));
}
html[dir='rtl'] .nv-side-item[aria-current='page']::after {
    background: radial-gradient(circle at bottom right, transparent var(--nv-bite), var(--nv-side-active-bg) var(--nv-bite));
}

/* A solid chip needs a PAIR that travels together: in dark mode --nv-bad flips
   to a light pink and a hard-coded #fff drops to ~2:1 — the count that says
   "you have open tickets" stops being readable. */
.nv-side-item .nv-side-badge {
    margin-inline-start: auto;
    background: var(--nv-bad); color: var(--nv-on-bad);
    font-size: 10.5px; font-weight: 700;
    border-radius: var(--nv-r-pill);
    padding: 1px 7px;
}

.nv-side-out {
    display: flex; align-items: center; gap: 11px; width: 100%;
    margin: 4px 12px 14px; padding: 9px 12px;
    width: calc(100% - 24px);
    border: 1px solid var(--nv-side-line);
    background: var(--nv-side-card);
    border-radius: var(--nv-r-ctl);
    color: var(--nv-side-text);
    font-size: 13px; font-weight: 600;
}
.nv-side-out:hover { background: var(--nv-side-hover); }
.nv-side-out i, .nv-side-out svg { width: 17px; height: 17px; flex-shrink: 0; }

/* ── The floating card ────────────────────────────────────────────────────
   It CAN be clipped: the top bar is no longer sticky, it is simply the first row
   of a column whose second row scrolls, so there is no sticky for a clipping
   ancestor to kill. The clip is what keeps content from painting over the
   rounded corners as it scrolls under the bar. */
.nv-main {
    flex: 1; min-width: 0;
    margin-inline-start: var(--nv-side-w);
    margin-block: var(--nv-app-gutter);
    margin-inline-end: var(--nv-app-gutter);
    background: var(--nv-paper);
    border-radius: var(--nv-r-app);
    display: flex; flex-direction: column;
    overflow: hidden;
}

/* flex: 0 0 auto, not sticky: the bar keeps its place because the column never
   moves — nothing to stick to and nothing to come unstuck from. */
.nv-top {
    flex: 0 0 auto;
    z-index: 30;
    min-height: var(--nv-top-h);
    background: var(--nv-white);
    border-start-start-radius: var(--nv-r-app);
    border-start-end-radius: var(--nv-r-app);
    border-bottom: 1px solid var(--nv-line);
    display: flex; align-items: center; gap: 10px;
    padding: 0 22px;
}

.nv-burger {
    display: none;
    width: 38px; height: 38px;
    border: 1px solid var(--nv-line); background: var(--nv-white);
    border-radius: var(--nv-r-ctl); color: var(--nv-ink);
    place-items: center;
}
.nv-burger i, .nv-burger svg { width: 19px; height: 19px; }
.nv-tabbar { display: none; }

.nv-search {
    position: relative;
    display: flex; align-items: center; gap: 9px;
    background: var(--nv-paper-2);
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-pill);
    padding: 9px 16px;
    width: min(360px, 34vw);
    min-width: 0;
    color: var(--nv-ink-5);
}
.nv-search input {
    border: 0; background: transparent; outline: none;
    font: inherit; font-size: 13px; color: var(--nv-ink); width: 100%; min-width: 0;
}
.nv-search i, .nv-search svg { width: 16px; height: 16px; flex-shrink: 0; }

/* The service-search results. `position: fixed` is wrong here and `absolute` is
   right: the bar is inside a card with `overflow: hidden`, so the panel is
   clipped — which is why it hangs off the WRAPPER, not off the bar. */
.nv-searchwrap { position: relative; min-width: 0; display: flex; }
.nv-searchpop {
    position: absolute; top: calc(100% + 6px);
    inset-inline: 0; z-index: 200;
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-card);
    box-shadow: var(--nv-shadow-md);
    overflow: hidden;
    max-height: 60vh; overflow-y: auto;
}
.nv-sr {
    display: block; width: 100%; text-align: start;
    padding: 11px 16px; background: transparent;
    border: 0; border-bottom: 1px solid var(--nv-line);
}
.nv-sr:last-child { border-bottom: 0; }
.nv-sr:hover { background: var(--nv-paper-2); }
.nv-sr-top { display: flex; align-items: center; gap: 10px; }
.nv-sr-id {
    flex-shrink: 0; font-size: 11.5px; font-weight: 700;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    background: var(--nv-soft); color: var(--nv-deeper);
    padding: 2px 7px; border-radius: 6px;
}
.nv-sr-name { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nv-sr-rate { flex-shrink: 0; font-size: 12px; color: var(--nv-ink-5); font-variant-numeric: tabular-nums; }
.nv-sr-meta { margin-top: 3px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; font-size: 11.5px; color: var(--nv-ink-5); }
.nv-sr-tag { font-size: 10.5px; font-weight: 700; padding: 1px 5px; border-radius: 4px; background: var(--nv-ok-bg); color: var(--nv-ok); }
.nv-sr-tag-info { background: var(--nv-info-bg); color: var(--nv-info); }
.nv-sr-empty { padding: 14px 16px; font-size: 12.5px; color: var(--nv-ink-5); display: flex; align-items: center; gap: 8px; }

.nv-top-spacer { flex: 1; }

.nv-icon-btn {
    position: relative;
    width: 38px; height: 38px;
    display: grid; place-items: center;
    border: 1px solid var(--nv-line);
    background: var(--nv-white);
    border-radius: var(--nv-r-ctl);
    color: var(--nv-ink-3);
    flex-shrink: 0;
}
.nv-icon-btn:hover { background: var(--nv-paper-2); color: var(--nv-ink); }
.nv-icon-btn i, .nv-icon-btn svg { width: 18px; height: 18px; }

.nv-balance {
    display: flex; align-items: center; gap: 8px;
    background: var(--nv-soft);
    border: 1px solid var(--nv-line-2);
    border-radius: var(--nv-r-pill);
    padding: 5px 13px;
    font-weight: 600; font-size: 13.5px;
    color: var(--nv-ink);
    flex-shrink: 0;
}
.nv-balance i, .nv-balance svg { width: 15px; height: 15px; color: var(--nv-deep); flex-shrink: 0; }

.nv-avatar {
    width: 34px; height: 34px; border-radius: 50%;
    background: var(--nv-chip-ink); color: var(--nv-on-chip-ink);
    display: grid; place-items: center;
    font-size: 12.5px; font-weight: 700;
    flex-shrink: 0; overflow: hidden;
    border: 0;
}
.nv-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }

/* The two header drop-downs (language, account). `absolute` and not `fixed` for
   the same reason as the search results: the card clips, so the panel hangs off
   its own trigger. */
.nv-drop { position: relative; flex-shrink: 0; }
.nv-menu {
    position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 60;
    min-width: 11rem; max-width: 17rem; width: max-content;
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-card);
    box-shadow: var(--nv-shadow-md);
    padding: 5px;
    overflow: hidden;
}
.nv-menu-head { padding: 9px 11px 7px; min-width: 0; }
.nv-menu-head strong { display: block; font-size: 13px; font-weight: 600; color: var(--nv-ink); overflow: hidden; text-overflow: ellipsis; }
.nv-menu-head span { display: block; font-size: 11.5px; color: var(--nv-ink-6); overflow: hidden; text-overflow: ellipsis; }
.nv-menu-sep { height: 1px; background: var(--nv-line); margin: 4px 0; }
.nv-menu-item {
    display: flex; align-items: center; gap: 9px; width: 100%;
    padding: 8px 11px; border-radius: 9px;
    font-size: 12.5px; color: var(--nv-ink-2);
    background: transparent; border: 0; text-align: start;
    white-space: nowrap;
}
.nv-menu-item:hover { background: var(--nv-paper-2); color: var(--nv-ink); }
.nv-menu-item i, .nv-menu-item svg { width: 15px; height: 15px; flex-shrink: 0; }
.nv-menu-item-on { background: var(--nv-soft); color: var(--nv-deeper); font-weight: 700; }
.nv-menu-item-danger { color: var(--nv-bad); }

/* ── The one scroller of the app ──────────────────────────────────────────
   min-height: 0 is not optional: a flex child defaults to min-height: auto, so
   it refuses to shrink below its content and the card grows past the viewport
   instead of scrolling inside it — the frame would come back off the bottom.

   scroll-padding-top is a literal and not a token: a custom property declared on
   the root cannot read one that is set further down the tree, and anything this
   sheet puts on `html` would fail at computed-value time with no error anywhere. */
.nv-content {
    flex: 1; min-height: 0;
    overflow-x: clip;
    overflow-y: auto;
    overscroll-behavior: none;
    /* No bottom padding: the credits line is the last thing inside the card and
       it carries its own surface, so a gap under it would leave a strip of card
       showing beneath the bar that is meant to close it. Its own padding is what
       keeps the text off the rounded corner. */
    padding: 24px 22px 0;
    scroll-padding-top: 12px;
    /* A column, so the credits line can be pushed to the FOOT of the card on a
       short page. Without it the footer simply followed the content and ended up
       floating half-way up an empty screen — News with five rows, the profile
       form, an order list with nothing in it. */
    display: flex;
    flex-direction: column;
}

/* The page itself. `1 0 auto` and not `1`: it has to be free to GROW into the
   leftover space — that is what pushes the footer down — and must never be
   shrunk below its own content, which would give the page a second scrollbar
   inside the one scroller this app has. Livewire always renders a single root
   element, so this reaches every screen without any of them knowing. */
.nv-content > :first-child { flex: 1 0 auto; min-width: 0; min-height: 0; max-width: 100%; }
/* The pull hint is prepended in front of the page. It must stay collapsed,
   and the page behind it keeps the growth that pins the footer. */
.nv-content > .nv-pull {
    flex: 0 0 auto;
    height: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    color: var(--nv-ink-4);
}
.nv-content > .nv-pull + * { flex: 1 0 auto; min-width: 0; min-height: 0; max-width: 100%; }

/* The product's own footer, widened to the card's edges so it reads as the foot
   OF the card instead of one more block floating in it. The negative inline
   margin cancels the scroller's gutter, which is the only way to do it from
   here: the markup belongs to the core and this package does not fork it. */
.nv-content > footer {
    flex: 0 0 auto;
    margin-inline: -22px;
    border-end-start-radius: var(--nv-r-app);
    border-end-end-radius: var(--nv-r-app);
}

.nv-page-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 20px; }
.nv-page-head h1 { font-size: 25px; font-weight: 700; letter-spacing: -.5px; }
.nv-page-head p { font-size: 13px; color: var(--nv-ink-5); margin-top: 3px; }
.nv-page-head .nv-ph-actions { margin-inline-start: auto; display: flex; gap: 9px; align-items: center; flex-wrap: wrap; }

/* ══════════════════════════════════════════════════════════════════════════
   5 · PRIMITIVES
   ══════════════════════════════════════════════════════════════════════════ */
.nv-card {
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-card);
    box-shadow: var(--nv-shadow-sm);
}
.nv-card-pad { padding: 18px; }
.nv-card-head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 16px 18px; border-bottom: 1px solid var(--nv-line);
}
.nv-card-head h3 { font-size: 15px; font-weight: 650; letter-spacing: -.2px; }
.nv-card-head p { font-size: 12px; color: var(--nv-ink-5); margin-top: 2px; }
/* min-width: 0 + wrap: a flex child defaults to min-width: auto, so a couple of
   controls on the end of a card header widen the card past the viewport. */
.nv-card-head .nv-ch-right { margin-inline-start: auto; display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: wrap; }

.nv-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    border: 1px solid transparent;
    border-radius: var(--nv-r-pill);
    padding: 9px 17px;
    font-size: 13px; font-weight: 600;
    transition: filter .14s ease, background .14s ease;
}
.nv-btn i, .nv-btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.nv-btn-primary { background: var(--nv-chip-ink); color: var(--nv-on-chip-ink); }
.nv-btn-primary:hover { filter: brightness(1.25); }
.nv-btn-brand { background: var(--nv-brand); color: var(--nv-on-brand); }
.nv-btn-brand:hover { filter: brightness(.95); }
.nv-btn-ghost { background: var(--nv-white); border-color: var(--nv-line-2); color: var(--nv-ink-2); }
/* The hover used to be `background: var(--nv-paper-2)`, an ABSOLUTE surface
   colour — and a ghost button is routinely placed ON a surface. On the API
   page it sits inside .nv-code, whose background IS --nv-paper-2: measured at
   254,249,232 on both sides, so pointing at the button made it vanish into the
   box it was sitting on. A hover has to be relative to the BUTTON's own resting
   colour, never a named surface, or it is a coin flip whether it disappears
   wherever someone drops it next. Mixing towards the theme's ink keeps the warm
   tint (a flat grey reads cold on this palette) and the border firms up so the
   control is still outlined even where the fill happens to be close. */
.nv-btn-ghost:hover {
    background: color-mix(in srgb, var(--nv-ink) 7%, var(--nv-white));
    border-color: var(--nv-ink-5);
}

.nv-btn-sm { padding: 6px 13px; font-size: 12px; }
.nv-btn-block { width: 100%; }
.nv-btn:disabled, .nv-btn[aria-disabled='true'] { opacity: .5; cursor: not-allowed; }

.nv-chip {
    display: inline-flex; align-items: center; gap: 6px;
    border: 1px solid var(--nv-line-2);
    background: var(--nv-white);
    border-radius: var(--nv-r-pill);
    padding: 7px 14px;
    font-size: 12.5px; font-weight: 500; color: var(--nv-ink-3);
}
.nv-chip:hover { background: var(--nv-paper-2); color: var(--nv-ink); }
.nv-chip[aria-pressed='true'] { background: var(--nv-brand); border-color: var(--nv-brand); color: var(--nv-on-brand); font-weight: 600; }
.nv-chip i, .nv-chip svg { width: 15px; height: 15px; }
.nv-chip-count { background: var(--nv-paper-2); border-radius: var(--nv-r-pill); padding: 0 6px; font-size: 11px; font-weight: 600; color: var(--nv-ink-4); }
.nv-chip[aria-pressed='true'] .nv-chip-count { background: rgba(0, 0, 0, .13); color: inherit; }

.nv-badge {
    display: inline-flex; align-items: center; gap: 5px;
    border-radius: var(--nv-r-pill);
    padding: 3px 10px;
    font-size: 11.5px; font-weight: 600;
    white-space: nowrap;
}
.nv-badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.nv-badge-ok { background: var(--nv-ok-bg); color: var(--nv-ok); }
.nv-badge-warn { background: var(--nv-warn-bg); color: var(--nv-warn); }
.nv-badge-bad { background: var(--nv-bad-bg); color: var(--nv-bad); }
.nv-badge-info { background: var(--nv-info-bg); color: var(--nv-info); }
.nv-badge-mute { background: var(--nv-paper-2); color: var(--nv-ink-5); }

/* ── metric strip ─────────────────────────────────────────────────────── */
.nv-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-bottom: 16px; }
.nv-stat { display: flex; align-items: center; gap: 13px; padding: 16px 17px; }
.nv-stat-ico { width: 44px; height: 44px; border-radius: 13px; display: grid; place-items: center; flex-shrink: 0; }
.nv-stat-ico i, .nv-stat-ico svg { width: 21px; height: 21px; }
.nv-stat-ico-brand { background: var(--nv-soft); color: var(--nv-deep); }
.nv-stat-ico-ok { background: var(--nv-ok-bg); color: var(--nv-ok); }
.nv-stat-ico-info { background: var(--nv-info-bg); color: var(--nv-info); }
.nv-stat-ico-bad { background: var(--nv-bad-bg); color: var(--nv-bad); }
.nv-stat-ico-warn { background: var(--nv-warn-bg); color: var(--nv-warn); }

.nv-stat-val { font-size: 21px; font-weight: 700; letter-spacing: -.5px; line-height: 1.15; font-variant-numeric: tabular-nums; }
.nv-stat-lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--nv-ink-5); font-weight: 600; margin-top: 2px; }
/* The card is a flex row of icon + text: the text side has to GROW, or a share
   bar under the label sizes itself by the label and stops being comparable
   between the four cards. min-width:0 is the half that does the work — a flex
   item defaults to min-width:auto and refuses to shrink below its content. */
.nv-stat-body { flex: 1; min-width: 0; }
.nv-stat .nv-prog { margin-top: 8px; }

/* ── grids ────────────────────────────────────────────────────────────────
   Every track is minmax(0, …): a bare 1fr is minmax(auto, 1fr), so a card
   holding a wide table sizes the track by its min-content and pushes the page
   sideways. Same reason on the item side — a grid child defaults to
   min-width: auto. */
.nv-grid { display: grid; gap: 16px; margin-bottom: 16px; }
.nv-grid-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.nv-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.nv-grid-23 { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.nv-grid-form { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); align-items: start; }
.nv-grid > *, .nv-stats > * { min-width: 0; }
.nv-mb0 { margin-bottom: 0; }
.nv-mt16 { margin-top: 16px; }

/* ── tables ───────────────────────────────────────────────────────────── */
.nv-tablewrap { overflow-x: auto; }
.nv-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.nv-table thead th {
    text-align: start;
    font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
    color: var(--nv-ink-5); font-weight: 700;
    padding: 11px 13px;
    background: var(--nv-paper-2);
    border-bottom: 1px solid var(--nv-line);
    white-space: nowrap;
}
.nv-table tbody td { padding: 12px 13px; border-bottom: 1px solid var(--nv-line); vertical-align: middle; }
.nv-table tbody tr:last-child td { border-bottom: 0; }
.nv-table tbody tr:hover { background: var(--nv-paper-2); }
.nv-table .nv-t-id { font-variant-numeric: tabular-nums; color: var(--nv-ink-5); font-weight: 600; white-space: nowrap; }
/* The service name is the column a customer READS to tell two rows apart, so it
   gets the room and everything else stays on one line: in an imported catalogue
   the quality and the refill window are at the END of the name, which is exactly
   what a truncation eats. */
.nv-table .nv-t-name { min-width: 208px; }
.nv-table .nv-t-nowrap { white-space: nowrap; }
.nv-table .nv-t-strong { font-weight: 600; }
.nv-table .nv-t-sub { font-size: 11.5px; color: var(--nv-ink-5); margin-top: 2px; }
.nv-table .nv-t-num { font-variant-numeric: tabular-nums; text-align: end; white-space: nowrap; }
.nv-t-link { color: var(--nv-info); font-size: 12.5px; }
.nv-t-link:hover { text-decoration: underline; }
/* The LINK column is the opposite case to the service name: it is the row's
   longest string and the one nobody reads in full, so the cell is capped and the
   address clips with an ellipsis — the title keeps the whole of it, and the copy
   button next to it is how the customer actually takes it away. */
.nv-table .nv-t-url { max-width: 210px; }
.nv-t-clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
/* A sortable header is a CONTROL, so it says so with the pointer, and its arrow
   sits on the label's own line. No text-align here: a numeric header already
   carries nv-t-num, and the inline-flex span follows it. */
.nv-table .nv-th-sort { cursor: pointer; user-select: none; }
.nv-th-sort span { display: inline-flex; align-items: center; gap: 5px; }
.nv-th-sort i, .nv-th-sort svg { width: 13px; height: 13px; }

.nv-rowico { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; flex-shrink: 0; background: var(--nv-paper-2); color: var(--nv-ink-3); }
.nv-rowico i, .nv-rowico svg { width: 16px; height: 16px; }
.nv-cell-flex { display: flex; align-items: center; gap: 10px; min-width: 0; }

.nv-actions { display: flex; gap: 6px; }
.nv-act { width: 30px; height: 30px; border-radius: 9px; border: 1px solid var(--nv-line-2); background: var(--nv-white); display: grid; place-items: center; color: var(--nv-ink-4); }
.nv-act:hover { background: var(--nv-soft); color: var(--nv-ink); }
.nv-act i, .nv-act svg { width: 15px; height: 15px; }
/* Tinted actions, for a row where several icons sit side by side and one of them
   is destructive: the colour is what tells them apart before the tooltip does.
   Each modifier declares its OWN :hover — the plain .nv-act:hover above is
   (0,2,0) and would otherwise repaint them back to neutral on the way to the
   click. The pairs are the ones the design already travels with (bad-bg + bad,
   soft + deep), never a brand colour used as text: on a light card that is the
   1.6:1 that the product has been bitten by. */
.nv-act-bad { background: var(--nv-bad-bg); color: var(--nv-bad); border-color: var(--nv-bad); }
.nv-act-bad:hover { background: var(--nv-bad); color: var(--nv-on-bad); border-color: var(--nv-bad); }
.nv-act-soft { background: var(--nv-soft); color: var(--nv-deep); border-color: var(--nv-line-2); }
.nv-act-soft:hover { background: var(--nv-soft); color: var(--nv-deep); border-color: var(--nv-brand); }

.nv-tfoot { display: flex; align-items: center; gap: 12px; padding: 13px 16px; border-top: 1px solid var(--nv-line); font-size: 12.5px; color: var(--nv-ink-5); flex-wrap: wrap; }
/* The product's paginator markup is what lands inside this, so the styling is
   applied to whatever it renders rather than to a shape this package invents. */
.nv-pager { margin-inline-start: auto; min-width: 0; }
.nv-pager nav { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.nv-pager a, .nv-pager span, .nv-pager button {
    min-width: 31px; height: 31px; padding: 0 8px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--nv-line-2); background: var(--nv-white);
    border-radius: 9px; font-size: 12.5px; color: var(--nv-ink-3);
}
.nv-pager [aria-current='page'], .nv-pager [aria-current='true'] {
    background: var(--nv-brand); border-color: var(--nv-brand);
    color: var(--nv-on-brand); font-weight: 700;
}

/* ── toolbar ──────────────────────────────────────────────────────────── */
.nv-toolbar { display: flex; align-items: center; gap: 9px; padding: 14px 16px; flex-wrap: wrap; border-bottom: 1px solid var(--nv-line); }
.nv-toolbar .nv-tb-right { margin-inline-start: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; min-width: 0; }
/* A toolbar that has to stay on ONE line hands the leftover width to the pill bar
   and lets it scroll. Without this the wrapper sizes itself by its content —
   seven status tabs with counters — and pushes the search box onto a second row
   and the second export onto a third.

   The basis has to be 0 and NOT auto, and that is the whole fix: in a wrapping
   flex container the browser decides the LINES first, using each item's
   hypothetical base size, and only then shrinks what shares a line. With
   `auto` the base is the content (measured here: 804px of tabs against 890px
   of toolbar), so the pill forces the break before shrinking is ever
   considered and its overflow-x never gets used — the exact three-row layout
   this rule exists to prevent. With 0 the pill can never force a break and
   grows only into what is left over. min-width:0 is what then lets it shrink
   below its content; overflow-x already lives on .nv-tabswrap. */
.nv-toolbar .nv-tb-fill { flex: 1 1 0; min-width: 0; }
.nv-field-search {
    display: flex; align-items: center; gap: 8px;
    border: 1px solid var(--nv-line-2); background: var(--nv-white);
    border-radius: var(--nv-r-ctl); padding: 8px 13px;
    min-width: 0; flex: 1 1 230px; max-width: 320px;
    color: var(--nv-ink-5);
}
.nv-field-search input { border: 0; outline: none; background: transparent; font: inherit; font-size: 12.5px; color: var(--nv-ink); width: 100%; min-width: 0; }
.nv-field-search i, .nv-field-search svg { width: 15px; height: 15px; flex-shrink: 0; }

/* ── forms ────────────────────────────────────────────────────────────── */
.nv-label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 7px; }
.nv-label .nv-req { color: var(--nv-bad); }
.nv-label .nv-opt { color: var(--nv-ink-6); font-weight: 400; }
.nv-help { font-size: 11.5px; color: var(--nv-ink-5); margin-top: 6px; line-height: 1.5; }
/* A validation message is not a hint in another colour: it is the only text on
   the screen the customer has to act on, so it keeps its own class and never
   borrows .nv-help. */
.nv-err { font-size: 11.5px; color: var(--nv-bad); margin-top: 6px; line-height: 1.5; font-weight: 500; }

.nv-input, .nv-select, .nv-textarea {
    width: 100%;
    border: 1px solid var(--nv-line-2);
    background: var(--nv-white);
    border-radius: var(--nv-r-ctl);
    padding: 11px 14px;
    font: inherit; font-size: 13.5px; color: var(--nv-ink);
    outline: none;
}
.nv-input:focus, .nv-select:focus, .nv-textarea:focus {
    border-color: var(--nv-brand);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv-brand) 28%, transparent);
}
.nv-input:disabled, .nv-select:disabled, .nv-textarea:disabled { background: var(--nv-paper-2); color: var(--nv-ink-5); cursor: not-allowed; }
.nv-textarea { min-height: 92px; resize: vertical; line-height: 1.55; }
.nv-select { appearance: none; background-image: none; padding-inline-end: 38px; }
.nv-selwrap { position: relative; }
.nv-selwrap > i, .nv-selwrap > svg {
    position: absolute; inset-inline-end: 13px; top: 50%; transform: translateY(-50%);
    width: 16px; height: 16px; color: var(--nv-ink-5); pointer-events: none;
}
.nv-fieldrow { margin-bottom: 15px; }
.nv-check { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; }
.nv-check input { width: 16px; height: 16px; margin-top: 2px; flex-shrink: 0; accent-color: var(--nv-brand); }

/* A pill bar is a row of fixed-width chips: on a narrow screen it must SCROLL,
   never push the page sideways. Wrapping would break the pill shape. */
.nv-tabswrap { overflow-x: auto; scrollbar-width: none; margin-inline: -2px; padding-inline: 2px; }
.nv-tabswrap::-webkit-scrollbar { display: none; }
.nv-tabs { display: inline-flex; gap: 4px; background: var(--nv-paper-2); border: 1px solid var(--nv-line); border-radius: var(--nv-r-pill); padding: 4px; max-width: 100%; }
.nv-tab { border: 0; background: transparent; border-radius: var(--nv-r-pill); padding: 7px 15px; font-size: 12.5px; font-weight: 600; color: var(--nv-ink-4); display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.nv-tab i, .nv-tab svg { width: 15px; height: 15px; }
.nv-tab[aria-selected='true'] { background: var(--nv-white); color: var(--nv-ink); box-shadow: var(--nv-shadow-sm); }

/* ── network tiles ────────────────────────────────────────────────────── */
.nv-nets { display: flex; gap: 8px; flex-wrap: wrap; }
.nv-net {
    display: inline-flex; align-items: center; gap: 7px;
    border: 1px solid var(--nv-line-2); background: var(--nv-white);
    border-radius: var(--nv-r-ctl); padding: 8px 13px;
    font-size: 12.5px; font-weight: 500; color: var(--nv-ink-2);
}
.nv-net:hover { border-color: var(--nv-brand); }
.nv-net[aria-pressed='true'] { background: var(--nv-chip-ink); border-color: var(--nv-chip-ink); color: var(--nv-on-chip-ink); font-weight: 600; }
.nv-net i, .nv-net svg { width: 16px; height: 16px; }
.nv-net-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
/* A network with no services behind it: offered so the catalogue reads complete,
   never clickable, because filtering by it would empty the list and say nothing.
   The hover is cancelled too — a chip that lights up under the pointer and then
   refuses the click reads as a broken control rather than an unavailable one. */

/* ── order summary ────────────────────────────────────────────────────── */

.nv-note {
    display: flex; gap: 10px;
    background: var(--nv-paper-2);
    border: 1px solid var(--nv-line);
    border-radius: 13px; padding: 13px 14px;
    font-size: 12px; color: var(--nv-ink-3); line-height: 1.55;
}
.nv-note i, .nv-note svg { width: 17px; height: 17px; flex-shrink: 0; color: var(--nv-deep); margin-top: 1px; }
.nv-note h4 { font-size: 12.5px; font-weight: 650; color: var(--nv-ink); margin-bottom: 3px; }
.nv-note ul { margin: 0; padding-inline-start: 16px; }
.nv-note li { margin-bottom: 3px; }
/* The customer typed this into a textarea, so the line breaks they put in are
   part of what they wrote: collapsing them reflows their own instructions into
   one paragraph and reads as if the panel lost half the note. */
.nv-note-pre { white-space: pre-line; margin-top: 4px; }
.nv-note-ok { background: var(--nv-ok-bg); border-color: color-mix(in srgb, var(--nv-ok) 28%, transparent); }
.nv-note-ok i, .nv-note-ok svg, .nv-note-ok h4 { color: var(--nv-ok); }
.nv-note-warn { background: var(--nv-warn-bg); border-color: color-mix(in srgb, var(--nv-warn) 28%, transparent); }
.nv-note-warn i, .nv-note-warn svg, .nv-note-warn h4 { color: var(--nv-warn); }
.nv-note-bad { background: var(--nv-bad-bg); border-color: color-mix(in srgb, var(--nv-bad) 28%, transparent); }
.nv-note-bad i, .nv-note-bad svg, .nv-note-bad h4 { color: var(--nv-bad); }

/* ── charts and progress ──────────────────────────────────────────────── */
.nv-chart { width: 100%; height: auto; display: block; overflow: visible; }
.nv-legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12px; color: var(--nv-ink-4); }
.nv-legend span { display: inline-flex; align-items: center; gap: 6px; }
.nv-legend i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.nv-donut-wrap { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; justify-content: center; }
/* These live inside a 0 0 42 42 viewBox, so the sizes are USER UNITS and not
   pixels — a 25 here would render the number bigger than the ring. */
.nv-donut-mid { text-anchor: middle; }
.nv-donut-num { font-size: 6.4px; font-weight: 700; fill: var(--nv-ink); }
.nv-donut-lbl { font-size: 2.1px; font-weight: 600; fill: var(--nv-ink-5); letter-spacing: .12px; }
.nv-donut-list { display: grid; gap: 9px; min-width: 165px; }
.nv-donut-row { display: flex; align-items: center; gap: 9px; font-size: 12.5px; }
.nv-donut-row i { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.nv-donut-row b { margin-inline-start: auto; font-variant-numeric: tabular-nums; }
.nv-donut-row em { font-style: normal; color: var(--nv-ink-5); font-variant-numeric: tabular-nums; min-width: 26px; text-align: end; }
.nv-prog { height: 6px; border-radius: var(--nv-r-pill); background: var(--nv-line); overflow: hidden; }
.nv-prog i { display: block; height: 100%; border-radius: var(--nv-r-pill); background: var(--nv-brand); }
/* The WIDTH of a bar is data and is written inline by the view; the COLOUR is
   meaning and belongs here. Same specificity as the rule above (0,1,1), so these
   win on source order alone — keep them below it. */
.nv-prog-ok i { background: var(--nv-ok); }
.nv-prog-info i { background: var(--nv-info); }
.nv-prog-bad i { background: var(--nv-bad); }

/* ── quick actions ────────────────────────────────────────────────────── */
.nv-qa { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 11px; }
.nv-qa-item { display: flex; align-items: center; gap: 11px; border: 1px solid var(--nv-line-2); background: var(--nv-paper-2); border-radius: 13px; padding: 13px; min-width: 0; }
.nv-qa-item:hover { border-color: var(--nv-brand); background: var(--nv-soft); }
.nv-qa-ico { width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; flex-shrink: 0; background: var(--nv-soft); color: var(--nv-deep); }
.nv-qa-ico i, .nv-qa-ico svg { width: 18px; height: 18px; }
.nv-qa-item h4 { font-size: 13px; font-weight: 600; }
.nv-qa-item p { font-size: 11.5px; color: var(--nv-ink-5); margin-top: 1px; }

/* ── payment methods and amounts ──────────────────────────────────────── */
/* ONE LINE, and it scrolls. The reference lays the gateways out as a 4-column
   grid, which becomes a second and a third row as soon as the operator switches
   on more than four — and it pushes the amount box and the Continue button off
   the screen on the one page that takes money. So the grid became a rail, and
   what keeps a rail from being a place where cards hide is the three signals
   below: the arrows in the heading, the fade on whichever edge still has
   something past it, and a scrollbar that is hidden while the scroll is real. */
/* THE CARD THAT HOLDS THE RAIL HAS TO BE ALLOWED TO SHRINK, and this is not
   tidiness — without it the rail takes the page apart. The left column is a
   grid, a grid item's automatic minimum size is its min-content, and the row of
   cards propagates its full width straight through the scroll container: the
   card came out 1476px wide inside a 672px column, painted itself over the
   Payment summary and gave the whole page a horizontal scrollbar (measured at
   1440 with eight gateways). The four-column grid this replaced could never do
   it, so the guard arrives with the rail. Declared on its own class rather than
   on .nv-card: every other card in the portal sizes itself from its content and
   has no business being told it may collapse. */
.nv-paycard { min-width: 0; }
.nv-payhead { display: flex; align-items: center; gap: 10px; margin-bottom: 13px; min-width: 0; }
/* The step badge owns its own bottom margin when it stands alone; inside this
   row the ROW carries it, or the arrows sit 13px above the cards and the label
   13px above them again. */
.nv-payhead .nv-step { margin-bottom: 0; }
.nv-payrail-nav { display: flex; align-items: center; gap: 6px; margin-inline-start: auto; }
.nv-payrail-btn {
    width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
    display: grid; place-items: center;
    border: 1px solid var(--nv-line-2); background: var(--nv-white); color: var(--nv-ink-2);
}
.nv-payrail-btn svg { width: 15px; height: 15px; }
.nv-payrail-btn:hover:not(:disabled) { border-color: var(--nv-brand); color: var(--nv-ink); }
.nv-payrail-btn:disabled { opacity: .38; cursor: default; }
/* The glyph points where the rail is about to move, and in Arabic that is the
   other way. One transform rather than a second pair of icons: the scroll
   direction is already flipped in the component, so the two agree by
   construction instead of by someone remembering both. */
html[dir='rtl'] .nv-payrail-btn svg { transform: scaleX(-1); }

/* The wrapper exists for the fades, which cannot live on the scroller itself: a
   pseudo-element of a scroll container travels WITH the content, so it would
   slide out of sight at the exact moment it is saying there is more. They are
   pointer-events: none, or the edges of the rail would swallow the taps meant
   for the first and last card. Painted in the card's own colour through a
   token, so the dark card needs no second rule. */
.nv-payrail { position: relative; }
.nv-payrail::before,
.nv-payrail::after {
    content: ''; position: absolute; inset-block: 0; width: 34px; z-index: 1;
    pointer-events: none; opacity: 0; transition: opacity .15s ease;
}
.nv-payrail::before { inset-inline-start: 0; background: linear-gradient(to right, var(--nv-white), transparent); }
.nv-payrail::after { inset-inline-end: 0; background: linear-gradient(to left, var(--nv-white), transparent); }
html[dir='rtl'] .nv-payrail::before { background: linear-gradient(to left, var(--nv-white), transparent); }
html[dir='rtl'] .nv-payrail::after { background: linear-gradient(to right, var(--nv-white), transparent); }
/* Each edge answers for itself, so a rail whose cards all fit shows neither. */
.nv-payrail-more-s::before { opacity: 1; }
.nv-payrail-more-e::after { opacity: 1; }

.nv-pays {
    display: flex; gap: 12px;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x proximity;
    /* Hidden, not absent: the arrows and the fades are the affordance, and a
       track drawn under a row of cards reads as a seam across the card. */
    scrollbar-width: none;
    /* Room for the focus ring. The scrollport is the padding box, so without
       this the ring on the first and last card is clipped by the very container
       that makes the row scroll — a keyboard user would tab into a card and see
       nothing happen. */
    padding: 5px; scroll-padding-inline: 5px;
}
.nv-pays::-webkit-scrollbar { width: 0; height: 0; }
.nv-pay {
    /* The card grows to fill a short row, shrinks to a FLOOR, and only then does
       the row scroll. The floor is what decides when a carousel appears at all,
       so it is measured and not picked: the reference fits four cards across this
       column at ~150px each, and four gateways is what a real panel runs — with
       a fixed width they overflowed by 84px and earned arrows for a row that
       almost fitted. Shrinking to 134 lets four fit exactly as the reference
       draws them, and five or more scroll. */
    flex: 1 1 152px; min-width: 134px; max-width: 224px;
    scroll-snap-align: start;
    position: relative;
    border: 1.5px solid var(--nv-line-2); background: var(--nv-white);
    border-radius: 14px; padding: 15px; text-align: start;
    display: flex; flex-direction: column; gap: 9px;
}
.nv-pay:hover { border-color: var(--nv-brand); }
.nv-pay[aria-pressed='true'] { border-color: var(--nv-brand); background: var(--nv-soft); }
/* Plain ink and not the brand: an indicator has to stand out from what is
   behind it and the factory brand measures 1.61:1 on this card. The token
   inverts with the mode, so the ring is dark on the white card and light on the
   dark one with nothing else to declare. */
.nv-pay:focus-visible,
.nv-payrail-btn:focus-visible { outline: 2px solid var(--nv-ink); outline-offset: 2px; }
.nv-pay-ico { width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center; background: var(--nv-paper-2); flex-shrink: 0; }
.nv-pay-ico i, .nv-pay-ico svg { width: 19px; height: 19px; color: var(--nv-ink-2); }
/* An imported gateway name carries its quality and its guarantee at the END,
   and the card is now a fixed width — so the name wraps and CSS decides where
   it stops, with the whole value still reachable through the button's title.
   Never a limit in PHP: this is the list the customer chooses FROM. */
.nv-pay h4 {
    font-size: 13px; font-weight: 650; overflow-wrap: anywhere;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.nv-pay p { font-size: 11.5px; color: var(--nv-ink-5); line-height: 1.45; }
/* The chosen card says so twice. The border is the reference's signal and it is
   the one a colour-blind buyer can miss, which on this screen means paying
   through a gateway he did not pick. Brand surface with the on-brand ink the
   product computes: a fixed white mark disappears on a pale brand. */
.nv-pay-check {
    position: absolute; top: 8px; inset-inline-end: 8px;
    width: 18px; height: 18px; border-radius: 50%;
    display: none; place-items: center;
    background: var(--nv-brand); color: var(--nv-on-brand);
}
.nv-pay-check svg { width: 10px; height: 10px; }
.nv-pay[aria-pressed='true'] .nv-pay-check { display: grid; }

.nv-step { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 650; margin-bottom: 13px; }
.nv-step i { width: 23px; height: 23px; border-radius: 50%; background: var(--nv-brand); color: var(--nv-on-brand); display: grid; place-items: center; font-size: 11.5px; font-weight: 700; font-style: normal; flex-shrink: 0; }

.nv-amounts { display: flex; gap: 8px; flex-wrap: wrap; }
.nv-amount { border: 1px solid var(--nv-line-2); background: var(--nv-white); border-radius: var(--nv-r-ctl); padding: 8px 16px; font-size: 13px; font-weight: 600; color: var(--nv-ink-2); }
.nv-amount:hover { border-color: var(--nv-brand); }
.nv-amount[aria-pressed='true'] { background: var(--nv-chip-ink); border-color: var(--nv-chip-ink); color: var(--nv-on-chip-ink); }

/* ── Add funds: one column, three steps, across the whole card ────────────
   It used to be capped at 760px and centred, on the argument that a two-input
   form spread edge to edge is not a form. True of the INPUTS and false of the
   SCREEN: at 1900px it left two bands of empty surface either side of a narrow
   strip, the method rail could show four gateways where twelve fit, and the page
   read as a form someone had dropped in the middle of an empty room.

   So the column takes the card, and the widths are settled INSIDE each step
   instead — the amount box keeps a control's width and the presets move up
   beside it, the summary and the button span the step they belong to. That is
   what "fills the space" has to mean here: the page is full, the controls are
   still the size a hand expects.

   1400px and not `none`: past that the three reassurance tiles and the rail turn
   into a line of text stretched across a billboard, and a step's label ends up a
   screen away from its own field. */
.nv-fundswrap { display: flex; justify-content: center; }
/* Amount and phone boxes on Add Funds: a hair darker than the page line, so the
   field edge reads from a step back without turning into a heavy stroke. */
.nv-fundsflow .nv-input {
    border-color: color-mix(in srgb, #111 38%, var(--nv-line-2));
}
.nv-fundsflow {
    display: grid;
    gap: 16px;
    width: 100%;
    max-width: 1400px;
    min-width: 0;
}

/* Step 2, on a wide card: the box on the left at a control's width, the quick
   amounts beside it instead of underneath. A number field that runs the width of
   a 1900px screen is not easier to type into, and the presets were the only
   thing that could honestly fill that row — they are the same six buttons,
   simply given the space they were queuing under. Below 900px it falls back to
   the stacked order, which is the one a phone reads. */
.nv-amountrow { display: grid; gap: 14px; align-items: end; }
@media (min-width: 900px) {
    .nv-amountrow { grid-template-columns: minmax(0, 300px) minmax(0, 1fr); }
    /* The presets sit ON the field's baseline rather than under its label, and
       they FOLLOW the box instead of being pushed to the far edge: flush right
       they left a band of nothing between the amount and its own shortcuts,
       which reads as two unrelated controls rather than one row. */
    .nv-amountrow .nv-amounts { justify-content: flex-start; align-content: flex-end; }

    /* The end of the toolbar — search plus the two exports — is one group, and
       on a desktop it stays on one line. Its own wrap was dropping the second
       export onto a row of its own (measured: three controls needing 553px in
       the 431px the group was given), which reads as a button that fell off the
       bar rather than as a deliberate second row. The search box is the part
       that gives (flex: 1 1 230px), so the group absorbs the squeeze where a
       text field can afford it instead of breaking the line.

       It is scoped to this breakpoint on purpose: below it the three controls
       genuinely do not fit side by side, and nowrap there would trade a wrapped
       row for a horizontal scrollbar across the whole page. */
    .nv-toolbar .nv-tb-right { flex-wrap: nowrap; }

    /* Holding the group on one line moves the squeeze INTO the buttons, and a
       button is the one control that must not absorb it: "Export Excel" broke
       across two lines and the bar grew taller than it was before the fix. The
       label stays whole and the search box — which has a flexible basis and a
       placeholder that is allowed to clip — is what gives instead. */
    .nv-toolbar .nv-tb-right .nv-btn { white-space: nowrap; }
}

/* The summary body. It used to be a card of its own on the other side of the
   page; now it is the third step, so it carries no second frame — the step
   heading above it is the frame. */
.nv-paysum { margin-top: 12px; }
.nv-paysum-note { margin-top: 10px; }

/* The three reassurances as one strip. They wrap to one per line on a phone,
   where three columns of 11.5px text is not a strip, it is a wall. */
.nv-trustrow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 10px;
}
/* They are no longer cards, so they carry their own surface: without it they
   would be three unbounded blocks of grey text under the button. */
.nv-trustrow .nv-trust {
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-card);
}

.nv-trust { display: flex; gap: 11px; align-items: flex-start; padding: 14px; }
.nv-trust-ico { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; flex-shrink: 0; background: var(--nv-soft); color: var(--nv-deep); }
.nv-trust-ico i, .nv-trust-ico svg { width: 17px; height: 17px; }
.nv-trust h4 { font-size: 12.5px; font-weight: 650; }
.nv-trust p { font-size: 11.5px; color: var(--nv-ink-5); line-height: 1.5; margin-top: 2px; }

/* ── support: ticket list and conversation ────────────────────────────── */
/* Support is an INBOX, so it is laid out like one: the two panels share the
   window's height and each scrolls inside itself. Before this, the page was the
   scroller — the ticket list grew past the bottom of the screen (measured at
   782px against a 752px window) while the conversation beside it sat at its
   470px minimum with a third of it empty, which is the "one box eats the whole
   height" you see. Capping both means the composer never leaves the screen and
   the list is browsed without the page moving under the thread you are reading.
   dvh and not vh: on a phone, vh counts the address bar as if it were gone and
   the composer ends up under it. */
.nv-chatgrid {
    display: grid;
    grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
    gap: 16px;
    align-items: stretch;
    height: calc(100dvh - var(--nv-chat-chrome, 208px));
    min-height: 420px;
}
.nv-chatgrid-wide { grid-template-columns: minmax(0, 364px) minmax(0, 1fr); }
/* Each panel is a column that scrolls its own middle. The toolbar, the tabs and
   the composer stay put; only the rows and the bubbles move. */
.nv-chatgrid > .nv-card { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
/* The ticket rows. `.nv-tk` is the row itself, so the scroller is the space
   between the tabs and the bottom of the panel — expressed as "everything that
   is not a fixed part", which keeps working when a part is added. */
.nv-tklist { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
.nv-tklist::-webkit-scrollbar { width: 0; }
.nv-tklist:hover { scrollbar-width: thin; scrollbar-color: var(--nv-line) transparent; }
.nv-tklist:hover::-webkit-scrollbar { width: 4px; }
.nv-tklist:hover::-webkit-scrollbar-track { background: transparent; }
.nv-tklist:hover::-webkit-scrollbar-thumb { background: var(--nv-ink-2); border-radius: 999px; }
/* Status tabs. The pressed pill is painted with the PAIR --nv-brand /
   --nv-on-brand and never with a literal: --nv-brand is the buyer's own colour
   and the one tab that must be readable is the one you are standing on. The
   resting pill uses --nv-soft, which flips with the mode on its own, so no
   second rule is needed in the dark layer. */
/* Status tabs: ONE line that scrolls, never a block that grows.
   Wrapped, the five tabs took two rows and 87px off a column that was already
   taller than the window — and the row's height changed with the panel's
   language, so the list below it started in a different place per locale.
   Scrolled, the row is one line whatever the wording, and the scrollbar is
   hidden until the pointer is over it: visible, a 15px system bar under five
   32px pills is most of the row's height. It still scrolls by touch, by
   trackpad and by dragging (see the script in the view), and every tab stays
   reachable with Tab — the browser scrolls a focused one into view itself. */
/* The wrapper exists only to hold the fades — the scroller cannot, because a
   pseudo-element of a scroll container scrolls away with its content. Each fade
   is shown only while that edge really has tabs behind it (the script marks it),
   so a row that fits shows none and the wrapper is invisible. */
.nv-tktabswrap { position: relative; }
.nv-tktabswrap::before,
.nv-tktabswrap::after {
    content: '';
    position: absolute; inset-block: 1px 2px;
    width: 34px;
    pointer-events: none;
    opacity: 0;
    transition: opacity .15s ease;
    z-index: 1;
}
/* The gradient is painted from the CARD's own colour, so it reads as the row
   dissolving into the panel rather than as a grey smudge over it — and it
   follows the light/dark flip on its own, with no second rule. */
.nv-tktabswrap::before {
    inset-inline-start: 0;
    background: linear-gradient(to right, var(--nv-white) 35%, transparent);
}
.nv-tktabswrap::after {
    inset-inline-end: 0;
    background: linear-gradient(to left, var(--nv-white) 35%, transparent);
}
.nv-tktabs-more-s::before,
.nv-tktabs-more-e::after { opacity: 1; }

.nv-tktabs {
    display: flex; flex-wrap: nowrap; gap: 7px;
    /* 20px and not 16: the first pill used to start flush against the card's
       rounded corner and the last one was sliced by it. The gutter is what makes
       a scrolled row look scrolled instead of cropped, and it is also the space
       the fades live over. */
    padding: 11px 20px;
    border-bottom: 1px solid var(--nv-line);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;                /* Firefox: hidden at rest */
    scroll-behavior: smooth;
}
.nv-tktabs::-webkit-scrollbar { height: 0; }
/* Minimal, and only while the pointer is there. */
.nv-tktabs:hover { scrollbar-width: thin; scrollbar-color: var(--nv-line) transparent; }
.nv-tktabs:hover::-webkit-scrollbar { height: 4px; }
.nv-tktabs:hover::-webkit-scrollbar-track { background: transparent; }
.nv-tktabs:hover::-webkit-scrollbar-thumb { background: var(--nv-ink-2); border-radius: 999px; }
/* While a drag is in progress the row must not also select its own labels. */
.nv-tktabs-drag { cursor: grabbing; user-select: none; }
.nv-tktabs-drag .nv-tktab { pointer-events: none; }
.nv-tktab {
    padding: 6px 13px;
    /* Not shrinkable: in a nowrap row the default would squeeze five pills into
       the width instead of overflowing, and a squeezed pill clips its count —
       which is the one thing the tab is there to say. */
    flex: 0 0 auto;
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-pill);
    background: var(--nv-paper-2);
    color: var(--nv-ink-4);
    font-size: 12px; font-weight: 600; line-height: 1.2;
    white-space: nowrap; cursor: pointer;
    transition: background-color .13s ease, color .13s ease, border-color .13s ease;
}
.nv-tktab:hover:not(:disabled) { background: var(--nv-soft); color: var(--nv-ink); border-color: var(--nv-brand); }
.nv-tktab-on,
.nv-tktab-on:hover { background: var(--nv-brand); border-color: var(--nv-brand); color: var(--nv-on-brand); }
/* A tab with nothing behind it holds its place and stops being a target: hiding
   it would move the row every time a ticket changes state. */
.nv-tktab:disabled { opacity: .45; cursor: not-allowed; }

.nv-tk { display: flex; gap: 11px; padding: 13px 15px; border-bottom: 1px solid var(--nv-line); width: 100%; text-align: start; background: transparent; border-inline: 0; border-top: 0; }
.nv-tk:hover { background: var(--nv-paper-2); }
.nv-tk[aria-current='true'] { background: var(--nv-soft); box-shadow: inset 3px 0 0 var(--nv-brand); }
.nv-tk-ico { width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center; flex-shrink: 0; background: var(--nv-paper-2); color: var(--nv-ink-3); }
.nv-tk-ico i, .nv-tk-ico svg { width: 16px; height: 16px; }
.nv-tk-body { min-width: 0; flex: 1; }
.nv-tk-top { display: flex; align-items: center; gap: 8px; }
.nv-tk-top h4 { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.nv-tk-meta { font-size: 11px; color: var(--nv-ink-5); margin-top: 3px; display: flex; gap: 8px; flex-wrap: wrap; }

/* No min-height any more: the grid gives the panel its height, and a minimum on
   top of that is what made the card overshoot the window on a short screen. */
.nv-chat { display: flex; flex-direction: column; min-height: 0; }
.nv-chat-body {
    flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    padding: 18px; display: flex; flex-direction: column; gap: 14px;
    background: var(--nv-paper-2);
    /* Bubbles sit at the BOTTOM, against the composer, the way every messenger
       does it. Stretched from the top, two messages left 157px of empty grey
       between the last line and the input. */
    justify-content: flex-end;
    scrollbar-width: none;
}
.nv-chat-body::-webkit-scrollbar { width: 0; }
.nv-chat-body:hover { scrollbar-width: thin; scrollbar-color: var(--nv-line) transparent; }
.nv-chat-body:hover::-webkit-scrollbar { width: 4px; }
.nv-chat-body:hover::-webkit-scrollbar-track { background: transparent; }
.nv-chat-body:hover::-webkit-scrollbar-thumb { background: var(--nv-ink-2); border-radius: 999px; }
.nv-msg { display: flex; gap: 10px; max-width: 78%; }
.nv-msg-av { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; flex-shrink: 0; font-size: 11.5px; font-weight: 700; background: var(--nv-chip-ink); color: var(--nv-on-chip-ink); }
.nv-msg-bub { background: var(--nv-white); border: 1px solid var(--nv-line); border-radius: 14px; border-start-start-radius: 4px; padding: 11px 14px; font-size: 13px; line-height: 1.55; min-width: 0; overflow-wrap: anywhere; }
.nv-msg-time { font-size: 10.5px; color: var(--nv-ink-6); margin-top: 5px; }
.nv-msg-me { margin-inline-start: auto; flex-direction: row-reverse; }
.nv-msg-me .nv-msg-bub { background: var(--nv-brand); color: var(--nv-on-brand); border-color: var(--nv-brand); border-start-start-radius: 14px; border-start-end-radius: 4px; }
.nv-msg-me .nv-msg-av { background: var(--nv-soft); color: var(--nv-deeper); }
html.dark[data-theme='nativa'] .nv-msg-me .nv-msg-av { background: var(--nv-chip-ink); color: var(--nv-on-chip-ink); }
.nv-msg-me .nv-msg-time { text-align: end; color: var(--nv-ink-6); }
/* The same class does two jobs: the timestamp UNDER a bubble, which sits on the
   card and is right in the muted grey, and the author's name INSIDE the bubble,
   which on a brand-coloured bubble measured 1.75:1 — a name that is in the HTML
   and not on the screen. Inside the bubble the ink has to be the bubble's own,
   softened toward its background rather than swapped for a grey: a grey picked
   for the card has no idea what colour the operator's bubble is. Measured 5.9:1
   on the factory brand, and it follows any brand because both ends of the mix
   are that brand's own pair.

   Scoped to .nv-msg-me and NOT to every bubble: the other party's bubble is
   --nv-white, so on-brand ink inside it measured 1.44:1 — the first cut of this
   rule fixed one name and hid the other. There are two bubbles and only one of
   them is painted in the brand. */
.nv-msg-me .nv-msg-bub .nv-msg-time { color: color-mix(in srgb, var(--nv-on-brand) 78%, var(--nv-brand)); }
.nv-msg-file { display: inline-flex; align-items: center; gap: 7px; margin-top: 7px; font-size: 12px; font-weight: 600; }
.nv-msg-file i, .nv-msg-file svg { width: 14px; height: 14px; }

.nv-chat-foot { padding: 13px 16px; border-top: 1px solid var(--nv-line); background: var(--nv-white); }
.nv-chat-input { display: flex; align-items: flex-end; gap: 9px; }
.nv-chat-send { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0; background: var(--nv-chip-ink); color: var(--nv-on-chip-ink); border: 0; display: grid; place-items: center; }
.nv-chat-send i, .nv-chat-send svg { width: 17px; height: 17px; }

/* ── empty state, prose, key/value, code ──────────────────────────────── */
.nv-empty { padding: 44px 20px; text-align: center; }
.nv-empty-ico { width: 52px; height: 52px; border-radius: 16px; background: var(--nv-soft); color: var(--nv-deep); display: grid; place-items: center; margin: 0 auto 13px; }
.nv-empty-ico i, .nv-empty-ico svg { width: 24px; height: 24px; }
.nv-empty h3 { font-size: 15px; font-weight: 650; }
.nv-empty p { font-size: 13px; color: var(--nv-ink-5); margin: 5px auto 15px; max-width: 380px; line-height: 1.55; }

.nv-list-sep > * + * { border-top: 1px solid var(--nv-line); }
.nv-rowitem { display: flex; align-items: center; gap: 12px; padding: 13px 18px; min-width: 0; }
.nv-rowitem h4 { font-size: 13.5px; font-weight: 600; }
.nv-rowitem p { font-size: 12px; color: var(--nv-ink-5); margin-top: 2px; line-height: 1.5; }
.nv-rowitem .nv-ri-right { margin-inline-start: auto; text-align: end; flex-shrink: 0; }

.nv-kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 9px 18px; font-size: 13px; }
.nv-kv dt { color: var(--nv-ink-5); }
.nv-kv dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }

.nv-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12.5px; background: var(--nv-paper-2);
    border: 1px solid var(--nv-line); border-radius: var(--nv-r-ctl);
    padding: 11px 14px; overflow-x: auto; white-space: pre; color: var(--nv-ink-2);
}

/* ── Code sample box (API page) ────────────────────────────────────────────
   A sample the buyer is meant to COPY AND RUN was rendering as one flat block
   of one colour, which reads as a paragraph that happens to be monospaced. The
   ribbon says which language it is (the tab above is easy to lose track of once
   you have scrolled), carries the copy button where a reader expects it, and —
   the part that matters — gives the button a surface of its OWN. Floated on top
   of the code it was a white pill on cream that vanished on hover; here it can
   never collide with the box it belongs to. */
.nv-codewrap { border: 1px solid var(--nv-line); border-radius: var(--nv-r-ctl); overflow: hidden; }
.nv-codebar {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px 6px 12px;
    background: color-mix(in srgb, var(--nv-ink) 5%, var(--nv-white));
    border-bottom: 1px solid var(--nv-line);
}
.nv-codelang {
    font-size: 10.5px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
    color: var(--nv-ink-4);
}
.nv-codecopy {
    margin-inline-start: auto;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px; border-radius: var(--nv-r-pill);
    border: 1px solid var(--nv-line-2); background: var(--nv-white);
    color: var(--nv-ink-2); font-size: 11.5px; font-weight: 600;
    cursor: pointer; transition: background .14s ease, border-color .14s ease;
}
.nv-codecopy:hover { background: color-mix(in srgb, var(--nv-ink) 8%, var(--nv-white)); border-color: var(--nv-ink-5); }
.nv-codecopy i, .nv-codecopy svg { width: 13px; height: 13px; }
/* The box now owns the frame, so the <pre> drops its own or they double up. */
.nv-codewrap .nv-code { border: 0; border-radius: 0; margin: 0; }

/* ── Avatar as the way in to changing it ───────────────────────────────────
   The badge sits on the rim rather than over the face, so it never covers the
   photo it is offering to replace, and it carries the brand so it reads as a
   control instead of an ornament. It is 22px because it has to be a tap target
   on a phone without crowding a 68px avatar. */
.nv-avatarpick { position: relative; display: inline-flex; flex-shrink: 0; cursor: pointer; }
.nv-avatarpick-badge {
    position: absolute; inset-block-end: -2px; inset-inline-end: -2px;
    width: 22px; height: 22px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--nv-brand); color: var(--nv-on-brand);
    border: 2px solid var(--nv-white);
    transition: filter .14s ease;
}
.nv-avatarpick-badge i, .nv-avatarpick-badge svg { width: 11px; height: 11px; }
.nv-avatarpick:hover .nv-avatarpick-badge { filter: brightness(.92); }

/* ── Payment instructions, once a deposit is open ──────────────────────────
   scroll-margin-top clears the sticky top bar; the lit state is a two-second
   ring that says WHICH block just appeared, because the page did not navigate
   and something arriving silently at the bottom of a long page is the same as
   nothing arriving. It is removed again rather than left on: a permanent ring
   is decoration, and decoration stops meaning "look here". */
.nv-payinstr { scroll-margin-top: 92px; border-radius: var(--nv-r-card); transition: box-shadow .5s ease; }
.nv-payinstr-lit { box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv-brand) 55%, transparent); }
@media (prefers-reduced-motion: reduce) {
    .nv-payinstr { transition: none; }
}

/* Syntax colours. Applied by the highlighter in the API view, which only ever
   wraps existing text nodes — it cannot introduce markup, so the buyer's own
   API key inside the sample stays text. Each colour is mixed from the theme's
   ink so it lands on this palette instead of the usual editor primaries, and
   each is declared in BOTH modes because a token tuned for cream is unreadable
   on charcoal. */
.nv-hl-str { color: #8a5f00; }
.nv-hl-com { color: var(--nv-ink-5); font-style: italic; }
.nv-hl-key { color: #0b6b5e; font-weight: 600; }
.nv-hl-num { color: #7a3ba8; }
.nv-hl-url { color: #1f5fa8; }
html.dark .nv-hl-str { color: #e0b563; }
html.dark .nv-hl-com { color: var(--nv-ink-5); }
html.dark .nv-hl-key { color: #5fd2bd; }
html.dark .nv-hl-num { color: #c79bee; }
html.dark .nv-hl-url { color: #7db4ef; }

/* ══════════════════════════════════════════════════════════════════════════
   6 · RESPONSIVE
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1180px) {
    .nv-stats { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .nv-grid-23, .nv-grid-form, .nv-chatgrid, .nv-chatgrid-wide { grid-template-columns: minmax(0, 1fr); }

    /* Stacked, the inbox stops being an inbox: one column means the two panels
       SHARE the window's height instead of sitting side by side, so each gets
       half of it. Measured at 390px: 310px per panel, TWO of nine tickets in
       view and a 166px conversation. So below this width the cap is released
       and the PAGE scrolls again — which is what a phone does anyway: read the
       list, then the thread. The caps are desktop-only by nature, not by taste.
       The tabs stay a scrolling single line: that one is about the row's own
       height and is right at every width. */
    .nv-chatgrid, .nv-chatgrid-wide { height: auto; min-height: 0; }
    .nv-chatgrid > .nv-card { overflow: visible; }
    .nv-tklist { overflow-y: visible; }
    .nv-chat-body {
        overflow-y: visible;
        /* Back to the top: pinning bubbles to the bottom is what keeps them
           against the composer, and with no cap there is no bottom to pin to. */
        justify-content: flex-start;
        min-height: 300px;
    }

    /* The gateway rail needs no breakpoint of its own: it is one line at every
       width and the card basis decides how many of them are in view. The two
       grid-template rules that used to be here were dropped with the grid — a
       declaration for a display mode the element no longer has is a rule nobody
       can see doing nothing. */
}

@media (max-width: 1023px) {
    /* As a DRAWER the sidebar stops being "the part of the surface the card does
       not cover" and becomes a panel floating over the page, so it has to paint
       its own background again or the content shows straight through it.

       The breakpoint is 1023px and not 900 on purpose: it is the product's own
       `lg`, which is where the shell's Alpine state (`sideOpen`) and the burger
       the core ships already switch over. A second, different threshold would
       give a window width where the nav is a drawer and nothing opens it. */
    .nv-side { transform: translateX(-100%); box-shadow: var(--nv-shadow-md); background: var(--nv-side-bg); }
    html[dir='rtl'] .nv-side { transform: translateX(100%); }
    .nv-side[data-open='1'] { transform: none; }
    /* With no sidebar beside it the card takes the full width; the gutter stays,
       so the surface still frames it — which is what makes a phone read as the
       same design instead of a different one. */
    .nv-main { margin-inline: var(--nv-app-gutter); }
    /* Inside the drawer the active row is a normal pill again: there is no card
       to its inline end to merge with, and the two concave corners go with it or
       they paint card-coloured blobs onto the sidebar with nothing to bite. */
    .nv-side-item[aria-current='page'] {
        margin-inline-end: 0;
        padding-inline-end: 12px;
        border-radius: var(--nv-r-ctl);
    }
    .nv-side-item[aria-current='page']::before,
    .nv-side-item[aria-current='page']::after { content: none; }
    .nv-burger { display: grid; }
    /* The phone carries the same door on the bottom bar, so the header
       burger would be a second button for the one drawer. */
    html[data-theme='nativa'] .nv-burger { display: none; }
    html[data-theme='nativa'] .nv-tabbar {
        display: flex;
        position: fixed;
        z-index: 40;
        inset-inline: 0;
        bottom: 0;
        background: #0e0b16;
        border: 0;
        border-top: 1px solid #5c2e78;
        border-radius: 0;
        box-shadow: none;
        padding: 8px 6px calc(8px + env(safe-area-inset-bottom, 0px));
        gap: 0;
    }
    html[data-theme='nativa'] .nv-pull {
        height: 0;
        overflow: hidden;
        display: flex;
        align-items: flex-end;
        justify-content: center;
        flex: 0 0 auto;
        font-size: 12px;
        font-weight: 700;
        color: var(--nv-ink-4);
    }
    html[data-theme='nativa'] .nv-tabbar a,
    html[data-theme='nativa'] .nv-tabbar button {
        position: relative;
        flex: 1 1 0;
        min-width: 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 2px 6px;
        border: 0;
        background: transparent;
        color: var(--nv-side-text);
        font: inherit;
        font-size: 11px;
        font-weight: 650;
        line-height: 1.15;
        border-radius: 0;
        text-decoration: none;
    }
    html[data-theme='nativa'] .nv-tabbar [aria-current='page'],
    html[data-theme='nativa'] .nv-tabbar [aria-pressed='true'] {
        color: #ce6bff;
        background: transparent;
    }
    html[data-theme='nativa'] .nv-tabbar i,
    html[data-theme='nativa'] .nv-tabbar svg { width: 20px; height: 20px; }
    html[data-theme='nativa'] .nv-tabbar span {
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    html[data-theme='nativa'] .nv-tabbar-badge {
        position: absolute;
        top: 2px;
        inset-inline-end: 22%;
        min-width: 16px;
        height: 16px;
        padding: 0 4px;
        border-radius: 999px;
        background: var(--nv-bad);
        color: #fff;
        font-style: normal;
        font-size: 10px;
        font-weight: 700;
        line-height: 16px;
        text-align: center;
    }
    html[data-theme='nativa'] .nv-content {
        padding-bottom: calc(78px + env(safe-area-inset-bottom, 0px));
    }
    html[data-theme='nativa'] .nv-more {
        position: fixed;
        z-index: 30;
        inset: 0;
        display: flex;
        align-items: flex-end;
        padding: 72px 10px calc(76px + env(safe-area-inset-bottom, 0px));
    }
    html[data-theme='nativa'] .nv-more-veil {
        position: absolute;
        inset: 0;
        background: rgba(8, 4, 14, .62);
    }
    html[data-theme='nativa'] .nv-more-panel {
        position: relative;
        z-index: 1;
        width: 100%;
        max-height: 100%;
        overflow: auto;
        padding: 8px 12px 14px;
        border-radius: 22px;
        border: 1px solid #5c2e78;
        background: #1c1524;
        box-shadow: 0 0 0 1px rgba(189, 14, 220, .22), 0 24px 48px rgba(0, 0, 0, .45);
    }
    html[data-theme='nativa'] .nv-more-handle {
        display: block;
        width: 42px;
        height: 4px;
        margin: 4px auto 10px;
        border-radius: 999px;
        background: rgb(255 255 255 / .28);
    }
    html[data-theme='nativa'] .nv-more-head {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 2px 4px 12px;
    }
    html[data-theme='nativa'] .nv-more-ava {
        width: 42px;
        height: 42px;
        flex: 0 0 42px;
        background: #bd0edc;
        color: #fff;
        font-weight: 800;
    }
    html[data-theme='nativa'] .nv-more-who { min-width: 0; flex: 1; }
    html[data-theme='nativa'] .nv-more-who strong,
    html[data-theme='nativa'] .nv-more-who small {
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    html[data-theme='nativa'] .nv-more-who strong { font-size: 15px; color: #fff; }
    html[data-theme='nativa'] .nv-more-who small { margin-top: 2px; font-size: 12px; color: #b7b7b8; }
    html[data-theme='nativa'] .nv-more-x {
        width: 34px;
        height: 34px;
        flex: 0 0 34px;
        display: grid;
        place-items: center;
        border: 0;
        border-radius: 10px;
        background: rgb(255 255 255 / .08);
        color: #fff;
        cursor: pointer;
    }
    html[data-theme='nativa'] .nv-more-x svg,
    html[data-theme='nativa'] .nv-more-x i { width: 16px; height: 16px; }
    html[data-theme='nativa'] .nv-more-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 10px;
    }
    html[data-theme='nativa'] .nv-more-tile {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 8px;
        min-height: 92px;
        padding: 14px 8px;
        border-radius: 14px;
        border: 1px solid #5c2e78;
        background: #241a2e;
        color: #fff;
        font-size: 13px;
        font-weight: 650;
        line-height: 1.2;
        text-align: center;
    }
    html[data-theme='nativa'] .nv-more-tile i,
    html[data-theme='nativa'] .nv-more-tile svg { width: 22px; height: 22px; }
    html[data-theme='nativa'] .nv-more-tile[aria-current='page'] {
        color: #ce6bff;
        border-color: #ce6bff;
        box-shadow: 0 0 0 1px #bd0edc;
    }
    /* Support on a phone: the conversation is the screen. The ticket list
       follows it, and the composer stays above the bottom menu instead of
       sitting underneath it. */
    html[data-theme='nativa'] .nv-chatgrid,
    html[data-theme='nativa'] .nv-chatgrid-wide {
        display: flex;
        flex-direction: column;
        height: auto;
        min-height: 0;
    }
    html[data-theme='nativa'] .nv-chatgrid > .nv-chat {
        order: -1;
        flex: 0 0 auto;
        height: calc(100dvh - var(--nv-top-h) - 268px - env(safe-area-inset-bottom, 0px));
        min-height: 320px;
        overflow: hidden;
    }
    html[data-theme='nativa'] .nv-chatgrid > .nv-chat .nv-chat-body {
        overflow-y: auto;
        flex: 1;
        min-height: 0;
        justify-content: flex-end;
    }
    html[data-theme='nativa'] .nv-chatgrid .nv-msg { max-width: 92%; }
    .nv-backdrop { position: fixed; inset: 0; z-index: 35; background: rgba(0, 0, 0, .45); }
    .nv-grid-2, .nv-grid-3, .nv-qa { grid-template-columns: minmax(0, 1fr); }
}
@media (min-width: 1024px) {
    html[data-theme='nativa'] .nv-more { display: none !important; }
}

@media (max-width: 767px) {
    /* On a phone the bar carries the BRAND and the DOOR, and nothing else. The
       tools are not hidden — they move into the drawer, and that second half is
       what makes hiding them legitimate rather than a menu with no way in. */
    .nv-search { display: none; }
    .nv-top-hide { display: none; }
    /* Both win by SPECIFICITY (0,2,0) and not by order. Their off switches live
       further down the file, so an equally specific selector here would lose the
       cascade no matter that it sits inside a media query — which is exactly
       what happened once: the six controls the bar gives up landed in a block
       that never drew itself, and a phone had no balance, no language and no
       theme toggle anywhere on the screen. A media query is not a priority; it
       is only a condition. check-cascade.php now fails the build over it. */
    .nv-shell .nv-acct-btn { display: grid; }
    .nv-shell .nv-acct { display: block; }
}

/* Phone: these list pages read as an app. Filter chips wrap onto as many
   lines as they need, and each table row becomes a card so a wide ledger
   never slides sideways under the thumb. */
@media (max-width: 720px) {
    html[data-theme='nativa'] .nv-toolbar { align-items: stretch; }
    html[data-theme='nativa'] .nv-tabswrap {
        flex: 1 1 100%;
        max-width: 100%;
        overflow: visible;
    }
    html[data-theme='nativa'] .nv-tabs {
        display: flex;
        flex-wrap: wrap;
        width: 100%;
        border-radius: 18px;
    }
    html[data-theme='nativa'] .nv-tab { flex: 1 1 auto; justify-content: center; }
    html[data-theme='nativa'] .nv-toolbar .nv-tb-right,
    html[data-theme='nativa'] .nv-toolbar .nv-field-search {
        width: 100%;
        max-width: none;
        margin-inline-start: 0;
        flex: 1 1 100%;
    }
    html[data-theme='nativa'] .nv-tktabswrap::before,
    html[data-theme='nativa'] .nv-tktabswrap::after { content: none; }
    html[data-theme='nativa'] .nv-tktabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        padding-inline: 14px;
    }

    html[data-theme='nativa'] .nv-mlist { overflow-x: clip; }
    html[data-theme='nativa'] .nv-mlist .nv-table { min-width: 0; }
    html[data-theme='nativa'] .nv-mlist thead { display: none; }
    html[data-theme='nativa'] .nv-mlist tbody,
    html[data-theme='nativa'] .nv-mlist tr,
    html[data-theme='nativa'] .nv-mlist td { display: block; width: auto; }
    html[data-theme='nativa'] .nv-mlist tr {
        padding: 12px 14px 6px;
        border-bottom: 1px solid var(--nv-line);
    }
    html[data-theme='nativa'] .nv-mlist tbody tr:last-child { border-bottom: 0; }
    html[data-theme='nativa'] .nv-mlist td {
        display: flex;
        align-items: flex-start;
        justify-content: space-between;
        gap: 12px;
        padding: 7px 0;
        border: 0;
        min-width: 0;
        text-align: end;
        white-space: normal;
        overflow-wrap: anywhere;
    }
    html[data-theme='nativa'] .nv-mlist td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        max-width: 46%;
        text-align: start;
        font-size: 11px;
        font-weight: 700;
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--nv-ink-5);
    }
    html[data-theme='nativa'] .nv-mlist td.nv-m-title,
    html[data-theme='nativa'] .nv-mlist td[colspan] {
        display: block;
        text-align: start;
        min-width: 0;
    }
    html[data-theme='nativa'] .nv-mlist td.nv-m-title::before,
    html[data-theme='nativa'] .nv-mlist td[colspan]::before { content: none; }
    html[data-theme='nativa'] .nv-mlist td[colspan] { text-align: center; padding: 8px 0 18px; }
    html[data-theme='nativa'] .nv-mlist .nv-t-name { min-width: 0; }
    html[data-theme='nativa'] .nv-mlist .nv-t-num,
    html[data-theme='nativa'] .nv-mlist .nv-t-nowrap { white-space: normal; text-align: end; }
    html[data-theme='nativa'] .nv-mlist .nv-actions { justify-content: flex-end; }
    html[data-theme='nativa'] .nv-mlist .nv-cell-flex { justify-content: flex-end; }
    html[data-theme='nativa'] .nv-mlist td.nv-m-title .nv-cell-flex { justify-content: flex-start; }
}

@media (max-width: 560px) {
    .nv-stats { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
    .nv-stat { gap: 10px; padding: 12px; }
    .nv-stat-ico { width: 36px; height: 36px; border-radius: 11px; }
    .nv-stat-val { font-size: 18px; }
    /* No breakpoint for the rail: the shrink floor above already leaves a second
       card peeking at 390px, and a phone-only width would be a second number
       saying the same thing in a place nobody looks. */
    .nv-content { padding: 18px 14px 34px; }
    .nv-content > footer { margin-inline: -14px; }
    .nv-top { padding: 0 13px; gap: 7px; }
    .nv-balance { padding-inline: 10px; font-size: 12.5px; }
}

/* ── THE ACCOUNT SHEET (phone) ─────────────────────────────────────────────
   The right-hand half of the phone layout: the drawer on the left answers
   "where do I go", this answers "who am I and what do I have". Opening from
   the opposite edge is what keeps the two gestures from meaning the same
   thing, and `inset-inline-end` gets Arabic right without a second rule.

   Both switches are OFF here and ON inside the phone media query, which is
   above this line and carries `.nv-shell` so it outranks these two rather
   than racing them. Never reorder to fix a cascade: the next edit undoes it. */
.nv-acct { display: none; position: fixed; inset: 0; z-index: 60; }
.nv-acct-btn { display: none; flex-shrink: 0; }

.nv-acct-veil { position: absolute; inset: 0; background: rgba(0, 0, 0, .5); }

.nv-acct-panel {
    position: absolute; inset-block: 0; inset-inline-end: 0;
    width: min(330px, 88vw);
    display: flex; flex-direction: column; gap: 14px;
    padding: 16px 16px calc(16px + env(safe-area-inset-bottom));
    background: var(--nv-side-bg); color: var(--nv-side-text);
    overflow-y: auto; overscroll-behavior: contain;
    box-shadow: -18px 0 46px rgba(0, 0, 0, .34);
}

/* Slides in from the same edge it is pinned to. A logical translate, so in
   Arabic it arrives from the left along with everything else.

   `-slide-in/-slide-out` and not `-in/-out`: the first spelling of this was
   `.nv-acct-out`, which is ALSO the sign-out button at the foot of the sheet —
   so the button quietly inherited the panel's exit transform and rendered 298px
   off the right edge of its own container, present in the DOM and not on the
   screen. Within one package a class prefix is a NAMESPACE; two meanings for
   one name is a defect waiting for whoever adds the next rule. */
.nv-acct-anim     { transition: transform .22s ease, opacity .22s ease; }
.nv-acct-slide-in  { transform: translateX(0); opacity: 1; }
.nv-acct-slide-out { transform: translateX(100%); opacity: .4; }
[dir="rtl"] .nv-acct-slide-out { transform: translateX(-100%); }

.nv-acct-head { display: flex; align-items: center; gap: 11px; min-width: 0; }
.nv-acct-ava { width: 42px; height: 42px; font-size: 15px; flex-shrink: 0; }
.nv-acct-who { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.nv-acct-who strong { font-size: 14.5px; font-weight: 700; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nv-acct-who small { font-size: 11.5px; color: var(--nv-side-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nv-acct-head .nv-icon-btn { background: var(--nv-side-card); border-color: var(--nv-side-line); color: var(--nv-side-text); flex-shrink: 0; }

/* The headline of the sheet, not a row in it: checking the balance is what a
   customer opens their panel to do. The whole card is the way to top up, so
   the figure and the action cannot end up pointing at different places. */
.nv-acct-bal {
    display: grid; gap: 3px;
    background: var(--nv-side-card); border: 1px solid var(--nv-side-line);
    border-radius: var(--nv-r-lg, 16px); padding: 13px 15px;
}
.nv-acct-bal-k { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--nv-side-muted); }
.nv-acct-bal-v { font-size: 25px; font-weight: 800; letter-spacing: -.5px; line-height: 1.15; }
.nv-acct-bal-cta {
    margin-top: 7px; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    background: var(--nv-side-chip-bg); color: var(--nv-side-chip-ink);
    border-radius: var(--nv-r-pill); padding: 9px 14px;
    font-size: 13px; font-weight: 700;
}
.nv-acct-bal-cta i, .nv-acct-bal-cta svg { width: 15px; height: 15px; }

.nv-acct-rows { display: flex; flex-direction: column; gap: 2px; }
.nv-acct-row {
    display: flex; align-items: center; gap: 11px; width: 100%;
    padding: 11px 12px; border-radius: 12px;
    background: transparent; border: 0; text-align: start;
    font-size: 13.5px; font-weight: 600; color: var(--nv-side-text); cursor: pointer;
}
.nv-acct-row:hover { background: var(--nv-side-hover); }
.nv-acct-row i, .nv-acct-row svg { width: 17px; height: 17px; flex-shrink: 0; }
.nv-acct-row > span:first-of-type { flex: 1; min-width: 0; }
.nv-acct-row-go { margin-inline-start: auto; opacity: .5; }
.nv-acct-row-tag {
    margin-inline-start: auto; flex-shrink: 0;
    font-size: 11px; font-weight: 700; color: var(--nv-side-muted);
    background: var(--nv-side-card); border: 1px solid var(--nv-side-line);
    border-radius: var(--nv-r-pill); padding: 3px 9px;
}

/* Codes in a row rather than a drop-down: a menu that opens another menu on a
   phone is one tap too many, and the list is short. */
.nv-acct-langs { display: grid; gap: 8px; padding: 2px 12px 0; }
.nv-acct-langs-k { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--nv-side-muted); }
.nv-acct-langs-v { display: flex; gap: 6px; flex-wrap: wrap; }
.nv-acct-lang {
    padding: 6px 12px; border-radius: var(--nv-r-pill);
    border: 1px solid var(--nv-side-line); background: var(--nv-side-card);
    font-size: 12px; font-weight: 600; color: var(--nv-side-text);
}
.nv-acct-lang-on { background: var(--nv-side-chip-bg); color: var(--nv-side-chip-ink); }

.nv-acct-outwrap { margin-top: auto; padding-top: 4px; }
.nv-acct-out {
    display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
    padding: 12px; border-radius: var(--nv-r-pill);
    background: var(--nv-side-card); border: 1px solid var(--nv-side-line);
    font-size: 13.5px; font-weight: 700; color: var(--nv-side-text); cursor: pointer;
}
/* The drawer's own sign-out ink, not a danger red. Measured: the red reads
   3.16:1 on this surface — the operator's brand is the background here, so a
   colour chosen against neutral paper has no guarantee on it, and signing out
   is not a destructive action that needs one. */
.nv-acct-out i, .nv-acct-out svg { width: 16px; height: 16px; }

/* ══════════════════════════════════════════════════════════════════════════
   7 · SHELL FURNITURE
   ══════════════════════════════════════════════════════════════════════════
   The pieces the shell draws around the navigation. They live after the media
   queries for the same reason the account sheet does: each one is declared once
   here and only its VISIBILITY changes by width, so there is exactly one place
   that says what it looks like — and the query that flips them carries a
   container, so it outranks these lines instead of racing them.
   ────────────────────────────────────────────────────────────────────────── */

/* The help card at the foot of the surface. It states NOTHING — no reply time,
   no hours: a promise about the operator's support desk is theirs to make, and
   the portal has no field for them to make it in, so the design carries the
   invitation and not the claim. */
.nv-side-help {
    margin: 8px 12px 12px;
    background: var(--nv-side-card);
    border: 1px solid var(--nv-side-line);
    border-radius: 14px;
    padding: 12px;
    text-align: center;
}
.nv-side-help-ico {
    width: 34px; height: 34px; margin: 0 auto 8px;
    border-radius: 50%;
    background: var(--nv-side-chip-bg); color: var(--nv-side-chip-ink);
    display: grid; place-items: center;
}
.nv-side-help-ico i, .nv-side-help-ico svg { width: 17px; height: 17px; }
.nv-side-help h4 { font-size: 13px; font-weight: 600; color: var(--nv-side-text); margin-bottom: 9px; }
.nv-side-cta {
    display: block;
    background: var(--nv-side-chip-bg); color: var(--nv-side-chip-ink);
    border-radius: var(--nv-r-pill);
    padding: 8px 12px;
    font-size: 12.5px; font-weight: 600;
}
.nv-side-cta:hover { filter: brightness(1.2); }

/* The brand in the TOP BAR is phone-only: on a desktop the surface carries it,
   and repeating it would put the same logo twice on one screen. */
.nv-top-brand { display: none; align-items: center; gap: 9px; min-width: 0; flex-shrink: 1; }
.nv-top-brand-name { font-weight: 600; font-size: 14.5px; letter-spacing: -.2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nv-top-tools { display: flex; align-items: center; gap: 9px; min-width: 0; }

@media (max-width: 767px) {
    /* The bar carries FOUR things and no more: the door (left), the brand, the
       bell and the account button (right). The bell is not one more tool — it
       is the one control that says something happened, and a badge has to be
       countable without opening anything, which is the whole point of a badge.
       Everything else lives in the account sheet, and that second half is what
       makes hiding it legitimate rather than a menu with no way in. */
    .nv-top-brand { display: flex; }
}

/* ══════════════════════════════════════════════════════════════════════════
   8 · SCREEN VOCABULARY
   ══════════════════════════════════════════════════════════════════════════
   Everything below is used by exactly one or two screens, which is why it is
   here rather than among the primitives. check-portal.php asserts both
   directions — a class used and not declared, and a class declared and unused —
   so this section cannot quietly grow a rule nobody draws. That second
   direction is not tidiness: a finished, dark-mode-ready `.rf-imp-netall` sat
   in the product for versions with no Blade drawing the button it belonged to,
   and customers stayed trapped in one network because of it.
   ────────────────────────────────────────────────────────────────────────── */

/* ── A field the server rejected ──────────────────────────────────────────
   The message is `.nv-err`; this is the box it belongs to. Separate classes on
   purpose: a form that colours the border and prints nothing tells the customer
   something is wrong and not what. */
.nv-input-err,
.nv-input-err:focus {
    border-color: var(--nv-bad);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv-bad) 22%, transparent);
}

/* ── The service picker on New Order ──────────────────────────────────────
   Its own panel and not `.nv-searchpop`: that one hangs under the top bar and
   is capped at the bar's width, while this one is as wide as the field it
   belongs to and has to survive being the last thing in a card. */
.nv-svcpop {
    position: absolute; top: calc(100% + 6px);
    inset-inline: 0; z-index: 60;
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-card);
    box-shadow: var(--nv-shadow-md);
    overflow: hidden auto;
    max-height: 340px;
}
/* The row the customer is already on. A border and not only a fill: on the
   warm paper of this design a tint alone is a difference of two percent. */
.nv-sr-active {
    background: var(--nv-soft);
    box-shadow: inset 3px 0 0 var(--nv-brand);
}

/* ── The chart tooltip on Statistics ──────────────────────────────────────
   The layout lives here rather than in a style attribute because the node
   carries `x-show`, and Alpine reveals by REMOVING the inline `display` — an
   arrangement written inline is one Alpine can silently take apart. Flipping is
   a transform rather than a second set of coordinates: the point it belongs to
   has not moved, only the side the label hangs from. */

/* This one declaration is what keeps the tooltip on the chart. An absolutely
   positioned box is laid out against the padding box of its nearest POSITIONED
   ancestor, and if it has none it resolves against the page instead — silently,
   with the rule sitting correctly in the stylesheet the whole time. Every box
   between the tooltip and <body> is static, so without this the label for a
   September data point was drawn over the sidebar, a couple of hundred pixels
   from the dot it described.

   It belongs on a wrapper with NO padding of its own, never on .nv-card-pad:
   the coordinates are measured from the svg's corner, and the card's 18px of
   padding would push the origin 18px away from it in both axes. */
.nv-chartwrap { position: relative; }

.nv-tip {
    position: absolute;
    z-index: 10;
    pointer-events: none;
    white-space: nowrap;
    min-width: 100px;
    padding: 8px 12px;
    border-radius: 9px;
    background: var(--nv-chip-ink);
    color: var(--nv-on-chip-ink);
    font-size: 12.5px;
}
.nv-tip.nv-is-flip { transform: translateX(-100%); }
/* The one place the chip pair is WRONG in the dark. A tooltip is a raised
   surface, not a call to action: with the chip now carrying the brand, a solid
   yellow label would land on the chart every time the pointer crosses it —
   the loudest thing on a page whose point is a quiet line. Raised surface with
   the card's own ink instead, which is what "floating above" reads as here. */
html.dark[data-theme='nativa'] .nv-tip {
    background: var(--nv-soft);
    color: var(--nv-ink);
    border: 1px solid var(--nv-line-2);
}

/* ── A modal this design owns ─────────────────────────────────────────────
   The product's own `<x-admin.modal>` is used wherever the modal is driven by a
   Livewire property, and it stays the product's. These are for the two screens
   whose detail panel is pure Alpine (an order row, a service row): opening them
   must not cost a round trip, so there is no property for the product's
   component to bind to.

   The backdrop centres in a CLASS. With `x-show` on the same node an inline
   `display:flex` is removed the moment Alpine reveals it, and the card lands in
   the top-left corner — the product has that bug written down twice. */
.nv-modal-backdrop {
    position: fixed; inset: 0; z-index: 80;
    display: flex; align-items: center; justify-content: center;
    padding: 20px;
    background: rgba(0, 0, 0, .55);
    backdrop-filter: blur(4px);
    overflow-y: auto;
}
.nv-modal {
    width: min(560px, 94vw);
    max-height: calc(100dvh - 40px);
    display: flex; flex-direction: column;
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    border-radius: 20px;
    box-shadow: var(--nv-shadow-md);
    overflow: hidden;
}
.nv-modal-md { width: min(680px, 94vw); }
/* The header is a TINTED BAND, not a line of text with a rule under it.
   --nv-soft is the theme's brand wash and it flips with the mode on its own, so
   the dark layer needs no second rule. It is the same band the product's own
   dialog wears (see the .rf-modal-header block further down): these dialogs and
   that one are the same object to a customer, and two of them answering
   differently is what reads as a half-finished product. */
.nv-modal-head {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 20px;
    background: var(--nv-soft);
    border-bottom: 1px solid var(--nv-line);
    color: var(--nv-ink);
}
.nv-modal-title {
    font-size: 15.5px; font-weight: 700; letter-spacing: -.2px; min-width: 0;
    color: var(--nv-ink);
    /* A long announcement title must not push the ✕ off the band: in these
       dialogs it is the only control in the header. */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nv-modal-head .nv-act {
    margin-inline-start: auto;
    flex: 0 0 auto;
    width: 32px; height: 32px;
    border-radius: 50%;
    border: 1px solid var(--nv-line);
    background: var(--nv-white);
    color: var(--nv-ink-3);
}
.nv-modal-head .nv-act:hover {
    background: var(--nv-bad-bg);
    border-color: var(--nv-bad);
    color: var(--nv-bad);
}
/* min-height: 0 so the body, not the card, is what scrolls — without it a long
   order detail grows the card past the viewport and the footer leaves the
   screen with no way back to it. */
.nv-modal-body { padding: 18px 20px; overflow-y: auto; min-height: 0; }
.nv-modal-foot {
    display: flex; align-items: center; justify-content: flex-end; gap: 9px;
    padding: 13px 20px;
    background: var(--nv-paper-2);
    border-top: 1px solid var(--nv-line);
    flex-wrap: wrap;
}
/* The date line at the end of an announcement. It was an inline style on the
   <p>; here because a value repeated in markup is one nobody can restyle. */
.nv-modal-date { margin-top: 16px; font-size: 11.5px; color: var(--nv-ink-5); }

/* Order detail: a hero, the charge, then three figures. The shared modal
   shell stays as it is; only this body is dressed. */
html[data-theme='nativa'] .nv-od { padding: 0; }
html[data-theme='nativa'] .nv-od-hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 18px 20px 16px;
    color: #fff;
    background:
        radial-gradient(320px 160px at 100% 0%, rgba(232, 121, 249, .85), transparent 62%),
        linear-gradient(110deg, #120818 0%, #3a1468 100%);
}
html[data-theme='nativa'] .nv-od-k {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: rgb(255 255 255 / .72);
}
html[data-theme='nativa'] .nv-od-id {
    margin-top: 4px;
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: -.04em;
    line-height: 1;
}
html[data-theme='nativa'] .nv-od-svc {
    margin-top: 8px;
    font-size: 14px;
    font-weight: 650;
    color: #f4b2ff;
}
html[data-theme='nativa'] .nv-od-hero .nv-badge { flex: 0 0 auto; margin-top: 2px; }
html[data-theme='nativa'] .nv-od-charge {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--nv-line);
}
html[data-theme='nativa'] .nv-od-charge span,
html[data-theme='nativa'] .nv-od-stats span,
html[data-theme='nativa'] .nv-od-row span {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--nv-ink-5);
}
html[data-theme='nativa'] .nv-od-charge strong {
    font-size: 1.45rem;
    font-weight: 800;
    letter-spacing: -.03em;
    color: var(--nv-ink);
}
html[data-theme='nativa'] .nv-od-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    padding: 14px 20px 4px;
}
html[data-theme='nativa'] .nv-od-stats div {
    min-width: 0;
    padding: 10px 10px 8px;
    border-radius: 12px;
    border: 1px solid var(--nv-line);
    background: var(--nv-paper);
}
html[data-theme='nativa'] .nv-od-stats strong {
    display: block;
    margin-top: 4px;
    font-size: 1.05rem;
    font-weight: 800;
    color: var(--nv-ink);
}
html[data-theme='nativa'] .nv-od-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 20px 0;
}
html[data-theme='nativa'] .nv-od-row strong { font-size: 13.5px; font-weight: 700; color: var(--nv-ink); }
html[data-theme='nativa'] .nv-od-row a { overflow-wrap: anywhere; }
html[data-theme='nativa'] .nv-od-end { padding-bottom: 16px; }
html[data-theme='nativa'] .nv-od .nv-note { margin: 0 20px 16px; }
@media (max-width: 640px) {
    html[data-theme='nativa'] .nv-od-id { font-size: 1.6rem; }
    html[data-theme='nativa'] .nv-od-charge strong { font-size: 1.25rem; }
html[data-theme='nativa'] .nv-od-stats span {
    letter-spacing: .04em;
    font-size: 10px;
    white-space: nowrap;
}
}

/* ── The four figures of a service ────────────────────────────────────────
   Auto-fit rather than a fixed four: at the width of a phone four columns turn
   a rate into two characters and an ellipsis. */
.nv-metagrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 10px; }
.nv-metatile {
    background: var(--nv-paper-2);
    border: 1px solid var(--nv-line);
    border-radius: 12px;
    padding: 11px 13px;
    min-width: 0;
}
.nv-metatile-lbl { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--nv-ink-5); font-weight: 600; }
.nv-metatile-val { font-size: 15px; font-weight: 650; margin-top: 3px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE TICKET COMPOSER, THE FILE CHIP AND THE PROSE BLOCK
   ═══════════════════════════════════════════════════════════════════════════
   Every rule below is a REPAINT of a control the product already draws — the
   emoji picker, the link popover and the GIF picker all belong to the core's
   own `rfTicketComposer` Alpine component, which this package does not own and
   must not reimplement (PORTAL-CONTRACT.md §1). The geometry is copied from the
   core's sheet (resources/css/app.css, `.rf-ticket-popover` and friends) rather
   than re-guessed, so a grid of emoji stays seven wide and a GIF tile keeps its
   16/9 — a picker that reflows differently here would read as two products.

   The one thing that is NOT copied is the colour: `--color-*` is bridged at the
   top of this file, so the same numbers land in Nativa's ink and in the panel's
   own brand.
   ───────────────────────────────────────────────────────────────────────── */

/* The composer is `position: relative` and nothing else: the three popovers
   hang off it with the offsets the markup writes inline (`bottom: calc(100% +
   8px)`), so this element is their containing block. It must NOT grow a
   `transform`, `filter` or `backdrop-filter` — any of those would make it the
   containing block of a `fixed` child too, which is the trap that put the
   credential tooltip 211px above its own icon. */
html[data-theme='nativa'] .nv-composer-wrap { position: relative; }

/* ── Popover shell, shared by emoji / link / GIF ─────────────────────────── */
html[data-theme='nativa'] .nv-pop {
    position: absolute;
    z-index: 50;
    border-radius: 12px;
    border: 1px solid var(--nv-line);
    background: var(--nv-paper);
    box-shadow: var(--nv-shadow-md);
    min-width: 280px;
    overflow: hidden;
}

/* ── Emoji ───────────────────────────────────────────────────────────────── */
html[data-theme='nativa'] .nv-emoji-tabs { display: flex; border-bottom: 1px solid var(--nv-line); }
html[data-theme='nativa'] .nv-emoji-tab {
    flex: 1;
    padding: 6px 4px;
    font-size: 16px;
    background: transparent;
    border: none;
    cursor: pointer;
    opacity: .5;
    transition: opacity .15s;
}
html[data-theme='nativa'] .nv-emoji-tab:hover { opacity: .8; }
/* The active tab is marked by `aria-selected`, which the markup already sets —
   so the state is announced to a screen reader and painted from the SAME fact,
   instead of a second class that can disagree with it. */
html[data-theme='nativa'] .nv-emoji-tab[aria-selected='true'] {
    opacity: 1;
    border-bottom: 2px solid var(--brand, #f5c400);
}
html[data-theme='nativa'] .nv-emoji-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    padding: 6px;
    max-height: 200px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--nv-line) transparent;
}
html[data-theme='nativa'] .nv-emoji-btn {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border-radius: 8px;
    font-size: 18px;
    background: transparent;
    border: none;
    cursor: pointer;
    transition: background .1s;
}
html[data-theme='nativa'] .nv-emoji-btn:hover { background: var(--nv-paper-2); }

/* ── GIF ─────────────────────────────────────────────────────────────────── */
html[data-theme='nativa'] .nv-gif-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 4px;
    padding: 6px;
    max-height: 240px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--nv-line) transparent;
}
html[data-theme='nativa'] .nv-gif-item {
    aspect-ratio: 16 / 9;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    background: var(--nv-paper-2);
    transition: border-color .15s, transform .1s;
}
html[data-theme='nativa'] .nv-gif-item:hover {
    border-color: var(--brand, #f5c400);
    transform: scale(1.03);
}

/* The invisible sheet that closes whichever popover is open. It is a plain
   backdrop with NO blur on purpose: `backdrop-filter` here would turn this into
   the containing block of anything fixed inside the composer. */
html[data-theme='nativa'] .nv-overlay { position: fixed; inset: 0; z-index: 40; }

/* ── The active state of a composer icon ─────────────────────────────────── */
html[data-theme='nativa'] .nv-icon-btn-active {
    background: color-mix(in srgb, var(--brand, #f5c400) 22%, transparent);
    color: var(--nv-ink);
}

/* ── File chip: the attachment, in the composer and in the thread ────────── */
html[data-theme='nativa'] .nv-chip-file {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 10px;
    border-radius: 8px;
    border: 1px solid var(--nv-line);
    background: var(--nv-paper-2);
    font-size: 12px;
    color: var(--nv-ink-4);
    text-decoration: none;
    max-width: 100%;
    /* A file the buyer's client uploaded can be named anything; without this a
       forty-word filename pushes the remove button out of the composer. */
    overflow-wrap: anywhere;
    transition: border-color .15s, color .15s;
}
html[data-theme='nativa'] .nv-chip-file:hover { border-color: var(--brand, #f5c400); color: var(--nv-ink); }
html[data-theme='nativa'] .nv-chip-thumb {
    height: 34px; width: 34px;
    border-radius: 6px;
    object-fit: cover;
    flex-shrink: 0;
}
html[data-theme='nativa'] .nv-chip-file-x {
    margin-inline-start: 2px;
    padding: 0 2px;
    font-size: 14px; font-weight: 700; line-height: 1;
    color: var(--nv-ink-5);
    background: none; border: none;
    border-radius: 4px;
    cursor: pointer;
}
html[data-theme='nativa'] .nv-chip-file-x:hover { color: var(--nv-bad); }

/* ── Upload progress ─────────────────────────────────────────────────────── */
html[data-theme='nativa'] .nv-upbar {
    height: 3px;
    border-radius: 2px;
    background: var(--nv-line);
    overflow: hidden;
}
html[data-theme='nativa'] .nv-upbar-fill {
    height: 100%;
    width: 60%;
    border-radius: 2px;
    background: var(--brand, #f5c400);
    animation: nv-upload-pulse 1.2s ease-in-out infinite alternate;
}
@keyframes nv-upload-pulse {
    from { opacity: .6; width: 20%; }
    to   { opacity: 1;  width: 80%; }
}
/* An indeterminate bar that never stops is a moving distraction for someone who
   set the system preference for less motion; it becomes a static bar, which
   still says "busy" because it only exists while the upload is in flight. */
@media (prefers-reduced-motion: reduce) {
    html[data-theme='nativa'] .nv-upbar-fill { animation: none; width: 60%; }
}

/* ── A plain horizontal row ──────────────────────────────────────────────── */
/* Wraps on purpose: these rows carry a chip, a date and an action, and at phone
   width a nowrap row is what pushes the action off the card. */
html[data-theme='nativa'] .nv-row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; min-width: 0; }

/* ── The description of a service, inside its modal ──────────────────────── */
html[data-theme='nativa'] .nv-desc-lbl {
    display: block;
    font-size: 10.5px; font-weight: 600;
    text-transform: uppercase; letter-spacing: .06em;
    color: var(--nv-ink-5);
    margin-bottom: 6px;
}
html[data-theme='nativa'] .nv-desc {
    background: var(--nv-paper-2);
    border: 1px solid var(--nv-line);
    border-radius: 12px;
    padding: 12px 14px;
    /* Imported catalogues carry the whole delivery policy in this field, so it
       is capped and scrolls rather than pushing the modal's buttons off screen. */
    max-height: 190px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--nv-line) transparent;
}
html[data-theme='nativa'] .nv-desc-text {
    font-size: 13px;
    line-height: 1.65;
    color: var(--nv-ink-3);
    /* The provider writes this text with newlines and no markup; without this
       the whole policy collapses into one paragraph. */
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* ── Prose written by the operator (a news post) ─────────────────────────── */
/* The reading measure is NOT capped here: this block already sits inside a
   modal that is narrower than a line of 90 characters, so a second cap would
   only leave a gutter inside a gutter. */
html[data-theme='nativa'] .nv-prose { font-size: 14px; line-height: 1.72; color: var(--nv-ink-3); }
html[data-theme='nativa'] .nv-prose > :first-child { margin-top: 0; }
html[data-theme='nativa'] .nv-prose > :last-child { margin-bottom: 0; }
html[data-theme='nativa'] .nv-prose p { margin: 0 0 14px; text-wrap: pretty; }
html[data-theme='nativa'] .nv-prose h2,
html[data-theme='nativa'] .nv-prose h3,
html[data-theme='nativa'] .nv-prose h4 { color: var(--nv-ink); font-weight: 700; line-height: 1.3; margin: 22px 0 9px; }
html[data-theme='nativa'] .nv-prose h2 { font-size: 18px; }
html[data-theme='nativa'] .nv-prose h3 { font-size: 16px; }
html[data-theme='nativa'] .nv-prose h4 { font-size: 14.5px; }
html[data-theme='nativa'] .nv-prose ul,
html[data-theme='nativa'] .nv-prose ol { margin: 0 0 14px; padding-inline-start: 22px; }
html[data-theme='nativa'] .nv-prose li { margin-bottom: 5px; }
html[data-theme='nativa'] .nv-prose a { color: var(--nv-ink); text-decoration: underline; text-underline-offset: 2px; }
html[data-theme='nativa'] .nv-prose strong { font-weight: 650; color: var(--nv-ink); }
html[data-theme='nativa'] .nv-prose blockquote {
    margin: 0 0 14px;
    padding: 2px 0 2px 14px;
    border-inline-start: 3px solid var(--brand, #f5c400);
    color: var(--nv-ink-4);
}
html[data-theme='nativa'] .nv-prose img { max-width: 100%; height: auto; border-radius: 10px; }
/* A pasted table is the one thing in operator prose that can be wider than the
   modal; it scrolls inside its own box instead of widening the card. */
html[data-theme='nativa'] .nv-prose table { display: block; overflow-x: auto; max-width: 100%; border-collapse: collapse; }
html[data-theme='nativa'] .nv-prose td,
html[data-theme='nativa'] .nv-prose th { border: 1px solid var(--nv-line); padding: 6px 9px; font-size: 13px; }

/* ================================================================
   NEW ORDER — two-column composition
   ================================================================
   Prefix note: in a theme a class prefix is a NAMESPACE and the sheet is one
   file, so `nv-no-` means NEW ORDER here and nowhere else. It was checked
   against every other part before being used (0 prior matches).

   The brand-coloured pieces read `nv-btn-primary` / `--brand`, never a literal
   green: the accent in the reference mockup is THAT panel's brand, and the
   colour on this screen belongs to whoever bought the product.
   ================================================================ */

html[data-theme='nativa'] .nv-no {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
html[data-theme='nativa'] .nv-no-wallet {
    position: relative;
    z-index: 4;
    overflow: visible;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 20px;
    min-height: 196px;
    padding: 24px 22px 16px;
    border: 1px solid #7a3d9a;
    color: #fff;
    background: transparent;
    box-shadow: 0 0 0 1px rgba(189, 14, 220, .28), 0 22px 48px rgba(60, 0, 90, .28);
}
html[data-theme='nativa'] .nv-no-wallet.is-open { z-index: 50; }
html[data-theme='nativa'] .nv-no-wallet-bg {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    overflow: hidden;
    pointer-events: none;
    background:
        radial-gradient(520px 240px at 92% 0%, #e879f9 0%, rgba(189, 14, 220, .15) 42%, transparent 68%),
        radial-gradient(280px 180px at 62% 130%, rgba(124, 20, 180, .55), transparent 70%),
        linear-gradient(105deg, #100816 0%, #2a1044 48%, #6d14a8 100%);
}
html[data-theme='nativa'] .nv-no-wallet-bg::before,
html[data-theme='nativa'] .nv-no-wallet-bg::after {
    content: '';
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
}
html[data-theme='nativa'] .nv-no-wallet-bg::before {
    width: 240px; height: 240px;
    inset-inline-end: 6%; top: -90px;
    background: radial-gradient(circle, #f0abfc 0%, #bd0edc 38%, transparent 70%);
}
html[data-theme='nativa'] .nv-no-wallet-bg::after {
    width: 160px; height: 160px;
    inset-inline-start: 46%; bottom: -90px;
    background: rgb(255 255 255 / .07);
}
html[data-theme='nativa'] .nv-no-wallet-copy {
    position: relative;
    z-index: 1;
}
html[data-theme='nativa'] .nv-no-wallet-lbl {
    font-size: 11px;
    color: rgb(255 255 255 / .78);
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
}
html[data-theme='nativa'] .nv-no-wallet-val {
    margin-top: 8px;
    font-size: 2.65rem;
    font-weight: 800;
    letter-spacing: -.04em;
    color: #fff;
    line-height: 1;
}
html[data-theme='nativa'] .nv-no-wallet-actions {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr);
    align-items: center;
    gap: 12px;
    padding-top: 14px;
    border-top: 1px solid rgb(255 255 255 / .22);
}
html[data-theme='nativa'] .nv-no-wallet-sep {
    width: 1px;
    height: 26px;
    justify-self: center;
    background: rgb(255 255 255 / .45);
}
html[data-theme='nativa'] .nv-no-wallet .nv-drop { width: 100%; min-width: 0; }
html[data-theme='nativa'] .nv-no-wallet .nv-menu {
    z-index: 60;
    color: var(--nv-ink);
}
html[data-theme='nativa'] .nv-no-add,
html[data-theme='nativa'] .nv-no-ccy {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 44px;
    min-width: 0;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: 14px;
    font-weight: 750;
    cursor: pointer;
    white-space: nowrap;
}
html[data-theme='nativa'] .nv-no-add {
    background: #fff;
    color: #4a0870;
    box-shadow: 0 8px 20px rgba(40, 0, 60, .25);
}
html[data-theme='nativa'] .nv-no-add:hover { background: #f4b2ff; }
html[data-theme='nativa'] .nv-no-ccy {
    border-color: rgb(255 255 255 / .4);
    background: rgb(255 255 255 / .12);
    color: #fff;
    backdrop-filter: blur(8px);
}
html[data-theme='nativa'] .nv-no-add i,
html[data-theme='nativa'] .nv-no-ccy i { width: 16px; height: 16px; flex: 0 0 auto; }
html[data-theme='nativa'] .nv-no-ccy:hover { background: rgb(255 255 255 / .22); }
@media (max-width: 640px) {
    html[data-theme='nativa'] .nv-no-wallet { min-height: 0; padding: 20px 16px 14px; gap: 16px; }
    html[data-theme='nativa'] .nv-no-wallet-val { font-size: 2.15rem; }
    html[data-theme='nativa'] .nv-no-add,
    html[data-theme='nativa'] .nv-no-ccy { height: 42px; font-size: 13px; padding: 0 8px; }
    html[data-theme='nativa'] .nv-no-wallet .nv-menu { max-width: min(17rem, calc(100vw - 48px)); }
}
html[data-theme='nativa'] .nv-no-main,
html[data-theme='nativa'] .nv-no-side { min-width: 0; }
html[data-theme='nativa'] .nv-no-side { display: flex; flex-direction: column; gap: 16px; }
html[data-theme='nativa'] .nv-no-ph { margin-bottom: 14px; }

/* ---------------- breadcrumb ---------------- */
html[data-theme='nativa'] .nv-no-crumb {
    display: flex; align-items: center; justify-content: flex-end; gap: 6px;
    font-size: 12.5px; color: var(--nv-ink-4); min-height: 20px;
}
html[data-theme='nativa'] .nv-no-crumb i { width: 13px; height: 13px; }
html[data-theme='nativa'] .nv-no-crumb span { color: var(--nv-ink-2); font-weight: 650; }
html[data-theme='nativa'] .nv-no-crumb a:hover { color: var(--nv-ink-2); }
@media (max-width: 1100px) {
    html[data-theme='nativa'] .nv-no-crumb { justify-content: flex-start; }
}

/* ---------------- KPI tiles ---------------- */
html[data-theme='nativa'] .nv-no-kpis {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px; margin-bottom: 16px;
}
@media (max-width: 720px) {
    html[data-theme='nativa'] .nv-no-kpis { grid-template-columns: minmax(0, 1fr); }
}
html[data-theme='nativa'] .nv-no-kpi { padding: 14px 14px 13px; }
html[data-theme='nativa'] .nv-no-kpi-row { display: flex; align-items: center; gap: 9px; }
html[data-theme='nativa'] .nv-no-kpi-val {
    flex: 1; min-width: 0;
    font-size: 24px; font-weight: 800; line-height: 1.1; letter-spacing: -.02em; color: var(--nv-ink);
}
/* Full width on its own line: the row above has no room to spare (see the
   comment in create.blade.php), and a KPI label that wraps mid-word reads as a
   broken card rather than a narrow one. */
html[data-theme='nativa'] .nv-no-kpi-lbl {
    font-size: 12.5px; color: var(--nv-ink-4); margin-top: 7px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The trend chip takes the tile's own accent, so the figure, the bar and the
   line all read as one measurement instead of three. */
html[data-theme='nativa'] .nv-no-kpi .nv-stat-ico { width: 38px; height: 38px; flex: 0 0 38px; border-radius: 12px; }
html[data-theme='nativa'] .nv-no-kpi .nv-stat-ico i { width: 18px; height: 18px; }
html[data-theme='nativa'] .nv-no-kpi-trend {
    display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto;
    font-size: 11.5px; font-weight: 800; white-space: nowrap;
}
html[data-theme='nativa'] .nv-no-kpi-trend i { width: 12px; height: 12px; }
html[data-theme='nativa'] .nv-no-kpi-ok .nv-no-kpi-trend { color: var(--nv-ok); }
html[data-theme='nativa'] .nv-no-kpi-info .nv-no-kpi-trend { color: var(--nv-info); }
html[data-theme='nativa'] .nv-no-kpi-trend-down { color: var(--nv-bad) !important; }

html[data-theme='nativa'] .nv-no-kpi-foot {
    display: flex; align-items: center; gap: 9px; margin-top: 10px;
}
html[data-theme='nativa'] .nv-no-kpi-bar {
    flex: 1; min-width: 0; height: 6px; border-radius: 99px;
    background: var(--nv-line); overflow: hidden;
}
html[data-theme='nativa'] .nv-no-kpi-bar-fill { display: block; height: 100%; border-radius: 99px; }
html[data-theme='nativa'] .nv-no-kpi-ok .nv-no-kpi-bar-fill { background: var(--nv-ok); }
html[data-theme='nativa'] .nv-no-kpi-info .nv-no-kpi-bar-fill { background: var(--nv-info); }

html[data-theme='nativa'] .nv-no-kpi-spark { flex: 0 0 62px; width: 62px; height: 26px; overflow: visible; }
html[data-theme='nativa'] .nv-no-kpi-spark-line { fill: none; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; }
html[data-theme='nativa'] .nv-no-kpi-spark-fill { stroke: none; opacity: .14; }
html[data-theme='nativa'] .nv-no-kpi-ok .nv-no-kpi-spark-line { stroke: var(--nv-ok); }
html[data-theme='nativa'] .nv-no-kpi-ok .nv-no-kpi-spark-fill { fill: var(--nv-ok); }
html[data-theme='nativa'] .nv-no-kpi-info .nv-no-kpi-spark-line { stroke: var(--nv-info); }
html[data-theme='nativa'] .nv-no-kpi-info .nv-no-kpi-spark-fill { fill: var(--nv-info); }

/* ---------------- card head with icon tile ---------------- */
html[data-theme='nativa'] .nv-no-head { display: flex; align-items: center; gap: 12px; }
html[data-theme='nativa'] .nv-no-head p { margin: 2px 0 0; }
html[data-theme='nativa'] .nv-no-tile {
    width: 42px; height: 42px; border-radius: 13px; flex: 0 0 42px;
    display: grid; place-items: center;
    background: var(--brand, #f5c400); color: var(--nv-on-brand);
}
html[data-theme='nativa'] .nv-no-tile i { width: 20px; height: 20px; }

/* ---------------- order-type tabs ---------------- */
html[data-theme='nativa'] .nv-no-tabs {
    display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px;
}
html[data-theme='nativa'] .nv-no-tab {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 9px 14px; border-radius: 10px; border: 1px solid var(--nv-line);
    background: var(--nv-white); color: var(--nv-ink-2);
    font-size: 13px; font-weight: 700; transition: background .15s, color .15s, border-color .15s;
}
html[data-theme='nativa'] .nv-no-tab i { width: 15px; height: 15px; }
html[data-theme='nativa'] .nv-no-tab:hover { border-color: var(--nv-line-2); color: var(--nv-ink); }
html[data-theme='nativa'] .nv-no-tab[aria-selected='true'] {
    background: var(--brand, #f5c400); border-color: var(--brand, #f5c400); color: var(--nv-on-brand);
}

/* ---------------- form helpers ---------------- */
html[data-theme='nativa'] .nv-no-rel { position: relative; }
html[data-theme='nativa'] .nv-selwrap-off { opacity: .6; cursor: not-allowed; }
html[data-theme='nativa'] .nv-select-ph { pointer-events: none; display: flex; align-items: center; }
html[data-theme='nativa'] .nv-selwrap-btn { cursor: pointer; width: 100%; }
html[data-theme='nativa'] .nv-select-trunc {
    pointer-events: none; display: flex; align-items: center; width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
html[data-theme='nativa'] .nv-svcpop {
    position: absolute; z-index: 40; top: calc(100% + 4px); inset-inline: 0;
    max-height: 280px; overflow-y: auto;
}
html[data-theme='nativa'] .nv-svcpop-q { margin-bottom: 6px; }
html[data-theme='nativa'] .nv-sr { width: 100%; text-align: start; display: flex; align-items: flex-start; gap: 8px; }
/* The open list wraps instead of truncating — imported catalogues differ only
   in the tail ("… Max Quality — Refill 365 Days"). */
html[data-theme='nativa'] .nv-sr-name { flex: 1; min-width: 0; white-space: normal; overflow-wrap: anywhere; line-height: 1.35; }
html[data-theme='nativa'] .nv-sr-price { flex: 0 0 auto; font-weight: 800; color: var(--nv-brand-ink); }

html[data-theme='nativa'] .nv-no-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
html[data-theme='nativa'] .nv-no-subhead {
    display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
    font-size: 12.5px; font-weight: 700;
}
html[data-theme='nativa'] .nv-no-subhead i { width: 15px; height: 15px; }

/* ---------------- quantity + total price ---------------- */
html[data-theme='nativa'] .nv-no-qty {
    display: flex; flex-direction: column; gap: 10px; align-items: stretch;
}
html[data-theme='nativa'] .nv-no-price {
    border: 1px solid var(--nv-line); border-radius: 12px; background: var(--nv-paper-2);
    padding: 10px 14px; text-align: start;
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
html[data-theme='nativa'] .nv-no-price-lbl { font-size: 11.5px; color: var(--nv-ink-4); }
html[data-theme='nativa'] .nv-no-price-val {
    font-size: 19px; font-weight: 800; letter-spacing: -.02em;
    color: var(--nv-brand-ink); margin-top: 2px; overflow-wrap: anywhere;
}

/* ---------------- confirm + CTA ---------------- */
html[data-theme='nativa'] .nv-no-confirm { margin-top: 4px; }
html[data-theme='nativa'] .nv-no-cta { height: 46px; font-size: 14px; margin-top: 12px; }

html[data-theme='nativa'] .nv-no-receipt {
    border: 0;
    background:
        radial-gradient(120% 80% at 100% 0%, color-mix(in srgb, var(--nv-brand) 16%, transparent), transparent 55%),
        var(--nv-white);
    box-shadow: 0 16px 40px rgb(0 0 0 / .06);
}
html[data-theme='nativa'] .nv-no-receipt-pad {
    padding: 22px 22px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
html[data-theme='nativa'] .nv-no-receipt-kicker {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--nv-ink-4);
}
html[data-theme='nativa'] .nv-no-receipt-time {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border-radius: 16px;
    background: var(--nv-white);
    border: 1px solid color-mix(in srgb, var(--nv-ink) 10%, transparent);
}
html[data-theme='nativa'] .nv-no-receipt-ico {
    width: 42px; height: 42px; border-radius: 14px; flex: 0 0 42px;
    display: grid; place-items: center;
    background: var(--nv-ink); color: var(--nv-white);
}
html[data-theme='nativa'] .nv-no-receipt-ico i { width: 18px; height: 18px; }
html[data-theme='nativa'] .nv-no-receipt-time span {
    display: block; font-size: 12px; color: var(--nv-ink-4); font-weight: 600;
}
html[data-theme='nativa'] .nv-no-receipt-time strong {
    display: block; margin-top: 2px; font-size: 1.15rem; font-weight: 800;
    letter-spacing: -.02em; color: var(--nv-ink);
}
html[data-theme='nativa'] .nv-no-receipt-desc {
    padding: 4px 2px 2px;
    display: flex; flex-direction: column; gap: 8px;
    font-size: 13.5px; line-height: 1.55; color: var(--nv-ink-2);
}
html[data-theme='nativa'] .nv-no-receipt-btn {
    height: 52px;
    margin-top: 4px;
    border-radius: 16px;
    font-size: 15px;
    font-weight: 750;
    letter-spacing: -.01em;
}
html[data-theme='nativa'] .nv-no-bal {
    display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px;
    margin-top: 10px; font-size: 12.5px; color: var(--nv-ink-4);
}
html[data-theme='nativa'] .nv-no-bal strong { color: var(--nv-ink-2); }

/* ---------------- social networks ---------------- */
html[data-theme='nativa'] .nv-no-nethead { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
html[data-theme='nativa'] .nv-no-viewall {
    display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto;
    font-size: 12.5px; font-weight: 700; color: var(--nv-brand-ink);
}
html[data-theme='nativa'] .nv-no-viewall i { width: 14px; height: 14px; }
html[data-theme='nativa'] .nv-no-viewall:hover { text-decoration: underline; }

/* A grid, not a wrap: the chips have to FILL the row, and a flex-wrap leaves a
   ragged right edge that reads as three untidy rows.

   The minimum is not a round number — it is the content width MEASURED on the
   widest quick-access label ("WhatsApp", 122px at 13px/700 with its 22px glyph
   tile and padding), rounded up. Set it lower and that one chip truncates, which
   is the one thing a network selector must never do; set it higher and a column
   is lost for nothing. auto-fit then answers "how many fit" at whatever width
   the card happens to have, and the script keeps two rows of that answer. */
html[data-theme='nativa'] .nv-no-nets {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* The chip paints with the brand PAIR from the core (--net-x / --net-x-on).
   The on-colour is not decoration: Snapchat is #FFFC00 and a hardcoded white
   label there measures 1.1:1 — the text would be in the HTML and not on the
   screen. The inner glyph square derives from the same on-colour, so it stays
   visible on a light fill too. */
html[data-theme='nativa'] .nv-no-net {
    display: inline-flex; flex-direction: row; align-items: center; justify-content: flex-start; gap: 10px;
    width: 168px; max-width: 100%; min-width: 0;
    height: 48px; padding: 8px 12px; border-radius: 12px;
    background: var(--nv-white); color: var(--nv-ink);
    font-size: 13px; font-weight: 650; line-height: 1.15; text-align: start;
    border: 1px solid var(--nv-line);
    transition: transform .12s, box-shadow .12s, border-color .12s;
}
html[data-theme='nativa'] .nv-no-net:hover {
    transform: translateY(-1px);
    border-color: var(--nv-brand);
    box-shadow: 0 8px 18px rgb(0 0 0 / .16);
}
html[data-theme='nativa'] .nv-no-net[aria-pressed='true'] {
    border-color: #ce6bff;
    box-shadow: 0 0 0 1px #bd0edc, 0 0 16px rgba(189, 14, 220, .35);
}
html[data-theme='nativa'] .nv-no-net-ico {
    width: 28px; height: 28px; border-radius: 8px; flex: 0 0 28px;
    display: grid; place-items: center;
    background: var(--nv-net); color: var(--nv-net-on);
    font-size: 11px; font-weight: 800;
}
html[data-theme='nativa'] .nv-no-net-ico svg,
html[data-theme='nativa'] .nv-no-net-ico i { width: 16px; height: 16px; fill: currentColor; }
html[data-theme='nativa'] .nv-no-net-lbl {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    min-width: 0;
}
@media (max-width: 640px) {
    html[data-theme='nativa'] .nv-no-net {
        width: calc(50% - 5px);
        height: 46px;
        font-size: 12px;
    }
}
/* A network with neither a platform nor a default category is not clickable and
   says so in its title — offering it would empty the catalogue silently.
   It drops the brand fill instead of FADING it: at opacity .42 the labels
   measured 1.2–2.9:1, so the customer could not read which networks exist at
   all. A neutral surface says "not available here" just as clearly and stays
   legible — and it stops an unavailable network from wearing its brand at
   half strength, which reads like a rendering fault rather than a state. */
html[data-theme='nativa'] .nv-no-net-off {
    background: var(--nv-soft); color: var(--nv-ink-3);
    border-color: var(--nv-line); cursor: not-allowed;
}
html[data-theme='nativa'] .nv-no-net-off .nv-no-net-ico {
    background: color-mix(in srgb, var(--nv-ink-3) 22%, var(--nv-paper));
    color: var(--nv-ink-2);
}
html[data-theme='nativa'] .nv-no-net-off:hover { transform: none; box-shadow: none; }

/* A network the operator added themselves has no brand in the registry, so it
   wears the panel's own — the one colour the product is always allowed to use. */
html[data-theme='nativa'] .nv-no-net-own {
    background: var(--nv-white); color: var(--nv-ink);
}
html[data-theme='nativa'] .nv-no-net-own .nv-no-net-ico {
    background: var(--nv-brand); color: #fff;
}

/* The filter's release valve, inside the "View All" dialog. Full width and above
   the grid on purpose: as a chip under the card it read as one more network and
   spilled the strip onto a third row. */
html[data-theme='nativa'] .nv-no-allnets {
    display: flex; align-items: center; justify-content: center; gap: 6px;
    width: 100%; margin: 0 0 14px;
    padding: 10px 13px; border-radius: 10px;
    border: 1px dashed var(--nv-line-2); background: transparent;
    font-size: 12.5px; font-weight: 700; color: var(--nv-ink-3);
}
html[data-theme='nativa'] .nv-no-allnets i { width: 14px; height: 14px; }
html[data-theme='nativa'] .nv-no-allnets:hover { border-color: var(--brand, #f5c400); color: var(--nv-ink); }
html[data-theme='nativa'] .nv-no-allnets[aria-pressed='true'] {
    border-style: solid; border-color: var(--brand, #f5c400);
    background: var(--nv-soft); color: var(--nv-ink);
}

/* ---------------- order summary ---------------- */
html[data-theme='nativa'] .nv-no-box {
    display: flex; align-items: flex-start; gap: 8px;
    min-height: 42px; padding: 11px 12px;
    border: 1px solid var(--nv-line); border-radius: 11px; background: var(--nv-paper-2);
    font-size: 13px; color: var(--nv-ink-2); line-height: 1.4;
}
html[data-theme='nativa'] .nv-no-box i { width: 15px; height: 15px; flex: 0 0 15px; margin-top: 2px; color: var(--nv-ink-4); }
html[data-theme='nativa'] .nv-no-box span { min-width: 0; overflow-wrap: anywhere; }

/* Two by two by default, four across only where four actually FIT. The
   reference puts all four in one row because its right column is wider; at
   1200px this one is 342px and "100,000" was measured needing 49px in a 35px
   box — a limit the customer is supposed to order against, silently trimmed.
   A figure that decides an order is never truncated (same rule as the service
   name), so the grid gives way before the number does. */
html[data-theme='nativa'] .nv-no-metrics {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 14px;
}
@media (min-width: 1360px) {
    html[data-theme='nativa'] .nv-no-metrics { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
html[data-theme='nativa'] .nv-no-metric {
    border: 1px solid var(--nv-line); border-radius: 11px; background: var(--nv-paper-2); padding: 9px 10px;
}
html[data-theme='nativa'] .nv-no-metric-lbl { font-size: 11px; color: var(--nv-ink-4); }
html[data-theme='nativa'] .nv-no-metric-val {
    display: flex; align-items: center; gap: 5px; margin-top: 4px;
    font-size: 12.5px; font-weight: 700; color: var(--nv-ink);
}
html[data-theme='nativa'] .nv-no-metric-val i { width: 13px; height: 13px; flex: 0 0 13px; color: var(--nv-ink-4); }
html[data-theme='nativa'] .nv-no-metric-val span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

html[data-theme='nativa'] .nv-no-desc {
    border: 1px solid var(--nv-line); border-radius: 11px; background: var(--nv-paper-2);
    padding: 11px 12px; min-height: 84px;
}
html[data-theme='nativa'] .nv-no-desc-ph {
    display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--nv-ink-4);
}
html[data-theme='nativa'] .nv-no-desc-ph i { width: 15px; height: 15px; flex: 0 0 15px; }
html[data-theme='nativa'] .nv-no-bullet { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 6px; font-size: 12.5px; line-height: 1.4; }
html[data-theme='nativa'] .nv-no-bullet:last-child { margin-bottom: 0; }
html[data-theme='nativa'] .nv-no-dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 6px; margin-top: 5px; }

/* ---------------- all-networks modal ---------------- */
html[data-theme='nativa'] .nv-no-modal {
    position: fixed; inset: 0; z-index: 70;
    display: flex; align-items: center; justify-content: center; padding: 18px;
    background: rgb(0 0 0 / .45);
}
html[data-theme='nativa'] .nv-no-modal-card {
    width: min(560px, 100%); max-height: 82vh; display: flex; flex-direction: column;
    background: var(--nv-white); border: 1px solid var(--nv-line); border-radius: 16px;
    box-shadow: 0 24px 60px rgb(0 0 0 / .28); overflow: hidden;
}
html[data-theme='nativa'] .nv-no-modal-head {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 14px 16px; border-bottom: 1px solid var(--nv-line);
}
html[data-theme='nativa'] .nv-no-modal-head h3 { margin: 0; font-size: 15px; }
html[data-theme='nativa'] .nv-no-modal-x {
    width: 32px; height: 32px; border-radius: 9px; display: grid; place-items: center;
    color: var(--nv-ink-3);
}
html[data-theme='nativa'] .nv-no-modal-x:hover { background: var(--nv-soft); color: var(--nv-ink); }
html[data-theme='nativa'] .nv-no-modal-x i { width: 17px; height: 17px; }
html[data-theme='nativa'] .nv-no-modal-body { padding: 16px; overflow-y: auto; }

/* ---------------- dark layer ----------------
   The tiles and boxes sit on the dark card, so their wash lifts instead of
   staying a light grey rectangle on a dark surface. */
html.dark[data-theme='nativa'] .nv-no-price,
html.dark[data-theme='nativa'] .nv-no-box,
html.dark[data-theme='nativa'] .nv-no-metric,
html.dark[data-theme='nativa'] .nv-no-desc { background: var(--nv-soft); }
/* :not() is not tidiness — it is the whole rule. This selector has the SAME
   specificity as the active-tab rule above and comes later, so without it the
   dark layer repainted the SELECTED tab's background while leaving its
   on-brand ink: measured 1.37:1, the label in the HTML and not on the screen.
   A blanket rule always needs the exception for the surface that already
   declared its own pair. */
html.dark[data-theme='nativa'] .nv-no-tab:not([aria-selected='true']) { background: var(--nv-soft); }
html.dark[data-theme='nativa'] .nv-no-net {
    background: #1a1224;
    border-color: #5c2e78;
}
html.dark[data-theme='nativa'] .nv-no-net:hover { box-shadow: 0 8px 18px rgb(0 0 0 / .45); }
html.dark[data-theme='nativa'] .nv-no-net[aria-pressed='true'] {
    background: color-mix(in srgb, #bd0edc 16%, #1a1224);
    border-color: #ce6bff;
    box-shadow: 0 0 0 1px #bd0edc, 0 0 16px rgba(189, 14, 220, .4);
}

/* ── The product's modal, dressed by this theme ────────────────────────────
   The dialog is the PRODUCT'S component (rf-modal-*), not a copy: its two
   modes, its deferred @entangle, its "never closes by accident" rule and its
   editor-activate hook are behaviour, and a theme that reimplemented them would
   drift from the panel the day any of it changes. Only the surface is ours.

   It arrives here plain — a white sheet, a bare title and a naked ✕ — so it
   reads as a browser dialog dropped on a designed page. A tinted header and a
   round close give it the same build as every other card in this portal.

   Everything is scoped to the theme, so a panel on a stock skin is untouched. */
html[data-theme='nativa'] .rf-modal {
    border: 1px solid var(--nv-line);
    border-radius: var(--nv-r-card);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .22);
    overflow: hidden;                 /* or the tinted header squares its corners */
    background: var(--nv-white);
}

/* The header band. --nv-soft is the theme's brand wash and flips with the mode
   on its own, so no second rule in the dark layer. The ink is --nv-ink and not
   a literal: on the light wash it is the same ink the cards use, and in dark
   --nv-soft becomes a raised grey where a fixed dark would vanish. */
html[data-theme='nativa'] .rf-modal-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    background: var(--nv-soft);
    border-bottom: 1px solid var(--nv-line);
    color: var(--nv-ink);
}
html[data-theme='nativa'] .rf-modal-header .rf-card-title {
    font-size: 15.5px;
    font-weight: 700;
    letter-spacing: -.2px;
    margin: 0;
    min-width: 0;
    /* A long title must not push the ✕ off the band — that is the only control
       some of these dialogs have. */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    color: var(--nv-ink);
}

/* The close. Round, on its own surface, and pushed to the end of the band so it
   is in the same place in every dialog. Sized to the 32px touch target the rest
   of this portal uses, not to the 18px glyph inside it. */
html[data-theme='nativa'] .rf-modal-header .rf-icon-btn {
    margin-inline-start: auto;
    flex: 0 0 auto;
    width: 32px; height: 32px;
    display: grid; place-items: center;
    border-radius: 50%;
    border: 1px solid var(--nv-line);
    background: var(--nv-white);
    color: var(--nv-ink-3);
    transition: background-color .13s ease, color .13s ease, border-color .13s ease;
}
html[data-theme='nativa'] .rf-modal-header .rf-icon-btn:hover {
    background: var(--nv-bad-bg);
    border-color: var(--nv-bad);
    color: var(--nv-bad);
}

html[data-theme='nativa'] .rf-modal-body { padding: 18px 16px; }

/* The footer. Its own surface and a top rule so Cancel and the primary action
   read as the end of the dialog rather than as two more buttons in the form.
   It wraps because two long labels in a narrow dialog would otherwise overflow
   the sheet the theme just told to clip its corners. */
html[data-theme='nativa'] .rf-modal-footer {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 9px;
    padding: 13px 16px;
    background: var(--nv-paper-2);
    border-top: 1px solid var(--nv-line);
}

/* The fee breakdown is the PRODUCT'S partial (partials/deposit-fee-summary),
   included and never copied. It carries `max-w-sm` because in the stock skin it
   lives in the narrow right-hand column, where 384px fills the space. In this
   layout the checkout is one 760px column, so the same cap left the figure a
   customer checks before paying floating at half the width of the button that
   charges him. The cap is released HERE and only inside the theme; the product
   keeps its own.

   Outside @layer on purpose: Tailwind emits its utilities inside a cascade
   layer, and any unlayered declaration beats a layered one wherever it sits. */
html[data-theme='nativa'] .nv-paysum > .rf-card { max-width: none; }

/* Order logs: the four figures are the filters, two by two on a phone, and the
   table stays inside the card — ID, service, status, View. */
@media (max-width: 1023px) {
    html[data-theme='nativa'] .nv-ol-kpis,
    html[data-theme='nativa'] .nv-stat-qa .nv-qa {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}
html[data-theme='nativa'] .nv-ol-kpi {
    width: 100%;
    text-align: start;
    cursor: pointer;
    font: inherit;
    color: inherit;
    appearance: none;
}
html[data-theme='nativa'] .nv-ol-kpi.is-on {
    border-color: var(--nv-brand);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--nv-brand) 40%, transparent);
}
html[data-theme='nativa'] .nv-ol-wrap { overflow-x: clip; }
html[data-theme='nativa'] .nv-ol-table {
    width: 100%;
    table-layout: fixed;
}
html[data-theme='nativa'] .nv-ol-table col.nv-ol-id { width: 16%; }
html[data-theme='nativa'] .nv-ol-table col.nv-ol-status { width: 36%; }
html[data-theme='nativa'] .nv-ol-table col.nv-ol-view { width: 18%; }
html[data-theme='nativa'] .nv-ol-table .nv-t-name {
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
}
html[data-theme='nativa'] .nv-ol-table td:nth-child(3) .nv-badge { white-space: nowrap; }
html[data-theme='nativa'] .nv-ol-table thead th,
html[data-theme='nativa'] .nv-ol-table tbody td { overflow-wrap: anywhere; }
html[data-theme='nativa'] .nv-ol-viewbtn {
    width: 100%;
    padding-inline: 8px;
    white-space: nowrap;
}
@media (max-width: 640px) {
    html[data-theme='nativa'] .nv-ol-kpis { gap: 10px; }
    html[data-theme='nativa'] .nv-ol-kpi { padding: 12px 10px; gap: 8px; }
    html[data-theme='nativa'] .nv-ol-kpi .nv-stat-ico { width: 34px; height: 34px; border-radius: 10px; }
    html[data-theme='nativa'] .nv-ol-board .nv-tb-right {
        width: 100%;
        margin-inline-start: 0;
    }
    html[data-theme='nativa'] .nv-ol-board .nv-field-search { flex: 1 1 100%; max-width: none; }
    html[data-theme='nativa'] .nv-ol-table { font-size: 12px; }
    html[data-theme='nativa'] .nv-ol-table thead th,
    html[data-theme='nativa'] .nv-ol-table tbody td { padding: 10px 8px; }
}

/* A phone zooms the page when a field is under 16px, and a double-tap or a
   pinch zooms whatever section the finger lands on. Fields stay 16px on a
   small screen — including the sign-in card, which sits outside the shell —
   and every surface only pans, so the page stays the size it opened at. */
@media (max-width: 1023px) {
    html[data-theme='nativa'] input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']):not([type='button']):not([type='submit']):not([type='hidden']):not([type='image']),
    html[data-theme='nativa'] select,
    html[data-theme='nativa'] textarea {
        font-size: 16px !important;
    }
}
html[data-theme='nativa'],
html[data-theme='nativa'] body,
html[data-theme='nativa'] body * {
    touch-action: pan-x pan-y;
}

/* Success and info stay a corner note. A problem is a dialog: the host
   itself decides which, and these rules only dress the two surfaces. */
.nv-toast-stack {
    position: fixed;
    top: 72px;
    inset-inline-end: 16px;
    z-index: 90;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 360px;
    max-width: calc(100vw - 32px);
    pointer-events: none;
}
.nv-toast {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px;
    border-radius: 14px;
    background: var(--nv-white);
    border: 1px solid var(--nv-line);
    box-shadow: var(--nv-shadow-md);
    pointer-events: auto;
    color: var(--nv-ink);
}
.nv-toast-msg { flex: 1; font-size: 13.5px; line-height: 1.4; }
.nv-toast button {
    flex: none;
    color: var(--nv-ink-4);
    font-size: 18px;
    line-height: 1;
}
.nv-alert-backdrop { z-index: 100; }
.nv-alert { width: min(380px, 92vw); }
.nv-alert-body { padding: 26px 22px 22px; text-align: center; }
.nv-alert-ico {
    width: 52px;
    height: 52px;
    margin: 0 auto 14px;
    border-radius: 50%;
    display: grid;
    place-items: center;
}
.nv-alert-ico.is-bad { background: var(--nv-bad-bg); color: var(--nv-bad); }
.nv-alert-ico.is-warn { background: var(--nv-warn-bg); color: var(--nv-warn); }
.nv-alert-msg {
    margin: 0 0 18px;
    font-size: 15.5px;
    font-weight: 650;
    line-height: 1.45;
    color: var(--nv-ink);
}
