/* ========================================================================== */
/* NextXbase 2.0 — Premium Design System & Real Application Viewport Engine   */
/* "Control the Controls" — 2026 Light Luxury Glass Design Language            */
/* Dark-on-Light | High Contrast | Gold & Onyx on White Marble                */
/* MSHTML/IE11 Compatible — No CSS Variables, No backdrop-filter               */
/* Copyright (c) 2026 NextXbase Platform                                      */
/* ========================================================================== */

/* ========================================================================== */
/* GLOBAL RESET & FOUNDATION                                                   */
/* ========================================================================== */

*, *:before, *:after {
    box-sizing: border-box !important;
}

/* A WINDOW TALLER THAN THE SCREEN WAS UNREACHABLE. height:100vh with
   overflow:hidden clipped the document at exactly one viewport, so any
   window whose controls ran past the fold simply could not be scrolled
   to -- and the page LOOKED complete, which is the worst version of it.
   Two samples differing in whether they showed a scrollbar was only a
   difference in whether their content happened to fit.

   min-height keeps the app-shell look for every page that DOES fit -- a
   short window still fills the screen and still shows no scrollbar -- 
   while a taller one now grows and scrolls. overflow-x stays hidden so
   a stray absolute control cannot produce a sideways scrollbar. */
html, body {
    margin: 0;
    padding: 0;
    width: 100vw;
    height: 100vh;
    overflow: hidden !important;
    font-family: 'Segoe UI', 'Outfit', system-ui, -apple-system, sans-serif;
    -webkit-tap-highlight-color: transparent;

    /* Marble, not paper. A single flat #f5f3ef across a whole screen is the
       flattest thing in any interface and the eye reads it as unfinished --
       there is no such thing in a physical object. The gradient spans about
       three percent of luminance top to bottom: individually invisible,
       collectively the difference between a surface and a fill. */
    background: #f5f3ef;
    background: linear-gradient(to bottom, #faf8f4 0%, #f5f3ef 42%, #efece6 100%);
    color: #1a1814;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* ========================================================================== */
/* 1. Window Container Layout Engine                                          */
/* ========================================================================== */
/* A WINDOW TALLER THAN THE SCREEN WAS UNREACHABLE, and the obvious fix is
   WRONG. Swapping height for min-height here made the window's height
   INDEFINITE, and a flex column's children resolve percentage heights
   against a definite parent -- so every one of them collapsed. Measured
   by NextXbaseServer/tools/sizelab.py: the window went 885x462 -> 443x249 and a 110x28
   control became 30x8. The geometry guard is the only thing that saw it;
   the page still looked plausible.

   So the height stays DEFINITE and the window scrolls INSIDE itself.
   Children keep their parent, content past the fold becomes reachable,
   and a window that fits shows no scrollbar because overflow:auto only
   produces one when there is something to scroll. */
.nextxbase-window {
    position: absolute;
    top: 0;
    left: 0;
    /* 100vw/100vh, NOT 100%, AND THAT IS MEASURED RATHER THAN PREFERRED.

       The window lives inside #nxb-stage, which nextXbaseFitStage scales, so
       asking the STAGE for the size instead of the viewport looks obviously
       right -- `vh` ignores the scale and the two boxes disagree by exactly
       the scale factor, which is what pushes the status bar below the fold.

       It renders the whole application BLANK. This element is
       position:absolute, so a percentage height resolves against a
       containing block that has no definite height at layout time and
       collapses to zero. Photographed: an empty white client, no menubar, no
       controls. Same visible symptom as `overflow:hidden` below and a
       completely different cause -- which is the reason both are written
       down here instead of being rediscovered as one.

       The overflow this leaves is real and still open: see the note on
       overflow below. It is ~33px on a 1707x960 design, almost exactly the
       height of the chrome, because the menubar, toolbar and status bar are
       added OUTSIDE the declared window height rather than taken out of the
       client area. Fixing THAT is the fix; resizing the window is not. */
    width: 100vw;
    height: 100vh;
    /* DO NOT SET `overflow: hidden` HERE. It is the obviously-right value --
       the workspace inside already clips, and the reference's maximised window
       has no scrollbars -- and it renders the ENTIRE APPLICATION BLANK in the
       product. Tried and photographed: a white client area, no menubar, no
       controls, no status bar, while the emitted page was perfect and Chrome
       drew it correctly.

       The cause is recorded in CLAUDE.md and cost a whole session once already:
       MSHTML paints NOTHING when a clipped box contains transformed content,
       and nextXbaseFitStage scales this window's stage. `zoom` is the branch
       that survives clipping; `transform` is not, and the fallback path still
       uses it.

       So the scrollbar stays, and a document taller than the window is fixed by
       making the CONTENT fit -- which is what CLAUDE.md asks of a sample
       anyway -- not by clipping the window that holds it. */
    overflow-x: hidden;
    overflow-y: auto;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    z-index: 1;
    background: #f5f3ef;

    /* THE APPLICATION NEEDS AN EDGE. With border:none and a near-white fill
       this dissolved into any light background behind it -- an editor, a
       browser page -- and a user could not see where the app began.

       A neutral hairline plus an inset white highlight is a shallow bevel: the
       window reads as sitting slightly proud of what is behind it. Grey, not
       gold, so it separates without becoming decoration. */
    border: 1px solid #8b8479;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95),
                inset 0 0 0 1px rgba(255, 255, 255, 0.55),
                inset 0 -1px 0 rgba(0, 0, 0, 0.10),
                0 12px 34px rgba(0, 0, 0, 0.26);
}

/* THE OS FRAME AND THE PAGE FRAME ARE THE SAME EDGE, so exactly one of them
   may draw it.

   In the native shell the container is a real framed window -- the host gives
   it WS_OVERLAPPEDWINDOW and Windows draws this same hairline around the
   client. The border above then draws a SECOND one INSIDE it, and because
   box-sizing is border-box that does not merely look wrong, IT MOVES THINGS:
   1px off the client origin on both axes, and 2px out of the workspace in each
   dimension. Measured on ctl_fixture with the rect probe --

       win_000010   w 1280 h 800   clientWidth 1278   clientHeight 798

   -- and every control read dx +1 against the licensed reference.

   GATED ON BOTH MARKERS, because either one alone is wrong:

     .nxb-shell       we are the native container, not a browser tab. In a tab
                      there is no OS frame at all, and the edge above is
                      exactly what the comment on it describes -- without it
                      the app dissolves into a light page behind it.
     .wnd-os-framed   this window asked for a frame and the host gave it one.
                      A frameless popup IS its own edge and must keep the
                      border even inside the shell.

   So the border is dropped only where something else is already drawing it. */
.nxb-shell .nextxbase-window.wnd-os-framed {
    border: 0;
}

/* ========================================================================== */
/* Theme System — All use same Light Luxury base                              */
/* ========================================================================== */
body.theme-system, .theme-system.nextxbase-window,
body.theme-dark, .theme-dark.nextxbase-window,
body.theme-citrus, .theme-citrus.nextxbase-window,
body.theme-glassmorphism, .theme-glassmorphism.nextxbase-window {
    background: #f5f3ef;
    color: #1a1814;
}

/* Structural System Slots */
.nextxbase-slot-titlebar {
    flex: 0 0 auto;
    height: 38px;
    min-height: 38px;
    width: 100%;
    z-index: 100;
    box-sizing: border-box;
    /* POSITIONED SO THE z-index ABOVE IS OBEYED ON THE WINDOWS 7 FLOOR.
       These slots are flex items of .nextxbase-window. Modern flexbox says a
       flex item honours z-index even when it is not positioned; IE11 implements
       OLDER spec and does not. So in the product -- MSHTML in IE11 mode --
       the z-index was ignored, stacking fell back to DOM order, and
       slot-toolbar (later in the document) painted OVER slot-menubar: the
       menu's dropdowns came out BEHIND the buttonbar. In Chrome it looked
       correct the whole time, which is why it survived.
       position:relative with no offsets moves nothing in any engine. It only
       makes the element positioned, which is what IE11 requires before it
       will read a z-index at all. */
    position: relative;
}

.nextxbase-slot-menubar {
    flex: 0 0 auto;
    min-height: 32px;
    width: 100%;
    z-index: 90;
    box-sizing: border-box;
    /* POSITIONED SO THE z-index ABOVE IS OBEYED ON THE WINDOWS 7 FLOOR.
       These slots are flex items of .nextxbase-window. Modern flexbox says a
       flex item honours z-index even when it is not positioned; IE11 implements
       OLDER spec and does not. So in the product -- MSHTML in IE11 mode --
       the z-index was ignored, stacking fell back to DOM order, and
       slot-toolbar (later in the document) painted OVER slot-menubar: the
       menu's dropdowns came out BEHIND the buttonbar. In Chrome it looked
       correct the whole time, which is why it survived.
       position:relative with no offsets moves nothing in any engine. It only
       makes the element positioned, which is what IE11 requires before it
       will read a z-index at all. */
    position: relative;
}

.nextxbase-slot-toolbar {
    flex: 0 0 auto;
    width: 100%;
    z-index: 80;
    box-sizing: border-box;
    /* POSITIONED SO THE z-index ABOVE IS OBEYED ON THE WINDOWS 7 FLOOR.
       These slots are flex items of .nextxbase-window. Modern flexbox says a
       flex item honours z-index even when it is not positioned; IE11 implements
       OLDER spec and does not. So in the product -- MSHTML in IE11 mode --
       the z-index was ignored, stacking fell back to DOM order, and
       slot-toolbar (later in the document) painted OVER slot-menubar: the
       menu's dropdowns came out BEHIND the buttonbar. In Chrome it looked
       correct the whole time, which is why it survived.
       position:relative with no offsets moves nothing in any engine. It only
       makes the element positioned, which is what IE11 requires before it
       will read a z-index at all. */
    position: relative;
}

.nextxbase-slot-workspace {
    /* THE WORKSPACE STATES ITS OWN COLOUR so descendants can INHERIT one.

       .nextxbase-say asks for `background-color: inherit` -- a Win32 static
       erases its rectangle, and that erase is what makes a later control hide
       an earlier one. It resolved to TRANSPARENT and nothing was erased,
       because this rule declared no background-color: the window painted
       #f5f3ef and the workspace passed on nothing. Only .theme-light ever set
       one, by coincidence rather than design.

       Same value as .nextxbase-window's, so nothing changes visually here --
       what changes is that there is now a colour to inherit. */
    background-color: #f5f3ef;

    /* NO width/height 100% HERE -- `flex: 1 1 auto` ALREADY SIZES THIS.

       In a column flex container that declaration means "take the space the
       caption and footer leave". Adding height:100% asked for the whole
       window on top of it, so the workspace was the full window height while
       the caption sibling still occupied 31px above -- content exceeding the
       container by exactly the chrome, every time, which overflow:auto turned
       into a scrollbar. The taller the window the larger the absolute
       overflow, so it appeared ON MAXIMIZE and hid at the restored size,
       which is backwards: a bigger window cannot have less room.

       width:100% was the same mistake on the other axis, and it is why a
       horizontal scrollbar appeared as soon as the vertical one took 17px.

       min-height:0 because a flex item's automatic minimum size is its
       CONTENT size: without it a shrinking column item refuses to go below
       its content and overflows the container anyway. */
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    position: relative;

    /* A WINDOW CLIPS -- IT DOES NOT SCROLL.

       This was overflow:auto, and the scrollbars it produced were SPURIOUS.
       Measured with the two-button probe: the emitted markup places row 47 at
       top:846px with height 27, i.e. bottom 873, inside an 881px workspace.
       It fits. Nothing overflowed in either axis, yet both scrollbars
       appeared -- and the horizontal one took 17px off the bottom, pushing
       the control underneath it so it looked like it had never been emitted.
       One spurious bar creates real overflow on the other axis, which raises
       the second bar: a cascade from nothing.

       Clipping is also what the reference does. the classic maximised window
       has no scrollbars; its client is as big as it is.

       The DIALOG deliberately keeps overflow:auto, and that is not an
       inconsistency: a dialog's size is DECLARED, so a 700x520 dialog holding
       47 rows has more content than box permanently, and clipping there loses
       controls the user cannot reach. A maximised window is already as large
       as the screen allows -- there is no larger size to scroll toward. */
    overflow: hidden;
    box-sizing: border-box;

    /* NO z-index HERE, AND THAT IS THE WHOLE POINT.

       A POSITIONED element with a z-index opens a STACKING CONTEXT, and
       everything inside it is then stacked only against its siblings. This
       rule carried z-index:10 with no stated reason, and it cost a day: a
       modal dialog inside the workspace declares z-index 1000, the toolbar
       slot declares 80, and the dialog LOST -- because 1000 never met 80.
       The workspace's 10 met it, and 10 is less than 80. MayaPOS's dialog
       was painted under the ribbon and its banner read as a sliver.

       With no z-index the workspace stacks in flow: the dialog's 1000 now
       meets the chrome's 80 and 90 directly and wins, while ORDINARY
       controls -- z-index auto, like everything the applications declare --
       still lose to the chrome, which is what the chrome's numbers are for.
       Both outcomes come from one deletion rather than from a rule that has
       to know when a dialog is open.

       ON THE WINDOWS 7 FLOOR: `position:relative` alone opens no stacking
       context in IE11 either. UNVERIFIED THERE -- this box has no Win7 and
       the MSHTML rung has no CDP to measure with. */
    padding: 0;
    margin: 0;
}

/* 24px, AND NO RULE OF ITS OWN -- both numbers read off the reference.

   Its bar runs 889..912: one #747474 line, then 23 rows of content whose first
   row the inset highlight paints white, leaving the 22 gradient rows that get
   counted. 23 is also exactly what the 2007 gradient asks for (11 + 12), so
   the crease lands on its own pixel instead of being resampled.

   Ours was 28 and drew rgba(0,0,0,0.10) on top of the bar's own border, so
   there were TWO lines above the bar where the reference has one. The slot is
   emitted for a msgbar and nothing else (window.prg only opens it under
   lHasMsgBar), so the bar owning the rule costs no other caller anything. */
.nextxbase-slot-footer {
    flex: 0 0 auto;
    height: 24px;
    min-height: 24px;
    width: 100%;
    z-index: 100;
    box-sizing: border-box;
    background: #eceae5;
    border-top: 0;
    /* POSITIONED SO THE z-index ABOVE IS OBEYED ON THE WINDOWS 7 FLOOR.
       These slots are flex items of .nextxbase-window. Modern flexbox says a
       flex item honours z-index even when it is not positioned; IE11 implements
       OLDER spec and does not. So in the product -- MSHTML in IE11 mode --
       the z-index was ignored, stacking fell back to DOM order, and
       slot-toolbar (later in the document) painted OVER slot-menubar: the
       menu's dropdowns came out BEHIND the buttonbar. In Chrome it looked
       correct the whole time, which is why it survived.
       position:relative with no offsets moves nothing in any engine. It only
       makes the element positioned, which is what IE11 requires before it
       will read a z-index at all. */
    position: relative;
}

/* ========================================================================== */
/* 2. Titlebar — Dark Onyx Bar on Light Window (HIGH CONTRAST)                */
/* ========================================================================== */
.nextxbase-titlebar {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    justify-content: space-between !important;
    padding: 0 16px !important;

    /* Polished onyx: light falls from above, so the top of the bar is lifted
       and the bottom settles. The inner highlight is the single detail that
       makes a dark bar look like a material rather than a rectangle of ink.

       The gold hairline gets a dark line beneath it, the same groove used
       everywhere else -- one flat accent line reads as a border drawn ON the
       bar, two read as an edge the bar actually has. */
    background: #1a1814;
    background: linear-gradient(to bottom, #262219 0%, #1c1915 55%, #141210 100%);
    border-bottom: 1px solid rgba(184, 148, 42, 0.35);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07),
                0 1px 0 rgba(0, 0, 0, 0.45);
    -webkit-user-select: none;
    user-select: none;
    height: 38px;
    width: 100% !important;
    box-sizing: border-box !important;
    overflow: hidden !important;
    white-space: nowrap !important;
    position: relative;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.titlebar-caption {
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.8px;
    color: #d4af37;
    white-space: nowrap !important;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1 1 auto !important;
    min-width: 0 !important;
    margin-right: 12px !important;
    padding-right: 0 !important;
}

.titlebar-controls {
    flex: 0 0 auto !important;
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    margin-right: 8px !important;
    padding-right: 4px !important;
    white-space: nowrap !important;
}

.btn-titlebar {
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(212, 175, 55, 0.3);
    border-radius: 6px;
    color: #d4af37 !important;
    width: 28px;
    height: 24px;
    font-size: 12px;
    font-weight: bold;
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    cursor: pointer;
    transition: all 0.3s ease;
    box-sizing: border-box;
    position: relative;
    overflow: hidden;
}

.btn-titlebar:hover {
    background: rgba(212, 175, 55, 0.25);
    border-color: #d4af37;
    color: #f0d060 !important;
    box-shadow: 0 0 6px rgba(184, 148, 42, 0.2), 0 0 15px rgba(184, 148, 42, 0.1);
}

.btn-titlebar.btn-close {
    background: rgba(200, 50, 50, 0.25);
    border-color: rgba(200, 50, 50, 0.5);
    color: #e06050 !important;
}

.btn-titlebar.btn-close:hover {
    background: #dc3c3c !important;
    border-color: #f06060 !important;
    color: #ffffff !important;
    box-shadow: 0 0 12px rgba(220, 60, 60, 0.5);
}

/* ---------------------------------------------------------------------------
   ALL THREE CONTROLS ARE COLOURED, not just close.

   Close alone carried a tint and a halo, so the other two read as decoration
   next to it -- and a maximise button that looks inert is one nobody presses.
   The set is the one every desktop uses and every user already knows: red
   ends, amber steps aside, green grows. Close keeps the red it already had.

   Amber rather than the gold used elsewhere in the titlebar: #d4af37 is the
   chrome colour of this shell, so a gold minimise button would be invisible
   against its own furniture. Canary #ffd633 sits far enough from it to read
   as a distinct control at a glance and still belongs to the warm palette.
   --------------------------------------------------------------------------- */
.btn-titlebar.btn-minimize {
    background: rgba(255, 191, 63, 0.20);
    border-color: rgba(255, 191, 63, 0.50);
    color: #ffd166 !important;
}

.btn-titlebar.btn-minimize:hover {
    background: #ffc233 !important;
    border-color: #ffd633 !important;
    color: #3a2c00 !important;
    box-shadow: 0 0 12px rgba(255, 194, 51, 0.55);
}

.btn-titlebar.btn-maximize {
    background: rgba(40, 200, 100, 0.18);
    border-color: rgba(40, 200, 100, 0.45);
    color: #5fe08f !important;
}

.btn-titlebar.btn-maximize:hover {
    background: #28c85f !important;
    border-color: #4ade80 !important;
    color: #ffffff !important;
    box-shadow: 0 0 12px rgba(40, 200, 95, 0.5);
}

/* ========================================================================== */
/* Window & Dialog Resize Handles (Spec 1.B.2: 8 Resize Handles)              */
/* ========================================================================== */
.nxb-rs {
    position: absolute;
    z-index: 1000;
    box-sizing: border-box;
    background: transparent;
}

.nextxbase-window.wnd-maximized > .nxb-rs,
.nextxbase-dialog.wnd-maximized > .nxb-rs {
    display: none !important;
}

.nxb-rs-n {
    top: -4px;
    left: 8px;
    right: 8px;
    height: 8px;
    cursor: n-resize;
}

.nxb-rs-s {
    bottom: -4px;
    left: 8px;
    right: 8px;
    height: 8px;
    cursor: s-resize;
}

.nxb-rs-w {
    left: -4px;
    top: 8px;
    bottom: 8px;
    width: 8px;
    cursor: w-resize;
}

.nxb-rs-e {
    right: -4px;
    top: 8px;
    bottom: 8px;
    width: 8px;
    cursor: e-resize;
}

.nxb-rs-nw {
    top: -4px;
    left: -4px;
    width: 12px;
    height: 12px;
    cursor: nw-resize;
}

.nxb-rs-ne {
    top: -4px;
    right: -4px;
    width: 12px;
    height: 12px;
    cursor: ne-resize;
}

.nxb-rs-sw {
    bottom: -4px;
    left: -4px;
    width: 12px;
    height: 12px;
    cursor: sw-resize;
}

.nxb-rs-se {
    bottom: -4px;
    right: -4px;
    width: 12px;
    height: 12px;
    cursor: se-resize;
}

/* ========================================================================== */
/* OS Titlebar Button Themes (Spec 1.C: macOS, Windows 11 Fluent, Linux/GNOME)*/
/* ========================================================================== */

/* 1. macOS Traffic Lights Theme */
.theme-macos .nextxbase-slot-titlebar,
.theme-macos .nextxbase-dialog-header {
    flex-direction: row-reverse;
    justify-content: flex-end;
}

.theme-macos .titlebar-controls {
    order: -1;
    margin-right: 8px;
    margin-left: 0;
}

.theme-macos .btn-titlebar {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: none;
    margin: 0 4px;
    font-size: 0;
    line-height: 12px;
    transition: all 0.2s ease;
}

.theme-macos .btn-titlebar.btn-close {
    background: #ff5f56;
    border: 0.5px solid #e0443e;
    order: 1;
}

.theme-macos .btn-titlebar.btn-minimize {
    background: #ffbd2e;
    border: 0.5px solid #dea123;
    order: 2;
}

.theme-macos .btn-titlebar.btn-maximize {
    background: #27c93f;
    border: 0.5px solid #1aab29;
    order: 3;
}

.theme-macos .titlebar-controls:hover .btn-titlebar,
.theme-macos .btn-titlebar:hover {
    font-size: 8px;
    font-weight: 900;
    color: rgba(0, 0, 0, 0.65);
    box-shadow: none;
}

.theme-macos .btn-titlebar.btn-close:hover {
    background: #ff5f56;
    border-color: #e0443e;
    color: #4c0000;
}

.theme-macos .btn-titlebar.btn-minimize:hover {
    background: #ffbd2e;
    border-color: #dea123;
    color: #5a3c00;
}

.theme-macos .btn-titlebar.btn-maximize:hover {
    background: #27c93f;
    border-color: #1aab29;
    color: #004d11;
}

/* 2. Windows 11 Fluent Theme */
.theme-windows .btn-titlebar,
.theme-fluent .btn-titlebar,
.theme-fluent_light .btn-titlebar,
.theme-fluent_dark .btn-titlebar {
    width: 44px;
    height: 28px;
    border-radius: 0;
    border: none;
    background: transparent;
    color: inherit;
    font-size: 11px;
    font-weight: 300;
    transition: background-color 0.15s ease;
}

.theme-windows .btn-titlebar:hover,
.theme-fluent .btn-titlebar:hover,
.theme-fluent_light .btn-titlebar:hover,
.theme-fluent_dark .btn-titlebar:hover {
    background: rgba(128, 128, 128, 0.2);
    box-shadow: none;
    border: none;
}

.theme-windows .btn-titlebar.btn-close:hover,
.theme-fluent .btn-titlebar.btn-close:hover,
.theme-fluent_light .btn-titlebar.btn-close:hover,
.theme-fluent_dark .btn-titlebar.btn-close:hover {
    background: #c42b1c;
    color: #ffffff;
    border: none;
    box-shadow: none;
}

/* 3. Linux / GNOME Circular Flat Theme */
.theme-linux .btn-titlebar,
.theme-gnome .btn-titlebar {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.15);
    color: inherit;
    font-size: 11px;
    margin: 0 3px;
    transition: background-color 0.2s ease;
}

.theme-linux .btn-titlebar:hover,
.theme-gnome .btn-titlebar:hover {
    background: rgba(255, 255, 255, 0.3);
    box-shadow: none;
}

.theme-linux .btn-titlebar.btn-close:hover,
.theme-gnome .btn-titlebar.btn-close:hover {
    background: #e01b24;
    color: #ffffff;
}

/* A minimised window is its titlebar and nothing else. It still renders --
   dropping it from the page would leave no way to restore it, which is not
   what minimising means. */
.nextxbase-window.wnd-minimized > .nextxbase-slot-menubar,
.nextxbase-window.wnd-minimized > .nextxbase-slot-toolbar,
.nextxbase-window.wnd-minimized > .nextxbase-slot-workspace,
.nextxbase-window.wnd-minimized > .nextxbase-slot-footer {
    display: none !important;
}

.nextxbase-window.wnd-minimized {
    height: auto !important;
    min-height: 0 !important;
}

/* The lock cells take a click (the classic do), so they have to look like it. */
.msgbar-cell.msgbar-keyboard {
    cursor: pointer;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* ========================================================================== */
/* 3. Form Controls — Dark-on-Light Premium Design                            */
/* ========================================================================== */

/* TSAY Label — Crisp Dark Text on Light */
.nextxbase-say {
    /* A SAY IS OPAQUE, because a Win32 static ERASES its rectangle before it
       draws. That is not decoration -- it is what makes a later control hide an
       earlier one, and the reference sample depends on it everywhere:
       `8 CENTER` is invisible in the reference implementation because `9 RIGHT`'s 400px box covers
       it; the COLOR yellow stops at x=97 because `11 FONT`'s box covers the
       rest of it; and 14/15/16 read as one clean line because each erases the
       tail of the one before. Ours were transparent, so every overlapping
       caption showed through every other and the page turned to mush.

       `inherit` rather than a literal: it takes the container's own computed
       background, so this stays correct in every theme and on a panel with its
       own colour. An explicit COLOR clause is emitted inline and still wins. */
    background-color: inherit;

/* WEIGHT AND TRACKING BOTH CAME OFF, AND BOTH ARE FIDELITY.

       font-weight was 600. A the reference implementation SAY draws in the container's font at its
       normal weight -- bold is something the application ASKS for with a FONT
       clause, and an application cannot ask for not-bold once we have decided
       for it. Against the reference this is what reads as "not the reference implementation" across
       a whole form at a glance.

       letter-spacing was 0.3px, and tracking is WIDTH, not style: over a
       20-character label it is 6px the reference does not have, accumulating
       rightward, so a label column that starts aligned ends misaligned and the
       cause looks like a column-step defect. The cell table is trying to hold
       that axis still; this was quietly editing it. */
    font-weight: 400;
    color: #1a1814;
    display: inline-flex;
    display: -ms-inline-flexbox;
    align-items: center;
    -ms-flex-align: center;
    box-sizing: border-box;
    white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────── */
/* TGET Input — Recessed White Well with Gold Focus Ring           */
/* ─────────────────────────────────────────────────────────────── */
.nextxbase-get {
    background: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.18);
    /* SQUARE, for the reason `.nextxbase-btn` already states: the palette is
       ours to choose and the SHAPE is not. A 6px radius draws a lozenge where
       the reference draws a square-cornered control, and corner radius decides
       where the ink lands -- geometry, not paint. Visible in the cropped combo
       comparison as the single loudest difference, ahead of the arrow glyph. */
    border-radius: 0;
    /* NO VERTICAL PADDING -- IT WAS EATING THE TEXT.
       `6px 12px` in a control 19px tall left 19-2-12 = 5px of content box for
       a 14px font, so every GET on the grid probe rendered with its glyphs
       sliced top and bottom -- on a page whose every COORDINATE matched the
       reference exactly. The reference fits the same string in the same 19px
       because a native Edit reserves ~1px vertically, not 6.

       Zero rather than merely smaller: any FIXED vertical padding is wrong at
       some height, and the height is precisely what varies. At zero the
       browser centres the text in whatever box was declared, which is what
       the native control does and what makes 19px and 40px both correct.
       Horizontal padding stays -- it costs width that is usually generous and
       it keeps the text off the border. */
    padding: 0 10px;
    color: #1a1814;
    /* A GET DRAWS IN THE CONTAINER'S FONT, NOT A TYPEWRITER ONE. This said
       Consolas/JetBrains Mono, and in the aligned-form shot it is the single
       most obviously non-native thing on the page -- "Ridgeway Instruments" in
       a monospace face beside a reference that renders it proportional.

       No geometry moves: a GET's extent comes from its declared SIZE, never
       from its text, which is why the face can change in the same pass as the
       SAY weight without disturbing the measured cells. */
    font-family: 'Segoe UI', 'Outfit', system-ui, -apple-system, sans-serif;

line-height: normal;
    outline: none;
    box-sizing: border-box;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06);
}

.nextxbase-get:hover {
    border-color: #b8942a;
}

/* THE BUTTON-GET WRAPPER AND ITS BUTTON, WHICH NO THEME COULD REACH UNTIL
   NOW.  A GET carrying an ACTION or a BITMAP renders as a bordered wrapper
   around a borderless input plus a button, and every declaration on both of
   those elements was emitted INLINE -- so `.nextxbase-btnget-wrap` and
   `.nextxbase-btnget-btn` grepped ZERO in this file while the three glass
   themes turned every other input into a blurred pill and left this one a
   flat #7a756c frame.

   THE SELECTORS ARE BARE ON PURPOSE.  A bare class is (0,1,0) and loses to
   a theme's `.theme-x .foo` at (0,2,0), which is the entire point; putting
   these on a longer selector would out-specify every theme and reproduce
   the defect one layer down.

   THE VALUES ARE THE ENGINE DEFAULTS THEY REPLACE, BYTE FOR BYTE, so an
   unthemed page is unchanged.  The renderer now calls NXB_UiCss rather than
   NXB_UiCssDef for these, which emits nothing when the application has set
   no key -- so an application that DOES set one still wins inline, and
   ground rule 7 is preserved.

   THE INNER INPUT IS DELIBERATELY NOT HERE.  Its border:none must beat a
   theme rule on .nextxbase-get or the wrapper's frame and the theme's would
   both paint -- see the comment at its emit site in classes/controls.prg. */
.nextxbase-btnget-wrap {
    border: 1px solid #7a756c;
    border-radius: 3px;
    background: #fff;
}

.nextxbase-btnget-btn {
    padding: 0 6px;
    background: #e2e8f0;
    border: none;
    border-left: 1px solid #cbd5e1;
}

.nextxbase-get:focus {
    border-color: #b8942a;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(184, 148, 42, 0.15), 0 0 8px rgba(184, 148, 42, 0.1);
}

/* ─────────────────────────────────────────────────────────────── */
/* TBUTTON — the reference's visual WEIGHT, 2026 surface treatment  */
/* ─────────────────────────────────────────────────────────────── */
/* THIS WAS NEAR-BLACK WITH GOLD LETTERS, AND IT WAS THE HEAVIEST THING ON
   THE PAGE. The grid probe made it plain: two buttons reading as solid black
   bars while every other control is a light outline. The reference's button
   is a light face, a thin border and dark text -- about the same weight as a
   GET sitting next to it, which is what lets a form of forty controls read as
   a form instead of a row of banners.

   The 2026 treatment does the work that costs no SPACE: a subtle vertical
   gradient because light falls from above, a crisp hairline, a real pressed
   state, and the gold kept as an ACCENT on hover, focus and DEFAULT rather
   than as the resting colour. The brand becomes emphasis instead of default.

   None of the GEOMETRY below moves -- radius 0, no cast shadow, padding 0,
   flex centring. Each carries a recorded measurement and re-opening them
   would be re-litigating settled evidence. */
.nextxbase-btn {
    background: #f4f2ee;
    background: linear-gradient(to bottom, #fbfaf8 0%, #f1efea 100%);
    border: 1px solid #c3bcae;
    /* A BUTTON IS A RECTANGLE. This was 10px, which drew a lozenge where the
       reference draws a square-cornered control. The palette is ours to
       choose; the SHAPE is not -- corner radius decides where the ink lands,
       which makes it geometry rather than paint. */
    border-radius: 0;
    color: #23201b;
    font-family: 'Segoe UI', 'Outfit', system-ui, sans-serif;
    /* NORMAL WEIGHT, for the same reason the SAY label is: the reference
       draws a caption at the container's weight, and the aligned form shows
       ours bold against a regular reference on the same line. */
    font-weight: 400;

/* LETTER-SPACING IS GEOMETRY WEARING A TYPOGRAPHIC HAT. This was 0.6px,
       which widens every caption -- and on a button the application sized to
       its text, that is width taken from a budget already spent. The native
       control adds none, so any positive value makes our captions fit where
       the reference's do not, or clip where the reference's do not. */
    letter-spacing: 0;
    cursor: pointer;
    transition: all 0.3s ease;
    /* NO CAST SHADOW. Three stacked shadows spread 16px below the control,
       and measured against the reference that turned a declared SIZE 90,26
       into 93x34 of actual ink against the reference's 90x27.

       box-shadow does not affect LAYOUT, which is exactly why this survived:
       every coordinate was correct and the control still painted 7px outside
       its own rectangle. A control's visible extent is what decides whether
       it collides with its neighbour, so this made our pages read tighter
       than the reference at identical declarations -- and no amount of
       checking the emitted coordinates could have shown it. Only the picture
       could. */
    box-shadow: none;
    box-sizing: border-box;
    /* A DECLARED SIZE IS THE WHOLE CONTROL. This was `padding: 6px 16px`,
       which takes 32px out of a 92px button -- and with `overflow: hidden`
       the caption was then clipped SILENTLY: "Move &Up" emitted correctly as
       `Move <u>U</u>p` and rendered as "Move". the reference implementation centres the caption in
       the rect and adds nothing, so any padding here is subtracted from what
       the application asked for. Same defect as the dialog body's padding,
       one control down.

       Flex centring uses the full declared width instead, in both axes, which
       is what the native control does. */
    padding: 0;
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    position: relative;
    overflow: hidden;
}

/* A button with NO declared size has no application intent to violate, and
   its caption must not touch the border. Padding is restored only there. */
.nextxbase-btn:not([style*="width"]) {
    padding: 6px 16px;
}

/* The caption as ONE flex item. Without this wrapper the button inline
   content becomes SEPARATE flex items -- "Move " / <u>U</u> / "p" -- and
   whitespace BETWEEN flex items is discarded, so "Move &Up" rendered as
   "MoveUp" while "Move D&own" survived (its space is interior). Inline,
   so spaces inside the caption stay ordinary text. */
.nxb-cap {
    /* CENTRED BY POSITION, NOT BY FLEX DISTRIBUTION.

       The button carries justify-content:center and overflow:hidden, which is
       the right construction and works everywhere except where it must: IE11
       -- the document mode the desktop shell runs in -- does not keep an
       OVERFLOWING flex item centred, it aligns it to the start. So the
       centring applied to every caption that fits and abandoned exactly the
       case it existed for.

       Photographed against the reference, both declared SIZE 90,26 with a
       caption far too long:

           reference   "...tion that fills its..."   the MIDDLE
           ours        "5 a caption t"                the START

       Absolute centring is width-independent: the caption overflows both
       edges equally and overflow:hidden clips it symmetrically, which is what
       the reference shows. transform is IE9+, so it holds in the shell.

       STILL ONE ELEMENT with white-space:nowrap -- that is what fixed
       "Move &Up" rendering as "MoveUp". Without the wrapper the button's
       inline content became separate flex items, and whitespace BETWEEN flex
       items is discarded. The caption's spaces are interior text either way. */
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    white-space: nowrap;
}

/* An UNSIZED button has no declared rect to centre inside -- it shrink-wraps
   its caption -- so it keeps ordinary flow and the padding restored above. */
.nextxbase-btn:not([style*="width"]) .nxb-cap {
    position: static;
    transform: none;
    -ms-transform: none;
}

.nextxbase-btn:active {
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.08);
    background: #1a1814;
}

/* ─────────────────────────────────────────────────────────────── */
/* TCHECKBOX — Checkbox & Label                                    */
/* ─────────────────────────────────────────────────────────────── */
.nextxbase-chk,
.nextxbase-checkbox {
    width: 16px;
    height: 16px;
    cursor: pointer;
    vertical-align: middle;
    margin-right: 6px;
}

.nextxbase-chk-label {
    display: inline-block;
    /* THE CAPTION CLIPS AT THE BOX, it does not wrap or spill. The reference
       draws "Bound checkbox" in a 100px default box as "Bound checkbc"
       (measured 2026-09-02); a label that grew to its text would be a
       different control. */
    white-space: nowrap;
    overflow: hidden;
    box-sizing: border-box;

/* A CHECKBOX PROMPT IS A LABEL. Same argument as `.nextxbase-say` and the
       button caption: the reference draws it at the container's weight, and
       an application cannot ask for not-bold once we have decided. */
    font-weight: 400;
    color: #1a1814;
    cursor: pointer;
}

/* ─────────────────────────────────────────────────────────────── */
/* TCOMBOBOX — Clean White Select with Gold Focus                  */
/* ─────────────────────────────────────────────────────────────── */
.nextxbase-cbo {
    background: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.18);
    /* SQUARE, for the reason `.nextxbase-btn` already states: the palette is
       ours to choose and the SHAPE is not. A 6px radius draws a lozenge where
       the reference draws a square-cornered control, and corner radius decides
       where the ink lands -- geometry, not paint. Visible in the cropped combo
       comparison as the single loudest difference, ahead of the arrow glyph. */
    border-radius: 0;
    color: #1a1814;
    font-family: 'Segoe UI', 'Outfit', system-ui, sans-serif;

/* THE CLOSED HEIGHT IS THE FONT'S CELL PLUS THIS FRAME. A native combo
       does not take the declared SIZE height when closed -- that is the
       dropped list -- it is its font cell with the edit's 3px margin and the
       1px frame above and below: the reference measures 28 logical for
       Georgia -17 (cell 20 + 8) and 23 for its default font (15 + 8). The
       renderers emit NO height for a dropdown, so these two numbers, over
       line-height:normal, are what produce it -- components, not a constant.
       (The GET above has ZERO vertical padding for the opposite reason: a
       GET's height IS declared, and fixed padding was slicing its glyphs.)
       THE HORIZONTAL HALF WAS 8px AND NOTHING MEASURED IT. A native
       drop-down list insets its text ~3px inside the frame and the <select>
       adds its own inline indent on top, so 8 a side cost 16px of a width
       the APPLICATION chose: FiveDBU's unsized Type combo (the reference's
       fixed 80) kept 44px for text and clipped "Character" (51px) to
       "Characte" (2026-09-12).
       AND THE VERTICAL 3px CLIPPED EVERY DESCENDER. 23px border-box minus
       2 frame minus 6 padding leaves 15px, and Chrome's line box for 12px
       Segoe UI is 16 (ascent 13, descent 3, measured) -- so FiveDBU's
       Preferences drew "English" as "Enqlish". The HEIGHT is the
       reference's and stays; only the inset inside it shrinks to 2px,
       which is 17px of content and every glyph whole. */
    padding: 2px;
    line-height: normal;
    /* THIS RULE HAD NO box-sizing AT ALL, WHICH THE GET HAS HAD ALL ALONG.
       A declared SIZE 130 therefore rendered 130 + 24 padding + 2 border =
       156px: 20% wider than asked for and 20% wider than the reference's
       measured 130. The emitted markup says width:130px, so the defect is
       invisible in the HTML and invisible to any position test -- it shows
       only as a control quietly overlapping its neighbour. */
    box-sizing: border-box;
    outline: none;
    cursor: pointer;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06);
}

.nextxbase-cbo:hover {
    border-color: #b8942a;
}

.nextxbase-cbo:focus {
    border-color: #b8942a;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06), 0 0 0 3px rgba(184, 148, 42, 0.15);
}

/* Gold as ACCENT, not as resting colour -- and THE ONLY :hover rule for
   this class, which it was not until 2026-09-03. A second one above it
   dressed the button for a near-black face: background:#2a2720 with
   color:#f0d060. Same specificity, so the later rule won PER PROPERTY --
   this one supplied the white face and that one went on supplying the
   gold ink, and every button in the product painted gold on white at
   1.42:1 on hover. Measured on the painted pixels, not derived. Both
   rules read correctly on their own, which is why it survived: the defect
   existed only in the merge. DO NOT ADD A SECOND :hover RULE FOR THIS
   CLASS -- extend this one, exactly as the #xcommand rule requires.
   The glow below is the dead rule's, kept because it is wanted; its face
   and its ink are not. */
.nextxbase-btn:hover {
    /* NO background HERE, and that is the second half of the same
       defect. Repainting the FACE white while leaving the ink alone
       breaks every control whose ink is light: the theme chips carry a
       dark face with #d0ccc4 text, and a white hover face put that text
       at 1.50:1 -- measured on the pixels after the gold was removed.
       An accent that only ever ADDS (border, glow) cannot be wrong on a
       face it has not seen, which is the difference between fixing this
       button and fixing the rule. */
    border-color: #b8942a;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

/* A REAL PRESSED STATE. The face darkens and the highlight inverts, so the
   control reads as pushed IN rather than merely recoloured -- and it uses an
   INSET shadow, which does not paint outside the declared rect the way the
   cast shadow removed above did. */
.nextxbase-btn:active {
    background: #ebe7df;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.18);
}

.nextxbase-btn:focus {
    outline: none;
    border-color: #b8942a;
    box-shadow: 0 0 0 2px rgba(184, 148, 42, 0.25);
}

.nextxbase-btn:disabled,
.nextxbase-btn[disabled] {
    color: #9a958c;
    background: #f2f0ec;
    border-color: #d8d2c6;
    cursor: default;
}

/* DEFAULT FINALLY HAS AN APPEARANCE. TBUTTON has always stored lDefault and
   emitted data-default='1', and nothing has ever styled it -- a clause living
   in the object model, faithfully written into the markup, invisible on
   screen. The reference marks its default button with a heavier edge; ours
   gets the gold one, which is both the faithful behaviour and the modern
   idiom. */
.nextxbase-btn[data-default='1'] {
    border-color: #b8942a;
    box-shadow: inset 0 0 0 1px rgba(184, 148, 42, 0.35);
}

/* ─────────────────────────────────────────────────────────────── */
/* TPROGRESS — Native <progress> Element Styling                   */
/* ─────────────────────────────────────────────────────────────── */
progress.nextxbase-progress {
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 0;
    background: #eceae5;
    overflow: hidden;
}

/* Div-based progress fallback */
.nextxbase-progress {
    background: #eceae5;
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 0;
    overflow: hidden;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.08);
    position: relative;
}

.nextxbase-progress-bar {
    background: #b8942a;
    border-radius: 0;
    height: 100%;
    position: relative;
}

/* ─────────────────────────────────────────────────────────────── */
/* TGROUP (fieldset) — Elevated White Card with Gold Thread         */
/* ─────────────────────────────────────────────────────────────── */
.nextxbase-group {
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 0;
    /* A WHITE CARD, AND UNTIL 2026-09-05 NO THEME COULD REACH IT -- zero theme
       rules named .nextxbase-group while every dark theme painted the WINDOW
       behind it. So under charcoal, onyx, nord and fluent_dark a group stayed
       a white panel, and every label a theme paints light for dark chrome went
       invisible ON it. See the themed rule below. */
    background: #ffffff;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), 0 4px 8px rgba(0, 0, 0, 0.06), 0 8px 16px rgba(0, 0, 0, 0.04);
    position: relative;
    padding: 16px;
    margin: 0;
}

/* THE DARK THEMES' MISSING SURFACE, MEASURED WITH --pixels ON full_showcase.
   The computed-style pass reported ZERO unreadable text; the PAINTED pixels
   reported SIXTEEN, every one the same shape:

       rgb(248, 250, 252) on rgb(255, 255, 255)   1.05:1
       'User Name:' 'Account No:' 'Role Level:' 'Sync Status:'
       x charcoal, fluent_dark, nord, onyx

   The two passes disagree because a control is NOT a DOM DESCENDANT of the
   group it sits on -- this engine positions controls absolutely as SIBLINGS,
   so `group.contains(say)` is false while their rectangles overlap. Compositing
   DOM ancestors finds the dark WINDOW; the pixel behind the glyph is the
   group's white card. The capture wins, which is the rule this project already
   states for any disagreement between a derivation and a measurement.

   A TRANSLUCENT FILM RATHER THAN A COLOUR PER THEME, so the panel reads as
   raised on whatever ground the theme paints and no fifth colour has to be
   invented and kept in step. It is the idiom the dark .nextxbase-window rules
   already use for their own borders (rgba(255,255,255,0.12)).

   NO !important: `.theme-x .nextxbase-group` is two classes against the base
   rule's one, so it wins on specificity -- and an APPLICATION's own inline
   background still outranks it, which is the cascade order ground rule 7 asks
   for and is why this must not be forced. */
.theme-liquid-glass .nextxbase-group,
.theme-onyx .nextxbase-group,
.theme-fluent_dark .nextxbase-group,
.theme-nord .nextxbase-group,
.theme-charcoal .nextxbase-group,
.theme-onyx.control-theme-onyx.nextxbase-group,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-group,
.theme-nord.control-theme-nord.nextxbase-group,
.theme-charcoal.control-theme-charcoal.nextxbase-group {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.14);
    box-shadow: none;
}

/* AND THE CONTAINER UNDER IT, WHICH IS WHY THE RULE ABOVE DID NOT REACH FAR
   ENOUGH. ba1d36f9 says so in its own words -- 'the container ABOVE it is
   unthemed too' -- and bb3238d5 names the next step and stops: the folder
   page.

   A GROUP SITS ON A FOLDER PAGE, AND THAT PAGE IS OPAQUE WHITE IN EVERY
   THEME. Not from this stylesheet -- window.prg emits a <style> block
   carrying `.nextxbase-folder { ... background:#ffffff }` and the same for
   .nextxbase-tab-body -- which is why grepping here for a folder background
   finds nothing and why no theme had ever reached it. A 6% white film over
   white is still white, so the group card stayed light under a dark theme
   and the theme's near-white ink landed on it.

   MEASURED on dashboard2, --pixels, 1275 of 1275 judged: eleven elements
   under onyx between 1.41 and 1.96 -- four SAY captions, two checkbox
   prompts, three radio labels and two legends -- every one of them on a
   ground of rgb(174..196), which is white seen through two films.

   A DARKENING FILM, NOT A COLOUR, so no per-theme value is invented and the
   glass idiom the themes are built on survives. rgba(0,0,0,0.35) over the
   stage's darkest ground rgb(15,23,42) gives 17:1 for #f8fafc and over a
   BRIGHT caustic (~rgb(60,120,170)) still gives 8.3:1 -- which is the point:
   a thin white film varies with whatever gradient is beneath it, and a
   darkening one cannot go light. That variance is what made the group card
   neither light enough nor dark enough for either ink.

   Specificity carries it: `.theme-x .nextxbase-folder` is two classes
   against the emitted rule's one, so no !important is needed and an
   application's own inline background still outranks it. */
.theme-liquid-glass .nextxbase-folder,
.theme-onyx .nextxbase-folder,
.theme-fluent_dark .nextxbase-folder,
.theme-nord .nextxbase-folder,
.theme-charcoal .nextxbase-folder,
.theme-liquid-glass .nextxbase-tab-body,
.theme-onyx .nextxbase-tab-body,
.theme-fluent_dark .nextxbase-tab-body,
.theme-nord .nextxbase-tab-body,
.theme-charcoal .nextxbase-tab-body,
.theme-onyx.control-theme-onyx.nextxbase-folder,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-folder,
.theme-nord.control-theme-nord.nextxbase-folder,
.theme-charcoal.control-theme-charcoal.nextxbase-folder,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-tab-body,
.theme-onyx.control-theme-onyx.nextxbase-tab-body,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-tab-body,
.theme-nord.control-theme-nord.nextxbase-tab-body,
.theme-charcoal.control-theme-charcoal.nextxbase-tab-body {
    background: rgba(0, 0, 0, 0.35);
    border-color: rgba(255, 255, 255, 0.14);
}

/* THE LEGEND TAKES THE GROUP'S OWN INK ON A DARK THEME, and `inherit` is
   the answer rather than a gold because the ground under it CANNOT BE
   PINNED. Measured on dashboard2 under onyx, walking the legend's ancestors:
   between the text and the first opaque surface there are FOUR translucent
   layers and TWO gradient images --

       group film   rgba(255,255,255,0.06)
       dialog       rgba(30,41,59,0.48)  + background-image
       folder page  rgba(0,0,0,0.35)     (the rule above)
       window       rgba(30,41,59,0.48)  + background-image
       stage        rgb(15,23,42)        + background-image

   so the composite depends on WHERE on the page the legend sits. Three
   legends on one page, one theme: rgb(59,70,85), rgb(92,100,111) and
   rgb(123,129,136).

   THAT IS WHY A GOLD CANNOT DO IT, and the value was checked rather than
   assumed. #d4af37 -- the gold ba1d36f9 chose and bb3238d5 took back out --
   clears the two darker grounds at 4.53 and 2.84 and measures 1.87 on the
   lightest. Under the bar. A brighter gold would clear it and would be a
   THIRD value invented to fit one measurement, which is what bb3238d5's own
   comment asks the next reader not to do.

   The group already carries a correct ink for its own film -- the theme put
   #f8fafc there -- so the legend asks for it instead of restating it: 3.77:1
   on the worst of those three grounds, and a theme added later is covered
   without touching this. Same answer, same reason, as the dialog caption.

   WHAT IT COSTS, said plainly: on a DARK theme the legend is no longer gold.
   The accent survives everywhere the card is actually a white card -- the
   base #8a6f1f rule is untouched and light themes are unmoved. A gold nobody
   can read is not an accent. */
.theme-liquid-glass .nextxbase-group-legend,
.theme-onyx .nextxbase-group-legend,
.theme-fluent_dark .nextxbase-group-legend,
.theme-nord .nextxbase-group-legend,
.theme-charcoal .nextxbase-group-legend,
.theme-liquid-glass .nextxbase-group-caption,
.theme-onyx .nextxbase-group-caption,
.theme-fluent_dark .nextxbase-group-caption,
.theme-nord .nextxbase-group-caption,
.theme-charcoal .nextxbase-group-caption,
.theme-onyx.control-theme-onyx.nextxbase-group-legend,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-group-legend,
.theme-nord.control-theme-nord.nextxbase-group-legend,
.theme-charcoal.control-theme-charcoal.nextxbase-group-legend,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-group-caption,
.theme-onyx.control-theme-onyx.nextxbase-group-caption,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-group-caption,
.theme-nord.control-theme-nord.nextxbase-group-caption,
.theme-charcoal.control-theme-charcoal.nextxbase-group-caption {
    color: inherit;
}

/* NO PER-THEME GOLD FOR THE LEGEND, AND THE REASON IS ARITHMETIC RATHER THAN
   TASTE. A rule painting it #d4af37 under the dark themes stood here for
   twenty minutes: it fixed ONE red on full_showcase (onyx, 1.44:1) and caused
   TWELVE on dashboard2, whose groups sit on a FOLDER PAGE that is
   rgb(241,241,241) under every theme -- so the dark-chrome gold landed on a
   light ground at 1.85:1. Measured with --pixels both ways.

   NO SINGLE GOLD SPANS BOTH GROUNDS. Against onyx's group film rgb(73,91,116)
   the base #8a6f1f is 1.37:1 and #d4af37 is 3.25:1; against the folder page
   rgb(241,241,241) #8a6f1f is 4.4:1 and #d4af37 is 1.85:1. A constant cannot
   satisfy both because the GROUND varies, and it varies because
   `.nextxbase-dialog.is-folder-page` is itself an unthemed light surface --
   the same family as .nextxbase-group was, one container further out.

   So the base #8a6f1f stands and full_showcase keeps ONE onyx red, which is
   the smaller number and the honest one. The fix is the folder page, not a
   third colour. */
.nextxbase-group-caption,
.nextxbase-group-legend {
    color: #8a6f1f;
    font-family: 'Segoe UI', 'Outfit', system-ui, sans-serif;
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.5px;
    padding: 2px 10px;
}

/* ========================================================================== */
/* TDIALOG — Premium Modal                                                    */
/* ========================================================================== */
/* THE DIALOG FACE IS MEASURED, NOT STYLED.

   Sampled 2026-09-03 off a DPI-aware capture of the reference build, at the
   left edge of MayaPOS's camareros dialog: the corner pixel is square (227
   grey, no rounding at all), the edge is a few pixels of light shading and
   the face behind the controls is 240,240,240. Ours was a white face, a
   1px rgba(0,0,0,0.10) hairline and a 14px radius -- which is what the
   owner was looking at when they said there is no code anywhere asking for
   rounded dialog corners. There was: this rule.

   The soft multi-stop edge Windows themes draw is not reproduced; one solid
   line at one logical pixel is the honest simplification and it is what the
   eye reads at this size. The shadow stays, much lighter: the reference's
   dialog does carry a DWM drop shadow.

   A THEME CAN PUT THE ROUNDING BACK -- this is a stylesheet rule, which is
   where a default belongs, not an inline literal on the element. */
.nextxbase-dialog {
    /* THE INK IS HERE BECAUSE THE GROUND IS. A dialog that paints #f0f0f0 and
       states no colour leaves every caption inside it inheriting whatever the
       THEME put on the window -- near-white on a dark theme, onto this light
       ground. Measured 2026-09-05 on ctllab across all 15 themes: six
       .nextxbase-say at 1.09:1 under onyx and liquid-glass, rgb(248,250,252)
       on rgb(240,240,240).

       THIS IS NOT THE `.nextxbase-radio` MISTAKE ONE FILE UP, and the
       difference is the whole rule: an ink WITHOUT a ground defeats every
       theme, because a theme paints by setting `color` on an ancestor and
       inheritance loses to specificity. An ink WITH a ground is one decision
       stated once -- a theme that restyles this dialog overrides both together,
       and every theme rule here is already !important.

       So: a control that paints NO ground must state NO ink. A control that
       paints its OWN ground must state its own ink. Never one of the two. */
    background: #f0f0f0;
    color: #1a1814;
    border: 1px solid #a0a0a0;
    border-radius: 0;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
    display: flex;
    display: -ms-flexbox;
    flex-direction: column;
    -ms-flex-direction: column;
    box-sizing: border-box;
    z-index: 1000;
    overflow: hidden;
    position: relative;
}

/* A DIALOG THAT IS A FOLDER PAGE IS CONTENT, NOT A FLOATING WINDOW, SO IT MUST
   NOT CLAIM THE MODAL STACKING LEVEL.

   Measured on HbBuilder 2026-09-14, from the owner's report that a menu
   "overflows under the second buttonbar": the File menu paints correctly over
   both toolbars and then disappears the moment it reaches the workspace.
   elementFromPoint at the popup's own centre answers
   `DIV.nextxbase-dialog-body`, inside `dlg_000153.nextxbase-dialog.is-folder-page`
   at z-index 1000.

   The slot ladder above is right and was not the defect: menubar 90 beats
   toolbar 80, both positioned so the Windows 7 floor obeys them. What beat it
   is a DESCENDANT of the workspace -- and the workspace deliberately carries no
   z-index of its own (see .nextxbase-slot-workspace, which explains at length
   why), so a page-hosted dialog's 1000 is not contained by anything and
   competes directly against the menubar's 90 in the window's context.

   1000 is the level a MODAL earns: a modal must cover the menu, and that stays
   exactly as it was. An embedded page is placed absolutely inside its own tab
   body by dialog.prg's `::lPage` arm and is the only child there, so it needs
   no stacking level at all -- `auto` leaves it painting in flow, below the
   engine's own chrome and above nothing it was ever meant to outrank.

   A CASE, NOT A FORK: one rule still decides what a dialog's stacking level is;
   the embedded case answers differently and rejoins the same cascade. */
.nextxbase-dialog.is-folder-page {
    z-index: auto;
}

.nextxbase-dialog-header {
    background: #faf8f5;
    padding: 14px 20px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.10);
    color: #1a1814;
    font-weight: 700;
    font-size: 15px;
    letter-spacing: 0.3px;
}

/* The dialog's close box (dialog.prg, the WS_SYSMENU arm). Positioned rather
   than making the header a flex row, so a header WITHOUT a box -- and its
   icon and caption -- lays out exactly as before. The right padding keeps a
   long caption from running under the box. */
/* The splash picture (MsgLogo). The SERVER emits this element -- veil, picture
   and an inline copy of the centring below -- as the first thing in the body,
   so it paints before the application does and these rules are what make it
   fade rather than what make it appear. Nothing here may be load-bearing for
   the overlay EXISTING: a page whose stylesheet did not arrive must still show
   the splash and still be able to get rid of it. Centred above everything and
   click-through; is-off is added to the class list by _bootFade. */
.nxb-msglogo {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    -ms-flex-pack: center;
    justify-content: center;
    z-index: 99999;
    pointer-events: none;
    opacity: 1;
    transition: opacity 0.45s ease;
}

.nxb-msglogo.is-off {
    opacity: 0;
}

.nxb-msglogo img {
    max-width: 90%;
    max-height: 90%;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}

.nextxbase-dialog-header.has-close {
    position: relative;
    padding-right: 52px;
}

.nextxbase-dialog-header .nextxbase-dialog-close {
    position: absolute;
    right: 12px;
    top: 50%;
    margin-top: -12px;
}

.nextxbase-dialog-body {
    /* NOT `flex: 1`. That is shorthand for `flex: 1 1 0%`, and the 0% is a
       FLEX-BASIS that REPLACES this element's own height in a column flex
       container -- so the height the emitter sets here (the declared client
       rectangle) was overridden to zero and the whole dialog collapsed to a
       single line. `0 0 auto` means: do not grow, do not shrink, take the
       basis from my own height. */
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    position: relative;
    /* NO PADDING. This box IS the client rectangle: control coordinates are
       measured from its top-left, so a pad both offsets every control and
       shrinks the area they have to fit in. It was 20px, which cost 40px on
       each axis and produced a scrollbar on essentially every replicated
       dialog. */
    padding: 0;
    /* The emitter now sizes this box to the declared client area, so content
       that still exceeds it is a REAL layout defect and must stay visible
       rather than being hidden behind a scroll. */
    overflow: visible;
    box-sizing: content-box;
}

/* ========================================================================== */
/* MsgInfo / MsgAlert — Premium Custom Message Dialogs                        */
/* No system dialogs. Custom. Emojis. Onyx button. Gold neon. Glass.          */
/* ========================================================================== */
.nextxbase-msgbox-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.35);
    z-index: 9999;
}

.nextxbase-msgbox {
    position: fixed;
    top: 50%;
    left: 50%;
    min-width: 380px;
    max-width: 480px;
    background: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 20px;
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.08), 0 12px 24px rgba(0, 0, 0, 0.06), 0 24px 48px rgba(0, 0, 0, 0.04);
    z-index: 10000;
    overflow: hidden;
    border-top: 3px solid #b8942a;
}

.nextxbase-msgbox-icon {
    font-size: 48px;
    text-align: center;
    padding-top: 28px;
    line-height: 1;
}

.nextxbase-msgbox-text {
    padding: 16px 32px 8px;
    text-align: center;
    font-size: 15px;
    font-weight: 500;
    color: #1a1814;
    line-height: 1.6;
}

.nextxbase-msgbox-title {
    padding: 0 32px 20px;
    text-align: center;
    font-size: 11px;
    font-weight: 600;
    color: #8a857a;
    letter-spacing: 1.5px;
    text-transform: uppercase;
}

.nextxbase-msgbox-actions {
    display: flex;
    display: -ms-flexbox;
    justify-content: center;
    -ms-flex-pack: center;
    padding: 8px 32px 28px;
}

/* The Crown Jewel — Onyx Pill Button + Gold Letters + Neon Border */
.nextxbase-msgbox-btn {
    background: #1a1814;
    border: 2px solid rgba(184, 148, 42, 0.6);
    border-radius: 50px;
    color: #d4af37;
    font-family: 'Segoe UI', 'Outfit', system-ui, sans-serif;
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.8px;
    padding: 10px 36px;
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.15), 0 8px 16px rgba(0, 0, 0, 0.1), 0 0 8px rgba(184, 148, 42, 0.12);
    position: relative;
    overflow: hidden;
}

.nextxbase-msgbox-btn:hover {
    border-color: #d4af37;
    color: #f0d060;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

/* ========================================================================== */
/* 3.1 MenuBar — Dark Onyx Shelf                                               */
/* ========================================================================== */
.nextxbase-menubar {
    background: #1a1814;
    border-bottom: 1px solid rgba(0, 0, 0, 0.15);
    padding: 0 8px;
    height: 32px;
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    position: relative;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}

.nextxbase-menu-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    display: -ms-flexbox;
    flex-direction: row;
    -ms-flex-direction: row;
}

.nextxbase-menu-item {
    position: relative;
}

/* NO font-size HERE. It used to say 13px, which is a DEFAULT for a menu and
   not a decision about this element -- and stated on the child it overruled the
   font the application declared on the bar, so `MENU oMenu FONT oFont` reached
   a strip with no text of its own and could never be seen. The default lives on
   the container now (see .nextxbase-menubar / .nextxbase-menu-popup below), so
   a declared font wins by ordinary cascade and an undeclared menu is unchanged. */
.nextxbase-menu-link {
    color: #d0ccc4;
    text-decoration: none;
    font-size: inherit;
    font-family: inherit;
    font-weight: inherit;
    padding: 4px 12px;
    border-radius: 6px;
    display: block;
    transition: all 0.15s ease;
}

.nextxbase-menu-link:hover {
    background: rgba(212, 175, 55, 0.15);
    color: #d4af37;
}

/* ========================================================================== */
/* 3.2 RibbonBar — Dark Onyx Panel (Contrast against Light Workspace)          */
/* ========================================================================== */
.nextxbase-ribbonbar {
    background: #1a1814;
    background: linear-gradient(to bottom, #221f18 0%, #1a1814 60%, #151310 100%);

    /* Dark panel meeting a light workspace. The old 15%-black border was
       invisible against a #1a1814 panel -- black on near-black -- so the
       ribbon ran into the client area with no boundary at all. Full-strength
       black hairline, then a light hairline under it on the workspace side:
       the groove is legible from either direction. */
    border-bottom: 1px solid rgba(0, 0, 0, 0.65);
    display: flex;
    display: -ms-flexbox;
    flex-direction: column;
    -ms-flex-direction: column;
    width: 100%;
    position: relative;

    /* The lifted top edge the other dark surfaces have. Without it the ribbon
       met the titlebar as one undifferentiated slab of near-black -- two
       components, no boundary, which is the same defect the bottom edge had
       before the groove went in. */
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08),
                0 1px 0 rgba(255, 255, 255, 0.75),
                0 3px 10px rgba(0, 0, 0, 0.14);
}

.nextxbase-ribbon-tabs {
    display: flex;
    display: -ms-flexbox;
    flex-direction: row;
    -ms-flex-direction: row;
    list-style: none;
    margin: 0;
    /* THE DEFAULT STRIP IS 26px, measured on the reference with a ribbon that
       declares no clauses at all (sizelab R01): its TRIBBONBAR sits at y=-1
       and its TRPANEL at y=25. An application that says TOPMARGIN overrides
       this inline -- see TRIBBONBAR:GenerateHTML.

       align-items:flex-end because the reference's caption sits at the BOTTOM
       of the strip: of its 26 rows, 16 are empty, the glyphs occupy 10, and
       one row is left beneath them. */
    height: 26px;
    box-sizing: border-box;
    align-items: flex-end;
    -ms-flex-align: end;
    padding: 0 8px;
    background: rgba(0, 0, 0, 0.15);
    border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}

/* #8a857a on #1a1814 is about 4:1 -- borderline for 13px text, and this is an
   application rather than a developer tool, so an inactive tab still has to be
   comfortably readable rather than merely present. */
.nextxbase-ribbon-tab {
    padding: 0 18px 1px;
    /* MEASURED against the vendor at 1:1, not chosen: its folder caption is
       15px of cap height where ours was 10, from a 13px font at a 0.77 cap
       ratio -- so 19px. The application states no font (it calls SetFont with
       an undefined variable, which passes NIL), so this is our default against
       the classic on the one surface whose purpose is to look like the classic. */
    /* 13px, which is a 10px cap at the 0.77 ratio the note below uses -- and
       10px is what the reference's tab caption MEASURES, read off the captured
       pixels at two independent ink thresholds (tallest glyph run 10px for the
       cap, 7px for the x-height letters).

       IT WAS 19px, and that figure came from measuring MAYAPOS, whose ribbon
       declares TOPMARGIN 52 -- a clause this engine stored and never read, so
       its strip could not grow past the stylesheet's fixed height. Enlarging
       the font is what you do to fill a strip that will not stretch. With
       TOPMARGIN honoured the compensation is no longer needed, and it was
       never right for a ribbon that declares nothing. */
    font-size: 13px;
    line-height: 16px;
    font-weight: 700;
    color: #b3ada1;
    cursor: pointer;
    border-top-left-radius: 6px;
    border-top-right-radius: 6px;
    transition: all 0.3s ease;

    /* AN UNSELECTED FOLDER CARRIES NO BOX, and this rule used to argue the
       opposite: the outline was on every tab on purpose, 'so the strip reads
       as a row of tabs rather than as a row of words that one of them happens
       to be highlighted in'. That is a fair argument about how a tab strip
       ought to look, and the reference does the other thing -- scanned across
       the captured strip at y=20 and y=45, the ONLY vertical border between
       x=60 and x=760 is the selected folder's right edge. The selection is
       marked by its raised white ground alone, which is what the .active rule
       further down already says in its own comment. Looking like the
       reference is the goal, so the measurement wins.

       The border is kept as transparent rather than dropped so the selected
       folder, which DOES have one, is the same size as its neighbours and the
       captions stay on one baseline. */
    border: 1px solid transparent;
    border-bottom: none;
    background: transparent;
    margin-right: 2px;
}

.nextxbase-ribbon-tab:hover {
    color: #d0ccc4;
    background: rgba(255, 255, 255, 0.05);
}

/* THE ACTIVE TAB JOINS THE PANEL. It carries the panel's own background and
   border, and is pushed down one pixel over the strip's bottom rule so the two
   become a single surface with a notch cut in it. That shared edge is what
   makes a tab a tab; a highlighted label is just a highlighted label. */
.nextxbase-ribbon-tab.active {
    color: #d4af37;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.055) 100%);
    border-color: rgba(255, 255, 255, 0.16);
    border-bottom: 1px solid transparent;
    margin-bottom: -1px;
    padding-bottom: 7px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}

/* One panel per tab is emitted and the inactive ones are hidden, so switching
   a ribbon tab needs no server round-trip. The base rule is display:none on
   purpose: a panel with no .active must never show, and defaulting the other
   way would put every tab's groups on screen at once -- which is exactly the
   behaviour this replaced. */
/* Switching tabs must not move anything below the ribbon, but the height that
   achieves that is the TALLEST TAB's -- which no stylesheet can know, because
   the inactive panels are display:none and contribute nothing to measure.
   nextxbase-engine.js measures them at startup and writes the maximum here as
   a min-height; this floor is only what applies before that runs and if a
   ribbon somehow has no panels at all. */
.nextxbase-ribbon-body {
    /* rgb(244,245,247) on the reference -- a near-white the cards sit on, and
       NOT the bar's nClrPaneRB, which is the strip above. */
    background: #f4f5f7;
    display: none;
    flex-direction: row;
    -ms-flex-direction: row;
    /* THE PANEL-TO-GROUP INSET IS 1px, measured off the reference's own
       child windows rather than chosen: its panel sits at (2, 25) and its
       group at (3, 26). This was `8px 12px`, which nothing in this file ever
       claimed was reference-derived, and it put every group 11px right and
       7px low before a single button was placed. */
    /* THE PANEL STARTS AT THE STRIP, with nothing between them. Measured:
       the reference's TRPANEL top is 25 and its TRBGROUP top is 26 -- a
       single pixel, which our group's own 1px border already supplies.
       Ours was contributing three: this padding-top, the border-top
       below, and that border. */
    /* 3px under the group, not 1: with the panel now filling the bar the
       group inherits its height, and the reference leaves 2.2 between the
       two -- its group ends at 224.0 inside a panel ending at 226.2. At
       1px ours came out 173 against 171.1. */
    padding: 0 3px 3px;
    align-items: stretch;
    -ms-flex-align: stretch;
    /* TALL ENOUGH FOR A LARGE BUTTON *AND* ITS GROUP CAPTION. This was 92,
       which is less than the content needs:

           body padding      8 + 8
           group padding     6 + 6
           btn-large        70
           caption          13 line + 3 padding-top + 4 margin-top
                          = 118

       and because `overflow-y: hidden` sits directly below, the 26px deficit
       was taken out of the CAPTION rather than shown as a scrollbar -- it
       rendered underneath the buttons, with only its border-top line visible
       beside them and a fragment of its text between them. A ribbon group that
       cannot show its caption is not a ribbon group; the caption is the whole
       difference between a group and a toolbar cluster. */
    min-height: 118px;
    box-sizing: border-box;
    overflow-x: auto;
    overflow-y: hidden;
}

.nextxbase-ribbon-body.active {
    display: flex;
    display: -ms-flexbox;
    /* THE PANEL FILLS THE BAR, leaving the reference's margin at the
       bottom. Measured on the reference MayaPOS, which declares
       HEIGHT 230:

           bar     -0.9 .. 230.2
           panel   52.0 .. 226.2     <- 4 short of the bar's bottom

       Ours stopped at 222 against a bar that now ends at 232, so ten
       pixels of empty bar sat under the cards. The bar is a column flex
       container and this child had no grow, so it stayed content-sized
       however tall the bar was told to be. Only meaningful once the bar
       HAS a declared height -- a content-sized bar has no slack to give,
       which is why R01 is unaffected. */
    flex: 1 1 auto;
    -ms-flex: 1 1 auto;
    margin-bottom: 4px;
}

/* The panel wears the same top rule the tab strip ends on, so the active tab's
   missing bottom edge lands on a continuous line rather than a gap. */
.nextxbase-ribbon-body {
    /* No border-top: the strip and the panel carry different backgrounds,
       so the boundary is already visible, and the reference draws no
       separator there -- its panel begins immediately below the strip. */
    background: rgba(255, 255, 255, 0.055);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* Groups are what a ribbon is FOR -- they are the reason the buttons are not
   just a toolbar -- and at 4% white on 6% white they were very nearly not
   there. Raised, and given the same two-line groove between them so the
   clusters are countable at a glance. */
/* A WHITE CARD. Measured on the reference: the group interior is
   rgb(255,255,255) against a rgb(244,245,247) panel, with a hairline edge --
   the cards are what make a ribbon read as grouped, and ours were the same
   colour as everything around them. The declared GRADIANT belongs to the
   buttons inside, not here. */
.nextxbase-ribbon-group {
    background: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 0;
    background: rgba(255, 255, 255, 0.075);
    border: 1px solid rgba(255, 255, 255, 0.11);
    border-radius: 0;
    /* Never shrink below the content: a flex child defaults to shrinking, so a
       row of groups wider than the bar squeezed them all instead of scrolling,
       and the buttons inside clipped rather than the strip overflowing. */
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    display: flex;
    display: -ms-flexbox;
    flex-direction: column;
    -ms-flex-direction: column;
    justify-content: space-between;
    -ms-flex-pack: justify;
    padding: 6px;
    /* THE GAP BETWEEN GROUPS IS 3px, measured on the reference MayaPOS --
       its groups sit at 3.1, 187.1, 371.1 with a width of 180.9, so the
       pitch is 184 and the gap 3.1. Ours was 13, giving a pitch of 193.

       9px per group does not sound like much and it ACCUMULATES: MayaPOS
       declares 16 groups, so the last one sat ~135px right of where the
       reference puts it. Same shape as the button pitch R01 found -- a
       per-item constant is never a per-item error. */
    margin-right: 3px;
    position: relative;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* A PLACED group draws no border -- it would move its absolutely positioned
   children -- so its boundary is an inset ring instead. This carries the
   engine default the renderer used to state inline, byte for byte, so an
   unthemed page is unchanged; it sits AFTER .nextxbase-ribbon-group because
   that rule sets a box-shadow of its own at the same specificity, and it is
   a BARE single-class selector so a theme's .theme-x rule at (0,2,0) can
   still take it. A longer selector here would out-specify every theme and
   reproduce the defect one layer down. */
.nxb-rbgroup-ring {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.11);
}

/* Same separation the browse headers get, and for the same reason: an offset
   box-shadow ran the full height of the group and read as a frame edge rather
   than as a gap between clusters. Inset 8px top and bottom, dark hairline then
   light, so it sits in the panel instead of on it.

   :not(:last-child) because a divider after the final group is a line against
   empty ribbon -- it looks like a group failed to render. */
.nextxbase-ribbon-group:not(:last-child)::after {
    content: '';
    position: absolute;
    right: -7px;
    top: 8px;
    bottom: 8px;
    width: 0;
    border-left: 1px solid rgba(0, 0, 0, 0.55);
    border-right: 1px solid rgba(255, 255, 255, 0.08);
    pointer-events: none;
}

/* STRETCH, so a large button can match the tallest in the row and the labels
   line up. Every child that is NOT auto-height opts back out with align-self,
   which is what keeps a fixed-height small button vertically centred instead of
   pinned to the top of a tall group. */
.ribbon-group-content {
    /* THE POSITIONING CONTEXT for a button that declared `@ nRow,
       nCol`. The padding below is still the fallback for the short
       form, which has no coordinates; a placed button anchors here
       instead, at the number the application wrote. */
    position: relative;
    /* THE DECLARED INSET. MayaPOS writes `@ 15, 15 ADD BUTTON` inside a group
       of WIDTH 180, so the button's ground is inset and the card frames it --
       measured on the reference, the card corner is rgb(255,255,255) and the
       tan begins well inside it. Flex ignores the coordinates, so the inset is
       expressed as padding; without it the button reaches the card's edge and
       the whole tile reads as the button's colour. */
    padding: 6px;
    display: flex;
    display: -ms-flexbox;
    flex-direction: row;
    -ms-flex-direction: row;
    align-items: stretch;
    -ms-flex-align: stretch;
    /* 1 0 auto, NOT 1 -- AND THE BASIS IS THE WHOLE DEFECT.

       `flex: 1` expands to `flex: 1 1 0%`, and a flex-basis of ZERO means this
       row contributes NOTHING to its group's natural height: the group sized
       itself from the caption alone, so the buttons inside had no say in how
       tall their own group was. That is why every measurement came back short
       -- 54, then 110, against a genuine need of ~145 -- and why a three-line
       card spilled straight over the group caption. The containers were all
       obeying a natural height that had the buttons priced at zero.

       With basis auto the row's real content height counts, so the tallest
       card sets the group, the group sets the panel, and the sizing pass
       measures a number that means something. grow stays 1 so a short group
       still fills a panel that has been equalised to a taller tab; shrink is 0
       so nothing can collapse it again. */
    flex: 1 0 auto;
    -ms-flex: 1 0 auto;
}

/* 11px uppercase at #7a756c was the lowest-contrast text in the whole chrome,
   and it is the label that says what the cluster of buttons IS. */
.ribbon-group-caption {
    font-size: 11px;
    font-weight: 600;
    color: #a8a196;
    text-align: center;
    /* NO text-transform. The caption is the application's own string --
       MayaPOS writes "Trabajando con Camareros..." and this rule rendered it
       as shouting, which is a different caption rather than a different
       style. The vendor draws the characters in the source. letter-spacing
       went with it: 0.8px was tuned for a three-word English label and pulls
       a full sentence apart. */
    margin-top: 4px;
    border-top: 1px solid rgba(255, 255, 255, 0.10);
    padding-top: 3px;
}

/* ─────────────────────────────────────────────────────────────── */
/* Ribbon Buttons — Onyx Pill with Glass-like Top Highlight        */
/* ─────────────────────────────────────────────────────────────── */
.nextxbase-button,
.nextxbase-btn,
.nextxbase-btnbmp,
.nextxbase-ribbon-btn {
    background: #2a2720;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 0;
    color: #d0ccc4;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease;
    padding: 6px 12px;
    font-family: 'Segoe UI', 'Outfit', system-ui, sans-serif;
    /* 12px, the system GUI font -- see THE DEFAULT GUI FONT SIZE rule; this
       later rule was 13px and beat that one for every button. Measured on
       ctl_fixture: an unsized button's caption at 13px made the control 186
       wide against the reference's 163. */
    font-size: 12px;
    /* 400, NOT 500, AND IT IS THE OTHER HALF OF THE STORY ABOVE. The
       font-SIZE on this rule was 13px and was corrected to 12 against the
       reference; the WEIGHT was left semibold, and a native button caption
       is not semibold. Decided on two captures read side by side, not on a
       number: the reference's 'Has Action' is drawn in thin strokes and
       ours was visibly heavier at the same size on the same box.
       ⚠ IT DOES NOT IMPROVE THE UNSIZED WIDTHS AND WAS NOT DONE FOR THEM.
       Measured across three captions: the delta to the reference goes
       +8.8 -> +5.4 on one, +1.4 -> -8.5 on another and -7.8 -> -8.3 on the
       third, because the reference's own auto-size rule is unmodellable
       from three points (section 8 item 0b). This is a LOOK change with a
       geometric side effect, and saying so is the difference between a
       decision and a coincidence. */
    font-weight: 400;
    position: relative;
    overflow: hidden;
    margin-right: 4px;
    box-sizing: border-box;
}

/* THE TWO BUTTON CLASSES CARRY THEIR OWN TRANSITION, AND IT USED TO BE
   WRITTEN INLINE ON EVERY ONE OF THEM.

   TBUTTON:GenerateHTML emitted `cursor:pointer; transition:transform 0.1s,
   box-shadow 0.1s;` on the element. cursor:pointer was already in the rule
   above, identical, so it was pure duplication. The transition was NOT
   identical -- the rule above says `all 0.3s ease` -- so the inline was the
   only thing that made a button animate the way this engine intends, and
   because it was inline it also outranked every theme. Measured: 272
   buttons across 26 samples, and .theme-frost asks for

       transition: transform 0.12s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.12s

   which could never fire on any of them.

   THIS RULE IS SCOPED TO THE TWO BUTTON CLASSES ON PURPOSE. The block above
   also covers .nextxbase-btnbmp and .nextxbase-ribbon-btn, which never
   carried the inline and are left on `all 0.3s ease` -- changing an
   animation for two controls this defect does not concern would be a look
   change nobody asked for. Same specificity (0,1,0), declared LATER, so it
   wins for these two; a theme's (0,2,0) still wins over both.

   ⚠️ 20 ELEMENTS DO CHANGE, AND THAT IS THE POINT RATHER THAN A COST.
   Measured on the emitted pages: 292 elements carry these classes, 272 with
   the inline and 20 without -- the second path (TSBUTTON among them)
   animated `all 0.3s ease` while the first animated transform/box-shadow at
   0.1s. One control that behaves two ways is the fork directive 1 forbids;
   after this they are one. */
.nextxbase-button,
.nextxbase-btn {
    transition: transform 0.1s, box-shadow 0.1s;
}

.nextxbase-button.btn-flat,
.nextxbase-btnbmp-flat {
    background: transparent;
    border: none;
    box-shadow: none;
}

/* A fixed height under the button's overflow:hidden sliced any caption that
   wrapped to two lines THROUGH the glyphs -- "Rotate Keys" rendered as
   "Rotate Kevs" and "Audit Logs" as "Audit Loas", the descenders cut off at
   the clip edge. A ribbon button has to be at least 64px; it must not be
   exactly 64px when the caption it was given needs more. */
/* FIXED, not min-. A minimum grows, and growth is the whole problem: one
   two-line caption made one button taller than its neighbours, which made its
   group taller, which made the panel taller -- so the ribbon changed height
   when you switched to a tab whose captions happened to wrap. Every large
   button is now exactly the same box and the panel cannot move. */
.nextxbase-ribbon-btn.btn-large {
    flex-direction: column;
    -ms-flex-direction: column;
    justify-content: flex-start;
    -ms-flex-pack: start;
    /* A FLOOR, NOT A FIXED WIDTH -- the card sizes in BOTH axes.
       `width: 82px` meant a long caption had exactly one way to fit, by
       wrapping, and an icon wider than 82px had none at all: it clipped. The
       card now starts at 82 and grows if its content needs more, the group
       grows with it (flex: 0 0 auto), and the bar scrolls rather than
       squeezing. Neither the number of caption lines nor the icon size is
       assumed anywhere. */
    width: auto;
    min-width: 82px;

    /* NOT a fixed height. align-self:stretch makes every button in the row as
       tall as the tallest one, so the caption that wraps furthest sets the
       height and the rest match it -- one line or four, whatever it turns out
       to be. Fixing it to 78px was the same error as letting it size to
       content: it just clips instead of jumps. */
    height: auto;
    align-self: stretch;
    -ms-flex-item-align: stretch;

    font-size: 12px;
    line-height: 1.3;
    text-align: center;
    padding: 7px 4px 6px;
    white-space: normal;
}

/* The label ABSORBS the slack. Because the button is stretched to the row's
   tallest, the label growing to fill what is left is what keeps every icon on
   one line across the ribbon: a one-word caption simply gets a taller empty
   label rather than a higher-riding icon. */
.nextxbase-ribbon-btn.btn-large .ribbon-btn-label {
    display: block;
    width: 100%;
    /* 1 0 auto, NOT 1 1 auto -- THE SHRINK IS WHY NOTHING GREW.

       With shrink enabled the label collapses below its own content, so a
       three-line caption reported no more natural height than a one-line one:
       the card never grew, the group never grew, the panel never grew, and the
       text simply spilled out of the bottom of the card and over the group
       caption. Every container was behaving correctly on the size it was told,
       and the size it was told was wrong at the very first step.

       flex-grow stays 1 so a short caption still absorbs the slack and every
       icon in a row keeps a common baseline; only the SHRINK is removed, so
       the caption's real height propagates up through card, group and panel.
       Nothing assumes a line count anywhere. */
    flex: 1 0 auto;
    -ms-flex: 1 0 auto;
    word-wrap: break-word;
    word-break: break-word;
}


/* The icon box is emitted even when there is no bitmap, so a button without one
   still starts its caption at the same y as a button with one. */
.nextxbase-ribbon-btn.btn-large .ribbon-icon-box {
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    width: 100%;
    height: 30px;
    flex: 0 0 30px;
    -ms-flex: 0 0 30px;
    margin-bottom: 3px;
}

.nextxbase-ribbon-btn.btn-large .ribbon-icon {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.nextxbase-ribbon-btn.btn-small {
    flex-direction: row;
    -ms-flex-direction: row;
    justify-content: flex-start;
    -ms-flex-pack: start;
    height: auto;
    min-height: 30px;
    padding: 4px 10px;
    white-space: nowrap;

    /* A fixed height cannot stretch, and an unstretchable item falls back to
       the start of the axis -- so switching the row to stretch (which the large
       buttons need) silently pinned these to the TOP of the group with all the
       slack underneath. They opt out and stay centred. */
    align-self: center;
    -ms-flex-item-align: center;
}

/* Small buttons keep their icon column too, so a group mixing captioned and
   un-captioned entries still reads as a column rather than a ragged edge. */
.nextxbase-ribbon-btn.btn-small .ribbon-icon-box {
    display: inline-flex;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    margin-right: 7px;
}

.nextxbase-ribbon-btn.btn-small .ribbon-icon {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* THE ENGINE DOES NOT EDIT THE APPLICATION'S TEXT. This carried
   overflow:hidden + text-overflow:ellipsis, so a caption longer than its
   button was silently replaced by a shortened one with a dot-dot-dot -- the
   engine deciding the words. The rule is the owner's: a caption that needs
   more room PUSHES the button wider, and where the application does not want a
   wider button it breaks the caption itself with a CRLF.

   The buttonbar copy of this exact element already said so, three rules below:
   "a caption wraps to as many lines as it needs, because the application chose
   the words and the button width, not us". This makes the ribbon agree with
   its own buttonbar.

   Since 71a35004 a declared size is a min-width rather than a width, so an
   inline-flex btn-small grows to its caption and this rule had probably become
   inert. Probably is the point: an inert rule that can only ever truncate is
   one layout change away from truncating again. */
.nextxbase-ribbon-btn.btn-small .ribbon-btn-label {
    overflow: visible;
    text-overflow: clip;
}

/* A buttonbar button is sized by DEFINE BUTTONBAR ... SIZE, so it must not
   inherit the ribbon's fixed box -- and must not STRETCH to the bar's height
   either: the ribbon's large button stretches so a row of them ends up equal,
   which is the ribbon's problem and not a toolbar's. */
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-large,
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-small {
    width: auto;
    height: auto;
    align-self: center;
    -ms-flex-item-align: center;

    /* THE CAPTION SITS ABOVE THE ICON ON A TOOLBAR, AND THE REFLECTION IS THE
       REASON. Owner, 2026-09-14: "fivewin shows the button label in the
       bottom, i think that to add the icon reflection, the label we should
       place on top of the icon, so the reflection is nicer".

       A reflection needs the room directly UNDER the icon, and that is exactly
       where the reference puts its caption -- so the two cannot both have it.
       This is a look decision the owner took with the reference's behaviour in
       front of them, not a parity defect: what the caption says, where the
       button is and how big it is are all still the application's.

       column-reverse rather than a second markup shape, so the DOM stays one
       order -- icon, then label -- for anything that reads it, and the ribbon
       (which keeps the caption below) is untouched because this is scoped to
       .nextxbase-buttonbar. IE11 implements column-reverse under -ms-.

       justify-content: flex-end, NOT flex-start. In column-reverse the main
       axis starts at the BOTTOM, so `end` is what packs the pair against the
       button's top edge and leaves the slack below the icon -- which is the
       room the reflection then paints into. */
    flex-direction: column-reverse;
    -ms-flex-direction: column-reverse;
    justify-content: flex-end;
    -ms-flex-pack: end;

    /* AND THE ROOM UNDER THE ICON IS THE REFLECTION'S WHOLE BUDGET, so it is
       measured here rather than left to a rule written for a ribbon.

       Measured on HbBuilder's 46px bar with the generic button padding: 6px
       top and 6px bottom take 12 of the 46, a 32px icon and its 3px margin
       take 35 more, and what is left under the icon is EIGHT PIXELS -- so a
       correct 1:1 reflection had almost nowhere to paint and read as though
       the effect had been removed. The bar's height is the application's and
       the icon is the art it supplied; the padding was the only term that was
       ours, and 6px of vertical padding is a ribbon card's, not a toolbar
       button's. At 2px the room is 10px, which is about a third of the icon --
       the bottom third is exactly what a reflection shows.

       The margin goes with it. It was `0 0 3px 0`, holding the CAPTION off
       the icon from below; the caption is above the icon now, so those 3px
       stopped separating anything and were simply spent. */
    padding: 2px 4px;

    /* AND THE BUTTON MUST NOT HANG OUT OF ITS OWN BAR, WHICH IS WHAT CHANGING
       THE FLEX DIRECTION DID. Measured on the served page, not reasoned about:
       with the bar at 20..66 and `overflow: hidden`, the button came out at
       35..81 -- fifteen pixels low, its icon clipped at the bar's edge and the
       reflection entirely outside it. Nothing about the button's own box had
       changed; its height was still 46 in a 46px bar.

       The button is an INLINE-FLEX inside a block wrap, so it sits on a text
       baseline, and an inline-flex box's baseline is synthesised from its FIRST
       flex item ALONG THE MAIN AXIS -- which column-reverse moves from the icon
       to the label. A baseline that moves drags the whole inline box with it.

       vertical-align removes the dependency rather than compensating for it:
       the box is aligned to the top of its line rather than to a baseline that
       is a function of what is inside it. It is what an inline-level element in
       a fixed-height bar should have said all along. */
    vertical-align: top;
}

/* THE ICON BOX IS A FULL-WIDTH ROW, NOT AN INLINE SLOT.
   The ribbon's small button puts the icon BESIDE the caption, so its box is
   18px wide with a margin-right to hold the caption off. Inherited into a
   column layout that margin becomes a horizontal OFFSET -- the icon rendered
   3px left of centre in every button on the bar -- and the 18px cap crushed
   art the toolbar had asked to be square. */
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-large .ribbon-icon-box,
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-small .ribbon-icon-box {
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    width: 100%;
    height: auto;
    min-height: 32px;
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    /* 0, NOT `0 0 3px 0`. Those 3px held the CAPTION off the icon from below;
       the caption is above the icon now, so they separated nothing and were
       simply spent out of the room the reflection paints in. */
    margin: 0;
}

/* Three classes, to beat .nextxbase-ribbon-btn.btn-small .ribbon-icon on
   SPECIFICITY. The two-class version of this rule lost to it silently and the
   toolbar drew 16px art in a 70px square. */
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-large .ribbon-icon,
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-small .ribbon-icon {
    width: 32px;
    height: 32px;
    margin-bottom: 0;
}

/* THE CAPTION TAKES THE ROOM IT NEEDS AND NO MORE.
   flex: 0 0 auto is the fix for "there is a blank space below": the ribbon's
   large button gives its label flex: 1 1 auto so the label ABSORBS the slack
   and every icon in a stretched row stays on one line. A toolbar button is not
   stretched, so an absorbing label just parks empty space under the text.
   white-space stays NORMAL -- a caption wraps to as many lines as it needs,
   because the application chose the words and the button width, not us. */
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-large .ribbon-btn-label,
.nextxbase-buttonbar .nextxbase-ribbon-btn.btn-small .ribbon-btn-label {
    display: block;
    width: 100%;
    height: auto;
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    text-align: center;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    word-wrap: break-word;
    word-break: break-word;
}

.nextxbase-ribbon-btn:hover {
    background: #3a3630;
    border-color: #d4af37;
    color: #d4af37;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
}

.ribbon-icon {
    width: 24px;
    height: 24px;
}
.nextxbase-buttonbar {
    background: #1a1814;
    background: linear-gradient(to bottom, #221f18 0%, #1a1814 60%, #151310 100%);

    /* Same boundary as the ribbon, and it had the same invisible border. */
    border-bottom: 1px solid rgba(0, 0, 0, 0.65);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.75),
                0 3px 10px rgba(0, 0, 0, 0.14);
    /* NO PADDING: the reference bar's first button starts at x=0 of the
       client and its buttons are the bar's full height (measured 2026-09-02,
       FiveDBU SIZE 70,70: bar 72.9 logical, buttons 72, first button at 0).
       The 6px/12px that sat here made the bar 91 logical for the same
       declaration and indented the row by 12. The bar's height is the
       declared button height plus its frame, set by TBUTTONBAR:New. */
    padding: 0;
    display: flex;
    display: -ms-flexbox;
    flex-direction: row;
    -ms-flex-direction: row;

    /* TOP, NOT CENTRE. the classic TButtonBar puts its buttons at the top edge of
       the bar and leaves whatever the declared SIZE gives it below them --
       `DEFINE BUTTONBAR oBar SIZE 60, 60` is a 60px bar with its buttons at the
       top, not floating in the middle of it.

       This read `center`, which is indistinguishable from correct whenever the
       bar hugs its buttons -- every bar FiveDBU declares. It only becomes
       visible once a bar is taller than its content, which is the general shape
       of an alignment defect: nothing to see until there is slack to align
       inside. */
    align-items: flex-start;
    -ms-flex-align: start;
}

/* ========================================================================== */
/* TXBROWSE / Data Grid — Dark Header on White Grid (HIGH CONTRAST)           */
/* ========================================================================== */
.nextxbase-grid-container {
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 0;
    overflow: hidden;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), 0 4px 8px rgba(0, 0, 0, 0.06), 0 8px 16px rgba(0, 0, 0, 0.04);
    background: #ffffff;

    /* AND THE INK BESIDE THE GROUND, because they are one decision (0-E).
       This rule painted white and stated no colour, which was harmless only
       for as long as TXBROWSE wrote both of them inline on every browse. It
       no longer does -- the renderer asks the cascade and emits nothing when
       nobody answers -- so an unthemed grid would take its ink from whatever
       ancestor happens to state one, and a dark ancestor over this white
       ground is the 1.00:1 case this file records nine times over.
       #000000 is exactly the literal the renderer used to emit, so an
       unthemed page is unchanged; what is different is that a theme rule can
       now override it, which an inline declaration never allowed. */
    color: #000000;
}

/* THE GROUND IS HANDED DOWN TO THE CELLS, which is what lets the browse be
   themed at all.

   TXBROWSE used to write `background:#ffffff` inline on the container AND on
   every row, so nothing below ever needed a colour of its own. It asks the
   cascade now and emits nothing when the application named none -- and a
   `background` is NOT an inherited property, so without this the table, the
   rows and the cells would all be transparent. Transparent is right for an
   ordinary cell (the container shows through) and WRONG for a `position:
   sticky` one, where the rows being scrolled horizontally would show through
   the frozen column. Four live browses freeze a column, so that is a real
   path rather than a hypothetical.

   `inherit` rather than a colour, because this rule cannot know which theme
   is live -- which is the whole point of removing the literal. It is the
   same idiom .nextxbase-say already uses, and it is CSS2, so the IE11 floor
   reads it. A row that DOES state its own colour -- an application's
   bClrStd, or the selection -- still overrides it, which is rung 1 winning
   exactly as it should. */
.nextxbase-grid-container table,
.nextxbase-grid-container tbody,
.nextxbase-grid-container tbody tr,
.nextxbase-grid-container tbody td {
    background-color: inherit;
}

.nextxbase-grid-container table,
table.nextxbase-grid {
    border-collapse: collapse;
    width: 100%;
}

.nextxbase-grid-container thead th,
table.nextxbase-grid thead th {
    /* A HEADER THE SAME SHAPE AS THE REFERENCE'S, IN OUR PALETTE.

       This was near-black with gold text at weight 700 and 0.5px tracking,
       which is not "the classic design with 2026 aesthetics" -- it is a
       different control. The gradient, the hairline and the hover are ours to
       choose; weight, tracking, alignment and a light ground are what make it
       read as the same control at all.

       PADDING IS THE ROW-HEIGHT DEFECT. 10px top and bottom floors the header
       at 10+13+10 = 33 no matter what the emitter writes, and the browse's
       declared height is what RowsToDisplay() counts against -- so padding was
       silently deciding how many records fit. Same class as the GET padding
       that ate its own text. Horizontal padding stays; it costs no height.

       text-align is NOT set here any more: the emitter writes it per column
       from nHeadStrAlign, and a blanket rule here overrode the column's own
       choice -- so a centred header could never render centred. */
    background: #eef1f6;
    background: linear-gradient(to bottom, #f7f9fc 0%, #e8ecf3 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9);
    color: #1a1814;
    font-weight: 400;
    font-size: 13px;
    letter-spacing: 0;
    /* Same as the data cell: a header that wraps is a header that sets its own
       height. "Company Name" broke onto two lines and took the whole header
       band with it. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: clip;
    padding: 1px 6px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.25);
}

/* Dark hairline then a light one -- the same two-line groove the toolbar and
   the ribbon use, turned on its side. th + th so the first column has no
   divider hanging off its left edge. */
/* A SEPARATION, NOT A RULE. A border-left runs the full height of the cell and
   reads as a table gridline -- it divides the header into boxes instead of
   spacing the labels apart. The divider is inset 7px top and bottom so it
   floats between the captions, which is the difference between "this table is
   ruled" and "these are separate columns".

   Sunken rather than drawn: dark hairline on the left, light hairline on the
   right, so the light lands on the far side of the cut and the eye reads a
   groove in the surface. One flat line at any weight reads as ink on top of
   it. This needs a pseudo-element -- a border cannot be inset from its own
   cell's edges -- so the cell becomes the positioning context. */
.nextxbase-grid-container thead th,
table.nextxbase-grid thead th {
    position: relative;
}

.nextxbase-grid-container thead th + th::before,
table.nextxbase-grid thead th + th::before {
    content: '';
    position: absolute;
    left: 0;
    top: 7px;
    bottom: 7px;
    width: 0;
    border-left: 1px solid rgba(0, 0, 0, 0.55);
    border-right: 1px solid rgba(255, 255, 255, 0.10);
    pointer-events: none;
}

/* THE HEADER IS NOT DARK IN EVERY THEME. The rule above is tuned for the
   default #1a1814 header; the system themes paint it #f3f3f3 / #ececec /
   #dfdcd8 and theme-light #e9e0cd, where a 55%-black divider is a black bar
   and the white hairline beside it does nothing at all.

   Same groove, inverted weights: a soft dark hairline with a strong white one
   against it. Worth stating because it is the kind of rule that looks correct
   in whichever theme happens to be open and wrong in the other four. */
.os-windows.theme-system .nextxbase-grid-container thead th + th::before,
.os-windows.theme-system table.nextxbase-grid thead th + th::before,
.os-macos.theme-system .nextxbase-grid-container thead th + th::before,
.os-macos.theme-system table.nextxbase-grid thead th + th::before,
.os-linux.theme-system .nextxbase-grid-container thead th + th::before,
.os-linux.theme-system table.nextxbase-grid thead th + th::before,
.theme-light .nextxbase-grid-container thead th + th::before,
.theme-light table.nextxbase-grid thead th + th::before,
.theme-light.control-theme-light.nextxbase-grid-container thead th + th::before {
    border-left: 1px solid rgba(0, 0, 0, 0.20);
    border-right: 1px solid rgba(255, 255, 255, 0.95);
}

/* A BROWSE THAT IS THE CLIENT AREA IS FLUSH.

   The container's 10px radius and three-layer drop shadow are right for a grid
   inside a dialog with room around it. When the browse FILLS a window they are
   the owner's "8-10px gap on the left when maximized": the radius lets the
   window's ground show at the corners and the 16px blur lays a soft band down
   the outside edge. Nothing for a filling control to cast a shadow onto, and
   the classic does not.

   Scoped to the fill case -- the decoration is correct everywhere else, and
   dropping it globally would flatten every dialog grid in the product to fix a
   case that only arises when the browse IS the client. */
.nextxbase-grid-container.nxb-brw-client {
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

/* NO DIVIDER AGAINST THE RECORD SELECTOR.

   The `th + th::before` rule states its own intent: "th + th so the first
   column has no divider hanging off its left edge." The record selector breaks
   that reasoning by being a real <th class='nxb-recsel'> -- so the first DATA
   column is a `th + th` and gets the groove after all, drawn against the
   selector's coloured band. That is the owner's "first column title
   contaminated by the side texture".

   content:none, so the pseudo element is never generated rather than generated
   and hidden. */
.nextxbase-grid-container thead th.nxb-recsel + th::before,
table.nextxbase-grid thead th.nxb-recsel + th::before {
    content: none;
}

.nextxbase-grid-container tbody td,
table.nextxbase-grid tbody td {
    /* VERTICAL PADDING REMOVED -- IT WAS SETTING THE ROW HEIGHT.
       9px top and bottom floors a cell at 9+13+9 = 31px, so the emitter's
       style='height:20px' could never bind and a 120px browse showed 2 of its
       4 records instead of 4. Row height is geometry here: RowsToDisplay()
       divides the usable height by it to decide how many records exist on
       screen, so a stylesheet that inflates it changes what the control DOES,
       not how it looks. Horizontal padding stays -- it costs no height. */
    padding: 0 6px;
    font-size: 13px;

    /* INK BY INHERITANCE, NOT BY LITERAL -- AND THIS ONE DEFEATED EVERY
       THEME AT ONCE, WHICH IS THE 0-E RULE STATED EXACTLY.

       It read `color: #1a1814`. A theme paints by setting `color` on an
       ANCESTOR -- here `.theme-<x> .nextxbase-grid-container` -- and
       INHERITANCE LOSES TO A DIRECT DECLARATION however specific the
       ancestor's selector is. So a near-black literal on the CELL beat all
       75 per-theme grid rules, and no specificity argument could ever have
       reached it.

       It was invisible for as long as TXBROWSE also wrote `background:
       #ffffff` inline on every row: dark ink on a white ground is correct,
       so the two defects cancelled and the grid looked right. Removing the
       inline ground is what made this one paint dark on dark -- which is
       0-E's other half, that ground and ink are ONE decision and fixing one
       without the other is worse than fixing neither.

       `inherit` matches `background-color: inherit` sitting on the same
       element forty lines above, so the cell now takes BOTH halves from the
       same place. An unthemed page is unchanged: the base
       .nextxbase-grid-container states #000000, near enough #1a1814 that no
       capture separates them, and it is now a value a theme can override. */
    color: inherit;
    /* A CELL CLIPS, IT NEVER WRAPS. Once COLSIZES became authoritative the
       width was bounded and the browser satisfied it the only other way it
       can -- by growing DOWNWARD. "Stark Industries" took a double-height row
       and the row height just freed from cell padding was handed straight
       back to content. the reference implementation draws what fits in the rectangle and clips the
       rest; a browse row is a fixed height by construction. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: clip;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}

.nextxbase-grid-container tbody tr:hover td,
table.nextxbase-grid tbody tr:hover td {
    background: rgba(184, 148, 42, 0.06);
}

/* THE BROWSE FOOTER AND ITS PAGE BUTTONS -- MOVED OFF THE INLINE STYLE,
   2026-09-09, AND THE REASON IS THAT NINE THEME DECLARATIONS WERE ALREADY
   DEAD.

   This stylesheet has said three things about .nxb-grid-smart-footer for a
   while -- frost, liquid-glass and onyx each set background, border-top and
   color on it -- and TXBROWSE:GenerateHTML wrote all three INLINE. An inline
   declaration outranks every class rule, so a browse footer painted #f8fafc
   with #334155 text under EVERY theme, and the nine rules below were
   unreachable. That is CLAUDE.md 0-E: ground and ink are one decision, and
   whichever half you do not own you must not state.

   The literals are not deleted, they are MOVED: the values here are the
   bytes the renderer used to emit, so the default light browse is unchanged
   and the only thing that moves is who can override it. Theme rules carry
   .theme-x .nxb-grid-smart-footer (0,2,0) against this rule's (0,1,0), so
   they win on specificity wherever a theme is active, independent of order.

   .nxb-pg-btn had NO rule at all and three IDENTICAL copies of five
   declarations inline -- one per button. Fifteen of TXBROWSE's twenty-six
   blockers were that duplication. A shared class is the one place they
   belong; the alternative on offer was fifteen invented cascade keys for
   what is one button style.

   GEOMETRY STAYS INLINE, deliberately: position, width, height, display,
   flex alignment and z-index are what the control DOES, not how it looks,
   and this file already records a stylesheet that changed a browse's row
   count by inflating cell padding. */
.nxb-grid-smart-footer {
    padding: 0 12px;
    background: #f8fafc;
    border-top: 1px solid #cbd5e1;
    border-bottom: 1px solid #cbd5e1;
    color: #334155;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 12px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

.nxb-grid-smart-footer .bi-table {
    color: #3b82f6;
}

.nxb-pg-btn {
    padding: 3px 8px;
    background: #ffffff;
    border: 1px solid #cbd5e1;
    border-radius: 4px;
    cursor: pointer;
    font-size: 11px;
}

.nxb-grid-searchbar i {
    color: #64748b;
    font-size: 13px;
}

/* ZEBRA IS A DECORATION, SO IT IS TRANSLUCENT. This used to be the opaque
   #faf8f5, and an opaque cell hides whatever a theme paints on the ROW:
   measured under onyx, every even row rendered cellBg rgb(250,248,245)
   with cellColor rgb(248,250,252) -- near-white text on near-white, so
   half the records were invisible in every dark theme at once.
   rgba(130,80,5,0.04) over #ffffff evaluates to exactly (250,248,245),
   so the default light grid is unchanged; over any other ground it now
   tints instead of blanking. Adding a td rule to each theme would have
   been nine copies to keep in sync, and the tenth theme would arrive
   broken. */
.nextxbase-grid-container tbody tr:nth-child(even) td {
    background: rgba(130, 80, 5, 0.04);
}

/* ========================================================================== */
/* 4. Mobile & Tablet Responsive -- REMOVED, and this is the reasoning         */
/* ========================================================================== */
/* There was an `@media (max-width: 768px)` block here. It is gone because it
   overrode DECLARED geometry with !important, and because in the product's own
   viewer it matched on ordinary desktop windows.

   PHOTOGRAPHED. ctllab's real window, screenshotted at three sizes: at a
   3849x2117 physical client the controls sat at their declared coordinates; at
   2963x911 and at 1363x911 a dialog declared at top:800px, left:480px, 401px
   wide filled the entire window and both scrollbars came on. The same emitted
   page in Chrome at the same viewport put that dialog exactly where it was
   declared. The divergence was this query matching in one engine and not the
   other -- not a rendering difference.

   WHY IT MATCHED. The webviewer's CSS viewport is much smaller than its
   window. MSHTML's own rect probe measured .nxb-stage at 847 CSS px while the
   HWND client was 3849 physical px, so on a 225%-scaled display only a
   maximized window clears 768. Every other window got phone geometry.

   WHAT IT OVERRODE. .nextxbase-window width/height to 100vw/100vh; the dialog
   top/left/width to 5vh/3vw/94vw; the workspace to a padded flex column; and
   -- the "scattered controls" defect -- say/get/btn/cbo to position:relative,
   top:auto, left:auto, width:100%, so those four controls lost their
   coordinates and stacked while every other control kept its declared
   position. Two coordinate systems on one canvas.

   CORRECTION, measured after the removal and recorded here rather than left
   standing: the commit that removed this block ALSO claimed the padded flex
   was why the probe read the workspace 34px wider than the stage (881 inside
   847). That was wrong. Re-probed with the block gone and the figure is
   unchanged, because 881 is the CONTENTS EXTENT the emitter computes and
   writes as min-width -- the parity dialog sits at left:480 with width:401,
   and 480+401 = 881. A workspace wider than the viewport is the specified
   behaviour ("the working space is always the size of the elements within"),
   and the scrollbar that follows is correct, not a defect. The removal above
   stands on its own evidence -- the photographed dialog overlay -- and needed
   no help from a second claim that was never checked.

   WHY REMOVED RATHER THAN RE-THRESHOLDED. The block's own comments had already
   reached that conclusion -- "any breakpoint is wrong here, because the
   window's width is a function of the declared SIZE and can be anything" --
   and twice answered it with another :not() marker class instead of removal.
   It also breaks the rule that a value must come from an argument, a DATA
   default or a parent: 768 is reachable by none of them, and it does not
   supply a default, it beats a declaration.

   MOBILE IS NOT LOST. The plan of record is groups and forms that know where
   they belong, so a phone layout can be derived from declared structure.
   Stripping coordinates with !important is the thing that plan replaces. When
   that work starts, it does not start here. */


/* ========================================================================== */
/* Custom MsgInfo Dialog (Light Luxury Design)                                */
/* ========================================================================== */

.nextxbase-msginfo-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0, 0, 0, 0.4);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 99999;
    animation: fadeIn 0.2s ease-out;
}

.nextxbase-msginfo-dialog {
    background: linear-gradient(135deg, rgba(255,255,255,0.95), rgba(250,250,250,0.85));
    border: 1px solid rgba(212, 175, 55, 0.4); /* Gold accent */
    border-radius: 12px;
    box-shadow: 0 20px 40px rgba(0,0,0,0.15), 0 0 15px rgba(212, 175, 55, 0.1);
    min-width: 350px;
    max-width: 450px;
    overflow: hidden;
    animation: slideUp 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.nextxbase-msginfo-header {
    background: #111111; /* Onyx */
    color: #D4AF37; /* Gold Neon */
    padding: 12px 20px;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    border-bottom: 2px solid #D4AF37;
}

.nextxbase-msginfo-body {
    padding: 30px 20px;
    color: #333;
    font-size: 16px;
    line-height: 1.5;
    text-align: center;
}

.nextxbase-msginfo-footer {
    padding: 15px 20px;
    background: rgba(0,0,0,0.02);
    border-top: 1px solid rgba(0,0,0,0.05);
    text-align: right;
}

.nextxbase-msginfo-btn {
    background: #D4AF37;
    color: #111;
    border: none;
    padding: 8px 24px;
    border-radius: 4px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    text-transform: uppercase;
    font-size: 13px;
    box-shadow: 0 4px 10px rgba(212, 175, 55, 0.2);
}

.nextxbase-msginfo-btn:hover {
    background: #F3E5AB;
    transform: translateY(-1px);
    box-shadow: 0 6px 15px rgba(212, 175, 55, 0.4);
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes slideUp {
    from { transform: translateY(20px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

/* ========================================================================== */
/* 5. Dropdown menus — button MENUs, menubar submenus, POPUP menus            */
/*                                                                            */
/* None of these selectors existed. Every class below was already being        */
/* EMITTED by menu.prg / ribbon.prg and matched nothing, so a dropdown was a   */
/* plain block element in normal flow: permanently visible, and growing the    */
/* toolbar slot instead of floating over the workspace. Nothing could close    */
/* it because nothing had ever opened it.                                     */
/* ========================================================================== */

/* The positioning context for a button's dropdown. Without this the popup     */
/* would anchor to the nearest positioned ancestor (the window) instead of     */
/* to its own button.                                                          */
.nextxbase-btn-wrap {
    position: relative;
    display: inline-block;
}

.nextxbase-btn-wrap.btn-group-start {
    margin-left: 12px;
    padding-left: 12px;
    border-left: 1px solid rgba(212, 175, 55, 0.18);
}

.nextxbase-btn-wrap.btn-right {
    margin-left: auto;
}

.btn-caret {
    margin-left: 5px;
    font-size: 9px;
    line-height: 1;
    opacity: 0.75;
}

.nextxbase-menu-item.is-open > .nextxbase-menu-link {
    background: rgba(212, 175, 55, 0.15);
    color: #d4af37;
}

.nextxbase-btn-wrap.is-open .btn-caret {
    opacity: 1;
    color: #d4af37;
}

/* Closed is the DEFAULT state. .is-open is added by NextXbase.toggleBtnMenu. */
.nextxbase-btn-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
}

.nextxbase-btn-menu.is-open {
    display: block;
}

/* -------------------------------------------------------------------------- */
/* The popup list itself (TMENU with lPopup, and every submenu).               */
/* -------------------------------------------------------------------------- */
ul.nextxbase-menu-popup {
    list-style: none;
    margin: 0;
    padding: 5px 0;
    min-width: 200px;
    background: #221f1a;
    border: 1px solid rgba(212, 175, 55, 0.25);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    white-space: nowrap;
}

ul.nextxbase-menu-popup .nextxbase-menu-item {
    position: relative;
}

ul.nextxbase-menu-popup .nextxbase-menu-link {
    display: block;
    padding: 6px 26px 6px 12px;
    color: #d0ccc4;
    font-size: inherit;
    text-decoration: none;
    white-space: nowrap;
}

/* THE MENU DEFAULT, stated where a declared font can outrank it. Both the bar
   and the panels, because FONT governs the whole tree and the emitter threads
   it to both. */
.nextxbase-menubar,
ul.nextxbase-menu-popup {
    font-size: 13px;
}

ul.nextxbase-menu-popup .nextxbase-menu-link:hover {
    background: rgba(212, 175, 55, 0.15);
    color: #d4af37;
}

/* -------------------------------------------------------------------------- */
/* Nested submenus. A submenu of a POPUP item flies out to the SIDE; a         */
/* submenu of a MENUBAR item drops DOWN. Both were previously rendered inline, */
/* stacked underneath their parent entry and always open.                      */
/* -------------------------------------------------------------------------- */
/* EVERY submenu, wherever it hangs. Scoping this to a POPUP ancestor was the
   defect: a menubar item sits in ul.nextxbase-menu-list, so it matched none of
   this and its dropdown stayed display:block in normal flow -- open, and
   growing the menubar slot, exactly as before any of this was written. */
.nextxbase-menu-item > ul.nextxbase-menu-popup {
    display: none;
    position: absolute;
    top: -5px;
    left: 100%;
    margin-left: 2px;
}

.nextxbase-menu-item.is-open > ul.nextxbase-menu-popup {
    display: block;
}

/* An item that owns a submenu gets a flyout arrow, so a nested branch is      */
/* distinguishable from a leaf without opening it.                             */
.nextxbase-menu-item.has-submenu > .nextxbase-menu-link:after {
    content: "\25B8";
    position: absolute;
    right: 10px;
    opacity: 0.6;
}

/* Menubar: the first level drops down, deeper levels keep flying out right.   */
.nextxbase-menu-list > .nextxbase-menu-item > ul.nextxbase-menu-popup {
    top: 100%;
    left: 0;
    margin-left: 0;
    margin-top: 0;
}

/* A menubar item owning a submenu gets a DOWN caret, not the flyout arrow.    */
.nextxbase-menu-list > .nextxbase-menu-item.has-submenu > .nextxbase-menu-link:after {
    content: "";
}

/* -------------------------------------------------------------------------- */
/* Item states. All four classes were emitted and styled by nothing.           */
/* -------------------------------------------------------------------------- */
.nextxbase-menu-separator {
    height: 0;
    margin: 4px 8px;
    border-top: 1px solid rgba(212, 175, 55, 0.18);
    font-size: 0;
    line-height: 0;
}

.nextxbase-menu-item.is-bold > .nextxbase-menu-link {
    font-weight: 700;
    color: #e8e4dc;
}

.nextxbase-menu-item.is-disabled > .nextxbase-menu-link {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
}

.nextxbase-menu-item.is-checked > .nextxbase-menu-link {
    color: #d4af37;
}

.menu-check {
    display: inline-block;
    width: 14px;
    margin-left: -10px;
    margin-right: 2px;
}

.menu-icon {
    width: 16px;
    height: 16px;
    vertical-align: middle;
    margin-right: 6px;
}

/* the classic BREAK starts a NEW COLUMN in the popup. A CSS dropdown cannot     */
/* re-flow into columns without a fixed height, so the break is rendered as a  */
/* heavier rule — the grouping the author declared survives, the column does   */
/* not. Recorded here rather than silently dropped.                            */
.nextxbase-menu-item.menu-column-break {
    border-top: 2px solid rgba(212, 175, 55, 0.3);
    margin-top: 4px;
    padding-top: 4px;
}

/* A SEPARATOR declared WITH a prompt is a section heading, not a rule.        */
.nextxbase-menu-separator.has-caption {
    height: auto;
    margin: 6px 0 2px;
    padding: 2px 12px;
    border-top: 1px solid rgba(212, 175, 55, 0.18);
    font-size: 11px;
    line-height: 1.8;
    letter-spacing: 0.9px;
    text-transform: uppercase;
    color: #8f8a80;
}

/* ========================================================================== */
/* TMSGBAR / TMSGITEM — the status bar                                        */
/*                                                                            */
/* Found by tools/audit_css_reach.php: every class the msgbar emits           */
/* (nextxbase-msgbar, msgbar-prompt, msgbar-cell, msgbar-keyboard,            */
/* msgbar-date) was an ORPHAN -- named by no rule anywhere -- so the footer    */
/* rendered as unstyled inline text on the default background. The class was  */
/* implemented and wired; nothing had ever dressed it.                        */
/* ========================================================================== */
/* ========================================================================== */
/* WINDOW TYPE AND BAR STYLE — classes that were emitted and named by no rule  */
/*                                                                            */
/* Found by tools/audit_css_reach.php, which lists classes the transpiler puts */
/* on the page that no stylesheet rule mentions. It reported .bar-2010,        */
/* .has-menu, .wnd-maximized and .wnd-type-main -- and a direct check then     */
/* showed ALL SIX wnd-type-* classes had zero rules between them. So TYPE      */
/* POPUP, TYPE TOOLBAR and TYPE SPLITTER each computed correctly, reached the  */
/* markup correctly, and rendered identically to a main window.                */
/*                                                                            */
/* This is the same failure the msgbar block below records, and the reason the */
/* audit exists: an inert class is invisible from both directions. The PRG     */
/* looks right because it emits the class; the CSS looks right because nothing */
/* references a class that is missing.                                         */
/* ========================================================================== */

/* A maximized window is flush to the screen edge, so the bevel that separates
   the app from a host background behind it has nothing left to separate from.
   The shadow and the radius go; the top highlight stays, because it is what
   keeps the titlebar from looking pasted on. */
.nextxbase-window.wnd-maximized {
    border-radius: 0;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95);
    top: 0 !important;
    left: 0 !important;
    width: 100% !important;
    height: 100% !important;
    z-index: 9999 !important;
}

/* The application's own window: the standing case, stated rather than left
   implicit so the class is no longer inert and the intent is readable. */
.nextxbase-window.wnd-type-main {
    border-radius: 0;
}

/* A POPUP floats above the application rather than being it -- a lighter frame
   and a deeper shadow, which is the difference a user reads as "this is on
   top of that". */
.nextxbase-window.wnd-type-popup {
    border-radius: 8px;
    border-color: #9a938a;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
                0 18px 48px rgba(0, 0, 0, 0.34);
}

/* A TOOLBAR window is a palette: same window, compact caption. Windows has
   drawn tool windows with a shortened title bar for thirty years and it is the
   cue that says "this one is an accessory". */
.nextxbase-window.wnd-type-toolbar {
    border-radius: 6px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
                0 12px 30px rgba(0, 0, 0, 0.28);
}

.nextxbase-window.wnd-type-toolbar > .nextxbase-slot-titlebar {
    height: 24px;
    min-height: 24px;
}

.nextxbase-window.wnd-type-toolbar .titlebar-caption {
    font-size: 12px;
    letter-spacing: 0.4px;
}

/* A SPLITTER is a divider, not a document: no caption furniture, and the
   grab surface reads as something you can pull. */
.nextxbase-window.wnd-type-splitter {
    border-radius: 0;
    box-shadow: none;
    cursor: col-resize;
}

/* ─────────────────────────────────────────────────────────────── */
/* BUTTONBAR STYLE — DEFINE BUTTONBAR ... STYLEBAR | 2010 | 2013 | 2015        */
/*                                                                            */
/* The clause was parsed by the command and dropped on the floor before it     */
/* reached the object; it reaches the page as bar-<style> now, and these are   */
/* what act on it. FiveDBU's own header does #define STYLEBAR 2010, so a bar   */
/* declared STYLEBAR lands here as bar-2010.                                   */
/* ─────────────────────────────────────────────────────────────── */

/* 2007/2010 is the glossy era: a vertical sheen across the bar and buttons
   that read as raised. */
.nextxbase-buttonbar.bar-2010,
.nextxbase-buttonbar.bar-stylebar {
    background: linear-gradient(to bottom, #2b2721 0%, #1f1c17 48%, #171410 100%);
}

.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn,
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn {
    background: linear-gradient(to bottom, #33302a 0%, #26231d 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10),
                0 1px 2px rgba(0, 0, 0, 0.35);
}

/* 2013 flattened everything -- no gradients, no bevels, the button appears
   only on hover. Rendering it identically to 2010 would make the option a
   label rather than a style. */
.nextxbase-buttonbar.bar-2013 {
    background: #17150f;
}

/* ===========================================================================
   BUTTONBAR ICON REFLECTION -- something a desktop toolkit cannot do, drawn
   entirely inside the space the design already has.

   THE RULE THIS OBEYS: an application's developer reserved a size for every
   control, and an improvement that changes that size is not an improvement.
   So this effect reserves NOTHING. The pseudo element is absolutely positioned
   and therefore out of flow: the emitted box model is identical with the
   reflection and without it, and a toolbar declared 48px tall stays 48px tall.

   The first version of this block added 13px of margin to make room. That grew
   every button, which grew the bar, which moved everything positioned below --
   a layout change wearing an enhancement's clothes.

   WHAT IS LEFT IS THE SLACK THAT WAS ALREADY THERE, and it is small:

       large   30px icon box around a 26px icon  ->  2px under the icon
               plus the box's own 3px bottom margin  ->  ~5px
       small   18px box around an 18px icon      ->  ~3px

   Hence a 5px reflection, not a 13px one. Short and tight -- the bright edge
   under a glass shelf rather than a mirror. That is the rule's honest
   consequence: the space is borrowed, so the effect is the size of the space.

   The mask is what makes borrowing safe. It reaches full transparency at 72%,
   so only the top two or three pixels are strongly painted -- the ones in real
   slack -- and wherever the box formally overlaps the caption below there is
   nothing visible left to collide.

   A MASK, NOT AN OPACITY OVERLAY: an overlay must be painted in the button's
   own background to fade into it, and this bar has five skins (2010, 2013,
   2015, stylebar, theme-system) plus light and dark. A mask fades to
   TRANSPARENT, so one rule is correct on all of them.

   @supports IS A CAPABILITY PROBE, NOT A POLICY GATE. The desktop container is
   MSHTML pinned to IE11, which implements neither CSS masks nor @supports, so
   it skips this block -- and since nothing here reserves space, skipping it
   costs exactly nothing.

   --nxb-icon is written by the emitter (ribbon.prg) from the same data: URI the
   <img> uses, because icons resolve at runtime and no stylesheet can name them.
   A button with no bitmap emits no property and the ::after paints nothing.
   =========================================================================== */
@supports (-webkit-mask-image: linear-gradient(black, transparent)) or
          (mask-image: linear-gradient(black, transparent)) {

    /* 1:1 WITH THE ICON, BECAUSE IT IS MEASURED FROM THE ICON AND NOT STATED.
       Owner, 2026-09-14: "the icons reflections from tbuttonbar buttons is half
       the size than the icon, it should be 1:1, for the entire class".

       They were right and the ratio was almost exactly a half: the toolbar
       draws its art at 32px (`.nextxbase-buttonbar .ribbon-icon`), and this
       rule drew the reflected copy at `--nxb-icon-h`, which was 18px for a
       small button and 26px for a large one. Two numbers stating the same
       quantity, neither derived from the other, so the reflection could only
       ever be right by coincidence -- and ground rule 7 is that a value a
       control draws with comes from an argument, a DATA default or its parent,
       never from a literal nothing can reach.

       THE FIX IS TO STOP STATING IT. The pseudo element is the icon box's, so
       `height: 100%` IS the icon's own box and `background-size: contain` draws
       the picture at exactly the size the <img> above it renders at -- the same
       rule `object-fit: contain` gives the icon itself, so the two cannot
       disagree about aspect ratio either. No constant survives, and the three
       custom properties this block used to carry (--nxb-reflect-h,
       --nxb-icon-h, --nxb-reflect-inset) are gone with them: 7 var() uses down
       to 1, which is the whole of this tree's exposure on the IE11 ratchet.

       IT IS A MIRROR NOW, NOT A SECOND COPY. `top: 100%` puts it immediately
       below the icon and `transform: scaleY(-1)` flips it, so the edge touching
       the icon is the icon's own bottom edge. The mask is unchanged and is
       still written in the element's own coordinates -- strongest at its
       bottom, fading up -- which the flip turns into strongest against the icon
       and fading away downward. (The note this replaces records scaleY(-1)
       making the effect invisible once before. That was true of the OLD
       geometry, where the element sat at the button's bottom edge and the flip
       moved the painted slice out of the box; here the flip is what makes it a
       reflection at all, and it is proved on a capture rather than argued.)

       IT STILL CANNOT INVADE A NEIGHBOUR, and for a better reason than before:
       the button carries `overflow: hidden` in the base rule every button
       shares, so the reflection is clipped by the button's own padding box and
       its rounded corners with no exception carved for the toolbar. The room it
       gets is the slack the caption-on-top rule leaves under the icon -- so the
       effect is the size of the space, which is what a reflection under a glass
       shelf looks like.

       The mask fades to nothing well before the clip, so the bottom edge of the
       button does not cut a visible line across it. */
    .nextxbase-buttonbar .ribbon-icon-box {
        position: relative;
    }

    .nextxbase-buttonbar .ribbon-icon-box::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        /* immediately under the icon, and as tall as it is */
        top: 100%;
        height: 100%;
        background-image: var(--nxb-icon);
        background-repeat: no-repeat;
        background-position: center top;
        background-size: contain;
        transform: scaleY(-1);
        /* THE FADE IS A FRACTION OF THE ICON, NOT OF THE ROOM, so a tall bar
           and a short one show the same reflection rather than one showing
           more of it. The bottom third is what is painted; past that there is
           nothing left to clip, so no bar height can cut a visible line
           across it. */
        -webkit-mask-image: linear-gradient(to top,
                            rgba(0, 0, 0, 0.50), transparent 34%);
        mask-image: linear-gradient(to top,
                    rgba(0, 0, 0, 0.50), transparent 34%);
        pointer-events: none;
    }
}

.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}

.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn:hover:not([disabled]) {
    background: rgba(255, 255, 255, 0.09);
    border-color: rgba(255, 255, 255, 0.12);
}

/* 2015 is 2013 with the accent carried into the hover and a lit underline on
   the pressed button. */
.nextxbase-buttonbar.bar-2015 {
    background: #14120d;
}

.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    border-radius: 0;
}

.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn:hover:not([disabled]) {
    background: rgba(212, 175, 55, 0.14);
    box-shadow: inset 0 -2px 0 #d4af37;
}

/* A button carrying MENU opens a dropdown, and it looked exactly like one that
   runs an action. The caret alone is 9px of glyph; the split rule is the part
   that reads at a glance, and it is the convention every toolbar with drop
   buttons has used since Office 97. Inset from top and bottom for the same
   reason the other dividers are -- a full-height line reads as a border. */
.nextxbase-btn-wrap.has-menu {
    position: relative;
}

.nextxbase-btn-wrap.has-menu .btn-caret {
    padding-left: 5px;
    /* THE ELEMENT `left: 0` BELOW HAS ALWAYS MEANT. Without this the caret is
       static, so the absolutely-positioned ::before resolves against the WRAP
       and the split rule lands at the far left edge of the button -- as far
       from the caret as it is possible to put it. */
    position: relative;
}

.nextxbase-btn-wrap.has-menu .btn-caret::before {
    content: '';
    position: absolute;
    top: 22%;
    bottom: 22%;
    left: 0;
    width: 0;
    border-left: 1px solid rgba(0, 0, 0, 0.5);
    border-right: 1px solid rgba(255, 255, 255, 0.09);
    pointer-events: none;
}

/* The status bar closes the window at the bottom, so its light comes from the
   same place: lifted top edge, settled bottom. */
/* THE LIGHT THEMES OVERRIDE `background` AND NOTHING ELSE, so the material
   added to the base rules reaches them through the properties they do not
   name -- and a 45%-black hairline under a #f3f3f3 title bar is a bruise.
   The theme blocks flatten the gradient for free; these flatten the light
   that went with it.

   This is the second time in one pass that a base-rule change leaked into
   four themes through an unnamed property. The rule of thumb it earns: when a
   theme overrides a surface, it overrides the surface's LIGHTING too, and
   `background` alone is not the surface. */
.theme-system .nextxbase-titlebar,
.theme-light .nextxbase-titlebar,
.theme-light.control-theme-light.nextxbase-titlebar {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
                0 1px 0 rgba(0, 0, 0, 0.10);
}

/* THE OFFICE 2007 STATUS BAR, sampled off the vendor at x=900 rather than
   picked: a 1px rule at (116,116,116), a highlight row at (252,253,255), then
   TWO BANDS meeting at a hard crease 12px down -- (226,239,255) darkening to
   (173,209,255), then (174,209,255) lightening back to (189,217,255).

   PAIRED stops at one offset, the same device the ribbon's folder gradient
   uses: a single shared stop blends the crease and the glass goes flat, and
   the crease is the thing that makes it read as glass at all.

   Pixel stops, not percentages -- the bar is a fixed height and the crease
   sits 12px down whatever the window width. A percentage crease drifts.

   This is a STYLE THE APPLICATION NAMED, not a theme, so it is scoped to the
   class and the theme rules below are untouched: a bar with no 2007 clause
   looks exactly as it did. */
.nextxbase-msgbar.msgbar-2007 {
    /* The BACKGROUND is not here: it is emitted inline by TMSGBAR, because a
       theme layer (.os-windows.theme-system .nextxbase-msgbar, 0,3,0, and
       four more like it) outranks anything written against the element alone.
       An application-declared appearance beats our theme -- the same rule,
       and the same remedy, as the ribbon's declared colours.

       The border and the text colour stay, because nothing contests them at a
       higher weight. */
    border-top: 1px solid #747474;
    color: #000;
}
/* BLACK, because that is what the reference draws: the darkest pixel in its
   prompt is (9,0,6) and in its MayaPOS panel (34,5,14). #1b3a5c was a guess at
   a "status bar blue" and was never reached anyway -- see the inline note in
   TMSGBAR:GenerateHTML for why these two rules lose. They are corrected rather
   than deleted so the file does not carry a colour that would be wrong if it
   ever did win. */
.nextxbase-msgbar.msgbar-2007 .msgbar-prompt,
.nextxbase-msgbar.msgbar-2007 .msgbar-cell {
    color: #000;
}

/* A CELL DIVIDER IS TWO COLUMNS, NOT ONE. Read off the reference at x 1530..1532,
   the same three values at every row of the band:

       1530   the gradient, very slightly darkened
       1531   (177,177,177)   the rule
       1532   (248,251,255)   the highlight beside it

   We drew a single #e5e5e5 hairline, which is the flat-theme look and not the
   2007 one -- an etched divider has a dark edge and a light edge, and losing
   the light one is what makes a bevel read as a line. The highlight is an
   inset shadow rather than a second element so the cell keeps its width. */
.nextxbase-msgbar.msgbar-2007 .msgbar-cell {
    border-left: 1px solid #b1b1b1;
    box-shadow: inset 1px 0 0 #f8fbff;
}

/* THE RESIZE GRIP, counted dot by dot at x 1694..1707, y 900..912. It is a
   staircase of 2x2 blocks in an 8x8 box, and the vendor draws it at the very
   bottom-right of the bar:

       y 902   .  .  .  .  .  .  X
       y 905   .  .  .  X  .  .  X
       y 908   X  .  .  X  .  .  X

   Blocks at (6,0) (3,3) (6,3) (0,6) (3,6) (6,6), 3px apart both ways. Drawn as
   an SVG data URI rather than repeating gradients because the pattern is a
   fixed staircase and not a repeat -- a gradient would have to fake it, and
   the whole point of counting the dots was to stop approximating.

   Measured ink: x 1696..1703, rows 902..909, lightest (191,191,191) against a
   gradient at 180. */
.msgbar-grip {
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    width: 8px;
    height: 8px;
    margin-left: 4px;
    align-self: flex-end;
    -ms-flex-item-align: end;
    /* 3, not 2: measured, the grip sat one row low inside the band -- its
       first dot row at band-offset 12 where the reference puts it at 11. */
    margin-bottom: 3px;
    background-repeat: no-repeat;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cg fill='%23bfbfbf'%3E%3Crect x='6' y='0' width='2' height='2'/%3E%3Crect x='3' y='3' width='2' height='2'/%3E%3Crect x='6' y='3' width='2' height='2'/%3E%3Crect x='0' y='6' width='2' height='2'/%3E%3Crect x='3' y='6' width='2' height='2'/%3E%3Crect x='6' y='6' width='2' height='2'/%3E%3C/g%3E%3C/svg%3E");
}

.theme-system .nextxbase-msgbar,
.theme-light .nextxbase-msgbar,
.theme-system .nextxbase-buttonbar,
.theme-light .nextxbase-buttonbar,
.theme-system .nextxbase-ribbonbar,
.theme-light .nextxbase-ribbonbar,
.theme-system.control-theme-system.nextxbase-msgbar,
.theme-light.control-theme-light.nextxbase-msgbar,
.theme-system.control-theme-system.nextxbase-buttonbar,
.theme-light.control-theme-light.nextxbase-buttonbar,
.theme-system.control-theme-system.nextxbase-ribbonbar,
.theme-light.control-theme-light.nextxbase-ribbonbar {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
                0 1px 0 rgba(0, 0, 0, 0.08);
}

/* ==========================================================================
   THE RIBBON HAD ONLY EVER BEEN LOOKED AT IN A DARK THEME.

   These four themes repaint the ribbonbar LIGHT (#f3f3f3 / #ececec / #dfdcd8 /
   #e9e0cd) and had overrides for the ribbon BUTTONS only. Everything else in
   the ribbon -- the tab strip, the tabs, the panel, the group boxes, the group
   captions and the dividers between them -- was still drawing the dark theme's
   white-on-black overlays, so on a light bar the entire structure of the
   ribbon was invisible: white at 7% over #f3f3f3 is #f5f5f5.

   This is the same leak twice found and twice written down: A THEME THAT
   OVERRIDES A SURFACE OVERRIDES THAT SURFACE'S LIGHTING TOO. `background`
   alone is not the surface. Every overlay below is the light-side twin of the
   dark rule it shadows, in the same order, so the two can be read against each
   other.

   The active tab and the panel deliberately share one value. That shared
   surface is what makes a tab a tab rather than a highlighted word, and using
   a TRANSLUCENT white for both keeps them matched automatically across all
   four themes, whose bar colours differ.
   ========================================================================== */
.theme-system .nextxbase-ribbon-tabs,
.theme-light .nextxbase-ribbon-tabs,
.theme-light.control-theme-light.nextxbase-ribbon-tabs {
    background: rgba(0, 0, 0, 0.05);
    border-bottom-color: rgba(0, 0, 0, 0.10);
}

.theme-system .nextxbase-ribbon-tab,
.theme-light .nextxbase-ribbon-tab,
/* AND WHENEVER THE APPLICATION ITSELF MADE THE STRIP LIGHT. ribbon.prg puts
   this class on the bar when CONTRASTCLR says its nClrPaneRB is light, so an
   app-chosen ground reaches the SAME measured ink instead of a second answer.
   No dark theme styles .nextxbase-ribbon-tab at all -- checked, not assumed --
   so this selector is what covers the other 13. */
.nxb-ribbon-onlight .nextxbase-ribbon-tab,
.theme-system.control-theme-system.nextxbase-ribbon-tab,
.theme-light.control-theme-light.nextxbase-ribbon-tab {
    /* The vendor's folder caption, sampled: (21,66,139), and the SAME blue on
       the selected folder and the unselected ones. Light themes only -- this
       blue on the dark bar is unreadable, and nothing has been measured
       there. */
    color: #15428B;
    /* Ground and border belong to the SELECTED folder only -- see the base
       rule. An unselected one is its caption and nothing else. */
    background: transparent;
    border-color: transparent;
}

.theme-system .nextxbase-ribbon-tab:hover,
.theme-light .nextxbase-ribbon-tab:hover,
.nxb-ribbon-onlight .nextxbase-ribbon-tab:hover,
.theme-system.control-theme-system.nextxbase-ribbon-tab:hover,
.theme-light.control-theme-light.nextxbase-ribbon-tab:hover {
    color: #241f18;
    background: rgba(0, 0, 0, 0.06);
}

.theme-system .nextxbase-ribbon-tab.active,
.theme-light .nextxbase-ribbon-tab.active,
.nxb-ribbon-onlight .nextxbase-ribbon-tab.active,
.theme-system.control-theme-system.nextxbase-ribbon-tab.active,
.theme-light.control-theme-light.nextxbase-ribbon-tab.active {
    /* SAME BLUE AS THE UNSELECTED FOLDERS. The vendor sample that fixed that
       colour was taken ON the selected folder -- (21,66,139) on 'Archivos'
       and the identical value on 'Informes' beside it -- so the selection is
       marked by its raised white ground, not by recolouring its text. The
       gold here was a house accent doing a job the ground already does. */
    color: #15428B;
    background: rgba(255, 255, 255, 0.62);
    border-color: rgba(0, 0, 0, 0.16);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95);
}

.theme-system .nextxbase-ribbon-body,
.theme-light .nextxbase-ribbon-body,
.theme-system.control-theme-system.nextxbase-ribbon-body,
.theme-light.control-theme-light.nextxbase-ribbon-body {
    background: rgba(255, 255, 255, 0.62);
    border-top-color: rgba(0, 0, 0, 0.16);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85);
}

.theme-system .nextxbase-ribbon-group,
.theme-light .nextxbase-ribbon-group,
.theme-system.control-theme-system.nextxbase-ribbon-group,
.theme-light.control-theme-light.nextxbase-ribbon-group {
    background: rgba(255, 255, 255, 0.72);
    border-color: rgba(0, 0, 0, 0.12);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

/* THE RING, RELIT WITH THE GROUND. The rule above turns the group's ground
   from the default dark to rgba(255,255,255,0.72), and the engine's white
   ring then measures 1.003:1 against it -- white on white, no boundary. The
   colour here is not invented: it is border-color from the very rule above,
   which these groups declare and cannot use because a placed group's
   border-width is 0. Drawing the ring in it reads 1.314:1.

   It must sit AFTER that rule: both are (0,2,0) and the later one wins.
   Without it the group's box-shadow above -- a top BEVEL, not a ring --
   would take the element and delete the boundary rather than recolour it. */
.theme-system .nxb-rbgroup-ring,
.theme-light .nxb-rbgroup-ring,
.theme-system.control-theme-system.nxb-rbgroup-ring,
.theme-light.control-theme-light.nxb-rbgroup-ring {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}

/* Dark hairline then light, same groove as everywhere else -- but the two
   hairlines swap strength on a light surface, because the shadow is the side
   that has to carry it. */
.theme-system .nextxbase-ribbon-group:not(:last-child)::after,
.theme-light .nextxbase-ribbon-group:not(:last-child)::after,
.theme-light.control-theme-light.nextxbase-ribbon-group:not(:last-child)::after {
    border-left-color: rgba(0, 0, 0, 0.14);
    border-right-color: rgba(255, 255, 255, 0.9);
}

.theme-system .ribbon-group-caption,
.theme-light .ribbon-group-caption {
    /* SAMPLED OFF THE VENDOR, not chosen: the darkest ink in its group
       caption is (103,110,125), a slate that leans BLUE -- blue is its
       highest channel. Ours was #5d564c = (93,86,76), which leans the other
       way entirely, red highest and blue lowest, so the two captions read as
       different colours rather than different shades. Both were measured at
       the darkest pixel, where antialiasing against the tan has not lightened
       the value, and #5d564c came back byte-exact -- which is what makes the
       comparison a like-for-like one. */
    color: #676e7d;
    /* NO RULE ABOVE THE CAPTION. Sampled down x=200 through the card, the
       vendor runs its gradient straight into the caption band -- rows 203..210
       step (207,184,151) to (206,181,147) with nothing interrupting them. Ours
       drew (181,159,129) across row 205, which is this border.

       TRANSPARENT rather than removed: the 1px still occupies its row, so the
       caption does not move up and the card keeps the 171-row span it now
       matches the vendor on. A border that is merely invisible is the cheap
       way to change one thing at a time here. */
    border-top-color: transparent;
}

.theme-system .nextxbase-grid-container thead th,
.theme-light .nextxbase-grid-container thead th,
.theme-system table.nextxbase-grid thead th,
.theme-light table.nextxbase-grid thead th,
.theme-system.control-theme-system.nextxbase-grid-container thead th,
.theme-light.control-theme-light.nextxbase-grid-container thead th {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85);
}

/* ─────────────────────────────────────────────────────────────── */
/* Title bar — the caption strip a dialog draws its own heading on  */
/* ─────────────────────────────────────────────────────────────── */

/* THIS CLASS WAS EMITTED AND NEVER DEFINED. compat_classes.prg has always
   written class='nextxbase-title', and the sheet had no rule for it, so every
   title in the tree rendered on its inline style alone -- position, size and
   background and nothing else.

   NO BACKGROUND HERE, DELIBERATELY. A title is a bar the application colours
   itself: COLORBOX and GRADIENT are how the corpus writes it, both arrive
   inline, and a class background would be a rule that loses to every title
   that declares one and wins on every title that does not -- which is the
   worst of both. The ground stays the inline style's. */
.nextxbase-title {
    box-sizing: border-box;
    border: 1px solid rgba(184, 148, 42, 0.35);
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    padding: 0 8px;
    font-size: 12px;
    font-weight: 600;
    color: #e8e4dc;
}

.nextxbase-title-round {
    border-radius: 6px;
}

/* NOBORDER, and it is the reason the border above is a class rule rather than
   inline: a clause that removes something needs something to remove. */
.nextxbase-title-noborder {
    border: none;
}

/* BASE — the classic's bottom-anchored variant, a strip that reads as the
   foot of the surface above it rather than as a raised bar of its own. Only
   the edge that meets that surface is drawn. */
.nextxbase-title-base {
    border-top: none;
    border-left: none;
    border-right: none;
}

/* The caption declared on the title itself (TEXT <c>), as opposed to a
   TTITLETEXT child placed at explicit coordinates. It is in the flex flow, so
   it centres vertically in the bar whatever the bar's height; a child with
   coordinates is absolutely positioned and paints over it, which is the order
   the emitter writes them in. */
.nextxbase-title-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.theme-light .nextxbase-title,
.theme-system .nextxbase-title,
.theme-light.control-theme-light.nextxbase-title,
.theme-system.control-theme-system.nextxbase-title {
    border-color: rgba(0, 0, 0, 0.18);
    color: #2b2822;
}

.nextxbase-msgbar {
    background: linear-gradient(to bottom, #201d17 0%, #1a1814 60%, #131110 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
    display: flex;
    display: -ms-flexbox;
    flex-direction: row;
    -ms-flex-direction: row;
    align-items: center;
    -ms-flex-align: center;
    height: 100%;
    box-sizing: border-box;
    /* The reference starts its prompt ink at x=4 with a 1px window border, so
       3px of padding. 10 pushed ours to x=11 and shortened the right-hand
       cells by the same amount at the other end. */
    padding: 0 3px;
    background: #1a1814;
    border-top: 1px solid rgba(184, 148, 42, 0.35);
    font-size: 12px;
    color: #d0ccc4;
    /* PRE, NOT NOWRAP -- an xBase string carries its spacing as DATA.

       MayaPOS builds its prompt as

           '-- ' + alltrim( nempresa ) + SPACE( 05 ) + FechaLet()

       and the reference draws that SPACE(05) as a 16px gap between the company
       name and the date; FechaLet() pads inside itself too. Under nowrap every
       one of those runs collapsed to a single space, so the two fields ran
       together and the bar read as one sentence instead of two fields. Neither
       string nor emitter was wrong -- the text was correct and HTML was
       throwing the spacing away before it reached the glass.

       pre keeps runs of spaces and still never wraps, which is what nowrap was
       there for. Applied to the bar rather than to the 2007 style: padding is
       how xBase code aligns anything, so this is fidelity to the string, not
       an appearance a particular bar asked for. */
    white-space: pre;
    overflow: hidden;
}

.msgbar-prompt {
    flex: 1 1 auto;
    -ms-flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    /* No letter-spacing: it is not the application's, and it stretched a
       prompt the reference draws at the font's own metrics. */
}

/* THE CELL IS 27 WIDE, NOT 45, and the icon was never the problem. Read off
   the reference between its two dividers:

       divider    1530..1532        divider    1557..1559
       icon ink   1537..1549  13 x 16

   so 27px of cell around a 13px icon -- about 6 either side. Ours put 10px of
   margin AND 10px of padding around a 12px icon and came out 45, which pushed
   our first divider to x 1512 against the reference's 1530 while the SECOND
   divider, at 1557, was already exactly right. One cell too wide moves every
   boundary to its left and none to its right, which is why only one of the two
   looked wrong.

   The margin goes entirely: the divider IS the separation, and adding a margin
   to it spaces the cells twice. */
.msgbar-cell {
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    padding: 2px 5px;
    border-left: 1px solid rgba(212, 175, 55, 0.20);
    color: #d4af37;
    font-variant-numeric: tabular-nums;
}

/* INS/OVR is a toggle: it must be legible when off, not invisible. */
.msgbar-keyboard {
    min-width: 34px;
    text-align: center;
}

.msgbar-date {
    min-width: 84px;
    text-align: center;
}

/* ==========================================================================
/* Buttonbar buttons stack the icon ABOVE the caption, which is what a
/* the reference implementation STYLEBAR looks like -- DEFINE BUTTONBAR ... SIZE 70, 70 declares a
/* SQUARE button precisely because the art sits over the label. Laid out in a
/* row they read as a web toolbar, not as the application being ported, and
/* the 32x32 art was being shrunk to 24px for a row that did not need it.
/* Only inside a buttonbar: a ribbon small-button is genuinely a row.
/* ========================================================================== */
.nextxbase-buttonbar .nextxbase-ribbon-btn {
    flex-direction: column;
    -ms-flex-direction: column;
    justify-content: center;
    -ms-flex-pack: center;
    padding: 6px 4px;
    line-height: 1.2;
    /* ADJACENT BAR BUTTONS SHARE A BORDER, NOT A GAP. The generic
       .nextxbase-ribbon-btn rule adds margin-right:4px for a ribbon's spaced
       groups; on a BUTTONBAR the reference's native buttons measure
       x 0..155, 153..308, 306..461 physical (FiveDBU SIZE 70,70 at 225%):
       each starts one logical px inside the previous one. Ours sat 7
       physical px apart. -1px reproduces the overlap; what remains is our
       70-wide button against their 69 (measured 2026-09-02). */
    margin-right: -1px;
}

.nextxbase-buttonbar .ribbon-icon {
    width: 32px;
    height: 32px;
    margin-bottom: 2px;
}

/* A SEGMENTED BUTTON, WHICH IS WHAT THE REFERENCE DRAWS. Measured off the
   the reference implementation FiveDBU toolbar (ADO / MySQL / Index / Replacement): a strip on the
   right edge running the FULL height of the button, split from the caption by
   one vertical rule, with a small centred arrow inside.

   This used to be `right: 4px; bottom: 3px` -- a 9px glyph parked in the
   bottom-right corner, with its 1px divider reduced to a stub beside it. The
   owner reported both halves of that: "the arrow shows a little line at the
   right and the arrow is too small".

   The strip is a target, not a decoration: it is the region you aim at to open
   the menu, so it has to be the height of the thing it belongs to. */
/* SPECIFICITY IS PART OF THIS RULE, NOT AN ACCIDENT OF IT. The generic
   `.nextxbase-btn-wrap.has-menu .btn-caret` above is 0,3,0 and makes the caret
   a positioning context for the ribbon's divider; a bare
   `.nextxbase-buttonbar .btn-caret` is 0,2,0 and LOSES to it, leaving the caret
   inline to wrap under the caption. Both rules are wanted, so this one names
   the wrap too and wins at 0,4,0. */
.nextxbase-buttonbar .nextxbase-btn-wrap.has-menu .btn-caret {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 13px;
    margin-left: 0;
    padding-left: 0;
    border-left: 1px solid rgba(0, 0, 0, 0.30);
    /* The glyph lives in ::after so the strip can size and divide independently
       of it -- font-size here would drag the centring around with the arrow. */
    font-size: 0;
    /* The generic .btn-caret is 0.75, which is right beside a caption and wrong
       alone in a strip: at that weight it reads as a disabled control. The
       reference draws this arrow solid. */
    opacity: 1;
}

/* Centred with top:50% and a negative margin rather than flexbox: the viewport
   is MSHTML in IE11 document mode, where the modern answer silently does not
   lay out. Half of line-height is the offset. */
.nextxbase-buttonbar .nextxbase-btn-wrap.has-menu .btn-caret::after {
    content: '\25BE';
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    margin-top: -7px;
    line-height: 14px;
    /* ~9px of glyph, which is what the reference draws. 11px rendered about 7
       and read as "the arrow is too small", which is how the owner reported it. */
    font-size: 14px;
    text-align: center;
}

/* The caption must not run under the strip. */
/* A MENU BUTTON IS THE DECLARED WIDTH PLUS ITS ARROW STRIP, NOT THE DECLARED
   WIDTH WITH THE ARROW SQUEEZED INSIDE. FiveDBU's ADO and MySQL buttons
   (SIZE 70,70, each with a MENU) measure 185 physical px on the reference
   against 155 for their plain neighbours: 69 + 13 logical. Ours kept the
   button at 70 and carved 15px of padding out of it for the caret, so the
   caption was pushed and every button to the right sat 12 logical px too
   far left. The strip is the wrap's right padding; the caret (absolute,
   right:0, 13px) lands in it; the button keeps the plain padding. */
.nextxbase-buttonbar .nextxbase-btn-wrap.has-menu {
    padding-right: 13px;
}
.nextxbase-buttonbar .has-menu .nextxbase-ribbon-btn {
    padding-right: 4px;
}
/* A GROUP SEPARATOR ON A BAR IS 7 LOGICAL PX: the reference's Paste..Previous
   and Next..Exit gaps measure 16 physical (826..842, 1150..1166) where the
   ribbon-flavoured 12 + 12 + 1 below gave 54. Bar-scoped; the ribbon keeps
   its own spacing. */
.nextxbase-buttonbar .nextxbase-btn-wrap.btn-group-start {
    margin-left: 3px;
    padding-left: 3px;
}

/* The generic divider is drawn by the strip's own border-left here, so the
   ribbon ::before rule must not also paint one. */
.nextxbase-buttonbar .nextxbase-btn-wrap.has-menu .btn-caret::before {
    display: none;
}

.nextxbase-buttonbar .nextxbase-ribbon-btn {
    position: relative;
}

/* A WHEN clause that evaluates .F. emits `disabled`, and the button rendered
   exactly like an enabled one -- the gate was honoured in the markup and
   invisible on screen. Found by looking at the page, not by reading it: no
   class is involved, so the orphan-class audit cannot see this one. */
.nextxbase-ribbon-btn:disabled,
.nextxbase-ribbon-btn[disabled] {
    opacity: 0.38;
    cursor: default;
    filter: grayscale(70%);
    border-color: rgba(255, 255, 255, 0.04);
}

.nextxbase-ribbon-btn:disabled:hover,
.nextxbase-ribbon-btn[disabled]:hover {
    background: #2a2720;
    border-color: rgba(255, 255, 255, 0.04);
    color: #d0ccc4;
    box-shadow: none;
}

/* ==========================================================================
/* BTNBMP icon, and the RADIO group
/*
/* Both found by pointing tools/audit_css_reach.php at the CONTROL FIXTURE
/* rather than at FiveDBU -- neither control appears on the FiveDBU page, so
/* the audit had nothing to say about them. An audit only reports on the page
/* you give it; the fixture exists precisely because it declares everything.
/*
/* .btn-icon was an orphan, so a BTNBMP bitmap rendered at its NATURAL size
/* inside a 120x32 button with overflow:hidden -- a 256px icon.png showed up
/* as a clipped arc bleeding over the neighbouring control. It looked like a
/* layout bug and was a missing width.
/*
/* .nextxbase-radio / .nextxbase-radio-item were orphans too: the group was
/* implemented and emitted and had no styling whatsoever.
/* ========================================================================== */
.btn-icon {
    width: 18px;
    height: 18px;
    vertical-align: middle;
    margin-right: 6px;
    flex: 0 0 auto;
}

/* The button carries 16px of side padding, which is right for a plain caption
   and wrong once an icon is in front of it: "With Icon" in a SIZE 120,32
   BTNBMP overflowed by a few pixels and rendered as "With". A declared size
   should hold the caption it was declared with.

   Keyed off a class the emitter writes, not :has() -- the viewport is MSHTML
   and :has() would simply never match there, which is the fail-open shape
   audit_css_reach.php exists to catch. */
.nextxbase-btn.has-icon {
    padding-left: 9px;
    padding-right: 9px;
}

.nextxbase-btn.icon-only,
.nextxbase-button.icon-only {
    padding: 0 !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    text-align: center !important;
}

.nextxbase-btn.icon-only .btn-icon,
.nextxbase-button.icon-only .btn-icon {
    margin: 0 !important;
    margin-right: 0 !important;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.nextxbase-btn.icon-only .nxb-btn-label,
.nextxbase-button.icon-only .nxb-btn-label {
    display: none !important;
}

/* A RADIO GROUP STACKS. Measured against the reference on ctl_fixture, whose
   three items sit at y 222 and y 246 -- one per row, the declared 24 apart --
   where ours put all three on one line at y 221. The row was explicit here, so
   no application could ever get the stack the vendor gives it.
   align-items moves to flex-start with the direction: centred on a column axis
   would centre every item HORIZONTALLY, which is a second, subtler wrong
   answer. */
.nextxbase-radio {
    display: flex;
    display: -ms-flexbox;
    flex-direction: column;
    -ms-flex-direction: column;
    align-items: flex-start;
    -ms-flex-align: start;
}

/* A `color: #1a1814` stood in the rule above, at column 0 after a blank line,
   inside a block whose comment is entirely about flex direction. It made every
   radio label unreadable on every dark theme, and no theme could reach it.

   THE PRINCIPLE, because this is not about one rule. A theme paints by setting
   `color` on an ANCESTOR -- body, .nextxbase-window, #nxb-stage. Inheritance
   loses to specificity ALWAYS, so any rule that sets `color` on a control class
   defeats every theme at once, silently, and looks like a harmless default.

   MEASURED 2026-09-05 on ctllab, with audit_theme_contrast driving all 15
   themes: `Alpha` and `Beta` at 1.00:1 under charcoal -- rgb(26,24,20) ink on
   rgb(24,24,27) ground, text and ground the same colour. The photograph shows
   two radio dots with no labels; the labels are there, painted black on black.

   It is a DELETION and not a new value on purpose: body already declares
   `color: #1a1814`, and so does every light theme, so the inherited ink under
   those is the same byte for byte and nothing moves. Only the dark themes
   change, which is the whole defect.

   Do NOT put an ink back on a control class unless the themes target that
   class too. If a control needs its own ink, it needs its own ground in the
   same breath -- see TLISTVIEW, which had the mirror image of this bug. */

/* ==========================================================================
   THE DEFAULT GUI FONT SIZE -- ONE DEFINITION FOR THE SIX BASIC CONTROLS.
   ==========================================================================
   Each of these rules used to carry its own `font-size: 14px`, six copies of
   one decision, and the decision was wrong by 14/12 against the reference.
   Measured 2026-09-02 on ctl_fixture, both builds, native rects in logical
   px: an unsized SAY carrying the same 50-character caption is 262 wide in
   the reference and was 309 here (ratio 1.18 = 14/12); the reference's
   unsized CHECKBOX shows "Bound checkbc" in its 100px box where we showed
   "Bound chec". The reference draws with the system GUI font, 9pt Segoe UI
   = 12 logical px. A control that declares FONT overrides this inline, as
   before. IE11 has no custom properties, so one grouped rule is the one
   definition; do not put the size back on the individual rules. */
.nextxbase-say,
.nextxbase-get,
.nextxbase-btn,
.nextxbase-chk-label,
.nextxbase-cbo,
.nextxbase-radio {
    font-size: 12px;
}


.nextxbase-radio-item {
    display: inline-flex;
    display: -ms-inline-flexbox;
    align-items: center;
    -ms-flex-align: center;
    cursor: pointer;
    white-space: nowrap;
}

.nextxbase-radio-item input[type=radio] {
    width: 15px;
    height: 15px;
    cursor: pointer;
    margin: 0;
}

/* WHEN and DEFAULT on a plain @ ... BUTTON were honoured in the MARKUP and
   invisible on screen -- "Gated" (WHEN .F.) rendered identically to an
   enabled button, and "Default" was indistinguishable from any other. The
   same defect was fixed for the buttonbar and left standing here, which is
   what a fix applied to one call site instead of to the class looks like.
   Neither is reachable by the orphan-class audit: one is an attribute, the
   other a pseudo-class. Only looking finds them. */
/* THE SECOND DISABLED RULE, and it used to say `opacity: 0.4; filter:
   grayscale(60%)`. The first one (above, ~line 815) already paints a disabled
   button the way the reference does -- opaque, grey text on a grey face --
   and this later block then made the whole button 40% transparent, so
   anything BEHIND a disabled button showed through it. Measured on
   ctl_fixture 2026-09-02: the radio's third item "Gamma" sits under the
   WHEN .F. button "Gated" by design; the reference hides it, ours showed
   both captions on top of each other. Two rules for one state is the fork
   CLAUDE.md 0-C forbids; this one keeps only what the first does not say. */
.nextxbase-btn:disabled,
.nextxbase-btn[disabled] {
    cursor: default;
}

.nextxbase-btn:disabled:hover,
.nextxbase-btn[disabled]:hover {
    background: #1a1814;
    border-color: rgba(184, 148, 42, 0.35);
    color: #d4af37;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.15), 0 8px 16px rgba(0, 0, 0, 0.1);
}

/* The DEFAULT button is the one Enter activates; the reference implementation gives it a heavier
   border, and so does every native dialog. */
.nextxbase-btn[data-default='1'] {
    border-color: #d4af37;
    box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.28), 0 2px 4px rgba(0, 0, 0, 0.2);
}

/* ==========================================================================
/* Selection: chrome is not text, data is
/*
/* Dragging across a menu, a button or the status bar produced the browser's
/* blue selection band -- correct for a document, wrong for an application:
/* no desktop app lets you rubber-band its menubar. The whole SHELL is now
/* unselectable.
/*
/* The grid, the tree and form fields are deliberately LEFT selectable. The
/* blanket "user-select:none on body" that this is often written as would
/* take copy-out with it, and being unable to copy a cell out of a browse is
/* a worse bug than the one being fixed.
/* ========================================================================== */
.nextxbase-menubar,
.nextxbase-menu-popup,
.nextxbase-btn-menu,
.nextxbase-buttonbar,
.nextxbase-ribbonbar,
.nextxbase-btn,
.nextxbase-ribbon-btn,
.nextxbase-msgbar,
.nextxbase-slot-titlebar,
.nextxbase-chk-label,
.nextxbase-radio-item,
.nextxbase-group-caption,
.nextxbase-group-legend,
.nextxbase-say {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* A menu entry carries no href now, so it needs its cursor stated. */
.nextxbase-menu-link {
    cursor: pointer;
}

/* Data stays selectable, explicitly, so a future blanket rule cannot quietly
   take copy-out away again. */
.nextxbase-grid-container tbody td,
table.nextxbase-grid tbody td,
.nextxbase-get,
input.nextxbase-get,
textarea {
    -webkit-user-select: text;
    -moz-user-select: text;
    -ms-user-select: text;
    user-select: text;
}

/* ==========================================================================
/* THEMES
/*
/* Every theme name -- system, dark, citrus, glassmorphism -- used to resolve
/* to the SAME light palette; theme-dark literally set background:#f5f3ef, a
/* light background under a dark name. Four names, one appearance, which is why
/* nothing could ever tell them apart.
/*
/* There are now three real ones:
/*
/*   theme-system  the HOST's own palette, picked by the os-* class the engine
/*                 already sets at startup. Windows, macOS and GNOME do not
/*                 look alike, and an app that claims to follow the system has
/*                 to follow whichever system it is on. This is the DEFAULT.
/*   theme-light   a warm light palette. Light is not white-and-grey -- flat
/*                 white chrome reads as unfinished, and grey reads as
/*                 disabled. This one is parchment with the gold accent the
/*                 rest of the shell already uses.
/*   theme-dark    the existing dark shell, unchanged.
/*
/* The os-* classes are applied by JS at runtime, so they never appear in the
/* emitted markup -- which is why tools/audit_css_reach.php cannot see them and
/* did not report them as orphans while they matched nothing at all.
/*
/* Explicit selectors, no CSS custom properties: the viewport is MSHTML.
/* ========================================================================== */

/* ---------------------------------------------------------------------- */
/* theme-system : WINDOWS  (Fluent / Windows 11 light)                     */
/* ---------------------------------------------------------------------- */
/* The workspace tracks the window's ground in every theme, so the colour a
   SAY erases with and the colour behind it never disagree. */
.os-windows.theme-system .nextxbase-window,
.os-windows.theme-system .nextxbase-slot-workspace {
    background-color: #f3f3f3;
}

.os-windows.theme-system .nextxbase-titlebar,
.os-windows.theme-system .nextxbase-menubar,
.os-windows.theme-system .nextxbase-buttonbar,
.os-windows.theme-system .nextxbase-ribbonbar,
.os-windows.theme-system .nextxbase-msgbar {
    background: #f3f3f3;
    border-color: #e5e5e5;
    color: #1b1b1b;
}

.os-windows.theme-system .titlebar-caption,
.os-windows.theme-system .msgbar-prompt,
.os-windows.theme-system .nextxbase-menu-link,
.os-windows.theme-system ul.nextxbase-menu-popup .nextxbase-menu-link {
    color: #1b1b1b;
}

.os-windows.theme-system .msgbar-cell {
    color: #0067c0;
    border-left-color: #e5e5e5;
}

.os-windows.theme-system ul.nextxbase-menu-popup {
    background: #f9f9f9;
    border: 1px solid #e5e5e5;
    border-radius: 8px;
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.14);
}

.os-windows.theme-system .nextxbase-menu-link:hover,
.os-windows.theme-system ul.nextxbase-menu-popup .nextxbase-menu-link:hover {
    background: rgba(0, 0, 0, 0.05);
    color: #1b1b1b;
}

.os-windows.theme-system .nextxbase-menu-item.is-open > .nextxbase-menu-link {
    background: rgba(0, 103, 192, 0.12);
    color: #0067c0;
}

.os-windows.theme-system .nextxbase-ribbon-btn,
.os-windows.theme-system .nextxbase-btn {
    background: #fbfbfb;
    border-color: #e0e0e0;
    color: #1b1b1b;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}

.os-windows.theme-system .nextxbase-ribbon-btn:hover,
.os-windows.theme-system .nextxbase-btn:hover {
    background: #f0f0f0;
    border-color: #d0d0d0;
    color: #1b1b1b;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.os-windows.theme-system .nextxbase-btn[data-default='1'] {
    background: #0067c0;
    border-color: #0067c0;
    color: #ffffff;
    box-shadow: none;
}

.os-windows.theme-system .nextxbase-grid-container thead th,
.os-windows.theme-system table.nextxbase-grid thead th {
    background: #f3f3f3;
    color: #1b1b1b;
    border-bottom-color: #e5e5e5;
}

.os-windows.theme-system .nextxbase-menu-separator {
    border-top-color: #e5e5e5;
}

/* ---------------------------------------------------------------------- */
/* theme-system : macOS                                                    */
/* ---------------------------------------------------------------------- */
.os-macos.theme-system .nextxbase-titlebar,
.os-macos.theme-system .nextxbase-menubar,
.os-macos.theme-system .nextxbase-buttonbar,
.os-macos.theme-system .nextxbase-ribbonbar,
.os-macos.theme-system .nextxbase-msgbar {
    background: #ececec;
    border-color: #d6d6d6;
    color: #1d1d1f;
}

.os-macos.theme-system .titlebar-caption,
.os-macos.theme-system .msgbar-prompt,
.os-macos.theme-system .nextxbase-menu-link,
.os-macos.theme-system ul.nextxbase-menu-popup .nextxbase-menu-link {
    color: #1d1d1f;
}

.os-macos.theme-system .msgbar-cell {
    color: #007aff;
    border-left-color: #d6d6d6;
}

.os-macos.theme-system ul.nextxbase-menu-popup {
    background: #f5f5f7;
    border: 1px solid #d6d6d6;
    border-radius: 8px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.22);
}

.os-macos.theme-system .nextxbase-menu-link:hover,
.os-macos.theme-system ul.nextxbase-menu-popup .nextxbase-menu-link:hover,
.os-macos.theme-system .nextxbase-menu-item.is-open > .nextxbase-menu-link {
    background: #007aff;
    color: #ffffff;
}

.os-macos.theme-system .nextxbase-ribbon-btn,
.os-macos.theme-system .nextxbase-btn {
    background: #ffffff;
    border-color: #d0d0d0;
    color: #1d1d1f;
    border-radius: 7px;
}

.os-macos.theme-system .nextxbase-btn[data-default='1'] {
    background: #007aff;
    border-color: #007aff;
    color: #ffffff;
}

.os-macos.theme-system .nextxbase-grid-container thead th,
.os-macos.theme-system table.nextxbase-grid thead th {
    background: #ececec;
    color: #1d1d1f;
    border-bottom-color: #d6d6d6;
}

.os-macos.theme-system .nextxbase-menu-separator {
    border-top-color: #d6d6d6;
}

/* ---------------------------------------------------------------------- */
/* theme-system : LINUX  (Adwaita / GNOME)                                 */
/* ---------------------------------------------------------------------- */
.os-linux.theme-system .nextxbase-titlebar,
.os-linux.theme-system .nextxbase-menubar,
.os-linux.theme-system .nextxbase-buttonbar,
.os-linux.theme-system .nextxbase-ribbonbar,
.os-linux.theme-system .nextxbase-msgbar {
    background: #dfdcd8;
    border-color: #cdc7c2;
    color: #2e3436;
}

.os-linux.theme-system .titlebar-caption,
.os-linux.theme-system .msgbar-prompt,
.os-linux.theme-system .nextxbase-menu-link,
.os-linux.theme-system ul.nextxbase-menu-popup .nextxbase-menu-link {
    color: #2e3436;
}

.os-linux.theme-system .msgbar-cell {
    color: #1c71d8;
    border-left-color: #cdc7c2;
}

.os-linux.theme-system ul.nextxbase-menu-popup {
    background: #f6f5f4;
    border: 1px solid #cdc7c2;
    border-radius: 6px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.20);
}

.os-linux.theme-system .nextxbase-menu-link:hover,
.os-linux.theme-system ul.nextxbase-menu-popup .nextxbase-menu-link:hover,
.os-linux.theme-system .nextxbase-menu-item.is-open > .nextxbase-menu-link {
    background: #3584e4;
    color: #ffffff;
}

.os-linux.theme-system .nextxbase-ribbon-btn,
.os-linux.theme-system .nextxbase-btn {
    background: #f6f5f4;
    border-color: #cdc7c2;
    color: #2e3436;
    border-radius: 5px;
}

.os-linux.theme-system .nextxbase-btn[data-default='1'] {
    background: #3584e4;
    border-color: #3584e4;
    color: #ffffff;
}

.os-linux.theme-system .nextxbase-grid-container thead th,
.os-linux.theme-system table.nextxbase-grid thead th {
    background: #dfdcd8;
    color: #2e3436;
    border-bottom-color: #cdc7c2;
}

.os-linux.theme-system .nextxbase-menu-separator {
    border-top-color: #cdc7c2;
}

/* ---------------------------------------------------------------------- */
/* theme-light : warm, not white-and-grey                                  */
/*                                                                          */
/* Also the setting the shipped the reference implementation bitmaps were drawn for: their       */
/* anti-aliased edges were blended against a light system background, so a  */
/* pale fringe is baked into the pixels beside the magenta. Keying cannot   */
/* remove it -- the reference implementation shows the same halo on dark chrome.                 */
/* ---------------------------------------------------------------------- */
.theme-light .nextxbase-titlebar,
.theme-light .nextxbase-menubar,
.theme-light .nextxbase-buttonbar,
.theme-light .nextxbase-ribbonbar,
.theme-light .nextxbase-msgbar,
.theme-light.control-theme-light.nextxbase-menubar,
.theme-light.control-theme-light.nextxbase-buttonbar,
.theme-light.control-theme-light.nextxbase-ribbonbar,
.theme-light.control-theme-light.nextxbase-msgbar {
    background: #e9e0cd;
    border-color: #cdbf9f;
    color: #2b2419;
}

.theme-light .nextxbase-window,
.theme-light .nextxbase-slot-workspace,
.theme-light.control-theme-light.nextxbase-slot-workspace {
    background: #f4efe4;
}

.theme-light .titlebar-caption {
    color: #6b4f0a;
}

.theme-light .msgbar-prompt {
    color: #2b2419;
}

.theme-light .msgbar-cell {
    color: #8a6a12;
    border-left-color: #cdbf9f;
}

.theme-light .nextxbase-menu-link,
.theme-light ul.nextxbase-menu-popup .nextxbase-menu-link,
.theme-light.control-theme-light.nextxbase-menu-link {
    color: #2b2419;
}

/* A CHECKED MENU ITEM IS GOLD, and the base rule paints it #d4af37 -- which is
   a DARK-CHROME gold. This theme's menubar ground is #e9e0cd, so the tick and
   its caption measured 1.60:1: "Dark Mode" and its check unreadable in the one
   theme where a user is most likely to be reading it.
   #8a6a12 IS NOT A COLOUR PICKED TO PASS -- it is this theme's own gold,
   already used for .msgbar-cell on the same #e9e0cd ground twenty lines above,
   so the checked state keeps its hue and its meaning. Measured 3.80:1. */
.theme-light .nextxbase-menu-item.is-checked > .nextxbase-menu-link {
    color: #8a6a12;
}

.theme-light ul.nextxbase-menu-popup {
    background: #fffdf7;
    border: 1px solid #ddd0b0;
    box-shadow: 0 10px 26px rgba(70, 55, 20, 0.20);
}

.theme-light .nextxbase-menu-link:hover,
.theme-light ul.nextxbase-menu-popup .nextxbase-menu-link:hover,
.theme-light .nextxbase-menu-item.is-open > .nextxbase-menu-link,
.theme-light.control-theme-light.nextxbase-menu-link:hover,
.theme-light.control-theme-light.nextxbase-menu-item.is-open > .nextxbase-menu-link {
    background: rgba(184, 148, 42, 0.20);
    color: #6b4f0a;
}

.theme-light .nextxbase-menu-separator,
.theme-light.control-theme-light.nextxbase-menu-separator {
    border-top-color: #ddd0b0;
}

.theme-light .nextxbase-ribbon-btn,
.theme-light .nextxbase-btn,
.theme-light.control-theme-light.nextxbase-ribbon-btn,
.theme-light.control-theme-light.nextxbase-btn {
    background: #fffdf7;
    border-color: #cdbf9f;
    color: #2b2419;
}

.theme-light .nextxbase-ribbon-btn:hover,
.theme-light .nextxbase-btn:hover,
.theme-light.control-theme-light.nextxbase-ribbon-btn:hover,
.theme-light.control-theme-light.nextxbase-btn:hover {
    background: #ffffff;
    border-color: #b8942a;
    color: #6b4f0a;
}

.theme-light .nextxbase-btn:disabled:hover,
.theme-light .nextxbase-btn[disabled]:hover,
.theme-light .nextxbase-ribbon-btn:disabled:hover,
.theme-light .nextxbase-ribbon-btn[disabled]:hover,
.theme-light.control-theme-light.nextxbase-btn:disabled:hover,
.theme-light.control-theme-light.nextxbase-btn[disabled]:hover,
.theme-light.control-theme-light.nextxbase-ribbon-btn:disabled:hover,
.theme-light.control-theme-light.nextxbase-ribbon-btn[disabled]:hover {
    background: #fffdf7;
    border-color: #cdbf9f;
    color: #2b2419;
}

.theme-light .nextxbase-btn[data-default='1'],
.theme-light.control-theme-light.nextxbase-btn[data-default='1'] {
    border-color: #b8942a;
    box-shadow: 0 0 0 2px rgba(184, 148, 42, 0.32);
}

.theme-light .nextxbase-grid-container thead th,
.theme-light table.nextxbase-grid thead th,
.theme-light.control-theme-light.nextxbase-grid-container thead th {
    background: #e9e0cd;
    color: #6b4f0a;
    border-bottom-color: #b8942a;
}

/* The ribbon button clips its own caption. overflow:hidden on the button --
   there for a ripple effect that does not exist -- cut "Rotate Keys" and
   "Audit Logs" straight through the descenders, rendering them "Rotate Kevs"
   and "Audit Loas". Raising min-height did NOT fix it, which is the tell that
   the height was never the constraint: the clip edge was.

   Text is allowed out of the box; the BACKGROUND still cannot escape, because
   the border-radius clips paint regardless of overflow. */
.nextxbase-ribbon-btn {
    overflow: visible;
}

/* ==========================================================================
/* THEME CROSSFADE
/*
/* The theme swap already animated, but only by accident and only in half the
/* shell: buttons, menu links and ribbon tabs carry "transition: all .3s" for
/* their HOVER states, and because that is "all" rather than a named list, it
/* caught background and colour when the theme class changed too. The bars
/* themselves carry no transition at all, so the chrome snapped while the
/* controls on top of it faded -- two speeds in one repaint.
/*
/* The surfaces are given the same 0.3s so the whole shell crossfades as one.
/* Named properties, never "all": these elements own layout, and animating
/* "all" would drag width/padding/position into any future change of theirs.
/* ========================================================================== */
.nextxbase-titlebar,
.nextxbase-menubar,
.nextxbase-buttonbar,
.nextxbase-ribbonbar,
.nextxbase-ribbon-group,
.nextxbase-msgbar,
.nextxbase-msgbar .msgbar-cell,
.nextxbase-msgbar .msgbar-prompt,
.nextxbase-titlebar .titlebar-caption,
.nextxbase-window,
.nextxbase-slot-workspace,
ul.nextxbase-menu-popup,
.nextxbase-menu-separator,
.nextxbase-grid-container thead th,
table.nextxbase-grid thead th {
    transition: background-color 0.3s ease,
                border-color 0.3s ease,
                color 0.3s ease,
                box-shadow 0.3s ease;
}

/* A popup that is being SHOWN must not fade its way in -- the menu has to be
   readable the instant it opens. The crossfade above is for a theme change,
   which happens to an already-painted page. */
.nextxbase-menu-item.is-open > ul.nextxbase-menu-popup,
.nextxbase-btn-wrap.is-open > ul.nextxbase-menu-popup {
    transition: none;
}


/* ==========================================================================
/* KEYBOARD STATE INDICATORS
/*
/* the classic status bar shows Caps / Num / Scrl / Ins, dim when the lock is
/* off and legible when it is on. We emitted one hardcoded "INS" that was
/* always lit -- three missing, and the fourth incapable of reporting anything.
/*
/* Dim is the DEFAULT here, deliberately. The page genuinely does not know the
/* lock states until a key event arrives, and an indicator that defaults to
/* "on" is wrong most of the time while looking authoritative. Dim-until-known
/* is honest, and it corrects itself on the first keystroke.
/* ========================================================================== */
.msgbar-cell.msgbar-keyboard {
    min-width: 34px;
    text-align: center;
    /* 0.38 WAS NOT LEGIBLE, AND THE RULE TWENTY LINES ABOVE ALREADY SAID
       SO: "INS/OVR is a toggle: it must be legible when off, not
       invisible." Measured on the painted pixels in ctllab and FiveDBU,
       all four cells landed at 1.53 to 1.72:1 -- rgb(169,200,227) on
       rgb(243,243,243) -- while the date beside them reads clearly. Dim
       until known is right and stays; this is the floor at which dim is
       still text. 0.65 measures about 2.2:1 against the is-on state's
       4:1, so off and on remain obviously different.

       0.65 WAS MEASURED AGAINST ONE GROUND AND A SECOND GROUND BREAKS IT.
       That reading was taken on ctllab and FiveDBU, whose msgbar is
       rgb(243,243,243). samples/account under the light theme has a CREAM
       bar, rgb(233,224,205), and its 'Num' cell measured 1.91:1 there --
       under the bar, on the same 0.65.

       The full ink derives out of the composite: 0.65F + 0.35G = the
       measured rgb(183,162,106) gives F = rgb(156,129,53), which is 2.86:1
       against that cream at full strength. 0.72 puts the dim state at 2.07
       there and leaves ctllab's ground better than it was, so no sample
       loses. On stays at opacity 1 and font-weight 600, so the two states
       are still plainly different.

       IT IS STILL A CONSTANT TUNED TO MEASUREMENTS, now two instead of one,
       and a third low-contrast bar could break it again. The structural
       answer is a dim INK the theme states rather than a blanket opacity --
       an opacity cannot know what is behind it. Not taken here: that is a
       design change to the msgbar's colour surface, not a floor adjustment. */
    opacity: 0.72;
    font-weight: 400;
    transition: opacity 0.15s ease, color 0.15s ease;
}

.msgbar-cell.msgbar-keyboard.is-on {
    opacity: 1;
    font-weight: 600;
}

.theme-light .msgbar-cell.msgbar-keyboard.is-on,
.os-windows.theme-system .msgbar-cell.msgbar-keyboard.is-on,
.os-macos.theme-system .msgbar-cell.msgbar-keyboard.is-on,
.os-linux.theme-system .msgbar-cell.msgbar-keyboard.is-on {
    color: inherit;
}


/* ==========================================================================
/* MENU ACCELERATOR HINTS
/*
/* the reference implementation carries the shortcut in the same prompt string, after a TAB:
/*   "&Next Window" + Chr(9) + "Ctrl+F6"
/* HTML collapses a tab to one space, so the whole thing rendered as a single
/* run -- "Next Window Ctrl+F6" -- instead of a label on the left and the hint
/* right-aligned in its own column, which is what makes a desktop menu
/* scannable.
/*
/* The popup gets flex only where a shortcut is actually present, so the
/* menubar's own links keep their existing layout untouched.
/* ========================================================================== */
ul.nextxbase-menu-popup .nextxbase-menu-link {
    display: flex;
    align-items: center;
}

ul.nextxbase-menu-popup .menu-label {
    flex: 1 1 auto;
}

.menu-shortcut {
    flex: 0 0 auto;
    margin-left: 24px;
    opacity: 0.62;
    font-size: 0.92em;
    white-space: nowrap;
}

.nextxbase-menu-link:hover .menu-shortcut {
    opacity: 0.85;
}

/* ==========================================================================
   XBROWSE — the classes the browse emitter actually names

   Every class below was already being emitted and NONE of them had a rule.
   An audit comparing the class names in classes/xbrowse.prg against this file
   returned 20 emitted, 0 styled. That is not a cosmetic gap: the progress bar
   is two nested <span>s, so with no width and no height it occupied no space
   and a lProgBar column rendered as nothing at all, while the record selector
   and the marquee marker inherited ordinary cell padding and pushed the grid
   out of alignment.

   The rules are deliberately narrow. The browse writes its COLOURS inline, per
   row, from the application's own bClrStd/bClrSel blocks, so anything here that
   set a colour would override the application and is therefore absent — this
   file decides SHAPE, the emitter decides COLOUR.
   ========================================================================== */

/* --- the trailing filler cell ------------------------------------------
   Absorbs whatever width the real columns do not use, so the ROW owns the
   surplus instead of the container showing through as a white band beside
   striped rows. It carries NO colours: the <tr> emits `background:` inline and
   a <td> is transparent, so the striping runs through it, and the header's
   filler is a <th> that picks up the `thead th` band above. It must simply not
   read as a column -- no padding, and none of the divider the real cells draw
   to separate themselves. */
.nextxbase-grid-container th.nxb-brw-pad,
.nextxbase-grid-container td.nxb-brw-pad,
table.nextxbase-grid th.nxb-brw-pad,
table.nextxbase-grid td.nxb-brw-pad {
    padding: 0;
    border-left: 0;
}

/* --- the record selector column ---------------------------------------- */
/* THE RECORD SELECTOR'S DEFAULT GROUND. Deliberately on the bare class,
   NOT on the .nextxbase-grid-container rule below: that selector is (0,2,1)
   and every theme rule for .nxb-recsel is (0,2,0), so putting the colour
   there would out-specify all three themes and reproduce the very defect
   this moved off the inline style. (0,1,0) loses to a theme, which is the
   whole point. #e0e0e0 is NXB_CLR_HDRBACK, the value TXBROWSE:New assigns,
   so the default browse is unchanged. */
.nxb-recsel {
    background: #e0e0e0;
}

.nextxbase-grid-container th.nxb-recsel,
.nextxbase-grid-container td.nxb-recsel {
    padding: 0 3px;
    text-align: center;
    font-size: 11px;
    white-space: nowrap;
    user-select: none;
}

/* The marquee marker sits BESIDE the record number rather than replacing it,
   which is how the reference implementation draws it, so it needs to be small and to not push the
   number out of the column. */
.nextxbase-grid-container .nxb-recsel-mk {
    /* 9px drew a dot where the reference draws a legible black triangle. The
       marker's LOGIC was already correct -- it tracks i == nRowSel, the current
       row -- so this was only that it could not be SEEN at the size it was
       given, which on screen is the same as not drawing it. */
    font-size: 11px;
    /* currentColor, NOT #000000. A hardcoded black triangle is invisible
       on any theme that darkens the record-selector cell -- measured at
       1.84:1 on the painted pixels under liquid-glass, black on
       rgb(35,60,82). currentColor is whatever the cell's own text is,
       which every theme already sets correctly, and on the light default
       that is black: the reference's legible black triangle is unchanged
       where it was right. Same shape as the browse zebra -- a theme
       repaints the ground and the ink stays where it was written. */
    color: currentColor;
    margin-right: 2px;
    vertical-align: middle;
}

/* --- sort direction marker --------------------------------------------- */
.nextxbase-grid-container .nxb-sort {
    font-size: 9px;
    margin-left: 4px;
    opacity: 0.75;
}

/* --- bitmaps: in a cell, as a per-row image, and in a header band ------- */
.nextxbase-grid-container .nxb-cell-bmp,
.nextxbase-grid-container .nxb-cell-img,
.nextxbase-grid-container .nxb-band-bmp {
    display: inline-block;
    /* A band bitmap may not be taller than the band it is in: the browse emits
       a 23px header row, and an unbounded image simply hangs out of it across
       the first data row. 18px leaves room for the border. */
    max-height: 18px;
    width: auto;
    vertical-align: middle;
}

/* An explicit nBmpWidth or lBmpStretch is emitted INLINE by the column, and
   must win over the max-height above or the column's instruction is ignored. */
.nextxbase-grid-container .nxb-cell-bmp[style],
/* An explicit height wins -- but ONLY when an explicit height was actually
   declared. This used to key off `[style]`, which BmpAttrs writes for a
   declared WIDTH as well, so the cap below was thrown away in the one case
   that needs it: width 24 with height:auto on a 50x50 source is 24px tall in a
   23px header band, and it hung down over the first data row with nothing
   clipping it. The emitter now names the stretch case outright. */
.nextxbase-grid-container .nxb-cell-img.nxb-bmp-stretch,
.nextxbase-grid-container .nxb-band-bmp.nxb-bmp-stretch {
    max-height: none;
}


.nextxbase-grid-container .nxb-band-bmp-left  { margin-right: 5px; }
/* AL_RIGHT means AFTER THE CAPTION, not "pinned to the cell's right edge".
   This floated the image, which removes it from flow -- and the header cell is
   `text-align: center`, so the caption centred across the WHOLE cell as if the
   image were not there and drew straight through it. An inline-block after the
   text puts it on the right of the caption AND leaves it where the centring can
   see it. */
.nextxbase-grid-container .nxb-band-bmp-right { margin-left: 5px; }

/* The check/box fallback glyph, used when a column names artwork the resource
   system cannot resolve. For SetChecks() that is the NORMAL path, because
   the classic default check bitmaps live in ITS resource DLL and not ours. The
   image NAME is kept in the title, so a genuinely missing file stays
   identifiable rather than being silently substituted. */
.nextxbase-grid-container .nxb-cell-bmp-alt {
    display: inline-block;
    min-width: 14px;
    text-align: center;
    opacity: 0.55;
}

/* --- progress-bar columns ---------------------------------------------- */
/* Without these two rules a lProgBar column emitted markup and drew nothing:
   an empty inline span has no height, so the bar was invisible and the cell
   looked merely blank rather than broken. */
.nextxbase-grid-container .nxb-cell-prog {
    display: inline-block;
    width: 100%;
    min-width: 40px;
    height: 10px;
    border-radius: 5px;
    background: rgba(0, 0, 0, 0.14);
    overflow: hidden;
    vertical-align: middle;
}

.nextxbase-grid-container .nxb-cell-prog-fill {
    display: block;
    height: 100%;
    border-radius: 5px;
}

/* --- bLeftText: a second string in the SAME cell ------------------------ */
/* It is left-aligned while the value stays right-aligned — a currency symbol
   against a right-aligned amount is the case the reference implementation has it for — so it floats
   rather than merely sitting before the text. */
.nextxbase-grid-container .nxb-cell-left {
    float: left;
    padding-right: 6px;
    opacity: 0.85;
}

/* --- the in-place cell editor -------------------------------------------
   The input REPLACES the cell text, so it has to occupy the cell exactly: any
   padding, border or line-height of its own makes the row grow the instant an
   edit starts, and every row below it jumps. Hence the box-sizing, the zero
   margin and the inherited metrics — the editor is meant to look like the cell
   became typeable, not like a control appeared on top of it.

   It inherits colour and background rather than declaring them. That is the
   theme rule this file has been bitten by three times: a surface that declares
   its own colours here looks correct in the dark theme it was written against
   and wrong in the four light ones, because nothing downstream knows to
   override a rule it does not know exists. Inheriting means the cell's own
   colours — which the engine already computes per row, per column, per theme
   and per selection state — are the editor's colours, in every theme, with no
   second place for them to be decided. */
.nextxbase-grid-container .nxb-cell-edit {
    display: block;
    width: 100%;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    margin: 0;
    padding: 0;
    border: 0;
    outline: 1px solid rgba(90, 160, 255, 0.85);
    outline-offset: -1px;
    background: inherit;
    color: inherit;
    font: inherit;
    text-align: inherit;
    line-height: inherit;
}

/* A select needs the arrow, so it keeps a little room on the side it draws on;
   everything else stays as above. */
.nextxbase-grid-container select.nxb-cell-edit {
    padding-right: 14px;
}

/* The filler row that carries the grid lines past the last record. It takes
   whatever height is left, which is what makes the lines reach the bottom; the
   cells are empty and must not claim a line's worth of height of their own, or
   a full table would gain a blank strip it never had. */
.nextxbase-grid-container tr.nxb-brw-filler {
    height: 100%;
}

.nextxbase-grid-container tr.nxb-brw-filler td {
    padding: 0;
    border-bottom: 0;
    background-clip: padding-box;
}

/* A cell picture that DOES something says so. A tick box you can click and one
   you cannot are the same glyph, and the only honest difference is the cursor:
   without this the grid offers no way to find out except by trying every one. */
.nextxbase-grid-container .nxb-cell-bmp-live {
    cursor: pointer;
}

.nextxbase-grid-container .nxb-cell-bmp-live:hover {
    outline: 1px solid #b8942a;
    border-radius: 2px;
}

/* The "..." of an EDIT_BUTTON column. It floats to the trailing edge because
   that is where the reference implementation draws it and because the value has to stay where it
   was: a button that pushes the text sideways makes the column jitter between
   rows that have one and rows that do not.

   Colours are inherited for the reason the editor above inherits them -- the
   cell's own colours are already computed per row, per column, per theme and
   per selection state, and a surface that declares its own here is correct in
   the dark theme it was written against and wrong in the four light ones. */
.nextxbase-grid-container .nxb-cell-btn {
    float: right;
    min-width: 18px;
    height: 16px;
    margin: 0 0 0 4px;
    padding: 0 3px;
    border: 1px solid rgba(128, 128, 128, 0.55);
    border-radius: 2px;
    background: rgba(128, 128, 128, 0.16);
    color: inherit;
    font: inherit;
    font-size: 11px;
    line-height: 12px;
    cursor: pointer;
}

.nextxbase-grid-container .nxb-cell-btn:hover {
    background: rgba(128, 128, 128, 0.30);
}

/* data-editbtn is lWillShowABtn, whose whole purpose in the reference implementation is to keep the
   DATA properly positioned on a column that will have a button -- so it is
   room, reserved, and not a button of its own. */
.nextxbase-grid-container tbody td[data-editbtn] {
    padding-right: 22px;
}

/* An editable cell says so before you click it. Without this the only way to
   discover which columns accept an edit is to try them all — and a double click
   that does nothing is indistinguishable from one that failed. */
.nextxbase-grid-container tbody td[data-col] {
    cursor: cell;
}

/* --- lHoverSelect ------------------------------------------------------- */
/* The generic grid hover earlier in this file applied to EVERY browse, so a
   browse whose lHoverSelect is .f. — which is the DEFAULT — highlighted rows
   anyway and the DATA said one thing while the page did another. These two
   rules are what make that flag mean something; the nohover one carries an
   extra class so it outranks the generic rule rather than merely restating it. */
.nextxbase-grid-container.nxb-brw-nohover tbody tr:hover td,
table.nextxbase-grid.nxb-brw-nohover tbody tr:hover td {
    background: inherit;
}

.nextxbase-grid-container.nxb-brw-hover tbody tr:hover td {
    background-color: rgba(226, 232, 240, 0.55);
    cursor: default;
}

/* --- lFullGridClr ------------------------------------------------------- */
/* The browse's own colours fill the WHOLE control, not only the strip the
   records occupy. THE CONTAINER ALREADY DOES THAT: the emitter writes the
   pane colour on the .nextxbase-grid-container itself, so the area below
   the last record is the browse's colour with no help from the table.

   This rule used to add `table.nextxbase-grid { height: 100% }` for the
   same purpose, and a table told to be taller than its rows hands the slack
   to the ROWS. Measured on ctl_fixture (SIZE 520,200, four records, row
   height 20): every data row rendered 44px, the reference's 22. The row
   height is geometry -- RowsToDisplay() divides by it -- so this was not a
   look, it was the control lying about how many records fit. Removed; the
   filler row (tr.nxb-brw-filler) remains the way grid LINES reach the
   bottom when a divider flag asks for them. */

/* --- lFullGrid / lRowBox / the Office styles ---------------------------- */
/* ONLY THE DATA CELLS. A border STYLE with no width and no colour is
   `medium currentColor`: the data cells carry their own `border-right:1px
   solid <line>` inline, so the style here only switched on what they state,
   while the record selector and the trailing pad cell state nothing -- and
   drew a 3px line in the CONTAINER'S ink. The container's ink is the
   application's bClrStd evaluated on the current record, so on FiveDBU with
   a deleted record selected it was CLR_HRED: two red rails down the whole
   browse (2026-09-12). :not() of a simple selector is IE11-safe. */
.nextxbase-grid-container.nxb-brw-fullgrid tbody td:not(.nxb-recsel):not(.nxb-brw-pad) {
    border-right-style: solid;
}

.nextxbase-grid-container.nxb-brw-rowbox tbody tr.nxb-row-sel td {
    outline: 1px dotted currentColor;
    outline-offset: -1px;
}

.nextxbase-grid-container.nxb-brw-flat {
    border-radius: 0;
    box-shadow: none;
}

.nextxbase-grid-container.nxb-brw-2007 thead th {
    font-weight: 600;
}

/* --- selected and marked rows ------------------------------------------- */
/* Both carry their colours INLINE from the application's colour blocks, so
   these rules add only what a colour cannot say. */
.nextxbase-grid-container tbody tr.nxb-row-sel td {
    font-weight: 600;
}

.nextxbase-grid-container tbody tr.nxb-row-marked td {
    box-shadow: inset 2px 0 0 currentColor;
}

/* --- a bounded page ----------------------------------------------------- */
.nextxbase-grid-more {
    padding: 6px 10px;
    font-size: 12px;
    opacity: 0.7;
    text-align: center;
}

/* ==========================================================================
   The remaining classes the emitters name and this file did not define

   Same audit as the browse block above, widened to every emitter: 77 class
   tokens are written into pages by classes/*.prg, and 14 of them had no rule.
   Listed here with the emitter that writes each, because the pairing is the
   thing that keeps drifting.

   TFOLDER is the one that mattered. Its header is a <ul> of <li>, so with no
   rule a tab strip rendered as a BULLETED VERTICAL LIST and the .active tab
   was indistinguishable from the others -- while the pages themselves hid and
   showed correctly, because the emitter writes display inline. The control
   looked broken in exactly the half nobody had styled.
   ========================================================================== */

/* --- TFOLDER (containers.prg) ------------------------------------------- */
.nextxbase-folder {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 8px;
}

.nextxbase-tab-header {
    display: flex;
    display: -ms-flexbox;
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    margin: 0;
    padding: 0 4px;
    list-style: none;          /* it is a <ul>: without this the tabs are bullets */
    border-bottom: 1px solid rgba(0, 0, 0, 0.12);
    background: rgba(0, 0, 0, 0.04);

    /* CLIP, DO NOT SCROLL. This said `overflow-x: auto` so a folder with more
       tabs than width could be scrolled -- and MSHTML, which is what the
       product renders with, reserves and PAINTS the scrollbar whether or not
       there is anything to scroll. Three tabs in a 360px folder came out with a
       stacked up/down control at the end of the strip that the reference implementation does not
       draw, in every folder in every application.

       Hidden is also the reference behaviour, not just a way to hide the
       furniture: a reference-implementation folder with too many tabs cuts them off at the edge,
       it does not offer to scroll them. */
    overflow: hidden;
    white-space: nowrap;
}

.nextxbase-tab-item {
    /* -ms-flex written to match the rest of this file. Without it the flex
       instruction does not reach the product viewport at all, and the strip is
       held together by the default inline flow of its <li>s -- which works
       today and stops the moment a tab needs to refuse to shrink. */
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
    /* THE TAB ROW IS SIZED FROM ITS FONT, NOT FROM PIXEL CONSTANTS (T41).
       The reference's tab row is 20.9 logical px in a roomy folder AND in one
       declared 25 tall -- it neither expands nor scales, it clips. Ours was
       46 (8 header padding + 3 margin + 7/7 item padding + line + borders),
       2.2x, in every folder at every height, so Colegios' 25 px strip showed
       no captions at all. 0.15em of padding and a 1.2 line box land the row at
       ~21 for 13 px text and move with the application's own font.
       window.prg's inline copy of this rule sets the same values -- it wins on
       padding, so both are kept saying one thing. */
    padding: 0.15em 1.2em;
    line-height: 1.2;
    font-size: 13px;
    cursor: pointer;
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: 6px 6px 0 0;
    margin-top: 0;
    user-select: none;
}

/* AN ICON IN A TAB IS THE HEIGHT OF THE CAPTION BESIDE IT, AND UNTIL NOW IT
   WAS THE HEIGHT OF WHATEVER BITMAP THE APPLICATION HAPPENED TO LOAD.
   TFOLDER emits `class='nextxbase-tab-icon'` on every tab image and NOTHING
   STYLED IT -- an emitted class with no rule -- so the <img> rendered at its
   intrinsic size and SET THE CHROME'S HEIGHT.

   MEASURED on samples/Colegios, which declares `oTabs:nHeight := 25` and
   loads bitmaps of two different sizes: icons 32, 16 and 32 px in one strip,
   a .nextxbase-tab-header 61 px tall inside a folder of 25, and
   .nextxbase-folder is overflow:hidden -- so the strip was clipped to a
   sliver and the captions with it. With this rule the icons are uniform per
   tab and the header is 47.

   1em RATHER THAN A NUMBER, because an icon beside a caption is the
   CAPTION'S height and the caption's size is the application's: Colegios
   sets oTabs:oFont and oTabs:oBold, so the active tab's icon comes out 16
   and the inactive ones 13, each tracking its own tab. A px here would be
   the constant ground rule 7 forbids.

   max-height AND NOT height: the aspect ratio is the bitmap's business, and
   an icon SMALLER than the line must not be stretched up to it.

   AND IT IS SAFE ON THE WINDOWS 7 FLOOR -- MEASURED, NOT ARGUED. This comment
   used to say the <img> is not a flex item because this rule declares no
   display. That was false on every page: window.prg's inline copy of
   .nextxbase-tab-item is display:inline-flex !important, so the <img> IS a
   flex item. IE11 honours this max-height anyway: samples/tabicon_probe, a
   48x48 bitmap captured on documentMode=11 and on WebView2, renders 28x28
   physical (1em) on both (TASKS.md T43, retracted 2026-09-11). An ABSOLUTE
   max-height on a flex-item image is what was measured; keep it absolute. */
.nextxbase-tab-icon {
    max-height: 1em;
    width: auto;
    vertical-align: middle;
}

.nextxbase-tab-item:hover {
    background: rgba(0, 0, 0, 0.05);
}

/* The active tab joins the body below it: the shared border is removed and the
   tab is pulled down over it, which is what makes a tab strip read as tabs
   rather than as a row of buttons. */
.nextxbase-tab-item.active {
    font-weight: 600;
    background: inherit;
    border-color: rgba(0, 0, 0, 0.12);
    /* -1px pulls the active tab over the strip's bottom border, which is what
       joins it to its page. It used to ALSO add padding-bottom: 8px, making the
       active tab taller than its row -- see T41 above. */
    margin-bottom: -1px;
}

.nextxbase-tab-body {
    flex: 1 1 auto;
    position: relative;
    overflow: auto;
}

/* display is written INLINE per page by the emitter and by switchTab(), so
   nothing here may set it -- a display in this rule would either be overridden
   (harmless but misleading) or, if made !important, would freeze every page
   visible and defeat both. */
.nextxbase-tab-page {
    position: relative;
    width: 100%;
    height: 100%;
}

/* --- TMSGBAR items (fivedbu_compat.prg) --------------------------------- */
/* These already carry .msgbar-cell, which is styled, so they were not
   invisible -- only unable to differ from a plain cell. FiveDBU declares
   twelve MSGITEMs and several carry a bitmap. */
/* A SIZED PANEL CENTRES ITS TEXT. MayaPOS declares SIZE 135, so the panel
   runs 1557..1692 on the reference and its caption sits at 1598..1658 --
   41 lead, 34 trail, centred. Ours left-aligned it at 18 lead and 60 trail.
   The declared width was being honoured and its content was not. */
.msgbar-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    -ms-flex-pack: center;
}

.msgbar-icon {
    /* 16, measured: the reference's padlock is 13 x 16 and ours was 12 x 14.
       Close enough to look right and not close enough to BE right. */
    height: 16px;
    width: auto;
    vertical-align: middle;
}

.msgbar-clock {
    font-variant-numeric: tabular-nums;   /* so the width does not jitterevery second */
    min-width: 44px;
    text-align: center;
}

/* --- window chrome (window.prg) ----------------------------------------- */
.btn-minimize,
.btn-maximize {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 22px;
    border: none;
    background: transparent;
    cursor: pointer;
    line-height: 1;
    font-size: 12px;
}

.btn-minimize:hover,
.btn-maximize:hover {
    background: rgba(0, 0, 0, 0.10);
}

.nextxbase-viewport-body {
    /* NO width/height 100% -- AND THAT IS NOT A NEW RULE, IT IS THE ONE
       .nextxbase-slot-workspace ALREADY CARRIES, 2,960 lines above, with the
       reasoning written out in full.

       The workspace element is emitted with BOTH classes:

           class='nextxbase-slot-workspace nextxbase-viewport-body'

       so this rule put back exactly what that one removes. `flex: 1 1 auto`
       already sizes the element to the space the caption and footer leave;
       asking for the whole window on top of that makes the content exceed its
       container by exactly the chrome, and overflow:auto turns the excess into
       a scrollbar -- appearing on MAXIMIZE and hiding at the restored size,
       which is backwards, because a bigger window cannot have less room. That
       is the both-scrollbars symptom the grid probe showed against a reference
       that has none.

       Removed rather than overridden with !important: this class is a ROLE
       marker ("this is the viewport's body"), and the SIZING belongs to
       whatever layout the element participates in -- which this class cannot
       know. An !important would leave two rules fighting, with the loser still
       wrong for every other element that ever takes this class. */
    position: relative;

    /* AND overflow IS NOT DECLARED HERE EITHER -- same reason, second
       property. slot-workspace sets `overflow: hidden` under a comment
       stating "A WINDOW CLIPS -- IT DOES NOT SCROLL ... the classic maximised
       window has no scrollbars", and `overflow: auto` here overrode it,
       giving the window the scrollbars the reference does not have.

       This class is emitted in exactly ONE place (window.prg:704) and always
       beside slot-workspace, so it is never this element's sole layout owner
       and anything geometric it declares can only CONTEST a deliberate value.
       It is a role/hook marker now and owns no geometry. position:relative
       stays only because slot-workspace declares the identical value.

       The DIALOG still scrolls -- that is governed separately by
       `.nextxbase-dialog.is-standalone > .nextxbase-dialog-body`, and it is
       deliberate: a dialog's size is DECLARED, so its content can exceed it
       permanently and clipping would lose controls the user cannot reach. A
       maximised window has no larger size to scroll toward. */
}

/* --- dialog + ribbon + report ------------------------------------------- */
.dialog-icon {
    height: 16px;
    width: auto;
    margin-right: 6px;
    vertical-align: middle;
}

/* cGrpLabel captions a CLUSTER of ribbon buttons; the reference implementation paints it under the
   group, so it is a block beneath rather than inline beside. */
.btn-grp-label {
    display: block;
    text-align: center;
    font-size: 11px;
    opacity: 0.7;
    margin-top: 2px;
}

/* A SECOND SELECTOR RATHER THAN A SECOND RULE. The "mono" modal kind -- a hex
   dump today -- wants exactly what a spooled report wants: a fixed pitch so
   columns line up, and its own scrollbar when the content is longer than the
   box. Listing it here means the font stack is stated ONCE; a copy of it
   beside the modal rules is two answers to one question, and the day somebody
   changes one the two drift with nothing to notice.

   It is additive by construction: every kind this engine emits today is info,
   warn or stop, so no existing modal matches this selector and none moves. */
.nextxbase-report,
.nxb-modal-mono .nxb-modal-body {
    font-family: Consolas, "Courier New", monospace;
    font-size: 12px;
    white-space: pre;
    overflow: auto;
}

/* The dump is the whole content, so it gets the room. A modal body's default
   padding is tuned for a sentence of prose. */
.nxb-modal-mono .nxb-modal-body {
    max-height: 60vh;
    padding: 12px 14px;
}
/* ===========================================================================
   ENGINE MODALS -- the confirmation the application asked for.

   Server-rendered, so they arrive as part of the page rather than being built
   in script. Styled to match the titlebar's glass-and-gold rather than looking
   like a browser alert, because to the user this IS the application asking.
   =========================================================================== */
/* THE TOAST IS THE OTHER HALF OF THIS FAMILY, AND IT HAD NO CSS AT ALL.

   NXB_RenderModals emits a data-nxb-toast attribute and the engine script
   turns it into a call to NextXbase.toast -- which built its element with
   style.cssText, so every declaration outranked every rule and NO THEME
   COULD REACH IT. Measured 2026-09-10: 35 rules in this stylesheet mention
   .nxb-modal and ZERO mentioned a toast, while audit_theme_blockers counted
   7 unreachable declarations on window.prg:2517.

   The values are the ones that were in that cssText, moved rather than
   chosen, so the toast looks today exactly as it looked yesterday and is
   now themeable. Ground and ink are stated together (0-E): every kind
   paints its own background AND its own colour.

   NO `gap` HERE, DELIBERATELY. The cssText carried `gap:10px`, which the
   IE11 floor ignores -- so on the fallback rung the icon and the text were
   already touching. A margin on the child is the portable form and is what
   this tree prescribes; it also keeps audit_ie11_css's ratchet from rising
   on a change that is meant to cost nothing. */
.nxb-toast {
    position: fixed;
    top: 24px;
    right: 24px;
    z-index: 99999;
    padding: 12px 20px;
    border-radius: 8px;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.25);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    background: #2563eb;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    transition: opacity 0.3s ease;
}

.nxb-toast .nxb-toast-icon {
    margin-right: 10px;
}

.nxb-toast-success { background: #059669; }
.nxb-toast-warn    { background: #d97706; }
.nxb-toast-error   { background: #dc2626; }
.nxb-toast-info    { background: #2563eb; }

.nxb-modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(10, 12, 18, 0.55);
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    z-index: 99999;
}

.nxb-modal {
    min-width: 320px;
    max-width: 520px;
    background: linear-gradient(180deg, #2b2f3a 0%, #21242d 100%);
    border: 1px solid rgba(212, 175, 55, 0.45);
    border-radius: 10px;
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55), 0 0 24px rgba(212, 175, 55, 0.12);
    overflow: hidden;
    font-family: "Segoe UI", Tahoma, sans-serif;
    /* GROUND AND INK ARE ONE DECISION (0-E), and this rule stated only the
       ground. Measured 2026-09-10 on the running product: the resolved
       colour on .nxb-modal was rgb(26,26,26) -- near-black, inherited from
       the page -- against a near-black gradient. Nothing is unreadable
       today because every CHILD states its own ink, so this is the standing
       risk 0-E describes rather than a live defect: the first child added
       without a class of its own would be invisible. Same value as
       .nxb-modal-body, so it changes no pixel now. */
    color: #e9ecf2;
}

.nxb-modal-title {
    padding: 12px 18px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.3px;
    color: #e8c96a;
    background: rgba(255, 255, 255, 0.05);
    border-bottom: 1px solid rgba(212, 175, 55, 0.25);
}

.nxb-modal-body {
    padding: 22px 18px;
    font-size: 14px;
    line-height: 1.5;
    color: #e9ecf2;
    white-space: pre-wrap;
}

.nxb-modal-foot {
    padding: 12px 18px 16px 18px;
    text-align: right;
}

.nxb-modal-btn {
    min-width: 84px;
    margin-left: 8px;
    padding: 7px 16px;
    font-size: 13px;
    font-family: inherit;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.07);
    color: #dfe4ec;
    cursor: pointer;
    transition: all 0.2s ease;
}

.nxb-modal-btn:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.32);
}

/* The default answer is visibly the default: Enter takes it, so it must be
   obvious WHICH one Enter takes before the user presses it. */
.nxb-modal-btn.nxb-modal-default {
    background: rgba(212, 175, 55, 0.22);
    border-color: #d4af37;
    color: #ffe9a8;
}

.nxb-modal-btn.nxb-modal-default:hover {
    background: #d4af37;
    color: #241d05;
    box-shadow: 0 0 12px rgba(212, 175, 55, 0.45);
}

.nxb-modal-btn.nxb-modal-yes.nxb-modal-default {
    background: rgba(40, 200, 100, 0.22);
    border-color: #28c85f;
    color: #b8f5cf;
}

.nxb-modal-btn.nxb-modal-yes.nxb-modal-default:hover {
    background: #28c85f;
    color: #05230f;
    box-shadow: 0 0 12px rgba(40, 200, 95, 0.45);
}

.nxb-modal-stop .nxb-modal-title  { color: #ff9a8a; border-bottom-color: rgba(220, 60, 60, 0.4); }
.nxb-modal-warn .nxb-modal-title  { color: #ffd166; border-bottom-color: rgba(255, 194, 51, 0.4); }

.theme-light .nxb-modal,
.theme-light.control-theme-light.nxb-modal {
    background: linear-gradient(180deg, #ffffff 0%, #f4f6fa 100%);
    border-color: rgba(0, 0, 0, 0.15);
}
.theme-light .nxb-modal-title,
.theme-light.control-theme-light.nxb-modal-title { color: #8a6d1f; background: rgba(0, 0, 0, 0.03); }
.theme-light .nxb-modal-body,
.theme-light.control-theme-light.nxb-modal-body  { color: #22262e; }
.theme-light .nxb-modal-btn,
.theme-light.control-theme-light.nxb-modal-btn   { background: #ffffff; border-color: #c9ced8; color: #22262e; }
/* The About box: product name as a heading rather than a line of body text,
   which is what makes it an About box and not a message. */
.nxb-modal-about .nxb-modal-title {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: 0.4px;
    padding: 18px 22px 10px 22px;
    background: none;
    border-bottom: none;
    color: #e8c96a;
}

.nxb-modal-about .nxb-modal-body {
    padding: 0 22px 8px 22px;
    font-size: 12.5px;
    color: #b9c0cc;
}

.nxb-modal-about {
    min-width: 300px;
    text-align: left;
}

.theme-light .nxb-modal-about .nxb-modal-body,
.theme-light.control-theme-light.nxb-modal-about .nxb-modal-body { color: #55606f; }
/* ===========================================================================
   MDI CHILD PANES -- a child window rendered INSIDE its parent's client area,
   which is what makes it a child rather than a replacement for the screen.
   =========================================================================== */
.nextxbase-window.wnd-pane {
    border: 1px solid rgba(0, 0, 0, 0.35);
    border-radius: 6px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
    overflow: hidden;
    display: flex;
    display: -ms-flexbox;
    flex-direction: column;
    -ms-flex-direction: column;
    background: #f4f5f7;
    z-index: 10;
}

/* The frontmost pane is the one keystrokes and menu commands act on, so it has
   to be obvious which that is -- otherwise Close All and Next Window look
   arbitrary. */
.nextxbase-window.wnd-pane.wnd-pane-active {
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.38), 0 0 0 1px rgba(212, 175, 55, 0.55);
    z-index: 20;
}

.nextxbase-window.wnd-pane .nextxbase-slot-titlebar {
    cursor: default;
}

.nextxbase-window.wnd-pane .titlebar-caption {
    cursor: pointer;
}

/* A pane's workspace scrolls on its own: a browse inside a tiled child must
   not push the parent's client area around. */
.nextxbase-window.wnd-pane > .nextxbase-slot-workspace {
    flex: 1 1 auto;
    -ms-flex: 1 1 auto;
    overflow: auto;
    position: relative;
}

/* The client area is the positioning context for every pane in it. Without
   this the absolute coordinates would be resolved against the page and the
   panes would sit over the menubar. */
.nextxbase-window > .nextxbase-slot-workspace {
    position: relative;
}

.theme-dark .nextxbase-window.wnd-pane,
.theme-system .nextxbase-window.wnd-pane {
    background: #2a2d35;
    border-color: rgba(255, 255, 255, 0.14);
}
/* EDITVARS prompt. The body scrolls rather than the page, because the number
   of boxes is the application's choice and a tall prompt must not push its own
   OK button off the screen. */
.nxb-modal-vars .nxb-modal-body {
    white-space: normal;
    max-height: 60vh;
    overflow-y: auto;
}
.nxb-modal-var-row {
    display: block;
    margin-bottom: 10px;
}
.nxb-modal-var-label {
    display: block;
    margin-bottom: 3px;
    font-size: 12px;
    opacity: 0.8;
}
.nxb-modal-var {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 8px;
    font-family: inherit;
    font-size: 13px;
    color: #e9ecf2;
    background: rgba(0, 0, 0, 0.25);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 4px;
}
.nxb-modal-var:focus {
    border-color: #d4af37;
    outline: none;
}
.theme-light .nxb-modal-var,
.theme-light.control-theme-light.nxb-modal-var {
    color: #22262e;
    background: #ffffff;
    border-color: #c9ced8;
}

/* XBROWSER picker. The body scrolls, not the page: the row count is the
   application's data and a long list must not push Cancel off the screen. */
.nxb-modal-pick .nxb-modal-body {
    white-space: normal;
    max-height: 60vh;
    overflow: auto;
    padding: 0;
}
.nxb-modal-pick .nxb-modal { min-width: 420px; }
table.nxb-pick {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
table.nxb-pick th {
    position: sticky;
    top: 0;
    padding: 8px 12px;
    text-align: left;
    font-weight: 600;
    color: #e8c96a;
    background: #2b2f3a;
    border-bottom: 1px solid rgba(212, 175, 55, 0.3);
}
table.nxb-pick td {
    padding: 6px 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
tr.nxb-pick-row { cursor: pointer; }
tr.nxb-pick-row:hover td { background: rgba(212, 175, 55, 0.16); }
.nxb-pick-more {
    margin: 0;
    padding: 8px 12px;
    font-size: 12px;
    opacity: 0.7;
}
.theme-light table.nxb-pick th { color: #8a6d1f; background: #f4f6fa; }
.theme-light table.nxb-pick td { border-bottom-color: rgba(0, 0, 0, 0.07); }
.theme-light tr.nxb-pick-row:hover td { background: rgba(212, 175, 55, 0.22); }

/* A STANDALONE DIALOG IS THE WINDOW, SO IT HAS NO FRAME.

   The border, radius and drop shadow of .nextxbase-dialog say "this floats
   over something". When the dialog IS the top-level window there is nothing
   behind it to float over, and the frame both looks wrong and eats pixels off
   the client rectangle every control is positioned against.

   Photographed against the reference implementation (samples/mutation/button, dialog mode): the
   reference is one native-framed window with a single caption; ours was a
   host window containing a bordered panel with a second caption. */
.nextxbase-dialog.is-standalone {
    position: static !important;
    transform: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    background: transparent !important;
}

.nextxbase-dialog.is-standalone > .nextxbase-dialog-body {
    /* The host workspace already carries the client origin from the window
       frame metrics; the body must not add a second inset on top of it. */
    padding: 0 !important;
    margin: 0 !important;
    width: 100%;
    height: 100%;
    min-width: 100%;
    min-height: 100%;

    /* SCROLL, DO NOT SWALLOW -- and this is a DELIBERATE divergence from the
       reference, not an oversight.

       With overflow:visible the controls past the sixth spilled out of the
       body box and vanished: IE11 does not reliably count visible-overflow
       content toward an ancestor's scrollable extent, so the host workspace
       never grew a scrollbar and they were unreachable.

       the reference implementation clips here too -- its dialog stops after "Move Up" with no
       scrollbar. Matching that would mean keeping controls the user cannot
       reach. A native dialog clips because it has no other option; ours
       renders in a scrollable viewport, so the choice is real, and silently
       hiding a control is the one outcome with no upside. A scrollbar says
       there is more; clipping says nothing. Same judgement as the window
       workspace, which already carries overflow:auto.

       Left here on purpose so nobody later "corrects" it back to match. */
    overflow: auto !important;
}

/* ─────────────────────────────────────────────────────────────── */
/* TBTNBMP — the toolbar-style button                              */
/* ─────────────────────────────────────────────────────────────── */

/* THERE WAS NO RULE FOR THIS CONTROL AT ALL.

   GenerateHTML has always emitted `nextxbase-btnbmp`, and once the FLAT
   clause was wired it emitted `nextxbase-btnbmp-flat` too -- into a
   stylesheet that mentioned neither. Both spellings fell back to the browser
   default and a FLAT button was pixel-identical to a raised one.

   That is the same defect as the swallowed clause it was meant to fix: a
   difference that exists in the object model, is faithfully written into the
   markup, and is invisible on screen. Wiring the clause without this rule
   would have looked like a fix and changed nothing. */
.nextxbase-btnbmp {
    position: absolute;
    display: flex;
    display: -ms-flexbox;
    align-items: center;
    -ms-flex-align: center;
    justify-content: center;
    -ms-flex-pack: center;
    padding: 0;
    box-sizing: border-box;
    cursor: pointer;
    overflow: hidden;
    white-space: nowrap;
    font-family: 'Segoe UI', 'Outfit', system-ui, sans-serif;
    font-size: 13px;
    color: #22262e;
    background: #f2f0ec;
    border: 1px solid #b9b2a4;
    border-radius: 0;
}

.nextxbase-btnbmp img {
    max-width: 100%;
    max-height: 100%;
}

/* FLAT is the toolbar look: no face and no border until the pointer is on it.
   This is the ONLY thing that distinguishes it from the raised form, so if it
   is ever removed the FLAT clause silently stops being observable again. */
.nextxbase-btnbmp-flat {
    background: transparent;
    border-color: transparent;
}

.nextxbase-btnbmp-flat:hover {
    background: #e8e4dc;
    border-color: #b9b2a4;
}

.nextxbase-btnbmp:active,
.nextxbase-btnbmp.is-selected {
    background: #ddd8cc;
    border-color: #8e8676;
}


/* ==========================================================================
 * A *STYLEBAR* TOOLBAR BUTTON IS FLAT UNTIL YOU TOUCH IT
 *
 * SCOPED TO THE FLAT BAR STYLES, AND THE SCOPE IS THE POINT.
 *
 * WHICH STYLES ARE FLAT WAS SETTLED BY THE VENDOR SOURCE, NOT BY GUESSING.
 * FiveDBU declares `DEFINE BUTTONBAR ... STYLEBAR`, and its the reference implementation reference
 * draws those buttons with NO box. But fivedbu.prg line 20 also carries
 *
 *     #define STYLEBAR      2010
 *
 * so the preprocessor rewrites the keyword before our #xcommand ever sees it
 * and the bar comes out `bar-2010`. The command and the marker are both
 * correct -- verified by preprocessing the same statement in isolation, where
 * STYLEBAR yields "STYLEBAR" -- and the application is genuinely asking for the
 * 2010 style. So 2010 is a FLAT style, on the evidence of the reference
 * picture, and 2013/2015 are its successors.
 *
 * A PLAIN `DEFINE BUTTONBAR` with no style keyword keeps its border: that is
 * the classic toolbar, and it is what the showcase declares.
 *
 * The first version of this rule was unscoped and flattened every bar in the
 * product; the second over-corrected onto .bar-stylebar alone and un-flattened
 * FiveDBU, whose reference is the only picture that settles the question. STYLEBAR is the classic
 * FLAT toolbar style -- it is what FiveDBU declares, and its reference draws
 * those buttons with no box at all. A plain `DEFINE BUTTONBAR` with no style
 * keyword, and the 2010/2013/2015 variants, all draw a BORDERED button.
 *
 * The first version of this rule was unscoped and flattened every bar in the
 * product, including the showcase's plain one -- correct for the bar in front
 * of me and wrong for the whole class of bars it actually matched.
 *
 * FiveDBU's bar is `DEFINE BUTTONBAR ... STYLEBAR`, and the reference draws
 * those buttons with NO box: icon and caption sit directly on the bar,
 * separated only by the group dividers. Ours drew a bordered, rounded, filled
 * rectangle around each, because a buttonbar button reuses
 * .nextxbase-ribbon-btn and a RIBBON button genuinely IS a tile. Ten boxes in
 * a row is the difference between a toolbar and a strip of buttons, and it was
 * the loudest remaining difference on the FiveDBU page.
 *
 * TBTNBMP already models this correctly -- DATA lFlat INIT .T., set from the
 * absence of a BORDER clause -- so the emitter's posture was right all along
 * and the stylesheet was overruling it.
 *
 * PLACED HERE, AT THE END, AND CARRYING .btn-large/.btn-small DELIBERATELY.
 * The first version of this rule was `.nextxbase-buttonbar
 * .nextxbase-ribbon-btn` written up beside the other buttonbar rules, and it
 * could never have applied: `.os-windows.theme-system .nextxbase-ribbon-btn`
 * is three classes to its two and wins outright, and the .theme-light pair
 * further down would win on order even at a tie. Same shape as the inline
 * menubar background fixed in the previous commit -- a correct rule written
 * where nothing could observe it. Three classes, after every theme block.
 *
 * The affordance moves to hover/active rather than vanishing: resting flat and
 * lighting on approach is what the reference does AND what a 2026 toolbar
 * does, so this is a place where the two agree completely.
 * ========================================================================== */
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-large,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-large,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-large,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-large,
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-small,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-small,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-small,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-small {
    background: transparent;
    background-image: none;
    border: 1px solid transparent;
    border-radius: 4px;
    box-shadow: none;
    color: inherit;
}

.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-large:hover,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-large:hover,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-large:hover,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-large:hover,
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-small:hover,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-small:hover,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-small:hover,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-small:hover {
    background: rgba(0, 0, 0, 0.06);
    background-image: none;
    border-color: rgba(0, 0, 0, 0.14);
    box-shadow: none;
    color: inherit;
}

.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-large:active,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-large:active,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-large:active,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-large:active,
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-small:active,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-small:active,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-small:active,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-small:active {
    background: rgba(0, 0, 0, 0.12);
    border-color: rgba(0, 0, 0, 0.20);
}

/* A disabled tool goes pale; it does not keep a box the enabled ones have
   given up. Previous and Next are disabled on FiveDBU's opening screen and
   must read as unavailable without drawing MORE ink than their neighbours. */
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-large:disabled,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-large:disabled,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-large:disabled,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-large:disabled,
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-small:disabled,
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-small:disabled,
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-small:disabled,
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-small:disabled,
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-large[disabled],
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-large[disabled],
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-large[disabled],
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-large[disabled],
.nextxbase-buttonbar.bar-stylebar .nextxbase-ribbon-btn.btn-small[disabled],
.nextxbase-buttonbar.bar-2010 .nextxbase-ribbon-btn.btn-small[disabled],
.nextxbase-buttonbar.bar-2013 .nextxbase-ribbon-btn.btn-small[disabled],
.nextxbase-buttonbar.bar-2015 .nextxbase-ribbon-btn.btn-small[disabled] {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    opacity: 0.45;
}

/* ==========================================================================
   A BUTTONBAR'S EDGE.

   `DEFINE BUTTONBAR ... BOTTOM` is the only thing distinguishing the second bar
   a program declares from the first, so a bar that ignores it renders both in
   the same place with nothing to explain the picture.

   LEFT and RIGHT change the FLOW as well as the position: a vertical bar whose
   buttons run left to right is not a vertical bar, and its width comes from the
   buttons rather than from the window.

   FLOAT deliberately renders as TOP -- a floating toolbar is a separate
   top-level window in Win32 and there is no analogue here; docking keeps every
   button present, reachable and in order. Written down rather than left as a
   silent coincidence of the selector list.
   ========================================================================== */
.nextxbase-buttonbar.bar-dock-bottom {
    margin-top: auto;

    /* The shadow and the hairline belong to whichever side faces the content,
       so on a bottom bar they move to the top edge -- otherwise the bar is lit
       from the wrong direction and reads as floating above the window. */
    border-bottom: 0;
    border-top: 1px solid rgba(0, 0, 0, 0.65);
    box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.75),
                0 -3px 10px rgba(0, 0, 0, 0.14);
}

.nextxbase-buttonbar.bar-dock-left,
.nextxbase-buttonbar.bar-dock-right {
    flex-direction: column;
    -ms-flex-direction: column;
    width: auto;
    align-self: stretch;
    -ms-flex-item-align: stretch;
    border-bottom: 0;
}

.nextxbase-buttonbar.bar-dock-left {
    border-right: 1px solid rgba(0, 0, 0, 0.65);
    box-shadow: 1px 0 0 rgba(255, 255, 255, 0.75);
}

.nextxbase-buttonbar.bar-dock-right {
    order: 1;
    border-left: 1px solid rgba(0, 0, 0, 0.65);
    box-shadow: -1px 0 0 rgba(255, 255, 255, 0.75);
}

/* NOBORDER means no border, and it has to outrank the edge rules above --
   which is why it is last and carries the same two-class weight they do. */
.nextxbase-buttonbar.bar-noborder {
    border: 0;
    box-shadow: none;
}

/* ==========================================================================
   FLEXBOX `gap` DOES NOT EXIST IN THE PRODUCT VIEWPORT.

   The desktop shell renders with MSHTML in IE11 document mode. It honours
   `display: -ms-flexbox` and lays the flex line out correctly, and then
   ignores `gap` entirely -- the property postdates it by years. So six rules
   in this file declared spacing that never happened, and the failure is
   invisible three ways over: the rule is present in the file, the markup is
   correct, and tools/shoot.ps1 photographs it working because that path
   renders with Edge. Only a native shot of the app shows it, which is how it
   was finally seen -- ctl_fixture next to ctl_fixture-the reference implementation, where the reference implementation
   draws "(o) Alpha  (o) Beta" and we drew "OAlphaOBetaOGamma".

   The `gap` declarations are deliberately KEPT. They are correct in Chromium
   and are what the headless path uses; this is a FALLBACK, not a replacement.
   Adjacent-sibling and universal selectors are IE7-era, so they reach the
   engine that actually ships.

   Only spacing that `gap` was already asking for is reproduced here, at the
   same values. This block adds no new layout decisions.
   ========================================================================== */
.titlebar-controls > * + * {
    margin-left: 6px;
}

.nextxbase-buttonbar .nextxbase-ribbon-btn > * + * {
    margin-left: 2px;
}

/* .nextxbase-radio > * + * { margin-left: 14px } WAS HERE and is gone. A radio
   group's items are stacked; a left margin on items 2..n indented them 14px
   against item 1 -- measured on ctl_fixture: Beta and Gamma sat right of
   Alpha where the reference aligns all three. And the pitch is not a gap at
   all: see the vertical twin of this rule further down. */

.msgbar-item > * + * {
    margin-left: 5px;
}

/* The BTNBMP caption is a <span>, so the sibling rule reaches it -- this is
   the bitmap sitting hard against "With Icon" in the native shot. */
.nextxbase-btnbmp > img.nxb-btnbmp-icon + span,
.nextxbase-btnbmp > span.nxb-btn-label + img {
    margin-left: 6px;
}

/* THE RADIO LABEL IS A TEXT NODE -- `<input> Alpha` -- and `* + *` cannot
   select text, so this one is a margin on the input itself. Its `margin: 0`
   above is part of the same defect: it removed the browser's OWN default
   spacing, so the caption sat against the glyph even before `gap` failed. */
.nextxbase-radio-item input[type=radio] {
    margin: 0 5px 0 0;
}

/* A BTNBMP inline icon is bounded by the button, not by the button's full height */
.nextxbase-btnbmp > img.nxb-btnbmp-icon {
    max-height: 20px;
    width: auto;
    flex: 0 0 auto;
    -ms-flex: 0 0 auto;
}

/* Background textures and full-size images fill the full button canvas */
.nextxbase-btnbmp > img.nxb-btnbmp-bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    max-height: none !important;
    max-width: none !important;
    border: none;
    padding: 0;
    margin: 0;
    pointer-events: none;
}

/* THEME: GLASSMORPHISM =======================================================
   Was a name with no styling: theme-system / theme-dark / theme-citrus /
   theme-glassmorphism all shared one `background:#f5f3ef` block, so picking it
   changed a class attribute and nothing else.

   The whole theme is inside @supports for backdrop-filter. IE11 -- what the
   native IWebBrowser2 container pins to -- cannot parse @supports, so it skips
   every rule here and renders exactly as it does today. Nothing below is a
   fallback for it; the flat theme IS the fallback, and it is already shipped.

   NOT ONE DECLARATION CHANGES A SIZE. Colour, background, border-COLOR, shadow
   and filter only. Borders that exist at 1px stay 1px and change hue. Space the
   developer reserved stays exactly as reserved -- that rule outranks any look.

   THE COLOUR IS IN THE GROUND, NOT THE PANELS. Every surface is translucent and
   blurs what is behind it, so the vivid field below shows THROUGH the chrome
   rather than being painted onto it. Re-tinting the product is then one
   gradient, not forty rules -- and no surface needs a per-palette variant,
   which is the same property that lets the buttonbar effect work on any skin.
   ========================================================================== */
/* ===========================================================================
   THE PAGE GROUND IS NOT BLUR-DEPENDENT, AND IT SPENT ITS LIFE INSIDE THE
   BLUR BLOCK.

   Everything below used to sit inside the @supports (backdrop-filter) rule
   that begins after it.  IE11 does not implement @supports AT ALL -- it
   discards the whole at-rule -- and IE11-mode MSHTML is this engine's
   SHIPPED FLOOR (Windows 7, no Evergreen runtime).  So on the floor:

       ten of fifteen themes painted NO page ground whatever
       (charcoal, fluent_dark, fluent_light, frost, liquid-glass,
        material3, nord, onyx, white, win32_classic -- measured 2026-09-10,
        and fluent_light is the one NXB_SetTheme falls back to)

   and what the user saw instead was window.prg's inline background:#f8fafc
   on #nxb-stage: a near-white page under every dark theme, which is exactly
   the case 0-E's table names.  audit_ie11_css could not see it -- that gate
   counts unsupported DECLARATIONS (grid, gap, var()) and knows nothing
   about @supports, so 805 lines, 12.8% of this stylesheet, were invisible
   to it.

   NOT ONE DECLARATION MOVED HERE MENTIONS backdrop-filter.  These rules are
   background-color, background-image gradients, background-attachment and
   color -- all of which IE11 renders.  The blur architecture stays inside
   the @supports below, where the condition is about something the rules
   actually use.  A CASE, not a fork: one ground for every rung, and the
   blur is the case.

   GROUND AND INK TRAVEL TOGETHER (0-E): every rule below states both, which
   is why they can be moved as a unit without a theme ending up with a dark
   ground and a dark ink.

   THE `!important` ON THE STAGE RULE STAYS, deliberately.  The per-theme
   `.theme-x #nxb-stage` selectors below are MORE specific than the bare
   `#nxb-stage`, so without it the stage would paint the ground a second
   time on top of the body's.  It is engine chrome making the stage a
   pass-through, not a theme rule locking an application out.
   =========================================================================== */
    #nxb-stage,
    #nxb-stage-fit,
    .nxb-stage-viewport {
        background: transparent !important;
        background-color: transparent !important;
        background-image: none !important;
    }

    /* ---------------------------------------------------------------------- */
    /* LAYER 3: GROUND ILLUMINATION (Substrate & Refraction Fields)            */
    /* ---------------------------------------------------------------------- */

    /* FROST GROUND -- the light the rest of the theme is made of.

       Reference: nextxbase.com/img/fivewin-3d.jpg. A near-white studio ground
       with soft pastel bleeds (lilac, sky, mint, peach) and no dark corner
       anywhere. What was here before was a "blackish-to-white" ramp ending at
       #1e293b, which is the opposite picture.

       EVERY STOP IS A PERCENTAGE, NEVER A PIXEL COUNT, and that is a defect
       fix rather than a style choice. The previous ground sized its radials
       absolutely -- radial-gradient(1000px 700px at 92% 92%, rgba(15,23,42,
       0.88)) -- so how much of the page went dark depended on how wide the
       viewport happened to be. Measured 2026-09-03: the product's CSS
       viewport is 1188 px where Chrome's was 1520, and one 1000px radial
       therefore swallowed the whole application. A ground whose appearance is
       a function of the viewport's pixel width is the @media breakpoint
       section 1b records, wearing a different hat. */
    html.theme-frost, body.theme-frost,
    .theme-frost #nxb-stage, .theme-frost .nxb-stage-viewport,
.theme-frost.control-theme-frost.nxb-stage-viewport {
        background-color: #eef3fb;
        background-image:
            radial-gradient(72% 62% at 6% 2%, rgba(155, 124, 250, 0.50), transparent 64%),
            radial-gradient(66% 56% at 97% 8%, rgba(103, 202, 252, 0.52), transparent 62%),
            radial-gradient(62% 56% at 90% 94%, rgba(252, 176, 120, 0.44), transparent 62%),
            radial-gradient(66% 60% at 3% 97%, rgba(77, 231, 205, 0.44), transparent 64%),
            radial-gradient(76% 66% at 48% 44%, rgba(255, 255, 255, 0.78), transparent 72%),
            linear-gradient(150deg, #ffffff 0%, #eaf1fb 46%, #e8ecff 100%);
        background-attachment: fixed;
        color: #16233a;
    }

    /* ONYX GROUND (Liquid Glass): Rich midnight slate ground with vibrant cyan & violet caustics */
    html.theme-liquid-glass, body.theme-liquid-glass,
    html.theme-onyx, body.theme-onyx,
    .theme-liquid-glass #nxb-stage, .theme-onyx #nxb-stage,
    .theme-liquid-glass .nxb-stage-viewport, .theme-onyx .nxb-stage-viewport,
.theme-liquid-glass.control-theme-liquid-glass.nxb-stage-viewport,
.theme-onyx.control-theme-onyx.nxb-stage-viewport {
        background-color: #0f172a;
        background-image:
            radial-gradient(1100px 750px at 12% -6%, rgba(14, 165, 233, 0.35), transparent 60%),
            radial-gradient(1000px 700px at 88% 8%, rgba(20, 184, 166, 0.32), transparent 60%),
            radial-gradient(1000px 800px at 80% 94%, rgba(139, 92, 246, 0.30), transparent 60%),
            radial-gradient(900px 700px at 10% 90%, rgba(56, 189, 248, 0.25), transparent 60%),
            linear-gradient(155deg, #1e293b 0%, #0f172a 50%, #020617 100%);
        background-attachment: fixed;
        color: #f8fafc;
    }

    /* STANDBY THEMES */
    html.theme-fluent_light, body.theme-fluent_light,
    html.theme-system, body.theme-system,
    .theme-fluent_light #nxb-stage, .theme-system #nxb-stage {
        background: #f3f3f3;
        color: #1a1a1a;
    }
    html.theme-fluent_dark, body.theme-fluent_dark,
    .theme-fluent_dark #nxb-stage {
        background: #202020;
        color: #ffffff;
    }
    html.theme-win32_classic, body.theme-win32_classic,
    .theme-win32_classic #nxb-stage {
        background: #3a6ea5;
        color: #000000;
    }
    html.theme-nord, body.theme-nord,
    .theme-nord #nxb-stage {
        background: #2e3440;
        color: #eceff4;
    }
    html.theme-material3, body.theme-material3,
    .theme-material3 #nxb-stage {
        background: #fef7ff;
        color: #1d1b20;
    }
    html.theme-white, body.theme-white,
    .theme-white #nxb-stage {
        background: #f8fafc;
        color: #0f172a;
    }
    html.theme-charcoal, body.theme-charcoal,
    .theme-charcoal #nxb-stage {
        background: #18181b;
        color: #f4f4f5;
    }
    html.theme-macos, body.theme-macos,
    .theme-macos #nxb-stage {
        background: #ececec;
        color: #1d1d1f;
    }
    html.theme-windows, body.theme-windows,
    .theme-windows #nxb-stage {
        background: #f3f3f3;
        color: #1a1a1a;
    }
    html.theme-linux, body.theme-linux,
    html.theme-gnome, body.theme-gnome,
    .theme-linux #nxb-stage, .theme-gnome #nxb-stage {
        background: #242424;
        color: #ffffff;
    }


/* ===========================================================================
   AND ELEVEN MORE RULES COULD NOT NEED THE BLUR THEY WERE GATED ON.

   03ca007b moved the page GROUND out of the @supports below. This is the
   rest of the same defect, found by asking one decidable question of every
   rule in that block: does it declare the tested property, and if not, is
   anything it paints TRANSLUCENT? A rule with an alpha channel genuinely
   belongs with the blur -- there has to be something to see through. A fully
   OPAQUE colour cannot depend on a backdrop filter at all.

   MEASURED 2026-09-10: 58 rules in the block, 13 declare a blur property, 45
   do not, and of those 45 exactly ELEVEN are opaque appearance. IE11 discards
   the at-rule whole, so on the shipped floor those eleven did not exist --
   win32_classic had no window chrome and no titlebar, nord had no titlebar,
   FIVE themes had no browse/grid styling at all, and two per-theme SAY ink
   rules were missing while their grounds (moved in 03ca007b) were not, which
   is 0-E's half-a-decision shape arriving on one rung only.

   TWO NON-BLUR RULES STAY INSIDE, DELIBERATELY, named so the next reader does
   not re-derive the list. The html/body rule there is a LAYOUT reset --
   margin, padding, width, min-height, not a colour -- and window.prg already
   emits margin:0;padding:0 inline on body, so moving it would change the
   floor's LAYOUT, a different unit with a different acceptance. The
   .btn-glass-* :active transform belongs to a button family that only exists
   as glass.

   AND THE ASSERTION THAT CAUGHT THIS COMMENT'S OWN FIRST DRAFT IS WORTH THE
   LINE: an earlier wording contained a literal CSS snippet in braces, so the
   brace-balance check on the rewritten file failed and NOTHING WAS WRITTEN.
   A comment is not inert to a scripted edit that counts delimiters.
   =========================================================================== */
.theme-win32_classic.nextxbase-window, .theme-win32_classic .nextxbase-window {
        box-sizing: border-box;
        background: #c0c0c0; border: 2px outset #ffffff;
        border-radius: 0px; box-shadow: 2px 2px 0px #000000; color: #000000;
    }
.theme-win32_classic .nextxbase-slot-titlebar,
.theme-win32_classic.control-theme-win32_classic.nextxbase-slot-titlebar {
        background: linear-gradient(90deg, #000080, #1084d0);
        color: #ffffff;
        font-weight: bold;
    }
.theme-nord .nextxbase-slot-titlebar,
.theme-nord.control-theme-nord.nextxbase-slot-titlebar {
        background: #3b4252;
        border-bottom: 1px solid #4c566a;
        color: #eceff4;
    }
.theme-liquid-glass .nextxbase-say,
    .theme-onyx .nextxbase-say,
    .theme-fluent_dark .nextxbase-say,
    .theme-nord .nextxbase-say,
    .theme-charcoal .nextxbase-say,
    /* A CHECKBOX PROMPT IS A LABEL and the base rule for it says exactly that
       -- "Same argument as `.nextxbase-say`". It was themed here and the
       checkbox caption was not, so .nextxbase-chk-label kept its base
       color:#1a1814 on every dark ground: MEASURED 1.00:1 on charcoal,
       1.14 on fluent_dark, 1.42 on nord. Same rule, not a second one, so the
       two cannot drift apart again.

       RESTORED, NOT WRITTEN. This is another instance's work verbatim. My
       ribbon commit 1909e8ee deleted it -- `git commit -- <path>` writes the
       WORKTREE, and mine predated their change, so committing my copy reverted
       theirs. The light half below survived; these five did not. */
    .theme-liquid-glass .nextxbase-chk-label,
    .theme-onyx .nextxbase-chk-label,
    .theme-fluent_dark .nextxbase-chk-label,
    .theme-nord .nextxbase-chk-label,
    .theme-charcoal .nextxbase-chk-label,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-say,
.theme-onyx.control-theme-onyx.nextxbase-say,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-say,
.theme-nord.control-theme-nord.nextxbase-say,
.theme-charcoal.control-theme-charcoal.nextxbase-say,
.theme-onyx.control-theme-onyx.nextxbase-chk-label,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-chk-label,
.theme-nord.control-theme-nord.nextxbase-chk-label,
.theme-charcoal.control-theme-charcoal.nextxbase-chk-label {
        color: #f8fafc;
    }
.theme-frost .nextxbase-say,
    .theme-fluent_light .nextxbase-say,
    .theme-white .nextxbase-say,
    .theme-frost .nextxbase-chk-label,
    .theme-fluent_light .nextxbase-chk-label,
    .theme-white .nextxbase-chk-label,
.theme-frost.control-theme-frost.nextxbase-say,
.theme-fluent_light.control-theme-fluent_light.nextxbase-say,
.theme-white.control-theme-white.nextxbase-say,
.theme-frost.control-theme-frost.nextxbase-chk-label,
.theme-fluent_light.control-theme-fluent_light.nextxbase-chk-label,
.theme-white.control-theme-white.nextxbase-chk-label {
        color: #061528;
    }
.theme-frost .nextxbase-grid-container tbody tr.nxb-row-sel,
.theme-frost.control-theme-frost.nextxbase-grid-container tbody tr.nxb-row-sel {
        background: linear-gradient(180deg, #4f96f6 0%, #2f6fe4 100%);
        color: #ffffff;
        font-weight: 600;
    }
/* Standard Themes Grids */
    .theme-fluent_light .nextxbase-grid-container,
    .theme-system .nextxbase-grid-container,
.theme-system.control-theme-system.nextxbase-grid-container {
        background: #ffffff; border: 1px solid #e5e5e5; border-radius: 8px;
    }
.theme-fluent_dark .nextxbase-grid-container,
.theme-fluent_dark.control-theme-fluent_dark.nextxbase-grid-container {
        background: #2b2b2b; border: 1px solid #3d3d3d; border-radius: 8px; color: #ffffff;
    }
.theme-win32_classic .nextxbase-grid-container,
.theme-win32_classic.control-theme-win32_classic.nextxbase-grid-container {
        background: #ffffff; border: 2px inset #ffffff; border-radius: 0px;
    }
.theme-win32_classic .nextxbase-grid-container thead th,
.theme-win32_classic.control-theme-win32_classic.nextxbase-grid-container thead th {
        background: #c0c0c0; border: 1px outset #ffffff; color: #000000;
    }
.theme-nord .nextxbase-grid-container,
.theme-nord.control-theme-nord.nextxbase-grid-container {
        background: #3b4252; border: 1px solid #4c566a; border-radius: 12px; color: #eceff4;
    }


/* ===========================================================================
   AND A GLASS WINDOW HAS NO FLAT FALLBACK, WHICH TURNED A FIX INTO A
   REGRESSION ON THE FLOOR. FOUND BY PHOTOGRAPHING IT.

   4a366dc0 moved the per-theme SAY INK out of the blur block. The per-theme
   WINDOW ground could not follow it: those rules declare backdrop-filter and
   their background carries an alpha, so they belong inside -- correctly.

   The result on the shipped floor, captured on floor_theme_probe with
   fluent_dark: body reached rgb(32,32,32) as intended, .nextxbase-window fell
   through to the GENERIC rgb(245,243,239), and the SAY painted rgb(255,255,255)
   on top of it. WHITE ON NEAR-WHITE, about 1.05:1. Before that commit the ink
   was missing too and read dark-on-light, so the move made this one surface
   WORSE. Ground and ink are one decision (0-E), and moving half of it across
   a rung boundary is the same defect wearing a new hat.

   EVERY NUMBER BELOW IS DERIVED, NOT CHOSEN. Each theme's glass window states
   an rgba; each theme's page ground is already outside this block. Compositing
   the first over the second is what "degrades to a flat colour" actually
   means, and it is arithmetic on two declarations that already exist rather
   than a palette somebody has to keep in step. The ink is copied from the same
   glass rule unchanged.

   THESE SIT BEFORE THE @supports SO THE GLASS STILL WINS ON A MODERN ENGINE:
   identical selectors, and the later rule takes it. Verified by comparing the
   resolved cascade before and after -- 0 of 63 theme/selector pairs moved.
   =========================================================================== */

.theme-frost.nextxbase-window,
    .theme-frost .nextxbase-window,
    .theme-frost.nextxbase-dialog,
    .theme-frost .nextxbase-dialog,
.theme-frost.control-theme-frost.nextxbase-dialog {
    background: #f2f6fc;
    color: #16233a;
}

.theme-liquid-glass.nextxbase-window,
    .theme-liquid-glass .nextxbase-window,
    .theme-onyx.nextxbase-window,
    .theme-onyx .nextxbase-window,
    .theme-liquid-glass.nextxbase-dialog,
    .theme-liquid-glass .nextxbase-dialog,
    .theme-onyx.nextxbase-dialog,
    .theme-onyx .nextxbase-dialog,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-dialog,
.theme-onyx.control-theme-onyx.nextxbase-dialog {
    background: #162032;
    color: #f8fafc;
}

.theme-fluent_light.nextxbase-window, .theme-fluent_light .nextxbase-window,
    .theme-system.nextxbase-window, .theme-system .nextxbase-window {
    background: #fefefe;
    color: #1a1a1a;
}

.theme-fluent_dark.nextxbase-window, .theme-fluent_dark .nextxbase-window {
    background: #242424;
    color: #ffffff;
}

.theme-nord.nextxbase-window, .theme-nord .nextxbase-window {
    background: #2e3440;
    color: #eceff4;
}

.theme-material3.nextxbase-window, .theme-material3 .nextxbase-window {
    background: #f3edf7;
    color: #1d1b20;
}

.theme-white.nextxbase-window, .theme-white .nextxbase-window {
    background: #ffffff;
    color: #0f172a;
}

.theme-charcoal.nextxbase-window, .theme-charcoal .nextxbase-window {
    background: #18181b;
    color: #f4f4f5;
}

/* THE WORKSPACE MUST NOT PAINT ITS OWN GROUND OVER THE WINDOW'S, AND THIS
   RULE WAS TRAPPED INSIDE THE @supports BELOW -- SO IT DID, ON THE FLOOR ONLY.

   MEASURED 2026-09-10 on the IE11 floor, fluent_dark, by the page itself
   -- the rect probe's #stylesheets row, which is the only channel out of a
   rung that has no CDP:

       windowBg        rgb(36, 36, 36)      the theme's ground, correct
       workspaceBg     rgb(245, 243, 239)   #f5f3ef -- a LITERAL
       topAtWinCentre  DIV.nextxbase-slot-workspace, painting that literal

   elementFromPoint at the window's own centre lands on the WORKSPACE, not
   on the window. So the window resolved dark and the photograph came back
   light and BOTH readings were right: a light slab painted on top of a
   correct window. No cascade question and no lost rule -- a paint order.

   .nextxbase-slot-workspace declares background-color #f5f3ef at the top of
   this file, and only .theme-light and .os-windows.theme-system ever
   override it. Every other theme depended on THIS declaration to take it
   back off -- and IE11 does not implement @supports, so it discards the
   at-rule whole and the literal stood.

   Moved out rather than duplicated: a modern engine reads exactly what it
   read before (the glass rules that genuinely need the at-rule are still
   inside it), and the floor now resolves the workspace the same way, which
   is the whole point. The two rungs disagreeing about one element is the
   fork, whatever either one looks like on its own. */
.nextxbase-slot-workspace {
    background-color: transparent !important;
}

@supports ((-webkit-backdrop-filter: blur(2px)) or (backdrop-filter: blur(2px))) {

    /* ====================================================================== */
    /* APPLE LIQUID GLASS (3-LAYER ARCHITECTURE: HIGHLIGHT, SHADOW, ILLUM)    */
    /* Reference: CSS-Tricks "Getting Clarity on Apple's Liquid Glass" (WWDC) */
    /* ====================================================================== */

    html, body {
        margin: 0 !important;
        padding: 0 !important;
        width: 100% !important;
        min-height: 100vh !important;
    }


    /* ---------------------------------------------------------------------- */
    /* LAYERS 1 & 2: FLOATING WINDOW SLABS (Highlight + Shadow + Illum)       */
    /* ---------------------------------------------------------------------- */

    /* FROST WINDOW (frosted crystal slab)

       IT NO LONGER PLACES OR SIZES THE WINDOW, and that is the point. This
       rule used to force position:absolute, top/left 24px and
       width/height:calc(100% - 48px) with !important on every window AND
       every dialog carrying the theme -- so a dialog declared
       FROM 120, 150 TO 540, 800 was stretched across the whole parent and the
       application's own coordinates were unreachable. A theme paints; an
       application places (ground rule 4, and section 1b's breakpoint is the
       same defect). The slab reads as a floating card because it is
       translucent over the pastel ground, not because it was inset by hand. */
    .theme-frost.nextxbase-window,
    .theme-frost .nextxbase-window,
    .theme-frost.nextxbase-dialog,
    .theme-frost .nextxbase-dialog,
.theme-frost.control-theme-frost.nextxbase-dialog {
        box-sizing: border-box;
        border-radius: 22px;

        /* Illumination (frosted substrate) */
        background: rgba(255, 255, 255, 0.26);
        background-image:
            linear-gradient(160deg,
                rgba(255, 255, 255, 0.58) 0%,
                rgba(255, 255, 255, 0.16) 46%,
                rgba(255, 255, 255, 0.40) 100%);
        -webkit-backdrop-filter: blur(30px) saturate(180%);
        backdrop-filter: blur(30px) saturate(180%);

        /* Highlight layer: one hairline, lit from the top */
        border: 1px solid rgba(255, 255, 255, 0.82);

        /* Shadow layer: wide, soft and BLUE-tinted, which is what makes a
           white card read as floating over white rather than as a hole. */
        box-shadow:
            0 40px 80px -32px rgba(30, 48, 90, 0.34),
            0 12px 30px -18px rgba(30, 48, 90, 0.20),
            inset 0 1px 0 rgba(255, 255, 255, 0.95),
            inset 0 0 60px rgba(255, 255, 255, 0.28);
        color: #16233a;
    }

    /* ONYX WINDOW (Liquid Glass: Luminous Translucent Smoked Glass Slab) */
    .theme-liquid-glass.nextxbase-window,
    .theme-liquid-glass .nextxbase-window,
    .theme-onyx.nextxbase-window,
    .theme-onyx .nextxbase-window,
    .theme-liquid-glass.nextxbase-dialog,
    .theme-liquid-glass .nextxbase-dialog,
    .theme-onyx.nextxbase-dialog,
    .theme-onyx .nextxbase-dialog,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-dialog,
.theme-onyx.control-theme-onyx.nextxbase-dialog {
        /* NO GEOMETRY HERE. A theme paints; an application places (ground rule 4).
           These rules used to force position:absolute, top/left 24px and
           width/height:calc(100% - 48px) with, so a window -- and,
           on the onyx selector, a DIALOG -- could not keep the box its own
           .prg declared. Removed in the same edit for all eight, because fixing
           frost alone left the identical defect in eight other themes. */
        box-sizing: border-box;
        border-radius: 28px;

        /* Illumination: Translucent Smoked Glass (airier, lighter & luminous) */
        background: rgba(30, 41, 59, 0.48);
        background-image:
            linear-gradient(135deg,
                rgba(255, 255, 255, 0.40) 0%,
                rgba(71, 85, 105, 0.38) 30%,
                rgba(30, 41, 59, 0.30) 65%,
                rgba(255, 255, 255, 0.20) 100%);
        -webkit-backdrop-filter: blur(36px) saturate(220%) brightness(108%);
        backdrop-filter: blur(36px) saturate(220%) brightness(108%);

        /* Highlight Layer (Clear Crystal Specular Edges) */
        border: 1.5px solid rgba(255, 255, 255, 0.55);
        border-bottom: 3.5px solid rgba(255, 255, 255, 0.28);
        border-right: 3px solid rgba(255, 255, 255, 0.28);

        /* Shadow Layer (Balanced Elevation + Internal Specular Glow) */
        box-shadow:
            0 40px 90px -15px rgba(0, 0, 0, 0.60),
            0 16px 36px -10px rgba(14, 165, 233, 0.20),
            inset 1.5px 1.5px 3px rgba(255, 255, 255, 0.90),
            inset -1px -1px 3px rgba(0, 0, 0, 0.20),
            inset 0 0 40px rgba(255, 255, 255, 0.20);
        color: #f8fafc;
    }

    /* Other Windows */
    .theme-fluent_light.nextxbase-window, .theme-fluent_light .nextxbase-window,
    .theme-system.nextxbase-window, .theme-system .nextxbase-window {
        box-sizing: border-box;
        background: rgba(255, 255, 255, 0.88);
        -webkit-backdrop-filter: blur(30px); backdrop-filter: blur(30px);
        border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 14px;
        box-shadow: 0 20px 50px rgba(0, 0, 0, 0.15); color: #1a1a1a;
    }
    .theme-fluent_dark.nextxbase-window, .theme-fluent_dark .nextxbase-window {
        box-sizing: border-box;
        background: rgba(36, 36, 36, 0.88);
        -webkit-backdrop-filter: blur(30px); backdrop-filter: blur(30px);
        border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 14px;
        box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); color: #ffffff;
    }
        .theme-nord.nextxbase-window, .theme-nord .nextxbase-window {
        box-sizing: border-box;
        background: rgba(46, 52, 64, 0.94);
        -webkit-backdrop-filter: blur(25px); backdrop-filter: blur(25px);
        border: 1px solid #4c566a; border-radius: 16px;
        box-shadow: 0 25px 60px rgba(0, 0, 0, 0.4); color: #eceff4;
    }
    .theme-material3.nextxbase-window, .theme-material3 .nextxbase-window {
        box-sizing: border-box;
        background: #f3edf7; border: 1px solid #cac4d0;
        border-radius: 20px; box-shadow: 0 16px 36px rgba(0, 0, 0, 0.12); color: #1d1b20;
    }
    .theme-white.nextxbase-window, .theme-white .nextxbase-window {
        box-sizing: border-box;
        background: rgba(255, 255, 255, 0.94); border: 1.5px solid #e2e8f0;
        border-radius: 20px; box-shadow: 0 25px 60px rgba(15, 23, 42, 0.1); color: #0f172a;
    }
    .theme-charcoal.nextxbase-window, .theme-charcoal .nextxbase-window {
        box-sizing: border-box;
        background: rgba(24, 24, 27, 0.96); border: 1.5px solid rgba(255, 255, 255, 0.12);
        border-radius: 20px; box-shadow: 0 30px 70px rgba(0, 0, 0, 0.6); color: #f4f4f5;
    }

    /* ---------------------------------------------------------------------- */
    /* TITLEBARS (Refractive Glass Header Band)                               */
    /* ---------------------------------------------------------------------- */
    .theme-frost .nextxbase-slot-titlebar {
        background: rgba(255, 255, 255, 0.55);
        -webkit-backdrop-filter: blur(22px) saturate(160%);
        backdrop-filter: blur(22px) saturate(160%);
        border-bottom: 1px solid rgba(255, 255, 255, 0.75);
        color: #1b2c4a;
        font-weight: 600;
        border-top-left-radius: 21px;
        border-top-right-radius: 21px;
    }
    .theme-liquid-glass .nextxbase-slot-titlebar,
    .theme-onyx .nextxbase-slot-titlebar,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-slot-titlebar,
.theme-onyx.control-theme-onyx.nextxbase-slot-titlebar {
        background: rgba(51, 65, 85, 0.45);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
        border-bottom: 1.5px solid rgba(255, 255, 255, 0.25);
        color: #ffffff;
        font-weight: 800;
        border-top-left-radius: 26px;
        border-top-right-radius: 26px;
    }

    /* ---------------------------------------------------------------------- */
    /* LABELS (TSAY) - PURE TRANSPARENT WITH HIGH CONTRAST                    */
    /* ---------------------------------------------------------------------- */
    .nextxbase-say {
        /* NO `!important`, FOR THE SAME REASON THE COLOUR RULE BELOW LOST
           ITS OWN: it was discarding a ground the APPLICATION DECLARED.
           `!important` in a stylesheet outranks a plain inline style, so
           every SAY was painted transparent even where the application had
           stated a background. Measured on MayaPOS's Ventas terminal --
           three SAYs on one dialog, every one discarded:

               say_000086  declared rgb(0,0,0)        -> rgba(0,0,0,0)
               say_000088  declared rgb(122,152,103)  -> rgba(0,0,0,0)
               say_000101  declared rgb(238,233,233)  -> rgba(0,0,0,0)

           The middle one is a GREEN swatch the application asked for and
           the user never sees. Section 0-E: ground and ink are ONE
           decision, and this was the ground half of the defect fixed for
           the ink in 7493765d.

           IT STILL WINS WHERE IT IS MEANT TO. The base `.nextxbase-say`
           rule asks for `background-color: inherit` and is thousands of
           lines ABOVE this one at the SAME specificity (0,1,0), so this
           still takes it by document order -- the glass themes this
           @supports block serves keep their transparent label. What it no
           longer does is outrank the application.

           AND IT CONTRADICTS THAT BASE RULE, WHICH IS WORTH KNOWING
           RATHER THAN FIXING HERE: the base one explains at length why a
           SAY must be OPAQUE -- a Win32 static ERASES its rectangle, which
           is what lets a later control hide an earlier one, and
           "ours were transparent, so every overlapping caption showed
           through every other and the page turned to mush". This rule
           forces that back. It is ALSO keyed on browser CAPABILITY rather
           than on a glass theme being active -- every neighbour in this
           @supports block is scoped `.theme-liquid-glass ...` and this one
           is bare -- so it reaches every theme on every modern engine.
           Narrowing it is a look change across 15 themes and wants a
           capture; dropping the force does not, and is the half that is
           unambiguously wrong. */
        background: transparent;
        background-color: transparent;
    }
        
    /* A DIALOG OWNS THE SURFACE INSIDE IT, so the two rules above must stop at
       its edge. They state an ink for a ground they do not own: the theme
       paints the WINDOW, and #f8fafc is right for a caption sitting on it --
       but a dialog paints its own #f0f0f0 (see .nextxbase-dialog) and a
       near-white caption on that is 1.09:1.

       MEASURED 2026-09-05, ctllab, all 15 themes: 'pushes the dialog wider'
       and 'fits inside' unreadable under charcoal, fluent_dark and nord. They
       are the last two rows of that gate's list.

       SCOPING THE RULES ABOVE would be the tidier fix and is not available:
       excluding a descendant needs :not() with a combinator or :has(), and the
       Windows 7 floor is MSHTML, where neither matches -- the fail-open shape
       audit_css_reach exists to catch. So the dialog restates the ink for the
       surface it does paint. Specificity is EQUAL (0,2,0 both), so this works
       only because it comes LATER in the file: keep it after the theme rules.

       IT PAIRS WITH .nextxbase-dialog's OWN GROUND and moves with it. If a
       theme is ever given a dark dialog, this ink has to move in the same
       edit -- whether a dialog should follow the theme at all is a design
       question nobody has answered, and it is not answered here. */
    /* REPEATED CLASS, AND IT IS LOAD-BEARING RATHER THAN A TYPO.
       This selector must outrank the theme block's COMPOUND arm
       (`.theme-onyx.control-theme-onyx.nextxbase-say`, 0,3,0) and must
       NOT outrank an application's own inline ink. `!important` did the
       first and could not help doing the second -- see the colour line
       below. Repeating the class is 0,4,0, which wins the first and
       loses to inline, which is exactly the order ground rule 5 asks
       for.

       THE FLOOR IS REASONED, NOT PHOTOGRAPHED, AND THAT IS SAID HERE
       RATHER THAN GLOSSED. A compound class selector is CSS2.1 and
       IE7+, and repeating one class is three checks against the same
       element, so MSHTML should resolve it -- but `audit_ie11_css`
       counts DECLARATIONS and reads no selector, and this is the
       FIRST repeated-class selector in this stylesheet, so nothing
       here has ever exercised the shape on the floor. If a dialog
       caption ever loses its ink under NEXTXBASE_VIEWER=mshtml, this
       selector is the first thing to suspect. */
    /* THE PLAIN FORM FIRST, AS A FALLBACK, AND IT IS THE SAME SHAPE THIS
       STYLESHEET ALREADY USES FOR `display:flex` BEFORE `display:grid`:
       state what every engine understands, then the enhancement.

       WHY IT IS HERE RATHER THAN TRUSTING THE REPEATED CLASS ALONE. The
       0,4,0 selector below is the FIRST repeated-class selector in this
       file, so nothing here has ever exercised that shape on the MSHTML
       floor, and no gate reads selectors -- `audit_ie11_css` counts
       DECLARATIONS.

       WHAT DEGRADES IF THE FLOOR IGNORES IT IS MEASURED, NOT GUESSED --
       two faithful fixtures, no wrapper class, so the specificities are
       the real ones (an earlier fixture wrapped each arm in a class and
       that extra 0,1,0 made the fallback look like it covered
       everything, which it does not):

                              app ink   no ink   compound theme
           fallback only        app      dialog     THEME
           both rules           app      dialog     dialog

       So the fallback holds the FIX and the inherit case on any engine,
       and the selector below buys exactly ONE thing: the theme's
       compound 0,3,0 arm. A floor that ignored it would lose that case
       alone rather than the whole rule. */

       IT COSTS NOTHING WHERE THE ENHANCEMENT WORKS: both declare the
       same `inherit`, so where both match the result is identical, and
       BOTH lose to an application's inline ink because neither forces.
       0,2,0 beats the theme rules by ORDER -- the argument the original
       comment above already makes -- and only the theme's COMPOUND
       0,3,0 arm needs the selector below. */
    .nextxbase-dialog .nextxbase-say,
    .nextxbase-dialog .nextxbase-chk-label {
        color: inherit;
    }

    .nextxbase-dialog .nextxbase-say.nextxbase-say.nextxbase-say,
    /* The checkbox prompt rides with the label here for the same reason it
       rides with it above: it IS a label, and a rule that themes one and not
       the other is exactly how the two drifted apart. */
    .nextxbase-dialog .nextxbase-chk-label.nextxbase-chk-label.nextxbase-chk-label {
        /* `inherit`, NOT A COLOUR, and that is the whole correction. Written
           first as #1a1814 -- right for the base #f0f0f0 dialog and WRONG the
           moment a theme restyles the dialog itself. frost, liquid-glass and
           onyx all do, each pairing its own ground with its own ink, and this
           rule overrode the ink and kept their ground: MEASURED with --pixels,
           'pushes the dialog wider' at 1.73:1 under onyx, rgb(28,27,31) on
           rgb(50,63,123). A regression I introduced this morning, found by the
           painted-pixel pass and not by the computed one.

           A caption's ink is the DIALOG's ink, whatever set it -- the base rule
           or any theme -- so the caption asks for it instead of restating it.
           One rule, no colour, no per-theme list to keep in step, and a theme
           added tomorrow is covered without touching this. `inherit` is IE8+,
           so it is available on the Windows 7 floor. */
        /* NO `!important`, AND THAT IS THE FIX. It beat the APPLICATION'S
           OWN INLINE INK, which no engine rule may do: `!important` in a
           stylesheet outranks a plain inline declaration, so every SAY
           inside a dialog was painted the dialog's colour EVEN WHERE THE
           APPLICATION HAD STATED ONE. Measured on MayaPOS's Ventas
           terminal: the panel caption declares `color:rgb(192,192,192)`
           inline and computed `rgb(26,24,20)` -- near-black on the
           application's own black brush, 1.18:1, invisible. Two more
           SAYs on that one dialog were losing a declared ink the same
           way. That is ground rule 5 broken by the engine: Harbour has
           already evaluated the colour and our job is to render the
           RESULT, not to overrule it.

           THE COMMENT ABOVE ALREADY SAID THE ORDERING ARGUMENT AND THE
           `!important` WAS NEVER PART OF IT -- 'Specificity is EQUAL
           (0,2,0 both), so this works only because it comes LATER in the
           file'. What that reasoning missed is the theme block's
           COMPOUND arm at 0,3,0, which order cannot beat; the repeated
           class above beats it by specificity instead.

           RED THEN GREEN on an isolated cascade fixture, all three
           properties at once, because fixing one by breaking another is
           the risk here:
                                       shipped   this rule
               application ink honoured  NO        YES
               inherits when none set    yes       yes
               beats the compound theme  yes       yes
        */
        color: inherit;
    }

    /* ---------------------------------------------------------------------- */
    /* FORM CONTROLS (TGET: Refractive Capsule Inputs)                        */
    /* ---------------------------------------------------------------------- */
    .theme-frost .nextxbase-get {
        background: rgba(255, 255, 255, 0.92);
        -webkit-backdrop-filter: blur(10px) saturate(150%);
        backdrop-filter: blur(10px) saturate(150%);
        border: 1px solid rgba(255, 255, 255, 0.95);
        border-radius: 999px;
        padding: 6px 18px;
        box-shadow:
            inset 0 0 0 1px rgba(148, 163, 184, 0.22),
            0 2px 6px rgba(30, 48, 90, 0.08);
        color: #16233a;
        font-weight: 500;
    }
    .theme-frost .nextxbase-get:focus,
.theme-frost.control-theme-frost.nextxbase-get:focus {
        border-color: rgba(56, 189, 248, 0.95);
        box-shadow:
            inset 0 0 0 1px rgba(56, 189, 248, 0.55),
            0 0 0 4px rgba(56, 189, 248, 0.25);
        outline: 0;
    }

    .theme-liquid-glass .nextxbase-get,
    .theme-onyx .nextxbase-get,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-get,
.theme-onyx.control-theme-onyx.nextxbase-get {
        background: rgba(51, 65, 85, 0.55);
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
        border: 1.5px solid rgba(255, 255, 255, 0.35);
        border-radius: 999px;
        padding: 6px 16px;
        box-shadow: inset 0 2px 4px rgba(0,0,0,0.20), 0 2px 8px rgba(0,0,0,0.15);
        color: #ffffff;
        font-weight: 600;
    }
    .theme-liquid-glass .nextxbase-get:focus,
    .theme-onyx .nextxbase-get:focus,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-get:focus,
.theme-onyx.control-theme-onyx.nextxbase-get:focus {
        border-color: #38bdf8;
        box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.35);
        outline: 0;
    }

    /* ---------------------------------------------------------------------- */
    /* DATA GRIDS (TXBROWSE: "Frosted Tips" Contrast Ledger Cards)            */
    /* ---------------------------------------------------------------------- */

    /* FROST TXBROWSE -- a frosted ledger card, with the SELECTED row solid.
       The reference paints selection as a saturated blue bar with white text;
       a 0.18-alpha tint reads as "hovered", not "this is the record you are
       on", and at that alpha the row's own dark text stays dark. */
    .theme-frost .nextxbase-grid-container,
    .theme-frost .nxb-brw,
    .theme-frost .nextxbase-xbrowse,
.theme-frost.control-theme-frost.nxb-brw,
.theme-frost.control-theme-frost.nextxbase-xbrowse {
        background: rgba(255, 255, 255, 0.58);
        -webkit-backdrop-filter: blur(18px) saturate(165%);
        backdrop-filter: blur(18px) saturate(165%);
        border: 1px solid rgba(255, 255, 255, 0.85);
        border-radius: 16px;
        box-shadow:
            0 18px 40px -24px rgba(30, 48, 90, 0.32),
            inset 0 1px 0 rgba(255, 255, 255, 0.95);
        overflow: hidden;
    }
    .theme-frost .nextxbase-grid-container table,
    .theme-frost .nextxbase-grid,
.theme-frost.control-theme-frost.nextxbase-grid-container table,
.theme-frost.control-theme-frost.nextxbase-grid {
        background: transparent;
    }
    .theme-frost .nextxbase-grid-container thead tr,
    .theme-frost .nextxbase-grid thead th,
    .theme-frost .nextxbase-grid-container thead td,
.theme-frost.control-theme-frost.nextxbase-grid-container thead tr,
.theme-frost.control-theme-frost.nextxbase-grid thead th,
.theme-frost.control-theme-frost.nextxbase-grid-container thead td {
        background: linear-gradient(180deg, rgba(255,255,255,0.94) 0%, rgba(233,240,251,0.78) 100%);
        border-bottom: 1px solid rgba(148, 163, 184, 0.30);
        border-right: 1px solid rgba(148, 163, 184, 0.16);
        color: #33496b;
        font-weight: 700;
    }
    .theme-frost .nextxbase-grid-container tbody tr,
.theme-frost.control-theme-frost.nextxbase-grid-container tbody tr {
        background: transparent;
        color: #16233a;
        border-bottom: 1px solid rgba(148, 163, 184, 0.16);
    }
    .theme-frost .nextxbase-grid-container tbody tr:nth-child(even),
.theme-frost.control-theme-frost.nextxbase-grid-container tbody tr:nth-child(even) {
        background: rgba(255, 255, 255, 0.34);
    }
    .theme-frost .nextxbase-grid-container tbody tr:hover,
.theme-frost.control-theme-frost.nextxbase-grid-container tbody tr:hover {
        background: rgba(59, 130, 246, 0.10);
        color: #1d4ed8;
    }
        /* NO INK ON A CELL IN THIS FAMILY -- it inherits the ROW, and the row is
       where both the theme and the application state one.

       The comment that stood here said the cell needed its own white 'or the
       selected row paints dark ink on a saturated blue bar'. That was true
       ONLY because the rule below forced #16233a on every cell, which beat
       the row by specificity; raising the selected ink to cell level fixed
       that symptom and left the general one standing.

       AND IT INVERTED ONCE THE GROUND WENT BACK TO THE APPLICATION.
       xbrowse.prg:3942 emits the browse's own colour model inline on the TR
       -- here `color:#000000; background:#ffffff` for the selected row -- and
       since 28fab873 dropped the !important, that inline ground WINS while
       the forced cell ink did not. MEASURED on full_showcase, --pixels,
       frost: white on rgb(235,235,235), 1.17:1, plus the cell button and the
       record-selector mark at 1.17 and 1.32.

       With no colour on the cell every case falls out of the row, which
       already has one for all three: the theme's #16233a normally, its
       #ffffff on the selected blue bar, and the APPLICATION's whenever the
       browse states its own -- which is the order ground rule 7 asks for and
       the order 28fab873 was restoring. */
    .theme-frost .nextxbase-grid-container tbody tr.nxb-row-sel td,
    .theme-frost .nextxbase-grid-container tbody tr.nxb-row-sel th,
.theme-frost.control-theme-frost.nextxbase-grid-container tbody tr.nxb-row-sel th {
        border-right-color: rgba(255, 255, 255, 0.28);
    }
    .theme-frost .nextxbase-grid-container td,
.theme-frost.control-theme-frost.nextxbase-grid-container td {
        border-right: 1px solid rgba(148, 163, 184, 0.14);
    }
    .theme-frost .nxb-recsel,
.theme-frost.control-theme-frost.nxb-recsel {
        background: rgba(255, 255, 255, 0.45);
    }
    .theme-frost .nxb-grid-smart-footer,
.theme-frost.control-theme-frost.nxb-grid-smart-footer {
        background: rgba(255, 255, 255, 0.72);
        border-top: 1px solid rgba(255, 255, 255, 0.9);
        color: #33496b;
    }

    /* ONYX / LIQUID GLASS TXBROWSE (Translucent Smoked Slate Glass) */
    .theme-liquid-glass .nextxbase-grid-container,
    .theme-liquid-glass .nxb-brw,
    .theme-liquid-glass .nextxbase-xbrowse,
    .theme-onyx .nextxbase-grid-container,
    .theme-onyx .nxb-brw,
    .theme-onyx .nextxbase-xbrowse,
.theme-liquid-glass.control-theme-liquid-glass.nxb-brw,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-xbrowse,
.theme-onyx.control-theme-onyx.nextxbase-grid-container,
.theme-onyx.control-theme-onyx.nxb-brw,
.theme-onyx.control-theme-onyx.nextxbase-xbrowse {
        background: rgba(30, 41, 59, 0.55);
        /* AND THE INK BESIDE THE GROUND (0-E), WHICH THIS RULE OWED
           THE MOMENT ANYTHING ACTUALLY INHERITED FROM IT.

           This rule stated a DARK ground and no colour, which was
           harmless only for as long as TXBROWSE wrote background
           #ffffff and color #000000 inline on every browse -- the
           rule was dead, so its missing half could not hurt anyone.
           bc4b8ff0 removed those inline literals so the theme could
           finally reach a browse, and this rule woke up carrying one
           half of a two-half decision: the cells take the base
           .nextxbase-grid-container ink, #000000, and paint BLACK ON
           DARK NAVY GLASS.

           That is a regression from bc4b8ff0 and it is mine. It is
           also 0-E's exact warning arriving from the direction that
           file does not spell out: fixing a dead rule can expose the
           half somebody omitted BECAUSE it was dead.

           #f1f5fc is not chosen -- it is this theme's own declared
           foreground, from the engine registry:
               s_hThemes[ "liquid-glass" ] := TW32Theme():New(
                   "liquid-glass", "dark", "rgba(18,25,40,0.75)",
                   "#f1f5fc", ... )
           so the stylesheet and TW32Theme cannot drift apart on it. */
        color: #f1f5fc;
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
        border: 1.5px solid rgba(255, 255, 255, 0.28);
        border-radius: 20px;
        box-shadow: 0 16px 36px -10px rgba(0,0,0,0.45), inset 0 1.5px 2px rgba(255,255,255,0.25);
        overflow: hidden;
    }
    .theme-liquid-glass .nextxbase-grid-container table,
    .theme-liquid-glass .nextxbase-grid,
    .theme-onyx .nextxbase-grid-container table,
    .theme-onyx .nextxbase-grid,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid-container table,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid,
.theme-onyx.control-theme-onyx.nextxbase-grid-container table,
.theme-onyx.control-theme-onyx.nextxbase-grid {
        background: transparent;
    }
    .theme-liquid-glass .nextxbase-grid-container thead tr,
    .theme-liquid-glass .nextxbase-grid thead th,
    .theme-onyx .nextxbase-grid-container thead tr,
    .theme-onyx .nextxbase-grid thead th,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid-container thead tr,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid thead th,
.theme-onyx.control-theme-onyx.nextxbase-grid-container thead tr,
.theme-onyx.control-theme-onyx.nextxbase-grid thead th {
        background: linear-gradient(180deg, rgba(51,65,85,0.80) 0%, rgba(30,41,59,0.70) 100%);
        border-bottom: 1.5px solid rgba(255,255,255,0.25);
        border-right: 1px solid rgba(255,255,255,0.12);
        color: #ffffff;
        font-weight: 800;
    }
    .theme-liquid-glass .nextxbase-grid-container tbody tr,
    .theme-onyx .nextxbase-grid-container tbody tr,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid-container tbody tr,
.theme-onyx.control-theme-onyx.nextxbase-grid-container tbody tr {
        background: transparent;
        color: #f8fafc;
        border-bottom: 1px solid rgba(255, 255, 255, 0.10);
    }
    .theme-liquid-glass .nextxbase-grid-container tbody tr:nth-child(even),
    .theme-onyx .nextxbase-grid-container tbody tr:nth-child(even),
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid-container tbody tr:nth-child(even),
.theme-onyx.control-theme-onyx.nextxbase-grid-container tbody tr:nth-child(even) {
        background: rgba(255, 255, 255, 0.08);
    }
    .theme-liquid-glass .nextxbase-grid-container tbody tr:hover,
    .theme-liquid-glass .nextxbase-grid-container tbody tr.nxb-row-sel,
    .theme-onyx .nextxbase-grid-container tbody tr:hover,
    .theme-onyx .nextxbase-grid-container tbody tr.nxb-row-sel,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid-container tbody tr:hover,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-grid-container tbody tr.nxb-row-sel,
.theme-onyx.control-theme-onyx.nextxbase-grid-container tbody tr:hover,
.theme-onyx.control-theme-onyx.nextxbase-grid-container tbody tr.nxb-row-sel {
        background: rgba(14, 165, 233, 0.28);
        color: #38bdf8;
        font-weight: 600;
    }
    /* THE CELL TAKES THE ROW'S INK. A `color` here beat the row's, and the
       row's is the APPLICATION'S: xbrowse.prg:3942 emits the browse's own
       colour model inline -- `color:#000000; background:#ffffff` -- and an
       inline style on the TR is inherited by the TD, while a rule matching
       the TD is not inherited at all. Inheritance loses to specificity, so
       the theme's near-white landed on the application's white row.

       MEASURED on full_showcase, --pixels, onyx: 37 cells at 1.04-1.05:1,
       rgb(248,250,252) on rgb(255,255,255) -- 'Acme Corp', 'New York',
       'Active', every value in the browse.

       IT BECAME VISIBLE WHEN 28fab873 REMOVED 245 !important, and that
       commit is right: a global theme outranking code inverts the hierarchy.
       What it left behind is the other half -- the row's GROUND went back to
       the application while the cell's INK stayed with the theme, and the
       two met. Ground and ink are one decision.

       Dropping the declaration rather than setting a colour: with no rule on
       the cell it inherits the row, which is the application's ink where the
       application set one and the theme's (line above) where it did not.
       Both cases correct, nothing invented, and ground rule 7's order kept --
       an argument outranks a theme. */
    .theme-liquid-glass .nextxbase-grid-container td,
    .theme-onyx .nextxbase-grid-container td,
.theme-onyx.control-theme-onyx.nextxbase-grid-container td {
        border-right: 1px solid rgba(255, 255, 255, 0.10);
    }
    .theme-liquid-glass .nxb-recsel,
    .theme-onyx .nxb-recsel,
.theme-liquid-glass.control-theme-liquid-glass.nxb-recsel,
.theme-onyx.control-theme-onyx.nxb-recsel {
        background: rgba(30, 41, 59, 0.65);
    }
    .theme-liquid-glass .nxb-grid-smart-footer,
    .theme-onyx .nxb-grid-smart-footer,
.theme-liquid-glass.control-theme-liquid-glass.nxb-grid-smart-footer,
.theme-onyx.control-theme-onyx.nxb-grid-smart-footer {
        background: rgba(30, 41, 59, 0.70);
        border-top: 1.5px solid rgba(255, 255, 255, 0.20);
        color: #e2e8f0;
    }

                    
    /* ---------------------------------------------------------------------- */
    /* THEME SWITCHER DOCK BUTTONS (Continuous Glass Squircles)               */
    /* ---------------------------------------------------------------------- */
    /* EVERY button in a frost window is a glass chip. It used to be only the
       two that name a theme (.control-theme-frost, .control-theme-onyx); the
       other seven fell through to the engine's default button, which is near
       black, and a row of black slabs on a pastel ground was the loudest
       thing on the page. Scoped to the theme, so no other theme's buttons
       move.

       SPECIFICITY IS THE MECHANISM AND IT IS LOAD-BEARING: this is (0,2,0),
       which beats .control-theme-<name> at (0,1,0); the coloured action
       buttons below are stated as .nextxbase-btn.btn-glass-* -- also (0,2,0)
       but LATER in the file -- so they keep their colour on the tie.
       Restating them here would have been a second copy to keep in sync. */
    .theme-frost .nextxbase-btn,
    .theme-frost .nextxbase-button,
.theme-frost.control-theme-frost.nextxbase-button {
        background: rgba(255, 255, 255, 0.72);
        background-image: linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(255,255,255,0.52) 100%);
        -webkit-backdrop-filter: blur(14px) saturate(165%);
        backdrop-filter: blur(14px) saturate(165%);
        border: 1px solid rgba(255, 255, 255, 0.92);
        border-radius: 12px;
        color: #22375c;
        font-weight: 600;
        box-shadow:
            0 8px 18px -10px rgba(30, 48, 90, 0.38),
            inset 0 1px 0 rgba(255, 255, 255, 0.95);
        transition: transform 0.12s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.12s;
    }
    .theme-frost .nextxbase-btn:hover,
    .theme-frost .nextxbase-button:hover,
.theme-frost.control-theme-frost.nextxbase-btn:hover,
.theme-frost.control-theme-frost.nextxbase-button:hover {
        transform: translateY(-1px);
        box-shadow:
            0 12px 24px -10px rgba(30, 48, 90, 0.42),
            inset 0 1px 0 rgba(255, 255, 255, 0.98);
    }
    /* The chip naming the theme currently on screen reads as chosen. */
    .theme-frost .nextxbase-btn.control-theme-frost {
        background-image: linear-gradient(180deg, #6fb2ff 0%, #2f7bea 100%);
        border-color: rgba(255, 255, 255, 0.75);
        color: #ffffff;
        box-shadow:
            0 10px 22px -10px rgba(47, 123, 234, 0.60),
            inset 0 1px 0 rgba(255, 255, 255, 0.70);
    }

    /* SCOPED TO ITS OWN THEMES. Unscoped, this rule painted the onyx chip
       near-black inside a FROST window and beat the frost chip rule on file
       order. A dock chip is painted by the theme on screen. */
    .theme-onyx .control-theme-onyx,
    .theme-liquid-glass .control-theme-onyx,
    .theme-onyx .nextxbase-btn.theme-onyx,
    .theme-liquid-glass .nextxbase-btn.theme-onyx,
.theme-onyx.control-theme-onyx.nextxbase-btn.theme-onyx,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-btn.theme-onyx {
        background: rgba(30, 41, 59, 0.65);
        border: 1.5px solid rgba(255, 255, 255, 0.45);
        border-radius: 999px;
        color: #ffffff;
        font-weight: 700;
        box-shadow: 0 4px 14px rgba(0,0,0,0.3), inset 0 1px 1px rgba(255,255,255,0.5);
        transition: transform 0.12s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.12s;
    }
    .theme-onyx .control-theme-onyx:hover,
    .theme-liquid-glass .control-theme-onyx:hover,
    .theme-onyx .nextxbase-btn.theme-onyx:hover,
    .theme-liquid-glass .nextxbase-btn.theme-onyx:hover,
.theme-onyx.control-theme-onyx.nextxbase-btn.theme-onyx:hover,
.theme-liquid-glass.control-theme-liquid-glass.nextxbase-btn.theme-onyx:hover {
        transform: translateY(-1px);
        box-shadow: 0 6px 20px rgba(0,0,0,0.45), inset 0 1px 1px rgba(255,255,255,0.6);
    }

    /* ---------------------------------------------------------------------- */
    /* TACTILE 3D JELLY ACTION BUTTONS (Specular Dome + Spring Physics)       */
    /* ---------------------------------------------------------------------- */
    /* Rounded rectangles, not capsules, and the glow is the button's own hue
       at low alpha -- the reference's New / Save / Cancel are soft 3D keys,
       not neon lozenges.

       SELECTORS ARE (0,2,0) ON PURPOSE. .theme-frost .nextxbase-btn above is
       (0,2,0) too; these come later in the file, so they win the tie and an
       action button keeps its colour inside a frost window. A bare
       .btn-glass-new would be (0,1,0) and would lose it. */
    .nextxbase-btn.btn-glass-new,
    .nextxbase-btn.btn-glass-save,
    .nextxbase-btn.btn-glass-cancel {
        border: 1px solid rgba(255, 255, 255, 0.55);
        border-radius: 12px;
        color: #ffffff;
        font-weight: 600;
        letter-spacing: 0.01em;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        transition: transform 0.1s, box-shadow 0.1s;
    }
    .nextxbase-btn.btn-glass-new {
        background: linear-gradient(180deg, #5cb6fb 0%, #1f7fd6 100%) !important;
        background-image: linear-gradient(180deg, #5cb6fb 0%, #1f7fd6 100%) !important;
        box-shadow:
            0 12px 22px -12px rgba(31, 127, 214, 0.75),
            inset 0 1px 0 rgba(255, 255, 255, 0.55),
            inset 0 -1px 0 rgba(0, 0, 0, 0.12) !important;
    }
    .nextxbase-btn.btn-glass-save {
        background: linear-gradient(180deg, #5fd39b 0%, #21a06a 100%) !important;
        background-image: linear-gradient(180deg, #5fd39b 0%, #21a06a 100%) !important;
        box-shadow:
            0 12px 22px -12px rgba(33, 160, 106, 0.75),
            inset 0 1px 0 rgba(255, 255, 255, 0.55),
            inset 0 -1px 0 rgba(0, 0, 0, 0.12) !important;
    }
    .nextxbase-btn.btn-glass-cancel {
        background: linear-gradient(180deg, #fa8189 0%, #e0454f 100%) !important;
        background-image: linear-gradient(180deg, #fa8189 0%, #e0454f 100%) !important;
        box-shadow:
            0 12px 22px -12px rgba(224, 69, 79, 0.75),
            inset 0 1px 0 rgba(255, 255, 255, 0.55),
            inset 0 -1px 0 rgba(0, 0, 0, 0.12) !important;
    }
    .nextxbase-btn.btn-glass-new:active,
    .nextxbase-btn.btn-glass-save:active,
    .nextxbase-btn.btn-glass-cancel:active {
        transform: translateY(1px) scale(0.985) !important;
    }
}

/* THE BROWSE'S PAGINATION FOOTER REVEALS ITSELF, and until 2026-09-04 nothing
   could reveal it at all. The footer was emitted with an INLINE
   `opacity:0; pointer-events:none` and the only thing that would have undone
   that was NextXbase.initGridHUD -- a function defined nowhere, so the
   footer has never been visible in any application or any theme. Three theme
   rules style it; nobody has ever seen them.

   IT IS CSS AND NOT JAVASCRIPT ON PURPOSE. A :hover rule needs no function to
   exist, cannot be shadowed by a later assignment, and works on the Windows 7
   floor -- which is also why the hidden state is `visibility` and not
   `pointer-events`: IE11 implements pointer-events for SVG only, so on the
   floor an invisible footer would still have swallowed clicks aimed at the
   rows underneath it. visibility removes the box from hit testing on every
   engine. The inline declarations are gone from the emitter, because an
   inline opacity outranks every rule here and no cascade could have reached
   it. */
.nxb-grid-smart-footer {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease;
}
.nextxbase-grid-container:hover .nxb-grid-smart-footer,
.nxb-grid-smart-footer:hover {
    opacity: 1;
    visibility: visible;
}

/* A CONTROL THE APPLICATION HAS DISABLED -- ONE RULE, FOR EVERY CLASS.

   The stamp that puts this attribute on the outermost tag is in the shared
   child-render loop (NXB_StampDisabled), so it reaches classes nobody here
   wrote. Before it, 187 renderers drew their own element and named no
   disabled state at all: Disable() moved the flag and the page was unchanged.

   IT IS A RULE RATHER THAN AN INLINE STYLE so a theme can reach it. An inline
   literal outranks every stylesheet and is exactly what audit_theme_blockers
   counts; how a disabled control looks is a theme's business.

   IT DIMS ON THE WINDOWS 7 FLOOR AND DOES NOT REFUSE THE CLICK. IE11
   implements pointer-events for SVG only. Not a regression -- the 75 classes
   that emit these two properties themselves have always had the same limit --
   and the durable answer is refusing the event on the server. Do not read
   this rule as a guarantee.

   A REAL <button>, <input> OR <select> DOES NOT DEPEND ON IT: the five core
   controls emit the disabled ATTRIBUTE, which refuses focus and submission on
   every engine. This is the visual half, and the whole answer for a div. */
[data-nxb-disabled='1'] {
    pointer-events: none;
    opacity: 0.5;
}

/* MsgRun / MsgWait / MsgMeter -- the busy overlay the live channel draws while
   the server works. It states BOTH its ground and its ink (section 0-E), and
   its flex has the -ms- form the IE11 floor reads, though that floor has no
   EventSource and so never receives the event that creates it. */
.nxb-busy {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 99998;
    background: rgba(15, 23, 42, 0.28);
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    -ms-flex-pack: center;
    justify-content: center;
    cursor: wait;
}

.nxb-busy-box {
    min-width: 280px;
    max-width: 70%;
    padding: 16px 20px;
    background: #ffffff;
    color: #1a1814;
    border: 1px solid #cbd5e1;
    border-radius: 8px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 14px;
}

.nxb-busy-title {
    font-weight: 600;
    margin-bottom: 6px;
}

.nxb-busy-bar {
    display: none;
    height: 8px;
    margin-top: 12px;
    background: #e2e8f0;
    border-radius: 4px;
    overflow: hidden;
}

.nxb-busy-fill {
    height: 100%;
    width: 0;
    background: #2563eb;
}

/* ===========================================================================
   TREEVIEW -- THE GUIDES, THE TOGGLE SLOT AND THE FOLDER GLYPH

   These are in the stylesheet and not inline because they CANNOT be written
   inline: a connecting line is a :before and a :after, and a style attribute
   has no pseudo-elements. That is also why the tree drew a detached elbow per
   child and never a spine -- the renderer emitted a FLAT list, where "is this
   the last child of its parent" is not a question CSS can ask. The markup is
   nested now and :last-child answers it.

   Every tree class name this engine emits had ZERO rules here until now, so a
   tree was styled entirely by inline literals and no theme could reach one.

   IE11 FLOOR: single-colon :before/:after, :last-child and rgba() are all
   IE9+. Nothing here uses grid, gap, var() or :has(), so the ie11 ratchet
   does not move.

   THE GUIDES ARE ANCHORED TO THE ROW, NOT TO THE <li>, AND THAT IS THE WHOLE
   OF THIS BLOCK'S DESIGN.  They used to hang off the <li> at a pinned 12px --
   "where a default row's vertical centre falls" -- with a note here saying the
   elbow could not be made to track the row without custom properties, which
   the IE11 floor forbids.  THAT NOTE WAS WRONG, and it was wrong in the
   expensive direction: it told the next reader not to look.  An absolutely
   positioned pseudo-element resolves its percentages against ITS OWN
   containing block, so putting the elbow on the NODE and asking for `top: 50%`
   is the row's middle by construction, at any row height, with no custom
   property and nothing for an application to keep in step.  `bottom: 50%` ends
   the last child's spine at the same place for the same reason.

   MEASURED IN CHROME ON Colegios' OWN PAGE, elbow against row centre:

       default 25px rows      -1.5px      ->   +0.5px
       rows at 40px           -10.5px     ->   +0.5px

   The 1.5px is not cosmetic arithmetic: TTREEVIEW draws its row `inline-flex`,
   so the row sits on a text baseline and starts 1.5px below the <li> that the
   old rules measured from.  The other three dialects draw it `flex` and were
   never offset -- so ONE tree in four met its own guides, which is the
   variance rather than the pixel count.  Anchoring to the row removes the
   question instead of answering it twice.  The residual +0.5px is the border's
   own width: `top: 50%` places the line's TOP edge at the middle.

   IE11 FLOOR: single-colon :before/:after, :last-child, `top`+`bottom` on one
   absolutely positioned box and percentage offsets are all IE9+.  No calc(),
   no custom property, no grid, no :has() -- the ie11 ratchet does not move.
   =========================================================================== */

.nxb-tree-kids {
    list-style: none;
    margin: 0;
    padding-left: 18px;
    position: relative;
}

.nxb-tree-li {
    list-style: none;
    position: relative;
}

.nxb-tree-kids > .nxb-tree-li {
    padding-left: 14px;
}

/* THE ROW IS THE POSITIONING CONTEXT FOR ITS OWN GUIDES.  Without this the
   elbow below would resolve `top: 50%` against the nearest positioned
   ancestor, which is whatever container the tree happens to sit in -- so the
   line would land somewhere in the middle of the window.  No z-index here, so
   no stacking context is created and nothing this engine paints changes order. */
.nxb-tree-node {
    position: relative;
}

/* THE SPINE BELOW THE ROW, and it is the <li> that draws it because it has to
   run past this row's whole subtree to reach the next sibling.  A LAST child
   has no next sibling, so it draws none at all -- which is what turns a column
   of disconnected ticks into a tree, and is the job the pinned `height: 12px`
   used to do from the wrong end. */
.nxb-tree-kids > .nxb-tree-li:before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    border-left: 1px solid #94a3b8;
}

.nxb-tree-kids > .nxb-tree-li:last-child:before {
    display: none;
}

/* THE SPINE ABOVE THE ROW, DOWN TO THE ROW'S OWN MIDDLE.  `bottom: 50%` is the
   middle of the ROW, whatever the row's height; the 6px above it doubles over
   the previous sibling's spine, which is the same 1px line in the same colour
   at the same x, and is what keeps the run unbroken across the 1.5px a
   baseline-aligned row sits below its <li>.  For the FIRST child it reaches up
   toward the parent's row, which is where a spine belongs. */
.nxb-tree-kids > .nxb-tree-li > .nxb-tree-node:after {
    content: "";
    position: absolute;
    left: -14px;
    top: -6px;
    bottom: 50%;
    border-left: 1px solid #94a3b8;
}

/* THE ELBOW, at the row's middle at any row height.  -14px is this list's own
   `padding-left` below, so the elbow starts exactly on the spine; 12 of those
   14 are drawn, and the 2px that are not are the gap before the caret. */
.nxb-tree-kids > .nxb-tree-li > .nxb-tree-node:before {
    content: "";
    position: absolute;
    left: -14px;
    top: 50%;
    width: 12px;
    border-top: 1px solid #94a3b8;
}

/* ===========================================================================
   AND THE SAME GUIDES AT THE ROOT.  T129.

   THE REFERENCE ASKS FOR THEM AND IT IS NOT CONDITIONAL:
   `ttreevie.prg:236` builds its window style with TVS_LINESATROOT as a flat
   literal in the list, reachable by no argument and no DATA default, and five
   of the reference's own .rc files declare SysTreeView32 the same way.  Every
   rule above keys on `.nxb-tree-kids`, which both renderers open only inside
   `IF nLevel > nPrev` -- so a NESTED row hung off a spine with an elbow into
   its label while its PARENT, one level up, floated with no guide of any kind,
   and a tree whose nodes are all roots had no lines anywhere.  One tree, two
   grammars.

   THE ROOT IS NOT THE NESTED CASE WITH A DIFFERENT SELECTOR, which is why this
   is its own block rather than a second class name on the same rules.  Three
   things differ and each is answered here:

     a root has NO PARENT ROW to reach up to.  The nested spine runs from 6px
     above the row to the row's middle; at the root that would hang off the top
     of the list.  So the FIRST root starts its spine AT its own middle
     (`top: 50%`) and the LAST ends at its own middle (`bottom: 50%`) -- and a
     LONE root is both, so the two overrides meet and it draws no spine at all,
     which is correct and needs no third rule.

     a root has NOTHING TO ITS LEFT for the elbow to cross.  The root list
     keeps `padding: 0` -- its indent is the application's, through LIST_PAD --
     and the 14px the elbow needs is put on the root <li>, exactly as the
     nested list puts it on its own.  Adding `nxb-tree-kids` to the root <ul>
     instead would have drawn the guides AND moved every tree 18px right as a
     side effect of a paint change.

     a root item's SUBTREE has to be crossed at the ROOT's x, and the row's own
     two pseudo-elements are already the elbow and the spine.  The nested list
     is itself positioned, so it draws that stretch -- one line, from the top of
     the subtree to its bottom, at the same -14px the elbow starts from.

   SO THE RUN BETWEEN TWO ROOT ROWS IS THREE PIECES THAT MEET BY CONSTRUCTION:
   the upper row's node spine from its middle to the node's bottom, the subtree
   (if any), and the next row's node spine from 6px above it to its middle.
   The 6px doubles over the gap a container may put between two rows, which is
   the same trick the nested spine uses and for the same reason.

   IE11 FLOOR: `:not()` with a simple selector, `:first-child`, `:last-child`,
   single-colon :before/:after and percentage offsets are all IE9+.  No
   calc(), no custom property, no grid, no :has() -- the ie11 ratchet does not
   move.
   =========================================================================== */

.nxb-tree-root > .nxb-tree-li {
    padding-left: 14px;
}

/* THE SPINE THROUGH THE ROW ITSELF.  Full node height by default; the first
   root starts at its own middle because there is nothing above it, the last
   ends at its own middle because there is nothing below it. */
.nxb-tree-root > .nxb-tree-li > .nxb-tree-node:after {
    content: "";
    position: absolute;
    left: -14px;
    top: -6px;
    bottom: 0;
    border-left: 1px solid #94a3b8;
}

.nxb-tree-root > .nxb-tree-li:first-child > .nxb-tree-node:after {
    top: 50%;
}

.nxb-tree-root > .nxb-tree-li:last-child > .nxb-tree-node:after {
    bottom: 50%;
}

/* THE SPINE ACROSS A ROOT ITEM'S SUBTREE, at the ROOT's x rather than the
   subtree's.  A LAST root has no next sibling to reach, so it draws none --
   which is the same question `:last-child` answers for a nested row. */
.nxb-tree-root > .nxb-tree-li:not(:last-child) > .nxb-tree-kids:before {
    content: "";
    position: absolute;
    left: -14px;
    top: 0;
    bottom: 0;
    border-left: 1px solid #94a3b8;
}

/* THE ELBOW, and every root gets one -- that is what TVS_LINESATROOT means. */
.nxb-tree-root > .nxb-tree-li > .nxb-tree-node:before {
    content: "";
    position: absolute;
    left: -14px;
    top: 50%;
    width: 12px;
    border-top: 1px solid #94a3b8;
}

/* the toggle is emitted for every node, leaf included, so that every label on
   a level starts at the same x */
.nxb-tree-toggle {
    display: inline-block;
    width: 14px;
    min-width: 14px;
    text-align: center;
    font-size: 10px;
    line-height: 1;
    color: #64748b;
}

.nxb-tree-icon {
    margin-right: 6px;
    font-size: 14px;
    color: #eab308;
}

/* a leaf is not a folder and must not be gold */
.nxb-tree-icon.bi-file-earmark {
    color: #94a3b8;
}

.nxb-tree-node:hover {
    background: rgba(148, 163, 184, 0.16);
}


/* ==========================================================================
   THE RENDER-FAILURE MARKER. NXB_ChildHtml catches a control that raised while
   drawing and puts an EMPTY div here in its place, carrying the class name and
   a title pointing at error.log. With no rule an empty block element is zero
   pixels high, so the diagnostic painted nothing and its own tooltip had no
   hover target -- a control that died came out indistinguishable from one the
   application never declared, which is the silence the marker exists to break.

   The rule was written in 9fc6e509 and removed in 0b2429df, a theme commit
   about the frost ground whose message does not mention it; 56 selectors went
   with it, 45 of them dead. Restored 2026-09-14. min-* is what gives the title
   something to hover over, so do not drop it for the border alone.
   ========================================================================== */
.nxb-render-failed {
    position: absolute;
    min-width: 24px;
    min-height: 24px;
    border: 1px dashed #c0392b;
    background: repeating-linear-gradient(45deg,
        rgba(192, 57, 43, 0.06), rgba(192, 57, 43, 0.06) 6px,
        transparent 6px, transparent 12px);
}


/* ==========================================================================
   RESTORED: RULES A THEME COMMIT REMOVED WHILE A COMPILED RENDERER KEPT
   EMITTING THE CLASS
   ==========================================================================
   0b2429df (2026-09-03) is titled for the frost theme's ground ramp and took
   56 class selectors out of this file with it. Most of that was correct --
   45 of them are emitted by nothing. These are the ones a renderer in the
   COMPILED set still puts on an element, so the class was a hook that styled
   nothing.

   WHAT IS DELIBERATELY NOT RESTORED, because a verbatim restore would put
   back two defects this project has already paid for:

   1. THE BARE `color` ON AN ELEMENT THAT PAINTS NO GROUND. .nxb-res-say and
      the group legend carried `color:#1a1814` and no background. Section 0-E:
      ground and ink are ONE decision, and inheritance loses to specificity --
      a class rule setting `color` defeats every theme at once, which is how
      .nextxbase-radio reached 1.00:1 black-on-black. They inherit now.
      .nxb-res-btn and .nxb-brwfb DO paint a ground, so their ink goes back
      WITH it, as a pair.

   2. `accent-color` ON THE SLIDER AND `object-fit` ON .nextxbase-ximage.
      Both are on audit_ie11_css's ratchet and neither renders on the shipped
      IE11 floor, so restoring them would raise a bar for no effect there.
      The ::-ms-* track rules below are what actually paint the slider on the
      floor and they are restored in full.

   AND .nextxbase-ximage IS NOT RESTORED AT ALL, which is a finding rather
   than an omission: its only COMPILED emitter (special_controls.prg) puts the
   class on a <div> that already sets width, height, overflow, background and
   a themeable border-radius inline, and the removed rule -- object-fit,
   max-width, max-height -- was written for an <img>. The other emitter is
   all_fwh_stubs.prg, which buildH64 names on no `call :CLASS` line. Restoring
   it would style the wrong element.
   ========================================================================== */

/* The resource-decor three ARE the customer's own dialog, not our shell:
   every static, group frame and button face a .rc template declares comes
   through them, and their inline style is GEOMETRY ONLY. The font is here so
   a resource static matches the native dialog font, and `white-space` so a
   caption carrying an embedded newline does not collapse onto one line. */
.nxb-res-say {
    font: 11px/1.2 "MS Sans Serif", Tahoma, sans-serif;
    white-space: pre-line;
    overflow: hidden;
}

.nxb-res-group {
    border: 1px solid #b9c6d8;
    border-radius: 3px;
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    pointer-events: none;
}

.nxb-res-group > legend {
    font: 11px/1.2 "MS Sans Serif", Tahoma, sans-serif;
    padding: 0 4px;
    margin-left: 6px;
}

.nxb-res-btn {
    font: 11px/1.2 "MS Sans Serif", Tahoma, sans-serif;
    background: #f4f5f7;
    color: #1a1814;
    border: 1px solid #b9c6d8;
    border-radius: 3px;
    cursor: default;
}

/* The browse fallback table -- six emitters in controls.prg. */
.nxb-brwfb {
    width: 100%;
    border-collapse: collapse;
    font: 12px/1.3 "Segoe UI", Tahoma, sans-serif;
    color: #1a1814;
    background: #ffffff;
    table-layout: fixed;
}

.nxb-brwfb th {
    background: #e8eef7;
    border: 1px solid #b9c6d8;
    font-weight: 600;
    text-align: center;
    padding: 2px 6px;
    white-space: pre-line;
    overflow: hidden;
}

.nxb-brwfb td {
    border: 1px solid #dde3ec;
    padding: 1px 6px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nxb-brwfb tbody tr:nth-child(even) td { background: #eef4ff; }

.nxb-brwfb-empty td,
.nxb-brwfb-more td {
    text-align: center;
    font-style: italic;
    color: #6b6257;
    background: #faf8f5;
}

/* <input type='range'>, all_fwh_func_stubs.prg. */
.nextxbase-slider {
    cursor: pointer;
    vertical-align: middle;
    box-sizing: border-box;
    padding: 0;
    margin: 0;
    border: 0;
    background: transparent;
}

.nextxbase-slider::-ms-track {
    height: 100%;
    border: 0;
    padding: 0;
    color: transparent;
    background: transparent;
}

.nextxbase-slider::-ms-fill-upper {
    background: #cbd5e1;
    border-radius: 3px;
}

.nextxbase-slider::-ms-thumb {
    margin-top: 0;
}

.nextxbase-metro-title {
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* ========================================================================== */
/* Developer Tools & Live REPL Diagnostics (Track K-1 / K-2)                  */
/* ========================================================================== */

.nxb-devtool-badge {
    position: fixed;
    bottom: 12px;
    right: 12px;
    z-index: 2147483640;
    background: #0f172a;
    color: #38bdf8;
    border: 1px solid #334155;
    font-family: 'Cascadia Code', Consolas, monospace;
    font-size: 12px;
    padding: 5px 12px;
    border-radius: 14px;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
    opacity: 0.9;
    user-select: none;
    transition: all 0.2s ease;
}
.nxb-devtool-badge:hover {
    background: #1e293b;
    border-color: #38bdf8;
    box-shadow: 0 4px 16px rgba(56,189,248,0.4);
    opacity: 1;
}

.nxb-devtool-panel {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 330px;
    z-index: 2147483645;
    background: #0f172a;
    color: #e2e8f0;
    font-family: 'Cascadia Code', Consolas, 'Segoe UI', monospace;
    font-size: 12px;
    display: none;
    flex-direction: column;
    border-top: 2px solid #38bdf8;
    box-shadow: 0 -6px 25px rgba(0,0,0,0.6);
}

.nxb-devtool-hdr {
    display: flex;
    align-items: center;
    background: #1e293b;
    border-bottom: 1px solid #334155;
    padding: 0 10px;
    height: 34px;
    flex-shrink: 0;
}
.nxb-devtool-title {
    font-weight: bold;
    color: #38bdf8;
    margin-right: 18px;
    font-size: 13px;
    white-space: nowrap;
}
.nxb-devtool-tabs {
    display: flex;
    gap: 4px;
    flex: 1;
}
.nxb-devtool-tab {
    padding: 6px 12px;
    cursor: pointer;
    color: #94a3b8;
    border-bottom: 2px solid transparent;
    user-select: none;
    border-radius: 4px 4px 0 0;
}
.nxb-devtool-tab:hover {
    color: #f8fafc;
    background: rgba(255,255,255,0.05);
}
.nxb-devtool-tab.active {
    color: #38bdf8;
    border-bottom-color: #38bdf8;
    background: rgba(56,189,248,0.1);
    font-weight: bold;
}
.nxb-devtool-actions {
    display: flex;
    gap: 6px;
    align-items: center;
}
.nxb-devtool-btn {
    background: #334155;
    color: #f8fafc;
    border: 1px solid #475569;
    padding: 3px 8px;
    border-radius: 3px;
    cursor: pointer;
    font-family: inherit;
    font-size: 11px;
}
.nxb-devtool-btn:hover {
    background: #475569;
    border-color: #38bdf8;
}
.nxb-devtool-btn.active {
    background: #0284c7;
    border-color: #38bdf8;
    color: #fff;
}
.nxb-devtool-btn.close {
    font-size: 16px;
    line-height: 12px;
    padding: 3px 7px;
}

.nxb-devtool-body {
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    background: #0b1120;
}

/* Inspector */
.nxb-devtool-inspector-bar {
    padding: 6px 10px;
    background: #1e293b;
    border-bottom: 1px solid #334155;
    display: flex;
    align-items: center;
    gap: 12px;
}
.nxb-devtool-hint {
    color: #64748b;
    font-size: 11px;
}
.nxb-devtool-inspector-split {
    flex: 1;
    display: flex;
    overflow: hidden;
}
.nxb-devtool-tree {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
    border-right: 1px solid #334155;
}
.nxb-tree-win {
    margin-bottom: 10px;
}
.nxb-tree-win-title {
    padding: 4px 8px;
    background: #1e293b;
    border-radius: 4px;
    cursor: pointer;
    color: #38bdf8;
}
.nxb-tree-win-title:hover {
    background: #334155;
}
.nxb-tree-win-title.selected {
    background: #0284c7;
    color: #fff;
}
.nxb-tree-ctls {
    padding-left: 18px;
    margin-top: 4px;
}
.nxb-tree-ctl {
    padding: 3px 6px;
    cursor: pointer;
    border-radius: 3px;
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}
.nxb-tree-ctl:hover {
    background: #1e293b;
    color: #38bdf8;
}
.nxb-tree-ctl.selected {
    background: #38bdf8;
    color: #0f172a;
    font-weight: bold;
}
.nxb-tree-id {
    color: #64748b;
    font-size: 11px;
}
.nxb-tree-ctl.selected .nxb-tree-id {
    color: #0f172a;
}
.nxb-tree-extra {
    color: #a5f3fc;
    font-size: 11px;
    margin-left: 6px;
}
.nxb-tree-ctl.selected .nxb-tree-extra {
    color: #042f2e;
}
.nxb-tree-badge-dis {
    background: #b91c1c;
    color: #fff;
    font-size: 9px;
    padding: 1px 4px;
    border-radius: 3px;
    font-weight: bold;
}

.nxb-devtool-props {
    width: 340px;
    overflow-y: auto;
    padding: 10px;
    background: #131b2e;
}
.nxb-props-title {
    font-weight: bold;
    color: #38bdf8;
    margin-bottom: 8px;
    border-bottom: 1px solid #334155;
    padding-bottom: 4px;
}
.nxb-props-actions {
    margin-top: 10px;
}

/* REPL */
.nxb-devtool-repl-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.nxb-devtool-repl-log {
    flex: 1;
    overflow-y: auto;
    padding: 10px;
    font-family: inherit;
    line-height: 1.5;
}
.nxb-repl-welcome {
    color: #64748b;
    margin-bottom: 8px;
    font-style: italic;
}
.nxb-repl-entry-cmd {
    color: #f8fafc;
    margin-top: 6px;
    font-weight: bold;
}
.nxb-repl-entry-res {
    color: #e2e8f0;
    margin-left: 12px;
    margin-bottom: 6px;
}
.nxb-repl-prompt {
    color: #38bdf8;
    font-weight: bold;
}
.nxb-repl-type-badge {
    display: inline-block;
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: bold;
    margin-right: 6px;
}
.type-c { background: #0369a1; color: #fff; }
.type-n { background: #15803d; color: #fff; }
.type-d { background: #b45309; color: #fff; }
.type-l { background: #6d28d9; color: #fff; }
.type-a { background: #047857; color: #fff; }
.type-h { background: #0e7490; color: #fff; }
.type-o { background: #4338ca; color: #fff; }
.type-u { background: #475569; color: #fff; }
.type-err { background: #b91c1c; color: #fff; }
.nxb-repl-val {
    color: #38bdf8;
}
.nxb-repl-err {
    color: #f87171;
}
.nxb-devtool-repl-bar {
    display: flex;
    align-items: center;
    background: #1e293b;
    border-top: 1px solid #334155;
    padding: 4px 8px;
    gap: 8px;
}
.nxb-repl-input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: #38bdf8;
    font-family: inherit;
    font-size: 13px;
}

/* Tracer */
.nxb-devtool-tracer-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.nxb-devtool-tracer-hdr {
    padding: 6px 10px;
    background: #1e293b;
    border-bottom: 1px solid #334155;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.nxb-devtool-tracer-scroll {
    flex: 1;
    overflow-y: auto;
    padding: 6px;
}
.nxb-tracer-badge {
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: bold;
}
.status-ok { background: #166534; color: #bbf7d0; }
.status-pending { background: #854d0e; color: #fef08a; }
.status-err { background: #991b1b; color: #fecaca; }
.nxb-tracer-payload {
    max-width: 250px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #64748b;
}

/* Stats */
.nxb-devtool-stats-wrap {
    flex: 1;
    overflow-y: auto;
    padding: 12px;
}
.nxb-stats-section {
    font-weight: bold;
    color: #38bdf8;
    margin-bottom: 8px;
    border-bottom: 1px solid #334155;
    padding-bottom: 4px;
}

/* Tables */
.nxb-devtool-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 11px;
}
.nxb-devtool-table th, .nxb-devtool-table td {
    border: 1px solid #334155;
    padding: 4px 8px;
    text-align: left;
}
.nxb-devtool-table th {
    background: #1e293b;
    color: #94a3b8;
}
.nxb-devtool-table td {
    background: rgba(0,0,0,0.2);
}
.nxb-devtool-empty {
    color: #64748b;
    padding: 12px;
    text-align: center;
    font-style: italic;
}

/* Highlighter Overlay */
.nxb-devtool-highlighter {
    position: fixed;
    pointer-events: none;
    z-index: 2147483646;
    border: 2px solid #38bdf8;
    background: rgba(56, 189, 248, 0.25);
    box-shadow: 0 0 10px rgba(56, 189, 248, 0.5);
    transition: all 0.05s ease-out;
}
.nxb-highlighter-tag {
    position: absolute;
    top: -22px;
    left: -2px;
    background: #38bdf8;
    color: #0f172a;
    font-family: 'Cascadia Code', Consolas, monospace;
    font-size: 10px;
    font-weight: bold;
    padding: 2px 6px;
    border-radius: 3px 3px 0 0;
    white-space: nowrap;
}

/* Profiler Subsystem (Track K-3) */
.nxb-profiler-metrics {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 12px;
}
.nxb-profiler-card {
    flex: 1 1 120px;
    background: #1e293b;
    border: 1px solid #334155;
    border-radius: 4px;
    padding: 8px 10px;
    box-sizing: border-box;
}
.nxb-profiler-card-title {
    font-size: 10px;
    color: #94a3b8;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 4px;
}
.nxb-profiler-card-val {
    font-size: 16px;
    font-weight: bold;
    color: #f8fafc;
    font-family: 'Cascadia Code', Consolas, monospace;
}
.nxb-profiler-heatmap {
    background: #1e293b;
    border: 1px solid #334155;
    border-radius: 4px;
    padding: 10px;
    margin-bottom: 12px;
}
.nxb-heatmap-row {
    display: flex;
    align-items: center;
    margin-bottom: 6px;
    font-size: 11px;
}
.nxb-heatmap-label {
    width: 80px;
    color: #94a3b8;
    font-family: 'Cascadia Code', Consolas, monospace;
}
.nxb-heatmap-track {
    flex: 1;
    height: 14px;
    background: #0f172a;
    border-radius: 2px;
    overflow: hidden;
    margin: 0 8px;
    position: relative;
}
.nxb-heatmap-bar {
    height: 100%;
    transition: width 0.3s ease;
}
.nxb-heatmap-val {
    width: 60px;
    text-align: right;
    color: #f8fafc;
    font-family: 'Cascadia Code', Consolas, monospace;
}

/* ========================================================================== */
/* Mobile Viewport Adaptive Sizing & Touch Gestures (Track G-2)               */
/* ========================================================================== */
.nextxbase-folder, .nextxbase-tab-container {
    touch-action: pan-y;
}

.nxb-ptr-indicator {
    position: fixed;
    top: -60px;
    left: 50%;
    margin-left: -22px;
    width: 44px;
    height: 44px;
    border-radius: 22px;
    background: #ffffff;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
    display: none;
    z-index: 999999;
    text-align: center;
    line-height: 44px;
    pointer-events: none;
    transition: top 0.2s ease;
}
.nxb-ptr-indicator.active {
    display: block;
}
.nxb-ptr-indicator.ready {
    background: #0078d4;
    color: #ffffff;
}
.nxb-ptr-indicator.refreshing {
    display: block;
    top: 20px;
}
.nxb-ptr-spinner {
    display: inline-block;
    width: 22px;
    height: 22px;
    margin-top: 10px;
    border: 3px solid rgba(0, 120, 212, 0.2);
    border-top-color: #0078d4;
    border-radius: 50%;
    animation: nxb-spin 0.8s linear infinite;
}
.nxb-ptr-indicator.ready .nxb-ptr-spinner {
    border-color: rgba(255, 255, 255, 0.3);
    border-top-color: #ffffff;
}
@keyframes nxb-spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.nxb-mobile-fs-btn {
    position: fixed;
    bottom: 10px;
    left: 10px;
    z-index: 999998;
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.28);
    background: rgba(15, 23, 42, 0.78);
    color: #f8fafc;
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    user-select: none;
    -webkit-user-select: none;
}
.nxb-mobile-fs-btn.is-active {
    background: rgba(13, 148, 136, 0.85);
    border-color: rgba(255, 255, 255, 0.45);
}
html.nxb-mobile-immersive .nextxbase-window.wnd-type-main > .nextxbase-slot-titlebar,
html.nxb-mobile-immersive .nextxbase-window.wnd-type-main > .nextxbase-slot-menubar,
html.nxb-mobile-immersive .nextxbase-window.wnd-type-main > .nextxbase-slot-toolbar,
html.nxb-mobile-immersive .nextxbase-window.wnd-type-main > .nextxbase-slot-footer {
    display: none !important;
}
