/*
   The shell's own stylesheet. Served as _content/Nxt.Atrium.Presentation.Blazor/css/shell.css and declared in
   the host's stylesheet list, which Program.cs preflights at startup (https://github.com/btsoons/Nxt/issues/2542) — a linked sheet the host cannot
   serve renders the whole surface unstyled, and the failure is otherwise silent.

   Every colour is a token. Most are --nxt-* from the shared palette (C3, the closed colour vocabulary);
   the --nxt-atrium-* block below declares a few of this product's own, and those DO carry a hex literal -
   at their declaration and nowhere else, which is what a token is for.
*/

/* ATRIUM'S OWN TOKENS. Everything else in this file is an --nxt-* from the shared palette, which lives
   upstream in btsoons/Nxt and reaches here only through a manual package publish. These are decisions
   about how THIS shell lays itself out and draws its own furniture, rather than shared brand values, so
   they are named --nxt-atrium-* to say plainly that they are not the palette's.

   NO COUNT HERE, because the list is directly below and a number beside it is a second place to keep true.
   This note has now been wrong about that number twice: it said "these two" when there was ONE token, the
   two being its CSS and XAML spellings, and the correction then said "two, now eleven" when the answer was
   one and ten. Both were arithmetic nobody had to do.

   --nxt-atrium-page-inset has a twin: Nxt.Atrium.Page.Inset in ShellTemplates.xaml. Two spellings of one
   number in two files is exactly the drift btsoons/Nxt.Atrium#272 FR-3 is about, so
   ThePageIsAPageOnBothRenderersTests reads both and compares rather than trusting whoever edits one to
   remember the other. */
:root {
    --nxt-atrium-page-inset: 12px;

    /* THE PAGE'S EDGE (btsoons/Nxt.Atrium#283), the twin of Nxt.Atrium.Page.Edge.* in ShellTemplates.xaml:
       a 1px border on the BOTTOM ONLY at a 12 radius, so the line sweeps upward at each end. See that file
       for why the colour is a local token rather than a shared one. */
    --nxt-atrium-page-edge-color: #9A9A9A;
    --nxt-atrium-page-edge-width: 1px;
    --nxt-atrium-page-radius: 12px;

    /* INSIDE the page - see Nxt.Atrium.Page.Padding in ShellTemplates.xaml. The inset separates the page
       from the window; this separates the content from the page. */
    --nxt-atrium-page-padding: 10px;

    /* THE RULES INSIDE THE PAGE - the band under the header and the one above the administration strip.
       See Nxt.Atrium.Page.Rule.Brush in ShellTemplates.xaml for why one token carries both, and why it is
       not the nearest shared border token. */
    --nxt-atrium-page-rule-color: #A9A9A9;

    /* The one line over the app picker - see Nxt.Atrium.Picker.Heading.Brush in
       ShellTemplates.xaml for where the colour comes from and why it is its own token. */
    --nxt-atrium-picker-heading-color: #5D5D5D;

    /* THE TILE FRAME (btsoons/Nxt.Atrium#283), the twin of Nxt.Atrium.Tile.Frame.* in ShellTemplates.xaml.
       A tile in the reference is TWO nested boxes and we drew only the inner one. The inner half already
       matched to the number, from .nxt-btn; the frame was absent on both hosts.

       #5D5D5D and not the reference's black: Bas's call on seeing both, "black is too hard". Still the
       reference's own colour - ControlColorC17, two steps below its C19 black, on the ramp our neutrals
       already come from. See Nxt.Atrium.Tile.Frame.Brush in ShellTemplates.xaml for why neither
       neighbouring step nor any shared border token fits. */
    --nxt-atrium-tile-frame-color: #5D5D5D;
    --nxt-atrium-tile-frame-width: 1px;
    --nxt-atrium-tile-frame-radius: 8px;
    /* #713: a tile's own button - the twin of Nxt.Atrium.Tile.Body.Radius. */
    --nxt-atrium-tile-body-radius: 5px;

    /* VIEW LOG'S MARKS (#515 D-4), the twins of Nxt.Atrium.Log.* in ShellTemplates.xaml, read and compared by
       ViewLogMarksAreTheSameOnBothRenderersTests. A highlight marks a word; a tint is the paler wash a level or
       source rule gives a whole line. Text on either is the fixed dark colour below, so it reads in any theme. */
    --nxt-atrium-log-highlight-yellow: #FFE27A;
    --nxt-atrium-log-highlight-blue: #BFDCFA;
    --nxt-atrium-log-highlight-green: #C6EBC5;
    --nxt-atrium-log-highlight-pink: #F6CCDD;
    --nxt-atrium-log-highlight-orange: #FDD2A8;
    --nxt-atrium-log-tint-yellow: #FFF6D1;
    --nxt-atrium-log-tint-blue: #EAF2FB;
    --nxt-atrium-log-tint-green: #E9F6E8;
    --nxt-atrium-log-tint-pink: #FCEBF2;
    --nxt-atrium-log-tint-orange: #FDEEDF;
    --nxt-atrium-log-find: #FFB347;
    --nxt-atrium-log-mark-text: #1F1F1F;
    /* The timeline's colour for a slice whose worst line is Critical (#515 D-6); Error and Warning take the semantic
       colours, which have no darker step for Critical. */
    --nxt-atrium-log-critical: #5E0B0B;

    /* FIELD SIZES (btsoons/Nxt.Atrium#589, row 9e), the twins of Nxt.Atrium.Field.* in ShellTemplates.xaml. A field
       a person types or picks in takes its column's width, or one of these; never width: auto on an empty input,
       and never a px width of its own. FieldsAreWideEnoughToTypeInTests compares the two spellings. Long is also
       the cap on a form's field column. */
    --nxt-atrium-field-short: 120px;
    --nxt-atrium-field-medium: 240px;
    --nxt-atrium-field-long: 460px;

    /* THE ADMINISTRATION PAGE (btsoons/Nxt.Atrium#574, row 10n.23): every tab is a page inset 24 top and bottom and 28
       at the sides, the twin of Nxt.Atrium.Admin.Page.Padding in ShellTemplates.xaml.
       AdministrationPageAndCardAreTheSameOnBothRenderersTests compares the two spellings. */
    --nxt-atrium-admin-page-padding: 24px 28px;
}

.nxt-shell {
    display: flex;
    flex-direction: column;
    height: 100vh;
    /* --nxt-bg-base, not --nxt-surface-standard: the latter is defined only in the OperationTester's own
       palette copy, and adding a fourth palette file to define it would put this host outside the token
       parity gates that watch the three that exist. */
    background: var(--nxt-bg-base);
    color: var(--nxt-text-primary);
}

/* THE CONTROL STYLES ARE NOT HERE, AND THAT IS THE POINT (btsoons/Nxt.Atrium#274).

   This sheet briefly carried its own rules for input, select, textarea and button, written on the
   premise that this host had no shared control styling and no focus treatment at all. THE PREMISE WAS
   FALSE, and the measurement behind it was of ONE FILE read as a statement about the HOST.

   ShellStylesheets.All links SIX sheets, and controls.css comes BEFORE this one:
       _content/Nxt.Presentation.Blazor/css/controls.css      <- shared, from the package
       _content/Nxt.Atrium.Presentation.Blazor/css/shell.css  <- this one

   controls.css styles every one of those elements, and gives the TEXT INPUTS, select, textarea and the
   check/radio pair their focus treatment - border-color var(--nxt-accent-primary) with the shared
   focus-ring shadow. The rules added here were (0,2,1) and loaded afterwards, so they WON: the accent
   border became a grey one and a second ring was drawn on top of the shared glow. The change removed
   half of the affordance it claimed to be adding, and it restyled eight unrelated buttons on the
   administration screen on the way past. Caught in review of btsoons/Nxt.Atrium#279.

   ONE GAP IS REAL AND IS NOT THIS SHEET'S TO FILL: controls.css has no `button:focus` rule of any kind,
   so a focused button on this host draws the browser's default outline. Removing the block above put
   that back exactly as it was before #279 - no regression - but it is a genuine hole in the SHARED
   control chrome, and the fix belongs upstream beside the input rule rather than here, where it would be
   this product overriding the shared sheet again. Measured 2026-09-20; recorded rather than papered
   over.

   So the rule for this file: style this product's own classes, never the bare element. The shared
   sheet owns the controls, and TheBlazorHostLinksTheSharedControlStyles is what keeps it linked. */

.nxt-shell__toolbar,
.nxt-shell__status {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 8px;
    background: var(--nxt-bg-panel);
}

/* THE CHROME TOOLBAR IS NOT IN THE PAGE, so it keeps the palette's hairline. #283 briefly gave it the
   in-page rule colour and gave the in-page band nothing - the two were swapped on this host only, which is
   the very defect the story was opened to fix. The twin is ShellView.xaml's Padding="8,6" Border. */
.nxt-shell__toolbar { border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-shell__status  { border-top: 1px solid var(--nxt-border-primary); font-size: 12px; }

.nxt-shell__status-caption { color: var(--nxt-text-secondary); }

/* Which build is running, and which app is open (btsoons/Nxt.Atrium#11, map row 1j) — the twin of the two
   docked TextBlocks in ShellView.xaml. white-space: nowrap so a narrow window wraps the MESSAGE rather than
   splitting a version number down the middle. */
.nxt-shell__status-version { color: var(--nxt-text-secondary); margin-right: 8px; white-space: nowrap; }
.nxt-shell__status-version + .nxt-shell__status-caption { margin-left: 8px; }

.nxt-shell__toolbar-spacer { flex: 1 1 auto; }

.nxt-shell__body { display: flex; flex: 1 1 auto; min-height: 0; }

.nxt-shell__nav {
    width: 200px;
    flex: 0 0 auto;
    padding: 6px;
    background: var(--nxt-bg-sidebar);
    border-right: 1px solid var(--nxt-border-primary);
    overflow-y: auto;
}

/* THE PAGE (btsoons/Nxt.Atrium#272 FR-1), the twin of the Border in ShellView.xaml. The window is a
   SURFACE and the content is a PAGE on it: the margin lets .nxt-shell's own --nxt-bg-base show through on
   all four sides, so what is content is separated from what is chrome without anybody explaining it.

   min-width/min-height 0 are what let it SHRINK inside the flex row and column - without them the margin
   is added to an item that refuses to be smaller than its content, and the inset disappears at exactly the
   window sizes FR's acceptance criterion is about. */
.nxt-shell__content {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    overflow: auto;
    margin: var(--nxt-atrium-page-inset);
    padding: var(--nxt-atrium-page-padding);
    background: var(--nxt-bg-panel);
    border: 0;
    border-bottom: var(--nxt-atrium-page-edge-width) solid var(--nxt-atrium-page-edge-color);
    border-radius: var(--nxt-atrium-page-radius);
}

.nxt-shell__entry {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 4px 8px;
    margin: 2px 0;
    background: transparent;
    color: inherit;
    border: 1px solid transparent;
    border-radius: 3px;
    cursor: pointer;
    text-align: left;
    font: inherit;
}

.nxt-shell__entry:hover           { background: var(--nxt-btn-hover); }
.nxt-shell__entry--current        { font-weight: bold; }
.nxt-shell__toolbar .nxt-shell__entry { width: auto; }
.nxt-shell__status  .nxt-shell__entry { width: auto; }

.nxt-shell__entry-icon { width: 14px; height: 14px; flex: 0 0 auto; }

/* THE HOME SCREEN IS THE SHELL CARD (btsoons/Nxt.Atrium#11 FR-001). Padding "12 10 12 0" is the reference's
   ApplicationShell region from doc/ui/canvas/Shell.dc.html, and the base background is the GROUND the white
   card sits on — without it the card is a hairline rectangle on a field of its own colour, which is the
   reason SignInView carries the same token. */
/* WHITE, and it used to be --nxt-bg-base. That ground existed to give the CARD something to sit on; with
   the card gone (btsoons/Nxt.Atrium#283, which reverses #11 FR-001 - see ShellHomeView.xaml) the reason
   goes with it. */
.nxt-shell__home {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 10px 12px 0;
    background: var(--nxt-bg-panel);
}

/* One centred line with a rule under it - the twin of the TextBlock and Border in ShellHomeView.xaml. The
   rule is this element's own border rather than a second element: the same line in one fewer box. The WPF
   twin needs a separate Border because a DockPanel has no such shorthand. */
.nxt-shell__picker-heading {
    margin: 4px 0 10px 0;
    padding-bottom: 10px;
    font-family: var(--nxt-font-figure);
    font-style: italic;
    font-weight: 600;
    font-size: 22px;
    text-align: center;
    color: var(--nxt-atrium-picker-heading-color);
    border-bottom: 1px solid var(--nxt-border-primary);
}

/* The picker scrolls; the administration strip below it does not. Between them that is "the strip is at the
   bottom of the card" (FR-005), which the WPF twin reaches with a DockPanel. */
.nxt-shell__picker { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px 0; }

/* No gap: the tiles carry their own margin, which is the reference's arrangement and the one the WPF twin
   reaches with Margin="10". A gap AND a margin would be two spacings for one gutter. */
.nxt-shell__tiles { display: flex; flex-wrap: wrap; justify-content: center; }

/* GEOMETRY (btsoons/Nxt.Atrium#713), the twin of AppTileView.xaml: 160 wide, its own button a fixed 180 high so a row
   of tiles is level whatever each one says, and its sentences under the frame. Deliberately NOT the admin tile's
   geometry below (125x125): the difference is what tells the operator at a glance that the strip is a different
   kind of thing from the apps (#2747). */
.nxt-shell__tile-slot { width: 160px; margin: 10px; display: flex; flex-direction: column; }

.nxt-shell__tile-frame {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    background: var(--nxt-bg-panel);
    border: var(--nxt-atrium-tile-frame-width) solid var(--nxt-atrium-tile-frame-color);
    border-radius: var(--nxt-atrium-tile-frame-radius);
    position: relative;
}
/* The edge says two things, and each is also said otherwise: the Open badge, the refusal under the tile. An
   outline rather than the border, so the tile does not move by a pixel - the twin of TileEdge on AppTileView.xaml. */
.nxt-shell__tile-frame--problem { outline: 1px solid var(--nxt-semantic-error); outline-offset: -1px; }
.nxt-shell__tile-frame--current { outline: 2px solid var(--nxt-accent-primary); outline-offset: -1px; }

/* THE FOOT (#713), the twin of SettingsFoot and EmptyFoot on AppTileView.xaml: a hairline, then 36 high and edge to
   edge, its lower corners the frame's radius less its edge. The frame's padding stops at the foot. */
.nxt-shell__tile-foot {
    height: 36px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0;
    padding: 0;
    border: none;
    border-top: 1px solid var(--nxt-border-primary);
    border-radius: 0 0 calc(var(--nxt-atrium-tile-frame-radius) - 1px) calc(var(--nxt-atrium-tile-frame-radius) - 1px);
    background: var(--nxt-bg-panel);
    color: var(--nxt-text-primary);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
}
.nxt-shell__tile-foot:hover   { background: var(--nxt-surface-standard); }
.nxt-shell__tile-foot:active  { background: var(--nxt-btn-pressed); }
.nxt-shell__tile-foot:focus-visible { outline: 2px solid var(--nxt-accent-focus-ring); outline-offset: -2px; }
.nxt-shell__tile-foot--empty  { background: var(--nxt-surface-standard); cursor: default; }
.nxt-shell__tile-foot-icon    { width: 14px; height: 14px; }

.nxt-shell__tile {
    width: 100%;
    height: 180px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding: 10px 8px 8px 8px;
    color: inherit;
    cursor: pointer;
    font: inherit;
}
/* FLAT, where the shared .nxt-btn paints a gradient - the twin of Nxt.Atrium.Tile.BodyTemplate (#713). The press step
   stays the shared button's, which is why the hover does not apply while pressed. */
.nxt-btn.nxt-shell__tile {
    background: var(--nxt-surface-standard);
    border: 1px solid var(--nxt-border-primary);
    border-radius: var(--nxt-atrium-tile-body-radius);
}
.nxt-btn.nxt-shell__tile:hover:not(:active) { background: var(--nxt-btn-hover); }

.nxt-shell__tile-caption {
    font-size: 14px;
    font-weight: 600;
    line-height: 17px;
    text-align: center;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.nxt-shell__tile-state {
    margin-top: 2px;
    font-family: var(--nxt-font-mono);
    font-size: 10px;
    text-transform: uppercase;
    color: var(--nxt-text-secondary);
}

/* THE GLYPH SAYS WHETHER THE APP IS HERE (btsoons/Nxt.Atrium#275 FR-3): the accent when this station has it, muted
   with a download mark when a click would install it first. COLOUR IS NOT THE ONLY SIGNAL: the mark and the hint
   under the tile say it too. WHICH STATE IT IS comes from AppTileViewModel.NeedsInstalling - FR-4. */
.nxt-shell__tile-glyph     { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; position: relative; }
.nxt-shell__tile-icon      { width: 64px; height: 64px; color: var(--nxt-accent-primary); }
.nxt-shell__tile-state + .nxt-shell__tile-glyph .nxt-shell__tile-icon { width: 56px; height: 56px; }
.nxt-shell__tile--uninstalled .nxt-shell__tile-icon { color: var(--nxt-text-muted); }
.nxt-shell__tile-download {
    position: absolute;
    right: -10px;
    bottom: calc(50% - 36px);
    width: 24px;
    height: 24px;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--nxt-bg-panel);
    border: 1px solid var(--nxt-border-control);
    color: var(--nxt-text-secondary);
}
.nxt-shell__tile-download-icon { width: 14px; height: 14px; }
.nxt-shell__tile-version-room  { flex: 0 0 18px; }
.nxt-shell__tile-body          { position: relative; margin: 8px; }

/* THE VERSION ROW, over the button rather than inside it, so the restart icon never opens the app. Only the icon
   takes the pointer; a click anywhere else in the row falls through to the button. */
.nxt-shell__tile-version-row {
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    pointer-events: none;
}
.nxt-shell__tile-version { font-family: var(--nxt-font-mono); font-size: 11.5px; color: var(--nxt-text-secondary); }
.nxt-shell__tile-badge {
    margin-left: 2px;
    padding: 0 5px 1px 5px;
    border-radius: 3px;
    font-size: 10.5px;
    font-weight: 600;
    color: var(--nxt-accent-primary);
    background: var(--nxt-accent-secondary-soft);
}
/* #579: a restart sentence is this icon; the sentence is its title and its aria-label. */
.nxt-shell__tile-restart      { display: inline-flex; color: var(--nxt-text-secondary); cursor: help; pointer-events: auto; }
.nxt-shell__tile-restart-icon { width: 14px; height: 14px; }

/* UNDER THE FRAME, outside both buttons (#713). */
.nxt-shell__tile-lines { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; text-align: center; }
.nxt-shell__tile-lines:not(:has(> *)) { display: none; }

/* #2581 FR-3: what one click will do, in words, BEFORE the click. The reference platform greys the tile
   out and says nothing at all, which is the affordance this replaces. */
.nxt-shell__tile-hint      { font-size: 12px; text-align: center; color: var(--nxt-text-secondary); }

/* ONE indicator, on the tile that was clicked — never this AND a full-window overlay. */
.nxt-shell__tile-progress  { display: block; width: 100%; }

.nxt-shell__tile-progress-bar {
    display: block;
    height: 4px;
    border-radius: 2px;
    background: var(--nxt-accent-primary);
    animation: nxt-shell-tile-progress 1.2s ease-in-out infinite;
}

.nxt-shell__tile-progress-text {
    display: block;
    margin-top: 4px;
    font-size: 12px;
    text-align: center;
    color: var(--nxt-text-secondary);
}

.nxt-shell__tile-problem {
    display: flex;
    gap: 6px;
    justify-content: center;
    text-align: left;
    font-size: 12px;
    color: var(--nxt-semantic-error-strong);
}
.nxt-shell__tile-problem-icon { width: 14px; height: 14px; flex: 0 0 auto; margin-top: 1px; }

/* #599 FR-5(e): a date that stops this version is text to be read, never behind the restart icon. */
.nxt-shell__tile-due { font-size: 12px; font-weight: 600; color: var(--nxt-semantic-warning-strong); }

/* #392 FR-6: the update button, outside the button the tile is. */
.nxt-shell__tile-update-button { align-self: center; display: inline-flex; align-items: center; gap: 6px; }
.nxt-shell__tile-update-icon   { width: 14px; height: 14px; }

@keyframes nxt-shell-tile-progress {
    0%   { transform: scaleX(0.15); transform-origin: left; }
    50%  { transform: scaleX(1);    transform-origin: left; }
    100% { transform: scaleX(0.15); transform-origin: right; }
}

/* THE NXT MARK AND ITS MENU (btsoons/Nxt.Atrium#11 FR-010, map row 1i) — the twin of the logo button and
   its ContextMenu in ShellView.xaml. position: relative on the wrapper is what the absolutely-positioned
   item list hangs from, so the menu drops under the mark instead of at the corner of the page. */
.nxt-shell__logo-menu { position: relative; display: inline-flex; }

.nxt-shell__logo {
    display: inline-flex;
    align-items: center;
    padding: 4px;
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
}

.nxt-shell__logo:hover { background: var(--nxt-btn-hover); }

.nxt-shell__logo-menu-items {
    position: absolute;
    top: 100%;
    right: 0;
    z-index: 20;
    min-width: 148px;
    padding: 3px 0;
    background: var(--nxt-bg-panel);
    border: 1px solid var(--nxt-border-primary);
    box-shadow: 0 4px 12px rgba(0, 0, 0, .12);
}

.nxt-shell__logo-menu-item {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 5px 22px 5px 8px;
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    text-align: left;
    font: inherit;
}

.nxt-shell__logo-menu-item:hover { background: var(--nxt-btn-hover); }
.nxt-shell__logo-menu-rule       { height: 1px; margin: 3px 0; background: var(--nxt-border-row); }

/* ABOUT (btsoons/Nxt.Atrium#11 FR-010) — the twin of the panel in ShellView.xaml. */
.nxt-shell__about {
    align-self: center;
    min-width: 320px;
    margin: 16px;
    padding: 16px;
    background: var(--nxt-bg-panel);
    border: 1px solid var(--nxt-border-primary);
    border-radius: var(--nxt-corner-radius);
}

.nxt-shell__about-head  { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.nxt-shell__about-mark  { width: 28px; height: 29px; }
.nxt-shell__about-title { margin: 0; font-size: 18px; }
.nxt-shell__about-body  { margin: 0; color: var(--nxt-text-secondary); }

.nxt-shell__about-close {
    display: block;
    margin: 12px 0 0 auto;
    padding: 4px 12px;
    background: var(--nxt-bg-panel);
    color: inherit;
    border: 1px solid var(--nxt-border-primary);
    cursor: pointer;
    font: inherit;
}

.nxt-shell__about-close:hover { background: var(--nxt-btn-hover); }

/* THE ADMINISTRATION STRIP (btsoons/Nxt.Atrium#11 FR-005). The numbers are the reference's
   ToolMainSelectionView Grid.Row=3, read out of doc/ui/canvas/canvas.json's 'position' note rather than
   chosen here: a 3px top rule, CornerRadius "5 5 5 0", an inset panel at "3 1 2 2", MinHeight 75. Their WPF
   twins are in Controls/AdministrationStripView.xaml, and the two are meant to be read side by side.

   There is no rule for the EMPTY strip, deliberately: it does not render (FR-008). */
/* A rule at BOTH ends, and a radius on all four corners - see AdministrationStripView.xaml for why the
   flipped copy is there and why the old "5px 5px 5px 0" could not stay. */
.nxt-shell__admin {
    border-top: 3px solid var(--nxt-atrium-page-rule-color);
    border-bottom: 3px solid var(--nxt-atrium-page-rule-color);
    border-radius: 5px;
    padding: 1px 0;
}

.nxt-shell__admin-inset {
    margin: 1px 2px 1px 3px;
    border-radius: 5px;
    min-height: 75px;
    background: var(--nxt-bg-sidebar);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}

/* #713: the word up the strip's left edge, with a hairline after it - the twin of AdministrationEyebrow. */
.nxt-shell__admin-eyebrow {
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 6px;
    padding: 0 6px;
    /* The left edge of the box, which is its right once the word is turned to read upwards. */
    border-left: 1px solid var(--nxt-border-primary);
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-family: var(--nxt-font-mono);
    font-size: 10.5px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--nxt-text-secondary);
}

/* The reference's ADMIN tile, and deliberately not the app tile above it: 125x125 against the app's 160 by 180, an
   11px caption against 14, a 44px icon against 64. The difference is what says at a glance that this row is a different
   kind of thing from the apps (#2747). The frame takes what the tile used to carry, so the strip's height and the
   tile's footprint are unchanged. */
.nxt-shell__admin-tile-frame {
    width: 125px;
    height: 125px;
    margin: 7px;
    padding: 6px;
    box-sizing: border-box;
    background: var(--nxt-bg-panel);
    border: var(--nxt-atrium-tile-frame-width) solid var(--nxt-atrium-tile-frame-color);
    border-radius: var(--nxt-atrium-tile-frame-radius);
}

.nxt-shell__admin-tile {
    width: 100%;
    height: 100%;
    padding: 3px;
    /* Centred, the WPF Button's own default for its content - so the caption and glyph sit as a pair in
       the middle of the tile rather than at its head. */
    justify-content: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* The face, border and radius are .nxt-btn.nxt-shell__admin-tile's below, each the twin of a value on the WPF
       strip's button: the two hosts drew this tile differently while each described it in its own words
       (btsoons/Nxt.Atrium#272 FR-4, found in review of #279). */
    color: inherit;
    cursor: pointer;
    font: inherit;
}

/* The hover face is this sheet's because .nxt-btn declares NO :hover at all - only .nxt-btn--primary does. */
/* FLAT, as the app tile's body is (#713) - the twin of Nxt.Atrium.Tile.BodyTemplate on the WPF strip. */
.nxt-btn.nxt-shell__admin-tile:not(:disabled) {
    background: var(--nxt-surface-standard);
    border: 1px solid var(--nxt-border-primary);
    border-radius: var(--nxt-atrium-tile-body-radius);
}
/* :not(:disabled) on both: a tile whose command is running is disabled, and its look is the shared button's (Nora on #721). */
.nxt-btn.nxt-shell__admin-tile:hover:not(:active):not(:disabled) { background: var(--nxt-btn-hover); }
.nxt-btn.nxt-shell__admin-tile--current { border: 2px solid var(--nxt-accent-primary); }
.nxt-shell__admin-tile-caption        { font-size: 11px; font-weight: 600; line-height: 14px; text-align: center; }

/* 3px, and NOT margin-top:auto. Auto pushed the glyph to the foot of the tile, which is what the
   reference does and what this host did alone for as long as its WPF twin centred the pair. Bas set the
   number by looking at both: "3 pixels maybe". See AdministrationStripView.xaml for the whole account. */
.nxt-shell__admin-tile-icon           { width: 44px; height: 44px; margin-top: 3px; }

.nxt-shell__empty          { max-width: 520px; margin: 24px 0; }
.nxt-shell__empty-icon     { width: 32px; height: 32px; color: var(--nxt-text-muted); }
.nxt-shell__empty-title    { margin: 8px 0 4px 0; }
.nxt-shell__empty-body     { margin: 0 0 8px 0; color: var(--nxt-text-secondary); }
.nxt-shell__empty-suggestion { margin: 0; color: var(--nxt-text-secondary); }

/* THE NEEDS-ATTENTION PANEL (#713), the twin of ShellIssueStripView.xaml: one outlined Warning line that opens to a row
   per app, shown only to whoever sees the Administration strip. */
.nxt-shell__issues {
    margin-bottom: 12px;
    padding: 8px 12px;
    border: 1px solid var(--nxt-semantic-warning);
    border-radius: 5px;
    background: var(--nxt-bg-panel);
}
.nxt-shell__issues-line    { display: flex; align-items: center; gap: 10px; min-width: 0; }
.nxt-shell__issues-icon    { width: 16px; height: 16px; flex: 0 0 auto; color: var(--nxt-semantic-warning); }
.nxt-shell__issues-summary { font-weight: 600; color: var(--nxt-semantic-warning-strong); white-space: nowrap; }
.nxt-shell__issues-names   {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    color: var(--nxt-text-secondary);
}
.nxt-shell__issues-rows    { margin-top: 8px; }
.nxt-shell__issue          { padding: 8px 0; border-top: 1px solid var(--nxt-border-primary); }
.nxt-shell__issue-head     { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.nxt-shell__issue-subject  { font-size: 14px; font-weight: 600; }
.nxt-shell__issue-identity { font-family: var(--nxt-font-mono); font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-shell__issue-reason   { margin-top: 4px; font-size: 13.5px; }
.nxt-shell__issue-path     { display: flex; align-items: center; gap: 8px; margin-top: 4px; min-width: 0; }
/* Trimmed at the end, the whole path in its title: CSS has no middle trim, and neither has the WPF twin. */
.nxt-shell__issue-origin   {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--nxt-font-mono);
    font-size: 12px;
    color: var(--nxt-text-secondary);
}

/* THE GHOST BUTTON (#713), the twin of Nxt.Atrium.GhostButton: words and a glyph with no face. */
.nxt-shell__ghost-button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    min-height: 26px;
    padding: 3px 8px;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--nxt-text-primary);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}
.nxt-shell__ghost-button:hover:not(:active) { background: var(--nxt-surface-standard); }
.nxt-shell__ghost-button:active             { background: var(--nxt-btn-pressed); }
.nxt-shell__ghost-button:focus-visible      { outline: 2px solid var(--nxt-accent-focus-ring); outline-offset: 1px; }
.nxt-shell__ghost-button-icon               { width: 14px; height: 14px; }

/* THE ATTENTION MARK (#713), the twin of AttentionMark on AppTileView.xaml: amber with a white ring, at the frame's top
   left so it never meets the caption. */
.nxt-shell__tile-attention {
    position: absolute;
    top: -6px;
    left: -6px;
    width: 22px;
    height: 22px;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--nxt-bg-panel);
    border-radius: 50%;
    background: var(--nxt-semantic-warning);
    color: var(--nxt-text-on-accent);
}
.nxt-shell__tile-attention-icon { width: 12px; height: 12px; }

.nxt-shell__refusal {
    margin: 16px;
    padding: 12px;
    border: 1px solid var(--nxt-semantic-error);
    border-radius: 3px;
    background: var(--nxt-banner-error-bg);
    color: var(--nxt-banner-error-text);
}

/* #306: something the operator just did has worked. Neutral, because it is not a problem. */
.nxt-shell__notice {
    margin: 16px;
    padding: 12px;
    border: 1px solid var(--nxt-border-primary);
    border-radius: 3px;
    background: var(--nxt-bg-panel);
    color: var(--nxt-text-primary);
}

.nxt-shell__surface-error { margin: 16px; color: var(--nxt-semantic-error); }

.nxt-shell__busy {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--nxt-overlay-scrim);
    color: var(--nxt-text-on-accent);
    font-size: 16px;
}

/* ══ The house card (issue 10 FR-001; on this renderer by issue 35) ═══════════════════════════════
   The twin of Nxt.Atrium.Presentation.Wpf/Themes/CardTemplates.xaml, and the geometry is that file's
   geometry rather than a second opinion: the panel is 12, its header 80 tall and rounded 11 11 0 0 so the
   header's corners sit inside the panel's, and the footer strip is 30. CardSurfaceTests compares the four
   numbers across the two renderers, so neither can be tuned alone.

   `overflow: hidden` is WPF's ClipToBounds — the header's square lower corners would otherwise paint over
   the panel's radius.

   The header is filled with the shell gradient, which is why Card.razor hands the mark the REVERSED pair;
   the comment there says why both weights take the same colour. */

.nxt-card {
    display: flex;
    flex-direction: column;
    width: 375px;
    max-width: 100%;
    min-height: 475px;
    background: var(--nxt-bg-panel);
    border: var(--nxt-border-thickness) solid var(--nxt-border-primary);
    border-radius: 12px;
    overflow: hidden;
}

.nxt-card__header {
    flex: 0 0 80px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: 11px 11px 0 0;
    background: linear-gradient(to bottom, var(--nxt-chrome-shell-start), var(--nxt-chrome-shell-end));
    color: var(--nxt-text-on-accent);
}

.nxt-card__brand   { display: flex; align-items: center; gap: 11px; }
.nxt-card__mark    { flex: 0 0 auto; }
.nxt-card__product { font-size: 20px; font-weight: bold; }

/* Italic, as the reference's F0 caption is. The face is the serif variable: the reference's Times New Roman
   became --nxt-font-figure (Bas, 2026-10-04, 10n.25), a design token from the shared palette.css. */
.nxt-card__caption {
    margin-top: 1px;
    font-family: var(--nxt-font-figure);
    font-style: italic;
    font-size: 18px;
}

/* A column, so a consumer can push a block to the foot of the body with `margin-top: auto` — which is
   what the WPF twin's `*` spacer row does. 15 left and right is the WPF ContentPresenter's own inset. */
.nxt-card__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    padding: 0 15px;
}

.nxt-card__footer {
    flex: 0 0 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 15px;
}

/* A footer with a link on the left and the build on the right (#653). The version pushes itself right, so it is on the
   right whether or not a link is beside it, as the WPF twin docks it. */
.nxt-card__footer-row { display: flex; align-items: center; width: 100%; }

/* The station's name under the header (#653, map row 2e.2), and the build in the footer: mono, because both are
   identifiers a person reads back to support. */
.nxt-card__chip {
    align-self: flex-end;
    margin-top: 12px;
    padding: 4px 7px;
    border-radius: 3px;
    background: var(--nxt-surface-standard);
    font-family: var(--nxt-font-mono);
    font-size: 12px;
    color: var(--nxt-text-heading);
}

.nxt-card__version { margin-left: auto; font-family: var(--nxt-font-mono); font-size: 11px; color: var(--nxt-text-muted); }

/* A MESSAGE ON A CARD IS OUTLINED, NEVER FILLED (issue 10 FR-006). The reference states every one of them
   in a bordered box with 8 padding and the semantic colour on the border AND the text; the radius is
   whatever --nxt-corner-radius holds, which is the token's business and not this file's. A
   filled banner at 375 wide swallows the card — which is what the `--nxt-banner-*-bg` fills that stood
   here until issue 35 did. CardSurfaceTests fails on a background returning to any of these rules. */
.nxt-card__message {
    padding: 8px;
    border: var(--nxt-border-thickness) solid var(--nxt-border-primary);
    border-radius: var(--nxt-corner-radius);
}

.nxt-card__message--warning { border-color: var(--nxt-semantic-warning); color: var(--nxt-semantic-warning); }
.nxt-card__message--error   { border-color: var(--nxt-semantic-error);   color: var(--nxt-semantic-error); }

/* ══ Sign in and the forced password change (https://github.com/btsoons/Nxt/issues/2577), on the card ═══
   The card is the chrome; what is left here is where this surface's own content sits inside it. The
   buttons and inputs are the shared `.nxt-btn` / element rules — nothing here re-declares a selector
   controls.css owns.

   THE GROUND, AND IT IS NOT WHITE. The card is white, and with nothing behind it the host's own white came
   through and the card was a hairline rectangle on a field of the same colour. Both identity stages carry
   the same token, exactly as their WPF twins do.

   `margin: auto` on the card and NOT `align-items: center` on the box: a centred flex item whose content
   overflows loses its top edge to a scroll container that cannot reach it, and the store notice on a
   bootstrap station is five lines. */

.nxt-signin {
    display: flex;
    padding: 24px;
    overflow: auto;
    height: 100%;
    background: var(--nxt-bg-base);
}

.nxt-signin .nxt-card { margin: auto; }

/* A fact about the STORE, above the form it explains — because when the form is withheld that sentence is
   the reason there are no boxes below it. */
.nxt-signin__notice { margin-top: 14px; }

/* Whose password this is, and the rule stated before it can be broken. Both above the form they govern. */
.nxt-signin__intro { margin-top: 14px; }
.nxt-signin__intro > * + * { margin-top: 8px; }

/* #655: whose password this is, as a well. The ids are trimmed, never wrapped. */
.nxt-signin__account {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border-radius: 5px;
    background: var(--nxt-surface-standard);
    white-space: nowrap;
}
.nxt-signin__account .nxt-signin__glyph { flex-basis: 16px; width: 16px; height: 16px; margin: 0; color: var(--nxt-text-secondary); }
.nxt-signin__account-name { font-weight: 500; }
.nxt-signin__account-ids  { overflow: hidden; text-overflow: ellipsis; font-family: var(--nxt-font-mono); font-size: 12.5px; color: var(--nxt-text-secondary); }
.nxt-signin__guidance { margin: 0; color: var(--nxt-text-secondary); }

.nxt-signin__form  { margin-top: 26px; }
.nxt-signin__label { display: block; margin: 0 0 4px 0; }

/* 35, deliberately taller than --nxt-control-height (26). The reference sets 35 on this screen and only
   this screen: it is the one surface an operator touches before their gloves are off. */
.nxt-signin__input {
    display: block;
    box-sizing: border-box;
    width: 100%;
    height: 35px;
    margin: 0 0 10px 0;
}

/* #656: why the Organisation box was filled in. */
.nxt-signin__field-hint { margin: -5px 0 10px 0; font-size: 12px; color: var(--nxt-text-secondary); }

/* #654: a box a refusal is about gets an error edge, and the sentence sits right under it. The password field is a
   wrapper, so its entry takes the edge. Caps Lock is the same line in the warning colour. */
.nxt-signin__input--refused:not(.nxt-reveal),
.nxt-signin__input--refused .nxt-reveal__entry { border: 1.5px solid var(--nxt-semantic-error); }

.nxt-signin__field-line {
    display: flex;
    align-items: flex-start;
    gap: 5px;
    margin: -5px 0 10px 0;
    font-size: 12.5px;
}

.nxt-signin__field-line--refusal { color: var(--nxt-semantic-error-strong); }
.nxt-signin__field-line--caps    { color: var(--nxt-semantic-warning-strong); font-size: 12px; }
.nxt-signin__field-line--met     { color: var(--nxt-semantic-active-strong); font-size: 12px; }
.nxt-signin__field-line--unmet   { color: var(--nxt-text-secondary); font-size: 12px; }
.nxt-signin__glyph               { flex: 0 0 14px; width: 14px; height: 14px; margin-top: 1px; }
.nxt-signin__rules               { list-style: none; margin: 2px 0 10px 0; padding: 0; }
.nxt-signin__rules .nxt-signin__field-line { margin: 4px 0 0 0; }

/* #655: the card's width, 44 tall. */
.nxt-signin__submit { display: block; width: 100%; height: 44px; margin: 22px 0 0 0; }

/* WHY THE BUTTON IS OFF, ON THE CARD (issue 10 FR-007). It was a `title` here, which is invisible on a
   touchscreen, invisible without a pointer, and invisible in a screenshot sent to support. */
.nxt-signin__disabled-reason {
    margin: 8px 0 0 0;
    text-align: center;
    font-size: var(--nxt-font-size-small);
    color: var(--nxt-text-secondary);
}

/* The result of what you just did, below the button and at the FOOT of the body — the WPF twin's `*`
   spacer row, which is what keeps these sentences in one place across every state. */
.nxt-signin__results { margin-top: auto; margin-bottom: 14px; padding-top: 14px; }
.nxt-signin__results > * + * { margin-top: 8px; }

/* ── "Forgot your password?" — the link and its dialogue (issue 10 FR-008 to FR-010) ──────────────
   The link is the reference platform's hyperlink treatment: no underline, quiet grey at rest so it does
   not compete with the primary button, the accent and a pointer on hover. The dialogue is a panel over a
   scrim where the WPF host opens a real window — a window is a desktop idea and this host has none.

   The link has no box of its own any more: it sits in the card's footer strip, which owns its 30px and
   centres what it holds. `.nxt-signin__footer` was that box and went with issue 35. */

.nxt-link {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 300;
    color: var(--nxt-text-muted);
    text-decoration: none;
    cursor: pointer;
}
.nxt-link:hover { color: var(--nxt-accent-primary); }

/* #655 — Forgot your password is a stage of the sign-in card, in place of the form: no scrim, no panel, no title of its
   own. The card's caption says what it is. */
.nxt-recover { margin-top: 14px; }

.nxt-recover__explanation { margin: 0; }
.nxt-recover__caption {
    margin: 16px 0 6px 0;
    font-family: var(--nxt-font-mono);
    font-size: 10.5px;
    color: var(--nxt-text-secondary);
}

.nxt-recover__list {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--nxt-border-primary);
    border-radius: 8px;
    overflow: hidden;
}
.nxt-recover__who   { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--nxt-border-row); }
.nxt-recover__who:last-child { border-bottom: 0; }
.nxt-recover__name  { font-weight: 500; }
.nxt-recover__where { margin-left: auto; font-size: 12.5px; color: var(--nxt-text-secondary); }

/* FR-009 — never an empty box; the sentence is outlined, like every message on the card. */
.nxt-recover__nothing { margin-top: 0; }

/* #324 — the recovery at the machine, under the list; the twin of the WPF view's small secondary line. */
.nxt-recover__at-the-machine { margin: 10px 0 0 0; font-size: var(--nxt-font-size-small); color: var(--nxt-text-secondary); }

/* #655 — Back to sign in, the card's width. */
.nxt-recover__back {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 44px;
    margin: 18px 0 14px 0;
}
.nxt-recover__back .nxt-signin__glyph { flex-basis: 16px; width: 16px; height: 16px; margin: 0; }

.nxt-shell__audit-problem {
    margin: 16px;
    padding: 12px;
    border-radius: 3px;
    background: var(--nxt-banner-warn-bg);
    border: 1px solid var(--nxt-semantic-warning);
    color: var(--nxt-banner-warn-text);
}

.nxt-shell__status-operator { color: var(--nxt-text-secondary); margin-left: 12px; }

/* The licence notice on the status bar (btsoons/Nxt.Atrium#18 FR-011). WARNING and never error: a licence
   that is ending has stopped nothing. The twin is the Nxt.Semantic.Warning foreground in ShellView.xaml.
   Every colour is an --nxt-* token (C3). */
.nxt-shell__status-licence {
    color: var(--nxt-semantic-warning);
    margin-left: 16px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The directory notice on the status bar (btsoons/Nxt.Atrium#79 FR-024, #139). WARNING and never error,
   for the licence notice's reason: this station is working and somebody should attend to it. The twin is
   the Nxt.Semantic.Warning foreground in ShellView.xaml. Every colour is an --nxt-* token (C3). */
.nxt-shell__status-directory {
    color: var(--nxt-semantic-warning);
    margin-left: 16px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* == Administration (#2578) ====================================================================
   The panel, the buttons, the inputs, the tabs and the list rows are all the shared control
   chrome's own selectors (.nxt-panel, .nxt-btn, .nxt-tab, .nxt-list, element rules). Nothing here
   re-declares one controls.css owns; every colour is an --nxt-* token (C3). */

.nxt-admin {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    padding: 16px;
    gap: 12px;
    overflow: auto;
}

.nxt-admin__header      { display: flex; align-items: center; gap: 12px; }
.nxt-admin__title       { margin: 0; font-size: 18px; }
.nxt-admin__scope-label { color: var(--nxt-text-secondary); }
.nxt-admin__scope       { min-width: var(--nxt-atrium-field-medium); }

/* #445: the tabs are the shared <TabControl Class="nxt-admin__tabs">; this only lets it take the height the body
   below its strip had. */
.nxt-admin__tabs { flex: 1 1 auto; min-height: 0; }
.nxt-admin__tabs > .nxt-tabs__panel { display: flex; min-height: 0; padding: 0; }

/* THE ACTIVE TAB'S LABEL (btsoons/Nxt.Atrium#574; the #530 handoff, E): semibold in the shared blue accent (Bas,
   2026-10-04). The face is the shared theme's, already white when selected. Twin of TabLabel in AdministrationView.xaml. */
.nxt-admin__tabs .nxt-tab--selected { color: var(--nxt-accent-secondary); font-weight: 600; }

/* btsoons/Nxt.Atrium#570: the 1px separator before the Nxt tabs (the #530 handoff, 3b), 20 high and 10 clear of
   Licence's slope and of the Customers face. It is not a tab: Administration.razor marks the Customers tab with the
   span, and the line is drawn outside that tab's face. 31 = the slope's 10 of overlap undone, then 10 + 1 + 10;
   the twin of the Customers TabItem's margin in AdministrationView.xaml. */
.nxt-admin__tabs .nxt-tab:has(> .nxt-admin__tab-separator) { margin-left: 31px; }
.nxt-admin__tab-separator {
    position: absolute;
    left: calc(-11px - var(--nxt-border-thickness));
    top: 50%;
    width: 1px;
    height: 20px;
    transform: translateY(-50%);
    background: var(--nxt-border-primary);
}

/* btsoons/Nxt.Atrium#267 / #268 - the one header and the one way back, above whatever is open. */
/* The band under the page's header - the twin of ShellView.xaml's Padding="16,10" Border, and one of the
   two rules INSIDE the page that take --nxt-atrium-page-rule-color (btsoons/Nxt.Atrium#283). */
.nxt-shell__surface-head {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 16px; border-bottom: 1px solid var(--nxt-atrium-page-rule-color);
}
.nxt-shell__surface-head-icon  { width: 20px; height: 20px; }
.nxt-shell__surface-head-title { margin: 0; font-size: 18px; font-weight: 600; }
.nxt-shell__surface-close      { margin-left: auto; }
.nxt-shell__surface-close-icon { width: 14px; height: 14px; }

/* EVERY TAB IS A PAGE INSET 24/28 (#574): the one padding, and none of the shared tab panel's inset beside it. */
.nxt-admin__body  { display: flex; flex: 1 1 auto; min-height: 0; padding: var(--nxt-atrium-admin-page-padding); }
.nxt-admin__split { display: flex; gap: 16px; width: 100%; min-height: 0; align-items: flex-start; }

.nxt-admin__list   { width: 280px; flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; }
/* THE FORM IS A TWO-COLUMN GRID (btsoons/Nxt.Atrium#286, doc/ui/form-layout.md) - the twin of the Grid
   every *PanelView.xaml now uses: a label column of its own width, a field column, and the cap on the
   COLUMN rather than on any field.

   NO WRAPPER ELEMENT, and that is not a shortcut: a Razor @if emits no element, so the labels, inputs and
   hints inside one are already DIRECT CHILDREN of this pane in the rendered DOM. Adding a container per
   form would have been eight files edited to reach a layout the DOM already allows.

   Everything else spans both columns, so headings, lists, refusals and button rows are untouched. A hint
   goes to the field column only when it FOLLOWS a field: this pane also carries prose hints that describe
   the panel rather than a box, and those must not be indented under the fields. */
.nxt-admin__detail {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    grid-template-columns: auto minmax(0, var(--nxt-atrium-field-long));
    column-gap: 8px;
    align-content: start;
}

.nxt-admin__detail > *                                        { grid-column: 1 / -1; }
.nxt-admin__detail > .nxt-admin__label                        { grid-column: 1; align-self: center; }
.nxt-admin__detail > .nxt-admin__input                        { grid-column: 2; }
.nxt-admin__detail > .nxt-admin__input + .nxt-admin__hint     { grid-column: 2; }

.nxt-admin__list-actions   { display: flex; gap: 8px; }
.nxt-admin__detail-actions { display: flex; gap: 8px; margin-top: 12px; }

.nxt-admin__rows { list-style: none; margin: 0; padding: 0; max-height: 420px; overflow-y: auto; }

.nxt-admin__row-button {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    padding: 4px 8px;
    background: transparent;
    color: inherit;
    border: none;
    cursor: pointer;
    text-align: left;
}

.nxt-admin__row--selected { background: var(--nxt-bg-selected); }

.nxt-admin__row-title    { font-weight: 600; }
.nxt-admin__row-subtitle { color: var(--nxt-text-secondary); font-size: 12px; }
.nxt-admin__row-state    { color: var(--nxt-text-secondary); font-size: 12px; font-style: italic; }

.nxt-admin__detail-title { margin: 0 0 12px 0; font-size: 16px; }
.nxt-admin__label        { display: block; margin: 0 0 4px 0; }
/* NO max-width HERE. The cap is on the grid's field column (see .nxt-admin__detail above) - the same
   rule the WPF twin follows, for the same reason: a field that sizes itself is a field that decides
   the form's width. */
.nxt-admin__input        { display: block; width: 100%; margin: 0 0 8px 0; }
.nxt-admin__hint         { margin: 0 0 12px 0; color: var(--nxt-text-secondary); font-size: 12px; }
.nxt-admin__check        { display: flex; align-items: center; gap: 6px; margin: 8px 0 12px 0; }
.nxt-admin__icon         { width: 16px; height: 16px; flex: 0 0 auto; }

.nxt-admin__shuttle         { display: flex; gap: 12px; margin-top: 16px; align-items: flex-start; }
.nxt-admin__shuttle-side    { flex: 1 1 0; min-width: 0; }
.nxt-admin__shuttle-heading { margin: 0 0 6px 0; font-size: 13px; }
.nxt-admin__shuttle-buttons { display: flex; flex-direction: column; gap: 8px; padding-top: 24px; }

.nxt-admin__empty {
    padding: 16px;
    color: var(--nxt-text-secondary);
    border: 1px dashed var(--nxt-border-primary);
}

.nxt-admin__notice {
    padding: 12px;
    background: var(--nxt-banner-warn-bg);
    border: 1px solid var(--nxt-semantic-warning);
    color: var(--nxt-banner-warn-text);
}

.nxt-admin__refusal {
    margin: 0 0 12px 0;
    padding: 8px 12px;
    background: var(--nxt-banner-error-bg);
    border: 1px solid var(--nxt-semantic-error);
    color: var(--nxt-banner-error-text);
}

/* The organisations panel's three states (btsoons/Nxt.Atrium#17 FR-014, FR-015), and they are three
   VISIBLY different things — which is the whole requirement rather than a styling preference.

   --setup is "this station has not been given its organisation document yet". It deliberately does NOT
   inherit the warning fill .nxt-admin__notice carries: a setup state is a step somebody has still to take,
   and painting it amber tells an administrator something is wrong on a station where nothing is. It reads
   as .nxt-admin__empty does — a neutral dashed box — because that is already this screen's spelling for
   "there is nothing here yet, and here is what to do about it".

   --refused is the opposite fact and takes the error colours the per-document refusals below it take, so
   "could not look" and "there is nothing" cannot be mistaken for each other at a glance. Every colour is an
   --nxt-* token (C3); there is no hex literal here. */
.nxt-admin__notice--setup {
    background: none;
    border: 1px dashed var(--nxt-border-primary);
    color: var(--nxt-text-secondary);
}

.nxt-admin__notice--refused {
    background: var(--nxt-banner-error-bg);
    border: 1px solid var(--nxt-semantic-error);
    color: var(--nxt-banner-error-text);
}

/* THE LICENCE PANEL (btsoons/Nxt.Atrium#18 FR-023). A WARNING and never an error: a licence that is
   ending, or has ended, has stopped nothing — so it takes the warning tokens rather than --refused's error
   ones, which say something is broken. The twin is the Nxt.Semantic.Warning border in
   LicencePanelView.xaml. Every colour is an --nxt-* token (C3); there is no hex literal here. */
.nxt-admin__notice--warning {
    background: var(--nxt-banner-warn-bg);
    border: 1px solid var(--nxt-semantic-warning);
    color: var(--nxt-banner-warn-text);
}

/* THE LICENCE TAB (btsoons/Nxt.Atrium#573, the handoff's 3b-03), the twin of LicencePanelView.xaml: a page, the
   licence card and the file card at 1.25 : 1. The four figures are large, in the figure face, each with its label
   under it and a hairline between one and the next; the date is mono. Tokens only (C3). */
.nxt-licence          { display: flex; flex-direction: column; gap: 20px; flex: 1 1 auto; min-width: 0; overflow-y: auto; }
.nxt-licence__columns { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.nxt-licence__right   { display: flex; flex-direction: column; gap: 12px; }
.nxt-licence__figures { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.nxt-licence__cell    { display: flex; flex-direction: column; padding: 0 16px; }
.nxt-licence__cell:first-child { padding-left: 0; }
.nxt-licence__cell + .nxt-licence__cell { border-left: 1px solid var(--nxt-border-primary); }
.nxt-licence__figure  { font-family: var(--nxt-font-figure); font-size: 40px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-licence__label   { font-size: 13px; color: var(--nxt-text-secondary); }
.nxt-licence__until   { display: flex; justify-content: space-between; align-items: center; padding-top: 14px; border-top: 1px solid var(--nxt-border-primary); }
.nxt-licence__until-label { color: var(--nxt-text-secondary); }
.nxt-licence__date    { font-family: var(--nxt-font-mono); font-size: 16px; color: var(--nxt-text-heading); }
.nxt-licence__setup   { margin: 0; }

/* THE FILE CARD IS THE DROP TARGET (#573). Its 1.5px accent edge on the accent's soft white, one step darker while a
   file is over it (--over, from the view-model's IsFileOver). The file input is stretched, invisible, over the whole
   card and nowhere else, so a click anywhere on it opens the browser's picker and a file dropped anywhere on it lands
   in the input - which is how a browser takes a drop with no script.
   BESIDE THE SHARED CARD, AND ABOVE IT: the element also carries .nxt-admin-card, which is declared later in this
   file, so a single-class rule here lost its edge and its fill to the card (Nora on #621). Both rules name the card
   class too, which outranks it wherever either sits. AClassBesideTheSharedCard_WinsEveryPropertyItSets holds it. */
.nxt-admin-card.nxt-licence__file-card {
    position: relative;
    border: 1.5px solid var(--nxt-accent-secondary);
    background: var(--nxt-accent-secondary-soft);
}
/* Nxt.Accent.PrimarySoft has no custom property; it is the primary accent at 16% over white (#E1EAF3), as the shared
   grid's selected row mixes it (#1482). */
.nxt-admin-card.nxt-licence__file-card--over { background: color-mix(in srgb, var(--nxt-accent-primary) 16%, var(--nxt-bg-panel)); }
.nxt-licence__file-card .nxt-admin__hint { margin: 0; }
.nxt-licence__file-icon { width: 24px; height: 24px; color: var(--nxt-accent-secondary); }
.nxt-licence__take-in   { align-self: flex-start; }
.nxt-licence__file { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.nxt-licence__file:disabled { cursor: not-allowed; }

/* #522: the package picker is a button-shaped label over a transparent file input, as the licence panel's is. */
.nxt-catalog__choose { position: relative; display: inline-block; }
.nxt-catalog__file { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.nxt-catalog__file:disabled { cursor: not-allowed; }

.nxt-admin__refusals     { list-style: none; margin: 0 0 12px 0; padding: 0; }
.nxt-admin__refusal-file { display: block; font-weight: 600; }
.nxt-admin__refusal-why  { display: block; }

.nxt-admin__busy { padding: 8px 0; color: var(--nxt-text-secondary); }

/* THE NXT ADMINISTRATOR'S TENANT VIEW (btsoons/Nxt.Atrium#47 FR-007, FR-009). A stack of read-only
   sections and nothing that can be pressed — there is no button rule here because there is no button.
   It reuses .nxt-admin__rows, .nxt-admin__row-title/-subtitle/-state and the three notice spellings
   rather than declaring a second set of them: one concept, one spelling. Every colour is an --nxt-*
   token (C3); there is no hex literal here. */
.nxt-tenant__section { margin: 0 0 20px 0; }
.nxt-tenant__row     { display: flex; flex-direction: column; padding: 4px 0; }

/* == App catalogue (#2580) =====================================================================
   The panel, the buttons and the inputs are the shared control chrome's own selectors
   (.nxt-panel, .nxt-btn, element rules), and the screen reuses the administration layout's
   .nxt-admin__split / __detail / __hint / __refusal rather than declaring a second set of them —
   one concept, one spelling. Only what is genuinely new to this screen is here, and every colour
   is an --nxt-* token (C3). */

.nxt-catalog {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    padding: 16px;
    gap: 12px;
    overflow: auto;
}

/* #700 (row 5u.1): the list is a pane of its own, 420 wide with a hairline on its right, and its rows scroll inside
   it. The four columns are one grid template, shared by the header and every row so they line up. */
.nxt-catalog__list {
    width: 420px;
    flex: 0 0 auto;
    align-self: stretch;
    min-height: 0;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--nxt-border-primary);
}
.nxt-catalog__list-top { display: flex; gap: 8px; padding: 16px; align-items: center; }
.nxt-catalog__search { position: relative; flex: 1 1 auto; display: flex; }
.nxt-catalog__search-icon {
    position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
    width: 14px; height: 14px; color: var(--nxt-text-secondary); pointer-events: none;
}
.nxt-catalog__search > .nxt-admin__input { margin: 0; padding-left: 28px; }
.nxt-catalog__columns {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 64px 64px 64px;
    gap: 8px;
    align-items: start;
}
.nxt-catalog__head {
    padding: 6px 16px;
    background: var(--nxt-surface-standard);
    font-family: var(--nxt-font-mono);
    font-size: 10px;
    text-transform: uppercase;
    color: var(--nxt-text-secondary);
}
.nxt-catalog__no-match { margin: 12px 16px; color: var(--nxt-text-secondary); }
.nxt-catalog__apps { overflow-y: auto; min-height: 0; flex: 1 1 auto; }
.nxt-catalog__app { border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-catalog__app--muted { background: var(--nxt-surface-standard); color: var(--nxt-text-secondary); }
.nxt-catalog__app--selected {
    background: var(--nxt-accent-secondary-soft);
    box-shadow: inset 3px 0 0 var(--nxt-accent-primary);
}
.nxt-catalog__app-button {
    display: block;
    width: 100%;
    padding: 12px 16px;
    text-align: left;
    background: none;
    border: 0;
    color: inherit;
    cursor: pointer;
}
.nxt-catalog__app-name { display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px; min-width: 0; }
.nxt-catalog__app-title { font-weight: 600; font-size: 14px; }
.nxt-catalog__app-product {
    flex: 1 0 100%;
    font-family: var(--nxt-font-mono);
    font-size: 11.5px;
    color: var(--nxt-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
}
.nxt-catalog__version {
    font-family: var(--nxt-font-mono);
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.nxt-catalog__version--none { color: var(--nxt-text-muted); }
.nxt-catalog__app-warning {
    display: flex;
    gap: 6px;
    margin-top: 6px;
    font-size: 12px;
    color: var(--nxt-semantic-warning-strong);
}
.nxt-catalog__app-warning-icon { width: 14px; height: 14px; flex: 0 0 auto; }

/* A badge (#700): a short word in a pill beside a name. The twin is Nxt.Atrium.Badge in ShellTemplates.xaml. */
.nxt-badge {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 10px;
    font-size: 12px;
    font-weight: 500;
}
.nxt-badge--neutral { background: var(--nxt-bg-secondary); color: var(--nxt-text-secondary); }
.nxt-badge--active  { background: var(--nxt-semantic-active-soft); color: var(--nxt-semantic-active-strong); }

/* #701 (row 5u.2): the chosen app's header, and its three states as cards with a chevron between each pair. The twins
   are AppHeaderView.xaml and AppStateCardView.xaml. */
/* The shared detail grid caps its field column, which would cap the cards too: a third, flexible column lets a block
   that spans every column (the header, the cards, the versions) take the pane's width while a field keeps its cap. */
.nxt-admin__detail.nxt-catalog__detail {
    padding: 24px;
    grid-template-columns: auto minmax(0, var(--nxt-atrium-field-long)) minmax(0, 1fr);
}
.nxt-admin__detail.nxt-catalog__detail > button { justify-self: start; }
.nxt-catalog__header { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 20px; }
.nxt-catalog__header-icon {
    width: 44px; height: 44px; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    border-radius: 8px; background: var(--nxt-surface-standard);
}
.nxt-catalog__header-icon svg { width: 24px; height: 24px; }
.nxt-catalog__header-text { flex: 1 1 auto; min-width: 0; }
.nxt-catalog__header-name { display: flex; align-items: center; gap: 10px; font-size: 22px; font-weight: 600; }
.nxt-catalog__header-product { font-family: var(--nxt-font-mono); font-size: 13px; color: var(--nxt-text-secondary); }
.nxt-catalog__cards {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 20px minmax(0, 1fr) 20px minmax(0, 1fr);
    align-items: stretch;
    margin-bottom: 16px;
}
.nxt-catalog__chevron { width: 16px; height: 16px; align-self: center; justify-self: center; color: var(--nxt-text-muted); }
.nxt-catalog__card { padding: 16px; display: flex; flex-direction: column; }
.nxt-admin-card.nxt-catalog__card--next { border: 1.5px solid var(--nxt-accent-secondary); }
.nxt-catalog__card-eyebrow { font-family: var(--nxt-font-mono); font-size: 10.5px; color: var(--nxt-text-secondary); }
.nxt-catalog__card-version { font-family: var(--nxt-font-mono); font-size: 22px; margin: 6px 0; }
.nxt-catalog__card-version--empty { color: var(--nxt-text-muted); }
.nxt-catalog__card-audience { font-size: 12.5px; }
.nxt-catalog__card-deadline { font-size: 12.5px; margin-top: 4px; color: var(--nxt-text-secondary); }
.nxt-catalog__card-body { flex: 1 1 auto; display: flex; flex-direction: column; padding-bottom: 12px; }
.nxt-catalog__card-foot { padding-top: 12px; border-top: 1px solid var(--nxt-border-primary); }
.nxt-catalog__card-foot > .nxt-admin__hint { font-size: 12px; margin: 4px 0 0 0; }
.nxt-catalog__card-links { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 10px; }
.nxt-catalog__card-links .nxt-link { color: var(--nxt-accent-primary); }
.nxt-catalog__card-links .nxt-catalog__withdraw { color: var(--nxt-semantic-error-strong); }
.nxt-catalog__card-links .nxt-link:disabled { color: var(--nxt-text-disabled); cursor: not-allowed; }
.nxt-catalog__back { color: var(--nxt-accent-primary); margin-bottom: 12px; justify-self: start; }

/* #702 (row 5u.3): one act at a time, in the card it applies to. The open card widens; the other two are narrow and
   dimmed beside it. The twins are AppStateCardView.xaml and AppReleaseActView.xaml. */
.nxt-catalog__card-eyebrow { display: flex; justify-content: space-between; gap: 8px; }
.nxt-catalog__card-eyebrow > span + span { font-size: 11px; }
.nxt-admin-card.nxt-catalog__card--open { border: 1.5px solid var(--nxt-accent-secondary); }
.nxt-admin-card.nxt-catalog__card--withdrawing { border: 1.5px solid var(--nxt-semantic-error); }
.nxt-catalog__card--dimmed { opacity: 0.55; }
.nxt-catalog__cards--open { grid-template-columns: minmax(0, 1fr) 20px minmax(0, 1.6fr); }
.nxt-catalog__cards--open > .nxt-catalog__cards-narrow { grid-column: 1; display: flex; flex-direction: column; gap: 12px; }
.nxt-catalog__cards--open > .nxt-catalog__card { grid-column: 3; }
.nxt-catalog__card-act { margin-top: 12px; }
.nxt-catalog__act { display: flex; flex-direction: column; gap: 4px; }
.nxt-catalog__act-sentence { margin: 0 0 8px 0; }
.nxt-catalog__act-reason { min-height: 64px; }
.nxt-catalog__act .nxt-admin__input { margin: 0; }
.nxt-catalog__act-date.nxt-admin__input { width: var(--nxt-atrium-field-short); }
.nxt-catalog__act-reason-foot { display: flex; justify-content: space-between; gap: 12px; }
.nxt-catalog__act-reason-foot > .nxt-admin__hint { margin: 4px 0 0 0; font-size: 12px; }
.nxt-catalog__act-remaining { font-family: var(--nxt-font-mono); font-size: 11px; color: var(--nxt-text-secondary); margin-top: 4px; }
.nxt-catalog__act-buttons {
    display: flex; gap: 8px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--nxt-border-primary);
}
.nxt-catalog__act-below { margin-bottom: 16px; }
.nxt-catalog__sign-earlier {
    margin-bottom: 16px; padding: 12px; border: 1px solid var(--nxt-accent-secondary); border-radius: 5px;
    background: var(--nxt-bg-panel);
}
.nxt-catalog__sign-earlier > p { margin: 0 0 8px 0; }

/* #704 (row 5u.5): Attach is one dashed panel, the only dashed edge on the screen, and it takes a dropped package; every
   version is a row of one table. The twins are in AppReleasesPanelView.xaml. */
.nxt-catalog__attach {
    position: relative;
    margin-bottom: 24px;
    padding: 16px 18px;
    border: 1.5px dashed var(--nxt-border-control);
    border-radius: 8px;
}
.nxt-catalog__attach--over { background: var(--nxt-accent-secondary-soft); }
.nxt-catalog__attach-head { display: flex; gap: 12px; align-items: flex-start; }
.nxt-catalog__attach-icon { width: 24px; height: 24px; flex: 0 0 auto; color: var(--nxt-accent-primary); }
.nxt-catalog__attach-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.nxt-catalog__attach-text > .nxt-admin__hint { margin: 0; font-size: 12px; }
.nxt-catalog__attach-title { font-size: 14.5px; font-weight: 600; }
.nxt-catalog__attach > .nxt-admin__hint { margin: 8px 0 0 36px; font-size: 12px; }
.nxt-catalog__attach-form {
    display: grid;
    grid-template-columns: auto minmax(0, var(--nxt-atrium-field-long));
    column-gap: 8px;
    align-items: start;
    margin-top: 12px;
    position: relative;
    z-index: 1;
    background: var(--nxt-bg-panel);
}
.nxt-catalog__attach-form > *                   { grid-column: 1 / -1; }
.nxt-catalog__attach-form > .nxt-admin__label   { grid-column: 1; align-self: center; }
.nxt-catalog__attach-form > .nxt-admin__input   { grid-column: 2; }
.nxt-catalog__attach-form > .nxt-admin__input + .nxt-admin__hint { grid-column: 2; }
.nxt-catalog__attach-form > button              { justify-self: start; }
.nxt-catalog__versions-title { display: flex; justify-content: space-between; align-items: baseline; }
.nxt-catalog__versions-title > .nxt-catalog__section-title { font-size: 15px; }
.nxt-catalog__versions-counts { font-family: var(--nxt-font-mono); font-size: 11.5px; color: var(--nxt-text-secondary); }
.nxt-catalog__versions {
    border: 1px solid var(--nxt-border-primary);
    border-radius: 8px;
    overflow: hidden;
    margin-bottom: 8px;
}
.nxt-catalog__versions-row {
    display: grid;
    grid-template-columns: 90px 110px 150px minmax(0, 1fr);
    gap: 4px 0;
    width: 100%;
    padding: 8px 12px;
    text-align: left;
    background: none;
    border: 0;
    border-top: 1px solid var(--nxt-border-primary);
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.nxt-catalog__versions-head { border-top: 0; background: var(--nxt-surface-standard); font-size: 12px; color: var(--nxt-text-secondary); cursor: default; }
.nxt-catalog__versions-row--selected { background: var(--nxt-accent-secondary-soft); }
.nxt-catalog__versions-row--withdrawn { background: var(--nxt-surface-standard); color: var(--nxt-text-secondary); }
.nxt-catalog__versions-version { font-family: var(--nxt-font-mono); font-size: 13px; }
.nxt-catalog__versions-published { font-family: var(--nxt-font-mono); font-size: 12px; }
.nxt-catalog__versions-by { display: flex; flex-direction: column; }
.nxt-catalog__versions-detail { font-family: var(--nxt-font-mono); font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-catalog__versions-byline { font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-catalog__versions-withdrawn { grid-column: 2 / -1; font-size: 12px; }
.nxt-catalog__versions-second { grid-column: 1 / -1; display: flex; flex-direction: column; font-size: 12px; }
.nxt-catalog__versions-package { font-family: var(--nxt-font-mono); font-size: 11.5px; color: var(--nxt-text-secondary); }
.nxt-badge--waiting { background: var(--nxt-semantic-waiting-soft); color: var(--nxt-semantic-waiting-strong); }
.nxt-badge--info    { background: var(--nxt-accent-secondary-soft); color: var(--nxt-accent-secondary); }

/* #705 (row 5u.7): the icon is picked from a grid of its glyphs, and a sunken well previews the app's tiles. Both sit in
   the form's field column. The twin is AppDefinitionPanelView.xaml. */
.nxt-admin__detail > .nxt-catalog__icons,
.nxt-admin__detail > .nxt-catalog__icons + .nxt-admin__hint,
.nxt-admin__detail > .nxt-catalog__preview,
.nxt-admin__detail > .nxt-admin__check + .nxt-admin__hint { grid-column: 2; }
.nxt-catalog__icons { display: flex; flex-wrap: wrap; gap: 6px; }
.nxt-admin__detail > .nxt-catalog__icons-label { align-self: start; padding-top: 12px; }
.nxt-catalog__icon {
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--nxt-border-primary); border-radius: 6px;
    background: var(--nxt-bg-panel); color: inherit; cursor: pointer;
}
.nxt-catalog__icon svg { width: 20px; height: 20px; }
.nxt-catalog__icon--selected { border: 1.5px solid var(--nxt-accent-secondary); background: var(--nxt-accent-secondary-soft); }
.nxt-catalog__preview { margin: 16px 0; padding: 16px; border-radius: 8px; background: var(--nxt-surface-standard); }
.nxt-catalog__preview-eyebrow { display: block; margin-bottom: 10px; font-family: var(--nxt-font-mono); font-size: 10.5px; color: var(--nxt-text-secondary); }
.nxt-catalog__preview-tiles { display: flex; gap: 12px; }
.nxt-catalog__preview-tile {
    width: 120px; height: 96px; padding: 8px; box-sizing: border-box;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
    border: 1px solid var(--nxt-border-primary); border-radius: 8px; background: var(--nxt-bg-panel);
    font-size: 12.5px; text-align: center; overflow: hidden;
}
.nxt-catalog__preview-tile svg { width: 28px; height: 28px; flex: 0 0 auto; }
.nxt-catalog__preview-tile > span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nxt-catalog__preview-tile > .nxt-catalog__preview-state {
    margin-top: -6px; font-family: var(--nxt-font-mono); font-size: 10px; text-transform: uppercase;
    color: var(--nxt-text-secondary);
}
.nxt-catalog__definition-actions { padding-top: 12px; border-top: 1px solid var(--nxt-border-primary); }

.nxt-catalog__rows,
.nxt-catalog__release-rows,
.nxt-catalog__group-rows { list-style: none; margin: 0; padding: 0; }

.nxt-catalog__row,
.nxt-catalog__release-row { border-bottom: 1px solid var(--nxt-border-primary); }

.nxt-catalog__row--selected,
.nxt-catalog__release-row--selected { background: var(--nxt-btn-hover); }

.nxt-catalog__row-button {
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    gap: 4px 12px;
    width: 100%;
    padding: 6px 8px;
    text-align: left;
    background: none;
    border: 0;
    color: inherit;
    cursor: pointer;
}

.nxt-catalog__row-title       { font-weight: 600; }
.nxt-catalog__row-version     { }
.nxt-catalog__row-state       { color: var(--nxt-text-secondary); }
.nxt-catalog__audience        { margin-bottom: 12px; }

.nxt-catalog__row-product,
.nxt-catalog__row-notes   { grid-column: 1 / -1; font-size: 11px; color: var(--nxt-text-secondary); }
.nxt-catalog__row-offered { color: var(--nxt-semantic-active); }
.nxt-catalog__row-withdrawn { grid-column: 1 / -1; font-size: 11px; color: var(--nxt-semantic-warning); }

.nxt-catalog__row-warning {
    grid-column: 1 / -1;
    font-size: 11px;
    color: var(--nxt-semantic-warning);
}

.nxt-catalog__empty {
    padding: 16px;
    color: var(--nxt-text-secondary);
    border: 1px dashed var(--nxt-border-primary);
}

.nxt-catalog__section-title { margin: 16px 0 6px 0; font-size: 14px; }
.nxt-catalog__group-row     { padding: 2px 0; }

.nxt-catalog__confirm {
    margin: 8px 0 12px 0;
    padding: 12px;
    background: var(--nxt-banner-warn-bg);
    border: 1px solid var(--nxt-semantic-warning);
    color: var(--nxt-banner-warn-text);
}

/* == Organisation keys (btsoons/Nxt.Atrium#69) =================================================
   The panel, the buttons, the inputs, the list rows and the two notice spellings are all the
   administration layout's own selectors (.nxt-admin__split / __detail / __hint / __notice--setup /
   __notice--refused, .nxt-panel, .nxt-btn) - one concept, one spelling. Only what is genuinely new
   to this screen is here, and every colour is an --nxt-* token (C3).

   THE FINGERPRINT IS THE LARGEST THING ON THE SCREEN, and that is the requirement rather than a
   styling preference (map row 10m.8): the one step in the chain that is a person is reading these
   sixteen characters down a telephone, and a fingerprint set in body text is one nobody reads out. */

.nxt-keys__paste { font-family: var(--nxt-font-mono); }

.nxt-keys__fingerprint-block { margin: 0 0 12px 0; }

.nxt-keys__fingerprint {
    margin: 0 0 8px 0;
    font-family: var(--nxt-font-mono);
    font-size: 32px;
    letter-spacing: 1px;
    word-break: break-word;
}

.nxt-keys__instruction { margin: 0 0 6px 0; font-weight: 600; }

.nxt-keys__row-fingerprint { display: block; font-family: var(--nxt-font-mono); }

.nxt-keys__reason {
    display: block;
    margin: 0 0 8px 0;
    padding: 8px;
    border: 1px solid var(--nxt-border-primary);
}

.nxt-keys__reason-caption     { display: block; font-weight: 600; }
.nxt-keys__reason-consequence { display: block; color: var(--nxt-text-secondary); }

/* ── A password field with an eye (btsoons/Nxt.Atrium#307) ─────────────────────────────────────────
   RevealablePasswordField.razor. The layout class a caller passes (nxt-admin__input, nxt-signin__input)
   goes on .nxt-reveal, so the grid and the card place the whole field; the entry fills it.

   The entry is two classes deep because the shared sheet styles input[type="password"] as an ELEMENT,
   which outranks one class - and the room on the right for the eye would silently lose to its padding. */
.nxt-reveal { position: relative; }

.nxt-reveal > .nxt-reveal__entry {
    display: block;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    padding-right: 32px;
}

/* One eye per field. Edge draws its own reveal button inside a password input, which would be a second
   way to show the password that nothing here hides again. */
.nxt-reveal > .nxt-reveal__entry::-ms-reveal { display: none; }

/* Over the entry, inside its border, in its colours. Whether it can be SELECTED is decided inline in the
   component, not here: that must not depend on this sheet having loaded. */
.nxt-reveal__shown {
    position: absolute;
    top: 3px;
    bottom: 1px;
    left: 1px;
    right: 32px;
    display: flex;
    align-items: center;
    padding-left: 4px;
    overflow: hidden;
    white-space: pre;
    cursor: text;
    color: var(--nxt-text-primary);
    background: var(--nxt-bg-panel);
}

.nxt-reveal__eye {
    position: absolute;
    top: 50%;
    right: 4px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--nxt-text-secondary);
    cursor: pointer;
}

.nxt-reveal__glyph { width: 16px; height: 16px; }

/* #410 — a person's phones (PhoneList.razor) and the enrolment code (AddMyPhone.razor); laid out as the Add my
   phone design handoff draws them (#644, rows 2n.14-2n.18). The code is dark modules on the light panel whatever the theme,
   because a phone's camera reads dark on light. */
.nxt-phones { margin-top: 24px; }

.nxt-phones__header    { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 4px; }
.nxt-phones__heading   { margin: 0; font-size: 14px; font-weight: 600; }
.nxt-phones__counts    { font: 11.5px var(--nxt-font-mono); color: var(--nxt-text-secondary); }
.nxt-phones__directory { margin: 0 0 12px 0; font-size: 12.5px; color: var(--nxt-text-secondary); }

.nxt-phones__rows { border: 1px solid var(--nxt-border-primary); border-radius: 8px; overflow: hidden; }

.nxt-phones__row { padding: 14px 16px; }
.nxt-phones__row + .nxt-phones__row { border-top: 1px solid var(--nxt-border-primary); }
.nxt-phones__row--withdrawn { background: var(--nxt-surface-standard); color: var(--nxt-text-secondary); }

.nxt-phones__title { display: flex; align-items: center; gap: 10px; }
.nxt-phones__label { font-size: 14.5px; font-weight: 600; }

.nxt-phones__badge {
    padding: 1px 8px;
    border-radius: 10px;
    font-size: 12px;
    font-weight: 500;
    background: var(--nxt-semantic-active-soft);
    color: var(--nxt-semantic-active-strong);
}
.nxt-phones__badge--withdrawn { background: var(--nxt-bg-secondary); color: var(--nxt-text-secondary); }

.nxt-phones__key { font-family: var(--nxt-font-mono); }
.nxt-phones__row .nxt-phones__key { margin: 4px 0 2px 0; font-size: 13.5px; }
.nxt-phones__detail { font-size: 12px; color: var(--nxt-text-secondary); }

.nxt-phones__withdraw {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--nxt-border-primary);
}
.nxt-admin__input.nxt-phones__reason { width: var(--nxt-atrium-field-medium); margin: 0; }
.nxt-phones__why-off { margin-left: 2px; font-size: 12px; color: var(--nxt-text-secondary); }

.nxt-phones__code {
    box-sizing: border-box;
    width: 260px;
    height: 260px;
    padding: 14px;
    border: 1px solid var(--nxt-border-primary);
    border-radius: 5px;
    background: var(--nxt-bg-panel);
}

.nxt-phones__code path { fill: var(--nxt-bg-black); }

/* Add my phone's own layout (#644). Shell blue throughout, never the Atrium teal. */
.nxt-add-phone { max-width: 620px; padding: var(--nxt-atrium-admin-page-padding); }

.nxt-add-phone__eyebrow {
    font: 11px/1.2 var(--nxt-font-mono);
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--nxt-text-secondary);
}

.nxt-add-phone__steps         { margin-bottom: 16px; }
.nxt-add-phone__steps-caption { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.nxt-add-phone__step-name     { font-weight: 600; color: var(--nxt-accent-primary); }
.nxt-add-phone__segments      { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.nxt-add-phone__segment       { height: 3px; border-radius: 2px; background: var(--nxt-border-primary); }
.nxt-add-phone__segment--done { background: var(--nxt-accent-primary); }

.nxt-add-phone__guidance { margin: 0 0 16px 0; font-size: 14px; color: var(--nxt-text-primary); }

.nxt-add-phone__field { border-radius: 4px; }
.nxt-add-phone__field--refused { outline: 1.5px solid var(--nxt-semantic-error); }
.nxt-add-phone__field .nxt-admin__input { margin: 0; }

.nxt-add-phone__field-refusal {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 6px 0 0 0;
    font-size: 12.5px;
    color: var(--nxt-semantic-error-strong);
}
.nxt-add-phone__field-refusal-icon { width: 14px; height: 14px; flex: 0 0 auto; margin-top: 1px; }

.nxt-add-phone__actions        { margin-top: 16px; }
.nxt-add-phone__actions--rule  { padding-top: 16px; border-top: 1px solid var(--nxt-border-primary); }

.nxt-add-phone__scan        { display: grid; grid-template-columns: 260px 1fr; gap: 24px; }
.nxt-add-phone__scan-side   { display: flex; flex-direction: column; }
.nxt-add-phone__scan-side .nxt-add-phone__guidance { margin-bottom: 14px; }
.nxt-add-phone__countdown   { display: flex; justify-content: space-between; margin: 12px 0 6px 0; font-size: 11.5px; color: var(--nxt-text-secondary); }
.nxt-add-phone__time-left   { font-family: var(--nxt-font-mono); color: var(--nxt-text-primary); }

.nxt-add-phone__bar {
    display: block;
    width: 100%;
    height: 3px;
    border: 0;
    border-radius: 2px;
    appearance: none;
    background: var(--nxt-border-primary);
    color: var(--nxt-accent-primary);
}
.nxt-add-phone__bar::-webkit-progress-bar   { background: var(--nxt-border-primary); border-radius: 2px; }
.nxt-add-phone__bar::-webkit-progress-value { background: var(--nxt-accent-primary); border-radius: 2px; }
.nxt-add-phone__bar::-moz-progress-bar      { background: var(--nxt-accent-primary); border-radius: 2px; }

.nxt-add-phone__well    { display: flex; flex-direction: column; gap: 4px; padding: 14px 16px; border-radius: 8px; background: var(--nxt-surface-standard); }
.nxt-add-phone__station { font: 22px var(--nxt-font-mono); color: var(--nxt-text-primary); overflow-wrap: anywhere; }
.nxt-add-phone__caption { font-size: 12.5px; color: var(--nxt-text-secondary); }

.nxt-add-phone__fallback { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin-top: auto; padding-top: 16px; }

.nxt-add-phone__readback { padding: 18px; border-radius: 8px; background: var(--nxt-bg-black); }
.nxt-add-phone__readback-eyebrows {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
    font: 10.5px var(--nxt-font-mono);
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--nxt-text-muted);
}
.nxt-add-phone__groups { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
/* The stroke: the palette has no inverse line, so the secondary text at 0.4. */
.nxt-add-phone__group {
    display: flex;
    flex-direction: column;
    padding: 12px;
    border: 1px solid color-mix(in srgb, var(--nxt-text-secondary) 40%, transparent);
    border-radius: 5px;
}
.nxt-add-phone__group-number { font: 11px var(--nxt-font-mono); color: var(--nxt-text-muted); }
.nxt-add-phone__group-text   { font: 28px var(--nxt-font-mono); color: var(--nxt-text-on-accent); }

.nxt-add-phone__name-label { margin-top: 16px; }
.nxt-add-phone__hint       { margin: 6px 0 0 0; font-size: 12px; color: var(--nxt-text-secondary); }

.nxt-add-phone__done { display: flex; align-items: flex-start; gap: 12px; margin-top: 12px; }
.nxt-add-phone__done > .nxt-outlined-message { flex: 1 1 auto; }
.nxt-add-phone__done > .nxt-btn { flex: 0 0 auto; white-space: nowrap; }

.nxt-add-phone > .nxt-outlined-message { margin-top: 12px; }

.nxt-add-phone__phones-line { display: flex; align-items: center; gap: 8px; margin: 16px 0 0 0; color: var(--nxt-text-secondary); }
.nxt-add-phone__phone-icon  { width: 16px; height: 16px; flex: 0 0 auto; }
.nxt-link.nxt-add-phone__show { margin-left: 4px; color: var(--nxt-accent-primary); font-weight: 400; }

/* #411 - the phone panel on the sign-in card (PhoneSignInPanel.razor). Dark modules on the light panel whatever the
   theme, because a phone's camera reads dark on light. */
.nxt-signin__phone { margin-top: 16px; text-align: center; }
.nxt-signin__instruction { margin: 0 0 12px 0; }

/* #657: 184 with a 12 quiet zone inside a hairline, radius 5; dark on light whatever the theme. */
.nxt-signin__code-frame {
    box-sizing: border-box;
    width: 184px;
    height: 184px;
    margin: 0 auto;
    padding: 12px;
    border: 1px solid var(--nxt-border-primary);
    border-radius: 5px;
    background: var(--nxt-bg-panel);
}
.nxt-signin__code { display: block; width: 100%; height: 100%; }
.nxt-signin__code path { fill: var(--nxt-bg-black); }

/* #657: the code's time left. */
.nxt-signin__countdown  { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 10px; font-size: 11.5px; color: var(--nxt-text-secondary); }
.nxt-signin__time-left  { font-family: var(--nxt-font-mono); color: var(--nxt-text-primary); }
.nxt-signin__time-bar   { width: 80px; height: 3px; margin-left: 2px; accent-color: var(--nxt-accent-primary); }

/* #657: the check the phone asks for, on the card. */
.nxt-signin__station-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 14px 0 0 0;
    padding: 12px 14px;
    border-radius: 5px;
    background: var(--nxt-surface-standard);
    text-align: left;
}
.nxt-signin__station-check .nxt-signin__glyph { flex-basis: 16px; width: 16px; height: 16px; color: var(--nxt-text-secondary); }
.nxt-signin__station { font-family: var(--nxt-font-mono); }

/* ── View log (#500, map row 1x) ──────────────────────────────────────────────────────────────
   Reuses the administration layout's selectors for captions, hints and notices; only the controls
   row and the entries are new. Every colour is an --nxt-* token. */
.nxt-log__controls { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end; margin-bottom: 8px; }
.nxt-log__path { user-select: text; font-family: var(--nxt-font-mono); }
.nxt-log__entries { list-style: none; margin: 0; padding: 0; }
.nxt-log__entry { padding: 4px 0; border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-log__stamp, .nxt-log__category { color: var(--nxt-text-secondary); margin-right: 8px; }
.nxt-log__level { font-weight: 600; margin-right: 8px; }
.nxt-log__level--problem { color: var(--nxt-semantic-error); }
.nxt-log__message { margin: 2px 0 0 0; font-family: var(--nxt-font-mono); white-space: pre-wrap; overflow-wrap: anywhere; }

/* #515 part A: rules, Find's marks and reading comfort. The colours are the --nxt-atrium-log-* tokens above; every
   one of them is also said in words (the row's hidden sentence, the marker, the rule's caption). */
.nxt-visually-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.nxt-log__group { border: 0; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0 16px; }
.nxt-log__group > legend { width: 100%; }
.nxt-log__group .nxt-admin__check { margin: 4px 0; }
/* #563, row 1x.16: a compact header. One line of intro and path, one toolbar row with each caption beside its control,
   and the three panels' headings in one row; an open panel's body is drawn under them. */
.nxt-log__intro { display: flex; align-items: baseline; gap: 24px; margin-bottom: 8px; }
.nxt-log__intro .nxt-admin__hint { margin: 0; }
.nxt-log__intro-text { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nxt-log__intro-path { flex: 0 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nxt-log__toolbar { align-items: center; gap: 8px 16px; margin-bottom: 4px; }
.nxt-log__inline { display: flex; align-items: center; gap: 6px; }
.nxt-log__inline .nxt-admin__label { margin: 0; }
.nxt-log__find-mode .nxt-admin__check { margin: 0; }
.nxt-log__panel-headings { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-bottom: 4px; }
.nxt-log__panel-heading {
    display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; cursor: pointer; font: inherit;
    color: var(--nxt-text-primary); background: transparent; border: 1px solid var(--nxt-border-primary);
}
.nxt-log__panel-heading:hover { border-color: var(--nxt-accent-primary); }
.nxt-log__panel-heading:focus-visible { outline: 2px solid var(--nxt-accent-primary); outline-offset: 1px; }
.nxt-log__panel-heading[aria-expanded="true"] { background: var(--nxt-bg-panel); }
.nxt-log__panel { border-bottom: 1px solid var(--nxt-border-primary); margin: 0 0 8px 0; padding: 4px 0 8px 0; }
.nxt-log__panel[hidden] { display: none; }
.nxt-log__count-bar { align-items: center; gap: 4px 16px; margin-bottom: 4px; }
.nxt-log__count { margin: 0; }
.nxt-log__rule-list { list-style: none; margin: 0; padding: 0; }
.nxt-log__rule { display: flex; flex-wrap: wrap; align-items: center; gap: 0 12px; }
.nxt-log__rule .nxt-admin__check { margin: 2px 0; }
.nxt-log__swatch { display: inline-block; width: 12px; height: 12px; border: 1px solid var(--nxt-border-primary); }
.nxt-log__entry { position: relative; padding-left: 40px; }
.nxt-log--compact .nxt-log__entry { padding-top: 0; padding-bottom: 0; }
.nxt-log--compact .nxt-log__message { margin: 0; }
.nxt-log--nowrap .nxt-log__message { white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.nxt-log__marker { position: absolute; left: 24px; width: 14px; font-weight: 600; }
.nxt-log__entry--context { opacity: 0.7; }
.nxt-log__entry--tint, .nxt-log__entry--tint .nxt-log__stamp, .nxt-log__entry--tint .nxt-log__category { color: var(--nxt-atrium-log-mark-text); }
/* After the tint, on purpose: a row can be both, and then it reads greyed (D-4), as the WPF twin's trigger order does. */
.nxt-log__entry--greyed, .nxt-log__entry--greyed .nxt-log__stamp, .nxt-log__entry--greyed .nxt-log__category { color: var(--nxt-text-secondary); }
.nxt-log__entry--greyed .nxt-log__level { color: var(--nxt-text-secondary); font-weight: normal; }
.nxt-log__not-shown { padding: 2px 16px; color: var(--nxt-text-secondary); font-size: 0.9em; }
.nxt-log__nothing-left { padding: 12px 0; }
.nxt-log__copy-fallback { margin: 4px 0 8px 0; }
.nxt-log__copy-text { display: block; width: 100%; box-sizing: border-box; font-family: var(--nxt-font-mono); white-space: pre; margin: 4px 0; }
.nxt-log__trace-toggle { margin: 2px 0; }
.nxt-log__highlight { color: var(--nxt-atrium-log-mark-text); border-radius: 2px; }
.nxt-log__find { background: var(--nxt-atrium-log-find); color: var(--nxt-atrium-log-mark-text); font-weight: 700; border-radius: 2px; }
.nxt-log__highlight--yellow { background: var(--nxt-atrium-log-highlight-yellow); }
.nxt-log__highlight--blue   { background: var(--nxt-atrium-log-highlight-blue); }
.nxt-log__highlight--green  { background: var(--nxt-atrium-log-highlight-green); }
.nxt-log__highlight--pink   { background: var(--nxt-atrium-log-highlight-pink); }
.nxt-log__highlight--orange { background: var(--nxt-atrium-log-highlight-orange); }
.nxt-log__tint--yellow { background: var(--nxt-atrium-log-tint-yellow); }
.nxt-log__tint--blue   { background: var(--nxt-atrium-log-tint-blue); }
.nxt-log__tint--green  { background: var(--nxt-atrium-log-tint-green); }
.nxt-log__tint--pink   { background: var(--nxt-atrium-log-tint-pink); }
.nxt-log__tint--orange { background: var(--nxt-atrium-log-tint-orange); }

/* #515 part B: the timeline, the jumps, folding and gaps. A bar's colour is its worst level, and an Error or Critical
   bar also carries "!"; the chosen bar is pressed and underlined; the focus is an outline, a shape. */
.nxt-log__timeline { margin: 8px 0; }
.nxt-log__bars { display: flex; align-items: stretch; gap: 2px; height: 64px; }
.nxt-log__bar { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; padding: 0 1px; border: 0; border-bottom: 3px solid transparent; background: transparent; cursor: pointer; }
.nxt-log__bar--selected { border-bottom-color: var(--nxt-accent-primary); background: var(--nxt-bg-panel); }
.nxt-log__bar-mark { min-height: 1.2em; line-height: 1.2em; font-weight: 700; color: var(--nxt-semantic-error); text-align: center; }
.nxt-log__bar-area { flex: 1 1 0; display: flex; flex-direction: column; justify-content: flex-end; border-bottom: 2px solid var(--nxt-border-primary); }
.nxt-log__bar-fill { display: block; width: 100%; }
.nxt-log__bar--quiet .nxt-log__bar-fill { background: var(--nxt-text-muted); }
.nxt-log__bar--warning .nxt-log__bar-fill { background: var(--nxt-semantic-warning); }
.nxt-log__bar--error .nxt-log__bar-fill { background: var(--nxt-semantic-error); }
.nxt-log__bar--critical .nxt-log__bar-fill { background: var(--nxt-atrium-log-critical); }
.nxt-log__timeline-ends { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-top: 4px; color: var(--nxt-text-secondary); }
.nxt-log__window { font-weight: 600; color: var(--nxt-text-primary); }
.nxt-log__jumps { align-items: center; gap: 8px; }
.nxt-log__columns { padding-left: 40px; color: var(--nxt-text-secondary); font-size: 0.9em; }
.nxt-log__stamp { display: inline-block; min-width: 13em; }
.nxt-log__since { display: inline-block; min-width: 7em; margin-right: 8px; color: var(--nxt-text-secondary); }
.nxt-log__since--long { color: var(--nxt-semantic-warning); font-weight: 700; }
.nxt-log__columns .nxt-log__level { display: inline-block; min-width: 7em; font-weight: normal; }
.nxt-log__silence { padding: 2px 16px; background: var(--nxt-banner-warn-bg); color: var(--nxt-banner-warn-text); }
.nxt-log__repeats { margin-left: 8px; padding: 0 6px; border: 1px solid var(--nxt-border-primary); border-radius: 9px; font-size: 0.9em; }
.nxt-log__entry--focused { outline: 2px solid var(--nxt-accent-primary); outline-offset: -2px; }

/* #515 part C: follow a value, bookmarks and rule sets. A value a line names is a button drawn as underlined text; the
   value followed is outlined, a shape; a bookmark's star is pressed when set. */
.nxt-log__follow { font: inherit; color: inherit; border: 0; padding: 0; margin: 0; text-decoration: underline; cursor: pointer; }
.nxt-log__follow:not(.nxt-log__highlight):not(.nxt-log__find) { background: transparent; }
.nxt-log__followed { outline: 1.5px solid var(--nxt-accent-primary); outline-offset: 0; }
.nxt-log__follow-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; margin: 8px 0; padding: 4px 8px; border: 1.5px solid var(--nxt-accent-primary); }
.nxt-log__star { position: absolute; left: 0; top: 2px; width: 20px; padding: 0; line-height: 1.3em; border: 1px solid var(--nxt-border-primary); background: transparent; color: inherit; cursor: pointer; }
.nxt-log__star[aria-pressed="true"] { background: var(--nxt-bg-panel); }
.nxt-log__rule-sets-section { border-top: 1px solid var(--nxt-border-primary); margin: 8px 0 0 0; padding: 4px 0 0 0; }
.nxt-log__rule-sets { list-style: none; margin: 0 0 8px 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 8px; }
.nxt-log__rule-set { display: flex; align-items: stretch; gap: 2px; }
.nxt-log__rule-set-apply { text-align: left; }
.nxt-log__rule-set-description { display: block; font-weight: normal; color: var(--nxt-text-secondary); }

/* THE OUTLINED MESSAGE (btsoons/Nxt.Atrium#571): the one style every outcome on the Administration tabs is drawn in,
   the twin of Nxt.OutlinedMessage in ShellTemplates.xaml. OutlinedMessage.razor picks the modifier and the glyph from
   the view-model's tone. Never a filled banner. */
.nxt-outlined-message {
    display: flex;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--nxt-semantic-active);
    border-radius: 5px;
    background: var(--nxt-bg-panel);
    color: var(--nxt-text-primary);
}
.nxt-outlined-message__icon  { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px; color: var(--nxt-semantic-active); }
.nxt-outlined-message__text  { margin: 0; }
.nxt-outlined-message--refusal { border-color: var(--nxt-semantic-error); color: var(--nxt-semantic-error-strong); }
.nxt-outlined-message--refusal .nxt-outlined-message__icon { color: var(--nxt-semantic-error); }
.nxt-outlined-message--warning { border-color: var(--nxt-semantic-warning); }
.nxt-outlined-message--warning .nxt-outlined-message__icon { color: var(--nxt-semantic-warning); }
/* A FACT (#572): the shared blue accent, with nothing to do about it. */
.nxt-outlined-message--neutral { border-color: var(--nxt-accent-secondary); }
.nxt-outlined-message--neutral .nxt-outlined-message__icon { color: var(--nxt-accent-secondary); }

/* THE DANGER BUTTON (btsoons/Nxt.Atrium#571; Bas, 2026-10-04): local, built only from the shared error colours, the
   twin of Nxt.Atrium.DangerButton. */
.nxt-btn.nxt-btn--danger {
    background: var(--nxt-semantic-error);
    background-image: none;
    border-color: var(--nxt-semantic-error-strong);
    color: var(--nxt-text-on-accent);
}
.nxt-btn.nxt-btn--danger:hover:not(:disabled) { background: var(--nxt-semantic-error-strong); }
.nxt-btn.nxt-btn--danger:disabled             { opacity: 0.45; }

/* THE CUSTOMERS TAB (btsoons/Nxt.Atrium#571, the handoff's 3b-01), the twin of CustomersPanelView.xaml: a page of
   cards, one per task, each with its outcome under it. Fields take their card's column (#589). */
.nxt-customers          { display: flex; flex-direction: column; gap: 20px; flex: 1 1 auto; min-width: 0; overflow-y: auto; }
.nxt-customers__heading { margin: 0; font-size: 22px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-customers__intro   { margin: 4px 0 0 0; color: var(--nxt-text-secondary); }
.nxt-customers__top {
    display: grid;
    grid-template-columns: minmax(0, var(--nxt-atrium-field-long)) auto minmax(0, 1fr);
    gap: 12px 16px;
    align-items: end;
}
.nxt-customers__label   { font-size: 13px; font-weight: 500; color: var(--nxt-text-heading); }
.nxt-customers__field   { display: flex; flex-direction: column; gap: 5px; }
.nxt-customers__field > .nxt-admin__input,
.nxt-customers__field > .nxt-admin__hint { margin: 0; }
.nxt-customers__field-head { display: flex; justify-content: space-between; gap: 8px; }
.nxt-customers__hint    { margin: 0; }
.nxt-customers__actions { display: flex; align-items: center; gap: 10px; }
.nxt-customers__mono    { font-family: var(--nxt-font-mono); }
.nxt-customers__summary {
    display: grid;
    grid-template-columns: auto repeat(5, minmax(0, 1fr));
    border: 1px solid var(--nxt-border-primary);
    border-radius: 8px;
    background: var(--nxt-bg-secondary);
}
.nxt-customers__cell       { display: flex; flex-direction: column; gap: 2px; padding: 12px 16px; }
.nxt-customers__cell-label { font: 500 10.5px/1.2 var(--nxt-font-mono); letter-spacing: .09em; text-transform: uppercase; color: var(--nxt-text-secondary); }
.nxt-customers__cell-value { font: 500 15px/1.4 var(--nxt-font-mono); color: var(--nxt-text-heading); }
.nxt-customers__badge {
    align-self: flex-start;
    padding: 1px 8px;
    border-radius: 10px;
    font-weight: 500;
    background: var(--nxt-semantic-active-soft);
    color: var(--nxt-semantic-active-strong);
}
.nxt-customers__badge--suspended { background: var(--nxt-semantic-warning-soft); color: var(--nxt-semantic-warning-strong); }
.nxt-customers__cards   { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-items: start; }
.nxt-customers__stack   { display: flex; flex-direction: column; gap: 16px; }
.nxt-customers__numbers { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 14px; }
.nxt-customers__now     { font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-customers__now--changed { color: var(--nxt-accent-secondary); font-weight: 500; }
/* THE DATE MUST NOT STRETCH: its own width, from the size it is for (#589). */
.nxt-customers__field > .nxt-customers__date { width: var(--nxt-atrium-field-medium); max-width: 100%; }
.nxt-field--changed     { border: 1.5px solid var(--nxt-accent-secondary); }
.nxt-customers__later   { display: flex; flex-direction: column; gap: 12px; padding-top: 20px; border-top: 1px solid var(--nxt-border-primary); }
.nxt-customers__eyebrow { font: 500 11px/1.2 var(--nxt-font-mono); letter-spacing: .09em; text-transform: uppercase; color: var(--nxt-text-secondary); }
.nxt-customers__add     { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }

/* THE ADMINISTRATION SCREEN'S CARD (#571, made every tab's by #574): a 1px edge, radius 8, 20px inside, the panel's
   background - the twin of Nxt.Atrium.Admin.Card in ShellTemplates.xaml. It sets no layout, so a form's grid keeps its own;
   --stack lays a card out as a column. NOT .nxt-card, which is the sign-in card's (Card.razor): #571 spelled this one
   the same, and the later rule rewrote the sign-in card's padding and gave every task card its 375px width. */
.nxt-admin-card        { padding: 20px; border: 1px solid var(--nxt-border-primary); border-radius: 8px; background: var(--nxt-bg-panel); }
.nxt-admin-card--stack { display: flex; flex-direction: column; gap: 14px; }
.nxt-admin-card__title { margin: 0; font-size: 16px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-admin-card__text  { margin: 4px 0 0 0; }

/* A PAGE'S HEADING AND INTRO (#573), as the Customers and Nxt administrators tabs write theirs. */
.nxt-admin-page__heading { margin: 0; font-size: 22px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-admin-page__intro   { margin: 4px 0 0 0; color: var(--nxt-text-secondary); }

/* THE NXT ADMINISTRATORS TAB (btsoons/Nxt.Atrium#572, the handoff's 3b-02), the twin of NxtAdministratorsPanelView.xaml:
   the count and the phones on the left, adding a phone in numbered steps on the right, at 1 : 1.35. Ids and codes are
   in the mono face. */
.nxt-administrators          { display: flex; flex-direction: column; gap: 20px; flex: 1 1 auto; min-width: 0; overflow-y: auto; }
.nxt-administrators__columns { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); gap: 16px; align-items: start; }
.nxt-administrators__mono    { font-family: var(--nxt-font-mono); }
.nxt-administrators__phones  { width: 100%; border-collapse: separate; border-spacing: 0; border: 1px solid var(--nxt-border-primary); border-radius: 8px; background: var(--nxt-bg-panel); }
.nxt-administrators__phones th { padding: 8px 14px; text-align: left; font-weight: 500; color: var(--nxt-text-heading); background: var(--nxt-bg-secondary); border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-administrators__phones td { padding: 8px 14px; vertical-align: top; }
.nxt-administrators__phones td .nxt-admin__hint { margin: 0; }
.nxt-administrators__phone   { font-size: 14px; color: var(--nxt-text-heading); }
.nxt-administrators__code-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; }
.nxt-administrators__code-row > .nxt-admin__input { margin: 0; }
.nxt-administrators__compare { display: flex; flex-direction: column; gap: 8px; padding: 12px 16px; border-radius: 8px; background: var(--nxt-bg-black); }
.nxt-administrators__eyebrow { font: 500 11px/1.2 var(--nxt-font-mono); color: var(--nxt-text-on-accent); opacity: .7; }
.nxt-administrators__groups  { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.nxt-administrators__group   { padding: 4px 6px; text-align: center; font-size: 18px; color: var(--nxt-text-on-accent); border: 1px solid var(--nxt-text-secondary); border-radius: 5px; }
.nxt-administrators__sunken  { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 8px 12px; border-radius: 5px; background: var(--nxt-bg-secondary); color: var(--nxt-text-secondary); }
.nxt-administrators__code    { font-size: 15px; color: var(--nxt-text-heading); }

/* A NUMBERED STEP (#572): a 24px circle - a hairline while to come, a 1.5px accent outline while current, accent-filled
   with a check when done - its title, and its fields indented under it. The state is the view-model's. */
.nxt-step          { display: flex; flex-direction: column; gap: 10px; }
.nxt-step__head    { display: flex; align-items: center; gap: 10px; }
.nxt-step__title   { font-weight: 600; color: var(--nxt-text-heading); }
.nxt-step__body    { display: flex; flex-direction: column; gap: 10px; padding-left: 34px; }
.nxt-step__circle  {
    display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box;
    width: 24px; height: 24px; border-radius: 50%;
    border: 1px solid var(--nxt-border-primary);
    font-size: 12px; font-weight: 600; color: var(--nxt-text-secondary);
}
.nxt-step__circle--current { border: 1.5px solid var(--nxt-accent-secondary); color: var(--nxt-accent-secondary); }
.nxt-step__circle--done    { border-color: var(--nxt-accent-secondary); background: var(--nxt-accent-secondary); color: var(--nxt-text-on-accent); }
.nxt-step__tick            { width: 12px; height: 12px; }
