/*
   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. */
/* THE ONE SCROLLER (btsoons/Nxt.Atrium#781, row 1y): a page taller than the window scrolls here, with nothing declared. A
   column, so a page that scrolls itself (Organisation, App management, View log, the home screen) is given what is left
   under the header with flex and min-height 0, rather than height 100%, which is the whole area again and put a second
   scrollbar beside this one. */
.nxt-shell__content {
    display: flex;
    flex-direction: column;
    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; }
.nxt-shell__entry-badge { margin-left: 6px; padding: 0 6px; border-radius: 8px; font-size: 11px; font-weight: 600;
                          background: var(--nxt-accent-primary); color: var(--nxt-text-on-accent); }
.nxt-shell__new-apps { display: flex; align-items: center; gap: 16px; margin: 0 0 20px; padding: 12px 16px;
                       border: 1px solid var(--nxt-accent-primary); border-radius: 6px; background: var(--nxt-bg-panel); }
.nxt-shell__new-apps-text { flex: 1 1 auto; }
.nxt-shell__new-apps-title { font-weight: 600; margin: 0; }
.nxt-shell__new-apps-body { margin: 4px 0 0; font-size: 13px; color: var(--nxt-text-secondary); }

/* 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;
    flex: 1 1 auto;
    min-height: 0;
    padding: 10px 12px 0;
    background: var(--nxt-bg-panel);
}

/* One line at the left (#1050, row 9i) 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;
    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; }

/* 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); }
/* SET APART (nxttechnology/Nxt.Atrium#887, drawing 8b-04), the twins of the WPF strip template's triggers: the one divider
   before the first entry whose route declares an audience, and that entry's face near-black with its audience under the
   icon. The frame and the size are unchanged, and so is the current tile's accent border. */
.nxt-shell__admin-divider { width: 1px; align-self: stretch; margin: 10px 8px; background: var(--nxt-atrium-page-rule-color); }
.nxt-btn.nxt-shell__admin-tile--set-apart:not(:disabled) { background: var(--nxt-bg-black); color: var(--nxt-text-on-accent); }
.nxt-btn.nxt-shell__admin-tile--set-apart:not(.nxt-shell__admin-tile--current):not(:disabled) { border-color: var(--nxt-bg-black); }
.nxt-btn.nxt-shell__admin-tile--set-apart:hover:not(:active):not(:disabled) {
    background: color-mix(in srgb, var(--nxt-bg-black) 85%, var(--nxt-text-on-accent));
}
.nxt-shell__admin-tile-audience {
    margin-top: 4px;
    font-family: var(--nxt-font-mono);
    font-size: 9px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    opacity: 0.75;
}
.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; }

/* CENTRED in the tiles area, the one exception to 9i on the home (Bas, 2026-10-24, #1186, 1f.1): an empty state is not
   content to work on. The picker is a column only while it is empty, so a home with tiles lays out as before; the
   auto margin takes what the attention panel leaves, on both axes. The twin of EmptyState in ShellHomeView.xaml. */
.nxt-shell__picker--empty  { display: flex; flex-direction: column; }
.nxt-shell__empty          { max-width: 520px; margin: auto; display: flex; flex-direction: column; align-items: center; text-align: center; }
.nxt-shell__empty-icon     { font-size: 48px; line-height: 1; }
.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;
}

/* The signing-key notice on the status bar (btsoons/Nxt.Atrium#543 slice 2d, FR-7). WARNING and never error, for
   the licence notice's reason: a key that is ending has stopped nothing yet. The twin is the Nxt.Semantic.Warning
   foreground in ShellStatusBarView.xaml. Every colour is an --nxt-* token (C3). */
.nxt-shell__status-signing-key {
    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;
    flex: 1 1 auto;
    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. #781 FR-2: each tab's page scrolls inside the panel, under the strip, as the WPF tabs do. */
.nxt-admin__tabs { flex: 1 1 auto; min-height: 0; }
.nxt-admin__tabs > .nxt-tabs__panel { display: flex; min-height: 0; padding: 0; overflow: auto; }

/* 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#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-head-audience { white-space: nowrap; }
.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; }
/* #25 FR-021: a station at a site that is unknown or out of use is said in the warning colour, never as "not at a site". */
.nxt-admin__site          { margin: 0 0 4px 0; }
.nxt-admin__site--problem { color: var(--nxt-semantic-warning-strong); font-weight: 600; }
.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; max-width: 160px; }

/* #1092: why Add or Remove is off, said right under it. */
.nxt-admin__shuttle-reason { margin: -4px 0 0; font-size: 11px; }

.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; }
.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; }
.nxt-licence__hosting { margin: 12px 0 0; color: var(--nxt-text-secondary); }

/* 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;
    flex: 1 1 auto;
    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. */

/* The column the screen's parts stack in. Organisation keys is a tab of Nxt centre, whose body already insets it by the
   page padding, so its root is not .nxt-admin, whose own 16px doubled that inset (nxttechnology/Nxt.Atrium#886). */
.nxt-keys { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; gap: 12px; }

.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); }

/* #885 (row 10m.35): the withdraw reasons as radio cards, mildest first; the chosen one on the soft brand fill. The
   twin is the RadioButton template in OrganisationKeysView.xaml. */
.nxt-keys__reasons { border: 0; margin: 0 0 4px 0; padding: 0; min-width: 0; }

.nxt-keys__reason {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 0 10px;
    align-items: start;
    margin: 0 0 8px 0;
    padding: 10px 12px;
    border: 1.5px solid var(--nxt-border-primary);
    border-radius: 8px;
    background: var(--nxt-bg-panel);
    cursor: pointer;
}
.nxt-keys__reason > input[type="radio"] { margin: 3px 0 0 0; accent-color: var(--nxt-accent-primary); }
.nxt-keys__reason--chosen { border-color: var(--nxt-accent-primary); background: var(--nxt-accent-secondary-soft); }
.nxt-keys__reason:focus-within { outline: 2px solid var(--nxt-accent-primary); outline-offset: 1px; }

.nxt-keys__reason-caption     { display: block; font-size: 15px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-keys__reason-consequence { display: block; margin-top: 2px; color: var(--nxt-text-secondary); }
.nxt-keys__reason-mistake     { display: block; margin-top: 6px; font-style: italic; color: var(--nxt-text-secondary); }

.nxt-badge--warning { background: var(--nxt-semantic-warning-soft); color: var(--nxt-semantic-warning-strong); }
.nxt-badge--error   { background: var(--nxt-semantic-error-soft); color: var(--nxt-semantic-error-strong); }

/* The date and what it means for the chosen reason, side by side; the button and why it waits, on one row. */
.nxt-keys__beside { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center; }
.nxt-keys__beside > .nxt-admin__hint { flex: 1 1 260px; margin: 0; }
.nxt-keys__withdraw-row { flex-wrap: wrap; align-items: center; }
.nxt-keys__withdraw-row > .nxt-admin__hint { flex: 1 1 260px; margin: 0 0 0 4px; }

/* The guided flow (btsoons/Nxt.Atrium#783, row 10m.28), one step open at a time (#882, row 10m.32): the steps on
   the left, what is being certified on the right, the shell's host scrolling. A done step is one row with its answer
   and Change; the open step is a card with a 1.5px accent edge; a waiting step is one dashed, muted row. Twin of the
   WPF view's Step style. */
.nxt-keys__layout { display: flex; gap: 24px; align-items: flex-start; }

.nxt-keys__flow { flex: 1 1 auto; min-width: 0; }

.nxt-keys__aside { flex: 0 0 300px; max-width: 100%; }

@media (max-width: 900px) {
    .nxt-keys__layout { flex-direction: column; }
    .nxt-keys__aside  { flex-basis: auto; width: 100%; }
}

.nxt-keys__job { margin: 0; font-size: 22px; font-weight: 600; color: var(--nxt-text-heading); }

.nxt-keys__intro { margin: 6px 0 16px 0; font-size: 13.5px; color: var(--nxt-text-secondary); }

.nxt-keys__replacing { margin: 0 0 12px 0; font-size: 16px; font-weight: 600; color: var(--nxt-text-heading); }

/* A step is a hand-over step (#922, row 9h): its frame is .nxt-handover-step; these are its answer and its explanation. */
.nxt-keys__answer { font-size: 14px; overflow-wrap: anywhere; }

.nxt-keys__step-explanation { margin: 0; }

/* An eyebrow: mono, small, upper case. */
.nxt-keys__eyebrow {
    margin: 0;
    font-family: var(--nxt-font-mono);
    font-size: 10.5px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--nxt-text-secondary);
}

/* An answer's parts (#882 FR-1); twin of AnswerText in the WPF renderer. */
.nxt-keys__part--strong    { font-weight: 600; }
.nxt-keys__part--secondary { color: var(--nxt-text-secondary); }
.nxt-keys__part--mono      { font-family: var(--nxt-font-mono); }

/* The right column (#882 FR-4). */
.nxt-keys__aside-card {
    margin: 0 0 12px 0;
    padding: 14px 16px;
    border: 1px solid var(--nxt-border-primary);
    border-radius: 8px;
    background: var(--nxt-bg-panel);
}

.nxt-keys__certifying { margin: 6px 0 0 0; font-size: 14px; }

.nxt-keys__certifying-groups { margin: 6px 0 0 0; display: flex; flex-wrap: wrap; gap: 4px 8px; }

.nxt-keys__group { font-family: var(--nxt-font-mono); font-size: 12px; }

.nxt-keys__compact-row { margin: 6px 0 8px 0; }

.nxt-keys__compact-name     { display: block; font-weight: 600; }
.nxt-keys__compact-key      { display: block; font-family: var(--nxt-font-mono); font-size: 12px; }
.nxt-keys__compact-standing { display: block; font-size: 12px; color: var(--nxt-text-secondary); }

.nxt-keys__compact-standing--in-force { color: var(--nxt-semantic-active-strong); }

/* A button that reads as a link: Change, and the way to the full list. */
.nxt-btn.nxt-btn--link {
    min-height: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--nxt-accent-primary);
    font-weight: 400;
    cursor: pointer;
}

.nxt-btn.nxt-btn--link:hover { text-decoration: underline; }

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

.nxt-keys__choice-word        { font-weight: 600; }
.nxt-keys__choice-explanation { display: block; color: var(--nxt-text-secondary); }

.nxt-keys__vouch { margin: 0 0 8px 0; font-weight: 600; }

/* #922: the seven steps are hand-over steps, one under the other; step 6 has the Key name beside what it certifies. */
.nxt-keys__flow > div[data-step] { margin: 0 0 10px 0; }
.nxt-keys__certify      { display: flex; flex-wrap: wrap; gap: 12px 28px; align-items: flex-start; }
.nxt-keys__certify .nxt-keys__vouch { flex: 1 1 260px; margin: 0; }
.nxt-keys__certify-name { flex: 0 1 auto; padding: 12px 14px; border-radius: 5px; background: var(--nxt-bg-base); }
.nxt-keys__certify-name .nxt-keys__group { font-size: 20px; font-weight: 700; letter-spacing: .06em; }

/* #884 FR-3: how the key gets here - Type it, and Read it from Nxt Vault shown and not offered, its reason beside it. */
/* #785 D-2: the scanning block leads the open step; the code beside its four numbered instructions. */
.nxt-keys__scan { margin: 0 0 14px 0; padding: 0 0 12px 0; border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-keys__scan-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px 20px; margin: 0 0 8px 0; }
.nxt-keys__scan-row .nxt-phones__code { width: 200px; height: 200px; flex: none; }
.nxt-keys__scan-steps { margin: 0; padding-left: 20px; max-width: 420px; }
.nxt-keys__scan-steps li { margin: 0 0 6px 0; }
.nxt-keys__scan .nxt-btn { margin: 4px 0 6px 0; }

/* #944 FR-5: Use this Organisation key, with the reason beside it while it cannot be pressed. The field is the shared
   one (.nxt-handover), whose groups wrap whole. */
.nxt-keys__use-key { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 12px 0 0 0; }
.nxt-keys__use-key-reason { color: var(--nxt-text-secondary); }

.nxt-keys__fingerprint-label { margin: 8px 0 2px 0; font-weight: 600; }

/* Step 5, the call (#883, row 10m.33): who to call, the script beside the four groups in a 280px well, and the
   checkbox. Twin of the WPF view's step 5. */
.nxt-keys__badge-glyph { width: 16px; height: 16px; fill: currentColor; }

.nxt-keys__part--stop { color: var(--nxt-semantic-error-strong); }

.nxt-keys__who {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0 16px;
    padding: 12px 16px;
    border-radius: 5px;
    background: var(--nxt-surface-standard);
}

.nxt-keys__contact-name { margin: 4px 0 0 0; font-size: 18px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-keys__contact-role { margin: 2px 0 0 0; font-size: 13px; color: var(--nxt-text-secondary); }

.nxt-keys__who-number { text-align: right; }
.nxt-keys__direct-number { margin: 0; font-family: var(--nxt-font-mono); font-size: 22px; }
.nxt-keys__direct-kind { margin: 0 0 8px 0; font-size: 12px; color: var(--nxt-text-secondary); }

.nxt-keys__contact-source { grid-column: 1 / span 2; margin: 10px 0 0 0; font-size: 12px; color: var(--nxt-text-secondary); }

.nxt-keys__call { display: flex; gap: 16px; align-items: flex-start; margin: 14px 0 0 0; }

.nxt-keys__script { flex: 1 1 auto; min-width: 0; margin: 0; padding: 0; list-style: none; }
.nxt-keys__script-line { display: flex; gap: 8px; margin: 0 0 10px 0; }
.nxt-keys__script-number {
    flex: 0 0 12px;
    font-family: var(--nxt-font-mono);
    font-weight: 600;
    color: var(--nxt-accent-primary);
}

.nxt-keys__groups { flex: 0 0 280px; padding: 12px; border-radius: 5px; background: var(--nxt-surface-standard); }
.nxt-keys__groups-note { margin: 0; font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-keys__groups-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 8px 0; }
.nxt-keys__groups-cell {
    padding: 4px 6px;
    border: 1px solid var(--nxt-border-primary);
    border-radius: 4px;
    background: var(--nxt-bg-panel);
    font-family: var(--nxt-font-mono);
    font-size: 26px;
    text-align: center;
}

.nxt-keys__called { display: flex; gap: 10px; align-items: flex-start; margin: 14px 0 0 0; cursor: pointer; }
.nxt-keys__called-box {
    flex: 0 0 20px;
    width: 20px;
    height: 20px;
    margin: 1px 0 0 0;
    accent-color: var(--nxt-accent-primary);
    outline: 1.5px solid var(--nxt-accent-primary);
    outline-offset: -1.5px;
}
.nxt-keys__called-label { font-size: 15px; font-weight: 600; }
.nxt-keys__called-box:disabled + .nxt-keys__called-label { color: var(--nxt-text-secondary); }
.nxt-keys__called-note { margin: 4px 0 0 30px; font-size: 12.5px; }

@media (max-width: 700px) {
    .nxt-keys__call { flex-direction: column; }
    .nxt-keys__groups { flex-basis: auto; width: 100%; box-sizing: border-box; }
}

.nxt-keys__withdraw {
    margin: 0 0 12px 0;
    padding: 14px 16px;
    border: 1.5px solid var(--nxt-semantic-error);
    border-radius: 12px;
    background: var(--nxt-bg-panel);
}

.nxt-keys__rows { list-style: none; margin: 0; padding: 0; }

.nxt-keys__row { margin: 0 0 6px 0; padding: 8px 10px; border: 1px solid var(--nxt-border-primary); }

.nxt-keys__row-facts { display: flex; flex-wrap: wrap; gap: 4px 16px; }

.nxt-keys__row .nxt-keys__row-fingerprint { display: inline; }

/* ── 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 (MyPhones.razor); laid out as the Add my
   phone design handoff draws them (#644, rows 2n.14, retired, and 2n.23.15, 2n.23.16, 2n.21.17, 2n.22.18), and My phones (#937, row 2n.22.20). 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__key-label { display: block; font-size: 11px; letter-spacing: .09em; text-transform: uppercase; color: var(--nxt-text-secondary); }
.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); }

/* My phones' own layout (#644, #937). 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__start { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin-top: 20px; }
.nxt-add-phone__steps { display: flex; flex-direction: column; gap: 12px; margin-top: 24px; }

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

.nxt-add-phone__actions        { margin-top: 16px; }

.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; }

/* #937: the Key name compared with Nxt Sign's, and the phone's name, before the two buttons. */
.nxt-add-phone__compare  { display: flex; flex-direction: column; gap: 8px; padding-top: 14px; border-top: 1px solid var(--nxt-border-primary); }
.nxt-add-phone__key-name { font-size: 18px; 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 > .nxt-outlined-message { margin-top: 12px; }

/* #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); }

/* #1102: the same code inside a page starts at the left (#1050); the sign-in card above centres it on purpose. */
.nxt-reading-confirmation__phone .nxt-signin__code-frame { margin: 0; }
.nxt-reading-confirmation__phone .nxt-signin__countdown  { justify-content: flex-start; }

/* #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); }
/* #835 FR-10.4, FR-10.3: the row where a report was made, and the log a merged line came from. */
.nxt-log__moment { padding: 4px 8px; margin: 2px 0; border-left: 3px solid var(--nxt-accent-primary); background: var(--nxt-bg-panel); font-weight: 600; }
.nxt-log__moment-glyph { color: var(--nxt-accent-primary); margin-right: 6px; }
.nxt-log__moment .nxt-log__stamp { font-weight: 400; margin-left: 8px; }
.nxt-log__log-name { color: var(--nxt-text-secondary); border: 1px solid var(--nxt-border-primary); padding: 0 6px; margin-right: 8px; }
.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; }
/* #835 FR-10.4: the slice a report was made in; its caption says so as well. */
.nxt-log__bar-moment { line-height: 1.2em; font-weight: 700; color: var(--nxt-accent-primary); 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 PRIMARY BUTTON'S HOVER (btsoons/Nxt.Atrium#1001). controls.css styles every bare button's hover with
   `button:hover:not(:disabled) { background: var(--nxt-btn-hover) }`, which outranks `.nxt-btn--primary`'s face, so a
   primary button turned near-white under the mouse with its white text. The hover is the gradient's darkest stop,
   solid and opaque, which keeps the white text at 5.2:1; controls.css's own 0.88 opacity would leave it near 3:1. */
.nxt-btn.nxt-btn--primary:hover:not(:disabled) {
    background: var(--nxt-btn-primary-end);
    opacity: 1;
}

/* 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__hosting { border: 0; margin: 0 0 14px; padding: 0; min-width: 0; }
.nxt-customers__hosting > legend { padding: 0; width: 100%; }
.nxt-customers__choice  { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--nxt-text-primary); }
.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__list    { max-width: 760px; }
.nxt-administrators__task    { max-width: 880px; }
.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; }
/* The Added column grows rather than wrapping its second line, so every row's date starts in one place (#1050). */
.nxt-administrators__phones td + td { white-space: nowrap; }
.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; }
/* #941: the label ABOVE the code, never beside it, so the code cannot cover it at any width. */
.nxt-administrators__sunken  { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; 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 CODE IN GROUPS (#941), CodeInGroups.razor: a group never breaks, so the code wraps only at the spaces between them. */
.nxt-code-groups__group { white-space: nowrap; }
/* Ligatures off (#946 FR-1): a code is read character by character, and a ligature joins two. 'none' also turns off
   contextual forms, which is how JetBrains Mono joins two hyphens or two underscores. */
.nxt-code-groups { font-variant-ligatures: none; }

/* THE HAND-OVER BLOCK (#946, rows 9f and 9f.1), HandOverValue.razor and HandOverField.razor, the twins of
   HandOverValueView.xaml and HandOverFieldView.xaml: the name above the value, never on its line; the value and the
   Key name in groups that wrap whole; the typed field grows to as many lines as the value needs. */
.nxt-handover                { display: flex; flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; }
.nxt-handover__name          { font-size: 14px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-handover__meta          { font: 11.5px/1.3 var(--nxt-font-mono); color: var(--nxt-text-secondary); }
.nxt-handover__value         { font: 20px/1.4 var(--nxt-font-mono); color: var(--nxt-text-heading); }
.nxt-handover__key-name-value { font: 700 20px/1.4 var(--nxt-font-mono); color: var(--nxt-accent-secondary); }
.nxt-handover__key-name      { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.nxt-handover__actions       { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.nxt-handover__choices       { display: flex; flex-wrap: wrap; gap: 6px; }
.nxt-handover__choice        { font-family: var(--nxt-font-mono); font-variant-ligatures: none; }
.nxt-handover__spelled       { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.nxt-handover__character     { display: inline-block; width: 32px; font: 700 22px var(--nxt-font-mono); font-variant-ligatures: none; color: var(--nxt-text-heading); }
.nxt-handover__spelling      { font-size: 13px; color: var(--nxt-text-secondary); }
.nxt-handover__field         { margin: 0; font: 16px var(--nxt-font-mono); font-variant-ligatures: none; resize: none; field-sizing: content; min-height: 2.2em; overflow: hidden; }
/* #944 FR-1, FR-2 (rows 9f.1.1, 9f.1.2): the typed field's groups, numbered and wrapping whole; its refusal, selectable,
   with Copy. The twin of HandOverFieldView.xaml. */
.nxt-code-groups--numbered   { display: flex; flex-wrap: wrap; gap: 4px 10px; }
.nxt-code-groups__numbered   { display: inline-flex; flex-direction: column; align-items: center; }
.nxt-code-groups__number     { font-size: 10px; line-height: 1.2; color: var(--nxt-text-secondary); }
.nxt-handover__refusal       { align-items: flex-start; }
.nxt-handover__refusal-text  { display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; min-width: 0; user-select: text; }
.nxt-handover__refusal-problem { font-weight: 600; }
.nxt-handover__refusal-next  { color: var(--nxt-text-primary); }
.nxt-handover__refusal-copied { margin: 0; font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-handover__refusal-copy  { flex: 0 0 auto; }

/* THE NXT SUPPORT TAB (btsoons/Nxt.Atrium#548 FR-9, row 12c), the twin of NxtSupportPanelView.xaml: the open records
   on the left, each a card, and the card that records a start on the right. A record not closed is a warning line. */
.nxt-support             { display: flex; flex-direction: column; gap: 20px; flex: 1 1 auto; min-width: 0; overflow-y: auto; }
.nxt-support__columns    { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.nxt-support__title      { margin: 0; font-size: 16px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-support__cells      { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto; gap: 12px; align-items: start; }
.nxt-support__cells .nxt-admin__hint { margin: 0; }
.nxt-support__label      { margin-bottom: 2px; font: 10.5px var(--nxt-font-mono); color: var(--nxt-text-secondary); }
.nxt-support__value      { font-family: var(--nxt-font-mono); color: var(--nxt-text-heading); }
.nxt-support__why        { margin: 0; white-space: pre-wrap; }
.nxt-support__not-closed { margin: 0; font-weight: 500; color: var(--nxt-semantic-warning-strong); }

/* #1304 (row 10w): the agreement's compose form is the two-column grid of NxtAgreementsPanelView.xaml. The four
   checkboxes of what a version carries sit in the field column, under a label read from their top. */
.nxt-admin__detail > .nxt-agreements__carries { grid-column: 2; display: flex; flex-direction: column; margin-bottom: 8px; }
.nxt-admin__detail > .nxt-agreements__carries .nxt-admin__check { margin: 2px 0; }
.nxt-admin__detail > .nxt-agreements__top-label { align-self: start; padding-top: 6px; }

/* 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; }
.nxt-step__circle--refused { border-color: var(--nxt-semantic-error); background: var(--nxt-semantic-error); color: var(--nxt-text-on-accent); }

/* A HAND-OVER STEP (#947, row 9h), HandOverStep.razor, the twin of the WPF style Nxt.Atrium.HandOverStep: one framed
   block per step; the open one outlined in the accent; its head is the circle, the title, the line beside it and, on a
   done step, Reopen at the far end. A waiting step is its head alone. */
.nxt-handover-step          { display: flex; flex-direction: column; gap: 12px; padding: 18px 20px; border: 1px solid var(--nxt-border-primary); border-radius: 8px; background: var(--nxt-bg-panel); min-width: 0; }
.nxt-handover-step--open    { border-color: var(--nxt-accent-secondary); box-shadow: 0 0 0 1px var(--nxt-accent-secondary); }
.nxt-handover-step__head    { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.nxt-handover-step__title   { font-size: 14px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-handover-step__meta    { font: 11.5px/1.3 var(--nxt-font-mono); color: var(--nxt-text-secondary); }
.nxt-handover-step__reopen  { margin-left: auto; }
.nxt-handover-step__confirm { display: flex; flex-direction: column; gap: 8px; }
.nxt-handover-step__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.nxt-handover-step__body    { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.nxt-handover-step__aloud   { display: flex; flex-direction: column; gap: 6px; }

/* OUR SIGNING KEY IN FOUR STEPS (#948, row 3l.3): the overview of every key, and the parts of a key's task below. */
.nxt-our-key               { display: flex; gap: 32px; align-items: flex-start; flex-wrap: wrap; }
.nxt-our-key__main         { flex: 1 1 480px; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.nxt-our-key__intro        { margin: 0; font-size: 15px; }
/* #1223: the success box at the top of the overview, an outlined message with a heading, a sentence and one OK. */
.nxt-our-key__success          { align-items: flex-start; }
.nxt-our-key__success-text     { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.nxt-our-key__success-text > p { margin: 0; }
.nxt-our-key__success-heading  { font-size: 15px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-our-key__success-ok       { flex: 0 0 auto; }
/* #1221: every key a card — what it is for, its two keys, and its chip with its one button — stacked; the card whose
   button is the page's primary is outlined in the warning colour. The three parts wrap under each other where the card
   is too narrow for them side by side, so no width needs a rule of its own. */
.nxt-our-key__cards        { display: flex; flex-direction: column; gap: 12px; }
.nxt-our-key__card         { display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: flex-start; padding: 16px 18px; border: 1px solid var(--nxt-border-primary); border-radius: 6px; background: var(--nxt-bg-panel); }
.nxt-our-key__card--primary { border: 1.5px solid var(--nxt-semantic-warning); }
.nxt-our-key__card > .nxt-outlined-message { flex: 1 1 100%; }
.nxt-our-key__card-what    { flex: 1 1 280px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.nxt-our-key__card-what > * { margin: 0; }
.nxt-our-key__card-keys    { flex: 0 1 230px; margin: 0; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.nxt-our-key__card-key dt  { font-size: 12.5px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-our-key__card-key dd  { margin: 2px 0 0 0; display: flex; flex-direction: column; gap: 2px; }
.nxt-our-key__where        { font-weight: 400; color: var(--nxt-text-secondary); font-size: 12px; }
.nxt-our-key__none         { color: var(--nxt-text-secondary); font-size: 12.5px; }
.nxt-our-key__card-act     { flex: 0 1 250px; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; text-align: right; min-width: 0; }
.nxt-our-key__card-act p   { margin: 0; }
.nxt-our-key__leaked       { align-self: flex-start; }
/* #1225 (row 3l.14.5): step 3 is a card - the rail of parts beside the part shown, the part in a region of its own that
   scrolls, and Back and the primary in a footer outside it that stays in view: sticky to the bottom of the window when
   the page around it scrolls. Where the card is under 920px the rail folds into its one line (FR-7), the twin of the WPF
   view's PartRailFoldWidth: this measures the whole card, which is 947px in a 1280 window, and 960 folded it there. */
.nxt-our-key__part-card      { container-type: inline-size; display: flex; flex-direction: column; border: 1px solid var(--nxt-border-primary); border-radius: 8px; background: var(--nxt-bg-panel); min-width: 0; }
.nxt-our-key__part-card-head { display: flex; flex-direction: column; gap: 4px; padding: 16px 20px 12px; border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-our-key__part-card-lead { margin: 0; color: var(--nxt-text-secondary); }
.nxt-our-key__part-card-body { display: flex; gap: 24px; padding: 16px 20px; min-width: 0; }
.nxt-our-key__rail           { flex: 0 0 220px; list-style: none; margin: 0; padding: 0 16px 0 0; display: flex; flex-direction: column; gap: 14px; border-right: 1px solid var(--nxt-border-primary); }
.nxt-our-key__rail-part      { display: flex; gap: 10px; align-items: flex-start; }
.nxt-our-key__rail .nxt-step__circle { flex: none; width: 24px; height: 24px; font-size: 12px; }
.nxt-our-key__rail .nxt-step__circle--current { background: var(--nxt-accent-secondary); color: var(--nxt-text-on-accent); }
.nxt-our-key__rail-text      { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.nxt-our-key__rail-label     { font: 11px/1.3 var(--nxt-font-mono); color: var(--nxt-text-secondary); }
.nxt-our-key__rail-name      { font-size: 13.5px; font-weight: 600; color: var(--nxt-text-primary); }
.nxt-our-key__rail-part--here .nxt-our-key__rail-name { font-weight: 700; color: var(--nxt-accent-secondary); }
/* #1227: the part They are different was pressed on, while its stop page is shown. */
.nxt-our-key__rail .nxt-step__circle--stopped { border: 1.5px solid var(--nxt-semantic-error); background: var(--nxt-semantic-error); color: var(--nxt-text-on-accent); }
.nxt-our-key__rail-part--stopped .nxt-our-key__rail-name { font-weight: 700; color: var(--nxt-semantic-error); }
.nxt-our-key__stop-lead { font-weight: 600; margin: 0 0 8px; }
.nxt-our-key__rail-phone     { font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-our-key__part-line      { display: none; margin: 0; font: 12px/1.3 var(--nxt-font-mono); color: var(--nxt-text-secondary); }
.nxt-our-key__part-page      { --nxt-our-key-part-height: max(240px, calc(100vh - 420px)); flex: 1 1 auto; min-width: 0; max-height: var(--nxt-our-key-part-height); overflow: auto; display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.nxt-our-key__part-heading   { margin: 0; font-size: 17px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-our-key__part-footer    { position: sticky; bottom: 0; display: flex; align-items: center; gap: 12px; padding: 12px 20px; border-top: 1px solid var(--nxt-border-primary); background: var(--nxt-bg-panel); border-radius: 0 0 8px 8px; }
.nxt-our-key__part-footer-gap { flex: 1 1 auto; }
.nxt-our-key__part-footer-says { margin: 0; }
@container (max-width: 919px) {
    .nxt-our-key__part-card .nxt-our-key__part-card-body { flex-direction: column; }
    .nxt-our-key__part-card .nxt-our-key__rail      { display: none; }
    .nxt-our-key__part-card .nxt-our-key__part-line { display: block; }
}
.nxt-our-key__page-body    { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
/* #1226 (row 3l.14.6): parts 2 and 3 put a drawing of the Nxt Vault screen beside the Key name; where the part is too
   narrow for both it wraps under the name, the twin of the WPF view's WrapRow. The ring is the primary button's own border
   colour, so it is the same blue as every primary. */
.nxt-our-key__compare       { display: flex; flex-wrap: wrap; gap: 16px 28px; align-items: flex-start; align-self: stretch; }
.nxt-our-key__compare-name  { flex: 1 1 320px; min-width: 0; }
/* #1226: the drawing scales with the part's height, never above its own size: every length in the phone is in em, and its
   font size is the part's height less the heading and the caption, over the phone's height in em, so the whole phone and
   its ring are in view without scrolling the part. 1.65px is WPF's MinScale of 0.15 on 11px. */
.nxt-vault-screen           { flex: 0 1 260px; max-width: 280px; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.nxt-vault-screen__phone    { font-size: clamp(1.65px, calc((var(--nxt-our-key-part-height, 100vh) - 110px) / 35), 11px); width: 21.6em; max-width: 100%; box-sizing: border-box; border: .55em solid var(--nxt-text-secondary); border-radius: 2em; padding: .9em 1.27em 1.45em; background: var(--nxt-bg-panel); }
.nxt-vault-screen__app      { text-align: center; font-size: 1em; font-weight: 600; color: var(--nxt-text-secondary); margin: 0 0 .9em; }
.nxt-vault-screen__title    { margin: 0; font-size: 1.27em; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-vault-screen__says     { font-size: 1.05em; margin: .36em 0 .73em; }
.nxt-vault-screen__rows     { margin: 0 0 .73em; padding: .73em .9em .18em; border: .09em solid var(--nxt-border-primary); border-radius: .55em; }
.nxt-vault-screen__rows dt  { font-size: .95em; color: var(--nxt-text-secondary); }
.nxt-vault-screen__rows dd  { margin: 0 0 .55em; }
.nxt-vault-screen__value    { font: 1.05em/1.3 var(--nxt-font-mono); overflow-wrap: anywhere; }
.nxt-vault-screen__key-name { font-size: 1.18em; font-weight: 700; color: var(--nxt-accent-secondary); }
.nxt-vault-screen__button   { display: block; margin: .64em .27em .27em; padding: .45em .73em; border: .09em solid var(--nxt-border-primary); border-radius: .64em; background: var(--nxt-bg-panel); font-size: 1.05em; font-weight: 600; text-align: center; }
.nxt-vault-screen__button--ringed { outline: .23em solid var(--nxt-btn-primary-border); outline-offset: .27em; }
.nxt-vault-screen__caption  { font-size: 11.5px; color: var(--nxt-text-secondary); }
.nxt-our-key__fallback     { display: flex; flex-direction: column; gap: 6px; align-self: stretch; max-width: 720px; }
/* #1228 (row 3l.14.8): part 1 typed, in place of the code; the request line with its one Copy beside it. */
.nxt-our-key__type-heading { margin: 0; font-size: 15px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-our-key__type-says    { margin: 0 0 6px; }
.nxt-our-key__request-line { display: flex; gap: 8px; align-items: flex-start; }
.nxt-our-key__request-line textarea { flex: 1 1 auto; min-width: 0; }
.nxt-our-key__part-title   { font-size: 14px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-our-key__code         { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.nxt-our-key__code .nxt-phones__code { width: 200px; height: 200px; }
.nxt-our-key__typing       { display: flex; flex-direction: column; gap: 6px; }
/* #999: the code Nxt Sign scans, with its sentence beside it. */
.nxt-our-key__drop        { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
.nxt-our-key__drop .nxt-phones__code { width: 160px; height: 160px; flex: none; }
.nxt-our-key__phone-order  { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.nxt-our-key__phone-order p { margin: 0; }
.nxt-our-key__eyebrow      { font: 11px/1.3 var(--nxt-font-mono); letter-spacing: 0.09em; text-transform: uppercase; color: var(--nxt-text-secondary); }
/* #1229: waiting on parts 4 and 5, said in words beside an indicator that stands still where motion is reduced (FR-7). */
.nxt-our-key__ready        { margin: 0; font-weight: 600; color: var(--nxt-semantic-active-strong); }
.nxt-our-key__waiting      { align-self: stretch; max-width: 720px; display: flex; flex-direction: column; gap: 6px; padding: 12px 16px; border: 1px solid var(--nxt-border-primary); border-radius: 6px; background: var(--nxt-bg-panel); }
.nxt-our-key__waiting > p  { margin: 0; }
.nxt-our-key__waiting-line { margin: 0; display: flex; align-items: center; gap: 10px; font-weight: 600; }
.nxt-our-key__waiting-heading { color: var(--nxt-text-heading); }
.nxt-our-key__indicator    { flex: none; display: block; width: 96px; height: 4px; border-radius: 2px; background: var(--nxt-accent-primary); transform: scaleX(0.4); transform-origin: left; }
@media (prefers-reduced-motion: no-preference) {
    .nxt-our-key__indicator { animation: nxt-shell-tile-progress 1.2s ease-in-out infinite; }
}

/* A KEY'S TASK (#1224, row 3l.14.4), the twin of the WPF view's Steps panel: the title with Close on its right, the four
   steps as one row under it, and the open step's own content in a panel under the row. */
.nxt-our-key-task          { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.nxt-our-key__head         { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.nxt-our-key__task-what    { margin: -12px 0 0; color: var(--nxt-text-secondary); }
.nxt-our-key__title        { flex: 1 1 auto; margin: 0; font-size: 22px; font-weight: 600; color: var(--nxt-text-heading); }
.nxt-our-key__open         { display: flex; flex-direction: column; gap: 12px; padding: 18px 20px; border-radius: 8px; }
/* THE TRACK (FR-2, FR-7): four columns in one row, equal unless a name needs more, which the WPF twin's StepTrackPanel
   does the same way. A name never wraps; the line under it wraps to its column and never widens it (contain); where a
   quarter is under 230px - the WPF twin's TrackStepLeastWidth - every line goes, so the names stay whole. */
.nxt-our-key__track        { container-type: inline-size; display: grid; grid-template-columns: repeat(4, minmax(max-content, 1fr));
                             list-style: none; margin: 0; padding: 0; }
.nxt-our-key__track-step   { display: grid; grid-template-columns: 28px max-content minmax(0, 1fr); column-gap: 10px;
                             align-items: center; min-width: 0; padding-right: 8px; }
.nxt-our-key__track-step::after { content: ""; grid-row: 1; grid-column: 3; height: 2px; background: var(--nxt-border-primary); }
.nxt-our-key__track-step:last-child::after { visibility: hidden; }
.nxt-our-key__track-step--done::after { background: var(--nxt-accent-secondary); }
.nxt-our-key__track .nxt-step__circle { grid-row: 1; grid-column: 1; width: 28px; height: 28px; font-size: 13px; }
.nxt-our-key__track .nxt-step__circle--current { background: var(--nxt-accent-secondary); color: var(--nxt-text-on-accent); }
.nxt-our-key__track-name   { grid-row: 1; grid-column: 2; white-space: nowrap; font-size: 14px; font-weight: 600; color: var(--nxt-text-primary); }
.nxt-our-key__track-step--here .nxt-our-key__track-name { font-weight: 700; color: var(--nxt-accent-secondary); }
.nxt-our-key__track-line   { grid-row: 2; grid-column: 2 / 4; contain: inline-size; margin-top: 2px; font-size: 12px; color: var(--nxt-text-secondary); }
@container (max-width: 919px) {
    .nxt-our-key__track .nxt-our-key__track-line { display: none; }
}
/* #1222 (row 3l.14.2): Words on this page, beside the overview, and wrapped under it where the two do not fit; its text breaks inside it rather than run out. */
.nxt-our-key__words        { flex: 0 1 300px; min-width: 0; display: flex; flex-direction: column; gap: 10px; overflow-wrap: anywhere; }
.nxt-our-key__word-list    { margin: 0; display: flex; flex-direction: column; gap: 10px; }
.nxt-our-key__word dt      { font-weight: 700; color: var(--nxt-text-heading); }
.nxt-our-key__word dd      { margin: 2px 0 0 0; color: var(--nxt-text-secondary); }

/* THE TILE THAT SAYS THE STEP (#948 FR-5), AdministrationTileProgress.razor, the twin of AdministrationTileProgressView:
   three admin tiles wide and one high, so the strip keeps its height. */
.nxt-shell__admin-tile-frame:has(.nxt-tile-progress) { width: 403px; }
.nxt-btn.nxt-shell__admin-tile:has(.nxt-tile-progress) { align-items: stretch; justify-content: flex-start; text-align: left; }
.nxt-tile-progress          { display: flex; flex-direction: column; gap: 5px; width: 100%; min-width: 0; padding: 2px 4px; }
.nxt-tile-progress__caption { font-size: 13px; font-weight: 600; }
/* #1127: every key on a line of its own, its state at the right in its own colour; nothing is trimmed. */
.nxt-tile-progress__parts   { display: flex; flex-direction: column; gap: 1px; font-size: 11px; line-height: 1.3; }
.nxt-tile-progress__part    { display: flex; justify-content: space-between; gap: 10px; }
.nxt-tile-progress__standing { font-weight: 600; color: var(--nxt-semantic-warning-strong); }
.nxt-tile-progress__standing--done { color: var(--nxt-accent-secondary); }
.nxt-tile-progress__standing--unreadable { color: var(--nxt-semantic-error); }
.nxt-tile-progress__foot    { display: flex; align-items: flex-end; gap: 10px; }
.nxt-tile-progress__sentence { flex: 1; min-width: 0; font-size: 11px; line-height: 1.3; }
.nxt-tile-progress__continue { flex: none; font-size: 11px; font-weight: 600; color: var(--nxt-accent-secondary); }

/* #21 slice 2: the diagnostics notice as a link (FR-14), and Diagnostics > This station (FR-16). */
.nxt-shell__status-link {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    cursor: pointer;
    text-decoration: underline;
}

.nxt-diagnostics__figures { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 16px; }
.nxt-diagnostics__figures > div { display: flex; flex-direction: column; }
.nxt-diagnostics__figures strong { font-size: 16px; margin-top: 4px; }
.nxt-diagnostics__caption { color: var(--nxt-text-secondary); font-size: 12px; }
.nxt-diagnostics__reports { width: 100%; border-collapse: collapse; }
.nxt-diagnostics__reports th { text-align: left; color: var(--nxt-text-secondary); border-bottom: 1px solid var(--nxt-border-primary); padding: 6px 8px; }
/* As the WPF twin: the description is cut to one line with the rest on hover, and the reference selects as a whole. */
.nxt-diagnostics__description { display: block; max-width: 40ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nxt-diagnostics__reference { user-select: all; }
.nxt-diagnostics__reports td { border-bottom: 1px solid var(--nxt-border-row); padding: 6px 8px; vertical-align: top; }

/* #835 slice 3: the Diagnostics app's Reports, the twin of ReportsView.xaml. The filters sit in one row above the list. */
.nxt-reports__fresh { display: flex; align-items: center; gap: 12px; }
.nxt-reports__filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 16px 24px; margin-bottom: 12px; }
.nxt-reports__apps { border: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 16px; }
.nxt-reports__app { display: inline-flex; align-items: center; gap: 6px; }
.nxt-reports__period, .nxt-reports__find label { display: flex; flex-direction: column; gap: 4px; }
.nxt-reports__find { display: flex; align-items: flex-end; gap: 8px; }
.nxt-reports__open {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--nxt-accent-primary);
    text-align: left;
    cursor: pointer;
    text-decoration: underline;
}
.nxt-reports__pages { display: flex; align-items: center; gap: 12px; }
.nxt-reports__switch { display: flex; gap: 4px; margin-bottom: 12px; }

/* #835 slice 7: Statistics, the twin of StatisticsView.xaml. Bars are plain boxes sized by the view-model (C31, decision 15),
   every value they stand for is written beside them, and a slot with no bar is a zero, never missing data. */
.nxt-statistics__figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin: 12px 0; }
.nxt-statistics__figure { border: 1px solid var(--nxt-border-primary); border-radius: 6px; padding: 10px 12px; }
.nxt-statistics__value { display: block; font-size: 1.6em; color: var(--nxt-text-heading); }
.nxt-statistics__timeline { display: flex; align-items: stretch; gap: 2px; height: 140px; border-bottom: 1px solid var(--nxt-border-primary); }
.nxt-statistics__slot { flex: 1 1 0; min-width: 6px; display: flex; flex-direction: column; justify-content: flex-end; position: relative; }
.nxt-statistics__bar { background: var(--nxt-accent-primary); }
.nxt-statistics__slot--future { opacity: 0.4; justify-content: center; font-size: 0.75em; color: var(--nxt-text-muted); }
.nxt-statistics__mark { position: absolute; top: 0; bottom: 0; left: 50%; border-left: 2px dashed var(--nxt-semantic-warning); }
.nxt-statistics__marks { margin: 6px 0 0; padding-left: 18px; color: var(--nxt-text-secondary); }
.nxt-statistics__counts { display: flex; gap: 2px; font-size: 0.7em; color: var(--nxt-text-secondary); }
.nxt-statistics__counts span { flex: 1 1 0; min-width: 6px; text-align: center; overflow: hidden; }
.nxt-statistics__ranking { width: 100%; border-collapse: collapse; }
.nxt-statistics__ranking td { padding: 4px 8px; vertical-align: middle; }
.nxt-statistics__rank-bar { height: 10px; background: var(--nxt-accent-primary); }

/* #835 slice 4: one report in full, the twin of ReportInFullView.xaml. Logs and stacks keep their lines as written. */
.nxt-report__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.nxt-report__heading { margin: 12px 0 4px; }
.nxt-report__group { margin: 16px 0 6px; }
.nxt-report__fields { display: grid; grid-template-columns: minmax(12ch, 220px) 1fr; gap: 2px 12px; margin: 0; }
.nxt-report__fields dt { color: var(--nxt-text-secondary); }
.nxt-report__fields dd { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.nxt-report__stack, .nxt-report__log {
    font-family: var(--nxt-font-mono);
    white-space: pre;
    overflow: auto;
    max-height: 320px;
    border: 1px solid var(--nxt-border-row);
    padding: 8px;
    margin: 4px 0 8px;
}
.nxt-report__file { margin-bottom: 12px; }
.nxt-report__image { max-width: 100%; max-height: 320px; }
.nxt-report__journey { margin: 0; padding-left: 20px; }

/* #21 slice 2: the Diagnostics dialog (FR-3, FR-6, FR-7). */
.nxt-shell__crash-scrim {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--nxt-overlay-scrim);
    z-index: 1000;
}
.nxt-shell__crash-card {
    background: var(--nxt-bg-panel);
    border: 1px solid var(--nxt-border-primary);
    border-radius: 3px;
    padding: 24px;
    min-width: 360px;
    max-width: 640px;
    max-height: calc(100vh - 64px);
    overflow-y: auto;
}
.nxt-crash__title { font-size: 18px; margin: 0 0 12px; }
.nxt-crash__again, .nxt-crash__label { color: var(--nxt-text-secondary); }
.nxt-crash__description { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.nxt-crash__details { white-space: pre-wrap; font-size: 12px; max-height: 240px; overflow: auto; }
.nxt-crash__buttons { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }

/* THE APP CATALOGUE (#1006 FR-6 to FR-8, row 5v.2): the list on the left in two sections, the chosen app's entry beside
   it. The twin is AppCatalogueView.xaml. A row and its selection mark are App management's (nxt-catalog__app). */
.nxt-catalogue { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; padding: 16px; }
.nxt-catalogue__split { flex: 1 1 auto; align-items: stretch; }
.nxt-catalogue__list {
    width: 420px; flex: 0 0 auto; min-height: 0;
    display: flex; flex-direction: column;
    border: 1px solid var(--nxt-border-primary);
}
.nxt-catalogue__find { display: flex; flex-direction: column; gap: 6px; padding: 16px; }
.nxt-catalogue__find-label { font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-catalogue__rows { overflow-y: auto; min-height: 0; flex: 1 1 auto; }
.nxt-catalogue__note { margin: 0 16px 16px; color: var(--nxt-text-secondary); }
.nxt-catalogue__section {
    padding: 6px 16px;
    background: var(--nxt-surface-standard);
    border-top: 1px solid var(--nxt-border-primary);
    border-bottom: 1px solid var(--nxt-border-primary);
    font-family: var(--nxt-font-mono);
    font-size: 10px;
    color: var(--nxt-text-secondary);
}
.nxt-catalogue__row { display: flex; gap: 12px; align-items: center; }
.nxt-catalogue__row-icon {
    width: 36px; height: 36px; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    border-radius: 8px; background: var(--nxt-surface-standard);
}
.nxt-catalogue__row-icon svg { width: 20px; height: 20px; }
.nxt-catalogue__row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.nxt-catalogue__row-name { font-weight: 600; font-size: 14px; }
.nxt-catalogue__row-summary { font-size: 12px; color: var(--nxt-text-secondary); }
.nxt-catalogue__entry {
    flex: 1 1 auto; min-width: 0; overflow-y: auto;
    padding: 28px 36px;
    border: 1px solid var(--nxt-border-primary);
}
.nxt-catalogue__entry-head { display: flex; gap: 20px; align-items: flex-start; margin-bottom: 20px; }
.nxt-catalogue__entry-icon {
    width: 72px; height: 72px; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    border-radius: 8px; border: 1px solid var(--nxt-border-primary);
}
.nxt-catalogue__entry-icon svg { width: 40px; height: 40px; }
.nxt-catalogue__entry-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.nxt-catalogue__entry-name { margin: 0; font-size: 24px; font-weight: 600; }
.nxt-catalogue__entry-line { font-size: 13px; color: var(--nxt-text-secondary); }
.nxt-catalogue__action {
    margin-bottom: 20px; padding: 12px;
    border: 1px solid var(--nxt-border-primary); border-radius: 3px;
    font-size: 13px;
}
/* #1006 S2: a Released group's placement, beside the group in App management. */
.nxt-catalog__placement { display: inline-flex; gap: 12px; margin-left: 16px; }
/* #1006 S2: Pin and Unpin in the entry's action slot, and the unpin confirmation in its place. */
.nxt-catalogue__action-slot { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin-bottom: 20px; }
.nxt-catalogue__confirm p { margin: 6px 0; }
.nxt-catalogue__buttons { display: flex; gap: 8px; margin-top: 8px; }
.nxt-catalogue__rule { height: 1px; margin-bottom: 20px; background: var(--nxt-border-primary); }
.nxt-catalogue__screenshots { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 20px; align-items: center; }
.nxt-catalogue__screenshot { max-height: 180px; max-width: 320px; border: 1px solid var(--nxt-border-primary); border-radius: 3px; }
.nxt-catalogue__body { display: flex; gap: 32px; align-items: flex-start; }
.nxt-catalogue__about { flex: 1 1 auto; max-width: 520px; }
.nxt-catalogue__heading { margin: 0 0 8px; font-size: 15px; font-weight: 600; }
.nxt-catalogue__description { margin: 0 0 20px; font-size: 14px; line-height: 1.6; white-space: pre-line; }
.nxt-catalogue__facts {
    width: 280px; flex: 0 0 auto; margin: 0;
    display: grid; grid-template-columns: 110px 1fr; row-gap: 8px;
    font-size: 13px;
}
.nxt-catalogue__facts dt { color: var(--nxt-text-secondary); }
.nxt-catalogue__facts dd { margin: 0; }
.nxt-catalogue__mono { font-family: var(--nxt-font-mono); }
