/* /Components/Access/ActingForStatement.razor.rz.scp.css */
/* W8-22 · W23-02 — which agency an agent is acting for, as a statement. TOKENS ONLY: R3.1's sweep in
   PortalStyleSheetTests reads every *.razor.css in this project and refuses a hex or an rgb() literal.

   Moved whole from the switcher's sheet when W23-02 split the statement out of it (ActingForStatement.razor).

   A PILL: inline-flex so it is as wide as its own content rather than as wide as the page (a full-width bar
   would read as a third card), the pill radius UiChip already uses for the same shape, the surface token for
   its ground and the subtle outline for its edge. Compact - 4px block, 12px inline and an 8px gap, as tall as
   its own caption and no taller; asymmetric, which is why it is written here rather than taken from a
   utility (R5.1), and every number a whole multiple of the 4px base unit (R5.4).

   NO flex-direction and NO margin: the three children sit on one line, and the distance to anything around
   them belongs to the heading row this pill is handed to (I18).

   🔴 W23 · STACK-TIP WALK, FINDING 2d · ITS OWN INK. A pill that paints its own ground paints its own ink. Without
   one the agency's name inherited the agent portal hero's on-primary - white on this white surface in light mode - and
   read as a blank after "Acting for". text-primary on surface is the page's own body pair in both modes, so it reads
   on whatever band the pill is handed to. ActingForStatementContrastTests measures it. */
.biztech-acting-for[b-hmfu747v5v] {
    display: inline-flex;
    align-items: center;
    gap: 8px;

    padding-block: 4px;
    padding-inline: 12px;

    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
}

/* 🔴 ::deep, BECAUSE THE SVG IS UiIcon'S OWN ELEMENT. A bare `.biztech-icon` here would carry this component's
   scope attribute and match nothing (I19). The tint is a token, and R11.3 holds: UiIcon sets no colour of its
   own and inherits this one. */
.biztech-acting-for[b-hmfu747v5v]  .biztech-icon {
    flex: 0 0 auto;
    color: var(--biztech-palette-primary);
}
/* /Components/Access/AgentTileNarrowingPanel.razor.rz.scp.css */
/* W8-28 · 3 — "Tiles this agent sees" on /agent-access. TOKENS ONLY: R3.1's sweep reads every *.razor.css
   in this project and refuses a hex or an rgb() literal. */

/* I18 — the panel's parts are spaced by the container, never by a margin per child. 12px, a whole
   multiple of the 4px base unit (R5.4). */
.biztech-tile-narrowing[b-awukf68gmi] {
    display: grid;
    gap: 12px;
}

/* 🔴 THE COLLECTION GRID'S SHAPE, AND LEGACY'S: UserDashboardAccess.cshtml is a grid of checkboxes.
   auto-fill, because a portal may carry three tiles or fifteen. 14rem holds a tile label at the body
   step without wrapping mid-word, the collection grid's own figure on the same page. The wrapper divs
   these checkboxes sit in are this file's, so the grid track sizes them and no rule has to reach into
   UiCheckbox (I19). */
.biztech-tile-narrowing-picks[b-awukf68gmi] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: 8px 16px;
}

/* W19 · the panel on the agent page's terms. Every rule names this file's own markup (I19). */

/* The section: its heading and what the agent sees now, then its panel, spaced by the container (I18). */
.biztech-tile-narrowing-panel[b-awukf68gmi] {
    display: grid;
    gap: 12px;
}

.biztech-tile-narrowing-head[b-awukf68gmi] {
    display: grid;
    gap: 4px;
}

/* What Save would do: a tinted note with its glyph, the live session's presence note (W19-06). */
.biztech-tile-narrowing-pending[b-awukf68gmi] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px 12px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, transparent);
}

/* The glyph in the primary colour, the sentence in the page's ink. */
.biztech-tile-narrowing-pending-mark[b-awukf68gmi] {
    display: flex;
    color: var(--biztech-palette-primary);
}

/* The caption at the start and the actions at the end, under a rule; the actions wrap under the caption when narrow. */
.biztech-tile-narrowing-foot[b-awukf68gmi] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-tile-narrowing-actions[b-awukf68gmi] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-inline-start: auto;
}
/* /Components/Access/AgentWorkingKeysPanel.razor.rz.scp.css */
/* W8-28 · 2 — the working-keys panel on /agent-access. TOKENS ONLY: R3.1's sweep reads every *.razor.css
   in this project and refuses a hex or an rgb() literal. */

/* 🔴 I18 — THE SECTIONS ARE SPACED BY THE CONTAINER, NEVER BY A MARGIN PER CHILD. One panel per
   organisation, then the picker, then the direct keys: a margin on each would add to any gap and read as
   misaligned for a reason nobody can see in the markup. 16px, a whole multiple of the 4px base unit
   (R5.4). A plain div this file renders, so the scoped rule matches (I19). */
.biztech-working-keys[b-rrp5tcnxft] {
    display: grid;
    gap: 16px;
}

/* Inside each panel: the heading row and its table, spaced by the container rather than by a margin on
   the heading (I18). 8px, a whole multiple of the 4px base unit. */
.biztech-working-keys-section[b-rrp5tcnxft] {
    display: grid;
    gap: 8px;
}

/* W19 · the panel on the agent page's terms. Every rule names this file's own markup (I19). */

/* The section: its heading and sentence, then its body, spaced by the container (I18). */
.biztech-working-keys-panel[b-rrp5tcnxft] {
    display: grid;
    gap: 12px;
}

.biztech-working-keys-head[b-rrp5tcnxft] {
    display: grid;
    gap: 4px;
}

/* An organisation's name beside its glyph square and its chip - the portal tile's tinted chip, small (W19-04). */
.biztech-working-keys-title[b-rrp5tcnxft] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-working-keys-mark[b-rrp5tcnxft] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 28px;
    block-size: 28px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, transparent);
    color: var(--biztech-palette-primary);
}

/* A key is a machine name: the code face, at the body step, over its consequence. */
.biztech-working-key[b-rrp5tcnxft] {
    display: block;
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-body2-size);
}

/* Who granted it, then the verb, at the row's end. */
.biztech-working-keys-actions[b-rrp5tcnxft] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px 12px;
}

/* The organisation picker is a column and Add sits beside it, the row aligned to its TOP so an error under the select does
   not lift Add off the box: Add drops by the label block the select has and it has not (I20's arithmetic), where the two
   share a row. */
.biztech-working-keys-add[b-rrp5tcnxft] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px;
}

@media (min-width: 600px) {
    .biztech-working-keys-add-action[b-rrp5tcnxft] {
        margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}

.biztech-working-keys-add-field[b-rrp5tcnxft] {
    flex: 0 1 24rem;
    min-inline-size: 0;
}
/* /Components/Access/GrantHoldingsList.razor.rz.scp.css */
/* W22-03 · D1. The grants card's own stack: the heading, the roles, the grants and the closing sentence, spaced by the container's
   gap and never a margin per child (§2 I18). The card around it stacks this component as one child; it cannot reach these (I19). */

.biztech-grant-holdings[b-wi0ajcbchg] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W22-05 · finding 3 · one item per grant, stacked: the 24rem panel has no room for three columns of sentences. The <ul> zeroes the
   user agent's block margin and indent (a declared exception in UtilitySpecificityTests); the items are spaced by its gap. */
.biztech-grant-holdings-list[b-wi0ajcbchg] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-grant-holding[b-wi0ajcbchg] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* The wrapper only carries the test hook (UiText takes no unmatched attribute); without a box of its own the UiText span is the
   flex item, so each line keeps its own type slot's line-height rather than the item's inherited one. */
.biztech-grant-holding-line[b-wi0ajcbchg] {
    display: contents;
}
/* /Components/Access/OrganisationSwitcher.razor.rz.scp.css */
/* W23-02 · ADR 0038 — the organisation switcher. TOKENS ONLY: R3.1's sweep in PortalStyleSheetTests reads
   every *.razor.css in this project and refuses a hex or an rgb() literal.

   🔴 THE TRIGGER AND THE ROWS ARE UiMenu's AND UiMenuItem's, so a rule that reaches them says ::deep and names
   the child's own class (I19). The option row's spans are this file's own, rendered through ChildContent. No
   margin: in the header the row owns the gap (I18). */
.biztech-organisation-switcher[b-e5jo5sm0ab] {
    display: inline-flex;
    min-inline-size: 0;
}

/* A header control rather than a toolbar button: no edge until it is hovered, like the icon buttons beside it. */
.biztech-organisation-switcher[b-e5jo5sm0ab]  .biztech-menu-trigger-labelled {
    border-color: transparent;
    border-radius: var(--biztech-radius-pill);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-button-weight);
}

/* A long organisation name is clipped rather than pushing the theme toggle off the bar. */
.biztech-organisation-switcher[b-e5jo5sm0ab]  .biztech-menu-trigger-label {
    max-inline-size: 16rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* R13.7 · at phone width only the glyph stays. The trigger's accessible name still carries the organisation,
   because UiMenu composes it from the label whether or not the label is drawn. */
@media (max-width: 599.98px) {
    .biztech-organisation-switcher[b-e5jo5sm0ab]  .biztech-menu-trigger-label {
        display: none;
    }
}

.biztech-organisation-switcher__option[b-e5jo5sm0ab] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-organisation-switcher__name[b-e5jo5sm0ab] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-organisation-switcher__hidden[b-e5jo5sm0ab] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* W23-06 · D11 — the one organisation, named. It may shrink, never past its ceiling, and a long name WRAPS inside the
   pill rather than being clipped: R4.7 says a chip carries a name read aloud and does not truncate, and clipping cut
   the name mid-letter and the pill's own border with it (measured at 375px on the W23-06 walk, beside a switched
   operator's "Working in" chip). Wrapped, the header row grows by a line in that one case and stays inside 375px.
   ::deep because UiChip renders the chip (I19). */
.biztech-organisation-pill[b-e5jo5sm0ab] {
    display: inline-flex;
    flex: 0 1 auto;
    min-inline-size: 0;
    max-inline-size: 16rem;
}

.biztech-organisation-pill[b-e5jo5sm0ab]  .biztech-chip {
    max-inline-size: 100%;
    white-space: normal;
    text-align: center;
}

@media (max-width: 599.98px) {
    .biztech-organisation-pill[b-e5jo5sm0ab] {
        max-inline-size: 6rem;
    }
}
/* /Components/Access/PermissionTree.razor.rz.scp.css */
/* W14-03 · the permission tree. Specimens 14 and 15.

   🔴 I19. EVERY SELECTOR HERE NAMES A CLASS THIS FILE'S OWN MARKUP WRITES. Blazor stamps the scope
   attribute on a selector's LAST compound, so a rule ending in another component's element is stamped
   on markup this file did not write and is inert - no error, no warning, and a class with no effective
   rule renders exactly like a class with none. There is no `> *` anywhere below, and nothing reaches
   into UiTriStateBox, UiCheckbox or UiIcon: the rows are sized from GRID TRACKS, so no rule has to
   reach a child at all.

   🔴 I18. SPACING BETWEEN SIBLINGS IS A GAP ON THE CONTAINER, NEVER A MARGIN PER CHILD. The two add up:
   a 16px grid gap plus a margin on each child is a layout that looks misaligned for a reason nobody can
   see in the markup.

   🔴 I17. NO PADDING OF ITS OWN. The PAGE declares biztech-pa-4 on the panel this sits in. */

.biztech-tree[b-71uxg5cmbu] {
    display: grid;
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}

/* ── The rail ─────────────────────────────────────────────────────────────────────────────────
   Thirteen groups, always visible. NOT a collapsible level: the whole argument of specimen 14 is
   that a reader answers "what does this role do" without a click. */

.biztech-tree-rail[b-71uxg5cmbu] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.biztech-group[b-71uxg5cmbu] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;

    inline-size: 100%;
    padding-block: 4px;
    padding-inline: 8px;

    font: inherit;
    text-align: start;
    color: var(--biztech-palette-text-primary);
    background-color: transparent;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-default);
    cursor: pointer;
}

.biztech-group:hover[b-71uxg5cmbu] {
    background-color: color-mix(in srgb, currentcolor 6%, transparent);
}

/* The open group is tinted with the primary and bordered by it, the segmented track's "this one is on" (W19-03),
   where it was a grey outline the same weight as any field's. */
.biztech-group-open[b-71uxg5cmbu] {
    border-color: color-mix(in srgb, var(--biztech-palette-primary) 40%, transparent);
    background-color: color-mix(in srgb, var(--biztech-palette-primary) 8%, transparent);
}

.biztech-group-name[b-71uxg5cmbu] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
    font-size: var(--biztech-font-body2-size);
}

.biztech-group-tail[b-71uxg5cmbu] {
    display: flex;
    align-items: center;
    gap: 8px;
}

.biztech-group-count[b-71uxg5cmbu] {
    font-variant-numeric: tabular-nums;
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* The umber dot: where the unsaved edits are, so a reader who wandered off finds their own work.
   Its title attribute carries the count, because a dot alone says "something" and not "how much". */
.biztech-group-dirty[b-71uxg5cmbu] {
    inline-size: 8px;
    block-size: 8px;
    border-radius: 999px;
    background-color: var(--biztech-palette-primary);
}

/* ── The pane ─────────────────────────────────────────────────────────────────────────────── */

.biztech-tree-pane[b-71uxg5cmbu] {
    min-inline-size: 0;
}

.biztech-tree-pane-head[b-71uxg5cmbu] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-block-end: 12px;
}

.biztech-tree-pane-tally[b-71uxg5cmbu] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* Pushed to the end of the head row, so the search field keeps the space it needs. The class is on
   a wrapper this file writes rather than on UiButton itself - I19: a scoped rule cannot reach a child
   component's own root element, so styling the button directly would be inert. */
.biztech-select-all[b-71uxg5cmbu] {
    margin-inline-start: auto;
    flex: 0 0 auto;
}

.biztech-search-wrap[b-71uxg5cmbu] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 1 28rem;
    min-inline-size: 12rem;
}

.biztech-search-icon[b-71uxg5cmbu] {
    flex: 0 0 auto;
    color: var(--biztech-palette-text-secondary);
}

.biztech-tree-empty[b-71uxg5cmbu] {
    font-size: var(--biztech-font-body2-size);
    color: var(--biztech-palette-text-secondary);
}

/* ── Areas and keys ───────────────────────────────────────────────────────────────────────────
   W19 · every area of the open group in one frame - the quiet edge and corners twice the theme's radius the
   console's tables wear - each headed by a tinted band, the person's Permissions tab and the form builder's
   section shape (W19-03). 38 of the 66 areas hold a single key, and each still gets its band: hiding the level
   for them would make the layout jump as a reader moved between groups. */

.biztech-tree-frame[b-71uxg5cmbu] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    overflow: clip;
}

.biztech-area + .biztech-area[b-71uxg5cmbu] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The band. Both an element and a button wear this, so the button's own chrome is reset here rather than in a
   second rule - a <button> brings a background, a border and a centred text-align that a heading must not have. */
.biztech-area-head[b-71uxg5cmbu] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 8px;
    inline-size: 100%;
    padding: 8px 16px;
    font: inherit;
    text-align: start;
    color: inherit;
    background-color: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
    border: 0;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

button.biztech-area-head[b-71uxg5cmbu] {
    cursor: pointer;
}

.biztech-area-name[b-71uxg5cmbu] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

/* 🔴 THE DESCRIPTION SITS UNDER ITS KEY, INDENTED TO THE KEY'S TEXT, AND THAT IS THE WHOLE OF "align the
   descriptions" NOW. They sat in a second column beside the keys, which put them at a different edge in every
   area - each area's column was as wide as its own widest key - and a line above the checkbox's text, because a
   checkbox row is a control's height and a caption is not. Under the key, every description in every area
   starts at one edge: the box's 20px and the choice's 8px gap (.biztech-choice-control, .biztech-choice). */
.biztech-keys[b-71uxg5cmbu] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.biztech-perm[b-71uxg5cmbu] {
    display: flex;
    flex-direction: column;
    padding: 8px 16px;
}

.biztech-perm + .biztech-perm[b-71uxg5cmbu] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-perm-control[b-71uxg5cmbu] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-perm .biztech-key[b-71uxg5cmbu] {
    font-family: monospace;
    font-size: var(--biztech-font-body2-size);
}

.biztech-perm-text[b-71uxg5cmbu] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
    padding-inline-start: 28px;
}

.biztech-result-group[b-71uxg5cmbu] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* The key on a checkbox is the checkbox's own label, so it takes the code face from here, through ::deep (I19). */
.biztech-perm[b-71uxg5cmbu]  .biztech-choice-label {
    font-family: monospace;
    font-size: var(--biztech-font-body2-size);
}

.biztech-perm-desc[b-71uxg5cmbu] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* ── Below the tablet boundary ────────────────────────────────────────────────────────────────
   🔴 ONE COLUMN, AND THE RAIL SCROLLS ITSELF. The overflow belongs to the RAIL so the PAGE never
   scrolls sideways - the card's rule, and the thing RoleEditorViewportTests measures at 400px.

   Design §4 accepts the cost in writing: thirteen groups is a lot to scroll through on a phone, and a
   select in place of the rail is deliberately NOT built, because no operator sets up a role on a phone
   and a control nobody uses still has to be maintained. That paragraph names this the specimen to
   revisit if the assumption turns out wrong. */

@media (max-width: 767.98px) {
    .biztech-tree[b-71uxg5cmbu] {
        grid-template-columns: minmax(0, 1fr);
    }

    .biztech-tree-rail[b-71uxg5cmbu] {
        flex-direction: row;
        overflow-x: auto;
        padding-block-end: 4px;
    }

    .biztech-group[b-71uxg5cmbu] {
        inline-size: auto;
        flex: 0 0 auto;
    }

    .biztech-group-name[b-71uxg5cmbu] {
        white-space: nowrap;
        overflow-wrap: normal;
    }
}
/* /Components/Access/PersonAccessHistory.razor.rz.scp.css */
/*
    W14-04 · the Access tab's two tables.

    The key takes the same monospace treatment PersonPermissions gives it, for specimen 12's reason:
    "permission keys are set in monospace because they are identifiers with a colon syntax." Two copies
    rather than a shared class, because I19 makes a scoped rule reach only its own component's markup -
    promoting it to app.css would put one component's typography in the global sheet.

    🔴 I11, AS A RULE RATHER THAN A COMMENT: a withdrawn grant is struck through and STAYS. Revocation
    is a fact on the row, not a deletion, and "a vanished link never existed, as far as the room can
    tell." The colour goes with the strike, because a line-through alone is invisible at caption size
    to a reader who is scanning.
*/

.biztech-person-access-key[b-2iw96903er] {
    font-family: monospace;
    font-size: var(--biztech-font-caption-size);
}

.biztech-person-access-revoked[b-2iw96903er] {
    text-decoration: line-through;
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Access/PersonPermissions.razor.rz.scp.css */
/*
    W14-04 · specimen 12's rows.

    🔴 THE KEY IS MONOSPACE, AND SPECIMEN 12 GIVES THE ONE JUSTIFICATION FOR THAT FACE ON THESE SCREENS:
    "permission keys are set in monospace because they are identifiers with a colon syntax." Case:Export
    is a token to be matched, not prose to be read, and a proportional face makes the colon and the two
    halves blur together at caption size.

    I18: the gap belongs to the LIST and to each row, never a margin per child. A padlock, a key and two
    caption lines sit in one row, and four margins would add to the list's own spacing.

    I19: every selector names this component's own markup. Nothing reaches inside UiIcon, UiCheckbox or
    UiText, whose roots Blazor stamps with their OWN scope - a rule that tried would be inert with no
    error and no warning, which is what ScopedStyleReachTests sweeps for.
*/

/* W19 · every area in one frame - the quiet edge and corners twice the theme's radius the console's tables wear - and
   each area headed by a tinted band, the form builder's section shape (W19-03). Each area was a heading and a bordered
   box of its own, so thirty areas of one key each read as thirty boxes. */
.biztech-person-permission-areas[b-bj62ffubmy] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    overflow: clip;
}

.biztech-person-permission-area + .biztech-person-permission-area[b-bj62ffubmy] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-person-permission-area[b-bj62ffubmy]  .biztech-person-permission-band {
    padding: 8px 16px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-person-permissions[b-bj62ffubmy] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* A row is two columns: the key and what it does, then where it comes from at the row's end. Below sm the source
   drops under the description rather than squeezing it. */
.biztech-person-permission[b-bj62ffubmy] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 4px 24px;
    padding: 12px 16px;
}

.biztech-person-permission + .biztech-person-permission[b-bj62ffubmy] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-person-permission-main[b-bj62ffubmy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 20rem;
    min-inline-size: 0;
}

.biztech-person-permission-lead[b-bj62ffubmy] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-person-permission-from[b-bj62ffubmy] {
    flex: 0 1 22rem;
    min-inline-size: 0;
    text-align: end;
}

@media (max-width: 599.98px) {
    .biztech-person-permission-from[b-bj62ffubmy] {
        text-align: start;
    }
}

/* The note sits between the headline and the search, spaced by its own block. */
.biztech-person-permissions-note[b-bj62ffubmy] {
    margin-block-end: 16px;
}

/* The padlock sits with the row's first line rather than its baseline: it is an icon beside a token,
   and baseline-aligning a glyph against a monospace key drops it a pixel or two below the text. */
.biztech-person-permission-lock[b-bj62ffubmy] {
    display: inline-flex;
    align-items: center;
    align-self: center;
    color: var(--biztech-palette-text-secondary);
}

.biztech-person-permission-key[b-bj62ffubmy] {
    font-family: monospace;
    font-size: var(--biztech-font-caption-size);
}

/* 🔴 W8-39 · 1 · ONE LINE PER GRANT OF A KEY THEY HOLD DIRECTLY - a box, the key with its scope, and
   the provenance under it. The list spaces its own lines (I18), and it shares the row with the key's
   description on the same terms as .biztech-person-permission-said: it takes the room and wraps, so at
   375px the description drops beneath the lines rather than squeezing them.

   A <div>, not a <ul>: the permission row around it is already the list item, and a nested list would
   bring a user-agent margin and indent that a scoped reset here would have to zero - which beats every
   utility class a caller passes (UtilitySpecificityTests). Nothing to reset, so nothing is reset. */
.biztech-person-permission-grants[b-bj62ffubmy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* The description and the provenance line take the rest of the row and wrap together, so a long
   "Given directly, 2 Sep 2026 by Krishan S." does not push the key off its own line. */
.biztech-person-permission-said[b-bj62ffubmy] {
    min-inline-size: 0;
}

/* 🔴 W0-79 · 8 · THE FILTER'S OWN CLASSES, RE-DECLARED HERE RATHER THAN INHERITED FROM PermissionTree.

   I19: Blazor rewrites a scoped selector to `selector[b-<THIS component's hash>]`, and only elements
   this component's own markup renders carry that attribute. PermissionTree.razor.css declares
   .biztech-search-wrap, .biztech-search-icon and .biztech-tree-pane-tally, and every one of those rules
   reaches NOTHING here - present, named by the markup, and inert.

   AgentCaseLauncher.razor.css records this exact failure found on a running stack rather than in a test:
   `border: 0px, padding: 0px, display: block` on what was supposed to be a segmented control. A class
   with no effective rule renders exactly like a class with none, which is why ScopedStyleReachTests
   exists and why these names are deliberately DIFFERENT from the tree's - two components, two scopes,
   and a shared name would invite exactly the assumption that burned that file.

   No margin between the head row and the list: the head declares its own margin-block-end, which is the
   container spacing its own children rather than each child spacing itself (I18). */
.biztech-permission-filter-head[b-bj62ffubmy] {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-block-end: 12px;
}

/* flex: 1 1 12rem so the box takes the room the tally does not, and still wraps to its own line at
   375px rather than squeezing the tally off the row. min-inline-size: 0 is what lets a flex item
   shrink below its content at all. */
.biztech-permission-search[b-bj62ffubmy] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 1 28rem;
    min-inline-size: 12rem;
}

.biztech-permission-search-icon[b-bj62ffubmy] {
    flex: 0 0 auto;
    color: var(--biztech-palette-text-secondary);
}

.biztech-permission-tally[b-bj62ffubmy] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* The empty block stands in the list's place; the padding the dense block drops is given back here, because this is the
   only empty state in the panel. */
.biztech-permission-empty[b-bj62ffubmy] {
    padding-block: 24px;
}

/* W19 · the figures as tiles, W19-11's health tallies: a quiet card each, a figure over the word that says what it
   counts, and a 4px top edge in the tile's tone. Held is the primary; the parts it splits into are quiet. Wraps to two
   across on a phone. */
.biztech-permission-tallies[b-bj62ffubmy] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: 12px;
    margin-block-end: 16px;
}

.biztech-permission-tally[b-bj62ffubmy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-block-start: 4px solid var(--biztech-permission-tone, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-permission-tally--primary[b-bj62ffubmy] {
    --biztech-permission-tone: var(--biztech-palette-primary);
}

.biztech-permission-tally--quiet[b-bj62ffubmy] {
    --biztech-permission-tone: var(--biztech-palette-outline-subtle);
}

.biztech-permission-tally-figure[b-bj62ffubmy] {
    font-size: var(--biztech-font-h5-size);
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    color: var(--biztech-palette-text-primary);
}
/* /Components/Access/RegistrationRequirementsPanel.razor.rz.scp.css */
/* W19 · the panel's foot: Save under a rule, the form's end rather than one more field. Names this file's own markup (I19). */
.biztech-registration-foot[b-wcc63vxh2v] {
    display: block;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Access/RegistrationSettingsPanel.razor.rz.scp.css */
/* W19 · the panel's foot: Save under a rule, the form's end rather than one more field. Names this file's own markup (I19). */
.biztech-registration-foot[b-kvbqscmgkj] {
    display: block;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Admin/CaseTypePanel.razor.rz.scp.css */
/*
    W18 · /case-types/new — the create form's own look.

    A first pass fixed the BEHAVIOUR - a live button, per-field messages, a dropdown that stopped
    offering an empty row - and left the page looking the same, which it did: none of that changes a
    pixel until something is wrong.

    What was actually wrong was the absence of structure. Six controls, a checkbox and three paragraphs
    of helper text sat in one flat list inside one box, every line the same weight, with the only
    visual object on the screen being a navy pill labelled "Details". The fix is that the parts are
    GROUPED and the groups are named; nothing here is a colour change.
*/

/* ── the tab strip ───────────────────────────────────────────────────────────────────────────────

   🔴 THE TRACK MOVED TO app.css AS .biztech-segmented, WHEN THE CASE TYPE EDITOR BECAME ITS THIRD
   SURFACE. It was copied here from /inquiries' Active/Archived switch with the note that R8.2 wants
   three surfaces before something is a pattern; the editor's Details/Process/Delivery strip drew
   Filled + Primary for its open tab, which is the page's primary action, and asked for the same
   track. */

/* 🔴 THE PRESSED SEGMENT'S TINT MOVED TO app.css, AND THE DEBT THIS FILE RECORDED IS PAID.

   The rules were copied here from /inquiries' Active/Archived switch, with the note that "R8.2 wants
   THREE surfaces before something is a pattern, and this is the second". The third arrived: a stage
   row's Edit control is a toggle too - it opens the editor below and stays on while that editor is
   open - and it was drawn Filled + Primary, which is the page's own primary action.

   So `.biztech-button[aria-pressed="true"]` is the console's answer now, keyed on the state the DOM
   already carries rather than on a class any of the three had to remember. The track below is what
   stays here, because a segmented GROUP is this panel's shape and a lone toggle is not. */

/* ── the form's sections ─────────────────────────────────────────────────────────────────────────

   🔴 NAMED GROUPS RATHER THAN ONE LIST, WHICH IS THE WHOLE OF THE CHANGE.

   The controls were already in a grid and already the right widths; what they had no such thing as was
   a shape. Identity, access and delivery are three different decisions - one about what this type IS,
   one about how its links are guarded, one about where they land - and reading them as one run of
   eight controls is what made the screen look like an admin page from a decade ago.

   A rule rather than a margin per child (I18): the gap belongs to the container. 24px is 6 x 4 on the
   base unit (R5.1). */
.biztech-case-type-form[b-1tybl8cnx8] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* Every section but the first is separated by a hairline, which is what turns three groups into three
   groups rather than three paragraphs. `outline-subtle` rather than `outline`: this line divides
   related things inside one panel, and T24 §2.3 reserves the 3:1-tested token for boundaries something
   depends on seeing.

   :not(:first-child) asks the question the markup cannot - "is there a section above me?" - so a
   variant's extra section needs no branch and no class of its own. */
.biztech-case-type-section:not(:first-child)[b-1tybl8cnx8] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    padding-block-start: 24px;
}

/* 🔴 THE SECTION HEADING'S RULE MOVED TO app.css AS .biztech-section-title, BECAUSE THE PROCESS TAB
   WANTED THE SAME ONE. It was `.biztech-case-type-section-title` here and it reached this component's
   own markup only (I19) - the four tables on the Process tab are separate components, so a rule here
   could not touch them and four copies would be four chances to drift.

   R8.2 wants three surfaces before something is a pattern. This is five: Identity and Participant
   links on this tab, and Stages, Transitions, Obligations and Payload on the next. The empty state
   went to app.css the same way and for the same reason - see its own note there for what that move
   cost when it was left until the third surface asked. */

/* ── a field and the sentence under it ───────────────────────────────────────────────────────────

   🔴 THE HELPER TEXT WAS A SIBLING OF ITS FIELD AND SPACED BY THE GRID, which is why "Stable,
   lowercase, and never changed once cases exist." sat as far from the Key box as the Key box sat from
   the row above it. A caption belongs to the control it explains, and 4px is what .biztech-field
   already puts between a label and its box - so the field and its sentence read as one object. */
.biztech-case-type-field[b-1tybl8cnx8] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The Kind field's "Delivery tab" link: a <button> drawn as the console's text link (.biztech-link), inside a caption,
   so it takes the caption's size and line and none of a button's box. */
.biztech-case-type-inline-link[b-1tybl8cnx8] {
    border: 0;
    background: none;
    font: inherit;
    cursor: pointer;
}

.biztech-case-type-inline-link:disabled[b-1tybl8cnx8] {
    cursor: default;
    text-decoration: none;
}

/* ── the action row ──────────────────────────────────────────────────────────────────────────────

   Separated from the form by the same hairline the sections use, so the thing that COMMITS is not the
   ninth item in a list of controls. The caption beside it says what the chosen kind owns; R9.2 stopped
   using it as the "why is this disabled" answer when the button stopped being disabled. */
.biztech-case-type-actions[b-1tybl8cnx8] {
    display: flex;
    align-items: center;
    gap: 16px;

    /* 🔴 16 AND 16, DOWN FROM 24 AND 24, AND IT IS THE PROCESS TAB THAT SPENT IT. 48px above a primary
       action is generous rather than measured, and the four-section Process tab has no slack at all:
       measured at 1440x866, the space over its section hairlines is the exact height of the viewport,
       so the 8px each of separation a reader asked for there had to come from somewhere. 32px still
       sets this row apart from the form - the rule above it does most of that work. */
    margin-block-start: 16px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* ── a caption that runs to a paragraph ──────────────────────────────────────────────────────────

   The panel spans the page now, so a sentence under a full-width control would run the whole of it. 92ch,
   the Delivery tab's measure for the same kind of help text. display: block is half the rule: UiText
   renders a Caption as a <span>, and a max-inline-size on an inline box does nothing. ::deep because the
   element is UiText's (I19, R14.1b). */
[b-1tybl8cnx8] .biztech-case-type-help {
    display: block;
    max-inline-size: 92ch;
}

/* The panel takes the case list's card edge and corners (Inquiries.razor.css), so the case type screens and the lists
   they open from read as one set. It was UiPaper's full Outline edge, visibly heavier than the list's. Reached through
   a wrapper with no box of its own, because UiPaper is a component and this scope does not reach its element without
   ::deep. Fields inside keep their own Outline edge: that is the boundary a reader needs to see. */
.biztech-case-type-panel[b-1tybl8cnx8] {
    display: contents;
}

.biztech-case-type-panel[b-1tybl8cnx8]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Admin/CaseTypeRetirePanel.razor.rz.scp.css */
/* W27-04 · I18. The gap between the panel's children belongs to the container, never a margin on each. A column
   rather than the default row, because the heading, the sentence, the alert and the button read top to bottom. It
   sits on a card of its own below Save (CaseTypeBlueprintEditor), so it needs no hairline or margin to stand apart. */
.biztech-case-type-retire[b-6vve2usvwr] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
/* /Components/Admin/DeliveryPanel.razor.rz.scp.css */
/* 🔴 HELPER TEXT IS CAPPED BY A MEASURE, NOT BY A GRID FRACTION.

   Access and Signatures have nothing beside them, so a half-width cell looked like text breaking
   early against empty space rather than like a column. Full width is the other failure: the
   signature paragraph ran the whole panel at around 150 characters a line.

   A `ch` cap answers both, because it is the thing that actually matters - line length - rather than
   a fraction of whatever the panel happens to be. 68ch sits inside the 45-75 band, and unlike Md="6"
   it does not shrink further when the panel does: below that width the paragraph is simply full
   width, which is correct on a phone.

   Route keeps its half-width cells. Something IS beside them there - the deck select - so the
   fraction is doing real work.

   🔴 display: block IS HALF THE RULE, NOT TIDINESS. UiText renders Caption as a <span>, and a
   max-inline-size on an inline box is ignored outright - the first version of this rule shipped
   without it and the paragraph ran the full 920px panel exactly as before, with the cap declared and
   doing nothing.

   ::deep because UiText renders the element (I19, R14.1b). */
[b-b5du4jhqbc] .biztech-delivery-help {
    display: block;
    max-inline-size: 92ch;
}

/* The notice is prose too, so it takes the same measure - a full-width alert beside two capped
   paragraphs reads as a third width rather than as the same voice. The cap goes on the span this
   file writes rather than on the alert, because UiAlert's root is a flex row holding an icon beside
   its content and display: block there would take the icon out of it. */
[data-delivery-no-decks][b-b5du4jhqbc] {
    display: block;
    max-inline-size: 92ch;
}
/* /Components/Admin/FormBuilderCanvas.razor.rz.scp.css */
/* W3-21 · R14.1 layer 3 — the rail, the palette, the section runs, their rows and the body each row opens
   are this component's own markup.

   Layout, one border colour and one ink. Everything else comes from the seam's own components, which is why
   there is no type scale and no hover rule here: UiButton, UiIconButton, UiIcon and UiText carry theirs.

   Every length is a multiple of the 4px base unit (R5.1, R5.4), every colour is a semantic role read
   through --biztech-* (R3.1, R7.4), and the radius is read from the variable rather than restated as 8px
   (R5.5) - MudThemeProvider is unmounted on this document, so --mud-default-borderradius resolves to
   nothing and would silently render square corners.

   🔴 TWO RULES REACH A CHILD COMPONENT AND BOTH SAY SO WITH ::deep (I19, R14.1b). A disclosure's root is
   UiButton's own element and a row name's is UiText's, so this file's scope attribute never lands on either;
   PortalComposerTilePanel.razor.css records falling into exactly that trap and measuring ~950px of a head
   row that did nothing when clicked. Everything else is sized by a grid or flex TRACK, which needs no
   ::deep. */

.biztech-form-rail[b-3y5fuv7ty1] {
    display: flex;
    flex-direction: column;
    gap: 16px;

    /* min-width: 0 is load-bearing, not defensive: a flex or grid item's default minimum is its content, so
       a long field label would push the rail wider than its parent instead of truncating inside it.
       R13.8's no-spill rule is what that buys. */
    min-width: 0;
}

/* The tool tray: a bordered block at the head of the rail rather than twelve loose buttons above a list.
   No shadow (ADR 0026 D-E) - a border carries depth in flow, and a shadow is licensed only for the browser's
   top layer or something floating over content it does not push aside. */
.biztech-form-palette[b-3y5fuv7ty1] {
    padding: 12px;

    background: var(--biztech-palette-surface);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* 🔴 ONE WRAPPING ROW, SIZED BY THE LABELS IN IT, AND THAT IS THE WHOLE RESPONSIVE STRATEGY.

   What was here was `repeat(12, minmax(0, 1fr))` with a 4-track and a 2-track step below it, and the button
   inside each track was `width: 100%`. `.biztech-button` declares `white-space: nowrap`, so a track narrower
   than its own label does not wrap it and does not truncate it - the label overflows the box and runs under
   its neighbour's. Measured against these stylesheets in Chromium: at a 1024px viewport the tracks are 57px,
   five of the twelve labels spill past their own buttons, and "Dropdown" lands on the two boxes beside it.

   A row of content-sized pills cannot overlap at any width, because no box is ever narrower than what is
   written in it. So there is no media query here: the three that were are each a guess at a width where the
   labels would fit, and the guess is what was wrong. Measured after, tray height and label spill: 110px and
   no spill at 1440, 1280, 1024 and 768 - against 114, 114, 114 and 202 before, three of them with labels
   over their neighbours. 242px at 375, against 334.

   4px between the pills, which is the rail's own rhythm (I18: the container owns the spacing). */
.biztech-form-palette-row[b-3y5fuv7ty1] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
}

/* 8px, so the lead is not read as the first pill. It is the one place in this row where the gap is not the
   rhythm, because it separates a heading from controls rather than controls from each other. */
.biztech-form-palette-lead[b-3y5fuv7ty1] {
    margin-inline-end: 8px;
}

/* The lead in the secondary ink, so the pills are what the eye lands on. ::deep because the colour belongs
   to UiText's own element, which this sheet's scope attribute never reaches (I19, R14.1b) - and the seam
   has no "secondary ink" member of UiColor to pass instead. */
.biztech-form-palette-lead[b-3y5fuv7ty1]  .biztech-text {
    color: var(--biztech-palette-text-secondary);
}

/* 🔴 THE SECTION IS SET APART BECAUSE IT IS NOT A FIELD. 12px here plus the row's own 4px reads as 16px
   against 4px between the twelve - a 4:1 ratio, which is R5.9's proximity argument applied sideways. It
   carries a glyph as well (see the markup), so the distinction survives a wrap that puts this pill at the
   start of a line where its space would be invisible. */
.biztech-form-palette-section[b-3y5fuv7ty1] {
    margin-inline-start: 12px;
}

/* One run of fields - the ungrouped lead, a declared section, or the broken references. The border is what
   makes the run a thing a field can be dropped INTO rather than merely a heading above some rows.

   A flex column with a gap rather than a margin on the list below it: spacing between siblings belongs to
   the container (I18), and the two add up otherwise. */
.biztech-form-group[b-3y5fuv7ty1] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;

    /* 🔴 A CARD ON THE PAGE, SO A RUN READS AS A CONTAINER RATHER THAN AS MORE ROWS. The run, its heading
       and its rows were all a subtle border on the page's ground; a surface fill sets the run off from the
       ground it sits on, and the band below sets its heading off from the rows inside it. */
    background: var(--biztech-palette-surface);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* A run's heading: a tinted band across the top of the card, pulled out to its edges over the card's own
   padding, with a hairline under it. The tint is decoration rather than a boundary the reader depends on
   - the hairline and the heading's weight carry that - so it is not held to 3:1. Its top corners follow
   the card's, less the 1px border, so the band sits inside the border rather than over it. */
.biztech-form-band[b-3y5fuv7ty1] {
    margin: -8px -8px 4px;
    padding: 4px 8px;

    background: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    border-start-start-radius: calc(var(--biztech-radius-default) - 1px);
    border-start-end-radius: calc(var(--biztech-radius-default) - 1px);
}

/* A section's name at the heading weight, so it is not read at a field row's. ::deep because the weight
   belongs to UiText's own element (I19, R14.1b). */
.biztech-form-band[b-3y5fuv7ty1]  .biztech-text {
    font-weight: var(--biztech-font-subtitle1-weight);
}

/* Where a drop would land when the pointer is over the run rather than over one of its rows - which is the
   only way to reach an empty section. Dashed as well as coloured: the drag is a pointer gesture, but the
   marker must not be colour alone (R12.7). */
.biztech-form-group-over[b-3y5fuv7ty1] {
    border-color: var(--biztech-palette-primary);
    border-style: dashed;
}

/* 🔴 THE HEAD IS ONE LINE, AND THE WHOLE OF IT IS THE TARGET. A row was two lines - label above
   `key · Type · section` - which made 24 rows a very long page for a list whose job is to be scanned. */
.biztech-form-head[b-3y5fuv7ty1] {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
}

.biztech-form-head-open[b-3y5fuv7ty1] {
    flex: 1 1 auto;
    min-width: 0;
}

/* 🔴 THE DISCLOSURE HAS TO LOOK LIKE A ROW, NOT LIKE A BUTTON. UiButton brings a button's padding and a
   centred label; what this row wants is a name at the left edge with a chevron in front of it, and the whole
   width as the click target.

   ::deep for PortalComposerTilePanel's reason, stated there after the first draft wrote the rule without it
   and measured ~950px of head row that did nothing when clicked: the element is UiButton's own root and this
   file's scope attribute never reaches it unaided.

   No block-size override, unlike the composer's: that row's label is a heading ABOVE a summary and measured
   54px inside a 32px button. This one is a single line, so `.biztech-shell .biztech-button`'s definite 32px
   is exactly right and taking it back would make every row taller for nothing. */
.biztech-form-head-open[b-3y5fuv7ty1]  .biztech-form-disclosure {
    width: 100%;
    justify-content: flex-start;
    min-width: 0;
    padding-inline-start: 4px;
    text-align: start;
}

/* The name, its required mark and its key on one line, with only the NAME allowed to truncate. */
.biztech-form-line[b-3y5fuv7ty1] {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
}

.biztech-form-name[b-3y5fuv7ty1] {
    /* min-width: 0 is what lets it shrink inside the line above; a flex item's default minimum is its
       content, so without it the line would grow instead of the name truncating. */
    min-width: 0;
}

/* ::deep and the child's own class, which is what I19 sanctions: the element being clipped is UiText's own
   root, rendered as the h3 this row's name is.

   A long name truncates rather than wrapping the row to two lines - R4.7 permits it where the full value is
   reachable another way, and it is: opening the row shows the label in a text field. Uniform row heights are
   what make 24 of them scannable. */
.biztech-form-name[b-3y5fuv7ty1]  .biztech-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The ungrouped run's heading, which opens nothing - there is no section to edit - so it is a <p> rather
   than a dead button.

   No `margin: 0` here: BizTechCssVariables' document block already resets p, and restating it in a scoped
   sheet would beat every biztech-m* a caller passes at (0,2,0) against (0,1,0) - R14.1a. */
.biztech-form-head-plain[b-3y5fuv7ty1] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
    padding: 4px 8px;
}

.biztech-form-name-plain[b-3y5fuv7ty1] {
    font-weight: var(--biztech-font-subtitle1-weight);
}

.biztech-form-meta[b-3y5fuv7ty1] {
    /* R4.4's floor is 12px and the body size is already above it, so this reads at the body size in a dimmer
       role rather than being shrunk below the floor to fit. */
    color: var(--biztech-palette-text-secondary);
}

.biztech-form-meta[b-3y5fuv7ty1] {
    /* Never the thing that pushes a row wide: the name truncates first, and this drops off the end after it.
       R4.7's "reachable another way" is met twice over - the key is a field in the editor this row opens. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The shared dense empty block (app.css) inside a run, with room above and below so it reads as the
   section's answer rather than as a caption under its heading. */
.biztech-form-empty[b-3y5fuv7ty1] {
    padding: 12px 8px;
}

/* A field's type, or a section's counts: a fixed, end-aligned column between the name (which takes the
   rest of the row) and the controls, so every row's fact lines up with the one above it. Plain caption
   text in the secondary ink - a column of outlined chips was noise in a list this dense.

   16ch holds "Checkbox" and "Signature" with room, and "3 columns · 12 fields" wraps nowhere at caption
   size; `min-inline-size` rather than a width, so a longer one grows rather than clipping. */
.biztech-form-fact[b-3y5fuv7ty1] {
    flex: none;
    min-inline-size: 16ch;
    padding-inline: 8px;

    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    text-align: end;
    white-space: nowrap;
}

/* Move down is ArrowUpward turned over - design §9's one glyph, rotated. ::deep because the <svg> is
   UiIconButton's own markup (I19). */
.biztech-form-move-down[b-3y5fuv7ty1]  svg {
    transform: rotate(180deg);
}

.biztech-form-list[b-3y5fuv7ty1] {
    /* The default list indent puts every row a long way from the run's edge, which reads as an indented
       block rather than as the section's own field order. The run's own flex gap separates the list from
       the heading above it, so this is a reset and nothing else - UtilitySpecificityTests holds the
       exemption. */
    margin: 0;
    padding-left: 0;
    list-style: none;

    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-form-row[b-3y5fuv7ty1] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);

    /* The drag has no glyph of its own - UiIcons carries no grip, and its path data is held
       character-identical to MudBlazor's by UiIconTests, so inventing one is not a styling decision. The
       cursor is the affordance, and it is a BONUS route rather than the only one (R13.4): the move buttons
       beside every row are the discoverable, keyboard-reachable mechanism. */
    cursor: grab;
}

.biztech-form-row-open[b-3y5fuv7ty1] {
    /* R12.7 asks for a second channel beside colour, and the row's own disclosure already carries
       aria-expanded - so this is the visual half of a state that is announced either way. */
    border-color: var(--biztech-palette-primary);
}

/* ── where a drop lands ───────────────────────────────────────────────────────────────────────────

   🔴 A LINE IN THE GAP, NOT A DASHED ROW. The row a drag was over wore a dashed border, which said "this
   row" when the drop means "between these two" - and whether it landed above or below was left to be
   discovered. A 2px bar in the gap on the side it will land says both. The rail's 4px row gap and 16px
   run gap are where the bars sit, centred in each.

   pointer-events: none, or the bar would be the drop target instead of the row under it. A bar is a shape
   in a position, not a colour alone (R12.7). */
.biztech-form-row[b-3y5fuv7ty1],
.biztech-form-group[b-3y5fuv7ty1] {
    position: relative;
}

.biztech-form-drop-before[b-3y5fuv7ty1]::before,
.biztech-form-drop-after[b-3y5fuv7ty1]::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    block-size: 2px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    pointer-events: none;
}

.biztech-form-row.biztech-form-drop-before[b-3y5fuv7ty1]::before {
    inset-block-start: -4px;
}

.biztech-form-row.biztech-form-drop-after[b-3y5fuv7ty1]::after {
    inset-block-end: -4px;
}

.biztech-form-group.biztech-form-drop-before[b-3y5fuv7ty1]::before {
    inset-block-start: -10px;
}

.biztech-form-group.biztech-form-drop-after[b-3y5fuv7ty1]::after {
    inset-block-end: -10px;
}

/* The thing being carried stays where it was, faded, so the list does not jump while it moves. */
.biztech-form-dragging[b-3y5fuv7ty1] {
    opacity: 0.4;
}

/* A palette pill and a section's band can be picked up, as a row can. */
.biztech-form-palette-pill[b-3y5fuv7ty1],
.biztech-form-band[b-3y5fuv7ty1] {
    cursor: grab;
}

/* The same mark UiTextField renders beside a required label, and the same token, so a palette change moves
   both together. Never shrinks: it is the one glyph on the line that must survive a long name. */
.biztech-form-required[b-3y5fuv7ty1] {
    flex: none;
    color: var(--biztech-palette-error);
    margin-inline-start: -4px;
}

/* 🔴 CLIPPED, NOT DROPPED. The asterisk above is aria-hidden, exactly as the seam's is - but the seam's
   control carries aria-required and a row has no control, so the announced channel has to be this word.
   R12.7's "never one channel" with the two halves reversed from the usual: the glyph is the visual one and
   the text is the announced one.

   The clip-path idiom is app.css's own, used by .biztech-skip-link and .biztech-labels-in-headers and given
   the same reasoning in both: the element stays in the accessibility tree, which display: none would
   remove. */
.biztech-form-required-word[b-3y5fuv7ty1] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Wraps, because a section can carry all four gates at once and a row that scrolled sideways to show the
   fourth would hide the very disclosure this chip row exists to surface. */
.biztech-form-gates[b-3y5fuv7ty1] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding-inline-start: 8px;
}

/* The marker's span, which this file renders - so the colour reaches it, and the icon inside draws in
   currentcolor. It was the icon's own Class, which I19 puts out of this sheet's reach. */
.biztech-form-problem[b-3y5fuv7ty1] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-error);
}

/* 🔴 THE EDITOR OPENS INSIDE THE ROW. The wrapper is always rendered and its contents are not - the
   composer's shape: `hidden` keeps a collapsed body out of the accessibility tree while keeping the
   trigger's aria-controls pointing at an element that exists, and the @if beside it stops Blazor building
   an 18-control editor nobody opened.

   Inset from the head, with a rule above it, because a run of open rows otherwise has no visible seam.
   `hidden` is a presentation hint the browser applies as `display: none`, and any `display` here would beat
   it - so the rule is guarded by :not([hidden]) rather than trusting that none is declared. */
.biztech-form-body:not([hidden])[b-3y5fuv7ty1] {
    margin-block-start: 8px;
    padding-block: 8px;
    padding-inline: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);

    /* The row is draggable and the editor inside it is not: a text field that started a drag on mousedown
       would be a field nobody could select text in. */
    cursor: auto;
}
/* /Components/Admin/FormBuilderConditionEditor.razor.rz.scp.css */
/* W3-30 · Part B. The condition editor. TOKENS ONLY (R3.1). Every class here is on this file's own markup (I19);
   the seam's selects, fields, checkboxes and buttons are placed by the containers below and never reached into.
   Spacing between siblings belongs to these containers' gaps (I18). Every length is a multiple of the 4px base
   unit (R5.1). */

/* The match, each test, and the actions, stacked. */
.biztech-condition-editor[b-08vqwel889] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* One test: field, operator, value and its Remove, one under another on a phone, side by side once there is
   room. A border rather than a shadow carries the grouping in flow (ADR 0026 D-E). min-width 0 on the tracks so
   a long field key can never push the row past the panel at 375px. */
.biztech-condition-row[b-08vqwel889] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

@media (min-width: 960px) {
    .biztech-condition-row[b-08vqwel889] {
        grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
        align-items: end;
    }
}

/* The choices of an "is one of" test, wrapping rather than widening the row. */
.biztech-condition-choices[b-08vqwel889] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* Add a test, and the sentence saying why it is unavailable at four. */
.biztech-condition-actions[b-08vqwel889] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}
/* /Components/Admin/FormBuilderDateBoundEditor.razor.rz.scp.css */
/* W3-30 · Part C. One side of a date range. TOKENS ONLY (R3.1). The class is on this file's own markup (I19); the
   seam's checkbox, number field, select and date field are placed by this container's gap and never reached into
   (I18). 8px is two of the 4px base unit (R5.1). */
.biztech-date-bound[b-lq6t1qmrmq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}
/* /Components/Admin/FormBuilderFieldEditor.razor.rz.scp.css */
/* W3-21 · R14.1 layer 3 — two rules, both for this component's own wrappers.

   The colour is NOT here: UiText carries it through Color="UiColor.Error", which is a semantic role
   (R3.1) rather than a value this sheet would have to restate and keep in step with the palette. What is
   here is the only thing the wrapper is for - putting each message on its own line under the control it
   concerns, rather than running several together as inline spans. */

.biztech-form-builder-problem-line[b-oumf2susz4] {
    display: block;

    /* One scale step, so a message sits closer to the control it belongs to than to the next field -
       R5.9's rule about a label and its value, applied to a control and its refusal. */
    margin-block-start: 4px;
}

/* 🔴 I20 · A CHECKBOX BESIDE A LABELLED FIELD STARTS ONE LABEL TOO HIGH, AND THIS IS THAT LABEL.

   `.biztech-field` is a label above a control; `.biztech-choice` is a box beside a word, with no label
   block at all. Sharing a row with Type and Key, the Required box therefore lined up with THEIR LABELS
   rather than with their controls - which is what an operator reported on this editor as "checkbox field is
   not aligned with the rest", and word for word what I20 records the same defect being called on
   `/portals/new`.

   align-self: end would bottom-align the boxes instead, and it is the wrong tool: a neighbour's label wraps
   to two lines in a narrow column, and the checkbox would then hang below its control. Offset by the height
   of the label block that is MISSING and the controls line up whatever the words do.

   CALCULATED FROM THE TWO TOKENS THAT MAKE THE LABEL, never typed as 24px - this is PortalChooser's rule,
   copied with its arithmetic rather than with its number. `.biztech-field-label` reads body2's size and line
   height, so that product is the label's own box (14px x 1.43 = 20.02px), and 4px is `.biztech-field`'s own
   row gap. A type-scale change moves the offset with it.

   🔴 sm (600px) RATHER THAN PortalChooser's md, AND THE BREAKPOINT HAS TO FOLLOW THE MARKUP'S OWN. These
   cells declare Xs="12" Sm="6" Md="3", so the checkbox is already sharing a row at sm; below it every cell
   is full width and the box sits UNDERNEATH its neighbour, where an offset would read as 24px of
   unexplained space in a stack. R13.1's spelling for this side of the boundary is min-width: 600px. */
@media (min-width: 600px) {
    .biztech-form-choice[b-oumf2susz4] {
        margin-block-start: calc(
            var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}
/* /Components/Admin/FormBuilderFormulaEditor.razor.rz.scp.css */
/* W3-30 · Part I, review fix 1 (I19). The formula's problems: one per line, no bullets, a 4px gap between them and from
   the words above - the same step the field editor's problem lines take (FormBuilderFieldEditor.razor.css), declared
   here because a scoped rule reaches only its own component's markup. The gap is the container's (I18).
   The list indent goes by padding-inline-start, the idiom UtilitySpecificityTests needs no entry for: a scoped
   `padding: 0` would outrank every biztech-pa-* utility (0,2,0 against 0,1,0). */
.biztech-form-builder-formula-problems[b-p44w9b1gre] {
    display: grid;
    gap: 4px;
    margin: 4px 0 0;
    padding-inline-start: 0;
    list-style: none;
}

/* W27-06 · the formula's label and Format on one row above the code editor. The gaps are the containers' (I18). */
.biztech-form-builder-formula[b-p44w9b1gre] {
    display: grid;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-form-builder-formula__head[b-p44w9b1gre] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
/* /Components/Admin/FormBuilderLookupEditor.razor.rz.scp.css */
/* W27-11 · P4b. The lookup's problems: one per line, no bullets, a 4px gap between them and from the words above - the step
   FormBuilderFormulaEditor.razor.css takes, declared here because a scoped rule reaches only its own component's markup.
   The gap is the container's (I18). The list indent goes by padding-inline-start, the idiom UtilitySpecificityTests needs
   no entry for. */
.biztech-form-builder-lookup-problems[b-z231zhql44] {
    display: grid;
    gap: 4px;
    margin: 4px 0 0;
    padding-inline-start: 0;
    list-style: none;
}

/* The lookup's label and Format on one row above the code editor. The gaps are the containers' (I18). */
.biztech-form-builder-lookup[b-z231zhql44] {
    display: grid;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-form-builder-lookup__head[b-z231zhql44] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
/* /Components/Admin/FormBuilderPreview.razor.rz.scp.css */
/* W3-22 · R14.1 layer 3 — one rule, for this component's own row of gate chips.

   The colour is NOT here: UiChip carries it through Color="UiColor.Warning", which is a semantic role (R3.1)
   rather than a value this sheet would have to restate and keep in step with the palette. What is here is the
   only thing the row is for — letting four chips wrap instead of pushing the section's heading sideways.

   Every length is a multiple of the 4px base unit (R5.1, R5.4). */

.biztech-form-preview-gates[b-o5fnwc482h] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;

    /* One scale step below the heading and two above the fields, so the marks read as belonging to the
       section they sit under rather than to the first field beneath them — R5.9's rule about a label and its
       value, applied to a section and its disclosure. */
    margin-block: 4px 8px;
}

/* W3-30 · Part B. A conditional field above the sentence naming its gate, spaced by this column's own gap (I18). */
.biztech-form-preview-field[b-o5fnwc482h] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The gate, in the caption slot's secondary ink: it describes the field, it does not ask anything. The user
   agent's block margin on a <p> is removed by app.css's document reset, so the column's gap is the only space. */
.biztech-form-preview-field-gate[b-o5fnwc482h] {
    color: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
}

/* W3-30 · Part A. Where a step starts, on a canvas that shows every step at once: the assignee's progress line,
   in the same secondary ink and caption weight, with a rule above so the break between two steps is visible
   without reading. Tokens only (R3.1). */
.biztech-form-preview-step[b-o5fnwc482h] {
    margin-block: 0 4px;
    color: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

/* A later step's marker: the break between two steps. Step 1 takes none, so no rule sits under the panel's top
   edge separating nothing. OutlineSubtle is the hairline role - NOT --biztech-palette-divider, which is not one
   of the 22 roles and resolves to nothing (DocumentViewPanel.razor.css records that mistake). */
.biztech-form-preview-step-break[b-o5fnwc482h] {
    margin-block-start: 24px;
    padding-block-start: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Admin/FormJsonEditor.razor.rz.scp.css */
/* W27-06 · the JSON editor's own markup: its label and Format on one row above the code editor, and the refusal
   caption under them. Spacing is the container's gap (I17/I18); the code editor draws its own box (UiCodeEditor). */
.biztech-form-json-editor[b-hq5efhw8fh] {
    display: grid;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-form-json-editor__head[b-hq5efhw8fh] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-form-json-editor__caption[b-hq5efhw8fh] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Admin/FormJsonErrorList.razor.rz.scp.css */
/* T25 · R14.1 layer 3 — the <ul> and its rows are this component's own markup.

   Layout only. Every colour here would be a palette colour, and the alert this list sits inside already
   supplies the error colour through MudTheme (layer 1), so there is nothing to declare.

   No font-size either, deliberately: R5.4 puts every raw length on the 4px scale, and the size this
   wanted (13px) is not on it. Inheriting the alert's own size is the right answer rather than a named
   constant invented for one list - the monospace face is what distinguishes a pointer from prose here,
   not a smaller one. */

.biztech-form-json-errors[b-e5is8tydob] {
    /* The default list indent puts the pointers a long way from the alert's icon, which reads as a
       separate block rather than as its detail. */
    margin: 0;
    padding-left: 0;
    list-style: none;
}

.biztech-form-json-errors li[b-e5is8tydob] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;

    /* Ten of these stack, so the rhythm between them is what makes the list scannable rather than a
       wall of text. One scale step. */
    padding-block: 0.25rem;
}

.biztech-form-json-errors code[b-e5is8tydob] {
    /* The pointer is a path into the document the operator is editing, so it must not re-wrap or
       re-space: "fields[3].type" is a string they will search for verbatim.

       A stack rather than var(--mud-typography-monospace-family): MudBlazor 9.0.0 emits no such
       variable, and a var() that resolves to nothing would silently fall back to the proportional
       body face - which is the one thing this rule exists to prevent. */
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    white-space: nowrap;
    align-self: flex-start;
}

.biztech-form-json-errors span[b-e5is8tydob] {
    /* Takes the remaining width so a long sentence wraps under itself rather than under the pointer. */
    flex: 1 1 12rem;
    min-width: 0;
}
/* /Components/Admin/ManagedRecordForm.razor.rz.scp.css */
/* W19 · the shared admin form on the console's card: the quiet edge, corners twice the theme's radius and the surface, as
   the panels beside the console's tables are drawn (W19-08). The padding is this rule's own, because the form is a div
   and not a UiPaper (I17). Every selector names this component's own markup (I19). */
/* W19-18 · the page's width, as every console page has it: the 60rem measure (ADR 0026 D-G) left a one-field record on a
   card in the left half of the page. The fields stay two-up from md (the grid below), so each is half the card - a
   readable length on any width this console runs at. */
.biztech-managed-form[b-xukp4h5398] {
    max-inline-size: none;
    padding: 24px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* Save, Delete and the caption are the form's foot, under a rule, rather than one more row of the grid. */
.biztech-managed-form-foot[b-xukp4h5398] {
    flex-wrap: wrap;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W31-10 · a create's progress bar takes a line of its own in the wrapping foot, spaced by the foot's gap. */
.biztech-managed-form-progress[b-xukp4h5398] {
    flex: 1 0 100%;
}

@media (max-width: 599.98px) {
    .biztech-managed-form[b-xukp4h5398] {
        padding: 16px;
    }
}

/* The delete section below Save: a hairline over it and its heading, sentence and button in one column (I18). */
.biztech-managed-form-delete[b-xukp4h5398] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-block-start: 24px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W19-18 · a record nothing on this page can change: a sentence saying where it is changed, then what it holds as label and
   value pairs, two columns from desktop width (I18). */
.biztech-managed-form-readonly[b-xukp4h5398] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-managed-form-facts[b-xukp4h5398] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 12px 24px;
}

.biztech-managed-form-fact[b-xukp4h5398] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Admin/ManagedRecordImport.razor.rz.scp.css */
/* W0-40 · I18. The gap between the panel's children belongs to the container, never a margin on each. A
   column rather than the default row, because the heading, the sentence, the field and the buttons read
   top to bottom. */
.biztech-import-panel-body[b-29iccfs1xc] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
/* /Components/Admin/ManagedRecordList.razor.rz.scp.css */
/* W19 · the shared admin list on the console's card. At desktop width the table sits on a surface card with the quiet edge
   and corners twice the theme's radius - /case-types' and /people's three declarations, so every admin record list reads as
   the same console. Below md the table reflows into one card per row (R13.3), and those cards take the same edge, corners
   and surface. Every selector names this component's own markup; UiTable's rows are reached through ::deep (I19). */
@media (min-width: 960px) {
    .biztech-table-scroll[b-35cs6t6y3v] {
        border: 1px solid var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: var(--biztech-palette-surface);
    }
}

@media (max-width: 959.98px) {
    .biztech-table-scroll[b-35cs6t6y3v]  .biztech-table-row {
        border-color: var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: var(--biztech-palette-surface);
    }
}

/* The empty block stands where the table would, on the same card. */
.biztech-managed-list-empty[b-35cs6t6y3v] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* ── the pager: where the reader is on the left, Previous and Next at the right end ─────────────────── */
.biztech-managed-list-pager[b-35cs6t6y3v] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
}

/* ── the sort arrow, the case list's (W19-02) ───────────────────────────────────────────────────────
   One glyph turned for descending. It sits on the word's text-bottom, which the font's own metrics place, because the
   label is an inline context and an svg has no baseline. 16px, a mark beside a 14px heading. Faint (.38, the
   disabled-content alpha) where the column could sort, the primary on the column that does. */
.biztech-sort-glyph[b-35cs6t6y3v] {
    display: inline-flex;
    align-items: center;
    margin-inline-start: 4px;
    vertical-align: text-bottom;
}

.biztech-sort-glyph[b-35cs6t6y3v]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
}

.biztech-sort-descending[b-35cs6t6y3v] {
    transform: rotate(180deg);
}

.biztech-sort-glyph-idle[b-35cs6t6y3v] {
    opacity: .38;
}

.biztech-sort-glyph:not(.biztech-sort-glyph-idle)[b-35cs6t6y3v] {
    color: var(--biztech-palette-primary);
}
/* /Components/Admin/ProcessDiagram.razor.rz.scp.css */
/*
    W19-03 · the Process tab's diagram disclosure - this component's own markup, on the case type editor and
    the create panel. Every colour is a --biztech-* role, every length a multiple of the 4px base unit.
*/

/* ── the disclosure ────────────────────────────────────────────────────────────────────

   A bordered disclosure across the full width above the tables. It was a paper in a Md="5" column, where
   a left-to-right map showed two stages and the tables beside it lost their width. No shadow: it sits in
   the flow (ADR 0026 D-E). */
.biztech-process-diagram[b-4pd0nc39xx] {
    margin-block-end: 16px;

    background: var(--biztech-palette-surface);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* The whole line is the control, with this sheet's chevron rather than the user agent's marker. */
.biztech-process-diagram-summary[b-4pd0nc39xx] {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 8px 12px;

    cursor: pointer;
    list-style: none;
}

.biztech-process-diagram-summary[b-4pd0nc39xx]::-webkit-details-marker {
    display: none;
}

.biztech-process-diagram-chevron[b-4pd0nc39xx] {
    display: inline-flex;
    align-self: center;
    color: var(--biztech-palette-text-secondary);
}

/* Points down closed and up open, turned rather than swapped - one glyph, as the drawer's groups do. */
.biztech-process-diagram[open] .biztech-process-diagram-chevron[b-4pd0nc39xx] {
    transform: rotate(180deg);
}

/* W19-07 · turned at the theme's motion duration rather than flipped. */
.biztech-process-diagram-chevron[b-4pd0nc39xx] {
    transition: transform var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-process-diagram-body[b-4pd0nc39xx] {
    padding: 0 12px 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    padding-block-start: 12px;
}


/* R6.8: the OS's reduced-motion choice wins over the theme's. */
@media (prefers-reduced-motion: reduce) {
    .biztech-process-diagram-chevron[b-4pd0nc39xx] {
        transition: none;
    }
}
/* /Components/Admin/ProcessJsonView.razor.rz.scp.css */
/* W27-04 · I18. The editor and the sentence under it are spaced by a gap, as .biztech-case-type-field spaces its own children. */
.biztech-process-json[b-tv9qswz7r8] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Admin/ProcessTransitionsTable.razor.rz.scp.css */
/* 🔴 THE GUARD CELL'S ROW, AND IT IS SCOPED RATHER THAN SHARED BECAUSE THE MARKUP IS THIS
   COMPONENT'S OWN. §2 I19: a scoped rule reaches its own component's elements, and `.biztech-guard`
   and the spans inside it are written in this file. The controls within them are UiSelect and
   UiTextField, which a scoped rule here cannot reach and does not need to.

   min-inline-size: 0 is the whole of it. A flex item's default minimum is its content, so three
   labelled controls in a 376px cell each refused to go below their own width, the row wrapped, and
   the layout was three stacked boxes again - measured at 1440: tops 40px and 64px apart, widths
   growing 179 -> 231 -> 293 as each took the full cell. Zero lets them share what there is. */
.biztech-guard > span[b-drb7gy0q4h] {
    min-inline-size: 0;
    flex: 1 1 7rem;
}
/* /Components/Assistant/Actions/AdminActionFactView.razor.rz.scp.css */
/* W28-07 · an action card. Spacing belongs to the containers (I18): the card stacks with a gap, the list with a smaller one. */

.biztech-action-card[b-kmyw615y3o] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* W19-19 · the items are rows ruled apart, as an upload card's files and the quick actions are - not loose lines of text. */
.biztech-action-card-list[b-kmyw615y3o] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

/* W28-13 · who the card acts on: one line each, under the summary. */
.biztech-action-card-subjects[b-kmyw615y3o] {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* W31-09 §3 · D5 · a deck card's title fields: one per chosen file, stacked. The class had no rule, so the fields ran together. */
.biztech-action-card-deck-titles[b-kmyw615y3o] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Each line is UiText's own <p>: reached with ::deep on its class (I19), and its margin is the document reset's. */
.biztech-action-card-subjects[b-kmyw615y3o]  .biztech-action-card-subject {
    overflow-wrap: anywhere;
}

/* The tick's wrapper may shrink below its label's width; the label is UiCheckbox's own, reached with ::deep (I19). */
.biztech-action-card-tick[b-kmyw615y3o] {
    min-inline-size: 0;
}

.biztech-action-card-item[b-kmyw615y3o]  .biztech-choice-label {
    overflow-wrap: anywhere;
}

.biztech-action-card-item[b-kmyw615y3o] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    min-inline-size: 0;
    padding-block: 8px;
    padding-inline: 4px;
}

.biztech-action-card-item + .biztech-action-card-item[b-kmyw615y3o] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W28-10 · what an item will cause: its own row under the item, one line per cause.
   W19-19 · set in from the item under a quiet rule, so it reads as the item's and not as an item of its own. */
.biztech-action-card-causes[b-kmyw615y3o] {
    display: flex;
    flex-direction: column;
    flex-basis: 100%;
    gap: 2px;
    min-inline-size: 0;
    margin-inline-start: 12px;
    padding-inline-start: 12px;
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* A long address wraps inside the card at 375px rather than taking the panel sideways. */
.biztech-action-card-text[b-kmyw615y3o],
.biztech-action-card-detail[b-kmyw615y3o],
.biztech-action-card-cause[b-kmyw615y3o] {
    overflow-wrap: anywhere;
}

.biztech-action-card-detail[b-kmyw615y3o],
.biztech-action-card-cause[b-kmyw615y3o],
.biztech-action-card-note[b-kmyw615y3o] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-action-card-actions[b-kmyw615y3o] {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

/* W19-19 · the card's head: the operation's name as a small caption over the one heading of what it does. */
.biztech-action-card-head[b-kmyw615y3o] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.biztech-action-card-kind[b-kmyw615y3o] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    font-weight: var(--biztech-font-button-weight);
    color: var(--biztech-palette-text-secondary);
}

/* W19-19 · the card's buttons at its foot: Dismiss in the text's ink, the primary action last, both pills - the proposal pane's. */
.biztech-action-card-actions[b-kmyw615y3o] {
    align-items: center;
    padding-block-start: 4px;
}

.biztech-action-card-actions[b-kmyw615y3o]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

/* W19-19 · AS10's red line: a glyph and one caption line in the error colour, over the buttons. Its margin is the document reset's. */
.biztech-action-card-warning[b-kmyw615y3o] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-error);
}

.biztech-action-card-warning[b-kmyw615y3o]  .biztech-icon {
    flex: none;
}
/* /Components/Assistant/Actions/AdminActionFileChooser.razor.rz.scp.css */
/* W28-18 · W19-19 · an upload card's chooser: the drop area, one row per chosen file, the card's one line, and - once Upload is
   pressed with nothing chosen - the reason it waits. Spaced by the column's gap (I18). */
.biztech-action-card-files[b-mi30uuv9sc] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* 🔴 THE DROP AREA. A dashed box holding the upload glyph and the prompt over its hint; the real file input lies over all of it,
   transparent, so a press anywhere opens the picker and a drop lands on the input itself - the browser's own drop onto a file
   field. Its label is said, not drawn (the area draws it). The edge firms on hover and while a file is dragged over; the focus
   ring is the area's, since the input inside it cannot show one. */
.biztech-action-card-drop[b-mi30uuv9sc] {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    border: 1px dashed var(--biztech-palette-outline);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-background);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-action-card-drop:hover[b-mi30uuv9sc],
.biztech-action-card-drop:has(:focus-visible)[b-mi30uuv9sc] {
    border-color: var(--biztech-palette-primary);
}

.biztech-action-card-drop:has(:focus-visible)[b-mi30uuv9sc] {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 2px;
}

.biztech-action-card-drop[data-disabled][b-mi30uuv9sc] {
    opacity: 0.6;
}

.biztech-action-card-drop-glyph[b-mi30uuv9sc] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-action-card-drop-words[b-mi30uuv9sc] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.biztech-action-card-drop-prompt[b-mi30uuv9sc] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    font-weight: var(--biztech-font-button-weight);
    color: var(--biztech-palette-text-primary);
}

.biztech-action-card-drop-hint[b-mi30uuv9sc] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The seam's field fills the area; its input covers it, transparent; its label is clipped. ::deep: UiFileField renders them (I19). */
.biztech-action-card-drop[b-mi30uuv9sc]  .biztech-field {
    position: absolute;
    inset: 0;
}

.biztech-action-card-drop[b-mi30uuv9sc]  .biztech-input {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    opacity: 0;
    cursor: pointer;
}

.biztech-action-card-drop[b-mi30uuv9sc]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The chosen files: one row each, ruled apart as the quick actions are. */
.biztech-action-card-file-list[b-mi30uuv9sc] {
    display: flex;
    flex-direction: column;
}

.biztech-action-card-file[b-mi30uuv9sc] {
    display: flex;
    align-items: center;
    gap: 12px;
    min-inline-size: 0;
    padding: 8px 4px 8px 8px;
}

.biztech-action-card-file + .biztech-action-card-file[b-mi30uuv9sc] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-action-card-file-glyph[b-mi30uuv9sc] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-primary);
}

/* W30-07 · D7 · a chosen picture, shown before Upload in the glyph's place. */
.biztech-action-card-file-thumbnail[b-mi30uuv9sc] {
    flex: none;
    inline-size: 2.5rem;
    block-size: 2.5rem;
    object-fit: contain;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-action-card-file-words[b-mi30uuv9sc] {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    min-inline-size: 0;
}

.biztech-action-card-file-name[b-mi30uuv9sc] {
    min-inline-size: 0;
    max-inline-size: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-primary);
}

.biztech-action-card-file-size[b-mi30uuv9sc],
.biztech-action-card-file-later[b-mi30uuv9sc] {
    flex: none;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-action-card-file-later[b-mi30uuv9sc] {
    flex-basis: 100%;
    color: var(--biztech-palette-warning);
}

/* A logo's slot at the row's end, its label said and not drawn: the row is the file, the select its slot. */
.biztech-action-card-file-slot[b-mi30uuv9sc] {
    flex: none;
    inline-size: 11rem;
}

.biztech-action-card-file-slot[b-mi30uuv9sc]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-action-card-file[b-mi30uuv9sc]  .biztech-icon-button {
    flex: none;
    color: var(--biztech-palette-text-secondary);
}

.biztech-action-card-files-note[b-mi30uuv9sc],
.biztech-action-card-files-reason[b-mi30uuv9sc] {
    margin-block: 0;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-action-card-files-reason[b-mi30uuv9sc] {
    color: var(--biztech-palette-error);
}

@media (prefers-reduced-motion: reduce) {
    .biztech-action-card-drop[b-mi30uuv9sc] {
        transition: none;
    }
}
/* /Components/Assistant/Actions/AdminActionProgressView.razor.rz.scp.css */
/* W19-19 · an upload card while it runs: the bar and its count on one line, then each item a row ruled apart, as the chosen files were. */
.biztech-action-card-progress[b-dk756lei51] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-action-card-progress-head[b-dk756lei51] {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* The bar is UiProgressLinear's own element, reached with ::deep (I19); it takes the row's width beside the count. */
.biztech-action-card-progress-head[b-dk756lei51]  .biztech-action-card-progress-bar {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-action-card-progress-status[b-dk756lei51] {
    flex: none;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

.biztech-action-card-progress-list[b-dk756lei51] {
    display: flex;
    flex-direction: column;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-action-card-progress-row[b-dk756lei51] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    min-inline-size: 0;
    padding-block: 8px;
    padding-inline: 4px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-action-card-progress-row + .biztech-action-card-progress-row[b-dk756lei51] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-action-card-progress-name[b-dk756lei51] {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-action-card-progress-text[b-dk756lei51] {
    flex: none;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}
/* /Components/Assistant/Actions/AdminLogoSlotChooser.razor.rz.scp.css */
/* W28-21 · a logo row holds its slot's name, its picker and its one-line help, stacked: the gap belongs to the row, so at 375px the
   label sits above the file and its buttons with nothing to scroll sideways. */
/* The card's own column spaces its children (I18): the rows, "Choose several" and the notes below them. */
.biztech-logo-rows[b-w1zckgp6qr] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* R5.8 · a summary is 20px tall by default; under a coarse pointer it is a 44px target. */
@media (pointer: coarse) {
    .biztech-logo-other-summary[b-w1zckgp6qr] {
        display: flex;
        align-items: center;
        min-block-size: 44px;
    }
}

/* The closed disclosure over the rows nobody asked for: its rows sit under the summary with the same gap. */
.biztech-logo-other > .biztech-logo-rows[b-w1zckgp6qr] {
    margin-block-start: 8px;
}

.biztech-logo-row[b-w1zckgp6qr] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    min-inline-size: 0;
}
/* /Components/Assistant/AdminAnswerView.razor.rz.scp.css */
/* W22-02 · TD28. One turn in Admin mode.

   Its question, answer, working line and actions are the help turn's own classes, defined once in AssistantAnswerView.razor.css and
   reached from here by the SAME class names on this component's OWN markup - a scoped sheet reaches only the component that
   carries its attribute (I19), so the rules are repeated for this component and not shared by selector.

   🔴 NO COLOUR OF ITS OWN (ADR 0026 D-A). An admin turn is told apart by its words and its cards. */

.biztech-assistant-exchange[b-ujv7ekqru7] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* W19-05 · the asker's question as the help turn draws it: a bubble at the end of the row in the panel header's pair, the
   corner nearest the asker squared off. The header's colours are the panel's, not Admin's, so D-A's "no colour of its own"
   still holds - both modes draw it the same. */
.biztech-assistant-question[b-ujv7ekqru7] {
    align-self: flex-end;
    max-inline-size: 85%;
    padding: 8px 12px;
    background: light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container));
    color: light-dark(var(--biztech-palette-on-primary), var(--biztech-palette-on-primary-container));
    border-radius: calc(var(--biztech-radius-default) * 2);
    border-end-end-radius: calc(var(--biztech-radius-default) / 2);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

/* W19-19 · the files a question was sent with: compact chips at the bubble's side, over it - the composer's chips without their ×.
   A <ul> because how many there are is information; its indent goes by its own padding-inline-start. */
.biztech-assistant-question-files[b-ujv7ekqru7] {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-self: flex-end;
    gap: 8px;
    max-inline-size: 85%;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-assistant-question-file[b-ujv7ekqru7] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
    block-size: 36px;
    padding-inline: 8px 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-assistant-question-file-glyph[b-ujv7ekqru7] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-primary);
}

.biztech-assistant-question-file-name[b-ujv7ekqru7] {
    min-inline-size: 0;
    max-inline-size: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--biztech-palette-text-primary);
    font-weight: var(--biztech-font-button-weight);
}

/* W22-05 · finding 1 · the reply is paragraphs and lists now (AdminProseView, which styles them), spaced by this container (I18). */
.biztech-assistant-answer[b-ujv7ekqru7] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    font-size: var(--biztech-font-body2-size);
    line-height: 1.6;
    overflow-wrap: anywhere;
}

.biztech-assistant-working[b-ujv7ekqru7] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-actions[b-ujv7ekqru7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-text-secondary);
}

/* W19-05 · its text actions as the help turn's Stop is: a pill. */
.biztech-assistant-actions[b-ujv7ekqru7]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

/* W19-06 · the reply beside the assistant's mark, and the dots while it is written - AssistantAnswerView.razor.css's rules,
   repeated here because a scoped sheet reaches only its own component (I19), as this file's header says of the rest. */
.biztech-assistant-reply[b-ujv7ekqru7] {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr);
    align-items: start;
    gap: 12px;
}

.biztech-assistant-reply-mark[b-ujv7ekqru7] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 28px;
    block-size: 28px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-assistant-reply-mark[b-ujv7ekqru7]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
    font-size: 16px;
}

.biztech-assistant-reply-body[b-ujv7ekqru7] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding-block-start: 4px;
}

.biztech-assistant-typing[b-ujv7ekqru7] {
    display: inline-flex;
    gap: 4px;
}

.biztech-assistant-typing span[b-ujv7ekqru7] {
    inline-size: 8px;
    block-size: 8px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    animation: biztech-admin-typing-b-ujv7ekqru7 calc(var(--biztech-motion-duration, 120ms) * 10) ease-in-out infinite;
}

.biztech-assistant-typing span:nth-child(2)[b-ujv7ekqru7] {
    animation-delay: calc(var(--biztech-motion-duration, 120ms) * 2);
}

.biztech-assistant-typing span:nth-child(3)[b-ujv7ekqru7] {
    animation-delay: calc(var(--biztech-motion-duration, 120ms) * 4);
}

@keyframes biztech-admin-typing-b-ujv7ekqru7 {
    0%,
    80%,
    100% {
        opacity: 0.25;
    }

    40% {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-assistant-typing span[b-ujv7ekqru7] {
        animation: none;
        opacity: 0.6;
    }
}

/* W19-06 · the proposal and fact cards in the panel's shape. Each card's root is UiPaper, which its own sheet cannot reach (I19: a
   scoped rule reaches only its component's own markup, and a component root is the paper's), so the turn that holds them draws
   them: corners twice the theme's radius and the quiet edge every other card in the panel carries, and their actions as pills. */
.biztech-assistant-reply-body[b-ujv7ekqru7]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-assistant-reply-body[b-ujv7ekqru7]  .biztech-paper .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

/* W29-01 · D9. What the Assistant changed in a plan step: the lead and the diff stack with a gap (I18), the diff scrolls inside its own box.
   W19-19 · a box of its own, as the proposal's JSON is: the quiet edge, the page's ground, monospace at the caption size, and
   at most 320px tall before it scrolls, so a long change does not push the reply's buttons out of view. */
.biztech-plan-review[b-ujv7ekqru7] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-plan-diff[b-ujv7ekqru7] {
    margin: 0;
    max-block-size: 320px;
    overflow: auto;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
    white-space: pre;
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-body2-line-height);
    scrollbar-width: thin;
}
/* /Components/Assistant/AdminAssistantChat.razor.rz.scp.css */
/* W28-13 P10 · the conversation, its empty state and the question box, split out of AdminAssistantPage.razor.css with the markup they
   style. Every colour, radius, shadow and duration is a --biztech-* variable, so a tenant's palette, radius, depth and motion reach it
   (ADR 0026). */

/* 🔴 position: relative, AND IT IS WHAT KEEPS THE WINDOW STILL. The clipped status line is absolutely placed; without a positioned
   ancestor it was placed against the document at its static spot under the whole conversation, and the document grew to reach it.

   Two bands: the conversation's scroller over the box's band. The scroller is the full width, so its bar sits at the window's edge
   and a wheel anywhere over the chat moves the conversation; the box's band is in flow below it, so nothing ever passes under the box. */
.biztech-admin-chat-main[b-j5mzaxe6tf] {
    position: relative;
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    min-block-size: 0;
    overflow: hidden;
}

.biztech-admin-chat-scroll[b-j5mzaxe6tf] {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    padding-inline: 24px;
}

/* The reading column, centred; a short conversation's thread still fills the band, so the first turn starts at the top. */
.biztech-admin-chat[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    inline-size: 100%;
    max-inline-size: 48rem;
    min-block-size: 100%;
    margin-inline: auto;
    min-inline-size: 0;
}

/* ── The empty conversation ─────────────────────────────────────────────────────────────────────────────────────────────── */

/* One object, centred: the greeting, the box with its suggestions, then the templates. The space above lets it sit in the upper middle of the
   window, where a reader's eye lands. */
/* 🔴 CENTRED IN WHAT THE WINDOW LEAVES, AND `margin-block: auto` IS WHY IT CANNOT CLIP. The space above used to be a flat `6vh`,
   which is not centring - it is a guess that lands differently on every window, and on a short one it left a band of nothing at the
   top while pushing the suggestions under the fold. The scroller's child already declares `min-block-size: 100%`, so an auto margin
   on both sides of this section splits the leftover height between them: centred when there is room, collapsing to zero when there
   is not. `justify-content: center` would centre it too and then clip the top off anything taller than the window, because overflow
   has no way back past a centred flex line - an auto margin never produces unreachable overflow. */
.biztech-admin-chat-hero[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 24px;
    margin-block: auto;
    padding-block: 16px;
    text-align: center;
}

.biztech-admin-chat-mark[b-j5mzaxe6tf] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 48px;
    block-size: 48px;
    margin-block-end: -12px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-admin-chat-mark[b-j5mzaxe6tf]  .biztech-icon {
    inline-size: 28px;
    block-size: 28px;
    font-size: 28px;
}

.biztech-admin-chat-hero-box[b-j5mzaxe6tf] {
    inline-size: 100%;
    text-align: start;
}

/* W19-14 · a few short requests to start from, under the box: a caption, then plain rows ruled apart - no card around them. A
   <ul> because how many there are is information; its indent goes by its own padding-inline-start. Each row is one text button:
   its words, and a chevron at its end while it is hovered. They write in the box and go nowhere, so they are page ink, never link-blue. */
.biztech-admin-chat-quick[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    inline-size: 100%;
    text-align: start;
}

.biztech-admin-chat-quick > :first-child[b-j5mzaxe6tf] {
    padding-inline: 4px;
}

.biztech-admin-chat-starters[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-admin-chat-starters > li + li[b-j5mzaxe6tf] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-admin-chat-starter[b-j5mzaxe6tf] {
    display: flex;
}

.biztech-admin-chat-starter[b-j5mzaxe6tf]  .biztech-button {
    flex: 1 1 auto;
    justify-content: flex-start;
    gap: 12px;
    min-block-size: 40px;
    padding-inline: 12px;
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    letter-spacing: normal;
    text-align: start;
    text-transform: none;
}

/* Hovered, a faint wash of the ink across the row - the navigation rows' hover - and its chevron shows. */
.biztech-admin-chat-starter[b-j5mzaxe6tf]  .biztech-button:hover:not(:disabled) {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 4%, transparent);
}

.biztech-admin-chat-starter[b-j5mzaxe6tf]  .biztech-button-label {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-admin-chat-starter-words[b-j5mzaxe6tf] {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The chevron is drawn only while its row is hovered or holds keyboard focus: a quiet list at rest, the row under the pointer
   saying it can be pressed. Its box stays, so the words never move as it comes and goes. */
.biztech-admin-chat-starter-go[b-j5mzaxe6tf] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
    opacity: 0;
    transition: opacity var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-admin-chat-starter[b-j5mzaxe6tf]  .biztech-button:focus-visible .biztech-admin-chat-starter-go {
    opacity: 1;
}

.biztech-admin-chat-starter[b-j5mzaxe6tf]  .biztech-button:hover:not(:disabled) .biztech-admin-chat-starter-go {
    color: var(--biztech-palette-text-primary);
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .biztech-admin-chat-starter-go[b-j5mzaxe6tf] {
        transition: none;
    }
}


/* W22-08 · templates: a caption with View more, then two cards side by side - one column on a phone. Each card is one button: the
   job and the parts it sets up on one line. The card's edge and ground are the page's cards'; lit on hover. */
.biztech-admin-chat-templates[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    inline-size: 100%;
    padding-block-start: 8px;
    text-align: start;
    animation: biztech-appear var(--biztech-motion-duration, 120ms) ease-in-out calc(var(--biztech-motion-duration, 120ms) * 2) backwards;
}

.biztech-admin-chat-template-list[b-j5mzaxe6tf] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: 12px;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-admin-chat-template[b-j5mzaxe6tf] {
    display: flex;
    min-inline-size: 0;
}

/* 🔴 THE CARD KEEPS ITS OWN GROUND ON HOVER. A text button's hover is a grey wash (UiButton.razor.css, :hover:not(:disabled)), which
   turned the white card grey under the pointer; the selectors carry that rule's weight so the card's surface stands. */
.biztech-admin-chat-template[b-j5mzaxe6tf]  .biztech-button,
.biztech-admin-chat-template[b-j5mzaxe6tf]  .biztech-button:hover:not(:disabled) {
    flex: 1 1 auto;
    align-items: stretch;
    inline-size: 100%;
    block-size: auto;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    color: var(--biztech-palette-text-primary);
    text-align: start;
    white-space: normal;
    letter-spacing: normal;
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* Hovered, the card's edge firms to the full outline - lit, not recoloured. */
.biztech-admin-chat-template[b-j5mzaxe6tf]  .biztech-button:hover:not(:disabled) {
    border-color: var(--biztech-palette-outline);
}


.biztech-admin-chat-template[b-j5mzaxe6tf]  .biztech-button-label {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-admin-chat-template-words[b-j5mzaxe6tf] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}


.biztech-admin-chat-template-title[b-j5mzaxe6tf] {
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    line-height: var(--biztech-font-subtitle2-line-height);
}

/* The caption and View more on one line, at the row's two ends. */
.biztech-admin-chat-templates-head[b-j5mzaxe6tf] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-admin-chat-templates-more[b-j5mzaxe6tf]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

/* The parts it sets up, one line, cut with an ellipsis, so two cards stay one short row. */
.biztech-admin-chat-template-steps[b-j5mzaxe6tf] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

@media (prefers-reduced-motion: reduce) {
    .biztech-admin-chat-templates[b-j5mzaxe6tf],
    .biztech-admin-chat-template[b-j5mzaxe6tf]  .biztech-button {
            animation: none;
            transition: none;
        }
}

.biztech-admin-chat-notice[b-j5mzaxe6tf] {
    inline-size: 100%;
    margin-block: 0;
    padding: 12px 16px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
    background: var(--biztech-palette-surface);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    text-align: start;
}

/* ── The conversation ───────────────────────────────────────────────────────────────────────────────────────────────────── */
.biztech-admin-chat-thread[b-j5mzaxe6tf] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 40px;
    min-inline-size: 0;
    padding-block: 40px 8px;
}

/* 🔴 ON THE PAGE THE TURNS READ AS TWO VOICES WITHOUT A BADGE: the question a quiet bubble at the row's end, the reply plain text across
   the column with no mark beside it, and its actions a row of glyphs under it. The panel keeps its mark and its header-coloured
   bubble - it is narrow, and the colour tells its two voices apart there; a page column has the room to do it by position alone, and a
   full column of brand-coloured bubbles would be colour as a field (ADR 0026 D-A). Body size rather than the panel's body2. ::deep:
   AdminAnswerView renders all of it (I19). */
.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-exchange {
    gap: 24px;
}

.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-question {
    max-inline-size: 75%;
    padding: 12px 16px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 7%, var(--biztech-palette-background));
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-body1-size);
    line-height: var(--biztech-font-body1-line-height);
}

.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-reply {
    display: block;
}

.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-reply-mark {
    display: none;
}

.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-reply-body {
    gap: 16px;
    padding-block-start: 0;
}

.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-answer {
    font-size: var(--biztech-font-body1-size);
    line-height: 1.7;
}

/* The proposal and fact cards at the page's width: more room inside, on the surface, with the theme's card depth. */
.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-reply-body .biztech-paper {
    padding: 20px;
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-actions {
    margin-inline-start: -8px;
}

/* Scrolled to after each question and each answer; its margin keeps the last line clear of the pinned dock. */
/* W28-21 · B31. The two quick replies under a question: a wrapping row, spaced by its gap. */
.biztech-admin-chat-reply-chips[b-j5mzaxe6tf] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* W28-21 walk · the guide message a plan's conversation gains when a step is applied or skipped: its words, then the next step's reply. */
.biztech-admin-chat-guide[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-admin-chat-end[b-j5mzaxe6tf] {
    scroll-margin-block-end: 16px;
}

/* Pinned to the bottom of the chat's scroller while the thread scrolls under it. The fade above the box is the page's own ground, so a turn
   passing beneath goes out quietly rather than being cut at a line. */
/* The box's band, under the conversation and never over it. Its own column, as wide as the reading column and centred the same way,
   with the scroller's gutters, so the box lines up with the turns above it. */
.biztech-admin-chat-dock[b-j5mzaxe6tf] {
    flex: none;
    padding: 12px 24px 16px;
}

.biztech-admin-chat-dock-inner[b-j5mzaxe6tf] {
    inline-size: 100%;
    max-inline-size: 48rem;
    margin-inline: auto;
}

/* Said to a screen reader and not drawn: the turn itself shows a stop or a failure, and "answered" under the box is news only to
   someone who cannot see the answer arrive (the panel's data-quiet, for the same reason). */
.biztech-admin-chat-status[b-j5mzaxe6tf] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ── The question box ───────────────────────────────────────────────────────────────────────────────────────────────────── */
.biztech-admin-chat-compose[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* One card: the field on top, a toolbar under it. The field draws no edge, ring or hover of its own - the card is the control a reader
   sees, so the card shows the hover and the focus. Focused, its edge thickens to the primary colour (see :focus-within below). */
.biztech-admin-chat-box[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 8px 8px 4px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    transition:
        border-color var(--biztech-motion-duration, 120ms) ease-in-out,
        box-shadow var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* Not while it is focused: the hover would repaint the edge the ring lies on (app.css), and the line would read twice as thick. */
.biztech-admin-chat-box:hover:not(:focus-within)[b-j5mzaxe6tf] {
    border-color: var(--biztech-palette-outline);
}

/* Focused, the edge goes at once. It used to fade out at the motion setting, and for that moment the hovered edge's dark line showed
   under the primary ring before it went - a flicker on every click into the box. */
.biztech-admin-chat-box:focus-within[b-j5mzaxe6tf] {
    transition: none;
}

/* 🔴 THE CARD DRAWS NO FOCUS EDGE OF ITS OWN, AND THAT IS R3.11 RATHER THAN A PREFERENCE.
   What was here: `border-color: primary` plus `box-shadow: inset 0 0 0 1px primary` while anything inside had focus - with the box
   itself suppressing the house ring through `outline: none` so the two would not double up. The suppression is what the rule bans
   outright, and its exemption list is empty on purpose: two cards argued it down to zero and the sweep has no row to add.

   The box is `.biztech-input`, which app.css's single ring declaration already names, so removing the suppression gives it the same
   2px ring every other field in the console wears, on its own edge (`outline-offset: 0`, the field override). The card's edge then
   has to go, or focus would be said twice - and "declared once" is the sweep's own name. The card keeps its hover and its resting
   depth; what it gives up is a second way of saying the same thing. */
/* 🔴 THE SEND GLYPH SITS ON THE ATTACH ROW, at its end: the field takes the card's whole width, and the glyph is laid at the bottom
   corner of the field and the row together. It is the composer's own button, moved rather than copied, so its gating, its stop and
   its label are the composer's still. The row keeps the glyph's height and its end clear of it. */
.biztech-admin-chat-box-main[b-j5mzaxe6tf] {
    position: relative;
}

.biztech-assistant-composer[b-j5mzaxe6tf] {
    display: grid;
    min-inline-size: 0;
}

/* 🔴 THE SEAM'S CHAT COMPOSER, DRAWN AS THIS CARD'S CONTENT. UiChatComposer rules its row off with a hairline and pads it for a session
   rail; here the card is the frame, so the row draws neither, and the send glyph sits at the row's end, level with the last line. */
.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-chat-composer__row {
    align-items: flex-end;
    gap: 8px;
    padding: 0 0 0 4px;
    border-block-start: none;
}

/* 🔴 THE BOX GROWS WITH WHAT IS TYPED, from one line to about twelve, then scrolls inside itself. field-sizing: content sizes a textarea
   to its text; a browser without it keeps the composer's two rows, and Shift+Enter still starts a new line. Like the single-line field
   before it, the box draws no edge or hover of its own - the card shows those - and the selector carries the card and the
   pseudo-classes so it outweighs app.css's field rules.

   🔴 IT DOES DRAW ITS OWN RING, WHICH IT USED TO SUPPRESS. `outline: none` sat in this block so the card's focus edge would not be
   doubled; R3.11 bans the property and the card's edge went instead (see the note where it was). The border still goes transparent
   here, as app.css's own field rule does, so the ring lands on the edge rather than standing off from a second line. */
.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-chat-composer__box,
.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-chat-composer__box:hover:not(:disabled):not(:focus-visible),
.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-chat-composer__box:focus-visible {
    field-sizing: content;
    min-block-size: 48px;
    max-block-size: 18rem;
    padding: 12px 8px;
    overflow-y: auto;
    border-color: transparent;
    background: transparent;
    font-size: var(--biztech-font-body1-size);
    line-height: var(--biztech-font-body1-line-height);
    resize: none;
}

/* 🔴 R3.11'S ONE EXEMPTION: THE FIELD DRAWS NO RING, BECAUSE THE CARD AROUND IT DOES. The field is the card's whole upper half with
   no edge of its own, so its ring was a second box drawn inside the card. The shared ring is declared on the card instead
   (app.css, `.biztech-admin-chat-box:has(.biztech-chat-composer__box:focus-visible)`), so focus is said once, round the thing a
   reader sees as the box. PortalStyleSheetTests allows this selector and no other. */
.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-chat-composer__box:focus-visible {
    outline: none;
}

/* Filled while there is something to send, and a bare disabled glyph when there is not - the panel's own pair. The composer's module
   keeps `disabled` in step with the box as it is typed. */
.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-icon-button {
    position: absolute;
    inset-block-end: 0;
    inset-inline-end: 0;
}

.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-icon-button:not(:disabled) {
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
}

.biztech-admin-chat-box .biztech-assistant-composer[b-j5mzaxe6tf]  .biztech-icon-button:hover:not(:disabled) {
    background: color-mix(in srgb, var(--biztech-palette-primary) 88%, var(--biztech-palette-on-primary));
}

/* The attach row under the box. */
.biztech-admin-chat-toolbar[b-j5mzaxe6tf] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-block-size: 40px;
    padding-inline: 8px 48px;
}

.biztech-admin-chat-toolbar[b-j5mzaxe6tf]  .biztech-assistant-brief {
    flex: 1 1 12rem;
    min-inline-size: 0;
}

/* The attach row's limits are a paragraph under the box. They stay for a screen reader, clipped; a sighted reader meets them in the
   refusal when a file breaks one, which names the limit it broke. */
.biztech-admin-chat-toolbar[b-j5mzaxe6tf]  .biztech-assistant-brief-limits {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-admin-chat-hero[b-j5mzaxe6tf],
.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-exchange,
.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-paper,
.biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-card-line {
    animation: biztech-appear var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The suggestions follow the box by a beat, so the eye goes to the box first. */
.biztech-admin-chat-starters[b-j5mzaxe6tf] {
    animation: biztech-appear var(--biztech-motion-duration, 120ms) ease-in-out var(--biztech-motion-duration, 120ms) backwards;
}

@media (prefers-reduced-motion: reduce) {
    .biztech-admin-chat-hero[b-j5mzaxe6tf],
    .biztech-admin-chat-starters[b-j5mzaxe6tf],
    .biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-exchange,
    .biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-paper,
    .biztech-admin-chat-thread[b-j5mzaxe6tf]  .biztech-assistant-card-line {
            animation: none;
        }

    .biztech-admin-chat-box[b-j5mzaxe6tf] {
            transition: none;
        }
}

@media (max-width: 959.98px) {
    .biztech-admin-chat-scroll[b-j5mzaxe6tf],
    .biztech-admin-chat-dock[b-j5mzaxe6tf] {
            padding-inline: 16px;
        }
}

/* W28-21 · D17 · the open plan's opening: its body and standing under the heading, gapped like the hero. */
.biztech-admin-chat-opening[b-j5mzaxe6tf] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-inline-size: 60ch;
}

/* W28-21 · D19 · Show plan: drawn only while the plan is hidden, at every width, so widening the window after Back to chat never strands the plan. */
.biztech-admin-chat-show-plan[b-j5mzaxe6tf] {
    display: flex;
    justify-content: flex-end;
    padding-inline: 16px;
}
/* /Components/Assistant/AdminAssistantSide.razor.rz.scp.css */
/* W28-13 P10 · the conversation list and the plans, split out of AdminAssistantPage.razor.css with the markup they style. A rule that
   needs the layout's state (data-side, data-resizing) stays in the page and reaches in with ::deep on this component's own class
   (I19): the page's sheet says which. Every colour, radius, shadow and duration is a --biztech-* variable (ADR 0026). */

/* The list's right-edge handle: the preview's bar, drawn on the list's edge. The page's sheet holds the same base rules for the
   preview's handle, and the layout-state ones (closed, being dragged) for this one. */
.biztech-admin-chat-resize[b-1suhdblfdo] {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: var(--biztech-layer-sticky);
    inline-size: 8px;
    cursor: col-resize;
    touch-action: none;
}

.biztech-admin-chat-resize[b-1suhdblfdo]::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: 2px;
    background: transparent;
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The list's handle is its right edge, and only while the list is open. */
.biztech-admin-chat-resize-side[b-1suhdblfdo] {
    inset-inline: auto 0;
}

.biztech-admin-chat-resize-side[b-1suhdblfdo]::after {
    inset-inline: auto 0;
}

.biztech-admin-chat-resize:hover[b-1suhdblfdo]::after,
.biztech-admin-chat-resize:focus-visible[b-1suhdblfdo]::after {
    background: var(--biztech-palette-primary);
}

.biztech-admin-chat-resize:focus-visible[b-1suhdblfdo] {
    outline-offset: 0;
}

/* ── The conversation list ──────────────────────────────────────────────────────────────────────────────────────────────── */

/* A column of the layout's height, ruled off from the chat by a hairline as the navigation is. The list and the rail share its one
   cell and cross-fade as it slides; the list keeps its full width throughout and is clipped by the column, so it slides rather than
   squeezes. The list scrolls inside itself when it is long. */
.biztech-admin-chat-side[b-1suhdblfdo] {
    position: relative;
    display: grid;
    min-block-size: 0;
    min-inline-size: 0;
    overflow: hidden;
    border-inline-end: 1px solid var(--biztech-palette-outline-subtle);
    background: var(--biztech-palette-surface);
}

/* 🔴 border-box, AND THE COLUMN'S HAIRLINE TAKEN OFF. The track is the list's width; its 1px edge and the list's own padding sit inside
   it, so a list drawn at the track's full content width ran past the edge and was clipped there. */
.biztech-admin-chat-side-full[b-1suhdblfdo],
.biztech-admin-chat-side-rail[b-1suhdblfdo] {
    grid-area: 1 / 1;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    min-block-size: 0;
    transition: opacity var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-admin-chat-side-full[b-1suhdblfdo] {
    gap: 4px;
    inline-size: calc(var(--admin-chat-side) - 1px);
    padding: 12px 16px 12px 12px;
    overflow-y: auto;
    scrollbar-width: thin;
}

/* Folded: a rail of glyphs, centred in the rail's width. */
/* Folded, the rail holds New conversation alone, at the top: the same tinted circle the open list's New conversation carries. */
.biztech-admin-chat-side-rail[b-1suhdblfdo] {
    align-items: center;
    gap: 8px;
    inline-size: calc(var(--admin-chat-rail) - 1px);
    padding-block: 12px;
}

.biztech-admin-chat-rail-item[b-1suhdblfdo]  .biztech-icon-button {
    inline-size: 32px;
    block-size: 32px;
    min-inline-size: 32px;
    padding-block: 0;
    padding-inline: 0;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* The list's heading, said and not drawn: New conversation heads the column. */
.biztech-admin-chat-side-heading[b-1suhdblfdo] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* New conversation: a row of the list's own shape, its glyph in a tinted circle so it reads as the action the list starts with. */
.biztech-admin-chat-new[b-1suhdblfdo]  .biztech-button {
    inline-size: 100%;
    justify-content: flex-start;
    gap: 12px;
    padding-inline: 8px;
    border-radius: var(--biztech-radius-default);
    font-weight: var(--biztech-font-button-weight);
    color: var(--biztech-palette-text-primary);
}

.biztech-admin-chat-new[b-1suhdblfdo]  .biztech-button:hover {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, transparent);
}

.biztech-admin-chat-new[b-1suhdblfdo]  .biztech-button .biztech-icon {
    inline-size: 20px;
    block-size: 20px;
    padding: 2px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* 🔴 NEW CONVERSATION STANDS OFF THE LIST BY ITS OWN PADDING, BECAUSE THE THING THAT USED TO DO IT IS GONE. A "Recent" caption sat
   between them carrying `padding: 20px 8px 4px`, so the separation was a side effect of a label rather than anything declared: take
   the label away and New conversation drops onto the first conversation at the column's 4px gap. The padding is on this element's
   own box rather than a margin between siblings (I18), which is what the caption was doing too. 12px here and the column's 4px gap
   make 16. The list's heading is still said - the clipped <h2> above names the column to a screen reader. */
.biztech-admin-chat-new[b-1suhdblfdo] {
    display: block;
    padding-block-end: 12px;
}

/* W28-01 · the Plans group above the conversations: a caption, New plan, then the plan rows in the conversations' own shape. The
   group stands off the conversations by its own padding, as New conversation does (I18). */
.biztech-admin-chat-plans[b-1suhdblfdo] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-block-end: 12px;
}

/* W28-08 · the plans, then Export setup: one column, spaced by its gap. */
.biztech-admin-chat-setup[b-1suhdblfdo] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-14 · the Plans heading is said, not drawn: the tab above names the list. */
.biztech-admin-chat-plans-heading[b-1suhdblfdo] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* W19-14 · Chats and Plans: the segmented pair across the column's head, each half the width. */
.biztech-admin-chat-side-tabs[b-1suhdblfdo] {
    display: flex;
    flex: none;
    margin-block-end: 8px;
}

.biztech-admin-chat-side-tabs[b-1suhdblfdo]  .biztech-button {
    flex: 1 1 0;
}

/* A row being renamed: its field, then the tick and the cross. The field draws the house edge, as a field should while it is edited. */
.biztech-admin-chat-conversation-rename[b-1suhdblfdo] {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 2px;
    min-inline-size: 0;
    padding-block: 4px;
}

.biztech-admin-chat-conversation-rename[b-1suhdblfdo]  .biztech-field {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-admin-chat-conversation-rename[b-1suhdblfdo]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-admin-chat-side-note[b-1suhdblfdo] {
    margin-block: 0;
    padding-inline: 8px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-admin-chat-conversations[b-1suhdblfdo] {
    display: flex;
    flex-direction: column;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

/* A row: its title as one button, its delete at the far end, shown on hover or focus so the list reads as titles. The open
   conversation is tinted - the segmented control's "the open item is tinted, not filled". */
/* Each row ruled off from the next by a hairline inset to the titles' edge, so the list reads as rows and not as lines of a paragraph.
   The ROW is what lights - on hover and when open - across its title and its delete alike. */
.biztech-admin-chat-conversation[b-1suhdblfdo] {
    position: relative;
    display: flex;
    align-items: center;
    border-radius: var(--biztech-radius-default);
    transition: background-color var(--biztech-motion-duration) ease-in-out;
}

.biztech-admin-chat-conversation + .biztech-admin-chat-conversation[b-1suhdblfdo]::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* A lit row and the one after it need no rule between them: the tint already separates them. */
.biztech-admin-chat-conversation:hover[b-1suhdblfdo]::before,
.biztech-admin-chat-conversation[data-current][b-1suhdblfdo]::before,
.biztech-admin-chat-conversation:hover + .biztech-admin-chat-conversation[b-1suhdblfdo]::before,
.biztech-admin-chat-conversation[data-current] + .biztech-admin-chat-conversation[b-1suhdblfdo]::before {
    border-color: transparent;
}

.biztech-admin-chat-conversation:hover[b-1suhdblfdo] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, transparent);
}

.biztech-admin-chat-conversation[data-current][b-1suhdblfdo] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 9%, transparent);
}

.biztech-admin-chat-conversation-open[b-1suhdblfdo] {
    display: flex;
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* The title on one line, cut with an ellipsis; the row is the tinted thing, so the button draws no fill, edge or pressed state of its
   own (aria-pressed still says which is open). */
/* Prefixed with the row so these outweigh UiButton's own hover and pressed rules, whatever order the scoped sheets are bundled in. */
.biztech-admin-chat-conversation .biztech-admin-chat-conversation-open[b-1suhdblfdo]  .biztech-button,
.biztech-admin-chat-conversation .biztech-admin-chat-conversation-open[b-1suhdblfdo]  .biztech-button:hover,
.biztech-admin-chat-conversation .biztech-admin-chat-conversation-open[b-1suhdblfdo]  .biztech-button[aria-pressed="true"] {
    justify-content: flex-start;
    inline-size: 100%;
    min-inline-size: 0;
    block-size: 40px;
    padding-inline: 8px;
    border-color: transparent;
    border-radius: var(--biztech-radius-default);
    background: transparent;
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    letter-spacing: normal;
    color: var(--biztech-palette-text-primary);
}

.biztech-admin-chat-conversation-open[b-1suhdblfdo]  .biztech-button-label {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-admin-chat-conversation[data-current] .biztech-admin-chat-conversation-open[b-1suhdblfdo]  .biztech-button {
    font-weight: var(--biztech-font-button-weight);
}

/* W28-13 · a plan's row has a second line: where it started and when it last changed. The button keeps the first line to itself. */
.biztech-admin-chat-plan-open[b-1suhdblfdo] {
    flex-direction: column;
    align-items: flex-start;
}

/* W28-13 walk: an ellipsis hid the time, which is what tells two plans of one name apart. W19-14 · so the time comes first and
   never shrinks, and the template after it takes the ellipsis: one line, every row the same height, the time always shown. */
/* W31-10 · a time now names its zone ("02:19 UTC-04:00"), which with the date is wider than the column; the line wraps so the
   template moves under it, rather than the row clipping the zone off the time and reading as another zone (R4.7). */
.biztech-admin-chat-plan-detail[b-1suhdblfdo] {
    display: flex;
    flex-wrap: wrap;
    max-inline-size: 100%;
    min-inline-size: 0;
    white-space: nowrap;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-admin-chat-conversation-menu[b-1suhdblfdo] {
    display: flex;
    flex: none;
    padding-inline-end: 4px;
    opacity: 0;
    transition: opacity var(--biztech-motion-duration) ease-in-out;
}

/* 🔴 THE ROW'S MENU IS AS WIDE AS ITS TWO WORDS. The seam's panel has a 12rem floor and hangs from the ⋯ button's end, and at the list's
   narrowest (200px) that floor ran it past the list's start, where the list's own scroller clipped it. Two short items need 8rem. */
.biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-menu-panel {
    min-inline-size: 8rem;
}

/* Delete in the menu says what it does in the error role's colour, its glyph too - the words still say it (R12.7). The menu panel is the
   seam's, so ::deep, through the class the row hands its item. */
.biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-admin-chat-menu-delete,
.biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-admin-chat-menu-delete .biztech-icon {
    color: var(--biztech-palette-error);
}

.biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-admin-chat-menu-delete:hover {
    background: color-mix(in srgb, var(--biztech-palette-error) 8%, transparent);
}

/* The delete's own hover fill would be a second, smaller tint inside the row's; the glyph darkens instead. */
.biztech-admin-chat-conversation .biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-icon-button,
.biztech-admin-chat-conversation .biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-icon-button:hover {
    background: transparent;
    color: var(--biztech-palette-text-secondary);
}

.biztech-admin-chat-conversation .biztech-admin-chat-conversation-menu[b-1suhdblfdo]  .biztech-icon-button:hover {
    color: var(--biztech-palette-text-primary);
}

.biztech-admin-chat-conversation:hover .biztech-admin-chat-conversation-menu[b-1suhdblfdo],
.biztech-admin-chat-conversation:focus-within .biztech-admin-chat-conversation-menu[b-1suhdblfdo] {
    opacity: 1;
}

.biztech-admin-chat-conversation[b-1suhdblfdo] {
    animation: biztech-appear var(--biztech-motion-duration, 120ms) ease-in-out;
}

@media (prefers-reduced-motion: reduce) {
    .biztech-admin-chat-conversation[b-1suhdblfdo] {
            animation: none;
        }

    .biztech-admin-chat-resize[b-1suhdblfdo]::after,
    .biztech-admin-chat-side-full[b-1suhdblfdo],
    .biztech-admin-chat-side-rail[b-1suhdblfdo],
    .biztech-admin-chat-conversation[b-1suhdblfdo],
    .biztech-admin-chat-conversation-menu[b-1suhdblfdo] {
            transition: none;
        }
}

@media (max-width: 959.98px) {
    .biztech-admin-chat-side[b-1suhdblfdo] {
            overflow: visible;
        }

    .biztech-admin-chat-side-full[b-1suhdblfdo] {
            position: fixed;
            inset-block: var(--biztech-content-block-start, 0px) 0;
            inset-inline-start: 0;
            z-index: var(--biztech-layer-drawer);
            inline-size: min(18rem, 85vw);
            border-inline-end: 1px solid var(--biztech-palette-outline-subtle);
            background: var(--biztech-palette-surface);
            transition:
                opacity var(--biztech-motion-duration, 120ms) ease-in-out,
                transform var(--biztech-motion-duration, 120ms) ease-in-out;
        }

    .biztech-admin-chat-resize[b-1suhdblfdo] {
            display: none;
        }

        /* Without a hover, a delete that only appears on one could never be found. */
    .biztech-admin-chat-conversation-menu[b-1suhdblfdo] {
            opacity: 1;
        }
}

/* W31-10 · the time and its zone may wrap between words rather than run past the column's edge and lose the zone. */
.biztech-admin-chat-plan-when[b-1suhdblfdo] {
    flex: 0 1 auto;
    min-inline-size: 0;
    white-space: normal;
}

.biztech-admin-chat-plan-from[b-1suhdblfdo] {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 🔴 W19-14 · A PLAN IS ONE ROW OF TWO LINES. Its name and the line under it are one button (AdminAssistantSide), so the row's
   height is its two lines - the name 2px over its date, never a 40px button with the date hung under it - and the hover, the tint
   of the open plan and the press all cover both. Between the plans, the conversations' own hairline, so the two lists are ruled
   alike. The selectors carry the conversation row's weight, which sets its 40px, so these are read after it. */

.biztech-admin-chat-conversation .biztech-admin-chat-plan-open[b-1suhdblfdo]  .biztech-button,
.biztech-admin-chat-conversation .biztech-admin-chat-plan-open[b-1suhdblfdo]  .biztech-button:hover,
.biztech-admin-chat-conversation .biztech-admin-chat-plan-open[b-1suhdblfdo]  .biztech-button[aria-pressed="true"] {
    block-size: auto;
    min-block-size: 0;
    padding-block: 8px;
}

.biztech-admin-chat-plan-open[b-1suhdblfdo]  .biztech-button-label {
    display: flex;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-admin-chat-plan-words[b-1suhdblfdo] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
    text-align: start;
}

/* The two lines set close: a 2px gap, and each at a line height a little over its type, so the date reads as the name's own line. */
.biztech-admin-chat-plan-name[b-1suhdblfdo] {
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-admin-chat-plan-open .biztech-admin-chat-plan-detail[b-1suhdblfdo] {
    line-height: 1.4;
}
/* /Components/Assistant/AdminBriefPicker.razor.rz.scp.css */
/* W22-08 · moved from AssistantPanel.razor.css with the markup it styles, so the panel and the admin assistant page draw one row. */

/* W22-04 · Admin's attach row, under the composer and spaced by the footer's gap; the refusal stacks under the field. */
.biztech-assistant-brief[b-q1xi4t1s8o] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* 🔴 W19-06 · THE ATTACH ROW, DRAWN AS THE PANEL IS RATHER THAN AS THE BROWSER'S FILE BOX.

   It stays UiFileField - a real <input type="file"> (R8.8), with its own label and its own Remove - and this sheet only
   draws it. The field lays out as a row; its label is a pill with the attach glyph; the native box is clipped (the
   skip-link idiom: out of sight, still in the accessibility tree and still a tab stop, and its label still opens the
   picker), so the browser's own "Choose File / No file chosen" no longer stands in the footer. While the box has
   keyboard focus the pill wears app.css's ring, because the box itself cannot be seen to. Every rule reaches into
   UiFileField and UiText, so each says ::deep (I19). */
.biztech-assistant-brief-row[b-q1xi4t1s8o] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-assistant-brief-row[b-q1xi4t1s8o]  .biztech-field {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-assistant-brief-row[b-q1xi4t1s8o]  .biztech-field-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 12px 4px 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-caption-line-height);
    cursor: pointer;
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The attach glyph - UiIcons.AttachFile's own path - painted in the label's ink through a mask, because a label carries
   only its words and the seam gives it no slot for an icon. */
.biztech-assistant-brief-row[b-q1xi4t1s8o]  .biztech-field-label::before {
    content: "";
    inline-size: 16px;
    block-size: 16px;
    background: currentcolor;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.biztech-assistant-brief-row[b-q1xi4t1s8o]  .biztech-field-label:hover {
    border-color: var(--biztech-palette-primary);
}

.biztech-assistant-brief-row[b-q1xi4t1s8o]  .biztech-field:has(.biztech-input:focus-visible) .biztech-field-label {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 2px;
}

.biztech-assistant-brief-row[b-q1xi4t1s8o]  .biztech-field .biztech-input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-assistant-brief-limits[b-q1xi4t1s8o] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* 🔴 W19-19 · THE CHIPS: ONE ROW THAT WRAPS, EACH COMPACT. A chip is the file type's glyph, the name cut with an ellipsis, its size in
   the secondary ink, and a small ×. They sit side by side and wrap only when the row is full - each was a full-width pill on a line of
   its own, with Remove in words and a long name wrapped over three lines. The page's ground inside the box's surface, the tables'
   subtle edge, the theme's radius. */
.biztech-assistant-chips[b-q1xi4t1s8o] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.biztech-assistant-attached[b-q1xi4t1s8o] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-inline-size: 100%;
    min-inline-size: 0;
    block-size: 36px;
    padding-inline: 8px 4px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-assistant-attached-glyph[b-q1xi4t1s8o] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-primary);
}

.biztech-assistant-attached-name[b-q1xi4t1s8o] {
    min-inline-size: 0;
    max-inline-size: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--biztech-palette-text-primary);
    font-weight: var(--biztech-font-button-weight);
}

.biztech-assistant-attached-size[b-q1xi4t1s8o] {
    flex: none;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-attached[b-q1xi4t1s8o]  .biztech-icon-button {
    flex: none;
    inline-size: 24px;
    block-size: 24px;
    min-inline-size: 24px;
    padding-block: 0;
    padding-inline: 0;
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-attached[b-q1xi4t1s8o]  .biztech-icon-button:hover:not(:disabled) {
    color: var(--biztech-palette-text-primary);
}

/* The brand offer is a row of its own words and its button, not a chip: it keeps the chip's edge and ground at full height. */
.biztech-assistant-attached[data-admin-brand-offer][b-q1xi4t1s8o] {
    flex-wrap: wrap;
    align-self: flex-start;
    block-size: auto;
    padding: 8px 8px 8px 12px;
}

.biztech-assistant-attached[data-admin-brand-offer][b-q1xi4t1s8o]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}
/* /Components/Assistant/AdminLimitNotice.razor.rz.scp.css */
/* W28-14. The daily limit's notice: a warning or the reached state when there is one, and Continue after a stopped request. */
.biztech-admin-limit[b-0xn18dx64p] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-admin-limit-continue[b-0xn18dx64p] {
    display: flex;
}
/* /Components/Assistant/AdminPlanArtifact.razor.rz.scp.css */
/* W28-01 · a plan as an artifact in the Setup assistant page's pane: the proposal artifact's shell - a head, the step tabs and a body
   that scrolls. A column of the pane's height; only the body scrolls, so the head and the tabs stay. */
.biztech-plan-artifact[b-o78qlmn2sd] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    block-size: 100%;
    min-block-size: 0;
}

/* The name and its version on the leading side; Versions, Download and Close on the trailing one. */
.biztech-plan-artifact-head[b-o78qlmn2sd] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 12px;
    padding: 12px 12px 12px 20px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

/* W31-10 walk · the title shrank to one letter beside "Edit 5 of 5" and "8 of 8 steps done" in a narrow pane; the row wraps, and the
   title keeps at least 8rem before it ellipsizes. */
.biztech-plan-artifact-titles[b-o78qlmn2sd] {
    display: flex;
    flex-wrap: wrap;
    flex: 1 1 12rem;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-plan-artifact-titles[b-o78qlmn2sd]  h2 {
    min-inline-size: min(8rem, 100%);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-plan-artifact-version[b-o78qlmn2sd] {
    flex: none;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.biztech-plan-artifact-tools[b-o78qlmn2sd] {
    display: flex;
    align-items: center;
    gap: 4px;
}

.biztech-plan-artifact-versions[b-o78qlmn2sd]  .biztech-menu-trigger,
.biztech-plan-artifact-download[b-o78qlmn2sd]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

.biztech-plan-artifact-body[b-o78qlmn2sd] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 16px;
    min-block-size: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    padding: 20px;
    background: var(--biztech-palette-background);
}

/* An old version: what it is, and Restore at the far end. */
.biztech-plan-artifact-note[b-o78qlmn2sd] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-plan-artifact-note-words[b-o78qlmn2sd] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-plan-artifact-note[b-o78qlmn2sd]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

.biztech-plan-artifact-list[b-o78qlmn2sd] {
    margin-block: 0;
    padding-inline-start: 20px;
}

/* W28-08 · AS23 · the Live tab: the closed tenant framed from this origin, as tall as the pane allows. */
.biztech-plan-live[b-o78qlmn2sd] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 8px;
    min-block-size: 0;
}

/* 🔴 W19-14 · THE FRAME'S STAGE: THE REST OF THE PANE, FRAMED, AND NO MINIMUM HEIGHT. One of 32rem was taller than the pane on a
   laptop, so the body scrolled as well as the portal inside it - two scrollbars side by side, the portal proposal preview's own
   finding. The frame lies in the stage absolutely, so its height is always the stage's; the portal scrolls, the body does not. */
.biztech-plan-live-stage[b-o78qlmn2sd] {
    position: relative;
    flex: 1 1 auto;
    min-block-size: 0;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-plan-live-frame[b-o78qlmn2sd] {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    display: block;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: 100%;
    border: none;
}

/* As on a desktop screen: drawn at 1280px and scaled to the stage by biztech-fit.js, which sets data-fit once it is live; a failed
   import leaves the pane's width (R9.11). zoom scales the width given in pixels; the height is a share of the stage, so the frame
   still fills it and the page inside sees a desktop's window. */
.biztech-plan-live-stage[data-desktop] .biztech-plan-live-frame[data-fit][b-o78qlmn2sd] {
    --biztech-fit-zoom: 1;
    inline-size: 1280px;
    zoom: var(--biztech-fit-zoom);
}

/* The width switch: one outlined pill holding two glyph buttons, the pressed one tinted - the proposal pane's switch. */
.biztech-plan-artifact-switch[b-o78qlmn2sd] {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
}

.biztech-plan-artifact-switch[b-o78qlmn2sd]  .biztech-icon-button {
    inline-size: 28px;
    block-size: 28px;
    min-inline-size: 28px;
    padding-block: 0;
    padding-inline: 0;
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-text-secondary);
}

.biztech-plan-artifact-switch[b-o78qlmn2sd]  .biztech-icon-button[aria-pressed="true"] {
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* W28-21 · D19 · Back to chat: only where the pane covers the chat (below 960px), and only when the host handles it. */
.biztech-plan-artifact-back[b-o78qlmn2sd] {
    display: none;
}

@media (max-width: 959.98px) {
    .biztech-plan-artifact-back[b-o78qlmn2sd] {
        display: inline-flex;
        flex-basis: 100%;
    }

    /* The name wraps under Back to chat rather than shrinking to nothing beside it. */
    .biztech-plan-artifact-titles[b-o78qlmn2sd] {
        flex-wrap: wrap;
    }
}

/* W28-21 · D20 · the title as a field with Save and Cancel, one row. */
.biztech-plan-artifact-rename[b-o78qlmn2sd] {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-plan-artifact-rename[b-o78qlmn2sd]  .biztech-field {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-plan-artifact-rename[b-o78qlmn2sd]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The pane's name while the title is a field: still the aside's label, not painted. */
.biztech-plan-artifact-title-hidden[b-o78qlmn2sd] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* W30-08 · D16. Back to the import sits in the tools row as a button; its form takes no room of its own. */
.biztech-plan-artifact-back-to-import[b-o78qlmn2sd] {
    display: inline-flex;
}

.biztech-plan-artifact-back-to-import form[b-o78qlmn2sd] {
    display: contents;
}
/* /Components/Assistant/AdminPlanBrandPreview.razor.rz.scp.css */
/* W30-07 · D4 · D6 · the Brand step drawn: the theme with its switches, the contrast failures, then the logos and pictures, in a
   column whose gap is the only spacing between them (I18). The canvas scales itself to the pane, so it fits at 375px. */
.biztech-plan-brand[b-zfwebacldz] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-plan-brand-head[b-zfwebacldz] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 12px;
}

/* At 375px the switches wrap under the heading rather than pushing the pane sideways. */
.biztech-plan-brand-switches[b-zfwebacldz] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.biztech-plan-brand-switch[b-zfwebacldz] {
    display: inline-flex;
    gap: 4px;
}

.biztech-plan-brand-canvas[b-zfwebacldz],
.biztech-plan-brand-part[b-zfwebacldz],
.biztech-plan-brand-organisation[b-zfwebacldz] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-plan-brand-contrast[b-zfwebacldz] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-error);
    border-radius: var(--biztech-radius-default);
}

.biztech-plan-brand-note[b-zfwebacldz] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-plan-brand-list[b-zfwebacldz] {
    margin-block: 0;
    padding-inline-start: 20px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    overflow-wrap: anywhere;
}
/* /Components/Assistant/AdminPlanCaseTypesPreview.razor.rz.scp.css */
/* W30-07 · D8 · the case types, one row each, ruled apart; the gap is the only spacing inside a row (I18). */
.biztech-plan-case-types-list[b-brwi56627c] {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-plan-case-type[b-brwi56627c] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    min-inline-size: 0;
}

.biztech-plan-case-type + .biztech-plan-case-type[b-brwi56627c] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-plan-case-type-head[b-brwi56627c] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
}

.biztech-plan-case-type-words[b-brwi56627c] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
    min-inline-size: 0;
}

.biztech-plan-case-type-name[b-brwi56627c] {
    font-weight: var(--biztech-font-subtitle2-weight);
    overflow-wrap: anywhere;
}

.biztech-plan-case-type-note[b-brwi56627c] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The form is drawn at the pane's width and scrolls inside itself rather than taking the pane sideways at 375px. */
.biztech-plan-case-type-body[b-brwi56627c],
.biztech-plan-case-type-form[b-brwi56627c] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    overflow-x: auto;
}
/* /Components/Assistant/AdminPlanDryRun.razor.rz.scp.css */
/* W19-14 · W30-07 · a step's dry run as a card of its own: its heading, its note and its rows, in a column whose gap is the only
   spacing between them (I18). */
.biztech-plan-dry[b-jdhly0czza] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* W19-14 · the dry run's rows ruled off inside its card: the outline-subtle edge at the theme's radius. */
.biztech-plan-dry[b-jdhly0czza]  .biztech-table-scroll {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}
/* /Components/Assistant/AdminPlanPeople.razor.rz.scp.css */
/* W28-08 · the people step's sheet and its column choices: a panel, its fields in a grid that is one column at phone width. */
.biztech-plan-people[b-u58bftley8] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

.biztech-plan-people-fields[b-u58bftley8] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 12px;
}

.biztech-plan-people-problems[b-u58bftley8] {
    margin-block: 0;
    padding-inline-start: 20px;
}
/* /Components/Assistant/AdminPlanPictures.razor.rz.scp.css */
/* W30-07 · D6 · pictures by slot: a wrapping grid of thumbnails, each over its label; the gap is the only spacing (I18). */
.biztech-plan-pictures[b-roxp038q9j] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
    gap: 12px;
    min-inline-size: 0;
}

.biztech-plan-picture[b-roxp038q9j] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-plan-picture-image[b-roxp038q9j] {
    display: block;
    inline-size: 100%;
    block-size: 4rem;
    object-fit: contain;
    padding: 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-plan-picture-missing[b-roxp038q9j] {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
    overflow-wrap: anywhere;
}

.biztech-plan-picture-label[b-roxp038q9j] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}
/* /Components/Assistant/AdminPlanPortalPreview.razor.rz.scp.css */
/* W30-07 · D9 · each portal under its name: a frame of it as the plan has it, or the reason there is none. The gap is the only
   spacing (I18). */
.biztech-plan-portal[b-pitjzs4j2g],
.biztech-plan-portal-one[b-pitjzs4j2g] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-plan-portal[b-pitjzs4j2g] {
    gap: 16px;
}

.biztech-plan-portal-head[b-pitjzs4j2g] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
}

.biztech-plan-portal-switch[b-pitjzs4j2g] {
    display: inline-flex;
    gap: 4px;
}

/* The stage has a height of its own inside the step - the step scrolls, the portal scrolls inside its frame - and the frame lies in it
   absolutely, so it is always the stage's size; at 375px it is the pane's width. */
.biztech-plan-portal-stage[b-pitjzs4j2g] {
    position: relative;
    block-size: 28rem;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-plan-portal-frame[b-pitjzs4j2g] {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    display: block;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: 100%;
    border: none;
}

/* As on a desktop screen: drawn at 1280px and scaled to the stage by biztech-fit.js, which sets data-fit once it is live (R9.11). */
.biztech-plan-portal-stage[data-desktop] .biztech-plan-portal-frame[data-fit][b-pitjzs4j2g] {
    --biztech-fit-zoom: 1;
    inline-size: 1280px;
    zoom: var(--biztech-fit-zoom);
}

.biztech-plan-portal-note[b-pitjzs4j2g] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Assistant/AdminPlanPublish.razor.rz.scp.css */
/* W31-10 · once the tenant is open: Open the tenant and Close the plan, side by side under the review. */
.biztech-plan-published-actions[b-fjmo0hah1h] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Assistant/AdminPlanStepGuide.razor.rz.scp.css */
/* W28-21 · a step's guide: needs, what comes first, still needed, Skip and Next. A column whose gap is the only spacing (I18). */
.biztech-plan-guide[b-ceykqtahr2] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-plan-guide-section[b-ceykqtahr2] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-plan-guide-list[b-ceykqtahr2] {
    margin-block: 0;
    padding-inline-start: 20px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-plan-guide-ticks[b-ceykqtahr2] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-plan-guide-skip[b-ceykqtahr2] {
    align-self: flex-start;
}

.biztech-plan-guide-next[b-ceykqtahr2] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
}
/* /Components/Assistant/AdminPlanStepOutcome.razor.rz.scp.css */
/* W30-07 · D10 · what the last Apply did: the counts, what did not save, and the links, in a column whose gap is the only spacing
   (I18). A panel of its own (I17: it declares its own padding). */
.biztech-plan-outcome[b-f2nfky1kt5] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
    min-inline-size: 0;
}

.biztech-plan-outcome-counts[b-f2nfky1kt5] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-plan-outcome-list[b-f2nfky1kt5] {
    margin-block: 0;
    padding-inline-start: 20px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    overflow-wrap: anywhere;
}

.biztech-plan-outcome-links[b-f2nfky1kt5] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
}

.biztech-plan-outcome-link[b-f2nfky1kt5] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}
/* /Components/Assistant/AdminPlanStepReview.razor.rz.scp.css */
/* Spacing belongs to the container (I18): the review stacks its list, lead and diff with a gap; its own children carry none. */
.biztech-plan-review[b-sn6f6t9nzx] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W19-19 · who wrote each version is the diff's provenance, said at the caption size in the secondary ink. */
.biztech-plan-step-list[b-sn6f6t9nzx] {
    margin: 0;
    padding-inline-start: 20px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* W29-01 · D9. The diff scrolls inside its own box at 375px rather than taking the page sideways.
   W19-19 · a box of its own, as the proposal's JSON is: the quiet edge, the page's ground, monospace at the caption size, and
   at most 320px tall before it scrolls, so a long change does not push the reply's buttons out of view. */
.biztech-plan-diff[b-sn6f6t9nzx] {
    margin: 0;
    max-block-size: 320px;
    overflow: auto;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
    white-space: pre;
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-body2-line-height);
    scrollbar-width: thin;
}
/* /Components/Assistant/AdminPlanStepSummary.razor.rz.scp.css */
/* W30-07 · D1 · what a step holds, in words: a column of groups whose gap is the only spacing between them (I18). */
.biztech-plan-summary[b-ofo6y22mij] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-plan-summary-group[b-ofo6y22mij] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-plan-summary-lines[b-ofo6y22mij],
.biztech-plan-summary-tree[b-ofo6y22mij] {
    margin-block: 0;
    padding-inline-start: 20px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    overflow-wrap: anywhere;
}

.biztech-plan-summary-note[b-ofo6y22mij] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* D3 · an empty step is a card of its own (I17: it declares its own padding). */
.biztech-plan-summary-empty[b-ofo6y22mij] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    padding: 16px;
    border: 1px dashed var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Assistant/AdminPlanStepView.razor.rz.scp.css */
/* W28-01 · one step of a plan in the plan artifact: its status, its summary, its previews, Advanced, the dry run and Apply, in a
   column whose gap is the only spacing between them (I18). */
.biztech-plan-step[b-1ai15y3iqz] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-plan-step-status[b-1ai15y3iqz] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* W30-07 · D2 · Advanced: the disclosure, then the editor under it while open; the gap is the only spacing (I18). */
.biztech-plan-step-advanced[b-1ai15y3iqz] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-plan-step-advanced-toggle[b-1ai15y3iqz] {
    align-self: flex-start;
}

.biztech-plan-step-advanced-body[b-1ai15y3iqz] {
    min-inline-size: 0;
}

.biztech-plan-step-editor[b-1ai15y3iqz] {
    display: block;
    min-inline-size: 0;
}

.biztech-plan-step-lead[b-1ai15y3iqz] {
    margin-block: 0;
}

.biztech-plan-step-list[b-1ai15y3iqz] {
    margin-block: 4px 0;
    padding-inline-start: 20px;
}

/* 🔴 W19-14 · THE STEP'S ACTIONS: ONE BAR AT THE FOOT OF THE PANE'S SCROLLER, on the pane's own ground, as a proposal's are. It sticks
   to the scroller's foot so Save and Apply are in reach however far the editor and the rows run, and reaches the scroller's edges
   (its 20px padding taken back) so nothing scrolls past it at the sides. What the dry run says about applying sits at its start; Save
   then Apply, both pills, at its end. */
.biztech-plan-step-bar[b-1ai15y3iqz] {
    position: sticky;
    inset-block-end: -20px;
    z-index: var(--biztech-layer-sticky);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px 12px;
    margin-inline: -20px;
    margin-block-end: -20px;
    padding: 12px 20px 20px;
    background: var(--biztech-palette-background);
}

.biztech-plan-step-message[b-1ai15y3iqz] {
    flex: 1 1 12rem;
    min-inline-size: 0;
}

.biztech-plan-step-bar[b-1ai15y3iqz]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}
/* /Components/Assistant/AdminProposalArtifact.razor.rz.scp.css */
/* W22-08 · a proposal as an artifact in the Setup assistant page's pane: a head, the tabs, an optional working line, a body that
   scrolls, and a footer of the card's buttons. A column of the pane's height; only the body scrolls, so the head and the buttons stay. */
.biztech-artifact[b-o2jjww7ppv] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    block-size: 100%;
    min-block-size: 0;
}

/* The name and its kind on the leading side; the versions, the menu of what else waits and Close on the trailing one. */
.biztech-artifact-head[b-o2jjww7ppv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 12px;
    padding: 12px 12px 12px 20px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-artifact-titles[b-o2jjww7ppv] {
    display: flex;
    flex: 1 1 12rem;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-artifact-titles[b-o2jjww7ppv]  h2 {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-artifact-chip[b-o2jjww7ppv] {
    display: inline-flex;
    flex: none;
}

.biztech-artifact-tools[b-o2jjww7ppv] {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* The preview's switches - a portal's width, a theme's console or portal and its colour mode: each one outlined pill holding two glyph
   buttons, the pressed one tinted.
   ::deep: UiIconButton renders the buttons (I19). */
.biztech-artifact-switch[b-o2jjww7ppv] {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
}

.biztech-artifact-switch[b-o2jjww7ppv]  .biztech-icon-button {
    inline-size: 28px;
    block-size: 28px;
    min-inline-size: 28px;
    padding-block: 0;
    padding-inline: 0;
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-text-secondary);
}

.biztech-artifact-switch[b-o2jjww7ppv]  .biztech-icon-button[aria-pressed="true"] {
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-artifact-versions[b-o2jjww7ppv] {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding-inline: 4px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
}

.biztech-artifact-version-words[b-o2jjww7ppv] {
    padding-inline: 4px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.biztech-artifact-view[b-o2jjww7ppv]  .biztech-menu-trigger,
.biztech-artifact-pending[b-o2jjww7ppv]  .biztech-menu-trigger {
    border-radius: var(--biztech-radius-pill);
}

/* The body's frame, so the working veil can lie over what is in view however far the body has scrolled. */
.biztech-artifact-stage[b-o2jjww7ppv] {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-block-size: 0;
}

/* While the assistant works: a soft veil of the page's ground over the body - what is showing stays visible, a little blurred - and a
   small card at its centre with the answering dots and the progress line. It fades in at the theme's Motion setting. */
.biztech-artifact-working[b-o2jjww7ppv] {
    position: absolute;
    inset: 0;
    z-index: var(--biztech-layer-sticky);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: color-mix(in srgb, var(--biztech-palette-background) 72%, transparent);
    backdrop-filter: blur(2px);
    animation: biztech-appear var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-artifact-working-card[b-o2jjww7ppv] {
    display: flex;
    align-items: center;
    gap: 12px;
    max-inline-size: 100%;
    padding: 12px 20px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-artifact-working-words[b-o2jjww7ppv] {
    min-inline-size: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The assistant's answering dots (AdminAnswerView's), in the primary colour: opacity only, a period of ten motion steps, each dot two
   steps behind the one before. An indicator with its own rhythm, so it loops. */
.biztech-artifact-dots[b-o2jjww7ppv] {
    display: inline-flex;
    flex: none;
    gap: 4px;
}

.biztech-artifact-dots span[b-o2jjww7ppv] {
    inline-size: 8px;
    block-size: 8px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    animation: biztech-artifact-pulse-b-o2jjww7ppv calc(var(--biztech-motion-duration, 120ms) * 10) ease-in-out infinite;
}

.biztech-artifact-dots span:nth-child(2)[b-o2jjww7ppv] {
    animation-delay: calc(var(--biztech-motion-duration, 120ms) * 2);
}

.biztech-artifact-dots span:nth-child(3)[b-o2jjww7ppv] {
    animation-delay: calc(var(--biztech-motion-duration, 120ms) * 4);
}

@keyframes biztech-artifact-pulse-b-o2jjww7ppv {
    0%,
    100% {
        opacity: 0.3;
    }

    50% {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-artifact-working[b-o2jjww7ppv],
    .biztech-artifact-dots span[b-o2jjww7ppv] {
        animation: none;
    }
}

.biztech-artifact-body[b-o2jjww7ppv] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 16px;
    min-block-size: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    /* The theme's miniatures are scaled to this body's width: a scrollbar coming and going with their height would change the
       width that sets it, and they would shake (Themes.razor.css says how). The gutter is kept, so the width does not move. */
    scrollbar-gutter: stable;
    padding: 20px;
    background: var(--biztech-palette-background);
}

.biztech-artifact-note[b-o2jjww7ppv] {
    margin-block: 0;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The Changes tab: the card's own sections, on a card of the pane's. The card's paper draws its edge; the tab is its ground. */
.biztech-artifact-card[b-o2jjww7ppv] {
    min-inline-size: 0;
}

.biztech-artifact-card[b-o2jjww7ppv]  .biztech-paper {
    padding: 20px;
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* The JSON tab: Copy at the far end, the text under it, monospaced and scrolling sideways rather than wrapping its structure. */
.biztech-artifact-json[b-o2jjww7ppv] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-artifact-copy[b-o2jjww7ppv] {
    display: flex;
    justify-content: flex-end;
}

.biztech-artifact-copy[b-o2jjww7ppv]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

.biztech-artifact-json-text[b-o2jjww7ppv] {
    margin-block: 0;
    padding: 16px;
    overflow: auto;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-body2-line-height);
    white-space: pre;
}

/* The card's buttons along the foot, with the apply last - the card's own row, without the card's frame. Its ground is the body's,
   opaque, and no rule: on the surface colour under a rule the foot read as a separate strip under the preview. The body scrolls above
   it, never behind. */
.biztech-artifact-foot[b-o2jjww7ppv] {
    flex: none;
    padding: 12px 20px;
    background: var(--biztech-palette-background);
}

/* 🔴 THE CARD'S FRAME IS DROPPED HERE, ALL OF IT. The buttons are the card's, drawn by the card inside its UiPaper; in the foot that frame
   read as a second card under the pane - its edge, corners, ground and the theme's card depth. The foot is the frame. The depth goes the
   way app.css takes it off a nested panel: the custom property, never a literal shadow (ADR 0026 D-E). */
.biztech-artifact-foot[b-o2jjww7ppv]  .biztech-paper {
    --biztech-shadow-card: none;
    padding-block: 0;
    padding-inline: 0;
    border-color: transparent;
    border-radius: 0;
    background: transparent;
    box-shadow: var(--biztech-shadow-card);
}

.biztech-artifact-foot[b-o2jjww7ppv]  .biztech-assistant-card-actions {
    justify-content: flex-end;
    padding-block-start: 0;
    border-block-start: none;
}

.biztech-artifact-foot[b-o2jjww7ppv]  .biztech-assistant-card-actions .biztech-button {
    border-radius: var(--biztech-radius-pill);
}
/* /Components/Assistant/AdminProposalPreview.razor.rz.scp.css */
/* W22-08 · a proposal's preview in the admin assistant page's preview pane. Its parts are spaced by the column's gap (I18); it fills the
   pane's height, so a portal's frame can take what is left of it. */
.biztech-proposal-preview[b-bl8xlkqxzv] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    block-size: 100%;
    min-inline-size: 0;
}

/* The portal's stage: the rest of the pane's height, framed. The frame lies in it absolutely, so its height is always the stage's.
   No minimum height: one of 32rem was taller than the pane on a laptop, so the pane scrolled as well as the portal inside it - two
   scrollbars side by side. The portal scrolls; the pane does not. */
.biztech-proposal-preview-stage[b-bl8xlkqxzv] {
    position: relative;
    flex: 1 1 auto;
    min-block-size: 0;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

/* The portal, in its own shell at the pane's width; it scrolls inside itself. */
.biztech-proposal-preview-frame[b-bl8xlkqxzv] {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    display: block;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: 100%;
    border: none;
}

/* As on a desktop screen: drawn at 1280px (AdminProposalPreview's DesktopWidth) and scaled to the stage by biztech-fit.js, which sets
   data-fit once it is live; a failed import leaves the pane's width (R9.11). zoom scales the width given in pixels; the height is a
   share of the stage and is not scaled, so the frame still fills it, and the page inside sees a desktop's window. */
.biztech-proposal-preview-stage[data-desktop] .biztech-proposal-preview-frame[data-fit][b-bl8xlkqxzv] {
    --biztech-fit-zoom: 1;
    inline-size: 1280px;
    zoom: var(--biztech-fit-zoom);
}

/* The form on a card of its own, as a participant meets it. */
.biztech-proposal-preview-form[b-bl8xlkqxzv] {
    padding: 20px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    min-inline-size: 0;
}

/* A variant's form under its name (I18): the heading and the form are spaced by the container's gap. */
.biztech-proposal-preview-form--variant[b-bl8xlkqxzv] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The theme page's miniature heads itself "Preview"; here the pane's tab already says so. */
.biztech-proposal-preview-theme[b-bl8xlkqxzv]  .biztech-theme-canvas-head {
    display: none;
}

.biztech-proposal-preview-note[b-bl8xlkqxzv] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Assistant/AdminProseView.razor.rz.scp.css */
/* W22-05 · finding 1 · an admin reply's paragraphs and lists. The caller's column spaces them (I18); a paragraph keeps its line breaks.
   Moved here from AdminAnswerView.razor.css when the audit page began drawing replies too: a scoped sheet reaches only the component
   that writes the markup (I19). */

.biztech-assistant-paragraph[b-f0t6e04lny] {
    white-space: pre-wrap;
}

.biztech-assistant-list[b-f0t6e04lny] {
    margin: 0;
    padding-inline-start: 1.25rem;
}

/* The table's scroll region (W28-13 · D16): a reply's column breaks long words anywhere, and cells inherit it. A table scrolls
   instead of breaking a word mid-way. */
.biztech-assistant-table-region[b-f0t6e04lny] {
    overflow-wrap: normal;
}
/* /Components/Assistant/AdminReadinessFactView.razor.rz.scp.css */
/* W31-09 · D13 · the readiness checklist in its card: a caption, then one line per fact with its mark, its state in words, what was
   found and the screen where it is changed. Spacing belongs to the container (I18). */
.biztech-readiness[b-nyl5y1pidw] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-readiness-head[b-nyl5y1pidw] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px 8px;
}

.biztech-readiness-heading[b-nyl5y1pidw],
.biztech-readiness-tally[b-nyl5y1pidw],
.biztech-readiness-screen[b-nyl5y1pidw] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-readiness-heading[b-nyl5y1pidw] {
    font-weight: var(--biztech-font-button-weight);
}

.biztech-readiness-list[b-nyl5y1pidw] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-readiness-item[b-nyl5y1pidw] {
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

.biztech-readiness-body[b-nyl5y1pidw] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

.biztech-readiness-state[b-nyl5y1pidw] {
    font-weight: var(--biztech-font-button-weight);
}

.biztech-readiness-mark[b-nyl5y1pidw] {
    display: inline-flex;
    flex: none;
}

.biztech-readiness-ready[b-nyl5y1pidw] {
    color: var(--biztech-palette-success);
}

.biztech-readiness-not-ready[b-nyl5y1pidw] {
    color: var(--biztech-palette-error);
}

.biztech-readiness-check[b-nyl5y1pidw] {
    color: var(--biztech-palette-warning);
}
/* /Components/Assistant/AdminTemplateGallery.razor.rz.scp.css */
/* W28-12 · the template gallery in the Setup assistant page's pane. W19-14 · the pane's shape, as a proposal's artifact: a head under a
   rule, then a body on the page's ground that scrolls (the pane clips), holding the lead and the cards. */
.biztech-template-gallery[b-qbmxbisps8] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-block-size: 0;
    min-inline-size: 0;
}

.biztech-template-gallery-head[b-qbmxbisps8] {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 12px 12px 20px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-template-gallery-body[b-qbmxbisps8] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 16px;
    min-block-size: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    padding: 20px;
    background: var(--biztech-palette-background);
}

.biztech-template-gallery-list[b-qbmxbisps8] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A card as the new conversation's template cards are drawn: the tables' edge at twice the radius, on the surface, firmed on hover. */
.biztech-template-gallery-item[b-qbmxbisps8] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-template-gallery-item:hover[b-qbmxbisps8] {
    border-color: var(--biztech-palette-outline);
}

.biztech-template-gallery-title[b-qbmxbisps8] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
}

/* Whose it is - built in or the tenant's own - as a quiet caption beside the title. */
.biztech-template-gallery-kind[b-qbmxbisps8] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The parts it sets up, one line, cut with an ellipsis. */
.biztech-template-gallery-steps[b-qbmxbisps8] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-template-gallery-start[b-qbmxbisps8] {
    display: flex;
    justify-content: flex-end;
    padding-block-start: 8px;
}

.biztech-template-gallery-start[b-qbmxbisps8]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

@media (prefers-reduced-motion: reduce) {
    .biztech-template-gallery-item[b-qbmxbisps8] {
        transition: none;
    }
}
/* /Components/Assistant/AssistantAnswerView.razor.rz.scp.css */
/* W18-03. One question and its answer. */
.biztech-assistant-exchange[b-zz18eyx5dn] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-05 · the asker's question: a bubble at the end of the row in the band's colours - the panel header's pair, so
   the asker's words and the title band are one voice - with the corner nearest the asker squared off. */
.biztech-assistant-question[b-zz18eyx5dn] {
    align-self: flex-end;
    max-inline-size: 85%;
    padding: 8px 12px;
    background: light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container));
    color: light-dark(var(--biztech-palette-on-primary), var(--biztech-palette-on-primary-container));
    border-radius: calc(var(--biztech-radius-default) * 2);
    border-end-end-radius: calc(var(--biztech-radius-default) / 2);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

/* W19-05 · the reply: the assistant's mark in a 28px column, and everything about the answer beside it. */
.biztech-assistant-reply[b-zz18eyx5dn] {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr);
    align-items: start;
    gap: 12px;
}

.biztech-assistant-reply-mark[b-zz18eyx5dn],
.biztech-assistant-reply-avatar[b-zz18eyx5dn] {
    inline-size: 28px;
    block-size: 28px;
    border-radius: var(--biztech-radius-pill);
}

.biztech-assistant-reply-mark[b-zz18eyx5dn] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-assistant-reply-mark[b-zz18eyx5dn]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
    font-size: 16px;
}

.biztech-assistant-reply-avatar[b-zz18eyx5dn] {
    object-fit: cover;
}

.biztech-assistant-reply-body[b-zz18eyx5dn] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding-block-start: 4px;
}

.biztech-assistant-answer[b-zz18eyx5dn] {
    font-size: var(--biztech-font-body2-size);
    line-height: 1.6;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* W19-05 · the typing indicator: three dots pulsing in turn beside the sentence. Opacity only (R6.7); its period is
   the motion token's, ten times over, so a tenant who turns motion off stops it with everything else, and reduced
   motion stops it outright (R6.8). */
.biztech-assistant-working[b-zz18eyx5dn] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.biztech-assistant-typing[b-zz18eyx5dn] {
    display: inline-flex;
    gap: 4px;
}

.biztech-assistant-typing span[b-zz18eyx5dn] {
    inline-size: 8px;
    block-size: 8px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    animation: biztech-assistant-typing-b-zz18eyx5dn calc(var(--biztech-motion-duration, 120ms) * 10) ease-in-out infinite;
}

.biztech-assistant-typing span:nth-child(2)[b-zz18eyx5dn] {
    animation-delay: calc(var(--biztech-motion-duration, 120ms) * 2);
}

.biztech-assistant-typing span:nth-child(3)[b-zz18eyx5dn] {
    animation-delay: calc(var(--biztech-motion-duration, 120ms) * 4);
}

@keyframes biztech-assistant-typing-b-zz18eyx5dn {
    0%,
    80%,
    100% {
        opacity: 0.25;
    }

    40% {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-assistant-typing span[b-zz18eyx5dn] {
        animation: none;
        opacity: 0.6;
    }
}

.biztech-assistant-working[b-zz18eyx5dn],
.biztech-assistant-unsourced[b-zz18eyx5dn] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The cited sources: a heading and one card per document, always open. Each card is the number its chips in the
   answer carry, the title (and the quoted passage, when there is one), and Open. */
.biztech-assistant-sources[b-zz18eyx5dn] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-assistant-sources-heading[b-zz18eyx5dn] {
    font-size: var(--biztech-font-overline-size, var(--biztech-font-caption-size));
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-source-list[b-zz18eyx5dn] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-assistant-source[b-zz18eyx5dn] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    background: var(--biztech-palette-background);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 1.5);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

/* The chip's number, filled, so a reader matches the card to the mark in the answer. */
.biztech-assistant-source-number[b-zz18eyx5dn] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 24px;
    block-size: 24px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
}

.biztech-assistant-source-body[b-zz18eyx5dn] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-inline-size: 0;
}

.biztech-assistant-source-title[b-zz18eyx5dn] {
    font-weight: var(--biztech-font-subtitle2-weight);
    overflow-wrap: anywhere;
}

.biztech-assistant-source-quote[b-zz18eyx5dn] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
}

/* Open: a filled button in the primary role, drawn on the link itself so the new-tab rule above still applies. */
.biztech-assistant-source-open[b-zz18eyx5dn] {
    display: inline-flex;
    flex: none;
    align-items: center;
    padding: 4px 12px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    font-weight: var(--biztech-font-button-weight);
    text-decoration: none;
}

/* No underline in any state - it is a button to the eye. Hover is UiButton's filled hover: the ink mixed into the fill. */
.biztech-assistant-source-open[b-zz18eyx5dn],
.biztech-assistant-source-open:hover[b-zz18eyx5dn],
.biztech-assistant-source-open:visited[b-zz18eyx5dn] {
    color: var(--biztech-palette-on-primary);
    text-decoration: none;
}

.biztech-assistant-source-open:hover[b-zz18eyx5dn] {
    background: color-mix(in srgb, currentcolor 12%, var(--biztech-palette-primary));
}

/* W19-05 · one row of glyphs under the answer, in the secondary ink so they do not compete with it. */
.biztech-assistant-actions[b-zz18eyx5dn] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-actions[b-zz18eyx5dn]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

/* W19-06 · the rating's two glyphs join this row rather than standing as a block of their own, so the row reads rate - rate -
   copy - ask again, and the optional reason drops to a full line under all four (AssistantFeedback.razor.css gives it order: 1).
   display: contents takes only the group's BOX away: its role="group" and its name stay on the element, which Chromium,
   WebKit and Gecko all now expose for display: contents. */
.biztech-assistant-actions[b-zz18eyx5dn]  .biztech-assistant-feedback {
    display: contents;
}

/* W18-06 · D26. The tenant's disclaimer, under every completed answer - supporting text, never the answer. */
.biztech-assistant-disclaimer[b-zz18eyx5dn] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* W18-08. The label under a curated answer. */
.biztech-assistant-answer-kind[b-zz18eyx5dn] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    font-weight: var(--biztech-font-caption-weight);
    color: var(--biztech-palette-primary);
}
/* /Components/Assistant/AssistantCitationChip.razor.rz.scp.css */
/* W18-03. A numbered citation after the segment it supports. Its focus ring is app.css's one ring. */
.biztech-assistant-citation[b-z8myydjfye] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 1.5em;
    margin-inline-start: 4px;
    padding: 0 4px;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-pill);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-primary);
    text-decoration: none;
    vertical-align: baseline;
}

.biztech-assistant-citation-unlinked[b-z8myydjfye] {
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Assistant/AssistantConversationList.razor.rz.scp.css */
/* W18-06. The asker's earlier conversations: a title that resumes, and a delete control beside it. The empty and
   still-loading lines share one quiet style - the history list has no class of its own for "working". */
.biztech-assistant-history[b-nmo0h400z8] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-assistant-history-heading[b-nmo0h400z8] {
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

.biztech-assistant-history-empty[b-nmo0h400z8] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-history-list[b-nmo0h400z8] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.biztech-assistant-history-item[b-nmo0h400z8] {
    display: grid;
    /* minmax(0, 1fr), not 1fr: a grid track's minimum is its content's, so a long title widened the row past the
       panel and the whole body scrolled sideways (the browser walk). */
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
    padding: 4px 4px 4px 8px;
    border-radius: calc(var(--biztech-radius-default) * 1.5);
    color: var(--biztech-palette-text-secondary);
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* W19-05 · a row lights on hover, as a list item in a menu does, rather than each being ruled off. */
.biztech-assistant-history-item:hover[b-nmo0h400z8] {
    background: var(--biztech-palette-background);
}

/* The title wraps rather than overflowing: UiButton's root is the seam's own element, so ::deep says out loud that
   the rule reaches into it (I19). Left-aligned, since a wrapped title reads as a line of text, not a centred label. */
.biztech-assistant-history-item[b-nmo0h400z8]  .biztech-button {
    max-inline-size: 100%;
    /* app.css gives every panel button a definite block-size (W18-03, so Ask matches its field), which kept a
       wrapped title at one line's height and spilled it over the next row - the walk measured it. The floor stays;
       the height follows the lines. */
    block-size: auto;
    justify-content: flex-start;
    white-space: normal;
    text-align: start;
    overflow-wrap: anywhere;
    font-weight: var(--biztech-font-body2-weight);
}
/* /Components/Assistant/AssistantFactCard.razor.rz.scp.css */
/* W22-02 · §2 · TD30. A fact card: the same bordered UiPaper as the proposal card, holding whatever a family's view draws.

   Its rules are the ones it writes into its own markup - the stack that gaps what the view draws, and the sentence it falls back to.
   The view is a child component and is styled by its own sheet (I19). */

.biztech-assistant-card-stack[b-15v4rbf489] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-assistant-card-note[b-15v4rbf489] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* W19-19 · the frame: the template cards' edge and corners, so a card in the chat reads as one of them. ::deep: UiPaper renders it. */
.biztech-assistant-fact-frame[b-15v4rbf489]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Assistant/AssistantFeedback.razor.rz.scp.css */
/* W18-06 · D15. Two toggles on one row; the reason and its Send wrap below when asked for. */
.biztech-assistant-feedback[b-h9u0x6aqpi] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
}

/* W19-06 · the pressed rating: a round disc in the primary container rather than an outlined square - every other glyph in the
   panel is round. The pressed control keeps UiIconButton's outlined and primary classes, so it still differs from the other in
   shape and fill as well as ink, which is what the W18-06 walk found missing; this sheet only draws those classes round. */
.biztech-assistant-feedback[b-h9u0x6aqpi]  .biztech-icon-button-outlined {
    border-color: transparent;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* W19-06 · the reason: the panel's composer in small - a pill with the send glyph inside its end, on a line of its own under the
   row of glyphs (order: 1, so the copy and ask-again glyphs stay on the row above it). */
.biztech-assistant-feedback-reason[b-h9u0x6aqpi] {
    position: relative;
    display: grid;
    align-items: center;
    flex: 1 1 100%;
    order: 1;
}

.biztech-assistant-feedback-reason[b-h9u0x6aqpi]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-assistant-feedback-reason[b-h9u0x6aqpi]  .biztech-input {
    block-size: 40px;
    padding-inline: 16px 44px;
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-background);
}

.biztech-assistant-feedback-send[b-h9u0x6aqpi] {
    position: absolute;
    inset-inline-end: 4px;
    display: flex;
    color: var(--biztech-palette-primary);
}
/* /Components/Assistant/AssistantLauncher.razor.rz.scp.css */
/* W18-03 · D22. The floating launcher: a 56px round button in the lower corner, over the page.

   🔴 FIXED, AND IT PUSHES NOTHING ASIDE. The panel opens above it (AssistantPanel.razor.css keeps its
   bottom edge 88px up: this button's 56px plus 16px either side), so the button stays reachable while the
   panel is open. The shadow is D-E's floating-affordance licence, the board scroll button's relationship
   to content.

   🔴 THE AFFORDANCE LAYER, AND TREE ORDER DOES THE REST. At `sticky` the board's scroll buttons (at
   `affordance`) painted over the open panel's edge - seen in Chrome on /board. At the same layer the
   layout's dock, which comes after <main>, paints over them; and it stays under the overlay drawer's
   scrim below sm and under every dialog. */
.biztech-assistant-launcher[b-99th2wc2up] {
    position: fixed;
    z-index: var(--biztech-layer-affordance);
    inset-inline-end: 16px;
    inset-block-end: 16px;
    display: flex;
}

.biztech-assistant-launcher[b-99th2wc2up]  .biztech-icon-button {
    inline-size: 56px;
    block-size: 56px;
    padding: 16px;
    border-color: var(--biztech-palette-primary);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    box-shadow: var(--biztech-shadow-raised);
    transition:
        background-color var(--biztech-motion-duration, 120ms) ease-in-out,
        transform var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-assistant-launcher[b-99th2wc2up]  .biztech-icon-button:hover:not(:disabled) {
    background: color-mix(in srgb, var(--biztech-palette-primary) 88%, var(--biztech-palette-on-primary));
    transform: scale(1.06);
}

/* W19-05 · the glyph is 24px in a 56px disc; the seam's medium is drawn for a 40px one. */
.biztech-assistant-launcher[b-99th2wc2up]  .biztech-icon {
    inline-size: 24px;
    block-size: 24px;
    font-size: 24px;
}

@media (prefers-reduced-motion: reduce) {
    .biztech-assistant-launcher[b-99th2wc2up]  .biztech-icon-button:hover:not(:disabled) {
        transform: none;
    }
}
/* /Components/Assistant/AssistantPanel.razor.rz.scp.css */
/* W18-03 · D22. The panel's geometry, which it owns - a floating window over the page.

   🔴 FIXED, AND OVER THE PAGE RATHER THAN BESIDE IT. It opens above the floating launcher
   (AssistantLauncher.razor.css) and pushes nothing aside: neither layout makes room for it, so opening it
   moves nothing on the page. Its bottom edge is 88px up - the launcher's 56px plus 16px either side - so
   the launcher stays in reach to close it, and its height stops short of the top (the app bar's 64px plus
   the same gaps), so neither layout's header - and neither account menu - is ever under it. The shadow is
   D-E's licence for something that floats over content without pushing it aside.

   🔴 NON-MODAL: no scrim, no focus trap. The page around it stays operable.

   At `affordance`, the launcher's layer and for its reason (AssistantLauncher.razor.css): over the board's
   scroll buttons by tree order, under the overlay drawer's scrim and every dialog.

   At every width one card, 26rem wide or the viewport less a 16px gutter each side if that is narrower -
   so at 375px it is 343px wide and the page to either side of it is not claimed.

   🔴 W19-05 · A FIXED HEIGHT, NOT A CEILING. The panel grew with its content, so it opened as a short box and
   jumped taller with every answer, and the composer moved with it. It is 42rem tall or the room there is, and
   the body is what fills it - the header and the composer never move. The panel's own padding went to its three
   bands, so the header's band and the composer's rule run edge to edge.

   🔴 W19-05 · W19-04's LANGUAGE, NOT A NEW ONE. The portal pass drew its title band on the primary colour with a
   dot pattern, took corners twice the theme's radius for its cards, tinted squares for its glyphs and round
   buttons for "go". The panel is the same product's floating surface and takes the same vocabulary: every colour,
   radius, shadow and duration is a --biztech-* variable, so a tenant's palette, radius and motion reach it. */
.biztech-assistant[b-b2110bc1wf] {
    position: fixed;
    z-index: var(--biztech-layer-affordance);
    inset-inline-end: 16px;
    inset-block-end: 88px;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    inline-size: min(26rem, calc(100vw - 32px));
    block-size: min(42rem, calc(100dvh - 168px));
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    box-shadow: var(--biztech-shadow-raised);
    overflow: hidden;
    transform-origin: bottom right;
    animation: biztech-assistant-open-b-b2110bc1wf var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* W19-05 · D-F's budget: opacity and transform, the token's duration, and nothing that lays out. It rises out of
   the launcher, so the panel reads as the launcher's own. */
@keyframes biztech-assistant-open-b-b2110bc1wf {
    from {
        opacity: 0;
        transform: translateY(8px) scale(0.98);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* R6.8. */
@media (prefers-reduced-motion: reduce) {
    .biztech-assistant[b-b2110bc1wf] {
        animation-duration: 0s;
    }
}

/* 🔴 W22-07 · Part G · AND ITS TOP STOPS SHORT OF THE PAGE HEADER'S ACTIONS TOO, ABOVE THE PHONE.
   The 2026-10-05 walk found /themes' Save under the open panel at desktop width. The panel's height
   cleared the app bar alone (168px = the launcher's 88px, the app bar's 64px and a 16px gap), and below
   about 840px of viewport that put its top 16px below the app bar - across the band where PageHeader
   draws a page's actions, at the inline end, which is exactly where the panel floats.

   So above sm its height is capped by what is left under the header band as well: the launcher's 88px
   at the bottom, then the app bar READ FROM ITS TOKEN (a tenant's theme sets layout.appbarHeight, and
   MainLayout's first row is that token), then 88px for the band - the container's 16px top padding, a
   56px title row (an h5 title and one line of subtitle, the actions centred on it) and the same 16px
   gap. A cap and not a new height, so the panel is never taller than W19-05's fixed one, its bottom
   edge and its launcher are where they were, and it still pushes nothing aside.

   🔴 THE PLAN'S OPEN QUESTION, ANSWERED BY ITS FALLBACK. It proposed a new :root token,
   --biztech-page-header-clearance; tokens are emitted from the Theming project, which is outside this
   card's declared projects, so this is the existing app-bar token plus a scoped calc. The browser fact
   AssistantPanelBrowserTests.The_open_panel_never_covers_the_theme_editors_save is what measures it,
   hit-tested at 1280 and 1440 wide. At 599.98px and below the panel is the phone's card and unchanged. */
@media (min-width: 600px) {
    .biztech-assistant[b-b2110bc1wf] {
        max-block-size: calc(100dvh - var(--biztech-content-block-start, 0px) - 88px - 88px);
    }
}

/* W19-05 · the title band: W19-04's portal hero in miniature. The primary colour with its own ink in light mode; in
   dark mode the primary is a light blue and a light band was the brightest thing on the screen, so the band takes the
   primary container there. light-dark() follows the color-scheme UiThemeTokens declares on the root (R7.8), never the
   OS (I16). The icon buttons inherit the band's ink (UiColor.Inherit), and their hover mixes from currentcolor.
   No dot pattern: the portal band's reads as noise at this size. */
.biztech-assistant-header[b-b2110bc1wf] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 12px 16px 16px;
    color: light-dark(var(--biztech-palette-on-primary), var(--biztech-palette-on-primary-container));
    background: light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container));
}

/* The name and the line under it take the row's slack, so the mark sits before them and the controls after. */
.biztech-assistant-titles[b-b2110bc1wf] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-assistant-heading[b-b2110bc1wf] {
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: 600;
    line-height: var(--biztech-font-subtitle1-line-height);
    letter-spacing: -0.01em;
}

/* W22-02 · TD28. The Help | Admin switch, on a row of its own UNDER the header - the header is already full at phone width
   (avatar, heading, new, history, close), so a switch inside it would wrap or push a control off the 303px body. The segmented
   track is the global .biztech-segmented (app.css, I19: shared by components a scoped rule cannot reach), so this row only keeps
   it at its own width instead of stretching it.

   W19-05: the panel has no gap of its own now - its padding went to its bands - so this row is a band too, with its own inset
   and the subtle rule the other bands carry.

   🔴 NO COLOUR, NOW OR LATER (ADR 0026 D-A). Admin mode is told apart by words, never by a tint of this row or the panel. */
.biztech-assistant-mode[b-b2110bc1wf] {
    display: flex;
    justify-content: flex-start;
    padding: 8px 16px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

/* A step back toward the band, as the portal hero's lead paragraph is. */
.biztech-assistant-subtitle[b-b2110bc1wf] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: color-mix(in srgb, currentcolor 80%, transparent);
}

/* The assistant's mark when the tenant uploaded no avatar - on the band, a disc of the band's own ink at low strength. */
.biztech-assistant-mark[b-b2110bc1wf] {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, currentcolor 16%, transparent);
}

.biztech-assistant-avatar[b-b2110bc1wf] {
    flex: 0 0 auto;
    inline-size: 40px;
    block-size: 40px;
    /* R5.5's pill token, the one declared radius a circle may use. A ring in the band's ink keeps a photo off the band. */
    border-radius: var(--biztech-radius-pill);
    box-shadow: 0 0 0 2px color-mix(in srgb, currentcolor 30%, transparent);
    object-fit: cover;
}

/* W19-05. A stop or a failure: a band under the header. Otherwise clipped - app.css's skip-link idiom, which keeps
   the region in the accessibility tree and costs no height. */
.biztech-assistant-status[b-b2110bc1wf] {
    padding: 8px 16px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
    background: var(--biztech-palette-background);
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-assistant-status[data-quiet][b-b2110bc1wf] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The one scroller in the panel. The panel is a flex column of fixed header, status and footer around this, so a
   long answer scrolls here and the composer stays in reach. The ring app.css draws 4px outside a control sits inside
   this padding, so it is never clipped (R3.10, R12.3). */
.biztech-assistant-body[b-b2110bc1wf] {
    display: flex;
    flex-direction: column;
    gap: 24px;
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    padding: 20px 16px;
}

/* W19-05 · before the first question: a tinted glyph square - the portal tile's chip, larger - the greeting as a
   heading, and the suggestions under them. */
.biztech-assistant-welcome[b-b2110bc1wf] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    padding-block-start: 12px;
    text-align: center;
}

.biztech-assistant-welcome-mark[b-b2110bc1wf] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 64px;
    block-size: 64px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-assistant-welcome-mark[b-b2110bc1wf]  .biztech-icon {
    inline-size: 32px;
    block-size: 32px;
    font-size: 32px;
}

.biztech-assistant-welcome-avatar[b-b2110bc1wf] {
    inline-size: 64px;
    block-size: 64px;
    border-radius: var(--biztech-radius-pill);
    object-fit: cover;
}

.biztech-assistant-greeting[b-b2110bc1wf] {
    max-inline-size: 30ch;
    font-size: var(--biztech-font-h6-size);
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: -0.01em;
    color: var(--biztech-palette-text-primary);
}

.biztech-assistant-notice[b-b2110bc1wf] {
    padding: 12px 16px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
    background: var(--biztech-palette-background);
    border-radius: calc(var(--biztech-radius-default) * 1.5);
}

/* W19-05. Everything about the next question, ruled off from the conversation, edge to edge. */
.biztech-assistant-footer[b-b2110bc1wf] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W18-07 · "Talk to a person", on its own row above the composer - spaced by the footer's gap - as a pill. */
.biztech-assistant-hand-off[b-b2110bc1wf] {
    display: flex;
}

.biztech-assistant-hand-off[b-b2110bc1wf]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

/* W19-05 · one rounded box, the send button inside its end. The field's own border is the box's; the button sits
   over its trailing padding, so the two read as one control. */
.biztech-assistant-composer[b-b2110bc1wf] {
    position: relative;
    display: grid;
    align-items: center;
}

/* The label is a real <label for>, clipped rather than removed - UiChatComposer's mechanism (R12.4). ::deep because
   UiTextField renders it (I19). */
.biztech-assistant-composer[b-b2110bc1wf]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-assistant-composer[b-b2110bc1wf]  .biztech-input {
    block-size: 48px;
    padding-inline: 20px 52px;
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-background);
}

.biztech-assistant-send[b-b2110bc1wf] {
    position: absolute;
    inset-inline-end: 4px;
    display: flex;
}

/* Filled while there is something to send - the launcher's own pair, Primary over OnPrimary, and round - and a
   bare disabled glyph when there is not, so a pointer is not invited to press it. */
.biztech-assistant-send[b-b2110bc1wf]  .biztech-icon-button:not(:disabled) {
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
}

.biztech-assistant-send[b-b2110bc1wf]  .biztech-icon-button:hover:not(:disabled) {
    background: color-mix(in srgb, var(--biztech-palette-primary) 88%, var(--biztech-palette-on-primary));
}

/* W18-08 · D4. "Did you mean …?" and its one offer, spaced by the row's own gap (I18). */
.biztech-assistant-did-you-mean[b-b2110bc1wf] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-assistant-did-you-mean-label[b-b2110bc1wf] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-did-you-mean-mark[b-b2110bc1wf] {
    font-weight: var(--biztech-font-caption-weight);
    color: var(--biztech-palette-primary);
}

/* W22-02 · W19-06. Admin mode's empty state, drawn as the help mode's welcome is: the mark and the lead centred, then each
   family the person may use as a card - a tinted glyph, its name in the page's ink and what it does in the secondary one -
   then the closing line. The list is gapped by its container (I18). */
.biztech-assistant-empty[b-b2110bc1wf] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-empty-intro[b-b2110bc1wf] {
    max-inline-size: 32ch;
    font-size: var(--biztech-font-body1-size);
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: -0.01em;
    color: var(--biztech-palette-text-primary);
}

.biztech-assistant-empty-list[b-b2110bc1wf] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-assistant-family[b-b2110bc1wf] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-assistant-family-mark[b-b2110bc1wf] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* The card's words take the column's slack and wrap there: the Explain card quotes four questions in one sentence. */
.biztech-assistant-family-text[b-b2110bc1wf] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* The sentence's name is its title: on a line of its own, in the page's ink, its colon kept in the text for the sentence's sake
   and out of sight here. */
.biztech-assistant-family-title[b-b2110bc1wf] {
    display: block;
    font-weight: 600;
    color: var(--biztech-palette-text-primary);
}

/* The description is the second half of the family's sentence, so it starts in lower case; under its title it reads as its own
   line, so its first letter is raised here - the words themselves, and the sentence a screen reader hears, are unchanged. */
.biztech-assistant-family-body[b-b2110bc1wf] {
    display: block;
}

.biztech-assistant-family-body[b-b2110bc1wf]::first-letter {
    text-transform: uppercase;
}

.biztech-assistant-family-colon[b-b2110bc1wf] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-assistant-empty-closing[b-b2110bc1wf] {
    text-align: center;
}

/* The offer wraps like a suggestion does, for the same reason (AssistantSuggestionList.razor.css, I19). */
.biztech-assistant-did-you-mean[b-b2110bc1wf]  .biztech-button {
    max-inline-size: 100%;
    block-size: auto;
    white-space: normal;
    text-align: start;
    overflow-wrap: anywhere;
}

/* W24-01. The way to the docs before the first question: one quiet line, the panel's secondary ink, a link in the
   primary. */
.biztech-assistant-docs[b-b2110bc1wf] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-assistant-docs a[b-b2110bc1wf] {
    color: var(--biztech-palette-primary);
}
/* /Components/Assistant/AssistantProposalCard.razor.rz.scp.css */
/* W22-02 · §2 · TD30. A proposal from the admin assistant, as a card inside the panel's body.

   🔴 WORDS, NOT COLOUR (ADR 0026 D-A). Nothing here tints a card as "admin": it is a bordered UiPaper like any other, the change
   kinds are chips that SAY Added, Changed or Removed (R12.7: colour is never the only cue), and the only hue on the card is the
   Warning chip beside a risk, which carries its own word.

   🔴 SPACING IS THE CONTAINER'S (I18). The stack gaps its sections, each section gaps its own heading and list, each list gaps its
   items, and the JSON body pads itself from its summary. A <ul> and a <pre> zero the user agent's block margin (a declared exception
   in UtilitySpecificityTests); no child carries a margin of its own, so the gaps cannot add up the way a gap plus a margin per child does.

   🔴 I19 - EVERY RULE NAMES A CLASS THIS COMPONENT'S OWN MARKUP WRITES. UiPaper, UiChip, UiAlert and UiButton are children; none
   of them is styled from here. The disclosure's <summary> is this component's own element, which is why it can be drawn as the
   small outlined button its row-mates are. */

.biztech-assistant-card-stack[b-tvls401frp] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* W22-08 · the head: the kind's glyph in a tinted square, the name, and the kind in words at the far end. */
.biztech-assistant-card-head[b-tvls401frp] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

.biztech-assistant-card-mark[b-tvls401frp] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-assistant-card-title[b-tvls401frp] {
    flex: 1 1 8rem;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

.biztech-assistant-card-summary[b-tvls401frp] {
    margin-block: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
    overflow-wrap: anywhere;
}

/* W22-08 · each section ruled off from the one before by a hairline, so a long card reads as parts; the heading a quiet label over
   its list. */
.biztech-assistant-card-section[b-tvls401frp] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W22-08 · a section's heading with an action at its far end - the change list's Preview. */
.biztech-assistant-card-section-head[b-tvls401frp] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-assistant-card-section-head[b-tvls401frp]  .biztech-button {
    border-radius: var(--biztech-radius-pill);
}

.biztech-assistant-card-section[b-tvls401frp]  h4 {
    color: var(--biztech-palette-text-secondary);
}

/* The checks as one line: a glyph and its words, tinted for the role it reports (ADR 0026 D-H: a status is a tonal fill from an existing
   role). The words say it too (R12.7). A refusal's problems wrap under the line. */
.biztech-assistant-card-section[data-card-checks][b-tvls401frp] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: 8px;
}

.biztech-assistant-card-section[data-card-checks] > .biztech-assistant-card-list[b-tvls401frp] {
    grid-column: 1 / -1;
}

.biztech-assistant-card-check[b-tvls401frp] {
    display: inline-flex;
}

.biztech-assistant-card-section[data-card-checks="passed"] .biztech-assistant-card-check[b-tvls401frp],
.biztech-assistant-card-section[data-card-checks="passed"][b-tvls401frp]  h4 {
    color: var(--biztech-palette-success);
}

.biztech-assistant-card-section[data-card-checks="refused"] .biztech-assistant-card-check[b-tvls401frp],
.biztech-assistant-card-section[data-card-checks="refused"][b-tvls401frp]  h4 {
    color: var(--biztech-palette-error);
}

.biztech-assistant-card-list[b-tvls401frp] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-assistant-card-item[b-tvls401frp] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

/* W22-08 · a change's kind as a small tonal pill in its role's container - Added the success role, Removed the error role, Changed the
   primary's - so a long list can be scanned by kind. The chip's word says it too (R12.7). ::deep: UiChip renders it (I19). */
.biztech-assistant-card-item[b-tvls401frp]  .biztech-chip {
    flex: none;
    min-inline-size: 72px;
    justify-content: center;
    border-color: transparent;
    border-radius: var(--biztech-radius-pill);
    font-size: var(--biztech-font-caption-size);
}

.biztech-assistant-card-item[data-change="added"][b-tvls401frp]  .biztech-chip {
    background: var(--biztech-palette-success-container);
    color: var(--biztech-palette-on-success-container);
}

.biztech-assistant-card-item[data-change="removed"][b-tvls401frp]  .biztech-chip {
    background: var(--biztech-palette-error-container);
    color: var(--biztech-palette-on-error-container);
}

.biztech-assistant-card-item[data-change="changed"][b-tvls401frp]  .biztech-chip {
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* A sentence beside its chip wraps under it rather than running off the panel's 303px body. */
.biztech-assistant-card-text[b-tvls401frp] {
    flex: 1 1 8rem;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* W22-06 · D7. A theme colour's swatch, beside the change's chip and before its words, which name the hex too. The colour arrives as
   the custom property the markup sets - component-local, so not --biztech-*, which names only what the theme emitter declares
   (TokenSufficiencyTests); ComplianceFigureBar's --figure-share is the precedent. The outline keeps a white or near-surface colour
   visible against the card. */
.biztech-proposal-swatch[b-tvls401frp] {
    flex: none;
    align-self: center;
    inline-size: 12px;
    block-size: 12px;
    border-radius: var(--biztech-radius-pill);
    background: var(--proposal-swatch);
    box-shadow: inset 0 0 0 1px var(--biztech-palette-outline);
}

.biztech-assistant-card-note[b-tvls401frp] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* 🔴 I18. The polite region for the two Warnings is in the document BEFORE either appears (a region that arrives with its first message
   announces nothing), and so it is a flex item of the stack that is EMPTY nearly always - and an empty flex item still takes a gap on each
   side. Out of flow while it is empty, it takes none and stays in the accessibility tree; with a warning in it, it is an ordinary item
   with its one gap on each side. Not display:none or hidden, which would recreate the arrives-with-its-message problem. */
.biztech-assistant-card-notice:empty[b-tvls401frp] {
    position: absolute;
}

/* The actions wrap, as the panel's own actions row does. */
/* W22-08 · a foot under a rule, as a form's actions are (W19). */
.biztech-assistant-card-actions[b-tvls401frp] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-assistant-card-actions:empty[b-tvls401frp] {
    display: none;
}

/* "Open as JSON": a native disclosure drawn as a small outlined button, until W22-05 gives it a page of its own. Closed it is one
   button among its row-mates; open it takes the whole row, so the text has room and the buttons after it wrap beneath. */
.biztech-assistant-card-json[open][b-tvls401frp] {
    flex: 1 1 100%;
    min-inline-size: 0;
}

.biztech-assistant-card-json-summary[b-tvls401frp] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-block-size: 32px;
    padding: 4px 12px;
    border: 1px solid currentcolor;
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-button-line-height);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    text-transform: var(--biztech-font-button-transform);
    white-space: nowrap;
    cursor: pointer;
    list-style: none;
}

.biztech-assistant-card-json-summary[b-tvls401frp]::-webkit-details-marker {
    display: none;
}

.biztech-assistant-card-json-summary:hover[b-tvls401frp] {
    background: color-mix(in srgb, currentcolor 8%, transparent);
}

/* Aria: an open disclosure reads as pressed, so it is drawn as the pressed segment is (UiButton.razor.css). */
.biztech-assistant-card-json[open] > .biztech-assistant-card-json-summary[b-tvls401frp] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
}

/* I18: the gap between the summary and the text is the BODY's - the container's - and the <pre> carries no margin of its own. A <details>
   is not reliably a flex container, so the container's own padding is the gap that holds in every browser. The body itself is a
   <div>, so it stacks the findings' list and the <pre> with a gap of its own rather than letting them touch. */
.biztech-assistant-card-json-body[b-tvls401frp] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-block-start: 8px;
}

.biztech-assistant-card-json-text[b-tvls401frp] {
    box-sizing: border-box;
    margin: 0;
    padding: 8px;
    max-block-size: 16rem;
    overflow: auto;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ── W22-08 · the chat's artifact line ──────────────────────────────────────────────────────────────────────────────────────

   One bordered row in the conversation, the whole of it one button: the kind's glyph in its tinted square, the name over a quiet line
   of its kind, version and state, and a chevron at the far end. Lit on hover, and edged in the primary colour while the pane shows it
   (aria-pressed). A replaced version is quieter, and still opens. ::deep: the button is UiButton's (I19). */
.biztech-assistant-card-line[b-tvls401frp] {
    display: flex;
    min-inline-size: 0;
}

.biztech-assistant-card-line-open[b-tvls401frp] {
    display: flex;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button,
.biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button:hover,
.biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button[aria-pressed="true"] {
    justify-content: flex-start;
    inline-size: 100%;
    min-inline-size: 0;
    block-size: auto;
    padding: 12px 12px 12px 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    text-align: start;
    white-space: normal;
    letter-spacing: normal;
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button:hover {
    border-color: var(--biztech-palette-outline);
}

.biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button[aria-pressed="true"] {
    border-color: var(--biztech-palette-primary);
}

.biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button-label {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-assistant-card-line-words[b-tvls401frp] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-inline-size: 0;
}

.biztech-assistant-card-line-title[b-tvls401frp] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    line-height: var(--biztech-font-subtitle2-line-height);
}

.biztech-assistant-card-line-meta[b-tvls401frp] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-caption-weight);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The state in its role's colour, and in words (R12.7). */
.biztech-assistant-card-line-state[data-state="passed"][b-tvls401frp],
.biztech-assistant-card-line-state[data-state="applied"][b-tvls401frp] {
    color: var(--biztech-palette-success);
}

/* The warning hue darkened toward the ink, so caption-sized text keeps its contrast on the surface. */
.biztech-assistant-card-line-state[data-state="attention"][b-tvls401frp] {
    color: color-mix(in srgb, var(--biztech-palette-warning) 60%, var(--biztech-palette-text-primary));
}

.biztech-assistant-card-line-chevron[b-tvls401frp] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
}

.biztech-assistant-card-line[data-replaced] .biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button {
    background: transparent;
    color: var(--biztech-palette-text-secondary);
}

@media (prefers-reduced-motion: reduce) {
    .biztech-assistant-card-line-open[b-tvls401frp]  .biztech-button {
        transition: none;
    }
}
/* /Components/Assistant/AssistantScopeChip.razor.rz.scp.css */
/* W18-06 · D23. What the next question is about, above the composer where it is typed. */
.biztech-assistant-scope[b-7s9y92xg9s] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-inline-start: 12px;
    background: var(--biztech-palette-background);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

.biztech-assistant-scope-label[b-7s9y92xg9s] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}
/* /Components/Assistant/AssistantSuggestionList.razor.rz.scp.css */
/* W18-03. The suggestions, or the one sentence that says why there are none. */
.biztech-assistant-suggestions[b-1p3uyt7lmd] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-assistant-suggestions-heading[b-1p3uyt7lmd] {
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-caption-weight);
    color: var(--biztech-palette-text-secondary);
}

/* W19-05 · one question per row, full width, rather than a wrap of pills of every length. */
.biztech-assistant-suggestion-list[b-1p3uyt7lmd] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

/* W19-05. With nothing to offer, the heading and its one sentence sit centred under the welcome. */
.biztech-assistant-suggestions:has(.biztech-assistant-suggestions-empty)[b-1p3uyt7lmd] {
    text-align: center;
}

.biztech-assistant-suggestions-empty[b-1p3uyt7lmd] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* W18-08 · D3. The mark on a question with a reviewed answer: words in the primary ink, never colour alone. */
.biztech-assistant-curated-mark[b-1p3uyt7lmd] {
    font-weight: var(--biztech-font-caption-weight);
    color: var(--biztech-palette-primary);
}

/* W18-08, found by its browser walk: a long question - and every question carrying the reviewed mark - overflowed the
   350px panel at nowrap and put a horizontal scrollbar under the list. It wraps instead, the conversation list's rule
   (AssistantConversationList.razor.css): ::deep because UiButton's root is the seam's own element (I19). */
/* W19-05 · each question is W19-04's portal tile in one line: the subtle edge, corners twice the theme's radius, the
   page's ink, and a round "go" button at the far end - UiButton's end icon, drawn as a disc - that fills with the
   primary colour on hover while the edge takes the primary container. */
.biztech-assistant-suggestion-list[b-1p3uyt7lmd]  .biztech-button {
    inline-size: 100%;
    max-inline-size: 100%;
    block-size: auto;
    min-block-size: 48px;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 8px 8px 16px;
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    font-weight: var(--biztech-font-body2-weight);
    white-space: normal;
    text-align: start;
    overflow-wrap: anywhere;
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-assistant-suggestion-list[b-1p3uyt7lmd]  .biztech-button .biztech-icon {
    flex: 0 0 auto;
    box-sizing: border-box;
    inline-size: 32px;
    block-size: 32px;
    padding: 8px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-background);
    color: var(--biztech-palette-text-primary);
    transition:
        background-color var(--biztech-motion-duration, 120ms) ease-in-out,
        color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-assistant-suggestion-list[b-1p3uyt7lmd]  .biztech-button:hover:not(:disabled) {
    border-color: var(--biztech-palette-primary-container);
    background: var(--biztech-palette-surface);
}

.biztech-assistant-suggestion-list[b-1p3uyt7lmd]  .biztech-button:hover:not(:disabled) .biztech-icon {
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
}
/* /Components/Assistant/AssistantTemplateEditor.razor.rz.scp.css */
/* W28-12 · the template editor. Spacing by the containers' gap, never a child's margin (I18). W19-23 · a list on the list card
   and the open template as a card of its own: its steps, or its document. */
.biztech-template-editor[b-nfkfvdt7yq] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* What the list holds, then New template at the far end (§2a C2). */
.biztech-template-editor-bar[b-nfkfvdt7yq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.biztech-template-editor-name[b-nfkfvdt7yq] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.biztech-template-editor-title[b-nfkfvdt7yq] {
    font-weight: 600;
}

.biztech-template-editor-actions[b-nfkfvdt7yq],
.biztech-template-step-chips[b-nfkfvdt7yq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-template-editor-open[b-nfkfvdt7yq] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* The template's name, and the Steps / JSON switch at the row's end. */
.biztech-template-editor-open-head[b-nfkfvdt7yq] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

/* The document stays mounted while the steps show, so a switch of view never throws away what was typed. */
.biztech-template-editor-hidden[b-nfkfvdt7yq] {
    display: none;
}

/* The steps, each a numbered row on the quiet edge - what the Assistant works through, in order. A list by role on <div>s, so
   there is no user-agent list margin to reset (UtilitySpecificityTests). */
.biztech-template-steps[b-nfkfvdt7yq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-template-step[b-nfkfvdt7yq] {
    display: flex;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* §2a C9 · the step's number in the tinted circle a glyph takes on a card. */
.biztech-template-step-number[b-nfkfvdt7yq] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 28px;
    block-size: 28px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
    font-weight: 600;
    font-size: var(--biztech-font-body2-size);
}

.biztech-template-step-body[b-nfkfvdt7yq],
.biztech-template-step-group[b-nfkfvdt7yq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.biztech-template-step-group[b-nfkfvdt7yq] {
    gap: 4px;
}

.biztech-template-step-head[b-nfkfvdt7yq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The questions, one a line in the card's body size. */
.biztech-template-step-questions[b-nfkfvdt7yq] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

/* Save in the card's foot, under a rule, so it reads apart from the template above it. */
.biztech-template-editor-save[b-nfkfvdt7yq] {
    display: flex;
    justify-content: flex-end;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-template-editor-list[b-nfkfvdt7yq] {
    padding-inline-start: 20px;
}
/* /Components/Assistant/PlanPeopleEditor.razor.rz.scp.css */
/* W30-08 · P6 · the one People editor: the by-hand form, the sheet, another source, the count and the list.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-people-editor-panel[b-8taqzj4b5v] {
    display: grid;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-people-editor-form[b-8taqzj4b5v] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
    max-inline-size: 40rem;
}

.biztech-people-editor-roles[b-8taqzj4b5v] {
    display: grid;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-people-editor-columns[b-8taqzj4b5v] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    gap: 8px;
}

/* The status region: the alerts and the count stack with a gap (I18), none carrying a margin. */
.biztech-people-editor-status[b-8taqzj4b5v] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-people-editor-extra[b-8taqzj4b5v] {
    min-inline-size: 0;
}
/* /Components/Assistant/PlanPublishReview.razor.rz.scp.css */
/* W28-08 · W30-08 · D5 · the one Publish review: a panel of groups, each a heading and its ticks; the button last. */
.biztech-plan-publish[b-msuj6a0trs] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
}

.biztech-plan-publish-group[b-msuj6a0trs] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* W31-06 · F4 · a red's tick box and its Fix side by side; the Fix wraps below on a narrow screen. */
.biztech-plan-publish-red[b-msuj6a0trs] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Assistant/Statistics/StatisticFactView.razor.rz.scp.css */
/* W19-19 · a statistic in its card: a caption naming what was counted, the table, and how many rows it left out. Spacing belongs to
   the container (I18). */
.biztech-statistic[b-ospgzl1a70] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-statistic-heading[b-ospgzl1a70],
.biztech-statistic-more[b-ospgzl1a70] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-statistic-heading[b-ospgzl1a70] {
    font-weight: var(--biztech-font-button-weight);
}
/* /Components/Assistant/TenantPlansPage.razor.rz.scp.css */
/* W28-08 · the platform's new-tenant page: two sections of rows, then the plan pane at the height the artifact needs. */
.biztech-tenant-plans-sections[b-mn0t7eaufk] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

.biztech-tenant-plans-section[b-mn0t7eaufk] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-tenant-plans-list[b-mn0t7eaufk] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-tenant-plans-row[b-mn0t7eaufk] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    padding: 12px 16px;
    /* §2a C9 · a row is an in-flow card: the quiet edge, twice the theme's radius, the surface ground and the card's depth. */
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-tenant-plans-name[b-mn0t7eaufk] {
    display: flex;
    flex: 1 1 16rem;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* W19-23 · the template's title and its kind side by side. */
.biztech-tenant-plans-title[b-mn0t7eaufk] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-tenant-plans-pane[b-mn0t7eaufk] {
    display: flex;
    flex-direction: column;
    block-size: 80vh;
    min-block-size: 32rem;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

.biztech-tenant-plans-created[b-mn0t7eaufk] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}
/* /Components/Assistant/TenantSetupExportPanel.razor.rz.scp.css */
/* W28-08 · Export setup under the Setup assistant's plans: the side column's own spacing; the seed's select and button wrap. */
.biztech-setup-export[b-zdxoqnsgc3] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The side column's own heading and note, on the same tokens as the plans' (AdminAssistantPage.razor.css): its rules are scoped
   there and do not reach this component. */
.biztech-setup-export-heading[b-zdxoqnsgc3] {
    margin-block: 0;
    padding-inline: 8px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    font-weight: var(--biztech-font-button-weight);
    color: var(--biztech-palette-text-secondary);
}

.biztech-setup-export-note[b-zdxoqnsgc3] {
    margin-block: 0;
    padding-inline: 8px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-setup-export-seed[b-zdxoqnsgc3] {
    padding-inline: 8px;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px;
}
/* /Components/Assistant/TenantStepForm.razor.rz.scp.css */
/* W28-15 · the Tenant step's form: a column of boxes, the container owning the space between them (I18). */
.biztech-tenant-step-form[b-ot1ubnnnvj] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
/* /Components/Broadcasting/BroadcastPlayer.razor.rz.scp.css */
/* W6-23 · F8.16 · the audience's player.

   🔴 R13.7's 375px IS THE CONSTRAINT THIS FILE EXISTS FOR, and the card states it as an acceptance:
   "the player not eating the whole viewport and the channel's schedule still reachable below it". A
   16:9 video at 100% width is 211px tall on a phone - fine - but an UNCONSTRAINED one is whatever the
   stream's intrinsic size says, and a 1080p source lays out at 1080px tall before any CSS runs. The
   schedule would then be a scroll away from a page whose whole job is showing it.

   So the block size is capped against the VIEWPORT rather than against the element: 60svh leaves the
   schedule's first row on screen at every height, and `svh` rather than `vh` because iOS Safari's `vh`
   is the tallest the viewport ever gets - measured against the retracted URL bar - which is precisely
   the case where a cap must not be generous.

   🔴 NO COLOUR AT ALL, AND THE VIDEO'S GROUND IS THE PAGE'S. R14.1 layer 4's hex sweep
   (PortalStyleSheetTests.EveryStyleSheet) forbids a literal in any scoped sheet, and the first draft of
   this file carried `background: #000` out of habit - a player "should" be black. It should not: there
   is no token for the inside of a video frame, inventing one would be a palette decision this card has
   no business taking, and a named colour to dodge the sweep would be weakening a guardrail to make
   something pass. Letterbox bars therefore show the page's own ground, which is honest in both modes
   and is what `object-fit: contain` is for.

   I17 does not apply: this is not a panel and declares no `biztech-pa-*`. I18 does: the spacing between
   the video, the control and the caption is the CONTAINER'S gap, and no child carries a margin.

   12px is the house value for "between two controls" - the one MainLayout.razor.css:70,
   MainNavMenu.razor.css:36, UiAlert.razor.css:14 and InstallPrompt.razor.css all declare.
   BizTechCssVariables emits no spacing custom property, so a literal is what this layer has (R5.4: not
   a magic number, the house one). 🔴 An earlier draft wrote `var(--biztech-space-2)`, which does not
   exist - and an unresolvable custom property with no fallback drops the whole declaration silently,
   so the gap would simply have been zero with nothing to report it. */

.biztech-broadcast-player[b-3m3fzh12t3] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-broadcast-video[b-3m3fzh12t3] {
    inline-size: 100%;

    /* Before the first frame arrives a <video> with no source has NO intrinsic size, so it would
       collapse to nothing and the Watch control would jump the moment the stream attached. The ratio
       holds the box open at the shape a broadcast will almost always be. */
    aspect-ratio: 16 / 9;

    /* The cap. See the header: this is what keeps the schedule reachable at 375px. */
    max-block-size: 60svh;

    /* `contain`, so a stream whose shape is not 16:9 is letterboxed rather than cropped - an audience
       must not lose the edges of a slide because the host's camera is portrait. */
    object-fit: contain;

    /* --biztech-radius-default, not a `-md` that does not exist. The emitted token set is
       `default` and `pill`, and BizTechCssVariables.Emit is the only thing that decides that. */
    border-radius: var(--biztech-radius-default);
}

/* R5.8's 44px for the Watch control under a coarse pointer, carried by the control's own component. It used to arrive
   from app.css's `.biztech-anon` block, which floors every button on AnonymousLayout; the channel page sits in
   PortalLayout now, which floors only its own header's controls - so the minimum travels with the control, as
   InstallPrompt's does. The size class is named so the rule outweighs UiButton's own floor (W3-26's measurement). */
@media (pointer: coarse) {
    .biztech-broadcast-player[b-3m3fzh12t3]  .biztech-button.biztech-button-small,
    .biztech-broadcast-player[b-3m3fzh12t3]  .biztech-button.biztech-button-medium {
        min-block-size: 44px;
    }
}
/* /Components/Broadcasting/LiveNowBadge.razor.rz.scp.css */
/* W6-23 · F8.18 · the live-now badge.

   🔴 R6.8's GUARD RUNS IN THE `reduce` DIRECTION, WHICH IS THE REPOSITORY'S AND NOT A PREFERENCE.
   UiProgressLinear.razor.css is the one precedent for an animation in this application and it animates
   by default, then sets `animation: none` inside `@media (prefers-reduced-motion: reduce)` while
   keeping the element visibly meaningful - its own words: "removing the only sign that something is in
   flight is a worse answer than removing the motion."

   The same applies here and matters more: under `reduce` the dot stops pulsing and stays a DOT, beside
   the word "Live" and the event's name. The motion was never carrying the signal - R12.7 and R6.8 both
   require that - so removing it costs nothing a reader needs.

   (An earlier draft of the plan proposed the opposite direction, `no-preference` as the opt-in. It
   would work, and it would make this the only file in the application guarding motion the other way
   round, which is a worse outcome than either direction on its own merits.)

   🔴 PortalStyleSheetTests.The_one_animation_in_the_app_is_guarded_by_prefers_reduced_motion READS
   app.css ONLY, and asserts the board-card block. A @keyframes in a scoped sheet does not break it and
   does not need adding to it - UiProgressLinear already has one. That test's NAME is now stale and the
   test is still correct; leave it alone.

   R6.7 allows `transform` and `opacity` and nothing that lays out, which is why the pulse scales and
   fades rather than animating width - the same line UiProgressLinear draws.

   🔴 NO COLOUR LITERAL. `--biztech-palette-error` is the role, and it is in PaletteContrast's required
   pairs so both modes are already gated. Colour is not carrying the signal here (R12.7) - the word is -
   so the role is chosen for what an audience expects a live dot to look like rather than to convey
   anything on its own.

   12px / 8px are the house values this layer uses for "between two controls" and "inside a control" -
   BizTechCssVariables emits no spacing custom property, so a literal is what there is (R5.4). */

.biztech-live-badge[b-8fc2is7pve] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border-radius: var(--biztech-radius-pill);
}

.biztech-live-dot[b-8fc2is7pve] {
    /* A fixed box, so the dot does not inherit the line height of the text beside it.

       8px rather than the 10px this first carried: R5.4's sweep refuses a raw length that is neither a
       multiple of the 4px base unit nor a registered layout constant, and 10px is neither. The dot is
       decoration beside a word that carries the meaning, so nothing about it is load-bearing at an
       exact value - which is the only thing that would have earned a registry entry. */
    inline-size: 8px;
    block-size: 8px;
    flex: 0 0 auto;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-error);
    animation: biztech-live-pulse-b-8fc2is7pve 1600ms ease-in-out infinite;
}

.biztech-live-word[b-8fc2is7pve] {
    font-weight: var(--biztech-font-button-weight);
    color: var(--biztech-palette-error);

    /* The word is the signal, so it must survive at the size the caption around it is set in. */
    font-size: var(--biztech-font-caption-size);
    letter-spacing: var(--biztech-font-caption-letter-spacing);
    text-transform: uppercase;
}

.biztech-live-name[b-8fc2is7pve] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

@keyframes biztech-live-pulse-b-8fc2is7pve {
    from { opacity: 1; }
    50% { opacity: .35; }
    to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-live-dot[b-8fc2is7pve] {
        /* Still a dot, still red, still beside the word. It simply stops moving - WCAG 2.3.3, and the
           reason this is not `display: none`: the badge's meaning is the word and the name, and the
           dot going would change what the badge LOOKS like between two readers for no benefit. */
        animation: none;
    }
}
/* /Components/Broadcasting/LiveNowPrompt.razor.rz.scp.css */
/* W6-23 · F8.18 · the join prompt.

   🔴 LAYOUT ONLY, AND NO BOX-MODEL PROPERTY THE UTILITY LAYER OWNS - InstallPrompt.razor.css's rule
   and its measurement: Blazor rewrites a scoped selector at (0,2,0) against a utility class's (0,1,0),
   and _Host.cshtml links the scoped bundle AFTER app.css, so a scoped rule wins twice over. W0-52
   measured nine utilities computing zero that way. Spacing between this strip and the grid below it is
   the page's.

   12px is the house value for "between two controls" - the one MainLayout.razor.css:70,
   MainNavMenu.razor.css:36, UiAlert.razor.css:14 and InstallPrompt.razor.css all declare. No spacing
   custom property is emitted, so a literal is what this layer has (R5.4).

   R13.8 · `flex-wrap` rather than a min-width: at 375px the badge, the link and the dismiss control do
   not fit one line, and wrapping is what keeps every element's right edge inside #biztech-main.
   Nothing here declares `overflow-x`, which would exclude this subtree from the landmark walk while
   looking like a fix.

   🔴 ::deep ON EVERY SELECTOR THAT NAMES A CHILD COMPONENT'S CLASS - I19, and the shape
   ScopedStyleReachTests sweeps for. `biztech-live-join` is this file's own markup and takes a plain
   rule; `biztech-live-dismiss` is handed to UiIconButton as a Class parameter, so it lands on THAT
   component's root and carries ITS scope attribute. Without ::deep the compiled selector would be
   `.biztech-live-dismiss[b-thisfile]`, which matches nothing - present, inert and silent, which
   InstallPrompt.razor.css records shipping for as long as that rule existed. */

.biztech-live-prompt[b-636muifjsv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

/* The badge takes the room the two controls do not, so they stay together when it wraps.

   ::deep, because `biztech-live-badge` is LiveNowBadge's own markup and carries that component's
   scope attribute rather than this file's. */
.biztech-live-prompt[b-636muifjsv]  .biztech-live-badge {
    flex: 1 1 12rem;
}

.biztech-live-join[b-636muifjsv] {
    color: var(--biztech-palette-primary);
    font-weight: var(--biztech-font-button-weight);
}

/* 🔴 R5.8's 44px, CARRIED BY THIS COMPONENT RATHER THAN BY WHICHEVER SHELL HOSTS IT - the lesson
   InstallPromptTests learned when W1b-08 moved its host page off AnonymousLayout and the measurement
   dropped to 42.5px and 32px against 44. app.css's `(pointer: coarse)` block is scoped to
   `.biztech-anon`, and this strip renders on PortalLayout AND on the channel page's AnonymousLayout.

   That test's own message says where the fix goes: "Fix the control's size, never that block: it is a
   guardrail."

   Both axes for the icon button, because UiIconButton sets `block-size` in both and a single-axis
   floor leaves a 44x32 target. The anchor is text and floors only its height. */
@media (pointer: coarse) {
    .biztech-live-prompt[b-636muifjsv]  .biztech-live-dismiss {
        min-block-size: 44px;
        min-inline-size: 44px;
    }

    .biztech-live-join[b-636muifjsv] {
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }
}
/* /Components/Broadcasting/RecordingBadge.razor.rz.scp.css */
/* W6-25 · F8.29 · the availability indicator, on a schedule row.

   This file does almost nothing on purpose. The chip is UiChip's and is styled there; the words are
   the signal and need no help; the glyph is UiIcon's and inherits `currentColor` by R11.3. What is left
   is one question — how the chip and its link sit beside each other on a row that has to work at 375px.

   🔴 I19: BOTH CLASSES BELOW APPEAR IN THIS COMPONENT'S OWN MARKUP, which is the only kind of selector
   a scoped sheet can reach. There is deliberately NO rule for `.biztech-chip` here: that class is
   UiChip's own root, Blazor stamps this component's scope on the LAST compound, and a rule naming it
   would be inert with no error and no warning. Sizing the chip from outside means `::deep` or a grid
   track, and neither is needed — so neither is written.

   🔴 I18: the space between the chip and the link is the CONTAINER'S gap. A margin on the anchor would
   add to whatever gap the schedule row already declares, which is the failure that rule records: "the
   two add up."

   `inline-flex` rather than `flex`, because this sits inside a list item beside text and a block-level
   wrapper would force a line of its own at every width. `wrap` so the link drops below the chip at
   375px rather than pushing the row sideways — R13.8's "overflow-x: hidden is not a responsive
   strategy" is about hiding this, and wrapping is the thing it hides.

   12px is the house value for "between two controls" — the one MainLayout.razor.css:70,
   MainNavMenu.razor.css:36 and BroadcastPlayer.razor.css all declare. BizTechCssVariables emits no
   spacing custom property, so a literal is what this layer has (R5.4: not a magic number, the house
   one). */

.biztech-recording-availability[b-ddatstmyzh] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

/* The link takes the page's own link treatment and declares no colour of its own — R14.1 layer 4's hex
   sweep forbids a literal, and inventing a token for "a link inside a badge" would be a palette
   decision this card has no business taking. What IS declared is the target size: R5.8 asks for 44px
   under a coarse pointer, and a text link on a schedule row is otherwise whatever the line height
   happens to be. */
/* "Watch the recording" as the card's one real action: a FILLED primary pill with a play mark, so it can never be
   mistaken for the availability chip beside it, which is a tinted label. The primary and its own ink are a pair
   PaletteContrast holds. */
.biztech-recording-link[b-ddatstmyzh] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px 8px 12px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    font-size: var(--biztech-font-button-size);
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    transition: filter var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-recording-link:hover[b-ddatstmyzh] {
    filter: brightness(1.12);
}

/* The play mark: a triangle drawn from borders in the link's own ink, inside a small ring of the same ink. */
.biztech-recording-play[b-ddatstmyzh] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 20px;
    block-size: 20px;
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, currentColor 22%, transparent);
}

.biztech-recording-play[b-ddatstmyzh]::before {
    content: "";
    margin-inline-start: 2px;
    border-block: 4px solid transparent;
    border-inline-start: 8px solid currentColor;
}

@media (pointer: coarse) {
    .biztech-recording-link[b-ddatstmyzh] {
        /* The whole 44px, reached by padding rather than by a min-height: a link is inline, so a block
           size on it does nothing to the box a finger actually hits. The negative margin is deliberately
           absent — it would pull the row's own spacing back and reintroduce I18's addition problem. */
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }
}

/* The chip's glyph and its words had nothing between them ("⚠Recording failed"); UiChip lays its content out in a
   row and leaves the space to the caller. */
.biztech-recording-availability[b-ddatstmyzh]  .biztech-chip {
    gap: 4px;
}
/* /Components/Broadcasting/RecordingPlayer.razor.rz.scp.css */
/* W6-25 · F8.28 · the recorded player.

   🔴 DELIBERATELY THE SAME GEOMETRY AS BroadcastPlayer.razor.css, AND NOT SHARED WITH IT. Two scoped
   stylesheets cannot share a rule — Blazor stamps a different scope attribute on each, so a class
   declared in one is inert in the other (invariant I19). The alternative is a global utility, which
   R8.7 reserves for spacing. So the values are repeated and the REASONS are not: read that file for
   why the cap is 60svh, why it is `svh` rather than `vh`, why nothing here declares a colour, and why
   12px is the house gap. What follows records only what differs.

   🔴 WHAT DIFFERS: THE ASPECT RATIO IS A FALLBACK HERE RATHER THAN A HOLD-OPEN. A live <video> has no
   source until a track attaches, so it has no intrinsic size and would collapse to nothing; this one
   has a `src` from the first render, so the browser learns the real shape as soon as it reads the
   file's header. The ratio still matters for the moments BEFORE that — with preload="none" the header
   is not fetched until somebody presses play, so an unconstrained box would be zero-height and the
   controls would have nowhere to draw.

   I17 does not apply: this is not a panel and declares no `biztech-pa-*`. I18 does: the gap between the
   video and its caption belongs to the container, and neither child carries a margin.

   I19: every class below appears in this component's own markup. There is no `> *` and nothing reaching
   into a child component — the caption is a UiText and is left entirely alone. */

.biztech-recording-player[b-i51kyl9xcf] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-recording-video[b-i51kyl9xcf] {
    inline-size: 100%;

    /* The shape before the file's header is read. See the third paragraph of the header: with
       preload="none" that can be several seconds after the page settles, or never. */
    aspect-ratio: 16 / 9;

    /* The cap that keeps the page's heading and its delete control reachable at 375px, which is R13.7's
       smallest supported width. BroadcastPlayer.razor.css carries the full argument for the unit. */
    max-block-size: 60svh;

    /* `contain`, so a recording whose shape is not 16:9 is letterboxed rather than cropped. A cropped
       consultation loses whoever was sitting at the edge of frame. */
    object-fit: contain;

    border-radius: var(--biztech-radius-default);
}
/* /Components/Cases/AgentCaseStartPanel.razor.rz.scp.css */
/* W31-04 · the grouped Start tab: one column whose gap spaces the categories (I17/I18), and in each a heading over its
   cards. Moved from AgentCases.razor.css when that page merged into the launcher. */

.biztech-agent-case-groups[b-qrh7dyz227] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

.biztech-agent-case-group[b-qrh7dyz227] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
/* /Components/Cases/AgentSessionBody.razor.rz.scp.css */
/* W6-45 · F8.1 · design §3 and §4. The agent's session console — the two rules that are about THIS
   page's own elements and could not live anywhere else.

   R14.1: go one layer down only when the layer above cannot reach. `SessionStage.razor.css` is the
   frame's sheet and reaches the frame's own boxes; `UiToolbar.razor.css` is the seam's and reaches the
   row. Neither can see a wrapper this page writes into a slot, because a scoped rule compiles to
   `.rule[b-owner]` and these elements carry THIS page's scope attribute — which is also why the frame
   needs `::deep` to reach them from the other side. */

/* 🔴 THE MARKERS MUST NOT BECOME BOXES.

   Every control in the toolbar is wrapped in a span carrying `data-session-control`, because
   Components/Ui takes DECLARED parameters only — an undeclared attribute on a seam component is
   rejected at render, which is the finding `data-show-section` already records. Those markers are what
   let the render tests assert the toolbar's SET rather than a handful of labels.

   A wrapper span is a flex ITEM, so without this rule each control would sit inside its own box and the
   row's gap would apply between the boxes rather than between the controls. `display: contents` removes
   the box and leaves the children as direct flex items of the row. It is the same mechanism
   `UiToolbar.razor.css` uses on `.biztech-toolbar-inline`, for the same reason and one layer up.

   It zeroes no box-model property (R14.1a, UtilitySpecificityTests): there is no padding, margin,
   border or size here to zero — the element simply stops generating a box of its own. */
/* 🔴 W14-01 · THE ROW READS AS THREE ZONES, AND THE DIVIDERS ARE THE ONLY THING THAT SAYS SO.

   Seven controls at equal weight, so nothing read first. They are not seven things - they are three
   questions, in the order the work happens:

     who is driving  |  what is on the customer's screen  |  what you do on top of it      [frame]

   `take-presenter` opens the row; `show` holds BOTH pickers, because the select and the library answer
   one question from two sources; `annotate` opens the third. Swap already sits at the far end on
   .biztech-session-toolbar-end because it moves the LAYOUT rather than the content - SessionStage's own
   distinction, unchanged.

   🔴 NO NEW MARKUP, AND THAT IS DELIBERATE. The zones fall out of the data-session-control
   markers this page already writes, so nothing is restructured and UiToolbar's collapse - which renders
   Overflow TWICE, inline above sm and inside a More menu below - keeps working untouched. A wrapper per
   zone would have had to be written into both copies.

   outline-subtle, not outline: R3.7 declares the subtle role ornament, and a divider that groups is
   exactly that - it carries no state, and losing it costs tidiness rather than meaning. A border that
   MEANT something would take the stronger role (R3.5).

   Below sm the whole row is inside the More menu as a column, where a leading border would draw a tick
   down the left of two items. The media query at the end of this file undoes it there. */
.biztech-session-control[data-session-control="show"][b-avg0t7wg4n],
.biztech-session-control[data-session-control="annotate"][b-avg0t7wg4n] {
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
    padding-inline-start: 12px;
}

.biztech-session-control[b-avg0t7wg4n] {
    display: contents;
}

/* 🔴 W6-53 MOVED .biztech-session-heading TO app.css, AND THE REASON IS R8.2.

   The rule and its whole argument were here, scoped to this page. SessionViewer then needed the
   identical thing - design §3 empties the top of ITS stage too - and a scoped copy would have been the
   same rule in two files: "two components doing one job is the failure this rule exists for". A scoped
   sheet cannot be shared, so the class is app.css's now, with the reasoning intact. */

/* 🔴 W14-01 · AND THE DIVIDERS COME OFF BELOW sm, WHERE THE ROW IS NOT A ROW.

   UiToolbar collapses its Overflow into a `More` menu below this width, so the controls stack as a
   COLUMN - and a leading border on two of them draws a tick down the left of the list rather than a
   separator between groups. Grouping is a claim about a row; a column has already grouped by stacking.

   599.98px is MudBlazor's sm, which MainLayout.razor.css and app.css already key their blocks on. A
   second number here would let this row disagree with the drawer about where the layout changes, on the
   one screen where both are visible at once. */
@media (max-width: 599.98px) {
    .biztech-session-control[data-session-control="show"][b-avg0t7wg4n],
    .biztech-session-control[data-session-control="annotate"][b-avg0t7wg4n] {
        border-inline-start: 0;
        padding-inline-start: 0;
    }
}

/* 🔴 W19 · THE TOOLBAR'S SECOND LINE IS THE SECTIONS, AND IT IS DRAWN THERE BY ORDER, NOT BY WRAP.

   The row is UiToolbar's flex box, and every marker and wrapper on it is `display: contents`, so the
   sections zone is a direct flex item of the row. A full basis puts it on a line of its own and
   `order: 1` keeps it below every control however the markup is ordered; the chevron's panel takes
   `order: 2` so what unfolds still opens under both. The rule above the zone is ornament under R3.7 -
   the zone is already a line of its own - which is why it is outline-subtle.

   Below sm the zone is inside the More menu's column with everything else, where a line of its own is
   what every item already has. */
.biztech-session-toolbar[b-avg0t7wg4n] {
    display: contents;
}

.biztech-session-toolbar[b-avg0t7wg4n]  .biztech-toolbar-more {
    order: 2;
}

.biztech-session-sections[b-avg0t7wg4n] {
    order: 1;
    flex: 1 0 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding-block-start: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The zone's verb, said once. Caption ink and size: it labels the chips, it is not one of them. */
.biztech-session-sections__label[b-avg0t7wg4n] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
}

/* A section is a chip: the console's pill radius, so four of them read as a set of places rather than
   four more buttons shaped like Take presenter. Corners only - the seam's outline edge stays, because
   it is the one thing that says a chip can be pressed and must pass 3:1 (R3.5, WCAG 1.4.11) - and the
   button's padding and height are left alone (R14.1a). */
.biztech-session-sections[b-avg0t7wg4n]  .biztech-button-outlined {
    border-radius: var(--biztech-radius-pill);
}

/* 🔴 W19 · THE SAVE FOOT. A rule above it, 16px either side of the rule (biztech-mt-4 on the markup
   above, this padding below), and the caption beside the button with the row's 12px gap. The last
   grid's 12px margin collapses into the 16px above the rule - the paper is block flow - so the space
   over the rule is 16px. 4 x 4 (R5.1). */
.biztech-session-save[b-avg0t7wg4n] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding-block-start: 1rem;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W19 · the stage-focus track in the band, before Take presenter and Leave session, centred on the
   band's line, and 8px more after it than the band's gap between the two buttons, so the setting reads
   apart from the two actions. */
.biztech-session-bar-switch[b-avg0t7wg4n] {
    display: inline-flex;
    align-items: center;
    margin-inline-end: 8px;
}

/* 🔴 W19 · THE ROW'S TRAILING CONTROLS: ANNOTATE, THEN THE CHEVRON, AT ONE SIZE.

   The chevron is the seam's expander, which stretches to the row's height and pads 8px, so beside a
   wrapped sentence it stood 60px tall next to a 32px Annotate. Here it is the icon buttons' 32px square
   with their corner, centred on the line. Annotate takes an auto start margin so it sits at the
   trailing end even when no show zone is in the row to take the free width; when one is, the zone
   grows and the margin resolves to nothing. 8 x 4 (R5.1). */
.biztech-session-toolbar[b-avg0t7wg4n]  .biztech-toolbar-expander {
    align-self: center;
    /* The row's buttons are the theme's control height now, so the chevron is too - a square of it. */
    inline-size: var(--biztech-control-height);
    block-size: var(--biztech-control-height);
    padding: 4px;
    border-radius: var(--biztech-radius-default);
}

.biztech-session-control[data-session-control="annotate"][b-avg0t7wg4n]  .biztech-button {
    margin-inline-start: auto;
}

/* 🔴 And while Annotate is on the row, the chevron gives up its own auto margin to it. Two auto
   margins on one line split the free space between them, so on a type with no show zone - Customer
   Inquiry (Live) - the pen stood in the middle of the row. 4px rather than none keeps the chevron a
   step apart from the pen it now sits beside (the row's 8px gap plus this). 1 x 4 (R5.1). */
.biztech-session-toolbar[b-avg0t7wg4n]  .biztech-toolbar:has([data-session-control="annotate"]) > .biztech-toolbar-expander {
    margin-inline-start: 4px;
}

/* 🔴 W19 · ONE BOX AT THE END OF A PERSON'S ROW: THE ASK, AND THE CALL CONTROLS UNDER IT.

   The ask and the call controls were two grid items placing themselves - the ask across the row's two
   lines in the third column, the controls on a third line of their own - so a person in the call took
   three or four lines. One box in the third column, stacked and aligned to the end, keeps the row at two
   lines: Request beside the name, the round Mute and Remove beside the state. */
.biztech-session-row-end[b-avg0t7wg4n] {
    grid-row: 1 / span 2;
    grid-column: 3;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
}
/* /Components/Cases/AnnotationOverlay.razor.rz.scp.css */
/* W6-10 · F8.8 · the annotation overlay's own styles.

   Scoped, so they arrive through BizTech.Portal.styles.css - already referenced from
   Pages/_Host.cshtml, which is why this file needs no host-page change. SignaturePad.razor.css makes
   the same note.

   🔴 NO @media (prefers-color-scheme) ANYWHERE (I16, R7.3). Every colour here reads a --biztech-*
   token, which BizTechCssVariables re-emits when the mode flips - so a dark-mode overlay is free and
   there is nothing to keep in step. That is the whole reason the ink is SVG rather than a canvas: a
   canvas would need getComputedStyle and a repaint on the flip. */

.biztech-annotation-host[b-p34n9vrh8w] {
    /* The positioning context the ink layer fills. */
    position: relative;

    /* 🔴 W6-53 · R13.1. THE STICKY BAND MUST NOT LAND ON TOP OF THE INK, AND SCROLLING IS WHEN IT
       DID.

       SessionStage pins the band at 600px and up. Nothing here changed that - what changed is the STAGE:
       W6-53 took an h1, a `SESSION: {ref}` badge and a "You are in this session as X" line off the top
       of the customer's pane, so the artefact now begins about 90px higher. Scroll it into view and its
       top edge arrives UNDER the band rather than below it, and a pointer aimed at the first 48px of the
       drawing surface reaches the band instead.

       Measured by SessionAnnotationTouchTests.A_stroke_normalises_to_the_same_fractions_at_every_width,
       which went red at 768 and at 1440 and stayed GREEN at 375 - the one width where the band is not
       sticky. That split is the whole diagnosis, and it is why this is a page defect rather than a test
       accommodation: a customer who scrolls has the top of the artefact hidden under the band, and
       drawing there hits the band.

       scroll-margin-block-start is the property browsers give for exactly this, and Chromium honours it
       in scrollIntoViewIfNeeded. 4rem = 64px, a scale value, against a band measured at 49px - the
       clearance is deliberate rather than exact, because the band's height is content-driven and a
       single wrapped control would grow it.

       Inside the same media query the pin is, so below sm - where nothing is pinned - nothing is
       reserved either. R13.3: "every desktop-only rule must be reversed there". */
}

@media (min-width: 600px) {
    .biztech-annotation-host[b-p34n9vrh8w] {
        scroll-margin-block-start: 4rem;
    }
}

.biztech-annotation-ink[b-p34n9vrh8w] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;

    /* 🔴 IDLE BY DEFAULT, AND THIS IS THE CARD'S "AN OVERLAY, NEVER A MUTATION" IN ONE DECLARATION.
       Two stacked surfaces cannot both take a pointer, so until the visitor turns annotating on every
       field underneath is reachable and nothing about the form has changed. */
    pointer-events: none;
}

.biztech-annotation-live[b-p34n9vrh8w] {
    pointer-events: auto;

    /* 🔴 BOTH NEEDED ON TOUCH, and R13.5 names this surface specifically. touch-action stops the
       browser claiming the gesture for a scroll or a double-tap zoom before pointermove ever fires;
       without it the overlay is unusable on a phone and works perfectly on the desktop it was tested
       on. The module calls preventDefault as well - belt and braces, because the two fail differently.
       SessionAnnotationTouchTests dispatches real CDP touch input to prove it. */
    touch-action: none;
    cursor: crosshair;
}

/* One stroke's width in the unit square would be invisible, so the ink is sized in absolute units and
   told not to scale with the viewBox. Without non-scaling-stroke, preserveAspectRatio="none" stretches
   the line THICKNESS along with the geometry, and one mark is a different weight on each pane. */
.biztech-annotation-ink polyline[b-p34n9vrh8w],
.biztech-annotation-sample line[b-p34n9vrh8w] {
    fill: none;

    /* 4px, not 3: §5's scale is multiples of the 4px base unit and PortalStyleSheetTests enforces it.
       Thicker is the right direction anyway - this is a mark meant to be read on a projector and on a
       375px phone. */
    stroke-width: 4px;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

/* 🔴 THE FOUR PENS - D5. A COLOUR AND A DASH PATTERN EACH, never a colour alone: R11.5 and R12.2
   forbid colour as the only channel, and the legend beside the surface is what turns a dash into a
   name. Four roles from §3's 22, all of which BizTechPaletteDefaults sets in both modes. */
.biztech-annotation-pen-0[b-p34n9vrh8w] {
    stroke: var(--biztech-palette-primary);
}

.biztech-annotation-pen-1[b-p34n9vrh8w] {
    stroke: var(--biztech-palette-secondary);
    stroke-dasharray: 9 5;
}

.biztech-annotation-pen-2[b-p34n9vrh8w] {
    stroke: var(--biztech-palette-tertiary);
    stroke-dasharray: 2 5;
}

.biztech-annotation-pen-3[b-p34n9vrh8w] {
    stroke: var(--biztech-palette-info);
    stroke-dasharray: 12 4 2 4;
}

/* The in-progress stroke. Deliberately NEUTRAL ink rather than the drawer's own pen: the pen is
   assigned by AnnotationLayer from the room, which JavaScript does not have - and the real mark, in
   the real pen, replaces this a moment later when the pen lifts. */
.biztech-annotation-preview[b-p34n9vrh8w] {
    stroke: var(--biztech-palette-text-primary);
}

/* A <ul>, so the user agent gives it a block margin and a list indent, and both are noise here: this
   is a key to the ink, not a bulleted list in prose.

   🔴 margin-block AND padding-inline-start RATHER THAN THE SHORTHANDS, which is not cosmetic. A scoped
   selector is (0,2,0) against a utility class's (0,1,0), so `margin: 0` here would silently beat every
   biztech-mb-* a page passes this component - UtilitySpecificityTests' whole subject. The longhands
   remove exactly what the browser chose and leave the utility layer owning the rest, which is why this
   file needs no entry in that test's Declared set. */
.biztech-annotation-legend[b-p34n9vrh8w] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-block: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-annotation-legend li[b-p34n9vrh8w] {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.biztech-annotation-sample[b-p34n9vrh8w] {
    width: 24px;
    height: 8px;
    flex: 0 0 auto;
}
/* /Components/Cases/AssignPanel.razor.rz.scp.css */
/*
    W4-25 · the People tab's assign form. It spans the card, as the table under it does: capped at 880px, its
    fields stopped short of the card's edge and left a block of empty card to their right, so the form read as
    narrower than everything around it. The grid's own breakpoints still stack the columns on a phone.
*/

/*
    🔴 THE REMOVE CONTROL SITS LEVEL WITH THE BOXES, NOT WITH THE LABELS. Its cell is the only one in
    the row with no label above it, so once the row aligns to its top — which is what stops a
    validation message shoving its neighbours down — this control would ride up to the label line.

    The offset is the label's own line box (body2's size times body2's ratio) plus the 4px gap
    `.biztech-field` puts between a label and its control. Both halves are read from the tokens the
    label itself reads, so a change of type scale moves the control with it rather than leaving a
    number here that used to be right.
*/
.biztech-assign-remove[b-z1af1ryg3f] {
    display: inline-flex;
    margin-block-start: calc(
        (var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height)) + 4px);
}
/* /Components/Cases/CaseAppIntakePanel.razor.rz.scp.css */
/* W25-02 · the staff panel for what an app sent. I18: the stack carries the gap between its children; the spacing steps
   are the 8px grid's (R5), as SessionLibraryPicker spells them. */
.biztech-app-intake-stack[b-76hsaygtwe] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-app-intake-actions[b-76hsaygtwe] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* A SHA-256 is 64 characters with no break opportunity; it wraps anywhere rather than widening the page at 375px. */
.biztech-app-intake-hash[b-76hsaygtwe] {
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    overflow-wrap: anywhere;
    word-break: break-all;
}

/* The preview: a bounded, outlined box, never wider than the panel. */
.biztech-app-intake-snapshot[b-76hsaygtwe] {
    width: 100%;
    min-height: 20rem;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}
/* /Components/Cases/CaseAssistantConversation.razor.rz.scp.css */
/* W18-07 · D3. The transcript's own rhythm: the heading and the turns apart, each turn's lines together. */
.biztech-case-assistant-conversation[b-e2zytv7ech] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-case-assistant-turn[b-e2zytv7ech] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Cases/CaseCard.razor.rz.scp.css */
/*
    W8-24 · one case as a card — legacy's Assigned Inquiries tile.

    I17 · the padding is here because UiPaper has none of its own. I18 · the spacing between the cover,
    the chip, the subject and the rest is the container's `gap` and never a margin per child, or the
    two add up into a card that looks misaligned for a reason nobody can see in the markup.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit
    (PortalStyleSheetTests' two sweeps).
*/

/*
    🔴 THE CHAIN OF HEIGHTS, AND IT WAS BROKEN IN THE MIDDLE.

    A row of cards is one height so the Open buttons line up. That needs `height: 100%` at EVERY step
    from the grid column down to the card, and one step had none: UiGrid is a CSS grid, so the column
    stretches to the row on its own, but UiPaper sat between the column and the card at its content's
    height - so the card's `height: 100%` resolved against an auto-height parent and did nothing.
    Measured on the stack: four Open buttons in one row at y 459, 461, 475 and 475.

    The frame is a div CaseCard renders, which is what lets a ::deep rule reach the paper at all (I19).
*/
.biztech-case-card-frame[b-4srrdapwrm] {
    block-size: 100%;
    container-type: inline-size;
}

/*
    ::deep, because the element being sized is UiPaper's root and the scope attribute on it is UiPaper's.
    This sets a BOX SIZE and no appearance - the surface, the border and the radius all stay the seam's
    (R3.12). A Fill parameter on UiPaper would be the alternative, and it would put a layout concern of
    one caller into a component every page shares.
*/
.biztech-case-card-frame[b-4srrdapwrm]  .biztech-paper {
    block-size: 100%;
}

/*
    The grid track supplies the width; nothing here sets one (R8.7).
*/
/* 🔴 W8-25 · 12px AND A 2px GAP, DOWN FROM 16 AND 4, AFTER READING A ROW OF THESE ON THE STACK.
   A work card is four short caption lines and a chip: at 16px of padding with 4px between every line,
   half the card was space and a row of four ran past the fold on a laptop. The cover is the content;
   the text is a caption under it. R5's scale still holds and the sweep is what checked it - every
   length here is a multiple of the 4px base unit - and the CARD is what got smaller, not the type. */
.biztech-case-card[b-4srrdapwrm] {
    display: flex;
    flex-direction: column;
    gap: 8px;

    /* ❗ border-box, AND THE CHAIN ABOVE IS WHAT MADE IT LOAD-BEARING. There is no global
       `* { box-sizing: border-box }` in this application - UiButton and UiPaper each declare their own -
       so `height: 100%` here is 100% of the paper's CONTENT box and the 24px of padding is added on top
       of it. While UiPaper had no height that cost nothing: the percentage resolved against an auto
       parent and was dropped. Giving the paper a definite height ACTIVATED it, and a browser found the
       result - the card rendered 253px inside a 231px paper and the Open button hung 11px through the
       card's own bottom border, its rounded corners clipped. */
    box-sizing: border-box;
    height: 100%;
    padding: 20px;
}

/*
    The chip sits on its own line rather than beside the subject: a stage label is a tenant's text of
    no bounded length, and one sharing a row with a subject pushes the subject into a two-character
    column the day somebody names a stage "Awaiting compliance review".
*/
.biztech-case-card-stage[b-4srrdapwrm] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding-block-start: 4px;
}

/* The subject wants a little air above it and the captions under it want none - they are one block of
   secondary text, and spacing them apart made four lines read as four facts rather than one footnote. */
.biztech-case-card-subject[b-4srrdapwrm] {
    padding-block-start: 2px;
}

/*
    Two lines, then an ellipsis. A subject is derived from a template's display name on this surface,
    so it is usually short - but an operator's typed subject reaches the same card, and a work list
    must keep its rows aligned.
*/
.biztech-case-card-subject[b-4srrdapwrm] {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}

/* 🔴 THE PORTAL CARD'S LOOK, AND THE START CARD'S (CaseTemplateCard.razor.css), so the work tabs read as the same
   launcher as the Start tab. It was the seam's full-strength outline, an outlined stage chip, a 14px subject over
   three lines of grey small print, and two small outlined buttons. It is now the quiet edge with corners twice the
   theme's radius, the stage as a tinted pill, a 16px semibold subject, the reference in tabular figures, the two
   facts each beside a glyph. The launcher is the only surface that draws this card. Every colour is a --biztech-* token. */
.biztech-case-card-frame[b-4srrdapwrm]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-case-card-frame:hover[b-4srrdapwrm]  .biztech-paper {
    border-color: var(--biztech-palette-primary-container);
}

/* W19-17 · the card is the link: the text keeps its own ink rather than the link's, carries no underline, and the
   card takes a pale wash of the primary under the pointer, so the whole of it reads as the thing to press. Its focus
   ring is app.css's one :focus-visible rule, which names this class (R3.11). */
.biztech-case-card[b-4srrdapwrm] {
    color: inherit;
    text-decoration: none;
    border-radius: calc(var(--biztech-radius-default) * 2);
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-case-card:hover[b-4srrdapwrm] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 4%, transparent);
}

/* The stage, as a status pill: the primary container's wash with the primary's ink, and no outline. */
.biztech-case-card-stage[b-4srrdapwrm]  .biztech-chip {
    border-color: transparent;
    background: color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
    font-weight: 600;
}

.biztech-case-card[b-4srrdapwrm]  .biztech-case-card-subject {
    font-weight: 600;
    letter-spacing: -0.01em;
}

/* Tabular figures, so a reference like PRESENTA-20261003-EEE30CFD3D2F reads character by character - and no extra
   tracking, which pushed a 30-character reference past a four-across card's width and broke it at a hyphen. */
.biztech-case-card-ref[b-4srrdapwrm] {
    margin-block-start: -4px;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.biztech-case-card-facts[b-4srrdapwrm] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-block-start: 4px;
}

.biztech-case-card-fact[b-4srrdapwrm] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-case-card-fact[b-4srrdapwrm]  .biztech-icon {
    flex: 0 0 auto;
    margin-block-start: 2px;
}
/* /Components/Cases/CaseCoverImage.razor.rz.scp.css */
/*
    W8-24 · a cover picture and its designed absence, in one box.

    🔴 THE ASPECT RATIO IS DECLARED ONCE AND BOTH STATES READ IT. EducationItemFrame's sheet records why:
    the picture and its absence must occupy the same box, or a grid of cards resizes under the reader as
    thumbnails resolve. 16/9 because the subject is a deck's first slide, which is a slide.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit, which is what
    PortalStyleSheetTests' two sweeps require of any scoped sheet.
*/

/*
    Both states, so they cannot disagree about the box. object-fit is R11.7's second requirement: a
    thumbnail is whatever an author uploaded, and cover crops it rather than distorting a slide.

    max-inline-size alongside width, because this box sits inside a grid track that can be narrower than
    the picture at 375px and an image is not otherwise bound by its column.
*/
/* 🔴 W8-25 · 2/1 RATHER THAN 16/9, AND THE CARD IS WHY RATHER THAN THE PICTURE. At 16/9 the cover was
   the tallest thing on a card whose job is to carry four lines of text under it, so a row of four cards
   pushed its Open buttons past the fold. 2/1 keeps a recognisable deck thumbnail - the first slide is
   landscape - and gives the row back about 40px. object-fit: cover means nothing is squashed; it is
   cropped, which is what a thumbnail is for. */
.biztech-case-cover[b-1qc326cahd] {
    aspect-ratio: 2 / 1;
    border-radius: var(--biztech-radius-default);
    display: block;
    max-inline-size: 100%;
    object-fit: cover;
    width: 100%;
}

/*
    The designed absence: a dashed hairline on the paper's own surface, and nothing inside it. No icon
    and no word, because the name and the facts are text directly below - anything drawn here would be a
    third statement of what the card already says.

    OutlineSubtle rather than a fill, and that is EducationItemFrame's measured choice rather than a
    fresh one: the palette's roles carry no neutral fill, and a var() naming one that does not exist
    resolves to no colour at all - so the placeholder would render invisible with every test still
    green, because the colour sweep checks for literals rather than for names that resolve.
*/
.biztech-case-cover-placeholder[b-1qc326cahd] {
    border: 1px dashed var(--biztech-palette-outline-subtle);
}

/* W19-23 · the marked absence: the primary's pale tint with the card's glyph centred, so a form card in a row of deck
   pictures is a picture of its own rather than an empty frame. The glyph keeps R11.3's size. */
.biztech-case-cover-placeholder-marked[b-1qc326cahd] {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}
/* /Components/Cases/CaseFormSection.razor.rz.scp.css */
/* The Form and signatures card. TOKENS ONLY (R3.1). Every class here is on this file's own markup; UiText and UiIcon
   are reached only through wrappers this file renders (I19). Gaps belong to containers (I18). */

.biztech-form-section-head[b-0r1lcntsw6] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-block-end: 16px;
}

/* The theme's overline over each block, in the secondary ink - the blocks' names without adding h3s. */
.biztech-form-section-label[b-0r1lcntsw6] {
    margin-block: 20px 8px;
    color: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-overline-size);
    font-weight: var(--biztech-font-overline-weight);
    line-height: var(--biztech-font-overline-line-height);
    letter-spacing: var(--biztech-font-overline-letter-spacing);
    text-transform: var(--biztech-font-overline-transform);
}

.biztech-form-section-head + .biztech-form-section-label[b-0r1lcntsw6] {
    margin-block-start: 0;
}

.biztech-form-section-row[b-0r1lcntsw6] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-form-section-waiting[b-0r1lcntsw6] {
    margin-block-start: 12px;
}

/* A round tinted mark beside a status line: neutral while nothing has happened, success once it has. */
.biztech-form-section-glyph[b-0r1lcntsw6] {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 12%, transparent);
    color: var(--biztech-palette-text-secondary);
}

.biztech-form-section-glyph-done[b-0r1lcntsw6] {
    background: color-mix(in srgb, var(--biztech-palette-success) 14%, transparent);
    color: var(--biztech-palette-success);
}

.biztech-signature-list[b-0r1lcntsw6] {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-signature-row[b-0r1lcntsw6] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
}

.biztech-signature-row + .biztech-signature-row[b-0r1lcntsw6] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-signature-avatar[b-0r1lcntsw6] {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    inline-size: 36px;
    block-size: 36px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
    font-weight: var(--biztech-font-button-weight);
}

.biztech-signature-body[b-0r1lcntsw6] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-signature-signed[b-0r1lcntsw6] {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-success);
}

/* At phone width the "Signed" mark would squeeze the provenance line; the row's caption already says it. */
@media (max-width: 599.98px) {
    .biztech-signature-signed[b-0r1lcntsw6] {
        display: none;
    }
}

/* Someone still owed a signature: a muted avatar and an amber "Waiting" where a signed row has its green tick. */
.biztech-signature-avatar-waiting[b-0r1lcntsw6] {
    background: color-mix(in srgb, var(--biztech-palette-warning) 16%, transparent);
    color: var(--biztech-palette-warning);
}

.biztech-signature-waiting[b-0r1lcntsw6] {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-warning);
}

@media (max-width: 599.98px) {
    .biztech-signature-waiting[b-0r1lcntsw6] {
        display: none;
    }
}
/* /Components/Cases/CasePageBody.razor.rz.scp.css */
/* 🔴 W4-23. MOVED FROM CaseDetailPanel.razor.css, character for character, when that panel was
   dissolved into this page. The rule and its reasoning are T29 N11's and are reproduced in full
   because the reasoning is the valuable half.

   T29 N11. The milestone control's width, which was two inline Style="min-width: 12rem;" attributes
   on the two mutually-exclusive controls in the panel's header - R5.4 (a raw length is a scale
   multiple or a named constant, and never an inline layout style) and R14.2 (inline Style for layout
   is forbidden), twice, in one file.

   ::deep, and it is required rather than stylistic. Blazor's scoped-CSS attribute is stamped on the
   elements THIS component renders; UiSelect and UiTextField are child components that render their
   own markup, so a bare `.biztech-milestone-control` here would be compiled to
   `.biztech-milestone-control[b-xxxxxxxxxx]` and match nothing. `::deep` compiles to
   `[b-xxxxxxxxxx] .biztech-milestone-control`, which reaches the class the Class= parameter hands
   down - still scoped to this component's subtree, so no other select in the app is touched.

   12rem = 192px, a 4px-scale multiple, so it stays a scale value rather than becoming a registry
   constant. It exists so the two controls do not collapse to their content width in the action row's
   flex row - a "Milestone" select that shrinks to the width of "Saved" reads as a chip. */
[b-nz0tzlm5q1] .biztech-milestone-control {
    min-width: 12rem;
}

/* W18-07 · D3. The Overview's two panels - the lifecycle, then the assistant conversation the case was opened
   from - spaced by their container, not by a margin on either (I18). */
.biztech-case-overview[b-nz0tzlm5q1] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Every panel under the tabs takes the case list's card edge and corners (Inquiries.razor.css), so the case and the
   list it opens from read as one set. They were UiPaper's full Outline edge, visibly heavier than the list's. Reached
   through a wrapper with no box of its own, because the panels are components' elements. What sits inside a panel -
   fields, the progress markers - keeps its own Outline edge: those are boundaries a reader needs to see. */
.biztech-case-section[b-nz0tzlm5q1] {
    display: contents;
}

.biztech-case-section[b-nz0tzlm5q1]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The milestone card: what the case is waiting for on the left, the select and Advance on the right. It takes the
   panels' card edge and corners (.biztech-case-section, above) so the page reads as one set of cards, and wraps the
   controls under the words when the row is too narrow for both. The gap is the container's (I18); the margin under
   it is the biztech-mb-4 utility on the element. */
.biztech-case-advance[b-nz0tzlm5q1] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px 24px;
    box-sizing: border-box;
    padding: 16px 20px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-case-advance__text[b-nz0tzlm5q1] {
    display: flex;
    flex: 1 1 20rem;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-case-advance__controls[b-nz0tzlm5q1] {
    flex-wrap: wrap;
}

/* Advance meets the field's control rather than its label: one label line down, so an error under the field moves
   nothing beside it. Only while the two share a row; wrapped onto its own line on a phone, it needs none. */
.biztech-case-advance__submit[b-nz0tzlm5q1] {
    display: inline-flex;
}

@media (min-width: 600px) {
    .biztech-case-advance__submit[b-nz0tzlm5q1] {
        margin-top: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}
/* /Components/Cases/CaseProgressStrip.razor.rz.scp.css */
/*
    W4-22, W4-24 · F7.2, F7.27. The case's progress as a STEPPER: a named node per stage, joined by a
    rule, a tick on each one the case has passed and a chip on the one it is at.

    🔴 IT REPLACED A ROW OF DOTS AND A LEGEND NOBODY HAD. Five markers of three fills, 8px and 12px,
    with no labels, needed the sentence beside them to decode - and that sentence named only the
    current stage, so the dots either side of it said nothing at all.

    🔴 HOLLOW, NEVER DASHED. A stage the case has not reached is an outlined marker with muted ink.
    The map learnt this the hard way: a dash reads as an unfinished drawing rather than as "not yet".

    Every colour is a --biztech-* token - PortalStyleSheetTests sweeps every scoped sheet for a
    hand-written hex - and there is no @media (prefers-color-scheme) anywhere (I16, R7.3). The two
    modes differ because the tokens do, and for no other reason.
*/
.biztech-progress-strip[b-xwp1cvo6bw] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/*
    🔴 THE <ol> IS THE SEQUENCE. It is a list because the stages are ordered and that order is the fact
    being shown; the browser's block margin and its list marker would both fight the rail, so they come
    off here - the exemption UtilitySpecificityTests carries for this selector, with its reasoning.
*/
.biztech-progress-strip__markers[b-xwp1cvo6bw] {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

/*
    Three cells per node: the state above, the marker on the rail, the name below.

    🔴 `order` HERE IS LOAD-BEARING, NOT COSMETIC. The MARKUP reads marker, name, state - the order a
    screen reader needs, "First thing, Done". The SCREEN needs state, marker, name. CSS order moves the
    boxes and leaves the accessibility tree alone, which is the only way to have both, and it is why
    the reflow below sm costs nothing in the reading.

    The tick sits ABOVE the marker rather than inside it, which is why no On* ink is needed for a glyph
    on a filled dot - and why the same three cells simply re-order on the other axis.

    flex: 1 1 0 with min-inline-size: 0 so nine nodes share the row evenly and a long tenant label wraps
    inside its own node instead of pushing the page sideways, which is R13.8's whole subject.
*/
.biztech-progress-strip__node[b-xwp1cvo6bw] {
    position: relative;
    display: flex;
    flex: 1 1 0;
    min-inline-size: 0;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    text-align: center;
}

.biztech-progress-strip__node > .biztech-progress-strip__state[b-xwp1cvo6bw] {
    order: 1;
}

.biztech-progress-strip__node > .biztech-progress-strip__marker[b-xwp1cvo6bw] {
    order: 2;
}

.biztech-progress-strip__node > .biztech-progress-strip__label[b-xwp1cvo6bw] {
    order: 3;
}

/*
    The connecting rule: a pseudo-element on every node but the first, running back to the one before
    it. A pseudo-element rather than an element, so it is outside the accessibility tree by
    construction rather than by an aria-hidden somebody has to remember to add.

    EMPHASISED into a node the case has reached, MUTED into one it has not - so the sequence reads as a
    sequence rather than as five unrelated marks. A rail drawn in one colour end to end is the "inert"
    version the card warns about: it renders as the row of dots this replaced and looks correct in
    every file sweep.
*/
.biztech-progress-strip__node + .biztech-progress-strip__node[b-xwp1cvo6bw]::before {
    content: "";
    position: absolute;
    inset-inline-end: 50%;
    inline-size: 100%;

    /* R5.6 fixes every rule and border in this application at 1px, and a rail is a rule. */
    block-size: 1px;

    /* 56px = the state cell's 44 + the node's 4px gap + half the marker's 16px border box, so the rail
       meets the marker's middle.

       🔴 THE MARKER DECLARES `box-sizing: border-box` SO THAT 16 IS ITS REAL WIDTH. Without it the 1px
       border sits outside and the marker renders 18px - MudBlazor's global reset left with W0-53, and
       app.css sets box-sizing on two selectors, neither of them this - which put an earlier draft's
       rail 1px above the marker's centre. Half of 18 is also not on the 4px scale (R5.4), so the box
       model and the guardrail wanted the same correction.

       The state cell's height is FIXED rather than minimum for the same reason this number exists: a
       chip is taller than a tick, so a minimum would push the current node's marker down and leave the
       rail pointing at nothing. */
    inset-block-start: 56px;
    background: var(--biztech-palette-outline);
}

/*
    🔴 THE SIBLING COMBINATOR IS REPEATED HERE, AND IT IS LOAD-BEARING. Written first as a bare
    `.node--done::before`, this rule NEVER APPLIED and the rail shipped one colour end to end - the
    "inert" stepper the card warns looks correct in every file sweep. Blazor stamps its scope attribute
    on the last compound selector, so the two rules compiled to:

        .node + .node[b-x]::before   2 classes + 1 attribute = (0,3,1)   <- won everywhere
        .node--done[b-x]::before     1 class   + 1 attribute = (0,2,1)

    Source order never entered into it. Matching the shape makes them tie, and then source order does
    decide. ProgressStripLayoutTests compares the two selectors the way a browser does, because a regex
    that only checks both declarations EXIST was green against the broken sheet.
*/
.biztech-progress-strip__node + .biztech-progress-strip__node--done[b-xwp1cvo6bw]::before,
.biztech-progress-strip__node + .biztech-progress-strip__node--current[b-xwp1cvo6bw]::before {
    background: var(--biztech-palette-success);
}

/*
    The state cell keeps a FIXED height whether or not it holds anything, so every marker sits on one
    line across the row instead of stepping up under the node that carries the chip. That fixed height
    is what the rail's offset is measured from.

    🔴 TWO LINES' WORTH, NOT ONE, AND A BROWSER AT 768 IS WHAT DECIDED IT. At one line the "In progress"
    chip - which is ~88px of nowrap text at caption size - overhung a ~59px node by half its width in
    each direction and sat across its neighbours' cells. Capping it at the node's width lets it wrap
    instead, and the cell has to have room for the second line or the wrap would be clipped.

    44px suits both: a one-line chip is centred in it, a two-line chip fits, and the markers stay on
    one line either way.
*/
.biztech-progress-strip__state[b-xwp1cvo6bw] {
    display: flex;
    align-items: center;
    justify-content: center;
    block-size: 44px;
    max-inline-size: 100%;
}

/*
    The chip may not be wider than the node it belongs to. Without this it is sized by its own text and
    overhangs into the columns either side, which is what 768 showed.

    🔴 W0-75 · AND IT SAID `> *`, WHICH HAD NEVER APPLIED. Blazor stamps the scope attribute on a
    selector's LAST compound, so this compiled to `> *[b-xxxxxxxxxx]` - and the only two things this span
    ever holds are UiIcon's <svg> and UiChip's <span>, both rendered by a child component and neither
    carrying this component's scope. The overhang 768 showed has been back ever since.

    ::deep and the chip by name, rather than `::deep *`: the chip is what is sized by its own text, an
    icon is a fixed 1em box, and a cap applied to every descendant of the state span would be a rule
    about elements this file cannot see. ScopedStyleReachTests refuses a universal last compound now, so
    the shape cannot return in silence.
*/
.biztech-progress-strip__state[b-xwp1cvo6bw]  .biztech-chip {
    max-inline-size: 100%;
}

.biztech-progress-strip__node--done .biztech-progress-strip__state[b-xwp1cvo6bw] {
    color: var(--biztech-palette-success);
}

/*
    🔴 --biztech-palette-outline, NOT --outline-subtle. The map's --ahead node is being changed to this
    same token by this card and for the same reason: subtle measures 1.25:1 against the paper behind it
    and the shape is simply not there. Outline measures 3.33:1 light and 3.51:1 dark, which clears
    R3.6's 3:1 for a non-text boundary.
*/
.biztech-progress-strip__marker[b-xwp1cvo6bw] {
    position: relative;
    z-index: 1;

    /* So 16 is the marker's REAL size and half of it is a scale step. Nothing else on this page sets
       box-sizing: the global reset went with MudBlazor in W0-53. */
    box-sizing: border-box;
    inline-size: 16px;
    block-size: 16px;
    border-radius: 999px;
    border: 1px solid var(--biztech-palette-outline);
    background: var(--biztech-palette-surface);
}

.biztech-progress-strip__node--done .biztech-progress-strip__marker[b-xwp1cvo6bw] {
    border-color: var(--biztech-palette-success);
    background: var(--biztech-palette-success);
}

/* Where the case is now: the primary colour, so the eye lands on it first. */
.biztech-progress-strip__node--current .biztech-progress-strip__marker[b-xwp1cvo6bw] {
    border-color: var(--biztech-palette-primary);
    background: var(--biztech-palette-primary);
}

/*
    A layout class on a span THIS component renders. UiText renders its own markup, so a class handed to
    it would compile to a selector matching nothing - the ::deep trap CasePage.razor.css records in
    full. Colour is INHERITED across that boundary, which is why muting works from out here.
*/
.biztech-progress-strip__label[b-xwp1cvo6bw] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

.biztech-progress-strip__node--ahead .biztech-progress-strip__label[b-xwp1cvo6bw] {
    color: var(--biztech-palette-text-secondary);
}

/*
    The state as text for a reader who cannot see the tick, hidden by CLIPPING rather than display:none
    or visibility:hidden - the idiom .biztech-skip-link and .biztech-lifecycle-route both use, and for
    the same reason: removed is not the same as hidden. app.css publishes no shared utility for it
    (TenantChrome's header says so and DeckViewer.razor.css carries its own copy), so this sheet carries
    one too.
*/
.biztech-progress-strip__reading[b-xwp1cvo6bw] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/*
    🔴 375 IS THE HARD PART AND IT IS THE POINT. Nine named nodes do not fit across a phone, so below sm
    the stepper turns vertical: nodes stacked, the rule running down the left, names to the right of
    each. R13.3 - every desktop-only rule must be reversed there - and it is the same information in
    the axis that has room, which is why the answer is not a smaller font.
*/
@media (max-width: 599.98px) {
    .biztech-progress-strip__markers[b-xwp1cvo6bw] {
        flex-direction: column;
        align-items: stretch;
    }

    .biztech-progress-strip__node[b-xwp1cvo6bw] {
        flex: 0 0 auto;
        flex-direction: row;
        align-items: center;
        gap: 8px;
        min-block-size: 40px;
        text-align: start;
    }

    /* The rail turns with the nodes: down the left edge, meeting each marker's middle.

       8px: half the marker's 16px border box, which it declares box-sizing: border-box to make real.

       🔴 A KNOWN LIMIT, WRITTEN DOWN RATHER THAN HALF-FIXED. `inset-block-end: 50%` measures from THIS
       node's centre and `block-size: 100%` spans this node's height, so the rail arrives exactly at the
       previous marker only while the two nodes are the SAME height. min-block-size holds that for a
       single-line label; a tenant label long enough to wrap at 375 makes its node taller and leaves a
       short gap in the rail above it.

       A fixed overshoot cannot fix it in both directions - too little still leaves the gap, too much
       paints a stub above the previous marker - and the exact fix needs two segments per node, where
       the lower half would have to be coloured by the NEXT node's state, which CSS here cannot reach.
       Left as it is deliberately: the failure is a small gap in one rail on a phone, and the cure is
       worse than the symptom. */
    .biztech-progress-strip__node + .biztech-progress-strip__node[b-xwp1cvo6bw]::before {
        inset-block-start: auto;
        inset-block-end: 50%;
        inset-inline-start: 8px;
        inset-inline-end: auto;
        inline-size: 1px;
        block-size: 100%;
    }

    /* 🔴 THE SAME SELECTOR SHAPE AS THE DEFAULTS ABOVE, and that is required rather than tidy. Those
       order rules use the child combinator, so they score (0,2,0); a bare class here would score
       (0,1,0) and LOSE - a media query does not raise specificity - leaving the vertical stepper laid
       out in the horizontal order, with no warning and a green suite. */
    .biztech-progress-strip__node > .biztech-progress-strip__marker[b-xwp1cvo6bw] {
        order: 1;
    }

    .biztech-progress-strip__node > .biztech-progress-strip__label[b-xwp1cvo6bw] {
        order: 2;
        flex: 1 1 auto;
    }

    .biztech-progress-strip__node > .biztech-progress-strip__state[b-xwp1cvo6bw] {
        order: 3;
        min-block-size: 0;
    }
}
/* /Components/Cases/CaseTemplateCard.razor.rz.scp.css */
/*
    W8-24 · one template card on the launcher's Start tab.

    I17 · the padding is here because UiPaper has none of its own, and a panel that declares none draws
    its heading flush against its border.

    I18 · the spacing between the cover, the title, the facts and the action is the container's `gap`
    and never a margin per child - the two would add up, and a 16px gap plus a per-child margin is a
    card that looks misaligned for a reason nobody can see in the markup.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit
    (PortalStyleSheetTests' two sweeps).
*/

/*
    height: 100% so a row of cards is one height whatever their names wrap to, and the action below
    lines up across the row. The grid track supplies the width; nothing here sets one (R8.7).
*/
/*
    ❗ box-sizing, WITHOUT WHICH THE LINE ABOVE IS A TRAP. There is no global
    `* { box-sizing: border-box }` here, so `height: 100%` is 100% of the PARENT'S CONTENT BOX and the
    padding below is added to it. It costs nothing while the parent has no height of its own - the
    percentage is dropped - and it breaks the moment one is given. CaseCard is where that happened:
    W8-25 gave its UiPaper a definite height so a row of Open buttons would line up, which activated an
    inert `height: 100%` and pushed a 253px card through a 231px paper, clipping the button's corners on
    the card's own border. This box is currently in the harmless state; the declaration is what keeps it
    there. PortalStyleSheetTests.No_percentage_height_is_paired_with_padding_outside_a_border_box sweeps
    for the pair.
*/
/* The theme's case launcher alignment (ThemePortalLook): the card's content stretched to the start, or centred. */
.biztech-case-template-card[b-33rjq6mh8b] {
    display: flex;
    flex-direction: column;
    align-items: var(--biztech-portal-case-align, stretch);
    text-align: var(--biztech-portal-case-text-align, start);
    gap: 12px;
    box-sizing: border-box;
    height: 100%;
    padding: 20px;
}

/* 🔴 THE PORTAL CARD'S LOOK (PortalCard.razor.css), stacked for a narrow grid cell, so the launcher a tile opens
   reads as the same portal. It was the seam's full-strength outline, a 20px headline title, a row of grey chips and a
   small filled button pinned to the bottom-left corner. It is now the quiet edge with corners twice the theme's
   radius, a tinted glyph above a 16px semibold title, the facts as one quiet line, and the action across the foot.
   The frame fills its grid cell so every card in a row is one height, and the paper fills the frame. Every colour is
   a --biztech-* token. */
.biztech-case-template-frame[b-33rjq6mh8b] {
    display: flex;
    flex-direction: column;
    block-size: 100%;
}

/* The card follows the portal's Items settings - its edge, its edge under the pointer and its icon box - so a case
   card and a launcher tile read as one portal. */
.biztech-case-template-frame[b-33rjq6mh8b]  .biztech-paper {
    flex: 1 1 auto;
    border-color: var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The card answers the pointer by its edge - a transient response, never a shadow on an in-flow surface (D-E). */
.biztech-case-template-frame:hover[b-33rjq6mh8b]  .biztech-paper {
    border-color: var(--biztech-portal-card-hover-edge, var(--biztech-palette-primary-container));
}

.biztech-case-template-glyph[b-33rjq6mh8b] {
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: 44px;
    block-size: 44px;
    border-radius: var(--biztech-portal-icon-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-icon-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));
}

/* Two lines at most, so a long template name cannot push its card taller than its row. ::deep, because the class is
   on UiText's element, which is the seam's markup (I19) - the clamp written here without it never applied. */
.biztech-case-template-card[b-33rjq6mh8b]  .biztech-case-template-title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    font-weight: 600;
    letter-spacing: -0.01em;
}

/* What the template involves, as one line: a small glyph beside each word, the words a step back in ink. */
/* Shown unless the theme's case launcher hides what a case holds. */
.biztech-case-template-facts[b-33rjq6mh8b] {
    display: var(--biztech-portal-case-details, flex);
    justify-content: var(--biztech-portal-case-justify, flex-start);
    flex-wrap: wrap;
    gap: 4px 16px;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-case-template-fact[b-33rjq6mh8b] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

/* The action at the card's foot, pushed to the bottom so the actions of a row line up: a compact tonal pill - the
   primary colour's ink on a wash of its container - with its chevron after the word. Lighter than a filled button
   and still plainly the one thing to press; no rule above it, because the space the auto margin opens already
   separates it from the facts. */
/* W31-04 · D12. The Start ink is set here, on this file's own element, and the button inherits it (Color="Inherit"). It was
   set on the button through ::deep, where UiButton's own colour rule tied it on specificity and won by coming later. */
.biztech-case-template-action[b-33rjq6mh8b] {
    margin-block-start: auto;
    padding-block-start: 8px;
    color: var(--biztech-portal-start-ink, var(--biztech-palette-primary));
}

.biztech-case-template-action[b-33rjq6mh8b]  .biztech-button {
    gap: 4px;
    padding: 4px 12px 4px 16px;
    border: none;
    border-radius: var(--biztech-radius-pill);

    /* The theme's Start button (ThemePortalLook): this tonal pill, filled, outlined - an inset ring, so the button is
       the same size whichever it is - or a link. */
    background: var(--biztech-portal-start-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-start-ring, transparent);
    font-weight: 600;
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-case-template-action[b-33rjq6mh8b]  .biztech-button:hover:not(:disabled) {
    background: var(--biztech-portal-start-hover, var(--biztech-palette-primary-container));
}
/* /Components/Cases/CaseWorkList.razor.rz.scp.css */
/*
    W8-24 · the shared case list — the filter toolbar, its narrow-width alternates, the applied-filter
    chips and the sortable column headings.

    🔴 THIS SHEET MOVED OUT OF Inquiries.razor.css WITH THE MARKUP IT STYLES, AND I19 IS WHY RATHER
    THAN TIDINESS. Blazor stamps a component's scope attribute onto the elements in THAT component's
    own markup, so a rule left beside the page would compile to `.biztech-filter-search[b-pagescope]`
    and match nothing at all - not "match less", nothing - with every test still green and the search
    box simply unstyled. ScopedStyleReachTests caught all five on the first run.

    What stayed on the page: the Active/Archived switch, whose markup is in the tab strip's slot and
    did not move.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit, which is
    what PortalStyleSheetTests' two sweeps require of any scoped sheet.
*/

/* W4-26 · /inquiries' own rules. Design §7's `.mk-seg` and `.mk-filters`, and §8's phone.

   🔴 EVERY SELECTOR HERE MATCHES AN ELEMENT THIS PAGE RENDERS ITSELF, so there is no ::deep in this
   file and none is needed. Blazor stamps a scoped sheet's attribute only on elements the component
   renders, and each of these is a plain <span> or <div> written in Inquiries.razor - never a Ui*
   component's own box. UiTab.razor's header records what happens when that distinction is missed: a
   rule compiled against a component's element matches NOTHING, not "matches less".

   🔴 AND THAT IS WHY THE VIEW SWITCH'S RULE IS HERE RATHER THAN IN CaseWorkListStrip.razor.css.
   The switch is passed THROUGH that component into UiTabs.Trailing, so the natural place to look for
   its styling is the component it passes through - but a RenderFragment written in THIS file compiles
   into THIS file's render tree, so the span carries INQUIRIES' scope attribute and only a rule here
   can reach it. CaseWorkListStrip deliberately has no sheet at all.

   🔴 NOTHING HERE ZEROES A MARGIN OR A PADDING (R14.1a) and nothing declares a block-axis size. The
   controls take their box from --biztech-control-height, which MainLayout.razor.css narrows to 32px
   for the console; a declaration here would fork that decision, and the fork would look right on the
   operator console and wrong on /i/{key} - the surface nobody opens while building a console page. */

/* 🔴 IT FRAMES THE TWO SEGMENTS AND RESTYLES NEITHER. Reaching into UiButton's own anchor would mean
   ::deep at the same specificity as UiButton's own declarations, decided by nothing more principled
   than filename order in the generated bundle - the hazard UiToolbar.razor.css's separator note
   records in full. The specimen's joined look is worth a border and a 2px gap; it is not worth
   forking a seam control's box. */
/* 🔴 W4-26 · THE TOOLBAR'S LABELS ARE CLIPPED, NOT DELETED, AND THIS IS THE RULE THE ≤48px CLAUSE
   RESTS ON. Read this before "tidying" it away.

   THE ARITHMETIC. `.biztech-field` stacks a label above its box with a 4px gap, and the caption slot is
   12px at line-height 1.66 - 19.92px. So a labelled control in this row costs 24px MORE than its own
   box, and the card's clause is that the filter row measures 48px or less at 1264 wide. Design
   specimen 11 is drawn with no labels at all: `.mk-input` shows placeholder text inside the box and
   `.mk-select` reads "Stage: Signed". The card says twice that where prose and specimen disagree the
   SPECIMEN WINS, and this is the disagreement that clause depends on.

   🔴 CLIPPED RATHER THAN display:none, AND THE DIFFERENCE IS THE WHOLE POINT. The label keeps its
   `for` association, stays in the DOM and stays in the ACCESSIBILITY TREE, so every control in this row
   still has exactly the accessible name it had before - which `display: none` or `visibility: hidden`
   would take away, leaving three unnamed controls and an R12.4 failure that no test in this repository
   would see. This is app.css's own `.biztech-skip-link` idiom, and its note carries the reasoning:
   "present, focusable, and occupying no space".

   🔴 ::deep, AND ITS ROOT HAS TO BE ONE OF *THIS FILE'S* ELEMENTS - WHICH THE FIRST VERSION GOT
   WRONG AND A BROWSER PRICED AT 73.90625px. It was written
   `[data-case-filters] .biztech-toolbar ::deep .biztech-field-label`, which Blazor rewrites to
   `... .biztech-toolbar[b-xxxxxxxxxx] ...` - and `.biztech-toolbar` is rendered by UiToolbar, not by
   this page, so the scope attribute is never on it and the rule matched NOTHING. Not "matched less":
   nothing, which is exactly what UiTab.razor's header warns about and what MainNavMenu.razor.css
   records finding on screen rather than in a test.

   The two spans below ARE this file's, so the rewrite lands. They are also the only two labelled
   controls in the row, which is why this is two selectors rather than one on their container: the
   PANEL's fields keep their visible labels, and that is right - a panel that unfolds has room, and
   four unlabelled controls in a column would be four mysteries.

   R14.1a has no subject here: what that rule forbids is ZEROING a box-model property the utility layer
   owns - a margin or a padding - and nothing in app.css sets a label's size or its clip. */
.biztech-filter-search[b-jzbftvpy2s]  .biztech-field-label,
.biztech-filter-stage-wide[b-jzbftvpy2s]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* And with the labels out of flow every child of the row is its own single box, so UiToolbar's
   `align-items: center` centres like against like. That is what closes W0-63 finding 3 / W0-65
   finding 4 here - "a field stacks a caption-scale label above its box and a button does not, so
   `align-items: center` centres two different boxes and nothing lines up" - by removing the stack
   rather than by re-aligning the row. PortalPageShellTests' own theory is the guard, and this page's
   row is why its Inquiries entry moved. */

/* The search box: 28rem at most, the width every console list's search box has (app.css's filter bar), so it
   does not swallow a wide row and leave Stage and More adrift at the far edge. An inline size is not a
   spacing utility, so it lives here rather than in a Class (R8.7).

   `min-inline-size: 0` is what lets it shrink below its content, which is the same declaration
   UiToolbar makes on the row for the same reason: without it the box grows, the row grows, and
   `.biztech-main`'s `overflow-x: hidden` clips the result rather than scrolling it (R13.8). */
.biztech-filter-search[b-jzbftvpy2s] {
    flex: 0 1 28rem;
    min-inline-size: 0;
}

/* 🔴 D1 · THE TWO STAGE COPIES AND THE TWO MORE LABELS, AND EXACTLY ONE OF EACH IS DISPLAYED AT ANY
   WIDTH.

   `display: none` rather than `visibility: hidden` or a class swap, because it removes the other copy
   from the ACCESSIBILITY TREE as well as from the screen - which is what makes rendering a control
   twice honest rather than a duplicate announcement. UiToolbar.razor.css does the same thing at the
   same breakpoint and app.css's breadcrumb block states the identical reason: "a hidden ancestor is
   correctly absent from the accessibility tree rather than announced and invisible."

   The narrow pair is off by default and switched on below `sm`, so the desktop layout is the one with
   no media query behind it. 599.98px is how R13.1 says this application writes MudBlazor's `sm`. */
.biztech-filter-stage-narrow[b-jzbftvpy2s] {
    display: none;
}

/* W4-26 · the applied-filter chips. Design §7's `.mk-chips`.

   Wrapping, so a row of five chips is never clipped by `.biztech-main`'s `overflow-x: hidden` at any
   width (R13.8). `align-items: center` puts the count caption on the chips' own centre line rather
   than on their baseline, which a chip's padding would otherwise push out of true. */
.biztech-filter-chips[b-jzbftvpy2s] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* 🔴 THE COUNT LINE SITS AFTER THE CHIPS WITH AIR, AND `margin-inline-start: auto` IS WHAT IT
   SAID FIRST. That version pushed it to the row's end edge and was reported back the same day:
   "this text seems like so far away from chips". It is, and the reasoning behind it was wrong.

   The complaint it was answering was that at the row's own 8px the line read as a chip that had
   lost its pill - but what actually caused that was the CHIPS, which were 36px boxes around 12px
   of text with a 32px button in them. Once they became real pills with a full-ink value, a bare
   caption beside them was already unmistakably a different kind of thing, and the distance was
   solving a problem that had gone.

   Flush-right earns its distance when something else holds that edge for the eye to follow down.
   On one line with three chips it is ~900px of nothing between a summary and the things it
   summarises, and the reader has to cross the row to learn that 1 filter left 0 of 1 cases.

   16px total - the row's 8px gap and 8px more - which is the step this sheet uses everywhere else
   to say "related, not the same". */
[data-filter-count][b-jzbftvpy2s] {
    margin-inline-start: 8px;
}

/* The field name is the question and the value is the answer, so the answer is the one in full ink.

   BOTH HALVES NAME THEIR OWN INK, and the second rule is not the redundancy it looks like:
   `.biztech-chip` paints the default role secondary and the name would inherit that, but then this
   pairing would hold only while UiChip's default stays what it is today - a chip rendered in any
   other colour would give the QUESTION that colour and the answer plain text. Saying it here makes
   the contrast between the two a property of the chip rather than of the seam's current palette.
   UtilityClassTests refuses the alternative anyway: a class with no rule renders nothing. */
.biztech-filter-chip-field[b-jzbftvpy2s] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-filter-chip-value[b-jzbftvpy2s] {
    color: var(--biztech-palette-text-primary);
}

/* 🔴 THE CHIP'S DISMISS CONTROL. See the razor for why this page renders its own rather than
   shrinking the seam's: the smallest icon button is a 32px square, which is taller than the chip it
   would sit in, and narrowing it from here would outrank the utility layer on every caller.

   16px, which is the glyph and nothing else: the chip is as tall as its own label again. R5.8's 44px
   minimum is not in play - this is not a control standing on its own, it is the end of a pill whose
   whole row is 20px tall, and the filter it clears can also be cleared from the panel that set it.

   🔴 THE PADDING IS A REAL 2px AND NOT A `padding: 0`, AND THAT DISTINCTION IS THE WHOLE POINT.
   A <button> with nothing said carries the user agent's own `1px 6px`, which measured this control
   at 28x18 around a 16px glyph - wider than it is tall, off-centre in a pill. The reflex is to
   zero it, and UtilitySpecificityTests refuses exactly that: a scoped zero outranks every
   biztech-pa-* at (0,2,0) against (0,1,0). SessionChat's own `.biztech-session-chat__new` is the
   in-repo precedent and does the same thing - a page-owned button states the padding it wants.
   2px makes the target 20px around a 16px mark rather than the mark alone. */
.biztech-filter-chip-clear[b-jzbftvpy2s] {
    display: flex;
    align-items: center;
    justify-content: center;

    box-sizing: border-box;
    padding: 2px;
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--biztech-palette-text-secondary);
    cursor: pointer;
}

/* The glyph is the control's whole box. UiIcon's small is 20px and this row is 16px of caption, so
   the mark is sized here rather than left to tower over the words it belongs to. */
.biztech-filter-chip-clear[b-jzbftvpy2s]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
}

/* Secondary until it is pointed at: a chip's job is to say what is filtered, and the way OFF it
   should not compete with the words for the reader's eye. */
.biztech-filter-chip-clear:hover:not(:disabled)[b-jzbftvpy2s] {
    color: var(--biztech-palette-text-primary);
}

.biztech-filter-chip-clear:disabled[b-jzbftvpy2s] {
    color: var(--biztech-palette-text-disabled);
    cursor: default;
}

/* The label and the mark, 4px apart, inside the pill the seam draws. */
[data-filter-chip][b-jzbftvpy2s]  .biztech-chip {
    gap: 4px;
}


/* 🔴 W4-26 · THE SORT DIRECTION, AS ONE GLYPH ROTATED. Design §9: "One glyph, rotated by CSS for the
   other direction. That is one meaning with two orientations, not two meanings" - which is why UiIcons
   holds ArrowUpward and deliberately no ArrowDownward.

   The <span> is rendered by Inquiries.razor, so this sheet's scope attribute lands on it and no ::deep
   is needed - and rotating the span rather than the <svg> is what keeps this rule off UiIcon's own box,
   where it would have needed ::deep and would have applied to every icon on the page. */
.biztech-sort-glyph[b-jzbftvpy2s] {
    display: inline-flex;
    align-items: center;
    margin-inline-start: 4px;

    /* 🔴 THE ARROW SAT 4.5px ABOVE THE WORD, AND THE CAUSE IS THE ONE INLINE-LAYOUT RULE THAT
       CATCHES EVERYBODY. The sort arrows sat out of line with their own headings.

       This span lives inside `.biztech-button-label`, which is an INLINE context, so the span is
       placed on the text's BASELINE. An inline-flex box takes the baseline of its first flex item,
       and an <svg> has no text baseline at all - so the browser uses its bottom margin edge. The
       whole 20px arrow therefore stood ON the baseline with nothing below it, which is exactly the
       height of a descender above where the eye expects it. `align-items: center` above does not
       help: it centres the svg INSIDE this span, and this span is what is in the wrong place.

       Measured on the running build against the word's own box: baseline -4.5px, `middle` +1.8px,
       `text-bottom` +0.5px.

       🔴 A KEYWORD RATHER THAN THE -0.2em THAT MEASURED 0.3px. That number is better by two
       tenths of a pixel and worse in every other way: it is a constant nobody can derive, it is
       tied to the font this application happens to ship, and PortalStyleSheetTests refuses a raw
       length off the 4px scale unless it is load-bearing at that exact value - which this would
       not be. `text-bottom` is read from the font's own metrics, so it stays right if the face
       changes.

       🔴 AND THE STRUCTURAL FIX WAS WEIGHED AND REFUSED. A glyph rendered as a flex SIBLING of
       the label - which UiButton's new EndIcon does - needs no alignment at all, because the
       button's own `align-items: center` handles it. It cannot be used here: the descending state
       is a ROTATION, and EndIcon draws a bare UiIcon with no element of this page's to hang a
       state class on. Design §9 keeps one glyph rotated rather than two glyphs, so the wrapper
       has to stay. */
    vertical-align: text-bottom;
}

/* 🔴 16px, NOT UiIcon's 20. A heading is 14px of body2 and the arrow is a MARK BESIDE A WORD,
   not a control - at the seam's small size it outweighed the column name it qualifies, which is
   the same thing the chip's cross was doing inside its pill. The span is this page's own markup
   and the svg is UiIcon's, so the reach is one level and no further. */
.biztech-sort-glyph[b-jzbftvpy2s]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
}

.biztech-sort-descending[b-jzbftvpy2s] {
    transform: rotate(180deg);
}

/* 🔴 W16-17 · FINDING 4. A SORTABLE COLUMN LOOKS DIFFERENT FROM ONE THAT IS NOT.

   Two of this table's six columns sort; the other four were plain text with no control and nothing
   saying why - and `aria-sort` could not tell them apart either, because UiTh emits it only for the
   CURRENT sort. So a screen reader had one channel (a <button> versus a text node) and an eye had none.

   Every sortable heading now draws the glyph; this is the one that is not the current sort. R12.7 is
   satisfied by the glyph's PRESENCE, which reads with no colour perception at all - the opacity is what
   stops an idle arrow claiming an order the list is not in, not what carries the meaning.

   .38 is the Material disabled-content alpha the palette's own secondary ink already sits against, and
   it is applied to the glyph rather than to the heading: the WORD stays at full contrast, because the
   column's name is not the thing being de-emphasised. */
.biztech-sort-glyph-idle[b-jzbftvpy2s] {
    opacity: .38;
}

/* 🔴 THE CURRENT SORT IS THE ONLY COLOURED MARK IN THE HEADER, AND OPACITY ALONE WAS NOT
   ENOUGH TO SAY SO. Once the arrows were aligned there was no telling which one is
   active. at first glance it look like both active".

   🔴 AND THE CAUSE IS NOT CONTRAST, WHICH IS WHY MAKING THE IDLE ONE FAINTER WOULD NOT HAVE
   FIXED IT. Measured against the surface: the current mark reads 13.61:1 on dark and 16.41:1 on
   light, the idle one 3.16:1 and 2.33:1 - already a four to sevenfold difference. What defeats it
   is SHAPE: a faint arrow still POINTS A DIRECTION, so a reader scanning six headings sees two
   arrows making two claims and has to compare their weights to learn that one of them is not a
   claim at all. Weight is a judgement; hue is not.

   🔴 A DIFFERENT SHAPE FOR THE IDLE MARK IS THE BETTER ANSWER AND IT IS BLOCKED, SO THIS IS
   RECORDED RATHER THAN QUIETLY SETTLED FOR. The conventional unsorted mark is a vertical double
   arrow, which this application has no glyph for - and UiIconTests compares every constant
   character-for-character against material-icon-reference.json, a fixture GENERATED from the
   MudBlazor package that W13-11 removed. Writing the reference entry by hand would be authoring
   the answer to the test that checks it, which that fixture's own header refuses in as many
   words. Rotating SwapHoriz 90deg draws exactly the right mark and is refused for a different
   reason: R11.4 gives it "trade the stage and the rail", and one glyph may not carry two
   meanings. If a glyph can be minted, this rule should give way to it.

   🔴 NOT COLOUR ALONE, WHICH WCAG 1.4.1 WOULD REFUSE. The opacity above still separates the
   two, aria-sort on the <th> is the announced channel, and the ROTATION carries which direction
   - so a reader who perceives no hue at all loses nothing that was there before this rule.
   Primary is what this console already means by "this one is current": the nav's active item and
   the view switch's open segment both say it that way. */
.biztech-sort-glyph:not(.biztech-sort-glyph-idle)[b-jzbftvpy2s] {
    color: var(--biztech-palette-primary);
}

/* 🔴 W16-17 · FINDING 5 · WCAG 2.2 TARGET SIZE ON THE LINK A CASEWORKER PRESSES MOST.

   `.biztech-link` is app.css's inline anchor, so every case reference measured 246x18 - one line of
   body2 - under the 24x24 minimum, on the primary action of this list. Measured across 21 viewport
   widths on 2026-09-18.

   🔴 SCOPED TO THIS COMPONENT'S OWN ANCHOR, NOT TO `.biztech-link`. That class is on text links across
   the whole console and resizing all of them is a change no card has measured. This file renders the
   anchor itself, so Blazor stamps its scope attribute on it and no `::deep` is needed (I19).

   The inline size is deliberately not set: a reference is far wider than 24px and it is the CROSS axis
   that was under. `inline-flex` so the box can take a height at all - an inline anchor's cannot - and
   `align-items: center` so the text sits on the row's own line rather than at the top of a taller box. */
.biztech-link[data-case-link][b-jzbftvpy2s] {
    display: inline-flex;
    align-items: center;
    min-block-size: 24px;
}

/* The disclosure panel. In flow, below the toolbar - R9.6 names an inline panel as right for a filter
   and forbids a drawer - and wrapping, so five controls are never clipped at any width from 375px up
   (R13.8).

   `align-items: end` puts a date field's box on the same baseline as a select's despite their labels
   being different heights; without it the row reads as three controls at three heights. */
/* 🔴 THE ANCHOR. The toolbar and the panel share this box, so the panel can hang off its bottom
   edge without a wrapper of its own. `biztech-mb-3` came off it and onto nothing: the margin is the
   toolbar's now, because the panel no longer takes part in the flow that margin was spacing. */
.biztech-filters[b-jzbftvpy2s] {
    position: relative;
    margin-block-end: 12px;
}

/* 🔴 OVER THE LIST, NOT ABOVE IT - see the razor for the report and for why this is not a modal.

   `inset-inline: 0` rather than a width: the panel is as wide as the filter row it belongs to, at
   every breakpoint, with no number to keep in step.

   The shadow is R6.5's licence read literally - "anything that floats OVER content it does not push
   aside" - which became true of this panel on the day it stopped pushing. The border stays with it:
   R6.6 is that on dark a border does the work a shadow does on light, and this panel renders on
   both. */
/* 🔴 THE TRIGGER GOES TO THE END OF THE ROW, WHICH IS WHERE ITS PANEL HANGS FROM.

   `margin-inline-start: auto` rather than a second flex container: the toolbar is one row, and one
   auto margin is what pushes a single child to its far end without giving the row a structure it
   does not otherwise need. The search box and the stage filter keep the start, which is the order
   they are read in. */
[data-filter-more][b-jzbftvpy2s] {
    margin-inline-start: auto;

    /* The dot hangs off this, which is why the wrapper - and not the button - is the positioned
       ancestor. UiButton is the seam's and gets no page rule. */
    position: relative;
}

/* 🔴 A FILTER IS ON, SAID ON THE CONTROL THAT HIDES IT. The panel folds four filters away, and
   a closed disclosure looks identical whether or not anything behind it is set.

   8px, and no number in it: the razor records why a count here would be the third place on one
   screen reporting the same figure.

   🔴 THE RING IS NOT DECORATION - IT IS WHAT MAKES THE MARK LEGIBLE AGAINST THE CONTROL IT SITS
   ON. The dot straddles the button's own 1px border, so without a ring it reads as a bite out of
   the corner rather than as a mark on top of it. `surface` because UiToolbar declares that ground
   and this sits inside one.

   🔴 A REAL BORDER, AND IT WAS A box-shadow UNTIL InFlowElevationTests REFUSED IT. The shadow
   spelling is the shorter one - `0 0 0 2px` costs no layout - but ADR 0026 D-E keeps shadows for
   things that FLOAT over content, and this mark sits on a control and floats over nothing. The
   guard read it as depth because that is what a shadow means in this application, and the honest
   fix is the property that says what this is: 12px of box with a 2px border leaves the same 8px
   of colour, so nothing about the rendering changed - only the claim.

   1.4.11 wants 3:1 for a non-text indicator against what adjoins it, which here is the ring and the
   surface behind it. MEASURED on the running build rather than assumed: primary on surface is
   5.41:1 on dark (#5B9BD5 on #1B222B) and 8.86:1 on light (#0F4C81 on #FFFFFF). Both roles, so a
   tenant that overrides either gets a pair PaletteContrast already gates. */
.biztech-filter-more-dot[b-jzbftvpy2s] {
    position: absolute;
    inset-block-start: -4px;
    inset-inline-end: -4px;

    box-sizing: border-box;
    inline-size: 12px;
    block-size: 12px;
    border: 2px solid var(--biztech-palette-surface);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);

    /* It is aria-hidden and it must also be untouchable: a 12px circle over the corner of a
       control is a place a pointer will land, and a click landing on the mark instead of the
       button would be a disclosure that sometimes does not open. */
    pointer-events: none;
}

/* The dot's meaning, for a reader who gets no dot. Clipped rather than display:none, which would
   take it out of the accessibility tree along with the screen - the skip link's own idiom, and
   the reason app.css states it there at length. */
.biztech-filter-more-applied[b-jzbftvpy2s] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-filters-panel[b-jzbftvpy2s] {
    position: absolute;

    /* 🔴 ANCHORED TO THE TRIGGER'S END, NOT SPANNING THE ROW, AND THE CHIPS ARE WHY. A
       full-width panel opened straight over the applied-filter chips - "it open up above the applied
       filter chips" - which is the one row that says what is already on. The chips read from the
       start of the line and this hangs from the end, so they no longer meet.

       360px rather than the row's width: four stacked fields need about that, and a panel as wide
       as the table was covering three times what it needed to. `min()` keeps it inside a narrow
       viewport, where it becomes the full width and the block below stacks it anyway. */
    inset-inline: auto 0;
    inline-size: min(360px, 100%);
    inset-block-start: 100%;
    z-index: var(--biztech-layer-affordance);

    display: flex;
    flex-direction: column;
    align-items: stretch;

    /* 🔴 16px BETWEEN FIELDS, AND THE NUMBER IS DECIDED BY THE ONE INSIDE THEM.

       `.biztech-field` sets `gap: 4px` between a label and the control it names. This gap was 8,
       so "these two are one field" and "these two are different fields" were 4px apart - and a
       reader seeing a 2x difference at a glance does not see it at all - the panel
       looking odd, guessed as the padding; the padding was not it. Eight stacked items read as
       eight stacked items rather than as four labelled pairs.

       16 makes the separation 4x the binding, which is the ratio that does not need a second
       look. It is also the step the rest of the console stacks blocks at, and what
       MediaDeviceDialog settled on for the same job in a floating panel. */
    gap: 16px;
    margin-block-start: 8px;

    /* 16 rather than 12 for the same reason a dialog uses it: the panel's own edge should not be
       tighter than the space between the things inside it, or the first field looks pushed against
       the border while the rest breathe. */
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-overlay);
}

/* A click anywhere else closes the panel. UiMenu's scrim verbatim, including the transparency: it
   exists to catch a click, not to dim a page - the list behind it is what the reader is filtering
   and dimming it would be a modal by another name. Below the panel and above everything else. */
.biztech-filters-scrim[b-jzbftvpy2s] {
    position: fixed;
    inset: 0;
    z-index: var(--biztech-layer-scrim);
}

/* 🔴 AND THE COLLAPSED PANEL HAS TO BE TOLD TO GO, WHICH A BROWSER PRICED AT 73.90625px OF DEAD
   SPACE ABOVE THE TABLE.

   `hidden` is an attribute, and its effect is a USER-AGENT rule - `[hidden] { display: none }` - which
   any author `display` declaration outranks. So the rule above switched the panel back on while the
   attribute was still there: the markup said hidden, the accessibility tree said hidden, and the layout
   said 74px. Measured on the running page at 1264x615 before this rule existed, with the panel
   collapsed: `panel: top=273.0 bottom=347.0 h=73.9`.

   This is the one thing `@if` would have got right for free, and it is still not worth it - the
   trigger's aria-controls has to point at an element that EXISTS, and a dangling reference is a
   promise about a panel a screen reader cannot find. One rule is cheaper than that. */
.biztech-filters-panel[hidden][b-jzbftvpy2s] {
    display: none;
}

@media (max-width: 599.98px) {
    .biztech-filter-stage-wide[b-jzbftvpy2s] {
        display: none;
    }

    /* ONE CONTROL PER LINE ON A PHONE. Two 40px selects side by side at 375px leaves neither label
       readable - the control height goes back to 40px off the console's 32px below `sm`, which is the
       token's own narrowing, so the panel is taller here than the same markup is on a laptop.
       R13.3's reflow-per-pattern, applied to a filter panel.

       🔴 W0-75 · THE PANEL TURNS, RATHER THAN EVERY CHILD BEING TOLD TO FILL THE LINE. This was
       `.biztech-filter-stage-narrow, .biztech-filters-panel > *  { display: block; flex: 1 1 100% }`, and
       the `> *` half is a shape ScopedStyleReachTests refuses now: Blazor stamps the scope attribute on
       a selector's last compound, so a scoped `> *` reaches only the children the component wrote itself
       and silently skips any child that is another component's root. It was CORRECT here - every child
       of this panel is a span this page writes - and it was inert in four other files, which is why the
       shape goes rather than the rule.

       A column flex container says the same thing without naming a child: one item per line, and
       stretch gives each the panel's width. `flex: 1 1 100%` came off with it, because a column's
       cross-axis stretch is what made it redundant.

       🔴 BUT `display: block` ON THE NARROW STAGE FILTER DID NOT COME OFF, AND THE FIRST VERSION OF
       THIS REWRITE DROPPED IT. `.biztech-filter-stage-narrow` is `display: none` by DEFAULT - the pair
       above declares it, so the desktop layout is the one with no media query behind it - and this rule
       is what switches it on below `sm`. Folded into a `> *` selector it looked like part of the
       one-per-line layout; it is not. Without it the stage filter is absent below 600px altogether,
       which is one step worse than the card's own ## Do not, "do not hide a filter that is switched on":
       InquiriesViewportTests.On_a_phone_the_toolbar_collapses_and_keeps_the_view_switch reported
       `[data-filter='stage']:visible` as 0 after opening the panel, and its own comment says that is
       exactly what the fact is there to catch. It stands alone now, naming this page's own class, which
       is what it always was. */
    .biztech-filter-stage-narrow[b-jzbftvpy2s] {
        display: block;
    }

    .biztech-filters-panel[b-jzbftvpy2s] {
        flex-direction: column;
        align-items: stretch;
    }
}

/* 🔴 THE EMPTY STATE'S OWN RULES MOVED TO app.css AS .biztech-empty-state, AND THE REASON IS I19.

   They were copied to the People tab when it needed the same block, and that sheet's own note set the
   condition for moving them: "two surfaces is not yet a pattern (R8.2 wants three) ... if a third
   surface needs it, that is the moment to move all three." ComplianceRecordsPanel is the third. The
   reasoning about the defect this block replaced - a line of body text, a "No cases on this page." row
   and a disabled pager, three pieces of furniture for "there is nothing here" - went with the rules.

   What did NOT move is below: the loading block and the archived note are this list's alone. */

/* 🔴 THE LOADING BLOCK IS INVISIBLE FOR THE FIRST 150ms OF THE WAIT.

   A tab crossing settles in about 75ms on the running stack, so a loader shown at once is a flash the
   reader gains nothing from - the defect it replaced, wearing a different shape. 150ms is the usual
   floor for "long enough to notice"; under it this paints nothing at all, because the rows arrive and
   the block is removed before the delay elapses.

   `both` is the load-bearing word: the fill applies the `from` frame DURING the delay, which is what
   keeps the block at opacity 0 rather than showing it and then fading it in. The fade itself is R6.7's
   budget verbatim - opacity, var(--biztech-motion-duration, 120ms), ease-in-out - and R6.8's guard is below. */
@keyframes biztech-case-loading-appear-b-jzbftvpy2s {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

.biztech-case-loading[b-jzbftvpy2s] {
    animation: biztech-case-loading-appear-b-jzbftvpy2s var(--biztech-motion-duration, 120ms) ease-in-out 150ms both;
}

/* R6.8. The DELAY is not motion and stays: a reader who asked for no animation still gains nothing from
   a loader that outlives itself. Only the fade goes, so the block appears at the same moment, at once. */
@media (prefers-reduced-motion: reduce) {
    .biztech-case-loading[b-jzbftvpy2s] {
        animation-duration: 0s;
    }
}
/* /Components/Cases/CreateCasePanel.razor.rz.scp.css */
/*
    W0-65 · /inquiries/new — the create form's own column.

    🔴 A FORM IS AS WIDE AS IT IS READABLE, NOT AS WIDE AS THE PAGE.
    The panel spanned the full viewport for two controls, so at 1600px the fields huddled in the top
    left corner under an expanse of empty ground, and each control stretched to a width its content
    never needed. That is the shape of an admin screen from a decade ago, and it is a layout decision
    rather than a styling one.

    640px because that is a comfortable measure for a labelled form column and it holds the longest
    case-type name this registry produces without wrapping. `max-inline-size` rather than a width, so
    a phone gets the whole viewport and nothing is ever narrower than its container.
*/
.biztech-create-case[b-0iwzj4ltr0] {
    max-inline-size: 640px;
}

/* The panel takes the case list's card edge and corners (Inquiries.razor.css), so the form and the list it opens
   from read as one set. It was UiPaper's full Outline edge, visibly heavier than the list's. The fields inside keep
   their own Outline edge: that is the boundary a reader needs to see. */
.biztech-create-case[b-0iwzj4ltr0]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Cases/CustomerCaseTrail.razor.rz.scp.css */
/* The customer's case history: a status line, then the events as a timeline. Every colour is a palette role. */

/* 🔴 THE STATUS LINE: where the case is now, first. A tint of the primary over the surface - the same
   note the session pages draw - with the info glyph in the primary. */
.biztech-history__now[b-0605v2x5h8] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-block-end: 16px;
    padding: 12px 16px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

.biztech-history__now[b-0605v2x5h8]  p {
    color: var(--biztech-palette-text-primary);
}

/* 🔴 THE TIMELINE. No list markers - the line is the sequence. Each event is a row: a 12px dot in the
   primary on a 2px rule in the quiet outline that runs down to the next event, then the sentence over
   its date. The last event's rule stops at its dot. 3 x 4 and 4 x 4 on the base unit (R5.1). */
.biztech-history__trail[b-0605v2x5h8] {
    list-style: none;
    padding-inline-start: 0;
}

.biztech-history__event[b-0605v2x5h8] {
    position: relative;
    display: grid;
    grid-template-columns: 12px minmax(0, 1fr);
    column-gap: 16px;
    padding-block-end: 20px;
}

/* The rule is a 2px line centred in the dot's 12px column, drawn as a background so its position
   comes from the column rather than from an offset that would have to be half of something. */
.biztech-history__event[b-0605v2x5h8]::before {
    content: "";
    position: absolute;
    inset-block: 16px 0;
    inset-inline-start: 0;
    inline-size: 12px;
    background:
        linear-gradient(var(--biztech-palette-outline-subtle), var(--biztech-palette-outline-subtle))
        center / 2px 100% no-repeat;
}

.biztech-history__event:last-child[b-0605v2x5h8] {
    padding-block-end: 0;
}

.biztech-history__event:last-child[b-0605v2x5h8]::before {
    display: none;
}

.biztech-history__dot[b-0605v2x5h8] {
    inline-size: 12px;
    block-size: 12px;
    margin-block-start: 4px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
}

.biztech-history__body[b-0605v2x5h8] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-history__check[b-0605v2x5h8] {
    margin-block-start: 8px;
}
/* /Components/Cases/FormFileList.razor.rz.scp.css */
/* W3-30 · Part E. The files a field holds. TOKENS ONLY (R3.1); both classes are on this file's own markup (I19). A
   role="list" div, so there is no user-agent margin to reset and the caller's spacing utility applies; one gap on the
   container rather than a margin per row (I18). 4px and 8px are one and two of the 4px base unit (R5.1). */
.biztech-file-list[b-skosepj5cw] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

/* A caption and its Remove on one line, wrapping below the caption at 375px rather than pushing the page wide. */
.biztech-file-list-item[b-skosepj5cw] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    min-width: 0;
    overflow-wrap: anywhere;
}
/* /Components/Cases/FormLocationInput.razor.rz.scp.css */
/* W3-30 · Part H. The location group. TOKENS ONLY (R3.1); both classes are on this file's own markup (I19). One gap on
   the container rather than a margin per child (I18), and no margin here at all, so the caller's spacing utility on the
   fieldset applies (UtilitySpecificityTests). 8px is two of the 4px base unit (R5.1). */
.biztech-location[b-gwpg6fo8a9] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    min-inline-size: 0;
}

/* The button and Clear on one line, wrapping at 375px rather than pushing the page wide. */
.biztech-location-actions[b-gwpg6fo8a9] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}
/* /Components/Cases/FormRepeatGroup.razor.rz.scp.css */
/* W3-30 · Part G. A repeating section's entries. TOKENS ONLY (R3.1). Every class here is on this file's own markup
   (I19); UiGrid, UiButton and UiText are placed by the wrappers this file renders, never reached into. Gaps belong to
   containers (I18). */

/* The entries, then the Add row, spaced by this gap and nothing else. */
.biztech-repeat[b-21w69nk9w3] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* One entry: a quiet outline so "Vehicle 2" reads as one block. min-inline-size because a fieldset's default is
   min-content, which at 375px lets one long answer push the page sideways (R13.3). No margin reset: the user agent's
   2px inline margin is harmless here, and a scoped reset would beat every utility a caller passes
   (UtilitySpecificityTests). */
.biztech-repeat-entry[b-21w69nk9w3] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding: 12px 16px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* The entry's name. A legend is taken out of the fieldset's flow by the user agent; padding-inline 4px keeps the
   outline from touching its text. It takes focus when its entry is added; the ring is app.css's own (R3.11). */
.biztech-repeat-entry-legend[b-21w69nk9w3] {
    padding-inline: 4px;
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

/* Remove sits at the end of its entry, out of the way of the answers. */
.biztech-repeat-entry-actions[b-21w69nk9w3] {
    display: flex;
    justify-content: flex-end;
}

/* Add, and the sentence saying why it is closed, side by side where they fit and stacked where they do not. */
.biztech-repeat-actions[b-21w69nk9w3] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
}

.biztech-repeat-limit[b-21w69nk9w3] {
    color: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
}

/* The confirmation's own content: its heading, its sentence and its buttons, spaced by one gap. */
.biztech-repeat-confirm[b-21w69nk9w3] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-repeat-confirm-actions[b-21w69nk9w3] {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Cases/FormReview.razor.rz.scp.css */
/* W3-30 · Part A. The review page. TOKENS ONLY (R3.1). Every class here is on this file's own markup (I19);
   UiText and UiButton are placed by utilities on the row this file renders. Gaps belong to containers (I18). */

.biztech-form-review[b-5h5d4yfa00] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* A step's heading row above its answers, spaced by the step's own gap (I18) rather than a margin on the list. */
.biztech-form-review-step[b-5h5d4yfa00] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The pairs, spaced by the list's gap. Only the user agent's BLOCK margin on a <dl> is removed - it would sit
   on top of the step's gap - and the list is this file's own markup, handed no utility class by anything. */
.biztech-form-review-answers[b-5h5d4yfa00] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-block: 0;
}

/* W3-30 · Part G. One entry of a repeating section: its name above its answers, spaced by its own gap (I18). */
.biztech-form-review-entry[b-5h5d4yfa00] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* A question above its answer rather than beside it: at 375px a label and an answer side by side leave a
   long answer a column too narrow to read (R13.3). */
.biztech-form-review-pair[b-5h5d4yfa00] {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.biztech-form-review-question[b-5h5d4yfa00] {
    color: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
}

/* overflow-wrap so a long unbroken answer (an email address, a reference) wraps inside the column rather than
   widening the page at 375px. Only the user agent's 40px INLINE indent on a dd is removed - its one non-zero
   margin - and never the block margins, which stay free for the utility layer (UtilitySpecificityTests). */
.biztech-form-review-answer[b-5h5d4yfa00] {
    margin-inline-start: 0;
    overflow-wrap: anywhere;
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body1-size);
}
/* /Components/Cases/FormStepper.razor.rz.scp.css */
/* W3-30 · Part A. The step frame. TOKENS ONLY (R3.1). Every class here is on this file's own markup (I19);
   UiAlert and UiButton are placed by utilities on the wrappers this file renders, never reached into. */

/* I18: the head, the step, the refusal's region and the buttons are spaced by this gap and nothing else. */
.biztech-stepper[b-n911qpu8eg] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The progress line above its bar, spaced by the head's own gap. */
.biztech-stepper-head[b-n911qpu8eg] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The step's sections, in ordinary flow inside one item of the column above. min-inline-size so a wide
   section can never force the column past the page at 375px (a flex item's default is min-content). */
.biztech-stepper-body[b-n911qpu8eg] {
    display: block;
    min-inline-size: 0;
}

/* Where the person is - the one statement of it; the bar beneath only draws it. Secondary ink at the caption
   slot's weight, so it reads as orientation above the step rather than as a heading competing with the
   sections' own h3s. The user agent's block margin on a <p> is removed by app.css's document reset, so the
   head's gap is the only space here. */
.biztech-stepper-progress[b-n911qpu8eg] {
    color: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

/* The progress line takes focus on a step change; the focus ring is app.css's own (R3.11), so nothing here
   removes or restyles it. */

/* A native <progress>, drawn in the same shape and tint as UiProgressLinear's track - which is
   indeterminate only and takes no value, so it cannot say "2 of 3". No motion: a value change is a jump, and
   R6.7 forbids animating anything that lays out. */
.biztech-stepper-bar[b-n911qpu8eg] {
    display: block;
    appearance: none;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: 4px;
    border: 0;
    border-radius: var(--biztech-radius-pill);
    overflow: hidden;
    background: color-mix(in srgb, var(--biztech-palette-primary) 16%, transparent);
    color: var(--biztech-palette-primary);
}

.biztech-stepper-bar[b-n911qpu8eg]::-webkit-progress-bar {
    background: transparent;
}

.biztech-stepper-bar[b-n911qpu8eg]::-webkit-progress-value {
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
}

.biztech-stepper-bar[b-n911qpu8eg]::-moz-progress-bar {
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
}
/* /Components/Cases/MediaDeviceDialog.razor.rz.scp.css */
/* W14-02 · F8.11 · design D2, D3 and §4.1 — specimens 1, 2, 3 and 6.

   🔴 TWO KINDS OF ELEMENT IN ONE SHEET, AND THE ::deep BOUNDARY IS EXACTLY WHERE THEY MEET.

   Blazor's scoped CSS rewrites a selector to `.name[b-xxxxx]` and stamps that attribute onto elements
   THIS COMPONENT RENDERS. The dialog, its head, its stack and the preview BOX are the component's, so
   they must NOT carry ::deep. The <video>, the level meter and the meter's bars are created by
   wwwroot/js/biztech-media.js and carry no attribute at all, so a plain selector would never match one
   - the dialog would render correctly in a test that reads markup and show an unstyled, full-bleed
   video in a browser. MediaRoom.razor.css's header makes the same argument for the tiles, and
   MediaAssetTests asserts both halves of it.

   🔴 EVERY COLOUR IS A ROLE (R7.4), AND THE TILE'S TWO ROLES ARE WHY THIS SHEET IS LEGAL.

   The preview is a dark box with light text on it - a badge, a meter, a "No picture yet" - which is the
   treatment PortalStyleSheetTests refused when MediaRoom.razor.css first tried it with a literal, and
   its header records that refusal. W14-02 added TileGround and OnTile: authored roles that are the SAME
   VALUE IN BOTH MODES, measured at 9.65:1 by PaletteContrast.RequiredPairs. So the badge is readable in
   both themes AND the sheet writes no colour the palette does not control.

   Lengths are 4px multiples (R5.4). The one exception is the dialog's own width, which is a named
   layout constant below and says why. */

/* 🔴 A NATIVE <dialog>, SO NO z-index IS WRITTEN ANYWHERE IN THIS FILE. showModal() puts the element in
   the browser's TOP LAYER, above every stacking context on the page - which is what lets this overlay
   sidestep R6.2's "MudBlazor owns 1100-1600, do not compete" by having no opinion at all.

   The scrim is ::backdrop, the browser's own, for the same reason. */
.biztech-media-dialog[b-u86pj8c7fj] {
    /* 28rem: the dialog's measure. Wide enough for a 16:9 preview at a readable size and for a device
       name like "Jabra Evolve2 65" not to ellipsize, narrow enough to stay a dialog rather than become
       a page. Below that it is the viewport less a gutter - see the query at the foot. */
    inline-size: 28rem;
    max-inline-size: calc(100vw - 32px);

    /* A tall dialog must scroll INSIDE itself rather than push the scrim off the screen. */
    max-block-size: calc(100vh - 48px);

    /* 🔴 THE PANEL'S PADDING, DECLARED ONCE (I17). It was `padding: 0` here plus 16px on each of the
       three blocks inside, and UtilitySpecificityTests refused the reset - a scoped `padding: 0`
       resolves at (0,2,0) and silently outranks any biztech-pa-* a page might pass. One declaration is
       both legal and the shape that reset was working around. */
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
}

.biztech-media-dialog[b-u86pj8c7fj]::backdrop {
    /* The browser's own scrim colour would be a literal here, so it is a role: the page's ink at low
       opacity follows the mode, where a fixed black does not. */
    background: var(--biztech-palette-text-primary);
    opacity: 0.4;
}

.biztech-media-dialog-form[b-u86pj8c7fj] {
    display: flex;
    flex-direction: column;
    /* The form fills the dialog so the body can be the only scrolling part. */
    max-block-size: inherit;
}

/* 🔴 I17. THE PANEL DECLARES ITS OWN PADDING. Every block here carries it, because UiPaper has none of
   its own and neither does <dialog> - and a heading flush against a border is what I17 exists to stop. */
/* 🔴 I17. THE DIALOG DECLARES THE PADDING; these three blocks take none of their own, so the head, the
   body and the foot line up with each other and with the border by construction. */
.biztech-media-dialog-head[b-u86pj8c7fj] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* 🔴 THE ONE RESET IN THIS FILE, AND IT IS DECLARED IN UtilitySpecificityTests' OWN LIST. An <h2>
   carries a UA block margin of ~0.83em top and bottom; inside a padded head that pushes the title away
   from the border it is supposed to sit against, and the subtitle 20px below a line it belongs to.
   The head is a flex column, so the 4px between the two comes from its gap rather than from here. */
.biztech-media-dialog-title[b-u86pj8c7fj] {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}

/* margin-block rather than a shorthand reset, and the reason is UtilitySpecificityTests: a scoped
   `margin: 0` resolves at (0,2,0) and silently outranks any utility a page passes. A <p>'s UA margin is
   BLOCK only, so the longhand says exactly what is being collapsed and leaves the inline axis to the
   utility layer. The 4px above comes from the head's own gap (I18). */
.biztech-media-dialog-sub[b-u86pj8c7fj] {
    margin-block: 0;
    font-size: 0.75rem;
    color: var(--biztech-palette-text-secondary);
}

/* The only scrolling part: a tall device list must not push the foot off a short viewport. The block
   padding is what separates it from the head and the foot, and it is a scale step rather than a reset. */
.biztech-media-dialog-body[b-u86pj8c7fj] {
    padding-block: 16px;
    overflow-y: auto;
}

/* 🔴 I18. THE GAP BELONGS TO THE CONTAINER, never a margin per row. The two add up: a 16px gap plus a
   margin on each child is 24px down the rows and 16px across, which is a form that looks misaligned for
   a reason nobody can see in the markup. */
.biztech-media-dialog-stack[b-u86pj8c7fj] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-media-dialog-foot[b-u86pj8c7fj] {
    display: flex;
    justify-content: flex-end;
    /* §9's one primary per surface: Cancel is quiet and sits before Join, so the filled button is the
       one nearest the thumb. */
    gap: 8px;
}

/* The sentence that replaces the speaker picker where the browser has no setSinkId (D3, specimen 3).
   A row rather than a block, so the glyph sits beside the first line rather than above the paragraph. */
.biztech-media-dialog-unavailable[b-u86pj8c7fj] {
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

/* ── The preview ──────────────────────────────────────────────────────────────────────────────────
 *
 * 🔴 THE PREVIEW *IS* THE DIALOG rather than a thumbnail beside a form (specimen 1): it is the thing you
 * came to check. Stacked at every width, because a side-by-side layout would have to stack at 400px
 * anyway and one layout is fewer than two. */
.biztech-media-preview-frame[b-u86pj8c7fj] {
    position: relative;
    /* 16:9, declared as a ratio rather than a height, so the box keeps its shape at every dialog width. */
    aspect-ratio: 16 / 9;
    max-inline-size: 100%;
    overflow: hidden;
    border-radius: var(--biztech-radius-default);

    /* 🔴 W14-02's OWN ROLE, AND IT DOES NOT FOLLOW THE MODE. A preview is a dark box in both themes -
       see this file's header and BizTechPalette's block. */
    background: var(--biztech-palette-tile-ground);
}

/* The box the MODULE paints into. Absolutely positioned to fill the frame, so the badge and the
   placeholder below can overlay it without either affecting the other's layout. */
.biztech-media-preview-box[b-u86pj8c7fj] {
    position: absolute;
    inset: 0;
}

/* 🔴 THE BADGE STATES THE PROMISE THE DESIGN MAKES, and it is drawn ON the picture because that is
   where the eye already is. OnTile on TileGround, measured - not a scrim over a camera, which
   MediaRoom.razor.css rules out because what is under it cannot be measured. Here the ground IS the
   role, and the text shadow is what carries the badge over a bright frame. */
.biztech-media-preview-badge[b-u86pj8c7fj] {
    position: absolute;
    inset-block-start: 8px;
    inset-inline-start: 8px;
    padding: 4px 8px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-tile-ground);
    color: var(--biztech-palette-on-tile);
    font-size: 0.75rem;
}

/* Specimen 2's frame: "No picture yet", centred on the dark box, with the struck-through glyph.
   🔴 A <div> RATHER THAN A <p>, so there is no UA margin to reset - which is the cheaper answer than an
   entry in UtilitySpecificityTests' list. Nothing here is a paragraph of prose. */
.biztech-media-preview-off[b-u86pj8c7fj] {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
    justify-content: center;
    color: var(--biztech-palette-on-tile);
    font-size: 0.75rem;
}

/* ── The module's own elements — ::deep, and this file's header says why ──────────────────────────── */

[b-u86pj8c7fj] .biztech-media-video {
    inline-size: 100%;
    block-size: 100%;
    /* cover, not contain: a letterboxed face in a 28rem box is mostly empty ground, and the crop is
       what every conferencing client does. */
    object-fit: cover;
    display: block;
}

/* 🔴 MIRRORED, BECAUSE THIS IS YOU. A self-view that is not mirrored reads as somebody else's picture -
   you raise your left hand and the person on screen raises their right. MediaRoom.razor.css says the
   same thing about the local tile, and for the same reason. */
[b-u86pj8c7fj] .biztech-media-self {
    transform: scaleX(-1);
}

/* 🔴 THE METER SITS ON THE PICTURE, AT THE EDGE YOUR EYE IS ALREADY ON (specimen 1), so a dead
   microphone is visible without looking away from the thing you came to check. */
[b-u86pj8c7fj] .biztech-media-meter {
    position: absolute;
    inset-block-end: 8px;
    inset-inline-start: 8px;
    inset-inline-end: 8px;
    display: flex;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-on-tile);
    font-size: 0.75rem;
}

[b-u86pj8c7fj] .biztech-media-meter-bar {
    inline-size: 4px;
    block-size: 12px;

    /* Unlit. The ink at low opacity rather than a second role: a bar is ornament until it lights, and
       1.4.11 governs components that carry meaning. */
    background: var(--biztech-palette-on-tile);
    opacity: 0.3;
}

/* 🔴 LIT FROM data-media-level, WHICH THE MODULE WRITES ON EVERY SAMPLE. Four rules rather than a
   per-bar class, because a level is a count and CSS can select a count: `nth-child(-n+N)` lights the
   first N bars. The module writes 0-8 in the animated form and 0-3 in the coarse one.

   🔴 NOT COLOUR ALONE (R12.7): a lit bar is at full opacity AND the unlit ones are not, so the reading
   survives a monochrome render - it is a length of lit bar, which is what a meter is. */
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="1"] .biztech-media-meter-bar:nth-child(-n+1),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="2"] .biztech-media-meter-bar:nth-child(-n+2),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="3"] .biztech-media-meter-bar:nth-child(-n+3),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="4"] .biztech-media-meter-bar:nth-child(-n+4),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="5"] .biztech-media-meter-bar:nth-child(-n+5),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="6"] .biztech-media-meter-bar:nth-child(-n+6),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="7"] .biztech-media-meter-bar:nth-child(-n+7),
[b-u86pj8c7fj] .biztech-media-meter[data-media-level="8"] .biztech-media-meter-bar:nth-child(-n+8) {
    opacity: 1;
}

/* 🔴 THE COARSE FORM'S BARS ARE WIDER, so three of them read as a meter rather than as three dots. The
   module writes data-media-meter="coarse" when the reader has asked their system to stop things moving;
   nothing here animates in either form, because a meter that TRANSITIONED would lag the sound. */
[b-u86pj8c7fj] .biztech-media-meter[data-media-meter="coarse"] .biztech-media-meter-bar {
    inline-size: 12px;
}

[b-u86pj8c7fj] .biztech-media-meter-label {
    /* Pushed away from the bars, and allowed to shrink before they do: the bars are the reading and the
       words are the invitation. */
    margin-inline-start: 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* R13.3 · the reversal. At 400px the dialog is the viewport less a gutter, and the foot's two buttons
   stack rather than crowd - a 28rem measure does not exist on a phone. */
@media (max-width: 599px) {
    .biztech-media-dialog[b-u86pj8c7fj] {
        inline-size: calc(100vw - 32px);
    }

    .biztech-media-dialog-foot[b-u86pj8c7fj] {
        flex-direction: column-reverse;
    }
}

/* 🔴 W19 · THE DIALOG TAKES THE CONSOLE'S CARD AND THE TOP LAYER'S SHADOW.

   It was a 1px outline box at the plain radius with 16px inside, a 16px title and a 12px preview corner,
   so it read as a different product from the session behind it. Corners twice the theme's radius, the
   quiet edge, 24px inside, and the overlay shadow UiDialog already wears - a dialog is the top layer,
   which ADR 0026 D-E licenses a shadow for. Later rules in this file win over the earlier ones, which
   keeps the history above readable. */
.biztech-media-dialog[b-u86pj8c7fj] {
    padding: 24px;
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    box-shadow: var(--biztech-shadow-overlay);
}

.biztech-media-dialog-title[b-u86pj8c7fj] {
    font-size: var(--biztech-font-h5-size);
}

.biztech-media-dialog-sub[b-u86pj8c7fj] {
    font-size: var(--biztech-font-body2-size);
}

/* 🔴 THE FOCUS RING WAS CLIPPED. The body scrolls, and a scroll box clips whatever paints outside its
   padding box - so a focused select's 2px edge, which sits on the field's own border, lost its sides
   against the body's edge. 4px of inline padding taken back with a 4px negative margin gives the ring
   room without moving the fields. */
.biztech-media-dialog-body[b-u86pj8c7fj] {
    padding: 16px 4px;
    margin-inline: -4px;
}

/* The preview and its badge in the console's shapes: the card's corners on the frame, a pill for the
   badge. */
.biztech-media-preview-frame[b-u86pj8c7fj] {
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-media-preview-badge[b-u86pj8c7fj] {
    border-radius: var(--biztech-radius-pill);
}

/* The level meter's bars with rounded ends, so they read as a meter rather than as a row of separators. */
[b-u86pj8c7fj] .biztech-media-meter-bar {
    border-radius: var(--biztech-radius-pill);
}

/* The foot sits under a quiet rule, so the choices end before the decision. */
.biztech-media-dialog-foot[b-u86pj8c7fj] {
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Cases/MediaRoom.razor.rz.scp.css */
/* F8.11 · the video tiles.

   🔴 ::deep IS REQUIRED ON EVERY TILE RULE, AND THE REASON IS THE WHOLE POINT OF THIS FILE. Blazor's
   scoped CSS rewrites a selector to `.biztech-media-tile[b-xxxxx]`, and it stamps that attribute onto
   elements THIS COMPONENT RENDERS. The tiles are created by wwwroot/js/biztech-media.js, so they carry
   no attribute and a plain selector would never match one - the pane would render correctly in a test
   that inspects markup and show unstyled, full-bleed video in a browser. ::deep moves the attribute to
   the ancestor instead, which is the one form that reaches a child the module made.

   The three elements the COMPONENT renders - .biztech-media, .biztech-media-tiles and
   .biztech-media-controls - must NOT carry ::deep, for the mirror-image reason. MediaAssetTests asserts
   both halves, because either mistake is silent.

   🔴 EVERY COLOUR IS READ FROM A ROLE (R7.4), AND ONE PIECE OF THIS DESIGN CHANGED TO KEEP THAT TRUE.
   The participant's name was first drawn OVER the video on a translucent black scrim with white text -
   the standard conferencing treatment, and what every hand-built call UI does. PortalStyleSheetTests
   refused it, correctly: a scoped sheet may write no colour the palette does not control, and there is
   no exemption for one. A scrim is also a colour pair nothing measures - text-on-video is not in
   PaletteContrast.RequiredPairs, and it cannot be, because what is behind it is a camera.

   So the name sits BELOW the frame instead of on it. It costs a little tile height and it is the better
   design: the label takes the paper's own text colour by inheritance, so it follows dark mode and is
   readable whatever the camera is pointed at - which a scrim over a bright window is not. */

/* The pane's own vertical rhythm, so the tiles, the copy and the controls are evenly spaced without
   each of them carrying a margin utility. R5.1's 4px scale. */
.biztech-media[b-u6zxw9v36i] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* 🔴 W6-43 · design §4. TWO GRIDS, FOR TWO JOBS, AND BOTH HALVES WERE MEASURED IN A BROWSER ON
   2026-09-06 RATHER THAN READ.

   One rule served both until this card: repeat(auto-fit, minmax(9rem, 1fr)).

     In a 20rem rail it computes ONE column - grid-template-columns returned a single 294px track. Two
     9rem tiles and an 8px gap need 296px, and a 20rem rail less a paper's 12px padding leaves exactly
     296px, so it rounds down. Two people were two full-width stacked tiles of ~190px, and four were
     760px of rail.

     On an 869px stage the same rule computed 195px 195px 195px 195px - four faces 110px tall, on the one
     surface whose whole job is those faces.

   auto-fit packs as MANY tiles per row as fit. A rail wants a fixed glance; a stage wants as FEW as
   possible, so each tile is as large as it can be. Neither is the question auto-fit answers. */

/* The rail: fixed two-up, whatever the rail's width does to it. */
.biztech-media-tiles[b-u6zxw9v36i] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

/* 🔴 THE STAGE: FOUR RULES AND ONE ATTRIBUTE - no measuring, no ResizeObserver. biztech-media.js creates
   the tiles, so it already knows the count and writes it to data-tiles; `many` is what it writes beyond
   nine, because CSS cannot express a range and the column count stops changing there anyway. */
.biztech-media-on-stage .biztech-media-tiles[data-tiles="1"][b-u6zxw9v36i] {
    grid-template-columns: minmax(0, 1fr);
}

.biztech-media-on-stage .biztech-media-tiles[data-tiles="2"][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-tiles="3"][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-tiles="4"][b-u6zxw9v36i] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.biztech-media-on-stage .biztech-media-tiles[data-tiles="5"][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-tiles="6"][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-tiles="7"][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-tiles="8"][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-tiles="9"][b-u6zxw9v36i] {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.biztech-media-on-stage .biztech-media-tiles[data-tiles="many"][b-u6zxw9v36i] {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* 🔴 R13.3 · AND THE REVERSAL, WHICH IS THE RULE THIS SHEET WOULD OTHERWISE BREAK: "every desktop-only
   rule must be reversed there (container height, per-column scroll, sticky headings)". Four columns at
   375px is an 85px face, which is below the point a tile is for - minmax's 9rem floor was the old rule's
   way of saying the same thing. Two is the most a phone can carry. */
@media (max-width: 599px) {
    .biztech-media-on-stage .biztech-media-tiles[data-tiles][b-u6zxw9v36i] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Empty until somebody joins, and it must take NO space then - the flex gap above would otherwise
   leave 8px of nothing between the paper's heading and the Join button. :empty is exact here: the
   module either put a tile in or it did not. */
.biztech-media-tiles:empty[b-u6zxw9v36i] {
    display: none;
}

/* 🔴 W19 · A TILE IS A DARK ROUNDED FRAME WITH NO BORDER, AND EVERYTHING ELSE SITS ON IT.

   It was a bordered box with the frame on the page's ground and the name in a row of paper under it, so
   a call of three people was three white-edged boxes with a caption strip each. A tile is now the frame
   alone: the tile ground (the palette's dark role for exactly this), corners twice the theme's radius,
   16:9 on the tile itself so the name chip and the avatar can sit over it. */
[b-u6zxw9v36i] .biztech-media-tile {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: calc(var(--biztech-radius-default) * 2);
    overflow: hidden;
    background: var(--biztech-palette-tile-ground);
}

/* The frame fills the tile. Empty - a track not arrived, a camera off - it is the tile ground. */
[b-u6zxw9v36i] .biztech-media-frame {
    position: absolute;
    inset: 0;
    display: block;
}

[b-u6zxw9v36i] .biztech-media-video {
    inline-size: 100%;
    block-size: 100%;
    /* cover, not contain: a letterboxed face in a 9rem tile is mostly empty ground. The crop is the
       lesser cost, and it is what every conferencing client does. */
    object-fit: cover;
    display: block;
}

/* 🔴 MIRRORED, AND ONLY THE LOCAL ONE. A self-view that is not mirrored reads as somebody else's
   picture - you raise your left hand and the person on screen raises their right. A remote tile must
   NOT be mirrored: that is what the other person actually looks like. */
[b-u6zxw9v36i] .biztech-media-self {
    transform: scaleX(-1);
}

/* 🔴 W19 · THE NAME IS A CHIP OVER THE BOTTOM-LEADING CORNER.

   OPAQUE, and that is the rule this sheet has always kept: nothing is drawn on a moving picture,
   because PaletteContrast cannot measure a pair against one. The chip is the tile ground with the tile's
   ink - a measured pair - so the name reads the same over any frame. A long name ends in an ellipsis
   inside the chip rather than pushing the tile wider. 8px from the corner, 2px x 8px inside. */
[b-u6zxw9v36i] .biztech-media-name {
    position: absolute;
    inset-block-end: 8px;
    inset-inline-start: 8px;
    max-inline-size: calc(100% - 16px);
    display: inline-flex;
    align-items: center;
    gap: 4px;
    box-sizing: border-box;
    padding: 4px 8px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-tile-ground);
    color: var(--biztech-palette-on-tile);
    font-size: var(--biztech-font-caption-size);
    line-height: 1;
}

[b-u6zxw9v36i] .biztech-media-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 🔴 W6-45 · design §9, specimen 11a. MUTED IS THE ONE STATE COLOUR IS ALLOWED TO CARRY, still.

   §9: "Muted and camera-off take the error role ... being muted without knowing is why it earns the
   exception." The mark is now the mute button's own glyph in a 16px error disc with the error's ink - a
   pair PaletteContrast holds - instead of a red name with an emoji before it. And it is not colour
   alone (R12.7): the glyph is a shape, and the chip's title says "Muted". Absent - no box at all - until
   the tile is muted. */
[b-u6zxw9v36i] .biztech-media-mic {
    display: none;
    flex: 0 0 auto;
    inline-size: 16px;
    block-size: 16px;
    padding: 2px;
    box-sizing: border-box;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-error);
    fill: var(--biztech-palette-on-error);
}

[b-u6zxw9v36i] .biztech-media-muted .biztech-media-mic {
    display: block;
}

/* 🔴 W19 · CAMERA OFF IS MARKED IN THE CHIP TOO - the same 16px disc and the same error pair as the mute
   mark, with the camera-off glyph. It stands in for the sentence that sat under the tiles, so the state
   is on the tile it is about rather than under whichever tile happened to be last. */
[b-u6zxw9v36i] .biztech-media-cam {
    display: none;
    flex: 0 0 auto;
    inline-size: 16px;
    block-size: 16px;
    padding: 2px;
    box-sizing: border-box;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-error);
    fill: var(--biztech-palette-on-error);
}

[b-u6zxw9v36i] .biztech-media-camera-off .biztech-media-cam {
    display: block;
}

/* 🔴 W19 · CAMERA OFF: WHO IS THERE, NOT AN EMPTY FRAME.

   A tile whose camera is off was a blank ground - grey on light, black on dark - with a name strip, and
   one's own tile was removed outright. The avatar is the person's initials in a disc of the
   primary container and its ink, centred on the tile, shown only in this state. 8 x 4 to 16 x 4 (R5.1). */
[b-u6zxw9v36i] .biztech-media-avatar {
    display: none;
    position: absolute;
    /* Centred on the tile less half the name chip's height, so on a small rail tile (80px tall) the
       disc clears the chip at the foot instead of sitting on it. */
    inset-block-start: calc(50% - 12px);
    inset-inline-start: 50%;
    transform: translate(-50%, -50%);
    /* A third of the tile's width, between 32px and 64px: a rail's small tile gets a disc it can hold,
       the stage's large one stops at 64px. */
    inline-size: clamp(32px, 30%, 64px);
    aspect-ratio: 1;
    align-items: center;
    justify-content: center;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
    font-size: var(--biztech-font-h5-size);
    font-weight: 600;
}

[b-u6zxw9v36i] .biztech-media-camera-off .biztech-media-avatar {
    display: inline-flex;
}

.biztech-media-controls[b-u6zxw9v36i] {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
}

/* 🔴 W6-43 · design §4. THE RAIL'S CAP, AND ::deep IS REQUIRED BECAUSE THE TILE IS THE MODULE'S - this
   file's header says why in full. The module marks every tile past the fourth with data-media-overflow;
   only the RAIL hides them, which is the whole difference between a monitor and the content.

   A MARKER RATHER THAN :nth-child(n+5), AND THE AUDIO ELEMENTS ARE WHY. attachRemote() appends a remote
   <audio> into this same container, so :nth-child would count audio and cap the wrong tiles - and
   display: none would not rescue it, because :nth-child counts hidden elements too.

   MediaRoom renders "N more on camera" beside this, so the hiding is stated rather than silent. */
.biztech-media-in-rail[b-u6zxw9v36i]  .biztech-media-tile[data-media-overflow] {
    display: none;
}

/* The empty stage. Centred, because the card's clause is "centred on the stage, never a blank box", and
   a 16:9 grid of nothing is exactly the blank box it means. No colour is declared: the sentence inherits
   the paper's ink, which is this file's own standing rule and the reason a tile's name sits below its
   frame rather than over it. */
.biztech-media-empty[b-u6zxw9v36i] {
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 8px;
    /* W19 · 48px above and below, the shared empty block's own (app.css): this is the only thing on the
       stage, and a sentence clinging to the top of it read as a stage that had not finished loading. */
    padding: 48px 24px;
    text-align: center;
}

/* W19 · the glyph square: 64px, the primary container and its ink, corners twice the theme's radius -
   the assistant panel's welcome mark (W19-05), so the two empty rooms in the product look alike. 16 x 4
   on the base unit (R5.1). The container pair passes 4.5:1 in both modes (PaletteContrast). */
.biztech-media-empty__mark[b-u6zxw9v36i] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 64px;
    block-size: 64px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* The rail's overflow line: the count on the left, the way to see them on the right. It wraps, because a
   20rem rail less its paper's padding is 296px and "8 more on camera" beside a button does not fit. */
.biztech-media-more[b-u6zxw9v36i] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
}

/* ── A shared screen takes the stage — W14-02 · design D5, specimen 5 ────────────────────────────────

   🔴 ONE ATTRIBUTE, AND IT REPLACES THE GRID RATHER THAN ADDING TO IT. biztech-media.js writes
   data-media-sharing on the container the moment a screen arrives, so this is the same no-measuring,
   no-ResizeObserver approach the four data-tiles rules already take.

   THE SHARE IS THE FIRST CHILD (attachShare prepends), which is what lets it claim the whole first row
   with no rule of its own beyond the one below - and what keeps the tiles' order among themselves
   unchanged, so retile()'s cap still marks the same four. */
/* 🔴 BOTH SELECTORS, AND THE SECOND ONE IS THE WHOLE REASON THIS RULE WORKS AT ALL.
   Measured in a browser on 2026-09-11: the faces stayed two-up and full width however this block was
   written, because `.biztech-media-on-stage .biztech-media-tiles[data-tiles="2"]` above is (0,3,0) and
   a bare `.biztech-media-tiles[data-media-sharing]` is (0,2,0) - so the stage's column count won on
   SPECIFICITY and source order never came into it.

   The prefixed twin ties at (0,3,0) and sits later in the file, which is what actually takes the
   cascade. This is W14-03's `.biztech-th.biztech-numeric` finding one file along, and the guidelines'
   I19 note says why nothing catches it: a rule that loses the cascade renders exactly like a rule that
   was never written. */
.biztech-media-tiles[data-media-sharing][b-u6zxw9v36i],
.biztech-media-on-stage .biztech-media-tiles[data-media-sharing][b-u6zxw9v36i] {
    /* 🔴 THE PANE OWNS EXACTLY ONE SCREEN, AND THAT IS WHAT KILLS THE PAGE SCROLLBAR BY CONSTRUCTION
       rather than by a cap somebody guessed. Two rows: the share takes whatever is left after the face
       strip has taken what it needs.

       Driven in a browser on 2026-09-11, twice. The first version gave this ONE column, so every face
       became a full-width row under the share. The second capped the share's HEIGHT while leaving the
       tiles four equal columns of a 1350px stage - 337px wide and 80px tall, which is a 4:1 box, and
       `cover` turned every face into a letterbox slit. Krishan's words: "participant video should not
       be cropped."

       🔴 SO THE TILES ARE MEASURED BY WIDTH, NOT HEIGHT, which is the whole correction. A 9rem column
       keeps a face at the camera's own 16:9 and asks `cover` to crop nothing; a fixed height on a
       full-width box could only ever crop. 9rem is specimen 5's own rail measure. */
    grid-template-columns: repeat(auto-fill, 9rem);
    grid-template-rows: minmax(6rem, 1fr) auto;

    block-size: calc(100vh - 20rem);
}

/* 🔴 THE SHARE SPANS THE WHOLE WIDTH. Explicit rather than left to auto-placement, because the tiles
   are still grid items in the same container and would otherwise take a row each.

   🔴 NO CONTAINER IN THE SELECTOR, AND THAT IS A CORRECTION MADE UNDER A TEST. The first version read
   `.biztech-media-tiles[data-media-sharing] ::deep .biztech-media-share`, which put a
   COMPONENT-rendered class on a ::deep line - and MediaAssetTests' No_rule_for_a_component_rendered_-
   element_is_scoped_with_deep refused it, correctly. The attribute was never needed: a
   .biztech-media-share element only exists WHILE somebody is sharing, so its own presence is the
   condition. */
[b-u6zxw9v36i] .biztech-media-share {
    grid-column: 1 / -1;
    grid-row: 1;

    /* A grid item's default min-height is its content, which would let the shared screen push the row
       taller than the track it was given. Zero lets the row's 1fr actually bind. */
    min-block-size: 0;
}

/* Every tile goes in the second row, which is what makes the strip a strip: without this they would
   flow into whatever column the share left over and appear BESIDE it at the top. */
[b-u6zxw9v36i] .biztech-media-share ~ .biztech-media-tile {
    grid-row: 2;
}

/* 🔴 AND THE CAP APPLIES WHEREVER A SHARE IS UP, not only in the rail. When a screen holds the stage
   the cameras ARE a rail - inside the stage rather than beside it - so the same four-tile limit is what
   stops six faces squeezing a shared spreadsheet off the surface.

   The GENERAL SIBLING combinator rather than the container's attribute, for the reason above and one
   more: attachShare PREPENDS the pane, so every tile is a following sibling of it by construction. If
   that ever stopped being true the rule would stop applying rather than apply to the wrong thing. */
[b-u6zxw9v36i] .biztech-media-share ~ .biztech-media-tile[data-media-overflow] {
    display: none;
}

/* The share pane itself. 🔴 OUTLINED IN THE PRIMARY AND NAMED (specimen 5): a presenter who cannot see
   what the room sees cannot tell they shared the wrong window, so they see their own share and the
   caption says so. */
[b-u6zxw9v36i] .biztech-media-share {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-default);
    overflow: hidden;
    background: var(--biztech-palette-tile-ground);
}

/* 16:9, and TALLER than a tile - which is the whole point of the artefact/monitor split and what
   MediaTileGridTests.The_share_is_taller_than_the_camera_rail_beside_it measures. A share that shared
   the height with four faces is the layout this design replaces. */
/* 🔴 THE FRAME FILLS THE ROW IT WAS GIVEN AND IMPOSES NO RATIO OF ITS OWN.
   A shared screen already has an aspect - somebody's 16:10 laptop, a 21:9 ultrawide, a portrait
   window - and forcing 16:9 on it either crops it or wastes the row. Filling the row and letting
   `contain` letterbox inside is the only treatment that is correct for every one of them. */
[b-u6zxw9v36i] .biztech-media-share-frame {
    display: block;
    flex: 1 1 auto;
    min-block-size: 0;
}

/* 🔴 A SHARED SCREEN IS NEVER CROPPED, AND THIS IS A CORRECTNESS RULE RATHER THAN A TASTE ONE.
   .biztech-media-video is `cover`, which is right for a FACE - a letterboxed head in a 9rem tile is
   mostly empty ground. It is wrong for a spreadsheet: cover cuts the edges off the thing somebody
   shared, and the columns that fall off are exactly the ones nobody can ask about. */
[b-u6zxw9v36i] .biztech-media-share .biztech-media-video {
    object-fit: contain;
}

/* 🔴 AND THE FACES KEEP THEIR OWN RATIO. This rule used to force `block-size: 5rem` here and that was
   the crop: a 337px-wide box 80px tall is 4:1, and `cover` answers that by throwing away the top and
   bottom of somebody's head. The 9rem COLUMN above is what makes a face small now - the box stays
   16:9, which is what a webcam publishes, so there is nothing left to crop. */
[b-u6zxw9v36i] .biztech-media-share ~ .biztech-media-tile {
    align-self: start;
}

/* 🔴 THE CAPTION USES THE TILE'S TWO ROLES, for the reason W14-02 added them: it is drawn ON a dark
   pane in both themes, so a mode-following ink would be unreadable in one of them. Measured at 9.65:1
   by PaletteContrast.RequiredPairs. */
[b-u6zxw9v36i] .biztech-media-share-who {
    padding: 4px 8px;
    color: var(--biztech-palette-on-tile);
    font-size: 0.75rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Three read-only signals — W14-02 · design D6 ────────────────────────────────────────────────────

   🔴 A RING, NOT A BADGE AND NOT A COLOUR ALONE, and D6 gives the reason in one line: a ring survives
   colour blindness and a dark theme. It is an OUTLINE rather than a border, so the tile does not change
   size when somebody starts talking - a 3px border would move every other tile in the grid on every
   syllable. */
[b-u6zxw9v36i] .biztech-media-speaking {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: -2px;
}

/* 🔴 THE QUALITY MARK, AND IT IS IN THE NAME ROW RATHER THAN OVER THE FRAME. This file's header rules
   out a scrim on a tile because what is under it is a video frame, and PaletteContrast cannot measure a
   pair against moving pictures. The name row sits on the paper, where warning and error are already
   measured pairs - so the mark costs no new colour and no unmeasured pair, which is the same argument
   biztech-media-muted makes one rule up.

   🔴 AND IT IS NOT COLOUR ALONE (R12.7). The module writes U+1F4F6 ANTENNA WITH BARS as real text and a
   `title` naming the grade, so a reader who cannot tell the two inks apart still gets the fact - and
   the two grades differ by their WORD, not by their shape, because D6 asks for one icon at both. */
[b-u6zxw9v36i] .biztech-media-quality[data-media-quality="poor"] {
    color: var(--biztech-palette-warning);
}

[b-u6zxw9v36i] .biztech-media-quality[data-media-quality="lost"] {
    color: var(--biztech-palette-error);
}

/* 🔴 R13.3 · THE REVERSAL, and this file already carries one for the stage's columns. A pane pinned to
   `100vh - 20rem` on a 375px phone is a share about 200px tall with a strip under it - the shared
   document becomes unreadable to save a scroll nobody minds on a phone. So the height comes off and the
   content flows, which is the same trade the stage's two-column cap makes one rule up. */
@media (max-width: 599px) {
    /* Both selectors again - the stage's phone rule above is also (0,3,0). */
    .biztech-media-tiles[data-media-sharing][b-u6zxw9v36i],
    .biztech-media-on-stage .biztech-media-tiles[data-media-sharing][b-u6zxw9v36i] {
        block-size: auto;
        grid-template-rows: auto auto;
    }
}

/* ── Focusing the shared screen — W14-02, 2026-09-11 ─────────────────────────────────────────────────

   🔴 THE FACES ARE HIDDEN, NOT UNSUBSCRIBED. Every camera stays live and every track stays
   attached - this rule changes what is DRAWN and nothing else, so a face that comes back is the same
   face rather than a re-negotiated one. Hiding a picture is not leaving a room.

   ::deep, because the tiles are the module's. The root class is the COMPONENT's, so it carries no
   ::deep of its own - the same split this file's header describes, with the scope attribute moving onto
   the ancestor exactly as the rail's cap rule does. */
.biztech-media-cameras-hidden[b-u6zxw9v36i]  .biztech-media-tile {
    display: none;
}

/* And the share takes the row the strip was in. Both selectors again: the stage's own data-tiles rules
   are (0,3,0) and would otherwise put the columns back - the cascade defeat this file already records
   one block up. */
.biztech-media-cameras-hidden .biztech-media-tiles[data-media-sharing][b-u6zxw9v36i],
.biztech-media-cameras-hidden.biztech-media-on-stage .biztech-media-tiles[data-media-sharing][b-u6zxw9v36i] {
    grid-template-rows: minmax(6rem, 1fr);
}

/* 🔴 W19 · THE RAIL'S CONTROLS ARE ROUND, AND LEAVING IS FILLED RED.

   The seam's outlined icon button is a rounded square (the toolbar's media pair); in the rail's
   centred row of five it reads as a keypad, so the row takes the pill radius. Leave video is the error
   role filled with its ink - a measured pair - because it is the one control here that ends something.

   Reached through `.biztech-media-round`, a second class on the controls' row, rather than through
   `.biztech-media-controls` itself: MediaAssetTests keeps every line naming that class free of ::deep, so
   a rule meant FOR the row can never be scoped away from it. This line is ::deep used the other way, as
   the rail's overflow cap uses it - the row is the ancestor, the buttons are UiIconButton's. */
.biztech-media-round[b-u6zxw9v36i]  .biztech-icon-button {
    border-radius: var(--biztech-radius-pill);
}

.biztech-media-leave[b-u6zxw9v36i]  .biztech-icon-button {
    border-color: var(--biztech-palette-error);
    background: var(--biztech-palette-error);
    color: var(--biztech-palette-on-error);
}

/* 🔴 W19 · WAITING FOR OTHERS IS A STATUS LINE UNDER THE TILE, NOT A CHIP OVER IT.

   A pill across the top of one's own picture covered the face it was about. Under the tile, centred,
   a small dot in the success role that pulses softly - the line is about a room that is open and
   waiting - and the caption in the paper's secondary ink. The pulse is opacity only, its period the
   motion token x12 as the assistant's typing dots use x10 - so a tenant who turns motion off stops it -
   and off under reduced motion (R6.7, R6.8). */
.biztech-media[b-u6zxw9v36i] {
    position: relative;
}

.biztech-media-waiting[b-u6zxw9v36i] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-media-waiting__dot[b-u6zxw9v36i] {
    inline-size: 8px;
    block-size: 8px;
    flex: 0 0 auto;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-success);
    animation: biztech-media-waiting-b-u6zxw9v36i calc(var(--biztech-motion-duration, 120ms) * 12) ease-in-out infinite;
}

@keyframes biztech-media-waiting-b-u6zxw9v36i {
    50% {
        opacity: 0.35;
    }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-media-waiting__dot[b-u6zxw9v36i] {
        animation: none;
    }
}

/* 🔴 W19 · IN THE RAIL, ONE TILE IS THE RAIL'S WIDTH. The rail's two columns are for a call of several,
   and a lone self-view took half of a 296px rail - a thumbnail with the waiting chip running off it. */
.biztech-media-in-rail .biztech-media-tiles[data-tiles="1"][b-u6zxw9v36i] {
    grid-template-columns: minmax(0, 1fr);
}

/* /Components/Cases/ParticipantCallControls.razor.rz.scp.css */
/* 2026-10-08 design D5. The host's Mute and Remove from call, kept together on one line.

   🔴 W19 · PLACED BY THE PAGE, NOT BY THIS SHEET. This took the People list's third grid line itself,
   under the person's state; the operator's page now puts it in one row-end box with the signature ask
   (AgentSessionBody's `.biztech-session-row-end`), so this is only the pair. Round, as the video's own
   controls are, so a button that acts on the call reads as one. */
.biztech-call-controls[b-rfevwfa982] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.biztech-call-controls[b-rfevwfa982]  .biztech-icon-button {
    border-radius: var(--biztech-radius-pill);
}

.biztech-call-controls [data-call-remove][b-rfevwfa982]  .biztech-icon-button {
    border-color: var(--biztech-palette-error);
}

/* The hover label: a dark chip above the button, shown on hover and on keyboard focus. Ends at the
   button's end edge so it never runs out of the rail. */
.biztech-call-controls__item[b-rfevwfa982] {
    position: relative;
    display: inline-flex;
}

.biztech-call-controls__tip[b-rfevwfa982] {
    position: absolute;
    inset-block-end: calc(100% + 4px);
    inset-inline-end: 0;
    z-index: 1;
    padding: 4px 8px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-tile-ground);
    color: var(--biztech-palette-on-tile);
    font-size: var(--biztech-font-caption-size);
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-call-controls__item:hover .biztech-call-controls__tip[b-rfevwfa982],
.biztech-call-controls__item:focus-within .biztech-call-controls__tip[b-rfevwfa982] {
    opacity: 1;
}
/* /Components/Cases/ParticipantLinks.razor.rz.scp.css */
/*
    W4-25 · the People tab.

    🔴 THE EMPTY STATE'S RULES ARE IN app.css NOW, AS .biztech-empty-state. This file held a copy of the
    case list's block, because I19 means a scoped stylesheet reaches its own component's markup and
    nothing else - `.biztech-case-empty` could not be reused by name from here, it would compile against
    this component's scope and match nothing.

    The copy came with a condition, recorded here at the time: "two surfaces is not yet a pattern (R8.2
    wants three) ... if a third surface needs it, that is the moment to move all three."
    ComplianceRecordsPanel is the third, so the rules went to app.css, which has no scope attribute and
    can therefore be read by all three - and by whatever asks fourth.
*/

/*
    🔴 THE LINK FIELD IS AS WIDE AS THE PART THAT DISTINGUISHES IT. It was a full-width box holding
    the whole address and running out of box before it ran out of URL - so the widest thing on the
    row showed the scheme and the host the operator is already on, and truncated the key, which is
    the only part that differs between rows.

    26ch holds a scheme, a short host and the leading half of a key; the value is still the whole
    address, so selecting it by hand yields a working link and Copy sends the rest.
*/
.biztech-participant-key[b-9arwdraz3w] {
    inline-size: 26ch;
}

/*
    🔴 THE PANEL DECLARES ITS OWN PADDING, WHICH IS UiDialog'S CONTRACT AND NOT AN OVERSIGHT OF ITS.
    That component sets `padding: 0` on the <dialog> deliberately - "the PANEL inside declares its own
    padding, as UiPaper's callers do" - so a caller that declares none gets content against the border,
    which is what this looked like when it first shipped.

    24px, which is the step above the 16px a form row uses: a dialog is a thing standing on its own
    with nothing around it to establish a margin.
*/
.biztech-participant-qr[b-9arwdraz3w] {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 16px;

    padding: 24px;
    text-align: center;
}

/* The close control sits in the panel's corner rather than in the column, so the heading keeps the
   full width and the two do not fight for the first line. Inset by 8px, which leaves the 32px
   control inside the panel's own 24px padding without touching the border. */
.biztech-participant-qr-close[b-9arwdraz3w] {
    position: absolute;
    inset-block-start: 8px;
    inset-inline-end: 8px;
}

/*
    The code reads as an object on the surface rather than a hole punched in it: on the dark theme its
    own white ground lands edge-to-edge against a near-black panel.

    🔴 A BORDER AND NOTHING ELSE, BECAUSE THE WHITE IS ALREADY THE SEAM'S. UiQrCode paints a full-bleed
    white rect under the modules - ISO/IEC 18004 wants dark on light, and its header says so at length -
    so a background here would be a second declaration of the same fact, in a stylesheet that may not
    name a colour the palette does not control. PortalStyleSheetTests refuses it, and correctly: the one
    place that exception belongs is the component that owes the standard.
*/
.biztech-participant-qr[b-9arwdraz3w]  .biztech-qr {
    /*
        🔴 BIGGER THAN THE SEAM'S 9rem, BECAUSE THIS ONE IS THE SUBJECT RATHER THAN A DETAIL ON A ROW.
        The seam sizes for a code sitting in a table cell; in a dialog opened FOR the code, 9rem left
        it as a small square in the middle of a 34rem panel with empty ground either side - which is
        what was reported. 24rem fills that panel's content box with a margin rather than a moat.

        `min()` so a narrow viewport gets the column's width instead of overflowing it. The seam's
        header carries the floor this must not cross: below about 2 CSS px per module a phone camera
        starts guessing, and this only ever goes up from there.
    */
    inline-size: min(24rem, 100%);
    align-self: center;

    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* No radius on the SYMBOL itself - the seam's own note explains that rounding clips the finder
   patterns a scanner locates first. The border above is on the svg's box, outside the modules. */

/*
    🔴 THE CONTROLS SIT UNDER THE LINK, NOT BESIDE IT. They shared a line with the field for one
    revision and it was the wrong shape twice over: the field is the widest thing in the table, so on
    anything short of a very wide screen the three controls were the first to wrap - and when they did
    not, the row ran so far that the actions column beside it had nowhere to go.

    Under it, the field keeps its own line whatever the viewport, and the controls are a fixed group
    that never reflows. The cell is two lines by design rather than by accident.
*/
/* 🔴 NOT `.biztech-participant-link`, WHICH IS THE <td>'S OWN CLASS AND HAS BEEN SINCE T16. A rule
   by that name would turn the table CELL into a flex column as well as the stack inside it. */
.biztech-participant-link-stack[b-9arwdraz3w] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;

    /* 🔴 THE CELL BREATHES. The controls sat tight against the rows above and below:
       the cell had the table's own vertical padding and nothing else, so a 32px control filled it
       edge to edge. 8px (R5.1's 4px scale) without making the table taller than its content. */
    padding-block: 8px;
}

/*
    The three controls as one group. `flex-wrap` because a narrow viewport must drop them onto a
    second line rather than push the table sideways (R13.8) - the actions column beside this one
    already wraps for the same reason.

    The negative inline start pulls the group's first control back into line with the field above it:
    a text button carries 12px of its own padding, so without this the row of controls reads as
    indented under a field that starts at the cell's edge.
*/
.biztech-participant-actions[b-9arwdraz3w] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    margin-inline-start: -12px;
}

/*
    The person's three lines, which are three <span>s because that is what UiText renders by default -
    inline, so most callers can put one inside a sentence. Three of them in a cell run together into
    one string, which is what put the address next to the timestamp.

    2px rather than the 4px scale: these are three readings of one person and they belong tighter to
    each other than two fields of a form do.
*/
.biztech-participant-person[b-9arwdraz3w] {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/*
    🔴 THE OPEN CONTROL IS AN ANCHOR AND HAS TO LOOK LIKE ITS TWO NEIGHBOURS. It cannot BE a UiButton -
    that seam writes no `target` and no `rel`, and both are load-bearing here - so it borrows the
    text button's box instead of wearing app.css's inline-link blue - the link did not look
    like the buttons beside it.

    Every value is the seam's own: 32px is `.biztech-button-small`'s minimum, 4px/12px is its padding,
    and the glyph gap matches. A change to the button's box leaves this behind, which is the standing
    cost of a control that cannot be that component - `.biztech-session-chat__new` carries the same one.
*/
.biztech-participant-open[b-9arwdraz3w] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;

    box-sizing: border-box;
    min-block-size: 32px;
    padding: 4px 12px;
    border-radius: var(--biztech-radius-default);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-button-line-height);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    text-transform: var(--biztech-font-button-transform);
    /* Primary, which is what the two text buttons beside it render: UiButton defaults its Color to
       Primary, so an anchor in body ink between them was the odd one of three. */
    color: var(--biztech-palette-primary);
    text-decoration: none;

    /* R6.7: the same 120ms the seam uses, so the three do not fade at two speeds. */
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The same 8% wash UiButton's text variant uses, so hovering the three feels like hovering one set. */
.biztech-participant-open:hover[b-9arwdraz3w] {
    background: color-mix(in srgb, currentcolor 8%, transparent);
}

/*
    A row's own actions - Re-invite, Reissue code, Revoke - side by side, each as wide as the widest, so they
    read as one set rather than three widths. They were small buttons, a fixed 32px that ignored the theme's
    control height, so they sat shorter than every other button on the tab; they are the ordinary size now.
    Below md the table is short of width, so they stack instead of pushing it sideways (R13.8).
*/
.biztech-participant-row-actions[b-9arwdraz3w] {
    display: inline-grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 8px;
}

.biztech-participant-row-actions[b-9arwdraz3w]  .biztech-button {
    inline-size: 100%;
}

@media (max-width: 959.98px) {
    .biztech-participant-row-actions[b-9arwdraz3w] {
        grid-auto-flow: row;
    }
}
/* /Components/Cases/PdfFormOverlay.razor.rz.scp.css */
/*
    W3-18 · F6.22. Only what is the same for every control lives here; each rect is inline, because it is
    computed per widget from coordinates in someone else's document and no stylesheet could hold it.

    Every length is 0, 1px, 2px or a multiple of the 4px base unit, which is what
    PortalStyleSheetTests.No_stylesheet_writes_a_length_that_is_neither_a_scale_step_nor_a_named_constant
    requires. Every colour is read from the palette rather than written, which its sibling requires.
*/

/*
    🔴 THE CONTAINER SCROLLS ITSELF. A page rendered at 150dpi is 1240px wide, and letting that widen the
    document would give a narrow viewport a horizontal scrollbar on the whole page - the invariant that wide
    content scrolls inside its own box.
*/
.biztech-pdf-overlay[b-djnerpiw8k] {
    overflow: auto;
    max-width: 100%;
}

/* The positioning context every control's inline left/top is measured from. */
.biztech-pdf-overlay-page[b-djnerpiw8k] {
    position: relative;
    margin: 0 auto;
}

/*
    display: block removes the inline-image baseline gap, which would otherwise offset every control by a
    few pixels against the page it is positioned over - the same silent misalignment the coordinate flip
    causes, arriving by a different route.
*/
.biztech-pdf-overlay-image[b-djnerpiw8k] {
    display: block;
    width: 100%;
    height: auto;
}

.biztech-pdf-overlay-field[b-djnerpiw8k] {
    position: absolute;
}

/*
    The control fills the box the document drew, so what a participant clicks is the box they can see.

    🔴 NO outline: none. R3.11's focus ring is what tells a keyboard user where they are, and on this page
    it is the ONLY such cue - every other visual signal is in an image that is aria-hidden. The ring is
    raised above its neighbours so it is not clipped by an adjacent control's box.
*/
.biztech-pdf-overlay-control[b-djnerpiw8k] {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    padding: 0 2px;
    border: 1px solid var(--biztech-palette-outline);
    background-color: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    font: inherit;
}

.biztech-pdf-overlay-control:focus-visible[b-djnerpiw8k] {
    position: relative;
    z-index: 1;
}
/* /Components/Cases/SessionBar.razor.rz.scp.css */
/* W19 · the presence strip as a note rather than a paper - see the comment above the block in
   SessionBar.razor for why it stopped being a UiPaper.

   A tint of the primary over the surface, not a container role: this is not a state the strip is
   announcing, it is the page speaking, and the full primary container is what the stage bar's
   PRESENTING pill is filled with. The text inside keeps its own secondary ink, which reads on a 6%
   tint exactly as it reads on the surface. No border: the tint is the boundary, and an edge is what
   made the old strip look like a field. */
.biztech-session-note[b-srf0h9ikca] {
    padding: 0.5rem 0.75rem;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
}

/* Having left, nobody else's edits arrive - the one state of this strip where something has stopped -
   so it takes the warning's container and its ink. */
.biztech-session-note[data-left="true"][b-srf0h9ikca] {
    background: var(--biztech-palette-warning-container);
    color: var(--biztech-palette-on-warning-container);
}

/* The glyph in the primary, so the note is recognisable before it is read. */
.biztech-session-note[b-srf0h9ikca]  .biztech-session-note__mark {
    flex: 0 0 auto;
    color: var(--biztech-palette-primary);
}

/* The sentence beside the glyph takes the row's slack and wraps inside it, so on a phone the glyph stays
   at the start of the first line rather than on a line of its own above the words. */
.biztech-session-note[b-srf0h9ikca]  .biztech-session-note__text {
    flex: 1 1 12rem;
    min-inline-size: 0;
}
/* /Components/Cases/SessionCapturePrompt.razor.rz.scp.css */
/*
    The customer's document asks. Each ask is a picker and its "I can't provide this"; several sit side by side
    in columns of at least 18rem, so a wide stage is used rather than one narrow stack, and a phone still gets
    one column.
*/
.biztech-capture-asks[b-196cli8pue] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
    gap: 12px 16px;
    margin-block-end: 12px;
}

/* One ask, one light box: its name or picker, then where it stands. */
.biztech-capture-ask[b-196cli8pue] {
    padding: 8px 12px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
}

/* The state and its time on one line, with a gap - the agent's list's status line. */
.biztech-capture-status[b-196cli8pue] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}
/* /Components/Cases/SessionChat.razor.rz.scp.css */
/*
    W6-44 · F8.10 · the chat panel. Specimen 7 is the conversation, specimen 8 the other four states.

    Layout and hairlines only — no colour the palette does not control (R3.1) and no length that is not a
    multiple of the 4px base unit (R5.4). Everything visual comes from UiPaper, UiText and the tokens.

    🔴 THE SPECIMEN'S SUB-CAPTION TYPE SIZE IS NOT AVAILABLE HERE, AND THAT IS THE RIGHT ANSWER.
    Specimen 7 sets `.625rem` on the avatar's initials and on the gutter time; 10px is not on the 4px
    scale and no token below --biztech-font-caption-size exists, so both read the caption token instead.
    SessionParticipantRail.razor.css made the identical substitution for the identical mark. The
    specimen's `padding: 0 10px` and `gap: 6px` on the pill are 0.75rem and 0.5rem here for the same
    reason. Nothing was added to PortalStyleSheetTests.LayoutConstants: a registry entry is for a value
    that is load-bearing at exactly that number, and none of these is.

    🔴 THE PAPER IS FLUSH AND THESE ROWS CARRY THE PADDING. UiPaper declares none of its own, so this is
    not a reset — it is the only arrangement in which the log's scrollbar reaches the paper's border. A
    padded paper would inset the rail's one scroll container and put its scrollbar in the middle of the
    panel.
*/

/* min-block-size: 0 so the log can be the thing that scrolls rather than the column growing to fit it.
   A flex item's default minimum is its content, which is the same trap SessionStage's minmax(0, 1fr)
   answers one level up. */
.biztech-session-chat[b-ycnsnxkoev] {
    display: flex;
    flex-direction: column;
    min-block-size: 0;
}

.biztech-session-chat__head[b-ycnsnxkoev] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    /* W19 · 12px rather than 8px down the head, the inset the rail's other cards give their titles. */
    padding: 0.75rem;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

/*
    🔴 THE PILL IS THE ONE PLACE THIS PANEL SPENDS A FILL, AND IT IS NOT DECORATION.

    The card forbids tinted message backgrounds and right-alignment, because "the design direction spends
    colour on hierarchy and not on decoration". This is the other case: an interactive control that has
    just appeared, whose whole job is to be noticed by somebody who is reading something else. Primary
    over OnPrimary is a pair the palette already holds to contrast in both modes (R3.7), so it needs no
    new one — the same argument the card makes for "You" over a colour.

    The user-agent button defaults come off explicitly, the four the board card also undoes. The focus
    ring is NOT declared here: app.css has exactly one, shared, and this element is on its selector list.
*/
.biztech-session-chat__new[b-ycnsnxkoev] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;

    box-sizing: border-box;
    block-size: 1.5rem;
    padding: 0 0.75rem;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-pill);

    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);

    font: inherit;
    font-size: var(--biztech-font-caption-size);
    cursor: pointer;
}

/*
    🔴 block-size, NOT max-height, AND THAT IS THE CARD'S WHOLE POINT ONE LEVEL IN. W6-12 wrote
    `max-height: 14rem` so "a short conversation takes only the room it needs" — which means the panel
    grows by up to 224px as a conversation goes on, and W6-42 measured every presenter control moving
    120px when it did. "A box that cannot grow cannot push a button." 15rem is the specimen's 240px,
    which is 60 × 4, and it is fixed.

    🔴 15rem IS THE CONTENT BOX, WHICH IS WHAT THE CARD'S NUMBER NAMES. There is no universal
    `box-sizing` reset in this application (W0-53 deleted MudBlazor's `*` rule), so this box renders
    240 + 16 = 256px outer with the padding below. Specimen 7 renders the same 256 for the same reason:
    `padding: 8px 0` plus `block-size: 240px`, and no reset in its sheet either.
    AgentSessionViewportTests.The_chat_log_is_exactly_240px_whether_or_not_it_is_full measures
    `getComputedStyle().blockSize` for exactly this reason, and its own note records the first draft
    getting it wrong.

    This is the DIV that carries role="log" — see the markup's note on why the region wraps the list
    rather than being the list. So it needs no <ul> reset at all; those are on the rows below.
*/
.biztech-session-chat-log[b-ycnsnxkoev] {
    padding-block: 0.5rem;

    block-size: 15rem;
    overflow-y: auto;
    scrollbar-width: thin;
}

/*
    🔴 padding-inline-start, NOT padding: 0. UtilitySpecificityTests forbids the second outright, and its
    reason is real rather than stylistic: Blazor rewrites a scoped selector as `.x[b-xxxxxxxxxx]`, which
    is (0,2,0) against a utility class's (0,1,0), so `padding: 0` here would silently beat every
    biztech-pa-* anything ever passes this list. The inline-start property removes the BULLET INDENT,
    which is the only thing that actually needs removing, and it needs no exemption entry — the same
    choice the four <ul> resets already in that test's Declared set each made and wrote down.

    The block margin is a zero and DOES need one, which is the seventh <ul> entry in that register: the
    rows sit between the head's hairline and the composer's, and any block margin would open a gap
    between a hairline and the content it separates.
*/
.biztech-session-chat__rows[b-ycnsnxkoev] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;
}

/* W19 · the empty log: a centred column filling the log's height, the glyph over a line and a
   sentence. The log is a fixed-height box, so the block centres in it rather than clinging to its top.
   min-block-size rather than block-size, so a narrow rail that wraps the sentence still fits it. */
.biztech-session-chat__empty[b-ycnsnxkoev] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-block-size: 13rem;
    padding: 1rem 1.5rem;
    text-align: center;
}

/* The glyph in the secondary ink, as the shared empty block's mark: it labels the state, it does not
   announce it. */
.biztech-session-chat__empty-mark[b-ycnsnxkoev] {
    display: flex;
    color: var(--biztech-palette-text-secondary);
}

/* The failed-send alert's inset, which the flush paper does not supply and no `biztech-ma-*` utility
   exists to pass. Specimen 8's "send failed" card draws the same 8px 12px 0. */
.biztech-session-chat__notice[b-ycnsnxkoev] {
    padding: 0.5rem 0.75rem 0;
}

/* 🔴 THE COMPOSER'S OWN INSET AND HAIRLINE ARE NOT HERE, AND THE FIRST DRAFT PUT THEM HERE WRONGLY.
   Blazor's CSS isolation scopes this sheet to elements in THIS component's markup, so a class passed
   down as `<UiChatComposer Class="…">` lands on a div UiChatComposer renders and carries no [b-xxxxx]
   from here — the rule would compile, render, and match nothing. That is the ::deep trap
   CaseProgressStrip.razor.css records. They are declared in UiChatComposer.razor.css instead, on
   `.biztech-chat-composer__row`, which is also where specimen 7 draws them. */

/*
    A two-column grid rather than a flex row, because the avatar spans BOTH lines of a head row - the
    meta line and the body - and a follow-on's gutter has to line up under it exactly. 1.5rem is the
    specimen's 24px column and the avatar's own box, so the two cannot drift.
*/
/*
    🔴 THE INLINE PADDING IS THE ROW'S AND THE BLOCK PADDING IS THE HEAD ROW'S, WHICH IS THE INVERSE OF
    THE FIRST DRAFT AND DELIBERATELY SO. That draft put `padding: 0.25rem 0.75rem` here and then
    `padding-block: 0` on the follow-on - a box-model zero in a scoped sheet, at (0,2,1) with the scope
    attribute, which would outrank any utility. It passed UtilitySpecificityTests only because that
    sweep's regex matches the `padding:` shorthand and not the `padding-block` longhand.

    Harmless in fact - this <li> is rendered by this component, so no caller can pass it a utility - but
    sitting in a guard's blind spot is not a place to be when the same shape can be written with no zero
    at all. Widening that regex is a follow-up card's line, not this one's.
*/
.biztech-session-chat__msg[b-ycnsnxkoev] {
    display: grid;
    grid-template-columns: 1.5rem minmax(0, 1fr);
    column-gap: 0.5rem;
    padding-inline: 0.75rem;
    /* W19 · 4px between the bubbles of one run, so a run reads as a stack of one person's lines. */
    padding-block-start: 0.25rem;
}

/*
    A run head takes the vertical room; a follow-on does not, so a run reads as one block of text rather
    than as three rows that happen to be adjacent - the whole "three lines from one person is one act of
    speaking".
*/
.biztech-session-chat__msg[data-chat-row="message"][b-ycnsnxkoev] {
    padding-block-start: 0.5rem;
}

.biztech-session-chat__avatar[b-ycnsnxkoev] {
    grid-row: 1 / span 2;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    inline-size: 1.5rem;
    block-size: 1.5rem;

    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-background);
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
}

/* align-items: baseline so the name and the time sit on one line however their sizes differ, which is
   what makes "Sarah Chen  14:02" read as one caption rather than two stacked ones. */
.biztech-session-chat__meta[b-ycnsnxkoev] {
    grid-column: 2;
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    /* W19 · the name at the bubble's size, not a size above it. */
    font-size: var(--biztech-font-body2-size);
}

/*
    🔴 WEIGHT, NOT HUE. design-direction.html: "hierarchy from size and weight, never hue". A sender's
    name in a colour would need a contrast pair per mode and would say nothing a heavier weight does not
    — and it is the same argument the card makes for rendering "You" as a word.
*/
.biztech-session-chat__who[b-ycnsnxkoev] {
    font-weight: 600;
}

.biztech-session-chat__when[b-ycnsnxkoev] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* overflow-wrap so a pasted reference with no spaces in it wraps instead of widening the rail, which in
   a grid column would push the whole panel wider than the column it is in. */
.biztech-session-chat__body[b-ycnsnxkoev] {
    grid-column: 2;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* 🔴 W19 · A MESSAGE IS A BUBBLE, AND THE READER'S OWN ARE ON THE OTHER SIDE.

   The log was a column of names over plain lines, every voice at the same edge in the same ink, so
   telling your own words from the customer's meant reading the name above each run. Now each message
   is a bubble that hugs its text (85% of the column at most), the corner nearest its sender squared on
   a run's first line: everybody else's at the leading edge on the page's ground, the reader's own at
   the trailing edge on the primary container in its own ink - the pair PaletteContrast holds at 4.5:1.

   The reader's own run drops the avatar (it is aria-hidden, and "You" is still in the meta line), and
   its meta line and bubbles take the trailing edge of the same column, so the time gutter a follow-on
   reveals on hover keeps its place at the leading edge on both sides. The row no longer tints on hover:
   with bubbles, the bubble is the object, and a full-width band behind it read as a selection. */
.biztech-session-chat__body[b-ycnsnxkoev] {
    justify-self: start;
    max-inline-size: 85%;
    padding: 0.5rem 0.75rem;
    border-radius: calc(var(--biztech-radius-default) * 3);
    background: var(--biztech-palette-background);
    /* The panel's body size, so a bubble reads at the same size as the rail's other text. */
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-session-chat__msg[data-chat-row="message"] .biztech-session-chat__body[b-ycnsnxkoev] {
    border-start-start-radius: var(--biztech-radius-default);
}

.biztech-session-chat__msg[data-mine="true"] .biztech-session-chat__avatar[b-ycnsnxkoev] {
    visibility: hidden;
}

.biztech-session-chat__msg[data-mine="true"] .biztech-session-chat__meta[b-ycnsnxkoev] {
    justify-self: end;
}

.biztech-session-chat__msg[data-mine="true"] .biztech-session-chat__body[b-ycnsnxkoev] {
    justify-self: end;
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-session-chat__msg[data-mine="true"][data-chat-row="message"] .biztech-session-chat__body[b-ycnsnxkoev] {
    border-start-start-radius: calc(var(--biztech-radius-default) * 3);
    border-start-end-radius: var(--biztech-radius-default);
}

/*
    🔴 IN THE DOM AT ALL TIMES, HIDDEN BY OPACITY. "Hover-only information is not information", and the
    reason it is opacity rather than display: none or visibility: hidden is that both of those remove the
    text from the accessibility tree — so a screen-reader user would lose the one thing this rule exists
    to keep. opacity: 0 is read.

    grid-row: 1 so it sits beside the body rather than above it: this row has no meta line, so the body
    is on line 1 and an unplaced gutter would take line 1 and push the body to line 2.
*/
.biztech-session-chat__gutter[b-ycnsnxkoev] {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    text-align: end;

    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);

    opacity: 0;
    transition: opacity var(--biztech-motion-duration, 120ms) ease-in-out;
}

/*
    🔴 THE FOCUS SELECTOR IS ON THE LOG AND NOT ON THE ROW, and the two are different features rather
    than two spellings of one.

    :hover is per row — a pointer is on one message. :focus-within is on the LOG, because the log is the
    only tab stop this panel adds (R12.2 requires it: a fixed-height scroll container that only a mouse
    can move is unreachable on screen) and specimen 7's tabindex="0" per follow-on would put one stop per
    message on /i/{key}, ahead of the customer's own form fields, where AssigneeFormKeyboardTests walks
    the whole tab order. So one Tab reveals every time at once.
*/
.biztech-session-chat__msg[data-chat-row="follow-on"]:hover .biztech-session-chat__gutter[b-ycnsnxkoev],
.biztech-session-chat-log:focus-within .biztech-session-chat__gutter[b-ycnsnxkoev] {
    opacity: 1;
}

/*
    The two hairlines either side of the label are this row's own ::before and ::after, because a rule
    cannot be drawn through text. flex: 1 1 auto on both, so the label stays centred whatever its length
    — "Yesterday" and "Tue 18 Aug 2026" are the extremes and neither shifts the other's row.
*/
.biztech-session-chat__day[b-ycnsnxkoev] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 0.75rem 0.25rem;
}

.biztech-session-chat__day[b-ycnsnxkoev]::before,
.biztech-session-chat__day[b-ycnsnxkoev]::after {
    content: "";
    flex: 1 1 auto;
    block-size: 1px;
    background: var(--biztech-palette-outline-subtle);
}

.biztech-session-chat__day span[b-ycnsnxkoev] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* R12.8, R6.8, WCAG 2.3.3. The gutter's reveal is the one transition this sheet declares, and it is
   guarded here. The auto-scroll is the other half and cannot be reached from a media query at all —
   biztech-chat.js reads the same setting before its scrollTo, which is what the card means by "reduced
   motion is read in JavaScript as well as in CSS". */
@media (prefers-reduced-motion: reduce) {
    .biztech-session-chat__gutter[b-ycnsnxkoev] {
        transition: none;
    }
}
/* /Components/Cases/SessionClosedNotice.razor.rz.scp.css */
/* The finished page: SessionLeft's centred column - 48px above and below, 8px between the lines, the action a step
   further down - on whichever frame the door gives it. */
.biztech-session-closed[b-8avwewx7i6] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding-block: 48px;
    text-align: center;
}

/* A full-bleed door has no layout panel, so the message draws AssigneeForm's panel itself: one frame, never two. */
.biztech-session-closed--framed[b-8avwewx7i6] {
    box-sizing: border-box;
    inline-size: 100%;
    max-inline-size: 46rem;
    margin-inline: auto;
    padding-inline: 32px;
    background: var(--biztech-palette-surface);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* A 64px tinted chip with the done glyph - the primary container and its ink, the pair PaletteContrast holds at
   4.5:1 - so the page says what happened before it is read. */
.biztech-session-closed__mark[b-8avwewx7i6] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 64px;
    block-size: 64px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-session-closed__action[b-8avwewx7i6] {
    margin-block-start: 8px;
}
/* /Components/Cases/SessionContentPane.razor.rz.scp.css */
/*
    W6-11 · F8.9. Two rules, both §13.

    A pushed object is somebody ELSE'S file at somebody else's dimensions, arriving unannounced on a pane
    that is 375px wide on a phone. Neither rule is decoration: without them this component is the one that
    puts a horizontal scrollbar on the page.
*/

.biztech-session-content-image[b-3w29pabbb1] {
    /*
        Contained rather than covered, which is DeckViewer's own choice and its reasoning: a pushed
        document is something to read, so seeing all of it matters more than filling the frame. `cover`
        would crop whatever is at the edges - on a driving licence, the part the agent asked for.
    */
    max-width: 100%;
    height: auto;
    object-fit: contain;
}

.biztech-session-content-text[b-3w29pabbb1] {
    /*
        <pre> defaults to `white-space: pre`, so a document with long lines scrolls the PAGE sideways
        rather than itself - §13's own prohibition. `anywhere` rather than `break-word` because a stored
        document may carry an unbroken run of characters no dictionary would break.
    */
    white-space: pre-wrap;
    overflow-wrap: anywhere;

    /*
        🔴 AND NO `margin: 0`, WHICH THIS SHEET DECLARED UNTIL UtilitySpecificityTests CAUGHT IT. Blazor
        rewrites a scoped selector as `.x[b-xxxxxxxxxx]` - (0,2,0) against a utility class's (0,1,0) - so a
        reset here would silently beat any spacing utility a page passes this component, with
        the class still present in the markup. That test names three ways out; this is the third, and it
        was the honest one: the line was tidiness restating a `*` reset W0-53 removed, not a requirement.
        <pre>'s own block margin inside a UiPaper is ordinary spacing. If it ever needs changing, it needs
        a utility class in the markup rather than a reset in here.
    */
}
/* /Components/Cases/SessionDeckPane.razor.rz.scp.css */
/* W19 · the slide's screen: the page's ground behind the bare reading area, with the console's card
   corners. The ground is the same token the page sits on, so it is the quiet step down from the card's
   surface in both modes, and any tenant palette moves it with the page. Background and corners only -
   the reading area's size, padding and the slide's fit are DeckReadingArea's and stay there. */
.biztech-session-deck[b-zf3ciwyprq]  .biztech-deck-reading-area-bare {
    background: var(--biztech-palette-background);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Cases/SessionDocumentRequests.razor.rz.scp.css */
/*
    W6-09 · F8.7. Layout only — no colour, no font, no border. R3.1: a hex in a component stylesheet is a
    bug, and everything visual here comes from UiPaper, UiText and UiChip.

    The bound is SessionChat's, for the same reason: an agent who asks for four documents on a long call
    must not have the form pushed off the screen by the record of it. A max-height rather than a fixed
    height, so a call with one ask takes only the room it needs.
*/
/*
    🔴 padding-inline-start, NOT padding: 0 — and this is SessionChat.razor.css's note, which applies
    identically here. UtilitySpecificityTests forbids the second outright: Blazor rewrites a scoped
    selector as `.x[b-xxxxxxxxxx]`, which is (0,2,0) against a utility class's (0,1,0), so `padding: 0`
    would silently beat every biztech-pa-* anything ever passed this element. The inline-start property
    removes the BULLET INDENT, which is the only thing that needs removing.

    The bottom margin is a real value rather than a zero, so it is not the reset that rule is about.
*/
.biztech-session-documents[b-1luibvo47r] {
    list-style: none;
    margin: 0 0 0.75rem;
    padding-inline-start: 0;
    max-height: 14rem;
    overflow-y: auto;
}

/* The menu's own 4px edge is right for a list of items and cramped for a panel holding a form, so the panel
   brings its own room. */
.biztech-session-documents-panel[b-1luibvo47r] {
    padding: 12px;
}

/* Each request is one record: a light ground round its name and its status line, so two asks read as two
   things rather than four lines. */
.biztech-session-documents > li[b-1luibvo47r] {
    padding: 8px 12px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
}

.biztech-session-documents > li + li[b-1luibvo47r] {
    margin-top: 0.5rem;
}

.biztech-session-documents-status[b-1luibvo47r]  .biztech-text {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}
/* /Components/Cases/SessionFinishPanel.razor.rz.scp.css */
/*
    W6-35 · F8.21. Layout only — no colour, no font, no border. R3.1: a hex in a component stylesheet is a
    bug, and everything visual here comes from UiButton and UiText.

    No max-height, and the contrast with SessionDocumentRequests.razor.css is deliberate: that list is
    unbounded (an agent may ask for four documents on a long call), while this one is bounded by the case's
    own participants. A scroll box around three names would be chrome around nothing.
*/
/*
    🔴 padding-inline-start, NOT padding: 0 — SessionChat.razor.css's note, which applies identically here.
    UtilitySpecificityTests forbids the second outright: Blazor rewrites a scoped selector as
    `.x[b-xxxxxxxxxx]`, which is (0,2,0) against a utility class's (0,1,0), so `padding: 0` would silently
    beat every biztech-pa-* anything ever passed this element. The inline-start property removes the BULLET
    INDENT, which is the only thing that needs removing.

    The bottom margin is a real value rather than a zero, so it is not the reset that rule is about.
*/
.biztech-session-finish[b-23uq6pbckh] {
    list-style: none;
    margin: 0 0 0.75rem;
    padding-inline-start: 0;
}

/* 🔴 W6-53 · THE NAME AND ITS BUTTON WERE TOUCHING - MEASURED AT 0px IN CHROME ON 2026-09-09.

   The li stacked a block <p> on an inline-flex button with nothing between them, while every other
   pair in this card sits 8px or 12px apart. A ROW rather than a stack: at the rail's measured 294px
   the name and "Request signature" fit side by side, which also takes 20px off the card per signer -
   and flex-wrap drops the button under the name when a long name, or the "Asked" caption after it,
   needs the width. align-items: center puts the name's text box on the middle of the 32px control
   rather than on its top edge. 0.5rem is the 8px this card's other gaps already use (R5.4). */
.biztech-session-finish > li[b-23uq6pbckh] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    /* W19 · the Participants card's row rhythm: 4px above and below, a quiet rule between, so the two
       lists of the same people read as one kind of list. */
    padding-block: 0.25rem;
}

.biztech-session-finish > li + li[b-23uq6pbckh] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The name takes the row's slack, so the asks line up down the card's trailing edge however long each
   name is. */
.biztech-session-finish__name[b-23uq6pbckh] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* W19 · the initials mark, drawn as SessionParticipantRail draws it. A copy rather than a shared class
   because I19 keeps each sheet to its own markup, and two is not yet R8.2's three. */
.biztech-session-finish__mark[b-23uq6pbckh] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    inline-size: 1.5rem;
    block-size: 1.5rem;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-background);
    border: 1px solid var(--biztech-palette-outline-subtle);
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
}

/* W19 · the end, under a rule, across the card. The button is the seam's, so its width is reached
   through this component's own wrapper. */
.biztech-session-finish__end[b-23uq6pbckh] {
    padding-block-start: 0.75rem;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-session-finish__end[b-23uq6pbckh]  .biztech-button {
    inline-size: 100%;
    justify-content: center;
}

/* The milestone row: the select and its button side by side, above "End session".

   Two controls that do different things, so they are grouped away from End rather than sitting in one
   undifferentiated column of buttons - the panel's own markup remark says why the two acts are separate,
   and a reader should be able to see that they are.

   align-items: end so the button's baseline meets the select's, which has a label above it and is
   therefore taller. flex-wrap so a narrow rail stacks them instead of squeezing the select. Both
   lengths are 4px-scale multiples (R5.4). */
.biztech-session-milestone[b-23uq6pbckh] {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

/* ::deep, and it is required rather than stylistic - CasePage.razor.css's rule for the same class,
   reproduced because the reasoning is the valuable half. Blazor stamps its scoped-CSS attribute on the
   elements THIS component renders; UiSelect renders its own markup, so a bare selector here would
   compile to `.biztech-milestone-control[b-xxxxxxxxxx]` and match nothing. `::deep` compiles to
   `[b-xxxxxxxxxx] .biztech-milestone-control`, which reaches the class Class= hands down and stays
   scoped to this component's subtree.

   12rem = 192px, so it stays a scale value. It exists so the select does not collapse to the width of
   its longest stage label in the flex row above. */
[b-23uq6pbckh] .biztech-milestone-control {
    min-width: 12rem;
}

/* 🔴 W19 · THE CARD'S HEAD: a 40px people glyph in a round primary-container chip, then the heading
   over its count. The container pair passes 4.5:1 (PaletteContrast). 10 x 4 on the base unit (R5.1). */
.biztech-session-finish__head[b-23uq6pbckh] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-session-finish__glyph[b-23uq6pbckh] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-session-finish__title[b-23uq6pbckh] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
}

/* The people, under the head. 12px between them, the head's own gap. */
.biztech-session-finish__people[b-23uq6pbckh] {
    margin-block-start: 12px;
}

/* The ask at the end of a row: "Asked" beside a compact Request, kept together. */
.biztech-session-finish__ask[b-23uq6pbckh] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
}

/* In the people list's two-line row, the ask takes the third column across both lines. */
.biztech-session-finish__ask[b-23uq6pbckh] {
    grid-row: 1 / span 2;
    grid-column: 3;
}
/* /Components/Cases/SessionFormPane.razor.rz.scp.css */
/* W19 · a section heading starts a section.

   A quiet rule under the name and 24px above it - the previous grid's 12px margin collapses into this
   24px, the pane being block flow - so the run of fields before it ends before the next name begins. The first section takes no space above - the pane's own inset is already there - which
   is the one place `:first-child` is the right question, because the pane writes its headings and
   grids as siblings and nothing else precedes the first. 6 x 4 and 3 x 4 on the base unit (R5.1). */
.biztech-session-form__head[b-bz4ooa7rlr] {
    margin-block: 1.5rem 0.75rem;
    padding-block-end: 0.5rem;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-session-form__head:first-child[b-bz4ooa7rlr] {
    margin-block-start: 0;
}

/* 🔴 The section the presenter moved everybody to.

   It was marked only in the accessibility tree (aria-current), so a follower who had just been moved
   could not see where they had landed. The rule turns primary and 2px, which is the console's focused
   edge (W19-02), and passes 3:1 against the surface in both modes because the primary does (WCAG
   1.4.11). It never moves anything: the thickness is taken out of the padding so the fields under it
   stay where they were. */
.biztech-session-form__head[aria-current="true"][b-bz4ooa7rlr] {
    padding-block-end: calc(0.5rem - 1px);
    border-block-end: 2px solid var(--biztech-palette-primary);
    color: var(--biztech-palette-primary);
}
/* /Components/Cases/SessionLibraryPicker.razor.rz.scp.css */
/*
    The picker dialog's own geometry — the body inside UiDialog's panel, and nothing outside it.

    🔴 I17. THE PANEL DECLARES ITS OWN PADDING, BECAUSE UiDialog's DOES NOT. `.biztech-dialog-panel` is
    `padding: 0` on purpose and its own stylesheet says why: "a caller that forgets one gets a visibly
    flush dialog rather than a subtly wrong one". This is that padding. 24px is UiDialogHost's
    `.biztech-dialog-form`, so the two overlays in this application are padded the same.

    🔴 I18. ONE CONTAINER, ONE GAP, AND NOT A MARGIN ON ANY CHILD. The heading, the field, the summary,
    the results and the foot each carry none — two spacings would add up, and 16px is the gap
    `.biztech-dialog-form` already uses for a stack of dialog rows.

    🔴 I19. EVERY SELECTOR BELOW NAMES A CLASS THIS COMPONENT'S OWN MARKUP CARRIES, and none of them ends
    in a universal one. The scope attribute Blazor stamps is the selector's LAST compound, so a rule
    reaching into UiTable, UiTextField or UiDialog from here would be inert and look exactly like a rule
    that worked. `.biztech-table-scroll` is deliberately absent: it is app.css's, global, shared with
    thirteen other surfaces, and a scoped copy here would silently do nothing.
*/

/*
    🔴 THE RESULTS SCROLL, NOT THE DIALOG, AND THE PHONE IS WHY. Measured in Chromium at 375x900 on
    2026-09-17: `UiTable` reflows to `DataLabel` cards below sm - four facts stacked per row - so four
    resources are roughly 1,000px of cards. `.biztech-dialog-panel` caps the panel at `100vh - 32px` and
    scrolls it, so everything scrolled together: the search field and the Close button both left the screen,
    and the blocking sentence explaining why every Show was dead went with them.

    So this element takes the cap instead and distributes it. The heading, the field, the summary and the
    foot keep their intrinsic heights; the results take what is left and scroll inside it. The panel's own
    `overflow-y` then never fires, because its child never exceeds it.

    `min-block-size: 0` on the scrolling child is the part that is not optional: a flex item's automatic
    minimum size is its CONTENT, so without it the region refuses to shrink below the table and the whole
    panel grows again - the same rule that makes `overflow` inside flexbox look broken for no visible reason.
*/
.biztech-picker[b-g9b2v6g8f7] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
    box-sizing: border-box;
    max-block-size: calc(100vh - 32px);
}

/*
    §9's fourth empty state. The sentence and its Retry on one row, because they are one thought — and
    `align-items: start` so a wrapped sentence does not stretch the button to the height of its own
    paragraph.
*/
.biztech-picker-failure[b-g9b2v6g8f7] {
    display: flex;
    align-items: start;
    gap: 12px;
    flex-wrap: wrap;
}

/*
    🔴 THE RESULTS REGION IS WHAT REPORTS BUSY (I21), AND IT IS ALSO THE ONE PART THAT SCROLLS.
    Both follow from the same fact: it is the element holding what a read replaces, so it is where the
    reader's attention is and where the height has to be spent.
*/
.biztech-picker-results[b-g9b2v6g8f7] {
    display: flex;
    flex-direction: column;
    gap: 8px;

    /* Takes the height the fixed rows leave, and scrolls inside it - see .biztech-picker. */
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
}

/*
    The floor, on the LOADING state rather than on the region. A skeleton block and a four-row table are
    different heights, so a dialog that sized to whichever was showing would jump every time a read started
    and settled - and a modal that resizes under a reader moves the field they are typing into.

    It is here rather than on `.biztech-picker-results` because that element is now a flex item that must be
    allowed to shrink: a minimum on it would fight `min-block-size: 0` and bring the panel's own scrollbar
    back on a short viewport.
*/
.biztech-picker-loading[b-g9b2v6g8f7] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-block-size: 9rem;
}

/*
    🔴 A DIVIDER DRAWN BY THE CONTAINER, NOT BY A CHILD — and it is information rather than decoration:
    it is where the reader's choices stop and the way out begins. `border-block-start` on this element
    puts one line in the markup instead of a UiDivider sibling that would also need the stack's gap
    reasoned about twice.

    The blocking sentence sits at the START and the Close control at the END, so R9.2's reason reads
    before the control it is about, in both writing directions — `justify-content: space-between` with
    the sentence absent leaves Close where it always is.
*/
.biztech-picker-foot[b-g9b2v6g8f7] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline);
}

/*
    R13.3. Below sm the panel spans the screen it is on, so the padding comes in to keep the measure and
    the foot stacks — two controls of different kinds squeezed onto one 375px row is the layout
    `.biztech-dialog-actions` already refuses at this breakpoint.
*/
@media (max-width: 599.98px) {
    .biztech-picker[b-g9b2v6g8f7] {
        padding: 16px;
    }

    .biztech-picker-foot[b-g9b2v6g8f7] {
        align-items: start;
        flex-direction: column;
    }
}
/* /Components/Cases/SessionParticipantRail.razor.rz.scp.css */
/* 🔴 W6-40 · F8.1. What goes IN the rail column, never the column itself.

   This declares no width and no grid position on purpose: SessionStage owns the two-column split, and a
   component that placed itself could not be moved below the stage at sm, which is R13.3's reflow and the
   card's "at sm the rail moves below the stage rather than being clipped".

   Tokens only (R3.1). The card: "Where the mock's colours differ from the tokens, the tokens win." */

/* The block owns the gap between the roster panel and the signature slot, so neither child has to carry
   a trailing margin that would also apply when it is the last thing in the column. */
.biztech-session-rail[b-axqol7fle2] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* 🔴 W6-53 · design §4. THE HEAD IS ONE ROW, MEASURED FROM THE SPECIMEN'S OWN RULE:

     .mk-paper-head { display:flex; align-items:baseline; justify-content:space-between;
                      gap:8px; margin-bottom:8px }

   `baseline`, not `center`, and it is the specimen's word: the title is .875rem and the count is
   .75rem, so centring two boxes of different heights leaves neither text sitting on the other's line.
   The margin is here rather than a biztech-mb-* on the element, because the element is a bare div this
   file owns rather than a UiText a page configures. */
.biztech-session-rail__head[b-axqol7fle2] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-block-end: 0.5rem;
}

/* 🔴 W6-53. 4px OF PADDING AND A RULE BETWEEN ROWS, WHICH IS .mk-people li EXACTLY:

     .mk-people li      { display:flex; align-items:center; gap:8px; padding:4px 0 }
     .mk-people li + li { border-top: 1px solid outline-subtle }

   This had 8px of padding and no separator. Both halves matter and they trade against each other: the
   rule is what makes four rows read as four rows, so the padding can halve and the panel gets 16px
   shorter per person - which is the rail budget specimen 3's own note is counting when it caps the
   video grid at four tiles.

   `li + li` and not `li:not(:last-child)`: the border belongs to the row BELOW the boundary, so a list
   of one draws no rule at all and there is never a line under the last name. */
.biztech-session-rail__row[b-axqol7fle2] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-block: 0.25rem;
}

.biztech-session-rail__row + .biztech-session-rail__row[b-axqol7fle2] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* 🔴 W6-53 · design §4. THE STATE IS A CHIP, WHICH IS .mk-pill:

     .mk-pill { display:inline-flex; align-items:center; gap:6px; block-size:24px; padding:0 10px;
                border-radius:pill; border:1px solid outline-subtle; background:background }

   The word and its glyph sat loose at the end of the row before this, so a row read as three unrelated
   things rather than as a name and its standing.

   🔴 THE COLOURS ARE THE APPLICATION'S TOKENS AND NOT THE SPECIMEN'S, BY THE SPECIMEN'S OWN RULE
   - "Where the mock's colours differ from the tokens, the tokens win", which this file's header already
   cites. It is not a preference here: .mk-pill-ok reads var(--mk-ok-bg), var(--mk-ok-bd) and
   var(--mk-ok-fg), and NONE OF THE THREE IS DEFINED ANYWHERE IN THAT DOCUMENT. An unresolved var() is
   invalid at computed-value time, so in a browser that chip paints a transparent background and a
   currentColor border. There is no colour there to copy, so the palette supplies it.

   flex: 0 0 auto so a chip never shrinks under a long name - the name has min-inline-size: 0 below and
   is the thing that gives. white-space: nowrap so "Not here yet" stays one line inside a 24px chip. */
.biztech-session-rail__pill[b-axqol7fle2] {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    gap: 0.25rem;
    block-size: 1.5rem;

    /* 8px and 4px, where the specimen says 10px and 6px — the avatar's own remark below carries why
       all three round rather than being registered as constants. */
    padding-inline: 0.5rem;
    border-radius: var(--biztech-radius-pill);
    border: 1px solid var(--biztech-palette-outline-subtle);
    background: var(--biztech-palette-background);
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: 1;
    white-space: nowrap;
}

/* min-inline-size: 0 so a long name shrinks rather than pushing the state word out of the column. A
   grid or flex item's default minimum is its content, which is the same trap SessionStage's
   minmax(0, 1fr) answers one level up. */
.biztech-session-rail__name[b-axqol7fle2] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* The mock draws photographs. There is no UiAvatar in the seam and a participant carries only a name and
   an email, so there is no image to show - initials in a circle say who the row is without inventing a
   component or a face. aria-hidden in the markup: the full name is beside it. */
.biztech-session-rail__mark[b-axqol7fle2] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    inline-size: 1.5rem;
    block-size: 1.5rem;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-background);
    border: 1px solid var(--biztech-palette-outline-subtle);
    color: var(--biztech-palette-text-secondary);

    /* 🔴 W6-53. 24px AND OUTLINED, WHICH IS .mk-avatar EXACTLY:

         .mk-avatar { inline-size:24px; block-size:24px; border-radius:pill;
                      background:background; border:1px solid outline-subtle;
                      font-size:.625rem; font-weight:600; color:text-secondary }

       This was a 28px FILLED circle on outline-subtle. Three differences: the size, the fill, and the
       type. The fill is the one that mattered - a solid chip beside a solid state chip made the row
       read as two badges with a name wedged between them, and the specimen draws the avatar as an
       outline so the only filled thing on the row is the state.

       🔴 THE SPECIMEN'S THREE OFF-SCALE LENGTHS ROUND, AND PortalStyleSheetTests IS WHY. It refused
       .625rem here and the chip's 10px padding and 6px gap below, in as many words: "round it to the
       scale, or - if it is genuinely load-bearing at that exact value - add it to LayoutConstants here
       AND to §5's registry in the guidelines, with the measurement." Two pixels of initial and two of
       chip padding are not load-bearing at an exact value, so they round rather than buy a registry
       entry and a name each. "DO" at caption size and weight 600 measures under 16px, so it still sits
       inside a 24px circle. */
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
}

/* 🔴 THE ABSENT ROW IS DIMMED AND NOT HIDDEN, which is I11's discipline applied to presence: somebody
   who is not in the room is still on the case, and a row that vanished would tell a presenter the
   person was never invited. Only the MARK dims - the name keeps its ordinary ink, because R3.5 makes
   text somebody has to read a meaningful thing to see. */
.biztech-session-rail__row[data-present="false"] .biztech-session-rail__mark[b-axqol7fle2] {
    color: var(--biztech-palette-text-disabled);
}

/* 🔴 W6-53. THE OK CHIP, AND ITS THREE STATES ARE THE THREE THE SPECIMENS DRAW.

   `Here` and `Signed` are .mk-pill-ok - something that has happened. `Signing…` is .mk-pill-warn -
   something in flight. `Waiting…`, `Reading only` and `Not here yet` keep the base chip, which is
   .mk-pill-wait: text-secondary on the plain surface, no colour at all. That is the specimen's own
   grading and it is also R3.5's, because a row nobody is waiting on should not draw the eye.

   Matched on data-present as well as data-signoff, so the ONE chip whose colour comes from presence
   rather than from a signature gets it - a NotExpected row reading `Here`. A row reading `Not here
   yet` is NotExpected too and must stay uncoloured, which is why this cannot key on the state alone. */
.biztech-session-rail__row[data-signoff="signed"] .biztech-session-rail__pill[b-axqol7fle2],
.biztech-session-rail__row[data-signoff="not-expected"][data-present="true"] .biztech-session-rail__pill[b-axqol7fle2] {
    border-color: var(--biztech-palette-success);
    color: var(--biztech-palette-success);
}

.biztech-session-rail__row[data-signoff="signing"] .biztech-session-rail__pill[b-axqol7fle2] {
    border-color: var(--biztech-palette-warning);
    color: var(--biztech-palette-warning);
}

/* 🔴 COLOUR IS THE SECOND SIGNAL, NEVER THE ONLY ONE (R3.6, WCAG 1.4.1). Each row already carries an
   icon and a word - "Signed", "Signing…", "Waiting…" - so these two rules add emphasis to something
   already legible without them, which is what makes them safe on a page nobody can reconfigure. */
.biztech-session-rail__row[data-signoff="signed"][b-axqol7fle2] {
    color: var(--biztech-palette-success);
}

.biztech-session-rail__row[data-signoff="signing"][b-axqol7fle2] {
    color: var(--biztech-palette-warning);
}

/* A native <progress> keeps the user agent's paint unless every one of these is set, and the two
   pseudo-elements are NOT interchangeable: Chrome and Safari fill through ::-webkit-progress-value
   inside ::-webkit-progress-bar, Firefox through ::-moz-progress-bar. Setting one leaves the other
   browser showing a stock bar in a colour no palette controls. */
.biztech-session-rail__progress[b-axqol7fle2] {
    inline-size: 100%;
    block-size: 0.25rem;
    margin-block-start: 0.5rem;
    appearance: none;
    border: 0;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-outline-subtle);
}

.biztech-session-rail__progress[b-axqol7fle2]::-webkit-progress-bar {
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-outline-subtle);
}

.biztech-session-rail__progress[b-axqol7fle2]::-webkit-progress-value {
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
}

.biztech-session-rail__progress[b-axqol7fle2]::-moz-progress-bar {
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
}

/* 🔴 W19 · THE EMBEDDED LIST: A TINTED INSET INSIDE THE FINISH CARD.

   The page's ground as its fill and the card's corners, so the people read as one block inside the
   card rather than as more of the card's own lines. Rows keep their own rhythm and rule; the inset
   adds 12px either side and 4px above and below the first and last row. 3 x 4 and 1 x 4 (R5.1). */
.biztech-session-rail__inset[b-axqol7fle2] {
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* 🔴 Only once somebody is on it. With nobody, the inset drew a 8px grey strip with nothing in it
   under "0 here". The list itself stays mounted - it is a role="log" region, which must exist before
   its first row arrives to announce it (R12.6a) - and only its tint and inset wait for a row. */
.biztech-session-rail__inset:has(.biztech-session-rail__row)[b-axqol7fle2] {
    padding: 0.25rem 0.75rem;
    background: var(--biztech-palette-background);
}

/* On the inset's ground the mark and the pill keep a surface fill, so they stay chips rather than
   melting into the ground they share a colour with. */
.biztech-session-rail__inset .biztech-session-rail__mark[b-axqol7fle2],
.biztech-session-rail__inset .biztech-session-rail__pill[b-axqol7fle2] {
    background: var(--biztech-palette-surface);
}

/* 🔴 W19 · INSIDE THE FINISH CARD A ROW IS TWO LINES: THE NAME OVER ITS STATE.

   On one line the mark, the name, the pill and the card's Request shared a 272px row, and a two-word
   name wrapped onto two lines beside a pill that did not. As a grid the mark spans both lines, the name
   takes the first and the pill the second under it, and whatever the page puts at the row's end (the
   finish card's ask) sits in a third column centred on both - placed by the finish card's own sheet,
   since that element is the card's. */
.biztech-session-rail__inset .biztech-session-rail__row[b-axqol7fle2] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    column-gap: 8px;
    row-gap: 2px;
    align-items: center;
    padding-block: 8px;
}

.biztech-session-rail__inset .biztech-session-rail__mark[b-axqol7fle2] {
    grid-row: 1 / span 2;
}

.biztech-session-rail__inset .biztech-session-rail__pill[b-axqol7fle2] {
    grid-row: 2;
    grid-column: 2;
    justify-self: start;
}

/* 🔴 W19 · THE NAME AND ITS STATE STAY TOGETHER WHEN THE ROW END IS TALLER THAN THEY ARE.

   With the host's call controls under Request, the row's end is two 32px lines, and the grid gave the
   name and the chip a line each of that height, centred in it - so a gap opened between a name and its
   own state. The name now sits at the foot of its line and the chip at the head of its own, so the pair
   stays one block in the middle of the row whatever the end beside it holds. `::deep` for the name,
   because it is UiText's element rather than this component's. */
.biztech-session-rail__inset[b-axqol7fle2]  .biztech-session-rail__name {
    align-self: end;
}

.biztech-session-rail__inset .biztech-session-rail__pill[b-axqol7fle2] {
    align-self: start;
}
/* /Components/Cases/SessionPushBar.razor.rz.scp.css */
/* W19 · the show zone takes the row's free width, and wraps its own sentence inside it.

   With nothing to offer this zone is one sentence, and at its natural width it pushed Annotate and Swap
   onto the next line of the session toolbar. A basis and a zero minimum let the sentence break inside
   the zone instead, so the controls after it stay on the row. It GROWS as well, into
   the row's leftover width, so the sentence runs on one line where there is room and the row's
   remaining controls (Annotate, the chevron) sit together at the trailing end. The toolbar's markers are all
   `display: contents`, which is what makes this root a flex item of the row at all. */
.biztech-session-push[b-am7in2dvlh] {
    flex: 1 1 16rem;
    min-inline-size: 0;
}
/* /Components/Cases/SessionStage.razor.rz.scp.css */
/* 🔴 W6-40 · F8.1 · R13.1, R13.2, R13.3. One stage, one rail.

   R13.2 says structure responsively in MARKUP and use CSS only for what the grid cannot reach. This is
   that case: FormLayoutTests declares both mounting pages Surface.Workspace, and
   A_form_that_owns_its_fields_lays_them_out_on_a_grid asserts a workspace names zero UiGridItem - so the
   seam's grid is unavailable here. ResourceLibrary.razor.css:30,39 is the same shape for the same
   reason, the other hand round.

   🔴 minmax(0, 1fr) AND NOT 1fr, AND THE DIFFERENCE IS THE 375px CLAUSE. A grid track's default minimum
   is `auto`, which is its CONTENT - so a slide image wider than the column would push the track past the
   viewport and take the rail off the screen with it. `.biztech-main` declares overflow-x: hidden, so
   that would be CLIPPED rather than scrolled: the page would look fine and the rail would simply not be
   there. R13.8 records the same trap on the board. */

/* W19 · the notice row: the columns' own inline inset and no block padding. The note brings its own
   16px above (the page passes it a top margin), and the columns' top padding is the space below it,
   so a notice with nothing to say is a row of zero height rather than a 16px gap under the band. */
.biztech-session-stage__notice[b-a767le4z9p] {
    padding-inline: 1rem;
}

.biztech-session-stage__columns[b-a767le4z9p] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    padding: 1rem;
}

/* R13.1: md is 960, and MudBlazor's breakpoints are the application's so a page never disagrees with
   its grid. Above it the rail takes a fixed column and the stage takes what is left.

   24rem because the rail's content is a name, a state word and a signature pad - narrower than
   ResourceLibrary's 15rem list would suggest is enough, because a pad has to be drawable on. It was 20rem,
   and the pad's Clear and Confirm signature then could not share a line and stacked; 24rem holds both. Below md
   the single-column rule above applies and the rail stacks under the stage, which is the card's "at sm
   the rail moves below the stage rather than being clipped".

   align-items: start so the rail does not stretch to the height of a tall deck and leave its panel
   floating in empty space. */
@media (min-width: 960px) {
    .biztech-session-stage__columns[b-a767le4z9p] {
        grid-template-columns: minmax(0, 1fr) 24rem;
        align-items: start;
    }

    /* 🔴 W19 · MEETING FOCUS: 60:40 RATHER THAN THE FIXED RAIL.

       In Meeting focus the video takes the stage and the work paper moves into the rail, where 20rem -
       about a quarter of a desktop - squeezed a three-column form into a strip. The columns become three
       fifths and two fifths, so the form has room beside the video, and the video still has the larger
       share. Only when the page asks (WideRail); every other arrangement keeps the fixed rail. */
    .biztech-session-stage__columns[data-wide-rail="true"][b-a767le4z9p] {
        grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    }
}

/* Both tracks repeat min-inline-size: 0 because minmax() governs the TRACK and this governs the ITEM -
   a flex or grid item's own automatic minimum is its content too, and one without the other still
   overflows. */
.biztech-session-stage__main[b-a767le4z9p] {

    min-inline-size: 0;
}

/* 🔴 W6-42 · A FLEX COLUMN, AND NO scrolling OF ITS OWN. The card: "The rail can hold a child that
   fills it, with ONE scroll container inside the rail and no nesting." The one is SessionChat's log,
   which caps itself at 14rem and scrolls there. A rail that scrolled too would put a scrollbar inside a
   scrollbar, which is R13.3's "nine nested scrollers" one column in - and neither is reachable by
   keyboard in a predictable order.

   The gap is on this element rather than on each child, so nothing has to carry a trailing margin that
   would also apply when it is last. SessionParticipantRail.razor.css makes the same argument one level
   in. */
/* 🔴 W14-01 · A PRESENTER'S TOOLBAR IS 6rem OF WINDOW THAT IS NOT THE SLIDE.

   DeckReadingArea caps a slide at `100dvh` less a reserve, and defaults that reserve to 17rem - what a
   stage spends above and below the frame when the artefact is all there is. Measured at 1520x783 on
   2026-09-11, after the deck's name stopped being painted on either pane: the frame starts at y=204 on
   the customer's pane and at y=275 here, and the difference is this toolbar.

   🔴 19rem, AND IT WAS 24rem UNTIL THE ROW BECAME ONE LINE. The toolbar was two rows of word
   buttons when that number was measured; it is one row of 50px now, and the deck's own title went with
   the heading. Left at 24 the picture was capped at 311px tall inside a frame held open at its 384px
   floor - 73px of dead space, photographed and marked on 2026-09-11, with the cap rather than the floor
   as the cause.

   19rem still covers the PRESENCE ALERT - "Nobody else is here ..." renders above the deck whenever the
   room is empty, which is most of the time an operator is setting up - measured at y=250 for the frame's
   top with it showing, plus 48px of controls under it.

   🔴 LEFT AT THE DEFAULT, THE PREVIOUS/NEXT CONTROLS SIT BELOW THE FOLD AT EVERY WINDOW SIZE.
   The cap and the chrome above it both move with the viewport, so the shortfall is a CONSTANT - a bigger
   screen does not fix it, which is why the defect survived being looked at on a large monitor.

   :has(), and the selector is narrowed by it for a reason: the SAME stage renders the customer's pane
   with no Toolbar fragment at all, so a flat declaration on .biztech-session-stage__main would cost that
   pane ~150px of slide to solve a problem it does not have. Measured, on the wrong version of this rule.

   Both elements in this selector are SessionStage's own, so the scope attribute lands where Blazor puts
   it and nothing here reaches into a child component (I19). MainLayout's
   `.biztech-shell:has(> .biztech-drawer:not([hidden]))` is the in-repo precedent, and carries the
   verification that the rewriter appends the attribute at the END of the compound.

   The CHILD combinator is deliberate, for that rule's reason as well: a descendant `:has()` would match a
   nested stage if one is ever rendered inside this column. */
.biztech-session-stage__main:has(> .biztech-session-stage__toolbar)[b-a767le4z9p] {
    --biztech-deck-reserved-block: 19rem;
}

.biztech-session-stage__rail[b-a767le4z9p] {
    min-inline-size: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* 🔴 ::deep IS REQUIRED, NOT STYLISTIC. The rail's children come from the CALLING PAGE's render
   fragment and carry the PAGE's scope attribute, so a plain rule here would compile to
   `.biztech-session-stage-fill[b-xxxxxxxxxx]` and match nothing at all - the trap MediaRoom.razor.css
   and EducationItemFrame.razor.css each record, both found in a browser rather than by a test.

   flex: 1 1 auto with min-block-size: 0 is what lets a bounded rail hand its leftover height to one
   child, which is specimen 1's shape: chat takes what is left and only its log scrolls. In an
   auto-height column there is no leftover, so this costs nothing today - and it is what W6-44's fixed
   240px log lands into. */
.biztech-session-stage__rail[b-a767le4z9p]  .biztech-session-stage-fill {
    flex: 1 1 auto;
    min-block-size: 0;
}

/* 🔴 W19 · EVERY PANEL ON THE STAGE IS THE CONSOLE'S CARD.

   The case list, the case types table and the portal's tiles took the quiet edge and corners twice the
   theme's radius in W19's other cards. The session's panels kept the seam's default - the stronger
   outline and the plain radius - so a session opened from the case list looked like an older screen
   than the one it was opened from. One rule here, rather than one per panel, because the stage is the
   one place every one of those panels shares, and all three pages that mount it want the same cards.

   outline-subtle is ornament under R3.7, and that is right here: each card also sits on the page's
   ground, which separates it from its neighbour, so the edge marks a boundary nothing depends on
   seeing. The toolbar is the seam's own box and takes the same edge for the same reason. */
.biztech-session-stage__columns[b-a767le4z9p]  .biztech-paper,
.biztech-session-stage__toolbar[b-a767le4z9p]  .biztech-toolbar {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* 🔴 W6-53 · THE RAIL'S gap IS THE ONLY SPACING BETWEEN ITS CARDS, AND THIS RULE IS WHAT MAKES
   THE SENTENCE ABOVE TRUE.

   Measured in Chrome at 1264x615 on 2026-09-09: the finish card sat 32px above the participants card
   while the participants card sat 16px above chat, and the last card carried a trailing 16px INSIDE
   the rail. The rail's cards carry their own biztech-mb-4, which ADDS to gap rather than replacing it
   - the exact case the gap remark above says nothing should have to carry. One rail, two different
   gaps, and no reason a reader could see for either.

   🔴 THE MARGIN CANNOT COME OFF THE COMPONENTS. SessionChat also renders on AssigneeForm in
   normal block flow, where its own bottom margin is the only thing separating it from the signature
   prompt directly below it. So the RAIL neutralises the margin here and the cards keep one that is
   still correct everywhere else.

   ::deep for .biztech-session-stage-fill's reason directly above - the cards come from the calling
   page's fragment and carry the PAGE's scope attribute. Every rail card holds exactly ONE UiPaper and
   none nests a second, so this reaches each card and nothing inside one. */
.biztech-session-stage__rail[b-a767le4z9p]  .biztech-paper {
    margin-block-end: 0;
}

/* 🔴 W6-42 · R13.1, R13.3, R6.1. THE BAND PINS, AND MOBILE-FIRST IS WHY THE BASE RULE IS THE ONE THAT
   REVERSES IT.

   R13.3: "every desktop-only rule must be reversed there (container height, per-column scroll, sticky
   headings) or you get nine nested scrollers and nine headings pinned to the viewport." The measurement
   behind that sentence is the board's. Here the number is blunter: the demonstration machine is
   1264x615, and a band pinned on a 375px phone takes a fifth of the viewport and never gives it back.

   So the BASE rule is what a phone gets and the 600px block adds the pin. This file's existing 960px
   block is the same shape for the same reason.

   R6.1: never a raw z-index, use a layer. --biztech-layer-sticky is the layer
   .biztech-board-column-header takes (app.css:875) and for the same job.

   `top` rather than inset-block-start: that is the property the house sticky pattern uses, and this
   frame is not written for a vertical writing mode. */
.biztech-session-stage__bar[b-a767le4z9p] {
    position: static;
}

@media (min-width: 600px) {
    .biztech-session-stage__bar[b-a767le4z9p] {
        position: sticky;
        top: 0;
        z-index: var(--biztech-layer-sticky);
    }
}

/* 🔴 W6-42 · specimen 1. The toolbar row, and it is the FRAME's own element rather than a Ui*
   component - R14.1's "go one layer down only when the layer above cannot reach", and layer 3 reaches a
   flex row. It wraps, so a narrow stage stacks the controls instead of pushing the column wide. The
   margin is on this element rather than on each control, so a card adding a control adds no spacing
   decision with it. */
.biztech-session-stage__toolbar[b-a767le4z9p] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* 🔴 W6-53 · design §4. THE ROW IS A SURFACE, AND A FLEX ITEM CANNOT BE ONE.

   The specimen's toolbar is a bordered card the full width of the stage:

     .mk-toolbar { display:flex; align-items:center; gap:8px; flex-wrap:wrap; padding:8px;
                   background:surface; border:1px solid outline-subtle;
                   border-radius:default }

   UiToolbar already declares exactly those four surface properties, so nothing needed drawing - what
   was wrong is that this element is a FLEX ROW and UiToolbar was one of its items, so it sized to its
   own content. Driven in Chrome on 2026-09-09: the agent's toolbar card stopped at 620px on an 1130px
   stage, with Leave video's auto margin pushing against the inside of a shrink-wrapped box instead of
   against the stage edge. Reported as "the toolbar still not up to standard".

   flex: 1 1 auto gives the card the line. min-inline-size: 0 lets it shrink below its content so its
   OWN flex-wrap has something to do - UiToolbar.razor.css makes that argument for itself one level in,
   and a flex item's automatic minimum is its content, which is the same trap SessionStage's
   minmax(0, 1fr) answers one level up.

   ::deep for .biztech-session-stage-fill's reason above: UiToolbar renders its own markup, so a plain
   rule here would compile to `.biztech-toolbar[b-xxxxxxxxxx]` and match nothing. */
.biztech-session-stage__toolbar[b-a767le4z9p]  .biztech-toolbar {
    flex: 1 1 auto;
    min-inline-size: 0;
    /* 🔴 W19 · THE 16px UNDER THE ROW BELONGS TO THE ROW, NOT TO ITS SLOT. It was on the slot's
       wrapper, which stays in the column when the seam hides an empty toolbar - in Meeting focus with
       nothing to show, the stage's video card then stood 16px lower than the rail's first card beside
       it. On the toolbar itself, the space goes when the toolbar does. */
    margin-block-end: 1rem;
}

/* 🔴 W14-01 · SPECIMEN 1's SPACER IS GONE, AND THIS RECORDS WHY RATHER THAN DECLARING IT.

   W6-43 built `.biztech-session-toolbar-end` as an auto margin, and the argument was real: Swap and
   Leave video act on the FRAME and the CALL rather than on the artefact, so they sat away from the
   controls that do. W6-53 then had to add a second rule, because free space in a flex line is divided
   EQUALLY among every auto margin on it and the second wearer landed in the middle of the row.

   🔴 THAT ARITHMETIC IS WHY IT IS GONE. The row is five controls now and three of them are
   glyphs, and the expander added a third claimant - so the slack came out as ~200px before Swap and
   ~250px after it, photographed and marked on 2026-09-11. A gap says "these are different" only while
   the eye has enough row to read it as grouping; in a short row it reads as something broken.

   The class is off the markup too rather than left declaring nothing: a class in the markup with no
   rule anywhere is W5-05's own defect, which PortalStyleSheetTests exists to catch. Those controls wear
   `biztech-session-control` now, like every other member of the row, and SOURCE ORDER puts Leave video
   and then Swap at the end of it - which is the reading order both specimens want, reached without a
   declaration that has to be corrected twice. */


/* 🔴 W16-18 · finding 1 · R13.3, R6.1. THE RAIL'S DESTINATIONS, PINNED - AND MOBILE-FIRST IS WHY THIS
   ONE IS THE OPPOSITE WAY ROUND FROM THE BAND ABOVE.

   The band is static on a phone and sticky from 600, because a band pinned on a 375px screen takes a
   fifth of the viewport and never gives it back. This is the reverse case and gets the reverse shape:
   it exists ONLY while the rail is stacked under the stage, and it is switched off at exactly the
   width the rail becomes a rail. So the base rule is the pinned one and the media query removes it.

   R13.3: "every desktop-only rule must be reversed there (container height, per-column scroll, sticky
   headings) or you get nine nested scrollers and nine headings pinned to the viewport." A bar that
   survived past 960 would be the ninth thing pinned to a screen that no longer needs any of them.

   960 READ FROM THE SAME PLACE AS THE GRID, not a number chosen to be near it. One breakpoint, two
   rules, and the bar cannot outlive the layout it compensates for.

   R6.1: never a raw z-index, use a layer. --biztech-layer-sticky is what the band above and
   .biztech-board-column-header both take, for the same job.

   `bottom` rather than inset-block-end: that is the property the house sticky pattern uses, and this
   frame is not written for a vertical writing mode.

   flex-wrap, so a narrow screen stacks the controls instead of pushing the page wide - the toolbar's
   own argument one rule up. An opaque surface and a top hairline, because content passes UNDER this
   and a translucent bar over a form is unreadable at the moment it matters. */
.biztech-session-stage__reach[b-a767le4z9p] {
    position: sticky;
    bottom: 0;
    z-index: var(--biztech-layer-sticky);

    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding: 0.5rem 1rem;

    background: var(--biztech-palette-surface);
    border-block-start: 1px solid var(--biztech-palette-outline);
}

@media (min-width: 960px) {
    .biztech-session-stage__reach[b-a767le4z9p] {
        display: none;
    }
}

/* StickyToolbar: the toolbar card stays right under the band while the form scrolls, so Go to is always reachable.
   The offset is the band's MEASURED height (biztech-stage-band.js): one guessed from tokens put the card over the
   band's lower half whenever the title ran to two lines. Only once the module is live, and only where the rail sits
   beside the stage - on a phone a pinned card would take the screen (R13.3). The card's own ground is drawn on it,
   so the form does not show through it as it scrolls past. */
/* The band's height, 0 until biztech-stage-band.js writes the measured value on the element itself. */
.biztech-session-stage[b-a767le4z9p] {
    --biztech-session-band-height: 0px;
}

@media (min-width: 960px) {
    .biztech-session-stage[data-band-measured] .biztech-session-stage__toolbar[data-sticky="true"][b-a767le4z9p] {
        position: sticky;
        top: var(--biztech-session-band-height);
        z-index: var(--biztech-layer-sticky);
    }

    .biztech-session-stage[data-band-measured] .biztech-session-stage__toolbar[data-sticky="true"][b-a767le4z9p]  .biztech-toolbar {
        background: var(--biztech-palette-surface);
    }
}
/* /Components/Cases/SessionStageBar.razor.rz.scp.css */
/* 🔴 W6-40 · F8.1. The band the proposal draws across the top of a live session surface.

   R6.6 and §6's 10.0 note — "a border carries depth on an in-flow surface; a shadow is only for the top
   layer" (ADR 0026 D-E). This is in flow under the tenant header, so it takes an edge and no shadow.

   Tokens only. The card: "Where the mock's colours differ from the tokens, the tokens win", and R3.1
   makes a hex in a stylesheet a bug. The mock's live dot was green, and W19 made it red - the palette's
   Error role, which is the role rather than the value. */

.biztech-session-bar[b-sm0rkas1bw] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    /* W19 · 12px rather than 8px down the band: with the state in a pill and the exit a full control,
       8px left the pill and the button touching the band's edge. 3 x 4 on the base unit (R5.1). */
    padding: 0.75rem 1rem;
    background: var(--biztech-palette-surface);

    /* `outline` and not `outline-subtle`: this edge is what separates the band from the stage below it,
       which makes it meaningful under R3.5 — and R3.7 leaves outline-subtle deliberately untested, so a
       rule that must be seen may not rest on it. */
    border-block-end: 1px solid var(--biztech-palette-outline);
}

/* Not animated. R6.7's reduced-motion guard would be a second rule for a pulse nobody asked for, and a
   blinking dot in front of an audience is the kind of ornament that reads as a fault. */
.biztech-session-bar__dot[b-sm0rkas1bw] {
    inline-size: 0.5rem;
    block-size: 0.5rem;
    flex: 0 0 auto;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-error);
}

/* 🔴 W19 · THE STATE PILL, IN RED. Tinted with the error role's container and its ink, the dot in the
   role's full colour - the broadcast convention for "on air", which is what a presenter glances up to
   check. Red here carries no fault: the word inside says which state it is, LIVE or PRESENTING, and the
   pill is the same for both because both are the session being on.

   The container pair passes 4.5:1 in both modes - PaletteContrast holds OnErrorContainer against
   ErrorContainer - so the word is legible on its tint wherever a tenant's palette moves it. */
.biztech-session-bar__state[b-sm0rkas1bw] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
    block-size: 1.5rem;
    padding-inline: 0.5rem 0.75rem;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-error-container);
    color: var(--biztech-palette-on-error-container);
}

/* The count and its glyph, in the reference's quieter ink: a fact about the room you glance at, not the
   name of what is on screen. */
.biztech-session-bar__room[b-sm0rkas1bw] {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    color: var(--biztech-palette-text-secondary);
}

/* The proposal's separators. Ornament, and nothing depends on seeing them — which is exactly what R3.7
   says outline-subtle is for. */
.biztech-session-bar__rule[b-sm0rkas1bw] {
    inline-size: 1px;
    block-size: 1rem;
    flex: 0 0 auto;
    background: var(--biztech-palette-outline-subtle);
}

/* 🔴 W6-45 · specimen 1. The reference is a fact you look up, not the name you read from the back of
   the room, so it takes the secondary ink the count beside it already takes. ADR 0026 D-B: hierarchy
   from size and weight, and the one step down here is the type scale's, never a hue. */
.biztech-session-bar__ref[b-sm0rkas1bw] {
    color: var(--biztech-palette-text-secondary);
    /* W19 · a reference is read character by character against another copy of it, so its digits take
       one width each and two references line up when compared. */
    font-variant-numeric: tabular-nums;
}

/* 🔴 W6-45 · specimen 1's spacer. The exits sit at the FAR end of the band, which is what makes them
   read as a pair rather than as two more items in a row of facts.

   `margin-inline-start: auto` and NOT a UiSpacer, because this row wraps: a flex spacer that wrapped
   would become an empty element on a line of its own and stop pushing anything, while an auto margin
   simply has no leftover space to take and behaves. That is design §8's 375px band, where the row
   splits in two and the exits sit under the title rather than beside it.

   NO ::deep, and that is worth saying because the neighbouring frame needs one. The children come from
   the calling page and carry the PAGE's scope attribute, so a rule aimed AT a child would match nothing
   here - which is what SessionStage.razor.css records for .biztech-session-toolbar-end. Everything this
   rule sets is on the wrapper, which is this component's own element, and `gap` reaches its children
   from the parent without naming them. */
.biztech-session-bar__exits[b-sm0rkas1bw] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-inline-start: auto;
}

/* 🔴 W19 · BELOW sm THE BAND WRAPS, AND A SEPARATOR AT THE END OF A LINE SEPARATES NOTHING.

   At 390px the title, the reference and the count each take a line, and each rule landed at the end
   of the line before the thing it was meant to sit in front of. Below sm the lines are the separators.
   599.98px is the frame's own breakpoint (MainLayout.razor.css), not a second number. */
@media (max-width: 599.98px) {
    .biztech-session-bar__rule[b-sm0rkas1bw] {
        display: none;
    }
}

/* 🔴 W19 · ONE LINE ABOVE sm, AND THE TITLE BLOCK IS WHAT GIVES WAY.

   With the focus track, Take presenter and Leave session beside it, a long case subject pushed the
   band onto a second line at 1440px - the exits dropped under the title and the sticky band grew by a
   row for the whole session. The title and the reference are one stacked block now (see the markup),
   and above sm the band does not wrap: that block shrinks and each of its lines ends in an ellipsis,
   while everything else keeps its width. Below sm the band wraps as before. */
.biztech-session-bar__identity[b-sm0rkas1bw] {
    display: flex;
    flex-direction: column;
    flex: 0 1 auto;
    min-inline-size: 0;
}

.biztech-session-bar__title[b-sm0rkas1bw],
.biztech-session-bar__ref[b-sm0rkas1bw] {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

@media (min-width: 600px) {
    .biztech-session-bar[b-sm0rkas1bw] {
        flex-wrap: nowrap;
    }

    .biztech-session-bar__exits[b-sm0rkas1bw] {
        flex-wrap: nowrap;
        flex: 0 0 auto;
    }

    .biztech-session-bar__room[b-sm0rkas1bw] {
        flex: 0 0 auto;
        white-space: nowrap;
    }
}
/* /Components/Cases/SessionStartOffer.razor.rz.scp.css */
/*
    W6-58 addendum · the host's start offer. Layout only: colour and type come from UiText, UiPaper and the
    tokens (R3.1). The gap between the words and the button is the container's (I18), from biztech-gap-3.
*/
.biztech-session-start[b-wn2jvpggn3] {
    align-items: center;
    justify-content: space-between;
}

/* The words take the room the button leaves, and wrap above it on a narrow screen rather than squeezing
   it - flex-wrap on the container does the wrapping. */
.biztech-session-start__words[b-wn2jvpggn3] {
    flex: 1 1 16rem;
    min-inline-size: 0;
}
/* /Components/Cases/SessionTranscriptLog.razor.rz.scp.css */
/*
    W6-58 · F8.21 · a finished session's chat, read-only. Layout only: every colour and type size comes
    from UiText and the tokens (R3.1), and both lengths are on the 4px base unit (R5.4).

    I18: the spacing between rows belongs to the list, as a gap - never a margin on each row.
*/
.biztech-review-transcript[b-nrul49oouh] {
    display: grid;
    gap: 8px;

    /* The <ol>'s own reset: a transcript IS ordered, but its numbers would be noise, and the browser's
       block margin would sit on top of the panel's own padding. Declared in UtilitySpecificityTests. */
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}
/* /Components/Cases/SignaturePad.razor.rz.scp.css */
/* T12 · the signature pad's own styles.

   Scoped, so they arrive through BizTech.Portal.styles.css - already referenced from Pages/_Host.cshtml,
   which is why this file needs no host-page change. Case-list styles live in wwwroot/css/app.css instead
   because they restyle MudBlazor's own markup, which scoped CSS cannot reach. */

/* 🔴 W6-51. THE PAD IS ONE COLUMN, AND THE NUMBER HAS ONE HOME.

   The frame capped itself at the canvas's backing store while "Signing as" and the Clear/Sign row took
   the paper's full width, because all three were siblings. Three left edges aligned and three right edges
   not - reported from a browser on 2026-09-08, and worst on the agent's stage where the paper is 640px in
   a 1264px viewport and unbounded on a larger screen.

   A custom property rather than 600px written twice: the frame's own comment explains that the number IS
   the canvas's 600x200 backing store, and two copies of a number that must agree with a markup attribute
   is how they come to disagree. It inherits, so the frame below reads it without naming a selector. */
.biztech-signature[b-ck7cu6itya] {
    /* The whole width of the card it is in. It was capped at the canvas's 600px backing store, which left the
       box short of its card's edge on a wide page; the canvas scales to the width (height: auto keeps 3:1) and
       biztech-signature.js maps the pointer through the displayed size, so drawing still lands under it. */
    --biztech-signature-inline-size: 100%;

    max-inline-size: var(--biztech-signature-inline-size);
}

.biztech-signature-frame[b-ck7cu6itya] {
    /* Dashed, so it reads as "write here" rather than as a disabled input.

       The #cbd2d9 fallback is gone: it was here because --mud-palette-lines-default was a token the
       theme had never set, and T24's palette always sets it. */
    border: 1px dashed var(--biztech-palette-outline);

    /* T29 N3 · R5.5. This was a literal 4px, which quietly contradicted BizTechThemeProvider's own
       comment - it says the 6px default means "no visual change anywhere except the signature frame,
       which was 4px and becomes 6px like everything else". The frame never got the message, because
       nothing pointed it at the variable. Read the variable; do not restate the number. */
    border-radius: var(--biztech-radius-default);

    /* Surface, not white - so the frame matches the panel it sits in when the page is dark.
       The CANVAS inside still paints its own opaque white before any stroke, and that is
       deliberate rather than an oversight: a transparent PNG on a dark background is an invisible
       audit record. See biztech-signature.js. */
    background: var(--biztech-palette-surface);

    /* The canvas has a fixed 600x200 backing store and max-width lets the DISPLAYED size shrink below it
       on a phone. The module scales pointer coordinates by the displayed/backing ratio, so drawing still
       lands under the finger - see positionOf() in biztech-signature.js. */
    max-inline-size: var(--biztech-signature-inline-size, 600px);
    overflow: hidden;
}

.biztech-signature-canvas[b-ck7cu6itya] {
    display: block;
    width: 100%;
    height: auto;

    /* Both needed on touch. touch-action stops the browser claiming the gesture for a scroll or a
       double-tap zoom before pointermove ever fires; without it the pad is unusable on a phone and works
       perfectly on the desktop it was tested on. */
    touch-action: none;
    cursor: crosshair;
}
/* /Components/Compliance/ComplianceFigureBar.razor.rz.scp.css */
/*
    W8-17 · F10.9. One compliance dimension: its head, a ring of the share done beside how many need attention, each answer
    on a row with a thin bar, and the derived label. W19-23 · redrawn as a card.

    🔴 NO DATA-VIZ PALETTE (D2). The declared semantic roles - success, warning and their derived containers - and nothing
    else. §16's U1 is about a CATEGORICAL ORDER and sequential ramps; roles that already exist are neither, so U1 stays open
    and this card escalates nothing.

    🔴 THE ATTENTION COLOURS ARE THE WARNING ROLE MOVED, NOT NEW COLOURS. Warning is darkened so warning TEXT clears 4.5:1 on
    a white surface, and at that lightness it read as a muddy brown. Each is computed from the role, so a tenant's warning and
    dark mode reach them with no hex here: 60% more chroma and 12 degrees towards orange, then -
    - the INK at the role's own lightness, for the count: measured 6.5:1 on the default light surface and 6.8:1 on dark;
    - the MARK at a lightness of at least 72%, for a bar - not text, so it needs no 4.5:1;
    - the TINT, 18% of the mark over the surface, for the ring's undone part.

    Every length is a 4px-scale step, the radius reads its variable, and there is no @media (prefers-color-scheme) anywhere
    (I16, R7.3). The two modes differ because the tokens do.
*/
.biztech-compliance-figure[b-hceaxh6ysc] {
    --biztech-figure-attention: oklch(from var(--biztech-palette-warning) max(l, 0.72) calc(c * 1.6) calc(h - 12));
    --biztech-figure-attention-ink: oklch(from var(--biztech-palette-warning) l calc(c * 1.6) calc(h - 12));
    --biztech-figure-attention-tint: color-mix(in srgb, var(--biztech-figure-attention) 18%, var(--biztech-palette-surface));

    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The title and what it applies to, and the View link at the row's end. */
.biztech-compliance-figure__head[b-hceaxh6ysc] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
}

.biztech-compliance-figure__title[b-hceaxh6ysc] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.biztech-compliance-figure__applies[b-hceaxh6ysc] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-compliance-figure__view[b-hceaxh6ysc] {
    flex: none;
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
    color: var(--biztech-palette-primary);
    text-decoration: none;
    white-space: nowrap;
}

.biztech-compliance-figure__view:hover[b-hceaxh6ysc] {
    text-decoration: underline;
}

/* The ring and the words beside it, with a rule under them before the rows. */
.biztech-compliance-figure__headline[b-hceaxh6ysc] {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-block-end: 16px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

/* The share done as a ring: the success role for what is done over the attention tint for the rest. The size is the
   ring's own, 80px, two steps of the 4px scale's 40. */
.biztech-compliance-figure__ring[b-hceaxh6ysc] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 80px;
    block-size: 80px;
    border-radius: 999px;
    background: conic-gradient(
        var(--biztech-palette-success) calc(var(--figure-done) * 1%),
        var(--biztech-figure-attention-tint) 0);
}

.biztech-compliance-figure__headline--quiet .biztech-compliance-figure__ring[b-hceaxh6ysc] {
    background: var(--biztech-palette-outline-subtle);
}

/* The hole, on the card's own ground, holding the share's words. */
.biztech-compliance-figure__ring-words[b-hceaxh6ysc] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    inline-size: 60px;
    block-size: 60px;
    border-radius: 999px;
    background: var(--biztech-palette-surface);
}

.biztech-compliance-figure__ring-figure[b-hceaxh6ysc] {
    font-size: var(--biztech-font-body1-size);
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.biztech-compliance-figure__ring-caption[b-hceaxh6ysc] {
    font-size: var(--biztech-font-caption-size);
    line-height: 1.2;
    color: var(--biztech-palette-text-secondary);
}

.biztech-compliance-figure__headline-words[b-hceaxh6ysc] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
    min-inline-size: 0;
}

.biztech-compliance-figure__headline-figure[b-hceaxh6ysc] {
    font-size: var(--biztech-font-h5-size);
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.biztech-compliance-figure__headline-figure--words[b-hceaxh6ysc] {
    font-size: var(--biztech-font-body1-size);
    font-weight: 600;
}

.biztech-compliance-figure__headline--outstanding .biztech-compliance-figure__headline-figure[b-hceaxh6ysc] {
    color: var(--biztech-figure-attention-ink);
}

.biztech-compliance-figure__headline--quiet .biztech-compliance-figure__headline-figure[b-hceaxh6ysc] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-compliance-figure__headline--met .biztech-compliance-figure__headline-figure[b-hceaxh6ysc],
.biztech-compliance-figure__headline--met .biztech-compliance-figure__headline-mark[b-hceaxh6ysc] {
    color: var(--biztech-palette-success);
}

.biztech-compliance-figure__headline-mark[b-hceaxh6ysc] {
    display: inline-flex;
    align-self: center;
    color: var(--biztech-palette-text-secondary);
}

.biztech-compliance-figure__headline-context[b-hceaxh6ysc] {
    font-size: var(--biztech-font-body2-size);
    color: var(--biztech-palette-text-secondary);
}

/* The rows, one gap apart. A <ul> because how many answers there are is information; its user-agent margin and indent go
   (UtilitySpecificityTests declares this one). */
.biztech-compliance-figure__figures[b-hceaxh6ysc] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-compliance-figure__figure[b-hceaxh6ysc] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-compliance-figure__row[b-hceaxh6ysc] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-compliance-figure__label[b-hceaxh6ysc] {
    color: var(--biztech-palette-text-primary);
}

.biztech-compliance-figure__link[b-hceaxh6ysc] {
    text-decoration: none;
}

.biztech-compliance-figure__link:hover[b-hceaxh6ysc] {
    text-decoration: underline;
}

.biztech-compliance-figure__count[b-hceaxh6ysc] {
    font-weight: 600;
}

/* A not-applicable answer reads quieter, and draws no bar: it is never folded into done. */
.biztech-compliance-figure__figure--quiet .biztech-compliance-figure__label[b-hceaxh6ysc],
.biztech-compliance-figure__figure--quiet .biztech-compliance-figure__count[b-hceaxh6ysc] {
    color: var(--biztech-palette-text-secondary);
    font-weight: 400;
}

/* An answer's thin bar: its share of what applies, on a quiet track. The length is the markup's --figure-share. */
.biztech-compliance-figure__bar[b-hceaxh6ysc] {
    display: block;
    inline-size: 100%;
    block-size: 4px;
    overflow: hidden;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-outline-subtle);
}

.biztech-compliance-figure__segment[b-hceaxh6ysc] {
    display: block;
    block-size: 100%;
    inline-size: calc(var(--figure-share) * 1%);
    min-inline-size: 8px;
    border-radius: var(--biztech-radius-pill);
}

.biztech-compliance-figure__segment--met[b-hceaxh6ysc] {
    background-color: var(--biztech-palette-success);
}

.biztech-compliance-figure__segment--outstanding[b-hceaxh6ysc] {
    background-color: var(--biztech-figure-attention);
}

.biztech-compliance-figure__segment--not-applicable[b-hceaxh6ysc] {
    background-color: var(--biztech-palette-text-disabled);
}
/* /Components/Compliance/PeriodFilter.razor.rz.scp.css */
/* W19-15 · the oversight lists' period filter: a row of fields and Apply above the page's figures, on UiFilterBar's card
   (§2a C3). The bar draws the card and carries the gaps (I18); every class is this file's markup (I19), and the bar's own row
   is reached through ::deep from the wrapper written here. */

/* The bar centres its row; this one aligns to its top, so an error under a date moves nothing beside it (W19-12). */
.biztech-period-filter-row[b-hx2hrr92gs]  .biztech-toolbar {
    align-items: flex-start;
}

/* Each field a column sized to a date, so two dates and Apply sit together at the row's start rather than spread across it. */
.biztech-period-filter-field[b-hx2hrr92gs] {
    flex: 0 1 14rem;
    min-inline-size: 0;
}

/* On a phone each field takes the row, and Apply follows under them. */
@media (max-width: 599.98px) {
    .biztech-period-filter-field[b-hx2hrr92gs] {
        flex-basis: 100%;
    }
}

/* Apply lines up with the controls, not their labels: offset by the label block a field has and a button has not - body2's
   size times its line height, plus .biztech-field's 4px gap (W19-12). Only while everything shares ONE row: a container
   query on the filter's own width, because a wrapped Apply on a line of its own wants no offset, and where it wraps depends
   on how many fields the page added - not on the viewport. */
.biztech-period-filter-row[b-hx2hrr92gs] {
    container-type: inline-size;
}

@container (min-width: 38rem) {
    .biztech-period-filter-row:not(.biztech-period-filter-wide) .biztech-period-filter-apply[b-hx2hrr92gs] {
        margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}

@container (min-width: 52rem) {
    .biztech-period-filter-wide .biztech-period-filter-apply[b-hx2hrr92gs] {
        margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}
/* /Components/Content/AssetSharePanel.razor.rz.scp.css */
/* W19-15 · the share panel's own look. Every selector names markup AssetSharePanel.razor writes, and a child component's
   box is reached through `::deep` from that wrapper (I19). Containers carry the gaps (I18); every colour and radius is a
   --biztech-* variable. */

/* The paper takes the tables' quiet edge and corners (W19-08); it keeps its own padding (I17). */
.biztech-asset-share[b-dye41gkfqo]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The panel's blocks, one column on one gap - they were spaced by a biztech-mt-* here and there and touched elsewhere. */
.biztech-asset-share-body[b-dye41gkfqo] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The fresh link and its note. */
.biztech-asset-share-link[b-dye41gkfqo] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The address, the expiry and Share: stacked on a phone, one row from md, aligned to the TOP so an error under a field
   moves nothing beside it. */
.biztech-asset-share-form[b-dye41gkfqo] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 12px 16px;
}

@media (min-width: 960px) {
    .biztech-asset-share-form[b-dye41gkfqo] {
        grid-template-columns: minmax(0, 1fr) minmax(0, 16rem) auto;
    }

    /* Offset by one label line, so the button sits level with the fields' boxes rather than their labels. */
    .biztech-asset-share-submit[b-dye41gkfqo] {
        margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}
/* /Components/Content/ContentPackReleaseReview.razor.rz.scp.css */
/*
    W25-01 · D14. The review's own spacing: a column with one gap (I18), nothing per child - the 8px the composer's field
    groups use. Logical properties, no colour.
*/

.biztech-pack-review[b-7j1216a8xk] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-pack-review-allowances[b-7j1216a8xk] {
    display: grid;
    gap: 4px;
    margin: 0;
}

.biztech-pack-review-allowance[b-7j1216a8xk] {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) 1fr;
    gap: 8px;
}

.biztech-pack-review-allowance dt[b-7j1216a8xk] {
    font-weight: 600;
}

.biztech-pack-review-allowance dd[b-7j1216a8xk] {
    margin: 0;
    overflow-wrap: anywhere;
}

/* W27-01 · A4. Add allowance: a column with one gap (I18), its fields a wrapping row with one gap. */
.biztech-pack-review-add[b-7j1216a8xk] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    inline-size: 100%;
    min-inline-size: 0;
}

/* W19-15 · aligned to the TOP rather than the foot, so an error under the origin moves nothing beside it; the button is
   offset by one label line (below) to sit level with the fields' boxes. */
.biztech-pack-review-add-fields[b-7j1216a8xk] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px;
}

.biztech-pack-review-add-fields > span[data-publish-pack-allowance-submit][b-7j1216a8xk] {
    margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
}

.biztech-pack-review-add-fields > span[b-7j1216a8xk] {
    min-inline-size: 0;
}

.biztech-pack-review-add-fields > span[data-publish-pack-allowance-origin][b-7j1216a8xk] {
    flex: 1 1 16rem;
}
/* /Components/Content/DocumentViewDialog.razor.rz.scp.css */
/*
    W2-33 · D6. The panel already draws its own hairline and a bottom margin, which are right on a page and
    wrong inside a dialog that draws its own border: two lines one pixel apart, and a gap under the actions.

    ::deep and the panel's own class, which is I19's declared way to reach a child - named after a parent
    this component's own markup writes. The panel keeps its padding, because UiDialog's panel has none by
    decision (I17), and DocumentViewPanel.razor.css is untouched: a portal section still mounts it inline.
*/
.biztech-document-dialog[b-8ie1bijw9v]  .biztech-document-viewer {
    border: 0;
    margin-bottom: 0;
}
/* /Components/Content/DocumentViewPanel.razor.rz.scp.css */
/*
    W2-09 · F4.12. The document viewer's shape — a head, a status line, the frame, and the actions.

    🔴 EVERY COLOUR IS A --biztech-palette-* ROLE AND THE RADIUS IS --biztech-radius-default.
    PortalStyleSheetTests sweeps scoped sheets for both, and DeckViewer.razor.css records what the sweep
    caught the first time it shipped: `var(--biztech-radius-md)`, a token that does not exist. There are no
    spacing variables in this system, so lengths are literal rem — AssigneeForm.razor.css's arrangement.

    🔴 EVERY LENGTH IS A WHOLE MULTIPLE OF THE 4px BASE UNIT (R5.1, R5.4), so the length sweep passes with
    NO layout-constant registry row. R5.4's own note is explicit that adding one is not the cheap way out of
    that failure, and it would also mean editing §5 of the guidelines — outside this card's projects.
    24rem is 96 base units; 0.5rem is 2; 1rem is 4.

    I16 · no prefers-color-scheme anywhere. The mode is a token, resolved by UiThemeTokens.
*/

.biztech-document-viewer[b-1ztnq49ncu] {
    /*
        It wears a surface of its own, so an inline host (a portal section) draws it as a panel rather than
        floating: a frame with no ground of its own would read as part of the page around it.
        DocumentViewDialog removes the border and the margin where the dialog already draws both (W2-33 · D6).

        🔴 OutlineSubtle, AND `--biztech-palette-divider` IS THE MISTAKE THIS FILE ALREADY MADE ONCE.
        EducationItemFrame.razor.css records it in as many words: that variable is not one of the palette's
        22 roles, "and a var() that resolves to nothing falls back to no colour at all, so the placeholder
        would have rendered invisible with every test still green. The colour sweep checks for literals, not
        for names that resolve." TokenSufficiencyTests is what does check, and it named this line.
        OutlineSubtle is the hairline role and it flips with the mode.
    */
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background-color: var(--biztech-palette-surface);
    padding: var(--biztech-document-viewer-padding, 1rem);
    margin-bottom: var(--biztech-document-viewer-gap, 1rem);
}

.biztech-document-viewer-head[b-1ztnq49ncu] {
    /*
        The heading and the way out on one line, with the close control pushed to the end. `gap` rather than
        a margin on the button, so the two never collide when a long title wraps.
    */
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
}

.biztech-document-status[b-1ztnq49ncu] {
    /*
        🔴 IT KEEPS ITS PLACE WHEN IT HAS NOTHING TO SAY, AND THAT IS R12.6a's SHAPE IN CSS RATHER THAN A
        NICETY. The region is present in every state so that its FIRST message is an announcement (see the
        component), which means it is empty on the Inline path — and an empty box that then grows by its own
        height would shift the frame down on the frame where the reader is least able to predict it. R9.10's
        argument about a loading region, applied to a live one.
    */
    min-height: 1.25rem;
    margin-top: 0.5rem;
}

.biztech-document-frame[b-1ztnq49ncu] {
    /*
        🔴 THE FOCUS TARGET, AND IT MUST SHOW WHERE THE FOCUS IS. R12.2 makes this element focusable so a
        keyboard reader can reach the framed document's own pager; R3.11 then requires the ring, and app.css
        declares it once for every custom interactive element — so there is deliberately NO outline
        declaration here. `outline: none` would be an R12.8 violation and W0-53 measured what it cost when
        MudBlazor's sheet did it globally.
    */
    margin-top: 1rem;
}

.biztech-document-audio[b-1ztnq49ncu] {
    /*
        W25-04 · D15. The browser's own player, as wide as the panel so its scrubber has room, set where the frame
        would sit. No height: the control draws its own.
    */
    display: block;
    inline-size: 100%;
    margin-top: 1rem;
}

.biztech-document-video[b-1ztnq49ncu] {
    /*
        W31-05 · D3. The browser's own player, as wide as the panel and no taller than the frame it replaces, so a
        portrait video does not push the download below the fold at 375px. The element keeps the video's own ratio.
    */
    display: block;
    inline-size: 100%;
    max-block-size: 24rem;
    margin-top: 1rem;
}

.biztech-document-object[b-1ztnq49ncu] {
    /*
        🔴 A HEIGHT IN rem RATHER THAN A VIEWPORT UNIT OR AN ASPECT RATIO, AND THE REASON IS THE 375px
        ACCEPTANCE. `100vh` on a phone is the wrong number twice over — the browser chrome is not in it, and
        it ignores the panel's own padding — while an aspect-ratio tall enough to read a portrait page would
        make the frame taller than the screen at narrow widths. 24rem is what the deck reading area uses and
        it is measured against the same acceptance.

        `width: 100%` with `border: 0`: the frame's border is the WRAPPER's, so a document with its own white
        ground does not draw a second line inside ours.

        🔴 AND NO overflow WRAPPER AROUND IT. PortalLandmarkOverflowTests' header records why the obvious fix
        is the wrong one here: one overflow-x on a wrapper excludes its whole SUBTREE from the landmark walk,
        so hiding the frame inside a scroller would turn a real overflow into a green test measuring almost
        nothing. The frame is exactly the element somebody would reach for that with, which is what makes
        DocumentViewerViewportTests' Eligible guard load-bearing on this surface.
    */
    display: block;
    width: 100%;

    /* 24rem unless the host sets this: a portal page's document section sets it from the theme's viewer height. */
    height: var(--biztech-document-view-height, 24rem);
    border: 0;
    border-radius: var(--biztech-radius-default);
    background-color: var(--biztech-palette-background);
}

.biztech-document-actions[b-1ztnq49ncu] {
    /*
        Download first, Reopen after it — the download is the one control present in every state, and R9.17's
        "one order for the whole console" argument applies to a pair as much as to a list: a reader scanning
        this panel twice should not have to find the same control in two places.

        `flex-wrap` so the pair stacks rather than overflowing at 375px, which is what R13.3 asks of every
        desktop-only row.
    */
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
}
/* /Components/Content/LibraryChip.razor.rz.scp.css */
/* A label beside its control, on /library's bar. See LibraryChip.razor's header for why that is one
   component rather than the same declarations written at two call sites.

   🔴 THIS FILE USED TO DRAW A BOX AROUND BOTH, AND THE BOX IS WHAT WENT. Decision 2's chip put the label
   and the control inside one bordered rectangle, which meant taking the control's own border away so
   there would not be two. `app.css` then rings the CONTROL on focus — it holds exactly one
   `outline: 2px solid` declaration for every custom interactive element (R3.10) and
   `.biztech-input:focus-visible` is in its list — so clicking into the search field drew a second rounded
   box around the input ALONE, starting after the word "Search" and cutting across this file's border. The
   label was left outside the box its own control was in. Reported from a browser as "search label and
   search input is misaligned, showing as two different items", and it is the search field rather than the
   two selects because a text input matches `:focus-visible` on a POINTER press.

   🔴 THE FIX IS NOT A RING OF THIS FILE'S OWN, AND THAT IS THE POINT. Moving the indicator to the box
   would have meant a second focus-ring idiom plus an `outline: none` on the control —
   `PortalStyleSheetTests.The_focus_ring_is_declared_once_and_covers_every_custom_interactive_element`
   sweeps every scoped sheet for that property with a deliberately empty exemption list, and
   DocumentViewPanel.razor.css records the same refusal one surface along. So the box goes instead: the
   control keeps its own border, the ring lands on the thing that IS the visible box, and the label sits
   beside it the way a label does everywhere else in the application. What is left here is the ROW — which
   is all the chip shape ever needed to be.
   `ResourceLibraryViewportTests.A_focused_chip_paints_one_box_rather_than_two` is the guard.

   🔴 ::deep BECAUSE THE FIELD, ITS LABEL AND ITS CONTROL ARE THE SEAM'S ELEMENTS, NOT THIS COMPONENT'S.
   I19: a scoped rule reaches this component's own markup and nothing else, and the compound Blazor
   stamps is the selector's LAST one — so `.biztech-library-chip .biztech-field` would be inert, silently,
   with no error and no warning. The chip's own root takes no ::deep, because this file renders that div. */
.biztech-library-chip[b-6oybbtudnq] {
    display: inline-flex;
}

/* 🔴 THE SEARCH FIELD'S SHAPE: it is handed a third of the bar and has to take it, where a narrowing is
   as wide as the longest thing it can say. See LibraryChip.Fill. */
.biztech-library-chip[data-chip-fill][b-6oybbtudnq] {
    display: flex;
    inline-size: 100%;
}

/* 🔴 W6-53's .biztech-field-inline (app.css:1504) ALREADY DOES LABEL-BESIDE-CONTROL — flex-direction:
   row; align-items: center; gap: .25rem, with :1514's margin: 0 / white-space: nowrap on the label —
   built for the media toolbar. This rule rebuilds that idiom rather than reusing it, with its own 8px
   gap. Deliberately: R8.7 blocks routing a styling class through UiSelect.Class, so `.biztech-field-
   inline` cannot travel in from here, and .biztech-field-inline .biztech-input's min-inline-size: 12rem
   (app.css:1529) would be wrong here — a fixed minimum width fights the compactness a filter row needs,
   and the search field's own floor is [data-library-search]'s in LibraryControlBar.razor.css. Do not
   refactor to use it. */
.biztech-library-chip[b-6oybbtudnq]  .biztech-field {
    /* 🔴 STATED, NOT ASSUMED, AND ITS ABSENCE IS A DEFECT THIS FILE HAS ALREADY SHIPPED ONCE.
       .biztech-field declares `flex-direction: column` (app.css:1433) — a label ABOVE a control, which is
       right for a form and is the opposite of this. Everything else in the rule applied correctly and the
       direction did not, so the label stacked over the select inside a box pinned to
       --biztech-control-height and the control got the remainder: measured at 8px in Chromium, with the
       select's arrow hanging out below the border. Reported as "Filter button CSS is broken".
       ResourceLibraryViewportTests.Every_chip_puts_its_label_beside_a_control_that_has_height is the
       guard, and it is a browser probe because no bUnit test and no grep can see this: the markup is
       identical either way. */
    flex-direction: row;

    /* `center`, against the control's own box. With the border back on the control there is a box to
       centre against, and the label is the thing that moves — R9.1's label-above is what this departs
       from, and the departure is now the only one: no second border, no second radius, no height of its
       own. The control's --biztech-control-height IS the row's height. */
    align-items: center;
    gap: 8px;
}

/* The filling chip's field fills it too, or the row would leave the control at its content width inside a
   track three times as wide. */
.biztech-library-chip[data-chip-fill][b-6oybbtudnq]  .biztech-field {
    display: flex;
    inline-size: 100%;
}

.biztech-library-chip[b-6oybbtudnq]  .biztech-field-label {
    /* 🔴 NO SIZE AND NO COLOUR OF ITS OWN ANY MORE, AND THE BOX IS WHY. This took the caption step
       because it sat INSIDE the control's box, where a full-size label would have read as a value; beside
       one it is an ordinary field label and app.css:1463 already says what those are — body2's measure at
       subtitle2's weight, secondary ink. That rule's own note records what shrinking a label cost the last
       time ("labels are too small compared to input text", reported on /library/new), and there is no
       longer anything here to buy it back.

       `nowrap` stays: it is about the ROW, not about the box. A two-line label on a one-line bar is what
       it prevents. */
    white-space: nowrap;
}

/* 🔴 THE SEARCH FIELD TAKES THE REST OF ITS CHIP, AND `inline-size: 100%` IS NOT WHAT DOES IT.
   .biztech-input carries that (app.css:1691), which in a COLUMN meant "the field's width" and on a ROW
   means 100% of the field with the label's width still to pay for — so the two overflow and the control
   is shrunk back by flex-shrink to whatever is left, a width nothing states. `flex: 1` states it: the
   control takes the free space after the label. `min-inline-size: 0` is the half that is easy to miss —
   a flex item's automatic minimum is its content size, and for an <input> that is its `size` attribute's
   20 characters, which would keep the chip from shrinking below ~177px on a phone. .biztech-field-inline
   meets the same wall from the other side with a 12rem floor; this row wants the floor on the CHIP
   ([data-library-search]) rather than on the control, so that the two narrowings beside it can shrink to
   their content. */
.biztech-library-chip[data-chip-fill][b-6oybbtudnq]  .biztech-input {
    flex: 1;
    min-inline-size: 0;
}
/* /Components/Content/LibraryControlBar.razor.rz.scp.css */
/* 🔴 I18 · THE GAP IS THE CONTAINER'S. Every child below is spaced by a gap declared here and carries no
   margin of its own — two margins plus a gap is 24px down the rows and 16px across the columns, a grid
   that looks misaligned for a reason nobody can see in the markup. */
[data-library-control-bar][b-doh72zxasv] {
    display: flex;
    flex-direction: column;

    /* Two things stack here now, not three: the row, and the count below it. 8px rather than 12px
       because the count is a reading ABOUT the row rather than a sibling of it — R5.9's "a label and its
       value stay closer to each other than to the next pair", applied to a bar and its own result. */
    gap: 8px;
}

/* 🔴 ONE ROW: THE SEARCH, THE TWO NARROWINGS AND THE VIEW TOGGLE. The search field used to hold a line
   of its own above this one, full width — on the busiest screen in the platform that is a whole row of
   chrome before the first result, and the field is the widest instrument here rather than the one most
   in need of the room. Reported from a browser.

   🔴 `end`, NOT `center`, AND NOT `baseline`. Every box on this row is one --biztech-control-height tall
   and they are all chips now, so there is nothing to offset — but `end` is what keeps that true if one
   of them ever grows a label block again, which is I20's argument for the checkbox that lines up with
   its neighbour's label. `center` would split the difference and align nothing to anything. */
[data-library-narrowings][b-doh72zxasv] {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 12px;
}

/* The console's one filter bar: UiToolbar's card - its subtle edge, its padding, the surface and the theme's card
   depth - so the library's row reads as the case list's, the board's and the presentations'. */
[data-library-narrowings][b-doh72zxasv] {
    min-inline-size: 0;
    padding: 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

/* 🔴 A 28rem COLUMN, AND A FLOOR UNDER IT. W19-15: every W19 list's search box is a 28rem column, and this
   one was a third of the bar - about 30rem at 1440px and 15rem at a tablet, so it read as a different
   instrument on every screen. `flex: 0 1 28rem` is a basis this row may SHRINK when the chips beside it need
   their content width. The floor is what stops that shrinking from producing a search field too narrow to
   read what has been typed into it; below it the row wraps instead, which is the phone rendering. */
[data-library-search][b-doh72zxasv] {
    flex: 0 1 28rem;
    min-inline-size: 200px;
}

/* The two narrowings travel together: they wrap as a pair rather than one of them being orphaned onto a
   line with the toggle. Their own 8px is tighter than the row's 12px, which is what makes them read as
   one group rather than as two more items on the row (R5.9). */
[data-library-chips][b-doh72zxasv] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* 🔴 THE TRAILING EDGE, CLAIMED RATHER THAN LEFT OVER. `space-between` used to put the toggle here,
   which worked only while the status region sat between the chips and it and could absorb the slack.
   The count is below the row now, so an auto margin is what reserves the edge — and it is still the
   CONTAINER's spacing rather than a margin the toggle carries about itself (I18).

   🔴 AND IT IS `[data-library-view]` RATHER THAN `[data-library-view-toggle]`, WHICH IS I19 RATHER THAN
   A NAMING PREFERENCE. The second is LibraryViewToggle's own root: a scoped rule naming it is stamped
   with THIS component's scope, matches nothing, and fails with no error and no warning. The wrapper is
   an element this component renders, so the rule reaches it. */
[data-library-view][b-doh72zxasv] {
    margin-inline-start: auto;
}

/* 🔴 NO `> *` RULE ANYWHERE IN THIS FILE, AND I19 IS WHY. A scoped `> *` can reach a CHILD COMPONENT's
   root, and the guard sweep refuses any scoped selector ending in a universal one — with no exemption
   list, on purpose. Every selector above names an element this file renders. */
/* /Components/Content/LibraryFolderManager.razor.rz.scp.css */
/* W2-22 · F4.2. The folder management panel's own presentation, and nothing else's.
   W2-22b · it edits ONE folder — the one the hierarchy chose — rather than every folder at a level.

   Lengths are multiples of the 4px base unit (R5.1, R5.4), so no layout-constant registry row is needed.
   Colours come from --biztech-* only (R3), which PortalStyleSheetTests asserts over every scoped sheet.
   No prefers-color-scheme anywhere (I16): the mode is a token, not a media query.

   🔴 I18, TWICE OVER, AND BOTH HALVES WERE LIVE HERE. The panel spaced its blocks with a biztech-mb-*
   on each child, which ADDS to whatever a parent already spaces - the failure the invariant names. And
   inside each block nothing spaced anything at all: two fields, two consequence sentences and four
   controls touched, because biztech-pa-4 spaces a panel from its border and nothing spaced its contents
   from each other. Every gap below is on a container, and no child here carries a margin.

   🔴 I19. EVERY SELECTOR ENDS ON A CLASS THIS FILE'S OWN MARKUP WRITES. Nothing reaches into UiTextField,
   UiSwitch, UiButton or UiIconButton: the pair below is a GRID, so its tracks size the fields without any
   rule having to name them, and the action row's spacer is a <span> this file writes rather than a
   margin on a child component's root - which would be inert, with no error and no warning. */

/* The panel's two halves: create, and the chosen folder. */
.biztech-folder-panel[b-pc6cou0o4e] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Inside one half. Tighter than the gap between halves, so the two read as two things - the divider
   between them is doing less work than it looks. */
.biztech-folder-block[b-pc6cou0o4e] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Name and slug share a row where there is room for one. They are a pair - a folder's label and its
   address - and stacking them put the button below the fold on the narrow pane this panel now sits in.
   Below sm they stack, because two 40px controls and their labels do not fit 375px side by side. */
.biztech-folder-pair[b-pc6cou0o4e] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

@media (min-width: 600px) {
    .biztech-folder-pair[b-pc6cou0o4e] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Which folder the form below is about: its glyph, its name, and the level its move controls act in. */
.biztech-folder-chosen[b-pc6cou0o4e] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
}

/* 🔴 ONE ROW FOR FOUR CONTROLS, WHICH USED TO BE FOUR ROWS. Save and the three icon buttons were
   block-level children of the panel, so they stacked - a save button, then an up arrow, then a down
   arrow, then a delete, each on a line of its own. flex-wrap rather than a media query: the row wraps
   when the pane is too narrow for it, at whatever width that turns out to be. */
.biztech-folder-actions[b-pc6cou0o4e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;

    /* W19-15 · a foot under the quiet rule, the shape every W19 form's actions have. */
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* Pushes the three icon buttons to the end, away from Save. The delete is the destructive one and it
   ends up furthest from the control a reader reaches for most - R9.13's blast radius, applied to
   placement rather than to wording. A <span> rather than margin-inline-start on the next child, because
   that child is a component's own root and a scoped rule cannot reach it (I19). */
.biztech-folder-actions-spacer[b-pc6cou0o4e] {
    flex: 1 1 auto;
}
/* /Components/Content/LibraryFolderTree.razor.rz.scp.css */
/* W2-06 · F4.1. The folder tree's own presentation, and nothing else's.
   W2-22b · F4.2. It is a chooser now: one row is marked, and no row leads anywhere.

   Lengths are multiples of the 4px base unit (R5.1, R5.4), so no layout-constant registry row is needed -
   and R5.4's note is explicit that adding one is not the cheap way out of that sweep.

   Colours come from --biztech-* only (R3), which PortalStyleSheetTests asserts over every scoped sheet it
   discovers. No prefers-color-scheme anywhere (I16): the mode is a token, not a media query.

   🔴 I19. EVERY SELECTOR BELOW ENDS ON A CLASS OR ELEMENT THIS FILE'S OWN MARKUP WRITES. Blazor stamps
   the scope attribute on a selector's LAST compound, so a rule ending in a child component's element is
   stamped on markup this file did not write and is inert - no error, no warning, and a class with no
   effective rule renders exactly like a class with none. That is why the chevron's rotation is on a
   <span> this file writes rather than on UiIcon's <svg>, and why nothing here reaches into UiIcon.

   🔴 I18. SPACING BETWEEN SIBLING ROWS IS A GAP ON THE LIST, never a margin per row. */

.biztech-library-branch[b-yer7n94jmd] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;

    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Nested levels step in by five base units, which is the indent the hierarchy is read from. At the eight
   levels CK_ContentFolders_Depth permits that is 160px of the rail - which the rail has, because it is a
   20rem grid track and the deepest name still gets 160px of its own. The old 12px step was chosen when
   the tree shared a 375px screen with the listing; it does not any more. */
.biztech-library-branch .biztech-library-branch[b-yer7n94jmd] {
    padding-inline-start: 20px;
    margin-block-start: 2px;
}

/* One row: chevron, folder, name. Every row is a <button role="treeitem"> (W27-05), the root's included. */
.biztech-library-row[b-yer7n94jmd] {
    display: flex;
    align-items: center;
    gap: 8px;

    inline-size: 100%;

    /* R5.8's touch target under a coarse pointer. */
    min-block-size: 44px;
    padding-inline: 8px;

    /* The button half arrives with user-agent defaults - centred 13px Arial and a shrink-to-fit width -
       which app.css records the board card having had to undo. Declared rather than inherited. */
    font: inherit;
    /* W19-15 · body2, as the console's other trees and the agent's knowledge tree (W19-17) read. */
    font-size: var(--biztech-font-body2-size);
    text-align: start;
    color: var(--biztech-palette-text-primary);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-pill);

    cursor: pointer;

}

.biztech-library-row:hover[b-yer7n94jmd] {
    background-color: color-mix(in srgb, currentcolor 6%, transparent);
}

/* 🔴 THE ONE LOUD THING ON THE PAGE, AND IT IS LOAD-BEARING: it is the only thing that says which folder
   the panel on the right is editing. A tonal container rather than the role itself - PrimaryContainer is
   derived from Primary over the surface it is read on, and its OnPrimaryContainer partner is measured
   with it (ADR 0026 D-H), so this pair cannot fail contrast on a palette that boots. */
.biztech-library-row-chosen[b-yer7n94jmd] {
    background-color: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
    font-weight: 500;
}

.biztech-library-name[b-yer7n94jmd] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* The chevron: a fixed box whether or not a glyph is in it, so the root row's names line up with every
   name below it. */
.biztech-library-chevron[b-yer7n94jmd] {
    display: inline-flex;
    flex: none;
    inline-size: 20px;
    block-size: 20px;

    color: var(--biztech-palette-text-secondary);
    transition: rotate var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The chosen row's chevron takes the row's ink, or it would stay grey on a tinted fill. */
.biztech-library-row-chosen .biztech-library-chevron[b-yer7n94jmd] {
    color: inherit;
}

/* W27-05 · the open state is the page's now (the tree is an ARIA tree, no <details>), so the rotation follows
   a class the markup sets from that state. */
.biztech-library-chevron-open[b-yer7n94jmd] {
    rotate: 90deg;
}

/* R6.8. The rotation is the only motion in this file, and it is the one thing here that respects a
   reader who asked for none. */
@media (prefers-reduced-motion: reduce) {
    .biztech-library-chevron[b-yer7n94jmd] {
        transition: none;
    }
}
/* /Components/Content/LibraryPager.razor.rz.scp.css */
/* W19-15 · /library's pager: where the reader is on the left, Previous and Next at the row's end - /people's and the
   case list's row. Both selectors name markup LibraryPager.razor writes (I19); the gaps are the containers' (I18). The
   row wraps on a phone rather than scrolling: three short controls have nothing to clip. */
.biztech-library-pager[b-jf0eiuynka] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.biztech-library-pager-controls[b-jf0eiuynka] {
    display: flex;
    align-items: center;
    gap: 8px;
}
/* /Components/Content/LibraryRows.razor.rz.scp.css */
/* 🔴 THE TABLET BAND, WHERE THIS TABLE STOPPED FITTING — AND WHY IT IS SOLVED HERE RATHER THAN WITH A
   SCROLL REGION.

   R13.8 offers two answers to a table wider than its landmark: wear the labelled scroll region, or record
   why it cannot clip. This component takes the second, and the exemption is EARNED by
   ResourceLibraryViewportTests and DocumentViewerViewportTests asserting Assert.Empty(reading.Spilling) at
   375 / 768 / 1440 in both modes. The header of LibraryRows.razor records the measurement that closed the
   first option: `.biztech-table-scroll` declares `overflow-x: auto`, and the landmark-overflow walk
   excludes anything inside a clipping ancestor — so wrapping took /library from 126 judgeable elements to
   34, below the `Eligible * 2 > Examined` guard those suites carry precisely to catch a walk that has
   stopped measuring anything. Wrapping would trade the rendered proof for a source-text assertion.

   So the table has to FIT, and measured on the real page at 768px it no longer did. The numbers, taken
   from the failing suites rather than estimated:

     before this redesign   753 against a limit of 753   — exactly at the edge, with no slack at all
     + "View" → "Preview"   770                          — +17px, one wider button
     + the Owner column     838                          — +68px

   🔴 TASK 5 · RE-MEASURED RATHER THAN EXTENDED, and the difference matters. This series is kept as
   history, not continued by simple addition: `ResourceLibraryViewportTests` measures the container
   `LibraryRows` renders into at 768px TODAY as 480px, not 753px — a different landmark than whatever page
   the line above was measured against, from a layout change outside this redesign's scope. Adding "+ the
   Scan column" and "− the actions menu" on top of 838 would silently mix two container widths into one
   arithmetic, which is worse than the staleness Task 2 flagged and left alone rather than guessed past.

   🔴 WHAT TASK 5 ACTUALLY MEASURED, 2026-09-16, against today's page and today's 480px container at
   768px — via a temporary `page.EvaluateAsync` scaffold in `ResourceLibraryViewportTests.cs`, run once,
   read, and deleted rather than committed (the same technique reproduces it, if this ever needs
   re-checking):

     the table as it ships today                               480px, against a 480px container — fits
     Owner + Scan both forced visible, ordinary 12px padding    480px — STILL fits
     the same, but the OLD five-control actions cell rebuilt
       with the real classes git history records for it (this
       file at d2e0305b: two outlined buttons, two text
       buttons, each with its `.biztech-button-label` span)     593px — 113px OVER the 480px container

   🔴 THE SCAN COLUMN'S OWN COST DID NOT MEASURE AS A POSITIVE NUMBER, AND THAT IS REPORTED RATHER THAN
   FORCED. Toggling the Scan column on and off against today's real actions cell, at the ordinary
   (unbanded) 12px padding, produced 480px either way. `BrowserContentFolders`' fixture text (`ScanWords`,
   `row.Owner`) is short enough that `.biztech-table`'s `inline-size: 100%` lets the browser compress cell
   content to fit rather than force the table wider — a longer scan detail or a real email address as an
   Owner would cost something measurable; this fixture's does not, and writing a guessed number here in
   its place is exactly what this task's brief said not to do.

   🔴 THE ACTIONS COLLAPSE IS WHERE THE REAL SAVING IS, AND IT IS WHAT KEEPS THIS TABLE FITTING AT ALL.
   The reconstructed old cell overflows the 768px container by 113px; today's cell — one star, one
   trigger — does not overflow it at all, on the SAME fixture data. That is at least a 113px saving, and
   more against a longer Owner value where the four old buttons and a longer string would have compounded
   rather than measured independently.

   🔴 W16-17 · THE BAND STAYS, AND SO DOES THIS TABLE'S LAYOUT — BUT THE SENTENCE BELOW IT NO LONGER
   DERIVES FROM app.css, SO READ THIS BEFORE TRUSTING IT.

   W16-17 moved the application's card reflow from sm (599.98px) to md (959.98px). That would have made
   the band's own justification false: it hid Owner and Scan across 600–899.98px on the strength of
   "below 600px the reflow brings the value back with its own label", and with the reflow at md that
   range is the CARD layout, where this scoped `display: none` — (0,2,0) plus a scope attribute —
   outranks `.biztech-table-reflow .biztech-td { display: block }` in app.css. Owner and Scan would have
   been neither visible nor reachable at those widths.

   🔴 SO THIS TABLE OPTS OUT OF THE REFLOW INSTEAD, and the opt-out is what keeps the band honest.
   LibraryRows.razor passes `Reflow="UiTableReflow.Sm"` and states the measurement: every row here
   carries a UiMenu, and with the rows reflowed neither /library's nor the document viewer's row menu
   could be pressed at 768px — `.biztech-menu-scrim` intercepted every click, and five browser facts
   timed out. `Sm` rather than "does not reflow": turning it off outright took the card layout away on a
   phone too, and four more facts went red at 375px.
   UiMenu's own limitation is not fixable from a call site; ManagedRecordList.razor records that it
   "belongs on its own card".

   🔴 THE TWO HALVES ARE A PACKAGE, AND REMOVING EITHER ONE ALONE WAS MEASURED. Deleting this band while
   this table still renders as a table puts it past the landmark at 768px — five different browser facts,
   run and read. Keeping the band while the rows reflow hides two columns with no way back. Change both
   together or neither.

   `::deep` because `<th>` and `<td>` are `UiTh`'s and `UiTd`'s own elements, not this component's. That is
   the mechanism the guidelines name for exactly this (§8: "an entry's box is declared by `::deep
   .biztech-tab` in the parent's sheet") and the one I19 points at — "say `::deep` and name the child's own
   class". Passing a class through `Class=` is the alternative and R8.7 reserves that for spacing. */
/* 🔴 R5.8's 44px ON THE FOLDER LINK, AND IT IS A GUARANTEE MOVED RATHER THAN A NEW ONE. R5.8 exempts the
   operator console "by decision (mouse at a desk)"; W2-06 DECLINED that exemption for the folder tree,
   because choosing a folder was the narrowest affordance in the application. The tree is gone and the
   folders are rows here now, so the target moves with them - the alternative is a rule quietly dropped
   along with the element it was written for.

   On the ANCHOR rather than on the cell: the cell's block padding is the row's height, which the reflow
   below 600px rewrites on the surfaces that still reflow, and a target has to be the thing a thumb
   actually lands on. `inline-flex` so the box can take a height at all - an inline anchor's box does not. The glyph beside it is the cell's, not
   this element's, so the two still sit on one line.

   Scoped under the listing's own root, and NOT `::deep`: this anchor is rendered by this component, so
   the scoped attribute already reaches it. `::deep` is for `UiTh`'s and `UiTd`'s own elements, which is
   what the band below needs it for. */
@media (pointer: coarse) {
    .biztech-library-folder-link[b-vq2zczpyul] {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }
}

@media (min-width: 600px) and (max-width: 899.98px) {
    /* The Owner column, header and cells together, so the table can never carry a column with nothing
       under it. The cell is selected by SIGNATURE — `UiTd` renders `DataLabel` as `data-label`, which the
       reflow already depends on — and only the header needs position, which `[data-shows-owner]` makes
       safe. See the attribute's note in LibraryRows.razor. */
    [data-shows-owner][b-vq2zczpyul]  thead th:nth-child(3),
    [data-shows-owner][b-vq2zczpyul]  td[data-label="Owner"] {
        display: none;
    }

    /* And the inline padding comes in from 12px to 8px on what remains. 8px is still a real gutter — it is
       `biztech-gap-2`'s value and the reflow's own cell padding — and at five remaining columns it is the
       40px that turns a fit into a comfortable one rather than another edge to sit on. Block padding is
       untouched: the row's height is a touch target (R12.8), not spare width. */
    [data-shows-owner][b-vq2zczpyul]  .biztech-th,
    [data-shows-owner][b-vq2zczpyul]  .biztech-td {
        padding-inline: 8px;
    }

    /* The Scan column joins Owner in the band where six columns do not fit a tablet. The cell is
       selected by SIGNATURE — `data-label` — and only the header needs position.

       🔴 BOTH ATTRIBUTES, AND THAT IS I15 RATHER THAN CAUTION. Scan is the sixth column only when Owner
       renders too; with `ShowOwner` false the sixth child is the ACTIONS header, and this rule would
       hide it with no error and no warning. Scoping to the pair makes the position mean what it says.

       🔴 AND THE CELL CARRIES THE SAME PAIR, WHICH IT DID NOT AT FIRST. The cell is selected by
       signature rather than by position, so `[data-shows-scan]` alone was correct about WHICH cell —
       and wrong about WHEN. A surface passing `ShowScan` without `ShowOwner` would, across this band,
       keep a Scan HEADER the paired rule above declined to hide while every Scan CELL under it
       vanished: a column of nothing, and every body cell after it shifted left by one. No surface does
       that today, which is exactly why nothing would have caught it. The two halves of one column hide
       on one condition or the header and the cells disagree. */
    [data-shows-owner][data-shows-scan][b-vq2zczpyul]  thead th:nth-child(6),
    [data-shows-owner][data-shows-scan][b-vq2zczpyul]  td[data-label="Scan"] {
        display: none;
    }
}

/* ── W19-15 · the listing's look, on the other W19 lists' terms ──────────────────────────────────────

   The table sits on the quiet card: the subtle edge, corners twice the theme's radius and the surface, as
   /people's and /case-types' do. On a WRAPPER this component writes rather than on a scroll region - the
   header above records why this table has none - and the wrapper clips nothing, so a row menu's panel still
   opens past its edge. The last row's own hairline gives way to the card's edge, or the foot reads as a
   double rule. Below sm the rows are cards (Reflow="Sm"), and those cards take the same edge, corners and
   surface. Every colour and radius is a --biztech-* variable.

   The edge is an outline drawn inside the box, not a border. A 1px border took 2px from the table, and
   ResourceLibraryViewportTests holds the listing to the container's full width; an outline takes none. */
@media (min-width: 600px) {
    .biztech-library-table[b-vq2zczpyul] {
        outline: 1px solid var(--biztech-palette-outline-subtle);
        outline-offset: -1px;
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: var(--biztech-palette-surface);
    }

    .biztech-library-table[b-vq2zczpyul]  tbody .biztech-table-row:last-child .biztech-td {
        border-block-end: 0;
    }
}

@media (max-width: 599.98px) {
    .biztech-library-table[b-vq2zczpyul]  .biztech-table-row {
        border-color: var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: var(--biztech-palette-surface);
    }
}

/* The menu and the star at the row's end, so every row's trigger lines up down the column - the gap is the
   container's (I18). */
.biztech-library-row-actions[b-vq2zczpyul] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Content/LibraryTiles.razor.rz.scp.css */
/* Library 3 · Decision 4 — the grid's geometry.

   🔴 NO `> *` RULE ANYWHERE IN THIS FILE, AND I19 IS WHY. A scoped `> *` can reach a CHILD COMPONENT's
   root, and the guard sweep refuses any scoped selector ending in a universal one — with no exemption
   list, on purpose. Every size below comes from a grid or a flex container, so no rule has to reach a
   child. LibraryControlBar.razor.css closes with the same note for the same reason.

   🔴 AND NO `::deep` EITHER, WHICH IS WORTH STATING RATHER THAN LEAVING TO BE NOTICED. Every element
   selected here is rendered by LibraryTiles.razor itself, so the scope attribute Blazor stamps already
   reaches it. `::deep` is what LibraryRows.razor.css needs for `UiTh`'s and `UiTd`'s own elements; this
   file draws its own boxes and hands its children nothing but a slot to sit in. */

/* 🔴 A WRAPPING GRID SIZED BY THE TRACK, NOT BY THE COUNT. `auto-fill` with a minimum means the number
   of columns is the viewport's answer rather than a breakpoint's, so there is no width at which this
   has to be re-measured — which is what keeps ResourceLibraryViewportTests' sweep at 375 / 768 / 1440
   a check rather than the thing that decides the layout.

   208px is the track floor: 52 scale steps, wide enough for a 4:3 picture a reader can recognise a
   document from, and narrow enough that a phone at 375px gets one full-width column rather than two
   unreadable ones. */
[data-library-tile-grid][b-581be0gom7] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(208px, 1fr));
    gap: 16px;
}

/* I18 · the gap is the container's and no child carries a margin. The picture and the caption are the
   two children; stacking them is the whole of a tile. */
[data-library-tile][b-581be0gom7] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* 🔴 THE BOX IS RESERVED BEFORE THE BYTES ARRIVE, WHICH IS WHY `aspect-ratio` IS HERE AND NOT A HEIGHT.
   Every picture on the page is fetched by the browser, lazily and out of order, and a box that took its
   height from its image would reflow the whole grid once per arrival — R9.10's "nothing below moves when
   the content arrives", applied to twenty independent arrivals rather than one.

   `position: relative` is the image's containing block; `overflow: hidden` is what makes the radius
   clip it. The mark sits in normal flow and is centred by the flex, so it is ALREADY DRAWN when the
   image is positioned over it — which is the degraded tile's whole mechanism (see the component's
   header): no onerror handler, no JavaScript, nothing to fall back TO because nothing was replaced. */
/* 🔴 THE PICTURE IS AN ANCHOR NOW, SO IT HAS TO BE TOLD NOT TO LOOK LIKE ONE. `display: flex` already
   overrides the inline default, but an <a> also inherits the link colour and an underline — which would
   paint the folder glyph and the "Folder" caption inside it blue and underlined, and tint a thumbnail's
   surround. The caption below is the visible link; this is the same destination made pressable.

   `color: inherit` rather than a palette role: whatever the mark inside it would have been as a <div> is
   what it stays as an <a>. */
[data-library-tile-picture][b-581be0gom7] {
    color: inherit;
    text-decoration: none;

    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    /* W19-15 · the quiet edge and corners twice the theme's radius, the cards' and the tables' (W19-08). */
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background-color: var(--biztech-palette-surface);
}

/* `inset: 0` rather than a width and a height, so the image takes the box the aspect-ratio already
   decided; `object-fit: cover` fills it without distorting a portrait scan into a landscape one.
   `display: block` removes the inline baseline gap an <img> otherwise reserves under itself. */
[data-library-tile-picture] img[b-581be0gom7] {
    position: absolute;
    inset: 0;
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

/* The glyph above its label, which is R12.7's pair given a shape: the word is what carries the meaning
   and it sits where a reader looking at a picture would read it. */
[data-library-tile-mark][b-581be0gom7] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

/* The facts lead and the actions sit at the trailing edge — `space-between` rather than a margin on the
   last child, which is LibraryControlBar.razor.css's rule and I18's. `align-items: start` so a
   two-line title does not push the menu trigger down the tile with it. */
[data-library-tile-caption][b-581be0gom7] {
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: 8px;
}

/* 🔴 `min-inline-size: 0` IS WHAT LETS A LONG TITLE WRAP RATHER THAN WIDEN THE TRACK. A flex item's
   default minimum is its content, so one asset called "2026 Q3 consolidated regulatory submission"
   would push its tile wider than the track the grid gave it and spill the row — which is exactly what
   ResourceLibraryViewportTests measures. `overflow-wrap` breaks the token that has no space in it at
   all, which a filename-derived title frequently is. */
[data-library-tile-facts][b-581be0gom7] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* 🔴 R5.8's 44px ON THE FOLDER LINK, AND IT IS THE GUARANTEE LibraryRows.razor.css ALREADY MOVED ONCE
   RATHER THAN A NEW ONE. R5.8 exempts the operator console "by decision (mouse at a desk)"; W2-06
   DECLINED that exemption for choosing a folder, because it was the narrowest affordance in the
   application. The folders are tiles here now, so the target moves with them again — the alternative is
   a rule quietly dropped along with the element it was written for.

   `inline-flex` so the box can take a height at all: an inline anchor's box does not. */
@media (pointer: coarse) {
    .biztech-library-tile-link[b-581be0gom7] {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }
}

/* W19-15 · the picture is a link, so the pointer over it says so: its edge takes the primary, as /portals' report
   cards do. A picture with no address (a plain box) is not an anchor with an href and does not answer. */
[data-library-tile-picture][b-581be0gom7] {
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

[data-library-tile-picture][href]:hover[b-581be0gom7],
[data-library-tile-picture][data-library-tile-plays]:hover[b-581be0gom7] {
    border-color: var(--biztech-palette-primary);
}

/* W31-06 · D9 · a video's or a recording's picture and title are buttons, because they open the viewer rather than an
   address. A button arrives with the user agent's padding, font and fill; these take them back so the tile looks as
   the link tiles beside it do. */
[data-library-tile-plays][b-581be0gom7] {
    font: inherit;
    padding: 0;
    cursor: pointer;
}

.biztech-library-tile-play[b-581be0gom7] {
    font: inherit;
    padding: 0;
    border: 0;
    background: none;
    text-align: start;
    cursor: pointer;
}
/* /Components/Content/LibraryUploadCapPanel.razor.rz.scp.css */
/* W27-05 · F4.7 · the upload-limit panel: heading, statement, field and actions in one column whose gap
   spaces them (I18). The paper carries the padding (I17). */
.biztech-cap[b-mdeuso4wj8] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-15 · the field holds a number, so it is a column rather than the pane's width. */
.biztech-cap-field[b-mdeuso4wj8] {
    max-inline-size: 16rem;
}

/* W19-15 · the actions in a foot under the quiet rule, the shape every W19 form's foot has; its gap is its own (I18). */
.biztech-cap-foot[b-mdeuso4wj8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Content/MyDocumentsBody.razor.rz.scp.css */
/* W2-28 · /my-documents reads as a file list.

   🔴 ALMOST ALL OF THAT LOOK IS MARKUP RATHER THAN CSS, AND DELIBERATELY SO. The glyph and the name sit
   in a `biztech-d-flex biztech-align-center biztech-gap-2` row and the three quiet columns carry
   `biztech-text-secondary` — all four classes already global, none of them needing a rule here. The row
   separators are `.biztech-td`'s own `border-block-end`, which the table has drawn since W0-53.

   🔴 WHAT IS LEFT NEEDS ::deep, AND I19 IS WHY THAT IS SAID OUT LOUD. A scoped rule reaches THIS
   component's own markup and nothing else, and the compound Blazor stamps is the selector's LAST one. The
   `<tr>` and the `<td>` are UiTable's and UiTd's markup, not this page's — so `.biztech-td { … }` written
   here would compile, ship, and do nothing at all, with no error and no warning. `ScopedStyleReachTests`
   sweeps for exactly that shape. `::deep` says out loud that the target belongs to somebody else, and the
   class before it — `.biztech-documents-list` — is one this page's own markup really does carry. */

/* Drive's rows breathe more than a dense data table's. `.biztech-td` is 8px 12px; this takes the block
   axis to 12px and leaves the inline axis alone, so the columns stay where the reflow expects them. */
.biztech-documents-list[b-6cmvljjlwo]  .biztech-td {
    padding-block: 12px;
}

/* 🔴 A HOVER ON A ROW THAT IS NOT CLICKABLE, WHICH IS A DECISION RATHER THAN AN OVERSIGHT.

   `.biztech-table-row-actionable` exists and carries both a pointer cursor and this same tint, but it is
   applied by UiTable only when a row takes OnRowClick — and these rows do not (W2-28 D8: the reference
   image's rows open on click, this card was not asked for that, and it would need its own keyboard and
   announcement decisions).

   The tint is still worth having WITHOUT the cursor: every row carries three controls, and the thing a
   reader needs on the way to pressing Remove is confidence about which row they are on. So the hint is
   "this is the row you are pointing at", not "this row is a button" — which is why the cursor is left
   alone, and why the value is copied from the actionable rule rather than invented, so two kinds of row
   never tint by different amounts. */
.biztech-documents-list[b-6cmvljjlwo]  .biztech-table-row:hover .biztech-td {
    background: color-mix(in srgb, currentcolor 4%, transparent);
}

/* W19's note, spaced from the toolbar under it. */
.biztech-documents-note[b-6cmvljjlwo] {
    margin-block-end: 16px;
}

/* §2a C3 · the search's hook wrapper adds no box, so UiFilterSearch stays the filter bar's own flex item. */
.biztech-documents-search[b-6cmvljjlwo] {
    display: contents;
}

/* §2a C4 · the card is UiListCard's. What stays is this list's own: in a portal, the card's edge takes the theme's box
   edge where one is set; and the last row's own rule would double the card's edge, so it goes. */
.biztech-documents-list[b-6cmvljjlwo]  .biztech-list-card {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
}

.biztech-documents-list[b-6cmvljjlwo]  .biztech-table-row:last-child .biztech-td {
    border-block-end: 0;
}

/* The name: the glyph in the primary's pale square, the title in the heavier weight. */
.biztech-documents-name[b-6cmvljjlwo] {
    display: flex;
    align-items: center;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-documents-glyph[b-6cmvljjlwo] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

.biztech-documents-title[b-6cmvljjlwo] {
    font-weight: 600;
    color: var(--biztech-palette-text-primary);
    overflow-wrap: anywhere;
}
/* /Components/Content/MyDocumentUploadPanel.razor.rz.scp.css */
/* The add and replace form: W19's quiet card - the subtle edge, twice the theme's radius, the surface - where it was a
   paper with the full outline. The width is still .biztech-form's measure. Every colour and radius is a token. */
/* A block rather than a gapped column: the refusal's live region is in the markup while empty (R12.6a), and a gap
   would space that empty box too. The alert and the replace note carry their own bottom margins. */
.biztech-document-panel[b-16uxyrij8u] {
    padding: 24px;
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* W19's form foot: the actions under a rule, the form's end rather than one more row. */
.biztech-document-panel-foot[b-16uxyrij8u] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-block-start: 24px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Content/PublishAppsPanel.razor.rz.scp.css */
/*
    W27-01 · A3, A5. The panel's own spacing: columns with one gap each (I18), the papers padded by biztech-pa-4 (I17).
    Logical properties; the only colours are W19-15's quiet edges, as --biztech-* tokens.
*/

.biztech-publish-apps[b-tl9dhwnkts] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-publish-apps-section[b-tl9dhwnkts] {
    display: flex;
    flex-direction: column;
    align-items: stretch;

    /* W19-15 · 12px between a card's fields, where 8px set a field's label as close to the field above as to its own. */
    gap: 12px;
    min-inline-size: 0;
}

.biztech-publish-apps-rows[b-tl9dhwnkts] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-publish-apps-row[b-tl9dhwnkts] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* W31-01 · D16. A broken data: address finding sits on its own line, beneath the row's address. */
.biztech-publish-apps-row [data-publish-apps-broken-data][b-tl9dhwnkts] {
    flex-basis: 100%;
}

.biztech-publish-apps-file[b-tl9dhwnkts] {
    font-weight: 600;
}

/* W19-15 · the two ways to publish, one column on a phone and side by side from md. Each card is as tall as its own
   contents, so the shorter one does not stretch into an empty box. */
.biztech-publish-apps-choices[b-tl9dhwnkts] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 16px;
}

@media (min-width: 960px) {
    .biztech-publish-apps-choices[b-tl9dhwnkts] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* W19-15 · the cards and the results take the tables' quiet edge and corners (W19-08), from this panel's own root. */
.biztech-publish-apps[b-tl9dhwnkts]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* W19-15 · each card's action in a foot under the quiet rule. */
.biztech-publish-apps-foot[b-tl9dhwnkts] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Content/PublishPackPanel.razor.rz.scp.css */
/*  W2-14 · F4.10.

    A published site's address is one long token with no space and no hyphen a browser will break at -
    `http://packs.acme.example.com/agency-disclosure/` - so its min-content width is the min-content
    width of whatever box it sits in. The frontend guidelines are explicit that the page body must never
    scroll horizontally, and an unbreakable token is the ordinary way that happens.

    `anywhere` rather than `break-word`, because break-word will not break a token that is already
    alone on its line, which is exactly this case. On the ELEMENT rather than the panel, so only the
    address wraps oddly and the sentence around it still breaks at its spaces.

    Defensive rather than a fix for a measured failure: the one geometry failure this panel did cause
    was about WHERE it was mounted, not how wide it is - see the comment on its call site in
    ResourceLibrary.razor.
*/

[data-publish-pack-address][b-vw7mzg5klu] {
    overflow-wrap: anywhere;
}

/*  W25-01 · I18. The panel's own column spacing: the section and its status region each space their children with one
    gap, so the review, the file field, the buttons and the releases table never touch - and no child carries a margin
    of its own for it to add up with. */

[data-publish-pack][b-vw7mzg5klu],
[data-publish-pack-status][b-vw7mzg5klu] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* W19-15 · the paper takes the tables' quiet edge and corners (W19-08), from this panel's own wrapper. */
.biztech-publish-pack[b-vw7mzg5klu]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* W19-15 · the upload's actions in a foot under the quiet rule; the gap is the foot's (I18). */
.biztech-publish-pack-foot[b-vw7mzg5klu] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W19-15 · a release's chip and who made it current, on one line that wraps. */
.biztech-publish-pack-status[b-vw7mzg5klu] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
}
/* /Components/Content/ResourceAmendDialog.razor.rz.scp.css */
/* W2-27 · F4.1 · F4.3 — the amend dialog's own geometry, which it had none of.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). The one colour is W19-15's foot rule, a
   --biztech-* token. No prefers-color-scheme (I16).

   🔴 I17, AND THE DIALOG WAS FLUSH ON ALL FOUR SIDES. UiDialog declares `padding: 0` on
   .biztech-dialog-panel deliberately - "a caller that forgets one gets a visibly flush dialog rather
   than a subtly wrong one", in UiDialog.razor.css's own words. This file is that padding, and its
   absence is why the heading sat against the border and the fields ran edge to edge. 24px since
   W19-15, the same as .biztech-password-dialog, so the console's modals keep one number.

   🔴 I18. The heading spaced itself with biztech-mb-4 and the caption with biztech-mt-2 — margins per
   child, which add to whatever a parent already spaces. Both are gaps on a container below, and no
   child in this file carries a margin now.

   🔴 I19. Every selector ends on a class this file's own markup writes. Nothing reaches into UiButton,
   UiText, UiGrid or UiTextField, whose roots Blazor stamps with their own scope — a rule that tried
   would be inert, with no error and no warning. */

/* The dialog's body: its padding, and the space between its heading and whichever branch follows. */
.biztech-amend-dialog[b-rlv1z0jxn1] {
    display: flex;
    flex-direction: column;
    gap: 16px;

    /* W19-15 · 24px, the media, QR and first-password dialogs' padding (W19-02, W19-10, W19-12). */
    padding: 24px;
}

/* W19-15 · the title and its close control on one row. */
.biztech-amend-dialog-head[b-rlv1z0jxn1] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

/* 🔴 TWO BUTTONS THAT TOUCHED. The row was a bare <div>, so Cancel and Save rendered as inline-block
   neighbours separated by nothing but the whitespace text node between them, hard against the left
   edge. flex-end because the confirming action belongs at the end of the reading direction, and
   flex-wrap rather than a media query: the row wraps when 34rem less its padding is too narrow for
   it, at whatever width that turns out to be. */
.biztech-amend-dialog-actions[b-rlv1z0jxn1] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}

/* The actions and the sentence under them are one block — R9.2's blocking reason has to read as
   belonging to the button it is about, which 8px says and the grid's own gutter does not. */
.biztech-amend-dialog-footer[b-rlv1z0jxn1] {
    display: flex;
    flex-direction: column;
    gap: 8px;

    /* W19-15 · the foot sits under the quiet rule, as every W19 dialog's does. */
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Content/ResourceUploadList.razor.rz.scp.css */
/* W27-05 · a many-files upload's lines. The list is a column whose gap spaces the lines (I18); each line is
   a column of name, result and (while it runs) its own bar, spaced by its own gap. No padding: the list sits
   inside the form's padded panel (I17). */
.biztech-upload-list[b-uayt2chyrl] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-upload-row[b-uayt2chyrl] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;

    /* W19-15 · a hairline under each file, the quiet rule the tables' rows carry, so a list of twenty reads as rows. */
    padding-block-end: 8px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-upload-name[b-uayt2chyrl] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* /Components/Docs/DocsArticleBody.razor.rz.scp.css */
/* W24-01 · D11. One docs page: a contents list beside the body on a wide screen and above it on a narrow one, then
   the in-depth half behind a native disclosure. Gaps belong to the containers (I18). */

.biztech-docs-article[b-03pd2xe2z8] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
}

/* Beside the body from 1100px: the contents stay in view while the body scrolls. Grid tracks size both columns, so
   nothing here has to reach into a child component (I19). */
@media (min-width: 1100px) {
    .biztech-docs-article[b-03pd2xe2z8] {
        grid-template-columns: minmax(0, 1fr) 15rem;
        align-items: start;
    }

    .biztech-docs-contents[b-03pd2xe2z8] {
        grid-column: 2;
        grid-row: 1;
        position: sticky;
        inset-block-start: 88px;
    }

    .biztech-docs-body[b-03pd2xe2z8] {
        grid-column: 1;
        grid-row: 1;
    }
}

.biztech-docs-body[b-03pd2xe2z8] {
    display: flex;
    flex-direction: column;
    gap: 20px;
    min-inline-size: 0;
}

.biztech-docs-contents[b-03pd2xe2z8] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

.biztech-docs-contents-heading[b-03pd2xe2z8] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-overline-size);
    font-weight: var(--biztech-font-overline-weight);
    letter-spacing: var(--biztech-font-overline-letter-spacing);
    text-transform: var(--biztech-font-overline-transform);
}

.biztech-docs-contents-list[b-03pd2xe2z8] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    font-size: var(--biztech-font-body2-size);
    line-height: 1.4;
}

.biztech-docs-contents-list a[b-03pd2xe2z8] {
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
}

.biztech-docs-contents-list a:hover[b-03pd2xe2z8] {
    color: var(--biztech-palette-primary);
    text-decoration: underline;
}

.biztech-docs-contents-deep[b-03pd2xe2z8] {
    padding-block-start: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* ---------- the in-depth half ---------- */

.biztech-docs-deep[b-03pd2xe2z8] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    scroll-margin-block-start: 80px;
}

.biztech-docs-deep-summary[b-03pd2xe2z8] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px;
    cursor: pointer;
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    list-style: none;
}

.biztech-docs-deep-summary[b-03pd2xe2z8]::-webkit-details-marker {
    display: none;
}

/* The disclosure's own marker, drawn in the palette's ink and turned when open. A CSS border chevron rather than a
   glyph, because the summary must stay the one interactive element here. */
.biztech-docs-deep-summary[b-03pd2xe2z8]::before {
    content: "";
    flex: none;
    inline-size: 8px;
    block-size: 8px;
    border-inline-end: 2px solid currentcolor;
    border-block-end: 2px solid currentcolor;
    transform: rotate(-45deg);
    transition: transform var(--biztech-motion-duration);
}

.biztech-docs-deep[open] > .biztech-docs-deep-summary[b-03pd2xe2z8]::before {
    transform: rotate(45deg);
}

.biztech-docs-deep[open] > .biztech-docs-deep-summary[b-03pd2xe2z8] {
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-docs-deep-body[b-03pd2xe2z8] {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 8px 16px 20px;
}

/* W26-05 · D2 · AN AGENT PORTAL'S DOCS PAGE AT FULL WIDTH. Its paragraphs already keep 46rem (DocsBlockView); this keeps
   the article's tables, code and cards to the same body, with its 15rem contents beside the body across the 24px gap
   rather than at the screen's far edge - so the cap is the three together. From the standard measure, 71.25rem, where
   full first differs from standard and the contents already sit beside the body (1100px above). Start-aligned. Only
   under a full-width portal shell: the console's /docs has no such ancestor. */
@media (min-width: 71.25rem) {
    [data-portal-width="full"] .biztech-docs-article[b-03pd2xe2z8] {
        max-inline-size: calc(46rem + 24px + 15rem);
    }
}
/* /Components/Docs/DocsBlockView.razor.rz.scp.css */
/* W24-01 · ADR 0039 §4 · D8. The docs' visual blocks, in the palette's own roles, so they follow the theme and the
   mode with nothing of their own to keep in step (R7.3: no prefers-color-scheme here).

   Spacing between blocks is the article body's gap (I18), so no block below carries an outer margin. */

/* ---------- prose: the page author's paragraphs, headings, lists, tables and code ---------- */

.biztech-docs-prose[b-37d9nrvd5l] {
    color: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body1-size);
    line-height: 1.6;
    overflow-wrap: anywhere;
}

/* R4.6's prose measure: a sentence that runs the width of a console is one nobody finishes. Tables and code keep
   the column's width. */
.biztech-docs-prose[b-37d9nrvd5l]  p,
.biztech-docs-prose[b-37d9nrvd5l]  ul,
.biztech-docs-prose[b-37d9nrvd5l]  ol,
.biztech-docs-prose[b-37d9nrvd5l]  blockquote {
    max-inline-size: 46rem;
    margin-block: 0 12px;
}

.biztech-docs-prose[b-37d9nrvd5l]  h2 {
    margin-block: 32px 12px;
    padding-block-end: 8px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    font-size: var(--biztech-font-h5-size);
    font-weight: var(--biztech-font-h5-weight);
    line-height: var(--biztech-font-h5-line-height);
    scroll-margin-block-start: 80px;
}

.biztech-docs-prose[b-37d9nrvd5l]  h3 {
    margin-block: 24px 8px;
    font-size: var(--biztech-font-h6-size);
    font-weight: var(--biztech-font-h6-weight);
    line-height: var(--biztech-font-h6-line-height);
    scroll-margin-block-start: 80px;
}

.biztech-docs-prose[b-37d9nrvd5l]  h4 {
    margin-block: 16px 8px;
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle1-weight);
}

.biztech-docs-prose[b-37d9nrvd5l]  li {
    margin-block-end: 4px;
}

.biztech-docs-prose[b-37d9nrvd5l]  a {
    color: var(--biztech-palette-primary);
    text-underline-offset: 2px;
}

.biztech-docs-prose[b-37d9nrvd5l]  code {
    padding: 1px 4px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    font-family: var(--biztech-font-mono-family);
    font-size: 0.875em;
}

.biztech-docs-prose[b-37d9nrvd5l]  pre {
    margin-block: 0 12px;
    padding: 12px 16px;
    overflow-x: auto;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    font-size: var(--biztech-font-body2-size);
    line-height: 1.5;
}

/* I18 · the column's gap spaces the blocks, so a prose block's LAST element gives up its trailing margin - otherwise
   it adds to the gap, 32px below prose against 20px below a visual block (ui-invariant review, W24-01). Named
   elements, not `> :last-child`, because a scoped selector may not end in a universal one (I19). */
.biztech-docs-prose[b-37d9nrvd5l]  p:last-child,
.biztech-docs-prose[b-37d9nrvd5l]  ul:last-child,
.biztech-docs-prose[b-37d9nrvd5l]  ol:last-child,
.biztech-docs-prose[b-37d9nrvd5l]  blockquote:last-child,
.biztech-docs-prose[b-37d9nrvd5l]  pre:last-child,
.biztech-docs-prose[b-37d9nrvd5l]  table:last-child {
    margin-block-end: 0;
}

.biztech-docs-prose[b-37d9nrvd5l]  pre code {
    padding: 0;
    border: 0;
    font-size: inherit;
}

.biztech-docs-prose[b-37d9nrvd5l]  blockquote {
    padding-inline-start: 16px;
    border-inline-start: 4px solid var(--biztech-palette-outline);
    color: var(--biztech-palette-text-secondary);
}

.biztech-docs-prose[b-37d9nrvd5l]  table {
    display: block;
    max-inline-size: 100%;
    margin-block: 0 12px;
    overflow-x: auto;
    border-collapse: collapse;
    font-size: var(--biztech-font-body2-size);
}

.biztech-docs-prose[b-37d9nrvd5l]  th,
.biztech-docs-prose[b-37d9nrvd5l]  td {
    padding: 8px 12px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    text-align: start;
    vertical-align: top;
}

.biztech-docs-prose[b-37d9nrvd5l]  th {
    font-weight: var(--biztech-font-subtitle2-weight);
    white-space: nowrap;
}

.biztech-docs-prose[b-37d9nrvd5l]  h2:first-child,
.biztech-docs-prose[b-37d9nrvd5l]  h3:first-child {
    margin-block-start: 0;
}

/* ---------- cards: an at-a-glance grid ---------- */

.biztech-docs-cards[b-37d9nrvd5l] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
    gap: 12px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-docs-card[b-37d9nrvd5l] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-block-start: 4px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-docs-card-title[b-37d9nrvd5l] {
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    line-height: 1.3;
}

.biztech-docs-card-text[b-37d9nrvd5l] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: 1.5;
}

.biztech-docs-card-text[b-37d9nrvd5l]  a {
    color: var(--biztech-palette-primary);
}

.biztech-docs-card-text[b-37d9nrvd5l]  code {
    font-family: var(--biztech-font-mono-family);
    font-size: 0.875em;
}

/* ---------- flow: stages and arrows ---------- */

.biztech-docs-flow[b-37d9nrvd5l] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-docs-flow-row[b-37d9nrvd5l] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 0;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-docs-flow-stage[b-37d9nrvd5l] {
    display: flex;
    align-items: center;
}

.biztech-docs-flow-box[b-37d9nrvd5l] {
    display: flex;
    flex-direction: column;
    padding: 8px 16px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-docs-flow-name[b-37d9nrvd5l] {
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    white-space: nowrap;
}

.biztech-docs-flow-note[b-37d9nrvd5l] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}

.biztech-docs-flow-arrow[b-37d9nrvd5l] {
    display: inline-flex;
    padding-inline: 2px;
    color: var(--biztech-palette-text-secondary);
}

/* ---------- steps: numbered cards ---------- */

.biztech-docs-steps[b-37d9nrvd5l] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    max-inline-size: 46rem;
}

.biztech-docs-step[b-37d9nrvd5l] {
    display: grid;
    grid-template-columns: 28px 1fr;
    align-items: start;
    gap: 12px;
    padding: 8px 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-docs-step-number[b-37d9nrvd5l] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 28px;
    block-size: 28px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

.biztech-docs-step-text[b-37d9nrvd5l] {
    padding-block-start: 4px;
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-body1-size);
    line-height: 1.5;
}

.biztech-docs-step-text[b-37d9nrvd5l]  a {
    color: var(--biztech-palette-primary);
}

.biztech-docs-step-text[b-37d9nrvd5l]  code {
    font-family: var(--biztech-font-mono-family);
    font-size: 0.875em;
}

/* ---------- callout: tip, note, warning ---------- */

/* The kind's colour is on the border and the glyph, never the paragraph - UiAlert's reasoning: R3.6 puts the
   contrast on the border, and the body reads in the page's own ink. */
.biztech-docs-callout[b-37d9nrvd5l] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    max-inline-size: 46rem;
    padding: 12px 16px;
    border: 1px solid currentcolor;
    border-inline-start-width: 4px;
    border-radius: var(--biztech-radius-default);
}

.biztech-docs-callout-tip[b-37d9nrvd5l] { color: var(--biztech-palette-success); }
.biztech-docs-callout-note[b-37d9nrvd5l] { color: var(--biztech-palette-info); }
.biztech-docs-callout-warning[b-37d9nrvd5l] { color: var(--biztech-palette-warning); }

.biztech-docs-callout-icon[b-37d9nrvd5l] {
    display: inline-flex;
    margin-block-start: 2px;
}

.biztech-docs-callout-body[b-37d9nrvd5l] {
    flex: 1 1 auto;
    min-inline-size: 0;
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-body2-size);
    line-height: 1.55;
}

.biztech-docs-callout-label[b-37d9nrvd5l] {
    display: block;
    margin-block-end: 2px;
    font-weight: var(--biztech-font-subtitle2-weight);
}

.biztech-docs-callout-body[b-37d9nrvd5l]  p {
    margin-block: 0 8px;
}

.biztech-docs-callout-body[b-37d9nrvd5l]  p:last-child {
    margin-block-end: 0;
}

.biztech-docs-callout-body[b-37d9nrvd5l]  a {
    color: var(--biztech-palette-primary);
}

.biztech-docs-callout-body[b-37d9nrvd5l]  code {
    font-family: var(--biztech-font-mono-family);
    font-size: 0.875em;
}

/* ---------- matrix: who can do what ---------- */

/* The region scrolls, never the page: a wide matrix at 375px is reached by a sideways swipe inside its own box. */
.biztech-docs-matrix-scroll[b-37d9nrvd5l] {
    /* 🔴 THE CONTAINING BLOCK, AND IT IS LOAD-BEARING. The cells' hidden Yes/No words are position: absolute; without
       a positioned ancestor INSIDE this box their containing block is the page, so overflow-x here does not clip
       them and a wide matrix widened the whole page at 375px - measured on /docs/getting-started (578px of scroll
       in a 360px viewport) in the W24-01 browser walk. */
    position: relative;
    max-inline-size: 100%;
    overflow-x: auto;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

.biztech-docs-matrix[b-37d9nrvd5l] {
    inline-size: 100%;
    border-collapse: collapse;
    font-size: var(--biztech-font-body2-size);
}

.biztech-docs-matrix th[b-37d9nrvd5l],
.biztech-docs-matrix td[b-37d9nrvd5l] {
    padding: 8px 12px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    text-align: start;
    vertical-align: middle;
}

.biztech-docs-matrix thead th[b-37d9nrvd5l] {
    background: var(--biztech-palette-surface);
    font-weight: var(--biztech-font-subtitle2-weight);
    white-space: nowrap;
}

.biztech-docs-matrix tbody th[b-37d9nrvd5l] {
    font-weight: var(--biztech-font-body2-weight);
}

.biztech-docs-matrix tbody tr:last-child th[b-37d9nrvd5l],
.biztech-docs-matrix tbody tr:last-child td[b-37d9nrvd5l] {
    border-block-end: 0;
}

.biztech-docs-cell-yes[b-37d9nrvd5l],
.biztech-docs-cell-no[b-37d9nrvd5l] {
    text-align: center;
}

.biztech-docs-cell-yes[b-37d9nrvd5l] { color: var(--biztech-palette-success); }
.biztech-docs-cell-no[b-37d9nrvd5l] { color: var(--biztech-palette-text-disabled); }

.biztech-docs-mark[b-37d9nrvd5l] {
    display: inline-flex;
}

/* Present for a screen reader, occupying no space - the clip idiom app.css's skip link uses. */
.biztech-docs-hidden[b-37d9nrvd5l] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ---------- a block that did not parse ---------- */

.biztech-docs-problem[b-37d9nrvd5l] {
    margin: 0;
    padding: 12px 16px;
    overflow-x: auto;
    border: 1px dashed var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-body2-size);
}
/* /Components/Docs/DocsIndexBody.razor.rz.scp.css */
/* W24-01. The docs index: one section per audience, each a grid of page cards. The gap is the container's (I18). */

.biztech-docs-index[b-am2jro7q8h] {
    display: flex;
    flex-direction: column;
    gap: 32px;
}

.biztech-docs-index-group[b-am2jro7q8h] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-docs-index-heading[b-am2jro7q8h] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-overline-size);
    font-weight: var(--biztech-font-overline-weight);
    letter-spacing: var(--biztech-font-overline-letter-spacing);
    text-transform: var(--biztech-font-overline-transform);
}

.biztech-docs-index-list[b-am2jro7q8h] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
    gap: 12px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-docs-index-card[b-am2jro7q8h] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    block-size: 100%;
    box-sizing: border-box;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--biztech-motion-duration);
}

.biztech-docs-index-card:hover[b-am2jro7q8h] {
    border-color: var(--biztech-palette-primary);
}

.biztech-docs-index-title[b-am2jro7q8h] {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

.biztech-docs-index-summary[b-am2jro7q8h] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: 1.5;
}
/* /Components/Education/EducationExternalLink.razor.rz.scp.css */
/*
    W7-02 · the link out of a content card.

    The glyph sits on the text's baseline row rather than above it, and the label wraps rather than
    truncating: the host is part of the sentence R13.4 requires to be readable without a hover, so cutting
    it off would defeat the rule it exists for.

    Colours are the palette's link and text roles; every length is a multiple of the 4px base unit.
*/

/*
    🔴 min-height IS R5.8's 44px BY CONSTRUCTION RATHER THAN BY ACCIDENT. Without it the target passed the
    coarse-pointer assertion only because the label happens to wrap to two lines at 375px - so a shorter
    label, or a translated one, would have dropped under 44px with the test still green on the long ones.
    44px is a named layout constant in PortalStyleSheetTests, not an off-scale length.
*/
.biztech-education-link[b-vchwsqc041] {
    align-items: center;
    color: var(--biztech-palette-primary);
    display: inline-flex;
    gap: 4px;
    margin-top: auto;
    min-height: 44px;
    padding-top: 8px;
}

.biztech-education-link[b-vchwsqc041] {
    justify-content: space-between;
    gap: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--biztech-palette-outline-subtle);
    text-decoration: none;
}

.biztech-education-link-words[b-vchwsqc041] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
}

.biztech-education-link-label[b-vchwsqc041] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-education-link-host[b-vchwsqc041] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    overflow-wrap: anywhere;
}

.biztech-education-link:hover .biztech-education-link-label[b-vchwsqc041] {
    text-decoration: underline;
}

/* Said to a screen reader, not drawn: clipped rather than hidden, so it stays in the link's name. */
.biztech-education-link-hidden[b-vchwsqc041] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
/* /Components/Education/EducationItemFrame.razor.rz.scp.css */
/*
    W7-02 · one content card.

    🔴 THE ASPECT RATIO IS DECLARED ONCE AND BOTH STATES READ IT, which is R11.7's "a decided aspect ratio"
    doing a second job: the picture and its absence occupy the same box, so a card does not resize under the
    reader when a thumbnail resolves out of OnAfterRenderAsync. 16/9 because the ported catalogue is
    articles, decks and video stills rather than portraits.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit, which is what
    PortalStyleSheetTests' two sweeps require of any scoped sheet - they pick this file up with no edit.
*/

/*
    ❗ box-sizing, WITHOUT WHICH THE LINE ABOVE IS A TRAP. There is no global
    `* { box-sizing: border-box }` here, so `height: 100%` is 100% of the PARENT'S CONTENT BOX and the
    padding below is added to it. It costs nothing while the parent has no height of its own - the
    percentage is dropped - and it breaks the moment one is given. CaseCard is where that happened:
    W8-25 gave its UiPaper a definite height so a row of Open buttons would line up, which activated an
    inert `height: 100%` and pushed a 253px card through a 231px paper, clipping the button's corners on
    the card's own border. This box is currently in the harmless state; the declaration is what keeps it
    there. PortalStyleSheetTests.No_percentage_height_is_paired_with_padding_outside_a_border_box sweeps
    for the pair.
*/
.biztech-education-card[b-66tbn88m70] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    box-sizing: border-box;
    height: 100%;
    padding: 20px;
    /* W19's quiet card: the theme's box edge, twice its radius, the surface and the theme's Depth. */
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

/*
    Both states, so they cannot disagree about the box. object-fit is R11.7's second requirement: a
    thumbnail is whatever an author uploaded, and cover crops it rather than distorting a face or a slide.
*/
.biztech-education-thumb[b-66tbn88m70] {
    aspect-ratio: 16 / 9;
    border-radius: var(--biztech-radius-default);
    display: block;
    object-fit: cover;
    width: 100%;
}

/*
    Two lines, then an ellipsis. A hub of 308 cards must keep its rows aligned, and a title is a content
    title rather than a label - so it is clamped rather than bounded at the column, and the full text stays
    in the DOM for a screen reader.

    🔴 ::deep, AND IT IS REQUIRED RATHER THAN STYLISTIC - the same trap CasePage.razor.css and
    MainNavMenu.razor.css both record, the second "found on screen rather than in a test". The <h3> is
    rendered by UiText, so Blazor stamps UiText's scope attribute on it and not this component's; without
    ::deep this rule compiles to `.biztech-education-title[b-xxxxxxxxxx]` and matches nothing. The class is
    still in the markup, so a bUnit Find succeeds and the sheet sweeps pass - which is why
    EducationItemViewportTests.The_cards_title_really_is_clamped_to_two_lines reads the COMPUTED style.
*/
[b-66tbn88m70] .biztech-education-title {
    font-weight: 600;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}

/* A live event's time beside its calendar, and a live event's or a quiz's way in as the card's foot - the shape
   EducationExternalLink gives every other item. Here, with ::deep, because those items ship no sheet of their own
   (EducationComponentStyleTests): the markup is theirs, inside this card. 44px is R5.8's named target. */
.biztech-education-card[b-66tbn88m70]  .biztech-education-when {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-education-card[b-66tbn88m70]  .biztech-education-event-link,
.biztech-education-card[b-66tbn88m70]  .biztech-education-file-link,
.biztech-education-card[b-66tbn88m70]  .biztech-education-quiz-start {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 44px;
    margin-top: auto;
    padding-top: 12px;
    border-top: 1px solid var(--biztech-palette-outline-subtle);
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
    text-decoration: none;
}

.biztech-education-card[b-66tbn88m70]  .biztech-education-event-link:hover,
.biztech-education-card[b-66tbn88m70]  .biztech-education-file-link:hover,
.biztech-education-card[b-66tbn88m70]  .biztech-education-quiz-start:hover {
    text-decoration: underline;
}
/* /Components/Education/LearnLayoutRow.razor.rz.scp.css */
/* W31-05 · §3h · one kind per line: its heading field takes the room, the switch and the moves sit at the end. The line
   wraps when the field would fall under 14rem, so the field keeps a readable width at 390px. */
.biztech-learn-layout[b-0rapmlvift] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-learn-layout-row[b-0rapmlvift] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-learn-layout-heading[b-0rapmlvift] {
    flex: 1 1 14rem;
    min-width: 0;
}

/* Two moves' width held even when one is absent (R9.14), so the switches line up down the rows. */
.biztech-learn-layout-moves[b-0rapmlvift] {
    display: flex;
    gap: 4px;
    min-width: 4.5rem;
}
/* /Components/Identity/ChangeEmailDialog.razor.rz.scp.css */
/*
    W27-02 · the person page's account dialogs, SetFirstPasswordDialog's shape.

    I17: UiDialog carries no padding of its own; this is that padding.
    I18: the actions row's gap belongs to the row, never a margin on each button.
    I19: both selectors name this component's own markup.
*/

.biztech-person-dialog[b-k77rsi72m7] {
    padding: 16px;
}

.biztech-person-dialog-actions[b-k77rsi72m7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Identity/PersonAccountPanel.razor.rz.scp.css */
/*
    W27-02 · the person page's account actions.

    I18: the row's gap belongs to the row, never a margin on each button; the row wraps on a phone.
    I19: the selector names this component's own markup.
*/

.biztech-person-account-actions[b-dk0x829gpa] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Identity/PersonDetails.razor.rz.scp.css */
/* W19 · the Details tab's foot: Save and its caption on one line under a rule, the form's end rather than one more field.
   The gap is the container's (I18). Every selector names this file's own markup (I19). */
.biztech-person-details-foot[b-xf317gymk7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Identity/PersonRoles.razor.rz.scp.css */
/*
    W14-04 · specimen 11's save bar.

    🔴 THE UNSAVED MARKER IS THE SECONDARY, AND IT IS THE ONLY PLACE THIS PAGE USES IT. Specimen 11
    calls it "the burnt umber secondary - the only place that colour appears in this whole document, so
    'you have unsaved work' is unmistakable and nothing competes with it." A token, never a literal:
    PortalStyleSheetTests' colour sweep would refuse a hand-picked value, and correctly.

    I18: the gap belongs to the ROW. Four children can sit here - Save, Discard, the marker and the
    counts, the action first so it is where the eye starts - and spacing them with a margin each would add to the flow's own spacing, which is the
    "24px down the rows and 16px across the columns" mismatch I18 records.

    I19: both selectors name this component's own markup, and the stamped compound is last. Nothing
    reaches inside UiButton or UiText, whose roots carry their own scope - such a rule would be inert
    with no error and no warning, which is the failure mode ScopedStyleReachTests sweeps for.
*/

.biztech-person-roles-bar[b-jxjch94gsq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-person-roles-unsaved[b-jxjch94gsq] {
    color: var(--biztech-palette-secondary);
    font-weight: 600;
}

/* W23-02 · D20. The organisation picker under a ticked role: a block of its own, padded off the checkbox above,
   because it sits inside a span that has no gap to give. Capped at a column, as a select is everywhere else
   in the console; it ran the whole row's width. */
.biztech-person-roles-organisation[b-jxjch94gsq] {
    display: block;
    max-inline-size: 24rem;
    padding-block-start: 8px;
}

/* W19 · the roles as one list with a hairline between rows, rather than a grid of loose blocks. */
.biztech-person-roles-list[b-jxjch94gsq] {
    margin: 0;
    padding: 0;
    list-style: none;
}

.biztech-person-roles-row[b-jxjch94gsq] {
    padding-block: 12px;
}

.biztech-person-roles-row + .biztech-person-roles-row[b-jxjch94gsq] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-person-roles-choice[b-jxjch94gsq] {
    display: block;
}

/* The role, then its counts as a column at the row's end. Below sm the counts drop under the name. */
.biztech-person-roles-head[b-jxjch94gsq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 16px;
}

.biztech-person-roles-name[b-jxjch94gsq] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.biztech-person-roles-counts[b-jxjch94gsq] {
    font-variant-numeric: tabular-nums;
}
/* /Components/Identity/ProfileBody.razor.rz.scp.css */
/*
    W0-13 · F3.17. A person's own profile: one column of W19's quiet cards - who this is, the details and preferences
    with their Save, and the password with its own.

    🔴 SCOPED RATHER THAN app.css, AND THAT IS R14.1's LAYER 4. Every element these rules reach is
    rendered by THIS component, or is a seam component's root reached with ::deep from a wrapper this file owns (I19).

    Every length is a multiple of the 4px base unit (R5.4), and 999px is the registry's pill radius
    (R5.5). No hex anywhere: the colours come from the palette tokens, so the page follows a
    tenant theme and both modes without a second declaration (R3.1, R7.3 - there is no
    prefers-color-scheme here and there must not be, I16).
*/

/* The cards in one column, as wide as the layout's content - the theme's page width, which the portal's own pages take
   too. The fields' two columns keep a postcode box from running the full width. */
.biztech-profile[b-0bu9uh0a1a] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19's quiet card: the subtle edge, twice the theme's radius, the surface. The page was one long column on the ground
   with a divider before the password. */
.biztech-profile-card[b-0bu9uh0a1a] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* A card's title and the line that says what it is for. */
.biztech-profile-card-head[b-0bu9uh0a1a] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The second group inside one form: Preferences under Personal details, parted by a hairline rather than a second card,
   because one Save covers both. */
.biztech-profile-card-head-next[b-0bu9uh0a1a] {
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* Two columns from `sm` up; a field marked wide takes the row. */
.biztech-profile-fields[b-0bu9uh0a1a] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 600px) {
    .biztech-profile-fields[b-0bu9uh0a1a] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .biztech-profile-fields[b-0bu9uh0a1a]  > .biztech-profile-wide {
        grid-column: 1 / -1;
    }
}

/* W19's form foot: the action under a rule, the form's end rather than one more field. */
.biztech-profile-foot[b-0bu9uh0a1a] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* Who this is: the picture beside the name, the address and the picture's two actions. */
.biztech-profile-identity[b-0bu9uh0a1a] {
    flex-direction: row;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 24px;
}

.biztech-profile-who[b-0bu9uh0a1a] {
    display: flex;
    flex: 1 1 16rem;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-profile-email[b-0bu9uh0a1a] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    overflow-wrap: anywhere;
}

/*
    A circle, and object-fit: cover so a rectangular photograph is cropped rather than squashed. A
    person uploads whatever their phone produced; distorting their face is the failure this one
    declaration prevents.
*/
.biztech-profile-avatar-image[b-0bu9uh0a1a],
.biztech-profile-avatar-empty[b-0bu9uh0a1a] {
    inline-size: 72px;
    block-size: 72px;
    border-radius: 999px;
    flex: 0 0 auto;
}

.biztech-profile-avatar-image[b-0bu9uh0a1a] {
    object-fit: cover;
    /* OutlineSubtle, not Outline: this is a hairline around a photograph, not a control boundary that
       has to clear 3:1 against the surface behind it. */
    border: 1px solid var(--biztech-palette-outline-subtle);
}

/* The placeholder takes the primary's pale tone, so an empty picture reads as a place for one rather than a grey hole. */
.biztech-profile-avatar-empty[b-0bu9uh0a1a] {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

/* The glyph at 40px in the 72px circle; the seam draws it at 24px. */
.biztech-profile-avatar-empty[b-0bu9uh0a1a]  .biztech-icon {
    inline-size: 40px;
    block-size: 40px;
}

.biztech-profile-avatar-actions[b-0bu9uh0a1a] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-block-start: 8px;
}

/*
    "Change picture": the seam's file field, its native input laid invisibly over a button-shaped face. The input is
    still the control - it takes the press, the focus and the keyboard, and the browser's picker opens from it - so
    nothing native is reimplemented (R8.8). Its label is visually hidden; it still names the input.
*/
.biztech-profile-pick[b-0bu9uh0a1a] {
    position: relative;
    display: inline-flex;
    border-radius: var(--biztech-radius-default);
}

.biztech-profile-pick-face[b-0bu9uh0a1a] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    min-block-size: var(--biztech-control-height);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    padding-inline: 16px;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-primary);
    white-space: nowrap;
}

.biztech-profile-pick:hover .biztech-profile-pick-face[b-0bu9uh0a1a] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, transparent);
}

.biztech-profile-pick:focus-within[b-0bu9uh0a1a] {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 2px;
}

.biztech-profile-pick[b-0bu9uh0a1a]  .biztech-field {
    position: absolute;
    inset: 0;
}

.biztech-profile-pick[b-0bu9uh0a1a]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-profile-pick[b-0bu9uh0a1a]  input[type="file"] {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    opacity: 0;
    cursor: pointer;
}
/* /Components/Identity/RegistrationAgreement.razor.rz.scp.css */
/* W25-03 · I18 · the agreement, its box and the terms link are spaced by this container's gap, never per child. */
.biztech-register-agreement[b-5wd5ln95sd] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    margin-block-end: 16px;
}

/* The only scrolling part: a long agreement must not push the submit button off a short viewport. */
.biztech-register-agreement-body[b-5wd5ln95sd] {
    align-self: stretch;
    max-block-size: 12rem;
    overflow-y: auto;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    white-space: pre-line;
}
/* /Components/Identity/SetFirstPasswordDialog.razor.rz.scp.css */
/*
    W14-04 · specimen 10's dialog body.

    I17: UiDialog carries NO padding of its own - deliberately, so a caller that forgets one gets a
    visibly flush dialog rather than a subtly wrong one. This is that padding: 24px, the media dialog's
    and the QR dialog's (W19-02, W19-10), where it was 16px and the title sat close to the corner.

    I18: every gap belongs to its container, never a margin on a child. The body is one column whose gap
    spaces the head, the warning, the field and the foot.

    I19: every selector names this component's own markup. Nothing here reaches inside UiButton, whose
    root Blazor stamps with its own scope - a rule that tried would be inert, silently.
*/

.biztech-password-dialog[b-2s3fqbcvjc] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
}

.biztech-password-dialog-head[b-2s3fqbcvjc] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

/* The foot under a rule: what pressing does at the start, the two actions at the end, wrapping under it when narrow. */
.biztech-password-dialog-foot[b-2s3fqbcvjc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-password-dialog-actions[b-2s3fqbcvjc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-inline-start: auto;
}
/* /Components/Identity/TemporaryPasswordDialog.razor.rz.scp.css */
/*
    W27-02 · the person page's account dialogs, SetFirstPasswordDialog's shape.

    I17: UiDialog carries no padding of its own; this is that padding.
    I18: the actions row's gap belongs to the row, never a margin on each button.
    I19: both selectors name this component's own markup.
*/

.biztech-person-dialog[b-i9juvl3nwc] {
    padding: 16px;
}

.biztech-person-dialog-actions[b-i9juvl3nwc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Knowledge/KnowledgeImportPanel.razor.rz.scp.css */
/* W31-01 · I18. The gap between the panel's blocks belongs to the container, never a margin on each. A
   column, because the sentence, the field, the buttons and the check's answer read top to bottom. */
.biztech-knowledge-import-body[b-y15crwa26u] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding-top: 16px;
}

/* W31-01 walk. The heading sits beside its own disclosure mark: a flex summary drops the browser's marker, so the
   mark is drawn here, turned when the panel is open. */
.biztech-knowledge-import-summary[b-y15crwa26u] {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    list-style: none;
}

.biztech-knowledge-import-summary[b-y15crwa26u]::-webkit-details-marker {
    display: none;
}

.biztech-knowledge-import-summary[b-y15crwa26u]::before {
    content: "\25B8";
}

details[open] > .biztech-knowledge-import-summary[b-y15crwa26u]::before {
    content: "\25BE";
}

/* W31-01 walk. A cell's main words and its caption on their own lines, so the two never run together. */
.biztech-knowledge-import-cell[b-y15crwa26u] {
    display: grid;
    gap: 2px;
}

.biztech-knowledge-import-actions[b-y15crwa26u] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-knowledge-import-result[b-y15crwa26u] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Knowledge/KnowledgeItemPanel.razor.rz.scp.css */
/* W7-21 · F9.13. The curation panel's own spacing, and nothing else's.

   🔴 I18. THE GAPS BELONG TO THE CONTAINERS, NEVER TO THE CHILDREN. Two levels of it: the panel spaces
   its blocks, and each block spaces its own controls. A margin per child would add to these - "a 16px
   grid gap plus biztech-mb-2 on each field is 24px down the rows and 16px across the columns: a grid
   that looks misaligned for a reason nobody can see in the markup" - and the ABSENCE of both is worse
   and was live on the composer's tile panel, measured as four controls touching inside a padded panel.

   🔴 I17 IS THE PANEL'S OWN biztech-pa-4 IN THE MARKUP, NOT A RULE HERE. UiPaper has no padding of its
   own, so the utility class is what spaces the contents from the border; this file spaces them from each
   other. The two are different jobs and the invariant names both.

   🔴 I19. EVERY SELECTOR ENDS ON A CLASS THIS FILE'S OWN MARKUP WRITES. Nothing here reaches into
   UiTextField, UiSelect, UiButton or UiPaper: a scoped rule is stamped on the selector's LAST compound,
   so a rule ending on a child component's root would be stamped with markup this file did not write and
   would be inert - no error, no warning.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). */

.biztech-knowledge-panel[b-c7xm3k5uza] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-knowledge-block[b-c7xm3k5uza] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A row of controls: the two reorder buttons, or a submit beside its caption. It wraps, because at
   375px a submit and a sentence do not share a line and the caption must not be pushed off the panel. */
.biztech-knowledge-actions[b-c7xm3k5uza] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* W19 · the file field and the message under it when Attach is pressed with no file, 4px apart - a field's own gap. */
.biztech-knowledge-file[b-c7xm3k5uza] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Knowledge/KnowledgeItemPreview.razor.rz.scp.css */
/* W7-23 · D. The preview pane: the item's facts over its embedded viewer. W19-23 · a head - glyph, title with its
   standing chip, the facts on one line, the two links at the end - over Preview, AI summary and Details tabs.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). Colours come from --biztech-* only (R3). No
   prefers-color-scheme (I16). 🔴 I19. Every selector ends on markup this file writes; the frame and the
   image are this file's own elements. 🔴 I18. Gaps on the containers. */

.biztech-knowledge-preview[b-b8nfjcy8n4] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* Details: the description over the facts as label-and-value rows, two columns where there is room. */
.biztech-knowledge-preview-details[b-b8nfjcy8n4] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-knowledge-preview-facts[b-b8nfjcy8n4] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(12rem, 100%), 1fr));
    gap: 16px 24px;
    margin: 0;
}

.biztech-knowledge-preview-facts > div[b-b8nfjcy8n4] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-knowledge-preview-facts dt[b-b8nfjcy8n4] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-knowledge-preview-facts dd[b-b8nfjcy8n4] {
    margin: 0;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-primary);
}

/* The links at the head's end; under the title when the pane is too narrow for both. */
.biztech-knowledge-preview-links[b-b8nfjcy8n4] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* R5.8: the LINK is the touch target, not the row it sits in. Drawn as an outlined button with its glyph - they were
   bare coloured words - and still an anchor, because it navigates (R9.18). */
.biztech-knowledge-preview-link[b-b8nfjcy8n4] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    min-block-size: var(--biztech-control-height);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    padding-inline: 16px;
    white-space: nowrap;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-primary);
    text-decoration: none;
}

.biztech-knowledge-preview-link:hover[b-b8nfjcy8n4] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, transparent);
}

/* A grid: the glyph over both rows; the title and its chip, then the links, on the first; the facts line across the
   second under both, so the links never take its room and it keeps one line where there is any. */
.biztech-knowledge-preview-head[b-b8nfjcy8n4] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 4px 16px;
}

.biztech-knowledge-preview-head > .biztech-knowledge-preview-glyph[b-b8nfjcy8n4] {
    grid-row: 1 / span 2;
    align-self: start;
}

.biztech-knowledge-preview-head > .biztech-knowledge-preview-line[b-b8nfjcy8n4] {
    grid-column: 2 / -1;
}

/* On a phone: no glyph, and the title, the facts and the two links each a full row; the links wrap rather than break a word. */
@media (max-width: 599.98px) {
    .biztech-knowledge-preview-head[b-b8nfjcy8n4] {
        grid-template-columns: minmax(0, 1fr);
    }

    .biztech-knowledge-preview-head > .biztech-knowledge-preview-glyph[b-b8nfjcy8n4] {
        display: none;
    }

    .biztech-knowledge-preview-head > .biztech-knowledge-preview-line[b-b8nfjcy8n4] {
        grid-column: 1;
    }

    .biztech-knowledge-preview-head > .biztech-knowledge-preview-links[b-b8nfjcy8n4] {
        grid-row: 3;
        padding-block-start: 8px;
    }
}

.biztech-knowledge-preview-name[b-b8nfjcy8n4] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The facts on one quiet line, a dot between each. */
.biztech-knowledge-preview-line[b-b8nfjcy8n4] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 8px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* Each fact keeps its words together, so a wrap falls between facts and never mid-date. */
.biztech-knowledge-preview-line > span[b-b8nfjcy8n4] {
    white-space: nowrap;
}

/* The dot ENDS a fact rather than starting the next, so a wrapped line never opens on one. */
.biztech-knowledge-preview-line > span:not(:last-child)[b-b8nfjcy8n4]::after {
    content: "·";
    margin-inline-start: 8px;
}

.biztech-knowledge-preview-glyph[b-b8nfjcy8n4] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

/* The summary as a tinted note with a sparkle, where it was a bordered paper. */
.biztech-knowledge-preview-summary[b-b8nfjcy8n4] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-info) 8%, var(--biztech-palette-surface));
}

.biztech-knowledge-preview-summary-mark[b-b8nfjcy8n4] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-info) 14%, transparent);
    color: var(--biztech-palette-info);
}

.biztech-knowledge-preview-summary-words[b-b8nfjcy8n4] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* The viewer. The frame takes the pane's width and a reading height, so a PDF's toolbar and its first page
   are both on screen at 768px; the image scales down and never overflows the pane. */
.biztech-knowledge-preview-frame[b-b8nfjcy8n4] {
    min-inline-size: 0;
}

.biztech-knowledge-preview-frame iframe[b-b8nfjcy8n4] {
    display: block;
    inline-size: 100%;
    block-size: 72vh;
    min-block-size: 320px;

    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background-color: var(--biztech-palette-surface);
}

.biztech-knowledge-preview-frame img[b-b8nfjcy8n4] {
    display: block;
    max-inline-size: 100%;
    block-size: auto;

    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}
/* /Components/Knowledge/KnowledgeItemTree.razor.rz.scp.css */
/* W7-21 · F9.13. The knowledge item tree's own presentation, and nothing else's.

   🔴 A SECOND TREE STYLESHEET RATHER THAN A SHARED ONE, AND §16's BOUNDARY IS WHY. The resource library
   and the knowledge library are deliberately different corpora with different governance and a different
   access model - W2-07 reconfirmed that on structural grounds - and the card's `## Do not` forbids
   merging the two surfaces. A shared sheet would be the merge arriving through the stylesheet: one file
   that both pages have to agree about, and a change made for one silently reaching the other. The rules
   below are the same SHAPE as LibraryFolderTree's and that is the whole of the relationship.

   Lengths are multiples of the 4px base unit (R5.1, R5.4), so no layout-constant registry row is needed.

   Colours come from --biztech-* only (R3), which PortalStyleSheetTests asserts over every scoped sheet it
   discovers. No prefers-color-scheme anywhere (I16): the mode is a token, not a media query.

   🔴 I19. EVERY SELECTOR BELOW ENDS ON A CLASS OR ELEMENT THIS FILE'S OWN MARKUP WRITES. Blazor stamps
   the scope attribute on a selector's LAST compound, so a rule ending in a child component's element is
   stamped on markup this file did not write and is inert - no error, no warning, and a class with no
   effective rule renders exactly like a class with none. That is why the chevron's rotation is on a
   <span> this file writes rather than on UiIcon's <svg>, and why nothing here reaches into UiIcon.

   🔴 I18. SPACING BETWEEN SIBLING ROWS IS A GAP ON THE LIST, never a margin per row. */

.biztech-knowledge-branch[b-gayw23w0g3] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;

    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Nested levels step in by five base units. At the eight levels CK_KnowledgeItems_Depth permits that is
   160px of the rail - which the rail has, because it is a 20rem grid track and the deepest title still
   gets 160px of its own. */
.biztech-knowledge-branch .biztech-knowledge-branch[b-gayw23w0g3] {
    padding-inline-start: 20px;
    margin-block-start: 2px;
}

/* One row: chevron, glyph, title. A <summary> and a <button> wear the same class, because they are the
   same object to a reader and differ only in whether they open anything. */
.biztech-knowledge-row[b-gayw23w0g3] {
    display: flex;
    align-items: center;
    gap: 8px;

    inline-size: 100%;

    /* R5.8's touch target under a coarse pointer. A summary is 20px tall by default, which is half of
       what a thumb can hit. */
    min-block-size: 44px;
    padding-inline: 8px;

    /* The button half arrives with user-agent defaults - centred 13px Arial and a shrink-to-fit width -
       which app.css records the board card having had to undo. Declared rather than inherited. */
    font: inherit;
    /* W19-15 · body2, as the agent's knowledge tree reads (W19-17) and the library's folder tree now does. */
    font-size: var(--biztech-font-body2-size);
    text-align: start;
    color: var(--biztech-palette-text-primary);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-pill);

    cursor: pointer;

    /* The summary's own marker, suppressed in the one browser that would still draw it beside the
       chevron this file draws. `display: flex` already removes it in Chromium. */
    list-style: none;
}

.biztech-knowledge-row[b-gayw23w0g3]::-webkit-details-marker {
    display: none;
}

.biztech-knowledge-row:hover[b-gayw23w0g3] {
    background-color: color-mix(in srgb, currentcolor 6%, transparent);
}

/* 🔴 THE ONE LOUD THING IN THE RAIL, AND IT IS LOAD-BEARING: it is the only thing that says which node
   the two panels beside it act on. A tonal container rather than the role itself - PrimaryContainer is
   derived from Primary over the surface it is read on, and its OnPrimaryContainer partner is measured
   with it (ADR 0026 D-H), so this pair cannot fail contrast on a palette that boots. */
.biztech-knowledge-row-chosen[b-gayw23w0g3] {
    background-color: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
    font-weight: 500;
}

.biztech-knowledge-name[b-gayw23w0g3] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* The chevron: a fixed box whether or not a glyph is in it, so a leaf's title lines up with every title
   above it. */
.biztech-knowledge-chevron[b-gayw23w0g3] {
    display: inline-flex;
    flex: none;
    inline-size: 20px;
    block-size: 20px;

    color: var(--biztech-palette-text-secondary);
    transition: rotate var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* The chosen row's chevron takes the row's ink, or it would stay grey on a tinted fill. */
.biztech-knowledge-row-chosen .biztech-knowledge-chevron[b-gayw23w0g3] {
    color: inherit;
}

details[open] > .biztech-knowledge-row > .biztech-knowledge-chevron[b-gayw23w0g3] {
    rotate: 90deg;
}

/* R6.8. The rotation is the only motion in this file, and it is the one thing here that respects a
   reader who asked for none. */
@media (prefers-reduced-motion: reduce) {
    .biztech-knowledge-chevron[b-gayw23w0g3] {
        transition: none;
    }
}
/* /Components/Knowledge/KnowledgeLibraryCounterStrip.razor.rz.scp.css */
/* W8-30 · the reader's three counters. W19-23 · the seam's stat tiles; this sheet only hands them the portal's configured box
   edge, through the wrapper this component writes (I19), with the console's quiet edge when the portal names none. */
.biztech-knowledge-counters[b-xwxlnywyzp]  .biztech-stat-tile {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
}
/* /Components/Knowledge/KnowledgeLibraryTree.razor.rz.scp.css */
/* W7-23 · D. The reader's library tree and its type view.

   🔴 A STYLESHEET OF ITS OWN RATHER THAN KnowledgeItemTree's, because that one is the operator's rail and its
   rows are selection controls with a chosen state two panels act on; these are links to addresses. The
   SHAPE is the same, and that is the whole of the relationship.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). Colours come from --biztech-* only (R3). No
   prefers-color-scheme (I16).

   🔴 I19. EVERY SELECTOR ENDS ON A CLASS OR ELEMENT THIS FILE'S OWN MARKUP WRITES - the chevron's rotation is
   on a <span> this file writes, never on UiIcon's <svg>. 🔴 I18. Gaps on the lists, never margins. */

.biztech-knowledge-library[b-4u8xavixfb] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The Collection / Type switch is the shared .biztech-segmented track (app.css); it keeps its own width. */
.biztech-knowledge-library > .biztech-segmented[b-4u8xavixfb] {
    align-self: flex-start;
}

.biztech-knowledge-library-collections[b-4u8xavixfb] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;

    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-knowledge-library-branch[b-4u8xavixfb] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;

    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Nested levels step in by five base units - KnowledgeItemTree's measure, for its reason: eight levels
   still leave the deepest title room in a 22rem rail. */
.biztech-knowledge-library-branch .biztech-knowledge-library-branch[b-4u8xavixfb] {
    padding-inline-start: 16px;
    margin-block-start: 2px;
}

/* One row: chevron box, glyph, title, and a document's kind. A <summary>, an <a> and a plain <li> wear it
   alike - one object to a reader, differing in what it does. */
.biztech-knowledge-library-row[b-4u8xavixfb] {
    display: flex;
    align-items: center;
    gap: 8px;

    /* W19-23 · 36px and the theme's radius, where a 44px pill made a short list look padded and every hover a capsule. */
    min-block-size: 36px;
    padding-inline: 8px;

    /* Body2, where body1's 16px wrapped most titles in a 22rem rail and left the rows uneven. */
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
    border-radius: var(--biztech-radius-default);

    list-style: none;
}

summary.biztech-knowledge-library-row[b-4u8xavixfb] {
    cursor: pointer;
}

.biztech-knowledge-library-row[b-4u8xavixfb]::-webkit-details-marker {
    display: none;
}

a.biztech-knowledge-library-row:hover[b-4u8xavixfb],
summary.biztech-knowledge-library-row:hover[b-4u8xavixfb] {
    background-color: color-mix(in srgb, currentcolor 6%, transparent);
}

/* The item whose preview is open. A tonal container measured with its ink (ADR 0026 D-H); aria-current says
   the same thing to a screen reader. */
.biztech-knowledge-library-row-chosen[b-4u8xavixfb] {
    background-color: color-mix(in srgb, var(--biztech-palette-primary) 10%, transparent);
    color: var(--biztech-palette-primary);
    font-weight: 600;
}

/* One line each, the full title in the row's title attribute, where long titles wrapped to two and three lines. */
.biztech-knowledge-library-name[b-4u8xavixfb] {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-knowledge-library-kind[b-4u8xavixfb] {
    flex: none;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-knowledge-library-row-chosen .biztech-knowledge-library-kind[b-4u8xavixfb] {
    color: inherit;
}

/* A fixed box whether or not a glyph is in it, so every title lines up. */
.biztech-knowledge-library-chevron[b-4u8xavixfb] {
    display: inline-flex;
    flex: none;
    inline-size: 20px;
    block-size: 20px;

    color: var(--biztech-palette-text-secondary);
    transition: rotate var(--biztech-motion-duration, 120ms) ease-in-out;
}

details[open] > .biztech-knowledge-library-row > .biztech-knowledge-library-chevron[b-4u8xavixfb] {
    rotate: 90deg;
}

/* R6.8. The one motion here, and it respects a reader who asked for none. */
@media (prefers-reduced-motion: reduce) {
    .biztech-knowledge-library-chevron[b-4u8xavixfb] {
        transition: none;
    }
}

/* W19-23 · a collection's (or a kind's) header: the row's shape in the heavier weight, with its count in a pill at the end. */
.biztech-knowledge-library-group-row[b-4u8xavixfb] {
    font-weight: 600;
}

.biztech-knowledge-library-count[b-4u8xavixfb] {
    flex: none;
    min-inline-size: 24px;
    padding-inline: 8px;
    font-size: var(--biztech-font-caption-size);
    line-height: 20px;
    font-weight: 600;
    text-align: center;
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-text-secondary);
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 8%, var(--biztech-palette-surface));
}

/* A folded group's documents step in under its header by the chevron's box and the row's gap. */
details[data-knowledge-library-group] > .biztech-knowledge-library-branch[b-4u8xavixfb],
.biztech-knowledge-library-nothing[b-4u8xavixfb] {
    /* 28px puts a document's glyph under its collection's: the header's chevron box (20px) and gap (8px). */
    padding-inline-start: 28px;
}

/* The glyphs in the secondary ink, so the titles lead; the chosen row's take its colour. */
.biztech-knowledge-library-glyph[b-4u8xavixfb] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
}

.biztech-knowledge-library-row-chosen .biztech-knowledge-library-glyph[b-4u8xavixfb] {
    color: inherit;
}
/* /Components/Knowledge/KnowledgeReviewPanel.razor.rz.scp.css */
/* W7-21 · F9.15. The review panel's own spacing, and nothing else's.

   🔴 I18. THE GAPS BELONG TO THE CONTAINERS, NEVER TO THE CHILDREN — the same two levels
   KnowledgeItemPanel.razor.css uses, and the same reason: a margin per child ADDS to a container's gap
   and produces a layout that is misaligned for a reason nobody can see in the markup.

   🔴 I17 IS THE PANEL'S OWN biztech-pa-4 IN THE MARKUP, NOT A RULE HERE. UiPaper has no padding of its
   own; this file spaces the contents from each other.

   🔴 I19. EVERY SELECTOR ENDS ON A CLASS THIS FILE'S OWN MARKUP WRITES. Nothing reaches into UiChip,
   UiSelect or UiPaper: a scoped rule is stamped on the selector's LAST compound, so a rule ending on a
   child component's root is stamped with markup this file did not write and is silently inert.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). */

.biztech-knowledge-review[b-ldkxo1rd3s] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-knowledge-review-block[b-ldkxo1rd3s] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The standing: a chip and two readings. It wraps, because at 375px "Last reviewed" and "Due" each carry
   a local time AND its offset, and neither may be clipped - the offset is what makes the reading
   unambiguous (I6). */
.biztech-knowledge-review-standing[b-ldkxo1rd3s] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-knowledge-review-actions[b-ldkxo1rd3s] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The accumulation. A plain list: no bullet, no control, and one gap between entries rather than a
   margin on each - F9.15 requires that reviews accumulate and none is ever edited, so this is text. */
.biztech-knowledge-review-history[b-ldkxo1rd3s] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;

    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A rule down the left edge, so a reader can see where one review ends and the next begins without a
   heavier separator between every pair.

   🔴 OutlineSubtle, AND --biztech-palette-divider IS THE MISTAKE THIS FILE MADE FIRST - the third
   file to make it. EducationItemFrame.razor.css and DocumentViewPanel.razor.css each record it: that
   variable is not one of the palette's 22 roles, and "a var() that resolves to nothing falls back to no
   colour at all, so the placeholder would have rendered invisible with every test still green. The
   colour sweep checks for literals, not for names that resolve." TokenSufficiencyTests is what checks,
   and it named this line. OutlineSubtle is the hairline role and it flips with the mode. */
.biztech-knowledge-review-history > li[b-ldkxo1rd3s] {
    padding-inline-start: 12px;
    border-inline-start: 2px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Layout/AnonymousLayout.razor.rz.scp.css */
/* The anonymous /i/{key} shell. Deliberately plain: one branded band, one centred column, nothing
   clickable that is not part of the task.

   T24 replaced this file's five hard-coded colours with theme variables, and that one change is what
   makes dark mode on this page free. MudBlazor declares --mud-palette-* on :root and REGENERATES the
   block when IsDarkMode flips, so these follow the theme with no second variable system, no C#
   emission, and - importantly - no `@media (prefers-color-scheme: dark)` here. A media query would
   follow the OS while MudBlazor follows IsDarkMode, and the two disagree the moment they differ.

   The literals were not wrong before: this page had no IsDarkMode binding at all, so #f7f8fa and
   #0f4c81 were exactly what it rendered. They were consistent with a light-only page. Step 5 binds
   the mode, and these variables are what make the rest of the layout come with it. */

.biztech-anon[b-gxc2mmwtpr] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background: var(--biztech-palette-background);
}

.biztech-anon-header[b-gxc2mmwtpr] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    padding: 1rem 1.5rem;
}

/* W28-15 · D27 · THE USER'S D4: LIGHT KEEPS THE BRAND BAND, DARK USES THE DARK SURFACE. The layout stamps this class from its
   own mode (Effective.Dark), not prefers-color-scheme - which a scoped sheet may not contain and which would follow the OS
   while the toggle follows the person. It is the portal header's treatment (PortalLayout.razor.css): the surface, the primary
   text ink and one outline edge, so the band's ink and the toggle's inherited colour change with it. The mark stays legible:
   the default is the reverse (light-ink) mark, which reads on a dark surface. */
.biztech-anon-header-dark[b-gxc2mmwtpr] {
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    border-block-end: 1px solid var(--biztech-palette-outline);
}

/* The light/dark toggle. On the Primary band it takes the band's ink, as the app bar's toggle takes the app bar's;
   ::deep because UiIconButton renders the button (I19). */
.biztech-anon-toggle[b-gxc2mmwtpr] {
    display: inline-flex;
}

.biztech-anon-header .biztech-anon-toggle[b-gxc2mmwtpr]  .biztech-icon-button {
    color: inherit;
}

/* A form that hides the header keeps the toggle, at the top end of the page with no band behind it. */
.biztech-anon-toolbar[b-gxc2mmwtpr] {
    display: flex;
    justify-content: flex-end;
    padding: 8px 12px 0;
}

.biztech-anon-logo[b-gxc2mmwtpr] {
    height: 2rem;
    display: block;
}

.biztech-anon-main[b-gxc2mmwtpr] {
    flex: 1;
    display: flex;
    justify-content: center;
    /* 🔴 W19 · THE PANEL IS AS TALL AS WHAT IS IN IT. A flex row stretches its items by default, so the
       46rem panel ran from under the header to above the footer whatever it held: three lines of "You
       left the session" or a two-event history sat at the top of a 750px white box. flex-start lets the
       panel end where its content does; main still grows, so the footer stays at the foot. */
    align-items: flex-start;
    padding: 2rem 1rem;
}

/* 🔴 W0-59 · FINDING S6 · box-sizing IS THE WHOLE FIX, AND IT WAS MEASURED IN A BROWSER.
   At 375px this panel computed 368px inside a 360px client width, so /i/{key} scrolled sideways -
   scrollWidth 364 against clientWidth 360. `width: 100%` is a CONTENT width without this line, so the
   1rem padding app.css's phone block gives it and the 1px border below were both added on top of a
   width already equal to the space available. .biztech-paper declares it; this panel never did.
   It is the one page an outsider opens on a phone, which is the page R5.8's touch block exists for. */
.biztech-anon-panel[b-gxc2mmwtpr] {
    box-sizing: border-box;
    width: 100%;
    max-width: 46rem;
    background: var(--biztech-palette-surface);

    /* lines-default, not divider: this edge is what makes the panel read as an object, so it is a
       boundary under WCAG 1.4.11 and carries the 3:1 the palette's Outline role is tested at. */
    border: 1px solid var(--biztech-palette-outline);

    /* T29 N4 · R5.5. Was a literal 6px - the same value the theme sets, restated. One spelling of
       the radius, and it is the variable. */
    border-radius: var(--biztech-radius-default);
    padding: 2rem;
}

/* 🔴 W6-40 · F8.1 · R4.6 APPLIED TO THIS LAYOUT. A WORKING SURFACE IS NOT PROSE.

   .biztech-anon-panel is 46rem because "§7's assignee reads a case" - guidelines §1, 6.3. A stage with
   a participant rail beside it is the board's shape, not a case's, and R4.6 keeps working surfaces
   ("board, case table") uncapped on purpose.

   🔴 AN ALTERNATIVE TO .biztech-anon-panel, NOT A MODIFIER OF IT, AND THAT IS WHAT UtilitySpecificityTests
   FOUND. The first version was `.biztech-anon-panel .biztech-anon-panel-wide` with `padding: 0; border: 0`
   - and a scoped reset of a box-model property is exactly the silent-override shape that test exists to
   catch: Blazor rewrites a scoped selector as `.x[b-xxxxxxxxxx]`, (0,2,0) against a utility class's
   (0,1,0), so a `padding: 0` here would beat every biztech-pa-* anybody later passed - and beat
   app.css's own phone block, which sets `.biztech-anon-panel { padding: 1rem }` at 375px.

   The layout picks ONE class or the OTHER, so the wide panel simply never has a padding, a border, a
   background or a cap to remove. Nothing is zeroed, nothing is overridden, and the phone block does not
   apply because the class it names is not on the element.

   What is deliberately KEPT from the narrow panel is box-sizing and width - W0-59's finding S6, measured
   in a browser: without box-sizing this computed 368px inside a 360px client width and the page scrolled
   sideways. A full-bleed panel has no padding of its own, but its CHILDREN do, so the same trap is one
   nested element away.

   Two pages declare it - SessionViewer and CustomerPresentation - both through FormChromeChannel, so
   /i/{key} and /login keep the prose measure by construction. */
.biztech-anon-panel-wide[b-gxc2mmwtpr] {
    box-sizing: border-box;
    width: 100%;
}

/* T29 N22. The `font-size: 0.8125rem` that was here (13px) is gone rather than rounded, because it
   was the wrong KIND of fix: R4.3 says never pick a size independently of a slot, and 13px is not one
   - it sat between Caption's 12px and Body2's 14px for no recorded reason. The footer now renders as
   <MudText Typo="Typo.caption">, which is the slot for supporting copy, so the size comes from the
   type scale and follows it if the scale ever moves. Colour goes with it (mud-text-secondary). */
.biztech-anon-footer[b-gxc2mmwtpr] {
    padding: 1rem 1.5rem;
    text-align: center;
}
/* /Components/Layout/BackToPlatform.razor.rz.scp.css */
/* W28-18 · D15. The sentence and its button, a column that owns the space between them (I18). */
.biztech-back-to-platform[b-59numx6q17] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
}
/* /Components/Layout/HeaderTenantSwitcher.razor.rz.scp.css */
/* W23-04 · amendment 1, F6 — the platform operator's tenant switcher. TOKENS ONLY: R3.1's sweep in PortalStyleSheetTests
   reads every *.razor.css in this project and refuses a hex or an rgb() literal.

   🔴 THE TRIGGER AND THE ROWS ARE UiMenu's AND UiMenuItem's, so a rule that reaches them says ::deep and names the
   child's own class (I19); the option row's spans and the chip's span are this file's own. No margin: in the header the
   row owns the gap (I18). The menu is the organisation switcher's shape, so the two read as one pair of controls.

   🔴 R13.7 / R13.8 · "WORKING IN" STAYS AT EVERY WIDTH. On the platform the trigger reads "Platform" and folds to its
   glyph below sm, as the organisation switcher's does. Switched into a tenant, the trigger's words are the signal the
   card requires at all times, so they stay, capped and ellipsed rather than widening the page; the full name is in the
   trigger's title and accessible name. */
.biztech-tenant-switcher[b-k4k6fkftc4] {
    display: inline-flex;
    align-items: center;
    min-inline-size: 0;
}

/* A header control rather than a toolbar button: no edge until it is hovered, like the icon buttons beside it. */
.biztech-tenant-switcher[b-k4k6fkftc4]  .biztech-menu-trigger-labelled {
    border-color: transparent;
    border-radius: var(--biztech-radius-pill);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-button-weight);
}

.biztech-tenant-switcher[b-k4k6fkftc4]  .biztech-menu-trigger-label {
    max-inline-size: 16rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Switched in: the warning tint the "Working in" chip carried, so another tenant's data on screen is never quiet. */
.biztech-tenant-switcher--inside[b-k4k6fkftc4]  .biztech-menu-trigger-labelled {
    color: var(--biztech-palette-on-warning-container, var(--biztech-palette-warning));
    background: var(--biztech-palette-warning-container, transparent);
}

.biztech-tenant-switcher__option[b-k4k6fkftc4] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-tenant-switcher__name[b-k4k6fkftc4] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-tenant-switcher__hidden[b-k4k6fkftc4] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* One live tenant: the chip alone, no menu (W23-08 · D5). */
.biztech-tenant-switcher__chip[b-k4k6fkftc4] {
    display: inline-flex;
    flex: 0 1 auto;
    min-inline-size: 0;
    max-inline-size: 16rem;
    overflow: hidden;
}

/* The rail's glyph; everywhere else the words alone. */
.biztech-tenant-switcher__chip-glyph[b-k4k6fkftc4] {
    display: none;
}

@media (max-width: 599.98px) {
    .biztech-tenant-switcher:not(.biztech-tenant-switcher--inside)[b-k4k6fkftc4]  .biztech-menu-trigger-label {
        display: none;
    }

    .biztech-tenant-switcher--inside[b-k4k6fkftc4]  .biztech-menu-trigger-label {
        max-inline-size: 6rem;
    }

    .biztech-tenant-switcher__chip[b-k4k6fkftc4] {
        max-inline-size: 6rem;
    }
}
/* /Components/Layout/InstallPrompt.razor.rz.scp.css */
/* W1b-05 · F2.23 · the install strip.

   🔴 LAYOUT ONLY, AND NO BOX-MODEL PROPERTY THE UTILITY LAYER OWNS.

   R14.1a: Blazor's CSS isolation rewrites `.biztech-install` as `.biztech-install[b-xxxxxxxxxx]` -
   (0,2,0) against a utility class's (0,1,0) - and _Host.cshtml links BizTech.Portal.styles.css AFTER
   app.css on purpose, so a scoped rule wins twice over. W0-52 measured what that costs: nine utilities
   computing zero, including `biztech-pa-4` on every UiPaper in the application, with the class present
   on the element and doing nothing. A class that is present and inert passes every check in this
   repository.

   So no margin and no padding here. Spacing between this strip and the grid below it is the page's.

   The 12px gap is the one MainLayout.razor.css:70, MainNavMenu.razor.css:36 and UiAlert.razor.css:14 all
   declare - BizTechCssVariables emits no spacing custom property, so a literal is what this layer has and
   12px is what it consistently means by "between two controls" (R5.4: not a magic number, the house one).

   🔴 NO COLOUR. R14.1 layer 4's hex sweep forbids a literal, and there is nothing to declare anyway: the
   strip sits on the page's own ground and UiText inherits the ink. A background would need a semantic
   role, and "an unobtrusive affordance" is exactly the thing that should not have one.

   R13.8 · `flex-wrap` rather than a min-width: at 375px the sentence and the two controls do not fit one
   line, and wrapping is what keeps every element's right edge inside #biztech-main. Nothing here declares
   overflow - InstallPromptTests walks this subtree, and an `overflow-x` would exclude it from that walk
   while looking like a fix. */

/* 🔴 A CARD, IN THE PORTAL CARD'S LOOK (PortalCard.razor.css): the surface, the quiet edge, corners twice the
   theme's radius, and the tinted icon square at its start. It was a bare row on the page's ground - a sentence at
   one edge and a button at the other with a strip of nothing between them - so it read as stray text above the
   tiles rather than as a suggestion. 16px below it, through margin rather than the page's gap, because the page
   above it is not a flex column. Every colour is a token. */
.biztech-install[b-uur1rtvl9p] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
    margin-block-end: 16px;
    padding: 12px 12px 12px 16px;
    /* The theme's install suggestion (ThemePortalLook): this card, the primary's pale tone, or the primary, each with
       its own ink, which the dismiss button inherits. */
    border: 1px solid var(--biztech-portal-install-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-portal-install-ground, var(--biztech-palette-surface));
    color: var(--biztech-portal-install-ink, var(--biztech-palette-text-primary));
}

/* The Install button, reversed on a brand-coloured suggestion so it is not primary on primary. */
.biztech-install[b-uur1rtvl9p]  .biztech-install-accept {
    background: var(--biztech-portal-install-action-ground, var(--biztech-palette-primary));
    color: var(--biztech-portal-install-action-ink, var(--biztech-palette-on-primary));
}

.biztech-install-glyph[b-uur1rtvl9p] {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    /* The portal's icon box (Items), at a list row's corners, as the tiles' is. */
    border-radius: var(--biztech-portal-icon-radius-row, var(--biztech-radius-default));
    background: var(--biztech-portal-icon-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));
}

.biztech-install-actions[b-uur1rtvl9p] {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-inline-start: auto;
}

.biztech-install[b-uur1rtvl9p]  .biztech-install-text {
    color: var(--biztech-portal-install-ink, var(--biztech-palette-text-primary));
    font-size: var(--biztech-font-body1-size);
}

/* The sentence takes the room the two controls do not, so the buttons stay together when it wraps.

   ❗ ::deep, AND IT WAS MISSING FOR AS LONG AS THIS RULE HAS EXISTED. The class is handed to UiText as
   a Class parameter, so it lands on UiText's OWN root and carries UiText's scope attribute - never this
   file's. The compiled selector was `.biztech-install-text[b-thisfile]` and it matched nothing, so the
   sentence has always been a plain flex item: no grow, no 12rem basis, and at 375px the two buttons
   wrapped apart instead of staying together. Found by
   ScopedStyleReachTests.No_scoped_rule_names_a_class_only_a_child_component_is_handed, which W8-25 added
   after a browser found the same shape on the composer's tile heads. */
.biztech-install[b-uur1rtvl9p]  .biztech-install-text {
    flex: 1 1 12rem;
}

/* 🔴 R5.8's 44px, CARRIED BY THIS COMPONENT RATHER THAN BY WHICHEVER SHELL HOSTS IT.

   InstallPromptTests.Both_controls_meet_the_touch_minimum_under_a_coarse_pointer measures the rendered
   box in both axes, and it FAILED the moment W1b-08 moved `/portal/{slug}` and `/` off AnonymousLayout:
   42.5px and 32px against 44. Nothing about this strip changed - what changed is that app.css's coarse
   block is scoped to `.biztech-anon`, and this strip is now drawn inside PortalLayout too.

   That test's own message says where the fix goes: "Fix the control's size, never that block: it is a
   guardrail." So the floor is declared here, once, and holds on both shells - which is better than the
   state before this card, where the strip met R5.8 only because of where it happened to be rendered.

   The size class is named and both axes are floored for the icon button, for the reasons app.css's block
   records at length: UiButton floors the same property at (0,2,0) through scoped CSS, and UiIconButton
   sets `block-size` in both axes, so a single-axis floor leaves a 44x32 target.
   🔴 AND ::deep, WHICH IS THE HALF THAT WAS WRONG ON THE FIRST ATTEMPT AND IS R14.1a AGAIN.
   Without it these selectors were present and inert: scoped CSS appends this component's [b-xxxxx] to
   the last compound, and the buttons are rendered by the SEAM components, so they carry the seam's scope
   attribute and not this file's. The rule resolved, matched nothing, and the measurement did not move by
   a pixel. `X ::deep Y` compiles to `X[b-xxxxx] Y` - the attribute lands on the ancestor this file does
   own - which is the same reason PortalCard.razor.css reaches a section's anchors with it. */
@media (pointer: coarse) {
    .biztech-install[b-uur1rtvl9p]  .biztech-install-accept.biztech-button-small,
    .biztech-install[b-uur1rtvl9p]  .biztech-install-accept.biztech-button-medium,
    .biztech-install[b-uur1rtvl9p]  .biztech-install-dismiss {
        min-block-size: 44px;
    }

    .biztech-install[b-uur1rtvl9p]  .biztech-install-dismiss {
        min-inline-size: 44px;
    }
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* W0-51 · the operator shell's own chrome. W0-53 · and now the whole of it.

   🔴 THIS FILE GREW BECAUSE MUDBLAZOR STOPPED SIZING THE SHELL. Until W0-53 the app bar, the drawer
   and the main content were MudAppBar, MudDrawer and MudMainContent - MudBlazor laid them out and
   BizTechThemeProvider painted them - and this sheet held two rules because everything else already
   existed. The layout is <header>, <aside> and <main> now, so their box model is here.

   Every value below is a token or a layout constant, and there is no colour literal and no
   `prefers-color-scheme` (I16 · R7.3): UiThemeTokens declares --biztech-* and re-emits the block when
   the mode flips, so a media query would follow the OS while the application follows the toggle, and
   the two disagree the moment they differ. AnonymousLayout.razor.css carries the same note.

   Scoped rather than global, and that is R14.1 layer 3 read literally: every element these rules touch
   is one THIS component renders. The two exceptions are already global for the opposite reason -
   .biztech-skip-link and the shared focus ring in css/app.css are application rules that no single
   component owns. */

/* The frame. A grid rather than a flex row, because the app bar spans BOTH columns and the drawer and
   the main content share the row beneath it - which is one declaration as a grid and a nest of
   wrappers as anything else. */
.biztech-shell[b-y45if9bi06] {
    display: grid;
    grid-template-columns: auto 1fr;
    /* 🔴 W0-27 · A THIRD ROW, `auto`, so the footer takes its content's height and 1fr keeps giving the
       main landmark everything left over. min-block-size: 100vh below already pins the footer to the
       bottom of a short page. The narrow-viewport block redeclares only grid-template-columns, so this
       row holds at both widths. */
    /* 🔴 W19-14 · TWO ROWS, NOT THREE: THE APP BAR IS THE PHONE'S ONLY. The drawer spans both rows as the console's whole
       chrome, the page and the footer share the second column. The narrow block at the end of this file puts the bar's row
       back, for the bar it still draws there. */
    grid-template-rows: 1fr auto;
    min-block-size: 100vh;

    /* 🔴 W0-63 · FINDING 6 · THE CONSOLE'S DENSITY, AND IT IS A TOKEN SO THAT NOTHING ELSE MOVES.

       Custom properties inherit, and .biztech-shell is an element THIS component renders - so a scoped
       declaration reaches every descendant, including the seam's own elements, which is R14.1 layer 3
       read literally. app.css's --biztech-switch-ground is the in-repo precedent for narrowing a token by
       selector, and BizTechCssVariables.ControlHeight declares the 40px default at :root.

       This is what keeps /i/{key}, /login and /register at today's boxes without a single rule in this
       change mentioning them - which the card's ## Do not requires and
       AssigneeFormViewportTests.Every_tap_target_meets_the_touch_minimum measures.

       32px, not 36 or 30: the 4px base unit (R5.1), and it is what a small button already declares - so a
       field and the button beside it are the same box for the first time. R5.8 exempts the operator
       console by decision (mouse at a desk), and only the console.

       W19-07 · The 32px now comes from BizTechCssVariables.ConsoleControlHeight, emitted as
       --biztech-console-control-height and replaced by the theme's own height when it names one. A literal
       here out-ranked the theme's :root value, so the setting reached only the pages outside the console. */
    --biztech-control-height: var(--biztech-console-control-height);
    --biztech-control-padding-block: 4px;

    /* 🔴 W0-68 · THE RAIL'S WIDTH, DECLARED HERE AND READ BELOW.

       W0-68 gave it a home because it had TWO readers then: .biztech-drawer's own inline-size, and the
       snackbar host's leading inset, which had been a separate raw 16px measured against the VIEWPORT -
       so the message started underneath the rail and no test could see it. The host is anchored to the
       trailing edge now and reads nothing about the rail, so this is a named constant with one reader
       rather than two numbers that had to agree. It stays named: 240 is a measurement, and the drawer's
       own comment below says why a literal there would be the wrong shape of number.

       240px is what MudDrawer rendered at and what T24's measurements were taken against; the drawer's
       own comment says moving it would silently invalidate a recorded measurement, which is precisely
       why the number now has one home. 60 x 4 on the base unit (R5.1), so no row is added to §5's
       layout constant registry.

       A scoped custom property rather than a :root token, and W0-63's --biztech-control-height two rules
       up is the precedent: custom properties inherit, so a declaration on an element THIS component
       renders reaches every descendant including other components' elements (R14.1 layer 3). The rail
       exists on this shell and nowhere else - AnonymousLayout and SignInLayout render no drawer - so a
       token at :root would be a global answer to a question only one layout asks. */
    --biztech-drawer-inline-size: var(--biztech-drawer-width, 272px); /* W21-03: the theme's layout.drawerWidth; W19-14: 272px beneath it */

    /* W19-14 · the folded drawer's width: a 40px glyph row and the 12px gutter either side. 16 x 4 on the base unit (R5.1). */
    --biztech-drawer-rail-size: 64px;

    /* 🔴 WHERE THE CONTENT AREA BEGINS DOWN THE PAGE, for a fixed overlay that must clear the app bar.

       Row one above is exactly this tall, so the two read ONE declaration: a console that changes its
       density moves the bar and everything anchored below it in the same edit, rather than leaving a
       number somewhere else that happens to agree today.

       🔴 IT REPLACED --biztech-content-inline-start, W0-68's INLINE twin, AND THE SWAP IS THE WHOLE
       STORY. That property existed for one reader: UiSnackbarHost, which started at the viewport's
       leading edge where the 240px rail sits, so every message lost its first words behind it - five
       stacked messages each reading "e case type configured, so there is nothing to open. ...". The
       host is anchored to the TRAILING edge now, where there is no rail to clear, so nothing read the
       inline property any more and a property nothing reads is the W0-59 defect this repository has
       already paid for once. Its :has() rule and its narrow override went with it.

       🔴 SCOPED TO THIS SHELL, NOT :root, AND THAT IS WHAT MAKES THE OTHER TWO LAYOUTS RIGHT.
       --biztech-appbar-height IS at :root - UiThemeTokens emits it on every surface - so a host reading
       that token directly would sit 64px down on AnonymousLayout and SignInLayout, which render no app
       bar at all and whose own headers are not that tall. This shell is the only element that renders
       one, so the reader's fallback answers for everywhere else. */
    /* 🔴 W19-14 · NOTHING ABOVE THE CONTENT ON A DESKTOP NOW. The bar this read is the phone's only, so the content begins at
       the top; the narrow block puts the bar's height back. Pages that fill the window read this, never the bar's token. */
    --biztech-content-block-start: 0px;
}

/* Spans both tracks, like the app bar, so the drawer's 240px column does not indent it.
   🔴 AND DECLARES NO BOX OF ITS OWN. The chrome inside is nothing at all for every tenant that has
   configured neither block, which is every deployment until someone writes a row - so padding and a rule
   here would show a permanently empty bordered strip at the bottom of this console. TenantChrome's own
   wrapper carries them, and exists only when there is something to show. Found by looking at the running
   app, which is the only place it was visible. */
.biztech-footer[b-y45if9bi06] {
    /* W19-14 · beside the drawer, which spans both rows now, rather than under it. */
    grid-column: 2;
    grid-row: 2;
}

/* W22-08 · a page that fills the window to the bottom - the admin assistant's chat, whose question box is pinned there - says so with
   data-without-footer, and the footer is not drawn under it: it could only ever be a strip below the box, reached by scrolling past the
   end of the conversation. Every other page keeps it. */
.biztech-shell:has([data-without-footer]) .biztech-footer[b-y45if9bi06] {
    display: none;
}

/* W22-08 · a page that is the assistant itself - the Setup assistant's page, the same conversation the launcher would open - says so
   with data-without-launcher, and the floating launcher and its panel are not drawn over it: a second way into the conversation on
   screen beside the first. Every other page keeps them. */
.biztech-shell:has([data-without-launcher]) .biztech-assistant-dock[b-y45if9bi06] {
    display: none;
}

/* 🔴 THE APP BAR IS A BANNER, AND SINCE W0-65 IT IS PINNED TO THE VIEWPORT AS WELL AS PLACED IN THE
   GRID. MudAppBar was position: fixed with a spacer beneath it; a grid row plus `position: sticky`
   needs no spacer, because a sticky box stays in flow and its row still reserves the height. The
   `sticky` block below carries the measurement and the reason it is not `fixed`.

   The height comes from --biztech-appbar-height, which UiThemeTokens emits from the same constant
   MudBlazor's app bar used - so nothing on any page moves by a pixel. */
.biztech-appbar[b-y45if9bi06] {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 12px;
    padding-inline: 12px;

    background: var(--biztech-palette-appbar-background);
    color: var(--biztech-palette-on-appbar);

    /* 🔴 W0-69 · ADR 0026 D-E. A BORDER, NOT A SHADOW - AND `outline`, NOT `outline-subtle`.

       This was `box-shadow: var(--biztech-shadow-raised)`, which is D-E's own counter-example: an
       in-flow surface taking its depth from a shadow. R6.6 already said a border does on dark what a
       shadow does on light; D-E applies that to light too, and leaves the dialog as the one place in
       this application where a shadow reads as depth.

       It also became NECESSARY rather than merely preferable. D-A makes the light bar Neutral0, which
       is what DrawerBackground and Surface are in that mode - so the bar, the drawer and a card are
       all the same white, and this edge is the only thing separating the chrome from the page. That
       makes it a MEANINGFUL border under R3.5, so it takes `outline`: R3.7 declares `outline-subtle`
       ornament and leaves it DELIBERATELY UNTESTED, and a rule that depends on being seen must not
       depend on a ratio nobody checks.

       Measured 2026-09-03 by scripts/contrast-audit.py: Outline is 3.33:1 against Surface and 3.91:1
       against Background. The light bar IS Surface's value and the dark bar IS Background's, so both
       sides of this border are pairs PaletteContrast.RequiredPairs already holds - no pair was added.
       1px per R5.6. */
    border-block-end: 1px solid var(--biztech-palette-outline);

    /* 🔴 W0-63 · S2. `1fr` is `minmax(auto, 1fr)`, and this flex row's automatic minimum is what
       set the shell's single grid track to 382.391px at a 375px viewport - 32 + 166.4 + 0 + 32 + 36 + 32
       of children, 5 gaps of 12, 24 of inline padding. .biztech-main has carried this line since W0-59;
       the app bar spans the same track and never did, so every page showing the Developer Mode switch
       scrolled 7.4px sideways on a phone. /ui does not show that switch, which is why the browser
       suite's two routes both looked clean - PortalBrowserStubs grants the edit-in-context key now;
       W0b-07 then
   moved what that key buys from an app-bar switch to the editable regions' own gate, so the app bar this
   was measured against has two fewer children and roughly 40px of slack at 375. And
       The_shell_is_no_wider_than_the_viewport failed at 375 on both of them before this line. */
    min-inline-size: 0;

    /* 🔴 W0-65 · FINDING 1. STICKY, AND IT IS THE DRAWER'S OWN ARGUMENT ONE RULE DOWN.

       This block declared no `position` at all until this card, so on any page taller than the viewport
       the banner left the screen while .biztech-drawer - given `position: sticky` by W0-63 - stayed put.
       One chrome, two behaviours, decided by which of the two somebody had got to. Measured at 1440x900
       and at 375: the bar's top read -800 after scrolling 800px, against the drawer's 64.

       🔴 A GRID ITEM'S STICKY RANGE IS THE GRID CONTAINER, NOT ITS OWN GRID AREA, and this fix turns
       entirely on that. Row one is exactly var(--biztech-appbar-height) tall, so a banner clamped to its
       own area would have ZERO sticky range and this declaration would silently do nothing. Measured
       2026-08-31 in headless Chromium on a reduction of this grid before it was written: with sticky the
       bar's top reads 0 at scroll 800 where it read -800 without, and the drawer's box, the main
       landmark's origin and all three computed row tracks are unchanged.

       `sticky`, not `fixed`, which is the drawer's sentence verbatim: sticky stays in flow, so the grid
       row still reserves its height and .biztech-drawer, <main> and .biztech-footer keep the placements
       they have. A fixed banner would stop being a grid item and auto-placement would put the drawer in
       row one - it needs an explicit `grid-row` on three other elements to reach the same result.

       AND .biztech-footer IS NOT COVERED, which is that argument again: a sticky box is clipped to its
       containing block, so at the page's end the banner is still at the viewport's TOP while row three
       is at its bottom. */
    position: sticky;
    inset-block-start: 0;
    z-index: var(--biztech-layer-appbar);
    grid-row: 1;
}

/* Mirrors .biztech-anon-logo, which sits on the same band on the anonymous layout; the mark's aspect ratio does the rest.

   🔴 W26-02 · THE HEIGHT IS THE THEME'S, AND THE BAR IS ITS CEILING. layout.logoSize sets it (24, 32, 40 or 48px; 2rem
   unset), and max-block-size keeps 8px clear above and below at whatever height layout.appbarHeight gives the bar - so the
   largest step under a 48px bar draws at 32px rather than spilling out of it. The width cap, object-fit and
   object-position are PortalLayout.razor.css's .biztech-portal-mark, for the same reasons: the shipped 166.4px mark sits
   under the cap, so the unset bar is unchanged, and a wide wordmark is narrowed on a phone without being cropped. */
.biztech-appbar-logo[b-y45if9bi06] {
    block-size: var(--biztech-appbar-logo-height, 2rem);
    max-block-size: calc(var(--biztech-appbar-height, 64px) - 16px);
    inline-size: auto;
    max-inline-size: clamp(12rem, 30vw, 16rem);
    object-fit: contain;
    object-position: left center;
    display: block;
}

/* The drawer. 240px is what MudDrawer rendered at and what T24's measurements were taken against -
   "content flush against the drawer at x=240" is in PortalPageShellTests' own header, so moving it
   would silently invalidate a recorded measurement.

   `hidden` does the hiding: the layout toggles the attribute rather than unmounting the nav, so the
   items keep their identity across a toggle. display: none is the user agent's default for [hidden]
   and is restated here only because the flex display below would otherwise win. */
.biztech-drawer[b-y45if9bi06] {
    /* 🔴 W0-68 · READ RATHER THAN WRITTEN. The number is declared once on .biztech-shell, because the
       snackbar host's leading inset is derived from it too - see that declaration.

       WITH A FALLBACK, and R5.5's own note is the reason: "a var() that resolves to nothing falls back
       to no radius at all - silently". This property is declared on .biztech-shell and NOWHERE else -
       there is no :root emission, unlike --biztech-control-height - so the day it stops reaching this
       aside, `inline-size` computes to `auto` and the rail collapses to its content's width. The host's
       own read carries a fallback for the same reason; this one had none. */
    inline-size: var(--biztech-drawer-inline-size, 272px);
    /* 🔴 W19-14 · A COLUMN OF FOUR: the head, the switchers, the navigation's own scroller, the foot. The scroller is the only
       part that scrolls (.biztech-drawer-scroll), so this box clips nothing and the switchers' and the account's menus open
       over the page. */
    display: flex;
    flex-direction: column;
    grid-row: 1 / -1;

    /* The rail's own track, named rather than inferred. See .biztech-main's `grid-column` for what
       auto-placement did when this element stopped being a grid item. */
    grid-column: 1;

    /* 🔴 W14-01 · A HAIRLINE, BECAUSE THIS BAR SITS BESIDE THE WINDOW'S OWN.

       The scrollport above is W0-63's and is not reopened: 36 nav links are 1,887px of list in a 719px
       rail, and before that fix the last of them sat 683px below the fold with no way to reach it. What
       it costs on a page that ALSO scrolls is two full-width scrollbars on one screen, 1,200px apart,
       which reads as two windows rather than one. Seen on /session/{caseId} on 2026-09-11.

       SessionChat.razor.css is the precedent, and the rule it sets is worth stating: a scrollport INSIDE
       a page takes a hairline, so the page's own bar stays the one that reads as the document's. `thin`
       rather than `none` - UiTabs uses `none` where an arrow carries the affordance instead, and nothing
       here would carry it. The rail still scrolls by wheel, by drag and by keyboard. */
    /* (The scroller carries the hairline scrollbar now; see .biztech-drawer-scroll.) */

    /* 🔴 THE BAR IS DRAWN ONLY WHILE THE RAIL IS BEING SCROLLED, AND `thin` ABOVE IS WHAT MAKES THAT
       FREE. The scrollbar was permanently visible on the drawer - measured in Chrome on macOS, `scrollbar-width: thin` reserves 11px of PERMANENT, space-taking gutter (`auto`
       takes 15, `none` takes 0) and paints a thumb in it whether or not anybody is looking at the rail.

       🔴 THE COLOUR CHANGES, NOT THE WIDTH, AND THAT IS THE WHOLE TRICK. Hiding the bar with
       `scrollbar-width: none` and restoring `thin` on hover would move every nav label 11px sideways the
       moment the pointer crossed the rail. The gutter is reserved in both states and only its INK
       changes, so nothing reflows - and the gutter is only reserved at all while the content overflows,
       because `overflow-y` is `auto` rather than `scroll`.

       The two rules that do it are at the end of this file, with the other conditional blocks, and
       biztech-rail.js is what tells them when: a scroll event sets data-scrolling and a second of quiet
       clears it. Keyboard scrolling raises the same event, so arrow keys reveal it too. */
    border-inline-end: 1px solid var(--biztech-palette-outline-subtle);
    background: var(--biztech-palette-surface);

    /* 🔴 W0-63 · FINDING 1. STICKY AND HEIGHT-BOUNDED, WHICH IS WHAT MAKES THE `overflow-y` ABOVE
       MEAN ANYTHING.

       The grid row is `1fr` under `min-block-size: 100vh`, so on a page taller than the viewport the row
       grew to the main content and this box grew with it: measured 1,527.2px against 836px available on
       /inquiries, 3,288.9px on /ui, `scrollHeight == clientHeight` in both, and the last of 27 nav
       entries at y = 1,583.2 - 683px below the fold, reachable only by scrolling the page out from under
       the item you were aiming at. On a SHORT page (/Error) the same drawer measured 768.1px and scrolled
       inside itself correctly, which is how one console had two behaviours decided by page length.

       A definite block-size takes this element out of the row's height calculation, so the row is the
       main content's height and this box is the viewport's.

       `sticky`, not `fixed`: sticky stays in flow and is clipped to its own grid area, so .biztech-footer
       in row three is not covered - which a fixed drawer of this height would do on a short page, and
       which is a Done-when clause of its own. The narrow block at the end of this file redeclares
       `position: fixed` and wins by order, so the overlay drawer below sm is unchanged. */
    position: sticky;
    inset-block-start: 0;
    block-size: 100vh;
    align-self: start;
    /* W19-14 · above the page, as the app bar was: the drawer's menus open over the content beside it. */
    z-index: var(--biztech-layer-appbar);

    /* 🔴 THE RAIL FADES AND SLIDES RATHER THAN VANISHING, AND THE HARD PART IS `display`.

       The drawer vanished between frames, and no stylesheet could have done otherwise - the rule below is `display: none`, and an element going to or from `none` has no
       rendered box to interpolate against, so a transition on it never starts. That is the whole of the
       bug; nothing was missing a duration.

       `allow-discrete` is what makes the flip schedulable: `display` still changes discretely, but on a
       CLOSE it now changes at the END of the 120ms instead of the start, which is the frame the opacity
       and the transform need to exist in. R6.7's budget is unspent by this - what ANIMATES is `opacity`
       and `transform` and nothing else; `display` is sequenced, not interpolated, and no laid-out
       property is on the list. The @starting-style block below is the OPEN direction's half of the same
       problem: an element arriving from `display: none` has no before-change style, so without it the
       open would still snap.

       var(--biztech-motion-duration, 120ms) and ease-in-out, which is the budget verbatim (R6.7), and the reduced-motion block at the
       end of this file is R6.8's.

       🔴 13.2 · `margin-inline-start` IS A LAYOUT TRANSITION, AND IT IS LICENSED BY NAME RATHER THAN
       SMUGGLED IN. R6.7 ruled out animating anything that lays out, and the first version of this file
       obeyed that literally: the desktop rail could only FADE, because it is a 240px grid track and the
       page content is laid out beside it. It is noticeable at phone widths and much less so on a
       laptop, which is that restriction being felt rather than a bug. Guidelines 13.2 licenses the exception for this one surface; read its R6.7 note
       before copying this line anywhere else.

       🔴 THE MARGIN, NOT THE TRACK, AND THE DIFFERENCE IS WHETHER THE NAV REFLOWS. The obvious
       version transitions .biztech-shell's `grid-template-columns` from 240px to 0 - but the rail is a
       grid item, so its own box shrinks with the track and 36 nav labels rewrap, twice, on every toggle.
       A negative inline-start margin moves the rail instead of resizing it: `auto` track sizing reads the
       item's MARGIN box, so the track follows the margin down to zero while the rail's own box stays
       240px wide and nothing inside it moves relative to anything else.

       Measured on a standalone reproduction at 1200px, 2026-09-22, sampling every frame of one close:
       the main landmark's left edge went 241 → 1 over 113ms while a nav item's width read 240px in every
       frame, and `scrollWidth == clientWidth` throughout - the rail leaves by the inline-start edge, and
       overflow there creates no scroll in LTR, so nothing needs clipping. */
    transition:
        opacity var(--biztech-motion-duration, 120ms) ease-in-out,
        transform var(--biztech-motion-duration, 120ms) ease-in-out,
        margin-inline-start var(--biztech-motion-duration, 120ms) ease-in-out,
        inline-size var(--biztech-motion-duration, 120ms) ease-in-out,
        display var(--biztech-motion-duration, 120ms) ease-in-out allow-discrete;
}

/* 🔴 THE CLOSED STATE, AND `display: none` IS STILL THE FIRST LINE OF IT.

   PortalStyleSheetTests.A_class_toggled_with_hidden_and_given_a_display_declares_a_hidden_rule is the
   reason it is written out rather than left to the user agent, and the rest of this rule is why that
   test matters more than usual here: the transition above keeps the box rendered for var(--biztech-motion-duration, 120ms) after the
   attribute lands, so for those 120ms the closed drawer is still a 240px grid track and still in the
   tab order. It has to end at `none` - anything softer (`visibility`, `opacity` alone) would leave the
   rail holding its column open on a closed console, which is the layout W0-59 collapsed.

   At desktop that is the whole of the closed state: the drawer fades where it stands and the content
   snaps into the freed column, because the column IS layout and R6.7 does not let it be animated. The
   narrow block at the end of this file adds the slide, where the drawer is `position: fixed` and
   displaces nothing. */
.biztech-drawer[hidden][b-y45if9bi06] {
    display: none;
    opacity: 0;

    /* 🔴 13.2 · THE RAIL'S WHOLE OUTER WIDTH, WHICH IS THE TOKEN PLUS ITS BORDER.

       `+ 1px` is the `border-inline-end` declared above (R5.6's hairline), and leaving it out is a
       visible bug rather than a rounding argument: at `calc(var(...) * -1)` the border stays on screen,
       so the content settles at x=1 for the last frame and then jumps to 0 when `display: none` lands.
       Measured - the reproduction this was written against showed exactly that 1px step.

       The narrow block at the end of this file puts this back to 0: there the rail is `position: fixed`,
       where a margin displaces nothing and would only add itself to the transform. */
    margin-inline-start: calc((var(--biztech-drawer-inline-size) + 1px) * -1);
}

/* The open direction. A transition needs a before-change style and an element that was `display: none`
   has none, so this is where the open animates FROM; without it the close animates and the open snaps,
   which is the worse half of the original bug rather than a fix for it.

   🔴 GATED ON data-motion, AND THAT ATTRIBUTE EXISTS FOR THIS ONE RULE. `@starting-style` cannot
   tell "arrived from display: none" apart from "rendered for the first time", so ungated it also ran on
   every page LOAD - sliding the rail in and taking 241px of content with it, which is layout shift on
   arrival rather than a response to anything. MainLayout sets data-motion="ready" after its first
   render, so this matches only once a frame has already been painted.

   It was caught by PortalLandmarkOverflowTests.The_walk_ignores_a_progress_bar_that_is_mid_slide, which
   reads one element's edge twice: 2489.23 with the landmark still at x=0 and 1430px wide, then 2302.38
   once the entrance settled at x=241 and 1184px. That suite is about a progress bar and knows nothing
   about this rule - a page still moving 120ms after load breaks whatever happens to be measured.

   THE CHILD COMBINATOR, like the :has() above: the shell is this element's parent, and a descendant
   selector would also match a rail nested inside the island's own layout (ADR 0013). */
@starting-style {
    .biztech-shell[data-motion="ready"] > .biztech-drawer[b-y45if9bi06] {
        opacity: 0;
        margin-inline-start: calc((var(--biztech-drawer-inline-size) + 1px) * -1);
    }
}

/* The main landmark is a <main> rather than the div MudMainContent rendered, so it needs to fill its
   grid cell the way that div filled its parent, or every page loses the layout it was written
   against. min-inline-size: 0 is what stops a wide table stretching the grid column instead of
   scrolling inside it. */

/* 🔴 W6-42 · `clip` AND NOT `hidden`, AND THE DIFFERENCE IS A SCROLL CONTAINER NOBODY WANTED.

   This line said `overflow-x: hidden` from W0-51 until W6-42. The two clip identically - that is the
   whole of what R13.8 and its suites measure, and none of their assertions change - but `hidden`
   ALSO makes the element a scroll container, and `clip` does not. That difference is invisible until
   something inside wants a scrollport.

   🔴 MEASURED ON 2026-09-07, on /session/{caseId} at 1264x615. SessionStage's band declares
   `position: sticky; top: 0`, the declaration applied, and the band still scrolled away: 64 -> -336
   over a 400px scroll, the full distance. The ancestor walk says why -

     DIV.biztech-session-stage__bar  position=sticky top=0px               height=39
     DIV (the frame's own)           position=static                       height=2370
     MAIN.biztech-main               overflowX=hidden overflowY=auto       height=2370

   A sticky element resolves against its nearest ancestor SCROLLPORT, and `overflow-x: hidden`
   computes overflow-y to `auto`, so .biztech-main was it. Its height equals its content, so it never
   scrolls: the band pinned faithfully to a box that never moves. The document was what scrolled.

   The same band on AnonymousLayout pinned correctly the whole time - 96 -> 0 - because that chain
   declares no overflow at all. Two layouts, one component, opposite behaviour, and nothing in any
   stylesheet looked wrong.

   🔴 WHY THIS IS NOT A WEAKENING OF R13.8. That rule's enforcement is PortalDrawerTests measuring the
   landmark's width against the space available and walking every element's layout right edge, plus
   the landmark-overflow exclusions. `clip` clips the same pixels, so `documentElement.scrollWidth`
   stays exactly as honest as it was and every one of those assertions holds. What is given up is a
   scroll container the layout never used - .biztech-main has never had a height that could scroll.

   R13.6's floor is evergreen Chrome, Edge, Firefox and Safari, all of which ship `overflow: clip`;
   the same section already names :has(), color-mix() and ResizeObserver as load-bearing. */
.biztech-main[b-y45if9bi06] {
    display: block;
    inline-size: 100%;
    min-inline-size: 0;
    overflow-x: clip;

    /* 🔴 PLACED, NOT AUTO-PLACED, AND A CLOSED DRAWER IS WHY. THIS IS A FIX, NOT A TIDY-UP.

       `display: none` does not make the drawer a zero-width grid item - it stops it being a grid ITEM
       at all. Auto-placement then put this landmark in the FIRST track, the `auto` one the rail was
       sized by, and left `1fr` EMPTY beside it. So closing the navigation did not widen the page, it
       narrowed it to its own content and parked 1,202px of dead space down the right-hand side.

       Measured in Chrome on the running console at 1920px, 2026-09-22, drawer closed:

         as shipped                      main 703px at x=0, tracks `702.859px 1202.14px`
         with .biztech-main grid-column 2  main 1905px at x=0, tracks `0px 1905px`

       🔴 IT PREDATES THE MOTION WORK AND IS NOT CAUSED BY IT - the same 703px is measured with this
       file's transition and margin neutralised, which is how it was told apart. It was reported from a
       screenshot the day the rail learned to slide, because an animated close is what made anyone look
       at the state it lands in. Nothing about `display: none` here changed.

       One number holds it: this landmark is in track 2, the rail is in track 1, and an empty track 1
       is `auto` over nothing, which is 0. The narrow block at the end of this file puts this back to
       track 1, where the shell declares a single column and a track 2 would be IMPLICIT - the same trap
       one column further along. */
    grid-column: 2;
    grid-row: 1;
}

/* ── 🔴 W0-59 · FINDING S5 · THE DRAWER BELOW sm ───────────────────────────────────────────────────

   THE DRAWER NEVER COLLAPSED, AND THE CONSOLE WAS UNUSABLE ON A PHONE. MudDrawer had a breakpoint and
   turned itself into a temporary overlay; W0-51 replaced it with the <aside> above and replaced the
   layout but not the behaviour, so `auto 1fr` gave the drawer its 240px at every width.

   Measured in a browser, 2026-08-13, at 375px:

     /board        #biztech-main 103px wide, content reaching x = 450
     /case-types   #biztech-main 103px wide, content reaching x = 580

   against a 360px client width - and .biztech-main declares overflow-x: hidden, so that was CLIPPED
   RATHER THAN SCROLLED. The "Create case" button, the case-type filter and the right-hand table columns
   were not reachable by any means.

   AT sm AND ABOVE NOTHING BELOW APPLIES, so no desktop pixel moves. That is deliberate and it is the
   same argument the board's own breakpoint makes: the console is a desktop tool, the demo is presented on
   a laptop, and a card repairing a phone layout must not touch the screen the work is actually done on.

   599.98px is MudBlazor's sm, which app.css already keys four blocks on - the board's stack, the
   participant-link column and the anonymous panel's padding. A second number here would
   let the drawer disagree with the board about where the layout changes, on the one screen where both are
   visible together.

   🔴 W16-17 · THE TABLE REFLOW USED TO BE ON THAT LIST AND IS NOT ANY MORE, and a reader who expects
   one number for everything should know why before editing here. The reflow and this drawer sharing
   599.98px meant there was NO WIDTH at which the nav was present and the table still fitted: at 600px
   the drawer took 241 of 600 pixels and a 689px case table went into the 344 that remained, twice its
   column, still 45px over at 900. So the reflow moved up to md (959.98px, app.css block 5) and THIS
   number stayed put. The two are now NESTED rather than identical - cards up to md, nav from sm - and
   the band between them is the one that was broken. Moving this one as well would only relocate the
   problem, which is the alternative W16-17's plan records and refuses. */
@media (max-width: 599.98px) {
    /* One column. The drawer is out of the flow below, so a track reserved for it would be an empty
       240px gutter down the side of every page. */
    .biztech-shell[b-y45if9bi06] {
        grid-template-columns: 1fr;
        /* W19-14 · the bar's row, back for the phone's bar, and the content below it. */
        grid-template-rows: var(--biztech-appbar-height) 1fr auto;
        --biztech-content-block-start: var(--biztech-appbar-height);

        /* 🔴 W6-50 · design §8. THE NARROWING IS REVERSED HERE, AND IT WAS THE ONE DESKTOP-ONLY RULE
           THIS BLOCK FORGOT TO REVERSE.

           §8: "Control height goes back to 40px off the console's 32px, which is the token's own
           narrowing." W0-63 narrowed it 265 lines up and its reasoning names its own exemption:
           "R5.8 exempts the operator console by decision (MOUSE AT A DESK), and only the console."
           Below sm there is no mouse and no desk - the pointer is a finger, which is the exact case
           R5.8's minimum exists for and the case the exemption was never claiming.

           Driven at a 485px viewport on 2026-09-08, every UiButton and every input on every page
           resolved to min-height: 32px. --biztech-control-height reads 40px at :root and this block
           changed the grid, the content inset and the drawer without ever putting the token back.

           🔴 THE PADDING GOES WITH IT. 4px of block padding under a 40px box leaves the label sitting
           high in it; 8px is what the 40px control was drawn with before the narrowing, and R5.1's 4px
           base unit is why it is 8 and not 6.

           🔴 THIS SELECTOR, NOT :root. The token is declared on .biztech-shell so that /i/{key},
           /login and /register keep their own boxes - W0-63's own requirement, measured by
           AssigneeFormViewportTests.Every_tap_target_meets_the_touch_minimum. Reversing it at :root
           would move three surfaces this rule has no business touching. Same selector, same
           specificity, later in source: it wins, and nothing else moves. */
        --biztech-control-height: 40px;
        --biztech-control-padding-block: 8px;
    }

    /* 🔴 BACK TO TRACK 1, BECAUSE THE SHELL ABOVE DECLARES ONE COLUMN. `grid-column: 2` against a
       single-column grid does not clamp - it creates an IMPLICIT second track and puts the landmark in
       it, which is the same defect its own comment describes, one column further along. The rail is
       `position: fixed` at this width and out of the flow, so it needs no partner rule. */
    .biztech-main[b-y45if9bi06] {
        grid-column: 1;
        grid-row: 2;
    }

    .biztech-footer[b-y45if9bi06] {
        grid-column: 1;
        grid-row: 3;
    }

    /* Out of the flow and over the content. `position: fixed` rather than absolute: the shell is a grid
       with no positioning context of its own, and the drawer must stay put while the page behind it
       scrolls - an absolutely positioned drawer scrolls away and leaves the scrim behind.

       Below the app bar rather than over it, so the button that opened it stays visible and reachable:
       an overlay that covers its own toggle is one an operator has to guess their way out of.

       🔴 NO ATTRIBUTE SELECTOR HERE, AND THE FIRST VERSION HAD ONE. It read
       `.biztech-drawer[data-narrow="true"]`, with the markup rendering data-narrow="@_drawer.Narrow" - and
       a C# bool interpolates as "True" while a CSS attribute selector matches its value CASE-SENSITIVELY,
       so the rule applied to nothing. Every geometry assertion still passed, because the single-column grid
       above was doing the work by itself. Inside this media query everything IS narrow, and
       .biztech-drawer[hidden] { display: none } outside it already carries open/closed - so the marker was
       both broken and redundant. */
    .biztech-drawer[b-y45if9bi06] {
        position: fixed;
        inset-block: var(--biztech-appbar-height) 0;
        /* W19-14 · the insets size it here; the desktop's full-window height would run it past the bottom by the bar's height. */
        block-size: auto;
        inset-inline-start: 0;
        z-index: var(--biztech-layer-drawer);
        box-shadow: var(--biztech-shadow-overlay);
    }

    /* 🔴 THE SLIDE LIVES HERE AND NOWHERE ELSE, AND THE RULE ABOVE IS THE REASON.

       `position: fixed` is what makes a transform free: out of the flow, the rail displaces nothing, so
       moving it by its own width moves no other pixel and R6.7's "never animate anything that lays out"
       is not being read generously. At desktop the same drawer is a 240px GRID TRACK - sliding it there
       would leave a 240px hole and then snap the content into it, which is worse than the fade the
       outer rule gives and is why the transform is not declared alongside it.

       -100%, not a nudge: it ends clear of the screen edge, so the box-shadow above does not sit on the
       viewport boundary looking like a stuck panel. `opacity: 0` comes from the outer [hidden] rule,
       which this one adds to rather than replaces.

       🔴 THIS ONE PROPERTY IS PHYSICAL WHERE THE REST OF THE FILE IS LOGICAL, AND IT IS THE ONLY LTR
       ASSUMPTION IN THE DRAWER. There is no logical `translate`, so an RTL rail - which sits at the
       inline-start edge on the RIGHT - would slide the wrong way and cross the screen. Nothing in this
       application sets `dir` today and no locale asks for it, so the fix is NOT written here on
       speculation; the day one does, it is `:dir(rtl) .biztech-drawer[hidden] { transform:
       translateX(100%) }` beside this rule, and the desktop half above needs nothing because
       `margin-inline-start` already flips itself. */
    .biztech-drawer[hidden][b-y45if9bi06] {
        transform: translateX(-100%);

        /* 🔴 13.2 · THE DESKTOP MARGIN IS REVERSED HERE, AND WITHOUT THIS LINE THE OVERLAY LEAVES
           TWICE AS FAR. A margin on a `position: fixed` box offsets it from its inset edge, so the
           -241px above would compose with the -100% beside it and the rail would slide 481px to clear a
           390px screen - the same distance in the same 120ms, so it reads as a flick rather than a
           slide. It also has nothing to do: an overlay displaces no content, which is why the transform
           is the mechanism at this width and the margin is the mechanism at the other. */
        margin-inline-start: 0;
    }

    /* Gated for the same reason as the rule it narrows - see it for the measurement. Below sm the
       entrance moves no content, but an overlay flying in over a page the operator has not asked for it
       on is the same unrequested motion in a different direction. */
    @starting-style {
        .biztech-shell[data-motion="ready"] > .biztech-drawer[b-y45if9bi06] {
            transform: translateX(-100%);
            margin-inline-start: 0;
        }
    }

    /* The scrim. Same inset as the drawer, so the app bar stays operable underneath it - the operator can
       press the menu button again, which is the affordance they already know.

       A <button>, so it is reset to a plain surface: the user agent gives one a border, a background and
       its own appearance, and none of that belongs on a scrim.

       🔴 NO `padding: 0`, and UtilitySpecificityTests is why I know: it flagged one here, and the flag was
       right for a reason worth keeping. Every edge of this element is pinned, so padding cannot change what
       it covers - it would have been a declaration with no effect that also outranked the utility layer.
       The guard from that commit caught it on the very next one. */
    .biztech-drawer-scrim[b-y45if9bi06] {
        position: fixed;
        inset-block: var(--biztech-appbar-height) 0;
        inset-inline: 0;
        z-index: var(--biztech-layer-drawer-scrim);

        appearance: none;
        border: 0;
        background: var(--biztech-scrim);
        cursor: pointer;

        /* 🔴 THE DIM ARRIVES WITH THE RAIL, AND IT LEAVES WITHOUT IT - WHICH IS ASYMMETRIC AND
           KNOWN.

           This element is CONDITIONALLY RENDERED (narrow AND open), not toggled with `hidden`, so on a
           close it is gone from the DOM in the same frame the state changes and there is nothing left to
           transition out. Making it symmetric means rendering a scrim at every narrow width and hiding
           it with an attribute, which
           MainLayoutRenderTests.A_narrow_viewport_closes_the_drawer asserts against by name
           (`Assert.Empty(cut.FindAll(".biztech-drawer-scrim"))`) - a dismiss target present on a screen
           with nothing to dismiss is the thing that assertion exists to stop. So the fade in is the
           half that is free, and the scrim's disappearance stays on the same frame as the tap that
           caused it. */
        transition: opacity var(--biztech-motion-duration, 120ms) ease-in-out;
    }

    @starting-style {
        .biztech-drawer-scrim[b-y45if9bi06] {
            opacity: 0;
        }
    }
}

/* R6.8. Both subjects, both directions: with no transition the `display` flip is immediate again, which
   is the behaviour this file had before the rules above and is the correct one for a reader who asked
   for no motion. The @starting-style blocks stay harmless - a starting style with nothing to transition
   to is never interpolated. */
@media (prefers-reduced-motion: reduce) {
    .biztech-drawer[b-y45if9bi06],
    .biztech-drawer-scrim[b-y45if9bi06] {
        transition: none;
    }
}

/* 🔴 W18-03 · D22. THE ASSISTANT'S DOCK ADDS NO BOX. The launcher and the panel are fixed and position
   themselves over the page; nothing here makes room for them, so opening the panel moves nothing. */
.biztech-assistant-dock[b-y45if9bi06] {
    display: contents;
}

/* ── W19-14 · the drawer's parts ─────────────────────────────────────────────────────────────────────────────────────────── */

/* The brand and the fold control on one row, under the window's top edge. */
.biztech-drawer-head[b-y45if9bi06] {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 16px 12px 8px 16px;
}

.biztech-drawer-brand[b-y45if9bi06] {
    display: flex;
    align-items: center;
    min-inline-size: 0;
}

/* The wordmark at the theme's logo height (layout.logoSize, which sized the app bar's), never taller than a row allows. */
.biztech-drawer-logo[b-y45if9bi06] {
    display: block;
    block-size: var(--biztech-appbar-logo-height, 2rem);
    max-block-size: 40px;
    inline-size: auto;
    max-inline-size: 100%;
    object-fit: contain;
    object-position: left center;
}

/* The square mark, the rail's brand. */
.biztech-drawer-mark[b-y45if9bi06] {
    display: none;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    object-fit: cover;
}

.biztech-drawer-fold[b-y45if9bi06] {
    display: inline-flex;
    flex: none;
}

/* The fold control is a desktop's; below sm the app bar's menu button opens and shuts the overlay. The mode toggle is the bar's
   there too, so the drawer's own goes: one control under one name on screen at any width. */
@media (max-width: 599.98px) {
    .biztech-drawer-fold[b-y45if9bi06],
    .biztech-drawer-mode[b-y45if9bi06] {
        display: none;
    }
}

/* The tenant and organisation switchers: each a full-width outlined field-like trigger, its current place and its chevron. */
.biztech-drawer-switchers[b-y45if9bi06] {
    display: flex;
    flex: none;
    flex-direction: column;
    gap: 8px;
    padding: 4px 12px 8px;
}

.biztech-drawer-switchers:empty[b-y45if9bi06] {
    display: none;
}

.biztech-drawer-switchers[b-y45if9bi06]  .biztech-organisation-switcher,
.biztech-drawer-switchers[b-y45if9bi06]  .biztech-tenant-switcher,
.biztech-drawer-switchers[b-y45if9bi06]  .biztech-menu {
    display: flex;
    inline-size: 100%;
}

.biztech-drawer-switchers[b-y45if9bi06]  .biztech-menu-trigger-labelled {
    flex: 1 1 auto;
    justify-content: flex-start;
    gap: 8px;
    inline-size: 100%;
    min-block-size: 40px;
    padding-inline: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

/* The current place takes the row and keeps its words at every width - the header's rule hid them on a phone. */
.biztech-drawer-switchers[b-y45if9bi06]  .biztech-organisation-switcher .biztech-menu-trigger-label,
.biztech-drawer-switchers[b-y45if9bi06]  .biztech-tenant-switcher .biztech-menu-trigger-label {
    display: inline;
    flex: 1 1 auto;
    max-inline-size: none;
    overflow: hidden;
    text-align: start;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A drawer's menus open from its start edge, over the page, not back across the drawer. */
.biztech-drawer[b-y45if9bi06]  .biztech-menu-panel {
    inset-inline: 0 auto;
}

/* The navigation's own scroller, between the head and the foot. The hairline scrollbar, drawn only while it scrolls, is the
   rail's: biztech-rail.js marks this box (NavRailScrollReveal) and the two rules above it say what that draws. */
.biztech-drawer-scroll[b-y45if9bi06] {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
}

/* 🔴 THE RAIL'S SCROLLBAR, DRAWN WHILE THE RAIL IS BEING SCROLLED AND NOT OTHERWISE.

   The bar was permanently visible on the drawer - measured in Chrome on macOS, `scrollbar-width: thin` above reserves 11px of PERMANENT, space-taking gutter (`auto` takes 15,
   `none` takes 0) and paints a thumb in it whether or not anybody is reading the rail.

   🔴 THE COLOUR CHANGES, NOT THE WIDTH, AND THAT IS THE WHOLE TRICK. Hiding the bar with
   `scrollbar-width: none` and restoring `thin` while scrolling would move every nav label 11px sideways
   the moment the first scroll event landed. The gutter is reserved in both states and only its INK
   changes, so nothing reflows - and it is only reserved at all while the content overflows, because
   `overflow-y` is `auto` rather than `scroll`.

   🔴 BOTH RULES ARE GATED ON data-scroll-reveal, WHICH biztech-rail.js SETS WHEN IT ATTACHES. That is
   the module's promise that it can show the bar again: an import that fails (R9.11 - the file missing
   after an incomplete publish, a CSP tightening) leaves the attribute unset and the rail keeps the user
   agent's ordinary scrollbar, rather than one that can never be seen. data-scrolling is set on every
   scroll event and cleared a second after the last one (biztech-rail.js's IDLE_MS, which is
   the only place that number lives).

   🔴 THE FIRST VERSION KEYED ON :hover AND :focus-within, AND IT WAS THE WRONG QUESTION. CSS has no
   way to say "this box is scrolling right now", so hover was the nearest thing a stylesheet could ask -
   and it was reported back within the hour: "now when i move pointer outside it dissapear. i want to
   dissapear scrollbar when not scrolling". Hovering a rail and scrolling it are different acts, and
   resting the pointer on the drawer while reading it is the common one. Knowing the difference is a
   runtime fact, which is why there is a module - the same argument biztech-scroller.js's own header
   makes about the board's edge flags.

   NO TRANSITION, deliberately. R6.7's budget is opacity, transform, box-shadow and scroll-behavior;
   `scrollbar-color` is none of them, and a fade here would be a third licensed exception in two days for
   something nobody asked to see move. It appears on the first scroll event and goes once the rail
   has been still for IDLE_MS. */
.biztech-drawer-scroll[data-scroll-reveal][b-y45if9bi06] {
    scrollbar-color: transparent transparent;
}

/* `outline` rather than `outline-subtle`: R3.7 leaves the subtle one deliberately untested, and a thumb
   that cannot be seen is the bug this rule fixes rather than a lighter version of it. Measured 3.33:1
   against Surface by scripts/contrast-audit.py, which clears WCAG 1.4.11's 3:1 for a user interface
   component. */
.biztech-drawer-scroll[data-scroll-reveal][data-scrolling][b-y45if9bi06] {
    scrollbar-color: var(--biztech-palette-outline) transparent;
}

/* The mode and the account, under a rule at the drawer's foot. */
.biztech-drawer-foot[b-y45if9bi06] {
    display: flex;
    flex: none;
    flex-direction: column;
    gap: 2px;
    padding: 8px 12px 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* 🔴 EACH ROW'S CONTROL TAKES THE ROW. UiMenu's wrapper is inline-flex and shrinks to its trigger, and the trigger's 100% was a
   share of that - so the account row's hover was shorter than the mode row's in the open drawer, and on the rail its glyph sat
   off the column's centre line the mode glyph is on. The wrapper stretches, and both controls are the row's full width. */
.biztech-drawer-mode[b-y45if9bi06],
.biztech-drawer-account[b-y45if9bi06] {
    display: flex;
}

.biztech-drawer-account[b-y45if9bi06]  .biztech-menu {
    display: flex;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-drawer-mode[b-y45if9bi06]  .biztech-button,
.biztech-drawer-account[b-y45if9bi06]  .biztech-menu-trigger {
    flex: 1 1 auto;
    box-sizing: border-box;
    inline-size: 100%;
    min-inline-size: 0;
    justify-content: flex-start;
    gap: 12px;
    min-block-size: 40px;
    padding-inline: 12px;
    border-color: transparent;
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    letter-spacing: normal;
    text-transform: none;
}

/* 🔴 THE TWO ROWS ARE ONE SHAPE. A small button's glyph and the menu trigger's are both 20px; the pressed button's tint and edge
   and the trigger's 12% wash would make two rows that differ only by which control drew them. Both take the navigation rows'
   hover - a 6% wash of the ink - and the pressed mode is said by its glyph and its aria-pressed, not by a tinted box. */
.biztech-drawer-account[b-y45if9bi06]  .biztech-menu-trigger {
    inline-size: 100%;
    block-size: 40px;
}

.biztech-drawer-mode[b-y45if9bi06]  .biztech-button[aria-pressed="true"] {
    border-color: transparent;
    background: transparent;
    color: var(--biztech-palette-text-primary);
}

.biztech-drawer-mode[b-y45if9bi06]  .biztech-button:hover:not(:disabled),
.biztech-drawer-account[b-y45if9bi06]  .biztech-menu-trigger:hover:not(:disabled) {
    background: color-mix(in srgb, currentcolor 6%, transparent);
}

.biztech-drawer-account[b-y45if9bi06]  .biztech-menu-trigger-label {
    flex: 1 1 auto;
    overflow: hidden;
    text-align: start;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── W19-14 · the rail ──────────────────────────────────────────────────────────────────────────────────────────────────────

   Folded on a desktop, the drawer keeps its column at the rail's width: the mark over the fold control, each switcher's glyph in
   a square, each destination's glyph, and the mode and account glyphs. Words are clipped rather than removed, so each glyph keeps
   its name; a pointer gets it as the row's title. Nothing in the rail rewraps as it folds: every row is nowrap, and the
   scroller clips sideways. The drawer itself clips nothing, so a switcher's or the account's menu opens beside the rail. */
.biztech-drawer[data-rail][b-y45if9bi06] {
    inline-size: var(--biztech-drawer-rail-size);
}

.biztech-drawer[data-rail] .biztech-drawer-head[b-y45if9bi06] {
    flex-direction: column;
    gap: 12px;
    padding-inline: 12px;
}

.biztech-drawer[data-rail] .biztech-drawer-logo[b-y45if9bi06] {
    display: none;
}

.biztech-drawer[data-rail] .biztech-drawer-mark[b-y45if9bi06] {
    display: block;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group-chevron,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-menu-trigger-labelled > .biztech-icon:last-child {
    display: none;
}

/* 🔴 A GROUP'S ENTRIES POP OUT BESIDE THE RAIL. Every group is open in the markup while the drawer is a rail (MainNavMenu.Rail:
   a closed <details> hides its entries whatever a stylesheet says), and its list is drawn here as a panel beside the group's
   glyph - shown while the group is hovered or holds focus, so a keyboard reaches it by Tab as a pointer does by hover. The
   scroller lets it out: a rail of glyphs fits the window, and a panel inside a clipping box would be cut at the rail's edge.
   The panel's ::before is the 12px bridge between the glyph and the panel, so the pointer does not lose the hover crossing
   the gap. It fades in at the theme's motion; the reduced-motion block at the end of this file stops that. */
.biztech-drawer[data-rail] .biztech-drawer-scroll[b-y45if9bi06] {
    overflow: visible;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group {
    position: relative;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-sublist {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: calc(100% + 12px);
    z-index: var(--biztech-layer-sticky);
    min-inline-size: 13rem;
    padding: 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-overlay);
    visibility: hidden;
    opacity: 0;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-sublist::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-end: 100%;
    inline-size: 12px;
}

/* 🔴 SHOWN ON HOVER, OR WHILE THE KEYBOARD IS IN THE GROUP - :focus-visible, NOT :focus-within. A pressed entry keeps focus,
   so :focus-within held a pop-out open after the press while the next group's opened under the pointer: two at once. A mouse
   press is not :focus-visible; a Tab is. And a press shuts its own group's pop-out until the pointer leaves it
   (data-flyout-shut, MainNavMenu), so it does not stay over the page the press opened.

   🔴 IT FADES IN AND NEVER OUT. The fade is declared on the shown state only, so leaving it - the pointer going, a press, or
   the drawer folding to the rail with a group open - hides the panel at once. Declared on the panel itself, the fold faded
   out every open group's entries as a pop-out the moment they became one. */
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group:hover:not([data-flyout-shut]) > .biztech-nav-sublist,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group:has(:focus-visible) > .biztech-nav-sublist {
    visibility: visible;
    opacity: 1;
    transition: opacity var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* In the panel an entry is a row with its words, as in the open drawer, not the rail's centred glyph. */
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-sublist .biztech-nav-item {
    justify-content: flex-start;
    padding-inline: 12px;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-sublist .biztech-nav-item > span {
    position: static;
    inline-size: auto;
    block-size: auto;
    overflow: visible;
    clip-path: none;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-item > span,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-docs > span,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group-text,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-menu-trigger-label,
.biztech-drawer[data-rail] .biztech-drawer-mode[b-y45if9bi06]  .biztech-button-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-item,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-docs,
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group-label,
.biztech-drawer[data-rail] .biztech-drawer-mode[b-y45if9bi06]  .biztech-button,
.biztech-drawer[data-rail] .biztech-drawer-account[b-y45if9bi06]  .biztech-menu-trigger,
.biztech-drawer[data-rail] .biztech-drawer-switchers[b-y45if9bi06]  .biztech-menu-trigger-labelled {
    justify-content: center;
    padding-inline: 0;
}

.biztech-drawer[data-rail] .biztech-drawer-switchers[b-y45if9bi06]  .biztech-menu-trigger-labelled {
    inline-size: 40px;
    block-size: 40px;
    flex: none;
}

/* The one-tenant "Working in" chip had no menu to fold to a glyph, so its words were cropped at the rail's width. On the rail it is
   the switchers' 40px square on the same warning tint, the Tenancy glyph inside; its words are clipped, and the title names the tenant. */
.biztech-drawer[data-rail] .biztech-drawer-switchers[b-y45if9bi06]  .biztech-tenant-switcher__chip .biztech-chip {
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    padding-inline: 0;
    border-radius: var(--biztech-radius-default);
}

.biztech-drawer[data-rail] .biztech-drawer-switchers[b-y45if9bi06]  .biztech-tenant-switcher__chip-glyph {
    display: inline-flex;
}

.biztech-drawer[data-rail] .biztech-drawer-switchers[b-y45if9bi06]  .biztech-tenant-switcher__chip-text {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The rail's group row: the group's glyph lit when it holds the current page, as the design marks Tenancy. */
.biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-group:has(.biztech-nav-item.active) > .biztech-nav-group-label {
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
}

/* ── W19-14 · the app bar, a phone's only ─────────────────────────────────────────────────────────────────────────────────── */

/* 🔴 W19-14 · AND IT IS DRAWN ONLY BELOW sm. Above it the drawer carries the brand, the fold control, the switchers, the mode and
   the account; the bar would only say them twice. */
@media (min-width: 600px) {
    .biztech-appbar[b-y45if9bi06] {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-drawer[data-rail][b-y45if9bi06]  .biztech-nav-sublist {
        transition: none;
    }
}
/* /Components/Layout/MainNavMenu.razor.rz.scp.css */
/* W0-53 · the drawer's items, which MudNavMenu used to draw.

   Four rules, and between them they replace what MudNavLink rendered: a padded row, a glyph beside a
   label, a hover, and the current page marked. Nothing here is new design - the values are what the
   drawer measured at before this card, so an operator's eye lands where it already did.

   Scoped, because every element these rules touch is inside the <nav> this component renders (R14.1
   layer 3). The focus ring is NOT here: app.css declares exactly one, shared, and .biztech-nav-item is
   on its selector list - a second declaration in a scoped sheet is the thing that list exists to
   prevent.

   🔴 ::deep ON EVERY ITEM RULE, AND THIS WAS FOUND ON SCREEN RATHER THAN IN A TEST.
   Three of the four items are Blazor `NavLink` COMPONENTS, and Blazor stamps its scope attribute on
   the elements a component renders ITSELF - never on the markup a child component renders. So a bare
   `.biztech-nav-item` compiles to `.biztech-nav-item[b-xxxxxxxxxx]` and matches only the fourth item,
   the plain <a>. Measured in the browser on the running stack: the three NavLinks reported
   `min-block-size: 0px` and `text-decoration: underline` - default browser links - while the <a>
   reported 44px and none.

   ::deep compiles to `[b-xxxxxxxxxx] .biztech-nav-item`, a descendant selector rooted at the <nav>
   this component DOES render, which reaches both kinds and still cannot escape this subtree.
   CasePage.razor.css carries the identical fix for the identical reason, written when its two
   controls were MudBlazor components - the substrate changed and the rule did not. */

[b-mrrwcq35ki] .biztech-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    list-style: none;
    margin: 0;
    padding: 8px 12px;
}

/* 🔴 THE ROW IS 44px, WHICH IS R13.5's TOUCH TARGET AND NOT A COINCIDENCE. MudNavLink rendered 48px;
   the floor is what matters and the drawer is denser for it. */
[b-mrrwcq35ki] .biztech-nav-item,
[b-mrrwcq35ki] .biztech-nav-docs {
    display: flex;
    align-items: center;
    gap: 12px;

    /* 🔴 W0-63 · FINDING 6. 40px, was 44. R5.8's 44px touch minimum exempts the operator console
       BY DECISION - "mouse at a desk" - and 44px stays in PortalStyleSheetTests.LayoutConstants for the
       (pointer: coarse) block that still uses it on /i/{key}. 40 is 10 x 4 on the base unit, and it is
       what took 27 nav items from 1,527px of drawer to a box the viewport bounds. */
    min-block-size: 40px;
    padding-inline: 12px;
    /* W19-14 · a rounded row inside the drawer's gutter, as the design draws every row - the hover and the current page are
       tinted shapes rather than full-bleed bands. */
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
    white-space: nowrap;

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

[b-mrrwcq35ki] .biztech-nav-item:hover,
[b-mrrwcq35ki] .biztech-nav-docs:hover {
    background: color-mix(in srgb, currentcolor 6%, transparent);
}

/* 🔴 W0-59 · A NAV GROUP CAPTION. Two rules and an indent, which is the whole of what a group needs
   when it does not collapse. Three groups render it today - Cases, Oversight, and each administration
   group - so a change here moves all of them.

   The shape is secondary ink, caption scale, above its items. 16px of inline padding lines the
   caption's first letter up with the item labels' glyphs above it, and the block padding is asymmetric
   so the caption sits closer to what it labels than to what precedes it.

   (W0-59 chose this shape to match a SECOND drawer the app used to have, shipped by the retired
   designer shell, because an operator crossed between the two. There is one drawer now. The measurements
   above are kept on their own merits, and nothing outside this file constrains them any more.)

   No `padding: 0` on the sublist and no `margin: 0` on the caption: a <span> has neither, and the one
   reset here is the <ul>'s own block margin - which is why UtilitySpecificityTests carries a Declared
   entry for it beside .biztech-nav's, for the identical reason. */
[b-mrrwcq35ki] .biztech-nav-group-label {
    /* 🔴 14.0 · A <summary>, NOT A <span>, AND THE ROW IS A FLEX ONE BECAUSE IT CARRIES A CHEVRON NOW.
       The caption's own measurements below are untouched - this is the same ink, scale and padding it
       has had since W0-59, with a glyph in front of it and a pointer on it. */
    /* 🔴 W19-14 · A ROW LIKE ANY OTHER NOW, NOT A CAPTION. With the app bar gone the drawer is the console's whole chrome, and
       the design draws each group as a top-level row: its glyph, its name in the body's ink, and the chevron at the row's end,
       turning down when the group is open. Its entries carry no glyph and sit under the name. */
    display: flex;
    align-items: center;
    gap: 12px;
    min-block-size: 40px;
    cursor: pointer;

    /* The disclosure triangle a browser draws for itself, declined twice: `display: flex` already
       removes it in Chromium, and the pseudo-element below is for the one engine that would still draw
       it beside the chevron this sheet renders. LibraryFolderTree's summary carries the identical pair
       for the identical reason. */
    list-style: none;

    padding-inline: 12px;
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    white-space: nowrap;
}

[b-mrrwcq35ki] .biztech-nav-group-text {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The group holding the current page reads as current: its row in the primary ink, as the design marks Tenancy. */
[b-mrrwcq35ki] .biztech-nav-group:has(.biztech-nav-item.active) > .biztech-nav-group-label,
[b-mrrwcq35ki] .biztech-nav-group:has(.biztech-nav-item-parent) > .biztech-nav-group-label {
    color: var(--biztech-palette-primary);
    font-weight: var(--biztech-font-subtitle2-weight);
}

[b-mrrwcq35ki] .biztech-nav-group-label::-webkit-details-marker {
    display: none;
}

/* The caption is a control now, so it answers a pointer the way the items under it do. Same declaration
   as .biztech-nav-item:hover above rather than a second idiom: one drawer, one hover. */
[b-mrrwcq35ki] .biztech-nav-group-label:hover {
    background: color-mix(in srgb, currentcolor 6%, transparent);
}

/* 🔴 THE CLASS IS ON A WRAPPER THIS COMPONENT RENDERS, NOT ON UiIcon, AND I19 IS WHY. A scoped rule
   is stamped on the selector's LAST compound, so `.biztech-nav-group-chevron` on the component's own
   <svg> would be stamped with UiIcon's scope and would never match. LibraryFolderTree's chevron carries
   the same note; R8.7 is the other half - UiIcon.Class takes spacing utilities, and a rotation is not
   one. */
[b-mrrwcq35ki] .biztech-nav-group-chevron {
    display: flex;
    flex: none;

    /* R6.7's budget verbatim: `rotate` is a transform property, 120ms, ease-in-out. The guard is at the
       end of this file (R6.8). */
    transition: rotate var(--biztech-motion-duration, 120ms) ease-in-out;
}

[b-mrrwcq35ki] .biztech-nav-group[open] > .biztech-nav-group-label .biztech-nav-group-chevron {
    rotate: 90deg;
}

[b-mrrwcq35ki] .biztech-nav-sublist {
    display: flex;
    flex-direction: column;
    gap: 2px;
    list-style: none;
    margin: 0;
    padding-block-start: 2px;
    padding-inline-start: 0;
}

/* The indent says "these belong to the caption", and it is worth MORE now rather than less: 14.0 gave
   the caption a disclosure triangle, and a list that jumps back to the caption's own margin when it
   opens reads as a new list rather than as this one's contents. (The sentence here used to begin "once
   the disclosure triangle is not there to say it" - it is there now, and the indent stayed.)

   12px rather than a full glyph column: the two sub-items keep their own icons - each is a
   destination in its own right - so indenting by the icon's width would break the vertical line the
   other three items' glyphs sit on and buy nothing back. */
/* W19-14 · an entry has no glyph: its name lines up under its group's name - the row's 12px, the 16px glyph and the 12px gap. */
[b-mrrwcq35ki] .biztech-nav-sublist .biztech-nav-item {
    padding-inline-start: 40px;
}

/* `active` is Blazor's own class name, written by NavLink when the route matches - it is not ours to
   prefix, and renaming it would mean reimplementing the matching. The inset bar rather than a filled
   row for the reason .biztech-selected uses one on the case list: a tint alone is hard to see against
   a surface at a glance, and the two marks reading the same way is worth more than either. */
/* W19-18 · biztech-nav-item-parent is ours: a list marked current on a page it is the parent of outside its own path
   (AdminNavAncestry), which NavLink's prefix match cannot see. */
[b-mrrwcq35ki] .biztech-nav-item.active,
[b-mrrwcq35ki] .biztech-nav-item-parent,
[b-mrrwcq35ki] .biztech-nav-docs.active {
    /* W19-14 · a tinted pill in the primary ink, the design's; the inset edge went with the full-bleed rows. */
    color: var(--biztech-palette-primary);
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    font-weight: var(--biztech-font-subtitle2-weight);
}

/* · R5.8's touch minimum, and it applies to the caption for the first time because the caption is a
   control for the first time. 599.98px is the drawer's own breakpoint - the one number MainLayout,
   app.css and ViewportWatcher already agree on - and below it MainLayout puts --biztech-control-height
   back to 40px for exactly this reason: "below sm there is no mouse and no desk, which is the case
   R5.8's minimum exists for". A 32px caption is what the block padding above comes to, and a thumb
   cannot reliably hit it.

   Desktop is untouched. R5.8 exempts the operator console BY DECISION - mouse at a desk - which is the
   same exemption .biztech-nav-item's own 40px row is taken under, twenty lines up. */
@media (max-width: 599.98px) {
    [b-mrrwcq35ki] .biztech-nav-group-label {
        min-block-size: 44px;
    }
}

/* R6.8. The chevron's rotation is the only motion this sheet declares, and it is the one thing here
   that answers a reader who asked for none. */
@media (prefers-reduced-motion: reduce) {
    [b-mrrwcq35ki] .biztech-nav-group-chevron {
        transition: none;
    }
}

/* W24-01 · ADR 0039. The drawer's foot: the docs, under a rule, apart from the destinations a key decides. The list
   is this component's own markup, so the rule needs no ::deep; the link inside it shares the item's rules above. */
/* W19-14 · Docs at the foot of the list, pushed to the bottom of the drawer's scroller when the list is short. */
.biztech-nav-foot[b-mrrwcq35ki] {
    margin-block-start: auto;
}

/* W19-14 · the landmark is a column at least as tall as the drawer's scroller, so Docs sits at its foot when the list is short. */
.biztech-nav-root[b-mrrwcq35ki] {
    display: flex;
    flex-direction: column;
    min-block-size: 100%;
}
/* /Components/Layout/PageHeader.razor.rz.scp.css */
/* W16-08 · finding 1. THE ONLY RULE THIS COMPONENT HAS, AND IT APPLIES ONLY ON A PHONE.

   The desktop row is still three utility classes in PageHeader.razor and nothing here touches it.
   R14.1a's subject is a scoped rule at (0,2,0) silently outranking a utility at (0,1,0), and the two
   declarations below do exactly that - INSIDE the query and nowhere else. That is the reversal R13.3
   asks for, not a second opinion about the desktop row.

   🔴 MEASURED AT 390x844 ON 2026-09-14, ON /inquiries. `justify-space-between` divides one line
   between two flex items whose automatic minimum is their CONTENT, so New case / Refresh / Export kept
   their full width and the title block took what was left: a column of roughly 60px, with "Case list"
   broken over two lines and its one-sentence description running down EIGHT beside the buttons.

   This is the shared header, so it was every console page - 65 call sites - not one screen. The table
   below it stacked into cards correctly the whole time, and that is the pattern this follows.

   🔴 flex-direction ALONE IS NOT ENOUGH, which is the half a later reader would delete as redundant.
   `biztech-align-center` is a CROSS-axis rule, and on a column the cross axis is the INLINE one - so
   the actions row would shrink-wrap to its content and sit CENTRED under a full-width title. `stretch`
   gives it the line, and the row's own `biztech-d-flex` with no justification packs the buttons to the
   start, in reading order under the heading they belong to.

   🔴 NO RULE ABOVE sm, DELIBERATELY. The card's ## Do not: "do not hide the header's actions behind a
   menu on desktop to make one rule serve both widths." A phone and a laptop want different rows, and
   the honest way to say so is a breakpoint rather than one compromise that suits neither.

   The gap belongs to the CONTAINER, never a margin per child (I18) - the actions row carries none, and
   a margin here would ADD to the component's own biztech-mb-6 on the wrapper outside this element.
   12px is the 4px base unit times three; R5.4 admits no length that is neither a scale step nor a named
   constant, and PortalStyleSheetTests sweeps for one. */
/* 🔴 THE ACTIONS ROW WRAPS, AND A BROWSER FACT ASKED FOR THIS RULE RATHER THAN AN EYE.

   /case-types gained a third control - the lifecycle map, promoted out of the page's subtitle - and
   CaseTypesViewportTests went red at 375 and 768 in both modes: the outlined anchor laid out to
   right=484 against a limit of 375, and to right=811 against 753. `.biztech-main` declares
   `overflow-x: clip`, so that much of a control is CLIPPED rather than scrolled, which is R13.8's own
   defect - "overflow-x: hidden is not a responsive strategy, it hides the symptom and the diagnostic
   together".

   The row was `biztech-d-flex` and nothing else, so its items kept their content width and ran off the
   end. Wrapping is the whole fix: every control stays visible and takes a second line when the first
   one is full.

   🔴 IT IS NOT THE THING THIS FILE'S NEXT COMMENT FORBIDS. W16-08's `## Do not` reads "do not hide the
   header's actions behind a menu on desktop to make one rule serve both widths", and that is an
   argument against CONCEALING controls. Wrapping is the opposite: nothing is hidden, nothing is behind
   anything, and a page with two controls renders exactly as it did.

   🔴 AND IT ADDS A PROPERTY RATHER THAN OVERRIDING ONE, which is what keeps it clear of R14.1a. That
   rule's subject is a scoped selector at (0,2,0) silently outranking a utility at (0,1,0) - and the
   utilities on this element declare `display`, `align-items` and `gap`. `flex-wrap` is none of them,
   so there is nothing here for a utility to lose.

   NO justification, deliberately, and the media query below is why: on a phone the row is stretched
   and its items pack to the START, "in reading order under the heading they belong to". A
   `flex-end` here would reverse that on the one width where it was decided. */
.biztech-page-header-row > [data-page-actions][b-h0y6zgsz87] {
    flex-wrap: wrap;
}

@media (max-width: 599.98px) {
    .biztech-page-header-row[b-h0y6zgsz87] {
        flex-direction: column;
        align-items: stretch;
        gap: 0.75rem;
    }
}

/* 🔴 ON A DESKTOP ROW THE ACTIONS KEEP ONE LINE AND THE DESCRIPTION GIVES WAY. Both children took part in shrinking, and the
   actions' wrap above let the row give up its width first: on a 1,000px content column /portals drew New portal over Import
   on two lines beside a subtitle that still had room to break. The buttons are the controls a reader comes for; the
   subtitle is prose and wraps without losing anything.

   md (960px) and up only. Below it the console still spends 240px on its drawer, and a row that never shrinks is the
   60px title column the note above records - so the wrap stays there. 24px between the two is 6 x 4 on the base unit
   (R5.1), so a long subtitle never runs flush against the first button. */
@media (min-width: 960px) {
    .biztech-page-header-row[b-h0y6zgsz87] {
        gap: 24px;
    }

    .biztech-page-header-title[b-h0y6zgsz87] {
        flex: 1 1 auto;
        min-inline-size: 0;
    }

    .biztech-page-header-row > [data-page-actions][b-h0y6zgsz87] {
        flex: none;
        flex-wrap: nowrap;
    }
}

/* 🔴 W19-14 · THE TITLE READS AS A TITLE. With the app bar gone the page's own header is the first thing on the window, and the
   H5 slot at 500 read as a label: the same weight as a card's heading, a size apart. It is the H5 slot's size and a quarter
   (30px at the default), bold, set a little tight as display type is, with the description four pixels under it in the
   secondary ink. Scaled from the theme's own H5, so a typography setting still moves it. The column takes 8px of room above
   it, since nothing heads the window now. */
.biztech-page-header-title[b-h0y6zgsz87] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-block-start: 8px;
}

.biztech-page-header-title[b-h0y6zgsz87]  h1 {
    font-size: calc(var(--biztech-font-h5-size, 1.5rem) * 1.25);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.02em;
}
/* /Components/Layout/PortalContextBar.razor.rz.scp.css */
/* W8-01 · F10.16 — the "where you are" bar, as a pill in the title card's top corner. TOKENS ONLY: R3.1's sweep in
   PortalStyleSheetTests reads every scoped sheet, and nothing here is a literal colour.

   🔴 DRAWN IN THE INK OF WHATEVER IT SITS ON. It lives on PortalWelcomeCard's band, which is the primary colour in
   light mode and the primary container in dark, each with its own ink - so the pill takes currentColor for its text
   and a wash of currentColor for its ground and edge, and is legible on the band in both modes without naming
   either. The link is the band's ink at full strength; the wash only frames it.

   🔴 IN NORMAL FLOW. NOT position: fixed, NOT sticky. R13.8 extended to height: the bar costs the main landmark
   neither width nor the fold. PortalWelcomeCard places it; this sheet only draws it. */
.biztech-portal-context[b-y0i12qcink] {
    display: inline-flex;
    align-items: center;
}

/* The sentence names the portal and the organisation being acted for. The band's heading already shows the portal,
   so the sentence is for assistive technology: clipped from view, not removed, so the region still announces where
   the reader is on entry. */
.biztech-portal-context[b-y0i12qcink]  .biztech-portal-context__where {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    white-space: nowrap;
    clip-path: inset(50%);
}

.biztech-portal-context__out[b-y0i12qcink] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 12px 4px 16px;
    border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, currentColor 12%, transparent);
    color: inherit;
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-button-line-height);
    text-decoration: none;
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-portal-context__out:hover[b-y0i12qcink] {
    background: color-mix(in srgb, currentColor 22%, transparent);
}

@media (pointer: coarse) {
    .biztech-portal-context__out[b-y0i12qcink] {
        min-block-size: 44px;
    }
}
/* /Components/Layout/PortalLayout.razor.rz.scp.css */
/* 🔴 W1b-08 · F2.19, F2.21, F2.22 · the portal's own shell, and the FIFTH layout sheet.

   WHAT THIS IS NOT, twice over, because both alternatives were what the portal rendered inside before
   this card:

     .biztech-anon-panel   is max-inline-size: 46rem - §5's PROSE MEASURE (R4.6), there because §7's
                           assignee reads a case. W1a-08's plan measured what it did to a portal grid:
                           "12 tracks of 41px" on a 1536px viewport.
     .biztech-shell        is the operator console: a grid with a 240px drawer column, an app bar row
                           and a scrim. R13.8's measured defect site, and a customer must not see its
                           navigation at all.

   🔴 THE MAX WIDTH IS 71.25rem = 1140px, AND IT IS READ RATHER THAN CHOSEN. Legacy's shell wraps its
   main in a Bootstrap `.container` (_LayoutAdminDesign.cshtml:320), whose width at `xl` is 1140px. So
   the portal is centred at the width its own visitors have been reading it at.

   NO LayoutConstants ROW, and R5.4 is satisfied without one: 71.25 x 16 = 1140, and 1140 / 4 = 285, so
   this is a whole multiple of the 4px base unit - which is that rule's FIRST option, not its second.
   §5 is explicit that adding a registry row "is not the cheap way out" of that check, and
   SignInLayout's own 24rem panel takes the same route for the same reason (its Decision 5).

   EVERY OTHER LENGTH IS A 4px MULTIPLE and every colour is a --biztech-* token (R14.1 layer 1). No
   `prefers-color-scheme` anywhere (I16 · R7.3): UiThemeTokens re-emits the palette when the mode flips,
   so a media query here would follow the OS while the application follows its own field, and the two
   disagree the moment they differ. All four other layout sheets carry the same note.

   NO overflow OF ANY KIND (R13.8): "overflow-x: hidden is not a responsive strategy - it hides the
   symptom and the diagnostic together", and W0-55 exists because of it. The main keeps the whole
   viewport minus its gutters, which is what PortalHomeViewportTests measures against the landmark.

   LOGICAL PROPERTIES THROUGHOUT - min-block-size, max-inline-size, padding-inline - never height or
   width. */

.biztech-portal-shell[b-f04qs6ddqz] {
    display: flex;
    flex-direction: column;
    min-block-size: 100vh;
    background: var(--biztech-palette-background);

    /* W22-07 browser walk (TD38). UiSnackbarHost reads this to sit below the bar above the content - MainLayout declares it
       for the console's app bar. The portal declared none, so a message sat 16px from the top, under the sticky header below,
       and the theme applied from an agent portal announced itself to nobody. The header's height is its mark's height
       (portalPage.logoSize - W26-02 · D8) or its 32px controls, whichever is taller, plus its 12px block padding on each
       side; its 1px edge is inside the host's own 16px gutter. Unset, that is the 2rem + 24px it always was; at xxlarge
       (4rem, W28-19) it is 88px, which this same expression already yields, so the snackbar clears the taller bar. */
    --biztech-content-block-start: calc(max(var(--biztech-portal-header-logo-height, 2rem), 2rem) + 24px);
}

/* W25-04 · D6 · THE TENANT'S BACKGROUND PICTURE, UNDER A SCRIM, IN ITS OWN MODE ONLY.

   The picture is drawn behind the whole shell (portal home, tile pages, item pages) with the page's own ground laid
   over it at the scrim's strength - the pair the contrast gate checked over pure black and pure white, so text stays
   readable over any photograph (ThemeImageScrim). Keyed off the mode attribute UiThemeTokens and biztech-theme.js
   stamp, never prefers-color-scheme (I16). The three --portal-background-* properties are SHELL-LOCAL: the layout
   writes them on this element's style only when a picture is set (ThemePortalBackground says why they are not in
   the shared --biztech-* block), and the attribute is absent otherwise, so a theme with no picture draws exactly
   what it did. */
:root[data-biztech-theme="light"] .biztech-portal-shell[data-portal-background~="light"][b-f04qs6ddqz] {
    background-image:
        linear-gradient(
            color-mix(in srgb, var(--biztech-palette-background) calc(var(--portal-background-scrim) * 100%), transparent),
            color-mix(in srgb, var(--biztech-palette-background) calc(var(--portal-background-scrim) * 100%), transparent)),
        var(--portal-background-light);
    background-size: cover;
    background-position: center;
    background-attachment: scroll;
}

:root[data-biztech-theme="dark"] .biztech-portal-shell[data-portal-background~="dark"][b-f04qs6ddqz] {
    background-image:
        linear-gradient(
            color-mix(in srgb, var(--biztech-palette-background) calc(var(--portal-background-scrim) * 100%), transparent),
            color-mix(in srgb, var(--biztech-palette-background) calc(var(--portal-background-scrim) * 100%), transparent)),
        var(--portal-background-dark);
    background-size: cover;
    background-position: center;
    background-attachment: scroll;
}

/* 🔴 A SURFACE WITH A BOTTOM EDGE RATHER THAN A PAINTED BAND, and that is why the mark this header
   shows is the mode-appropriate one rather than the reverse one.

   AnonymousLayout and SignInLayout both paint their header `Primary` and both therefore render
   Marks.Reverse - the white-ink mark - which BizTechBrand.LoginLogoUrl's own measurement settled: 48x25
   of dark wordmark on #2196F3, close to illegible. Legacy's portal navbar is not a colour block: it is
   a pill on the page's own ground (_LayoutAdminDesign.cshtml:178-185). So this band is `surface` with
   one `outline` edge, and Marks.For(dark) is the right call in this file rather than a copy of theirs.

   The height is not declared: the mark's height (the theme's portalPage.logoSize, 2rem unset - W26-02) or its 32px
   controls, whichever is taller, plus the padding is what sets it, and a fixed height
   would be a length nothing measured. --biztech-appbar-height is deliberately NOT read - that token is
   the console's app bar, and borrowing it would tie this shell's proportions to the console's density. */
.biztech-portal-header[b-f04qs6ddqz] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;

    /* 🔴 STICKY AND TRANSLUCENT. The header scrolled away with the page, so a visitor deep in a long list had no
       account menu and no way home without scrolling back. Sticky at the top of the shell keeps it in flow - it
       pushes the page down exactly as before and covers nothing at rest - and the surface at 86% with a blur lets
       the page read through it as it passes under. Its inline padding lines the mark and the controls up with the
       page's own measure on a wide screen rather than pinning them to the window's edges - 1140px unless the theme
       names another; at full (W26-05) the measure is the viewport and this resolves to the 16px gutter. */
    position: sticky;
    inset-block-start: 0;
    z-index: var(--biztech-layer-sticky);
    padding-inline: max(16px, calc((100% - var(--biztech-portal-measure, 71.25rem)) / 2 + 16px));

    /* The theme's portal header (ThemePortalLook): this see-through surface, the primary colour with its own ink, or
       the page's ground with no line. The controls in it take its ink, as both inherit their colour. */
    background: var(--biztech-portal-header-ground, color-mix(in srgb, var(--biztech-palette-surface) 86%, transparent));
    backdrop-filter: var(--biztech-portal-header-filter, blur(12px));
    color: var(--biztech-portal-header-ink, var(--biztech-palette-text-primary));

    /* lines-default, not divider: this edge is what separates the shell from the page, so it is a
       boundary under WCAG 1.4.11 and carries the 3:1 the palette's Outline role is tested at - the same
       call .biztech-anon-panel and .biztech-signin-panel make about their own edges. */
    border-block-end: 1px solid var(--biztech-portal-header-edge, var(--biztech-palette-outline));
}

/* One dimension constrained, and the viewBox carries the ratio (R11.6).

   🔴 W26-02 · THE HEIGHT IS THE THEME'S. portalPage.logoSize sets it (24, 32, 40, 48 or, W28-19, 64px), and unset it is the 2rem the
   anonymous and sign-in layouts still give their header marks - so a theme that says nothing draws what it always did, and
   a tenant whose mark is square, not a wordmark, can draw it larger here without moving those two.

   THE WIDTH IS CAPPED SO A WORDMARK CANNOT PUSH THE CONTROLS OFF A PHONE: 192px at 375 and 768, 256px at 1440. The shipped
   mark is 166.4px wide at 2rem, under the cap, so the unset header is unchanged; a 5:1 wordmark at the largest step (240px)
   is narrowed on a phone and drawn whole on a laptop. object-fit: contain keeps its shape inside the box - never stretched,
   never cropped - and object-position starts it at the bar's leading edge (it has no logical form). */
.biztech-portal-mark[b-f04qs6ddqz] {
    block-size: var(--biztech-portal-header-logo-height, 2rem);
    inline-size: auto;
    max-inline-size: clamp(12rem, 30vw, 16rem);
    object-fit: contain;
    object-position: left center;
    display: block;
}

/* W27-09 · 11. The mark is a link home. A flex box, so the anchor adds no line box under the image
   and its focus ring hugs the mark. */
.biztech-portal-home[b-f04qs6ddqz] {
    display: inline-flex;
    align-items: center;
}

/* flex: 1 so the footer sits at the bottom of a short page rather than under the fold - the property
   .biztech-anon-main and .biztech-signin-main both use.

   NO align-items and NO justify-content, which is where this diverges from both of them deliberately:
   they centre a PANEL, and this holds a page. The centring here is margin-inline: auto on the measure
   below, so content flows from the top exactly as it does in the console. */
.biztech-portal-main[b-f04qs6ddqz] {
    flex: 1;
}

/* 🔴 THE CONTAINER LEGACY'S `.container` IS. margin-inline: auto is the centring; the max-inline-size is
   its 1140px; and the gutters and the vertical rhythm come from UiContainer inside it (R5.3, R5.10) so
   this sheet declares no padding of its own and cannot disagree with the rest of the application about
   what a page's inset is.

   A WRAPPER DIV RATHER THAN A RULE ON UiContainer: that component is the seam's, shared by every
   console page, and narrowing it here would centre and bound /inquiries too. R14.1's "go one layer down
   only when the layer above cannot reach" - this is one layer down, in this layout's own sheet, reaching
   only this layout's own element. */
.biztech-portal-measure[b-f04qs6ddqz] {
    box-sizing: border-box;
    /* The theme's page width (ThemePortalLook): 1140px unless it names narrow, wide or full (100%: the viewport, with
       UiContainer's gutters inside it). */
    max-inline-size: var(--biztech-portal-measure, 71.25rem);
    margin-inline: auto;
}

/* The new-case form takes the theme's page width in the portal, as every portal page does: at 640px it was narrower than
   the portal around it. Here, because this layout's markup is what carries the portal; the console keeps the column. */
.biztech-portal-shell[b-f04qs6ddqz]  .biztech-create-case {
    max-inline-size: none;
}

/* Legacy's centred "Powered by" line (_LayoutAdminDesign.cshtml:320-324), on the surface with the header's own edge
   above it, so the page's ground ends where the shell begins at both ends.

   🔴 TenantChrome IS SHARED WITH THE CONSOLE, so its look on the portal is set from HERE, through ::deep, and its own
   sheet is untouched. On the portal its rule goes - the footer's edge is the rule - and its page links are the
   footer's navigation: secondary ink and no underline at rest, the primary colour and an underline under the
   pointer, at body size rather than a caption a visitor has to squint at. */
.biztech-portal-footer[b-f04qs6ddqz] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin-block-start: 48px;
    padding: 12px 24px 24px;
    text-align: center;

    /* The theme's portal footer (ThemePortalLook): this surface with its line, the primary with its own ink, or the
       page's ground with no line. */
    background: var(--biztech-portal-footer-ground, var(--biztech-palette-surface));
    color: var(--biztech-portal-footer-ink, var(--biztech-palette-text-primary));
    border-block-start: 1px solid var(--biztech-portal-footer-edge, var(--biztech-palette-outline-subtle));
}

.biztech-portal-footer[b-f04qs6ddqz]  .biztech-chrome {
    border-block-start: none;
}

.biztech-portal-footer[b-f04qs6ddqz]  .biztech-chrome-pages {
    gap: 8px 24px;
}

.biztech-portal-footer[b-f04qs6ddqz]  .biztech-chrome-page {
    color: var(--biztech-portal-footer-link, var(--biztech-palette-text-secondary));
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    text-decoration: none;
}

.biztech-portal-footer[b-f04qs6ddqz]  .biztech-chrome-page:hover {
    color: var(--biztech-portal-footer-link-hover, var(--biztech-palette-primary));
    text-decoration: underline;
}

/* 🔴 W31-09 · D14 · A BRAND-FILLED HEADER OR FOOTER INKS EVERY CHILD, NOT ONLY ITS OWN TEXT. The fill is Primary and
   the ink OnPrimary, but the footer caption took TextSecondary through the global utility class, Powered by took
   TextSecondary and the call to action and page links took Primary - primary on primary, unreadable in dark mode on
   a live portal while the gate passed. Under data-portal-chrome="brand" secondary text is OnPrimary
   mixed 85% over Primary (ThemePortalChrome.SecondaryShare, which the contrast gate measures) and every link is OnPrimary
   and underlined, so it is told from text by more than colour. Only the controls the header itself draws are named:
   a menu's popover is drawn on the surface, not on the fill, and keeps its own ink. */
.biztech-portal-footer[data-portal-chrome="brand"][b-f04qs6ddqz]  .biztech-text-secondary,
.biztech-portal-footer[data-portal-chrome="brand"][b-f04qs6ddqz]  .biztech-poweredby {
    color: color-mix(in srgb, var(--biztech-palette-on-primary) 85%, var(--biztech-palette-primary));
}

.biztech-portal-footer[data-portal-chrome="brand"][b-f04qs6ddqz]  a,
.biztech-portal-footer[data-portal-chrome="brand"][b-f04qs6ddqz]  a:hover {
    color: var(--biztech-portal-footer-link, var(--biztech-palette-on-primary));
    text-decoration: underline;
}

.biztech-portal-header[data-portal-chrome="brand"][b-f04qs6ddqz]  .biztech-icon-button,
.biztech-portal-header[data-portal-chrome="brand"][b-f04qs6ddqz]  .biztech-menu-trigger,
.biztech-portal-header[data-portal-chrome="brand"][b-f04qs6ddqz]  .biztech-visitor-links .biztech-button {
    color: var(--biztech-portal-header-ink, var(--biztech-palette-on-primary));
    border-color: currentColor;
}

.biztech-portal-header[data-portal-chrome="brand"][b-f04qs6ddqz]  .biztech-visitor-links .biztech-button-text {
    text-decoration: underline;
}

/* R13.7's phone width. The header's inline padding comes in to match UiContainer's own phone gutter, so
   the mark and the page's content share one left edge at 375px - which is the alignment
   PortalHomeViewportTests measures against the landmark rather than eyeballs. */
@media (max-width: 599.98px) {
    .biztech-portal-header[b-f04qs6ddqz] {
        padding-inline: 12px;
    }

    .biztech-portal-footer[b-f04qs6ddqz] {
        padding-inline: 12px;
    }

    /* The assistant's launcher floats over the bottom right of the viewport, which at this width is over the
       page's own content; this is room for it, so the last tile can be scrolled out from under it. */
    .biztech-portal-main[b-f04qs6ddqz] {
        padding-block-end: 72px;
    }
}

/* 🔴 R5.8's 44px FOR THE SHELL'S OWN CONTROLS, AND IT IS HERE BECAUSE THIS CARD TOOK THE
   PAGE OUT FROM UNDER THE RULE THAT USED TO PROVIDE IT.

   app.css's `@media (pointer: coarse)` block floors `.biztech-input`, `.biztech-button` (by size class)
   and `.biztech-icon-button` at 44px - and it is scoped to `.biztech-anon`, deliberately: "Scoped to
   .biztech-anon so the console is untouched." `/portal/{slug}` and `/` rendered inside AnonymousLayout
   until W1b-08, so every control on them inherited that floor. PortalLayout is not `.biztech-anon` and
   must not pretend to be - that class carries a whole shell's worth of anonymous-page styling, and the
   40rem prose measure is exactly what this card moved the portal OFF.

   So the floor is declared here, for the controls this shell owns. InstallPromptTests caught the same
   regression one component down and InstallPrompt.razor.css now carries its own; that is the same
   decision twice rather than a duplicate, because a control's minimum should travel with the control
   and a shell answers for the controls it draws itself.

   THE SIZE CLASS IS NAMED, WHICH IS W3-26's MEASUREMENT AND NOT A PRECAUTION. app.css records it in
   full: UiButton.razor.css declares `.biztech-button-small { min-block-size: 32px }` and
   `.biztech-button-medium { min-block-size: 40px }` - the SAME property - and scoped CSS puts its
   [b-xxxxx] attribute on the last compound only, so those weigh (0,2,0), exactly what an unnamed
   `.biztech-portal-header .biztech-button` would weigh. Naming the size class makes this (0,3,0) and
   settles the cascade rather than depending on sheet order.

   `min-inline-size` on the icon button too, because UiIconButton.razor.css declares `block-size: 32px`
   in BOTH axes: a min-* floor beats a fixed size, but only in the axis it names, and a 44x32 target is
   not a 44px target. PortalHomeViewportTests measures the RENDERED BOX in both axes, which is the only
   check that can tell this rule from an inert one (R14.1a).
   🔴 AND ::deep, WHICH IS THE HALF THAT WAS WRONG ON THE FIRST ATTEMPT AND IS R14.1a AGAIN.
   Without it these selectors were present and inert: scoped CSS appends this component's [b-xxxxx] to
   the last compound, and the buttons are rendered by the SEAM components, so they carry the seam's scope
   attribute and not this file's. The rule resolved, matched nothing, and the measurement did not move by
   a pixel. `X ::deep Y` compiles to `X[b-xxxxx] Y` - the attribute lands on the ancestor this file does
   own - which is the same reason PortalCard.razor.css reaches a section's anchors with it.

   🔴 AND `.biztech-menu-trigger` IS NAMED BECAUSE IT WAS MEASURED AT 32x32, NOT BECAUSE THE
   LIST LOOKED SHORT. app.css's block names `.biztech-input`, `.biztech-button` and
   `.biztech-icon-button` and stops there, which was complete for the anonymous shell: nothing on a
   sign-in page opens a menu. This header does - OperatorMenu is what gives a customer a way to sign out
   - and UiMenu's activator carries its own class and 32px in both axes, so it arrived under this rule
   and was still 12px short. Read off the rendered DOM rather than off the seam's source: the probe
   reported `biztech-icon-button ... | 44x44 || biztech-menu-trigger | 32x32`. */
@media (pointer: coarse) {
    .biztech-portal-header[b-f04qs6ddqz]  .biztech-icon-button,
    .biztech-portal-header[b-f04qs6ddqz]  .biztech-menu-trigger,
    .biztech-portal-header[b-f04qs6ddqz]  .biztech-button.biztech-button-small,
    .biztech-portal-header[b-f04qs6ddqz]  .biztech-button.biztech-button-medium {
        min-block-size: 44px;
    }

    .biztech-portal-header[b-f04qs6ddqz]  .biztech-icon-button,
    .biztech-portal-header[b-f04qs6ddqz]  .biztech-menu-trigger {
        min-inline-size: 44px;
    }
}

/* 🔴 W18-03 · D22. MainLayout's rule: the assistant's dock adds no box, and the launcher and panel float
   over the page rather than making room. */
.biztech-assistant-dock[b-f04qs6ddqz] {
    display: contents;
}

/* W22-08 · a proposal's preview embedded in the Setup assistant page's pane says so with data-without-launcher, and the floating
   launcher and its panel are not drawn in the frame: the conversation is the page around it. MainLayout.razor.css's rule, here. */
.biztech-portal-shell:has([data-without-launcher]) .biztech-assistant-dock[b-f04qs6ddqz] {
    display: none;
}
/* /Components/Layout/SignInLayout.razor.rz.scp.css */
/* W0-59 · the front door's own surface.

   🔴 WHAT THIS IS NOT: .biztech-anon-*, whose panel is max-width: 46rem - §5's PROSE MEASURE (R4.6),
   there because §7's assignee reads a case. /login put two fields and a button in it, and measured
   736 x 608 at 1440 before this commit: not just wide but TALL, because .biztech-anon-main declares no
   align-items, so the panel stretched to the full column height with its content hugging the top edge.

   Every length below is a 4px multiple and every colour is a --biztech-* token. No prefers-color-scheme
   (I16 · R7.3): UiThemeTokens re-emits the palette when the mode flips, so a media query would follow the
   OS while the application follows its own field. Both other layout sheets carry the same note. */

/* 🔴 W19-18 · THE FRONT DOOR'S SHAPE. W16-07's argument for the old bar stands in what replaced it: the mark sits on a
   neutral ground in both modes (the page background here, AppbarBackground there), so the mode-following mark is right
   and a reverse mark would not be. What changed is that there is no bar: the mark and the toggle head the form's own
   column, and with a picture the picture takes the start half edge to edge.

   Two shapes, chosen by data-signin-image and the width:
     - the column alone: the mark and toggle at the top, the form centred on the console's card, one footer line;
     - 960px and wider with a picture: a two-track grid, the picture filling the start track top to bottom with the
       caption over its foot, and the same column in the end track with the form on the bare surface.
   Below 600px the card's edge and shadow go: the form is the page there, inside the 16px gutter. */
.biztech-signin[b-abtjk9s9fe] {
    display: flex;
    min-block-size: 100vh;
    background: var(--biztech-palette-background);
}

.biztech-signin-column[b-abtjk9s9fe] {
    flex: 1;
    min-inline-size: 0;
    display: flex;
    flex-direction: column;
}

/* The mark at the start and the light/dark toggle at the end, on the column's own ground. */
.biztech-signin-header[b-abtjk9s9fe] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 20px 24px;
}

/* W25-04 · D7. The tenant's caption sits under the mark when there is no picture to carry it; the brand spaces the
   two (I18). align-items: flex-start so the mark keeps its own width rather than stretching across the row. */
.biztech-signin-brand[b-abtjk9s9fe] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-signin-logo[b-abtjk9s9fe] {
    height: 2rem;
    display: block;
}

/* Centred on both axes and pulled up: the asymmetric padding is the offset into the upper third, on the 4px scale. */
.biztech-signin-main[b-abtjk9s9fe] {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px 16px 64px;
}

/* 24rem = 384px, a whole multiple of the 4px base unit (R5.4, Decision 5), and never the 46rem prose measure
   (LoginSurfaceTests). box-sizing: border-box so width plus padding never overflows at 375px. Bare by default - on a
   phone the form is the page, and beside a picture the picture is the object - and a card only where the column is
   the whole page at a desk width (below). */
.biztech-signin-panel[b-abtjk9s9fe] {
    box-sizing: border-box;
    inline-size: 100%;
    max-inline-size: 24rem;
}

/* The console's card where the form stands alone: the quiet edge, twice the theme's radius, and the theme's card
   depth (ADR 0026 D-E: var(--biztech-shadow-card), the one shadow an in-flow card takes). From 600px while no
   picture is drawn - always below 960px, where the picture is hidden, and above it only without one. */
@media (min-width: 600px) and (max-width: 959.98px) {
    .biztech-signin-panel[b-abtjk9s9fe] {
        background: var(--biztech-palette-surface);
        border: 1px solid var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        box-shadow: var(--biztech-shadow-card);
        padding: 32px;
    }
}

@media (min-width: 960px) {
    .biztech-signin:not([data-signin-image]) .biztech-signin-panel[b-abtjk9s9fe] {
        background: var(--biztech-palette-surface);
        border: 1px solid var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        box-shadow: var(--biztech-shadow-card);
        padding: 32px;
    }
}

/* Quiet and centred under the form: the tenant's name with the tag line and call to action on one row, the pages on
   the next. TenantChrome's own sheet stacks them under a rule for the portal's footer; here they are reached through
   ::deep from this file's footer (I19) and set as caption-size links in the secondary ink, underlined on hover. */
.biztech-signin-footer[b-abtjk9s9fe] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: 4px 16px;
    padding: 16px 24px 24px;
    text-align: center;
}

/* display: contents, so the tag line and the call to action join the name's row, and the pages break onto their own. */
.biztech-signin-footer[b-abtjk9s9fe]  .biztech-chrome {
    display: contents;
}

.biztech-signin-footer[b-abtjk9s9fe]  .biztech-chrome-pages {
    flex-basis: 100%;
    margin-block-start: 0;
    gap: 4px 16px;
}

.biztech-signin-footer[b-abtjk9s9fe]  .biztech-cta {
    margin-block-start: 0;
    font-size: var(--biztech-font-caption-size);
}

.biztech-signin-footer[b-abtjk9s9fe]  a {
    color: var(--biztech-palette-text-secondary);
    text-decoration: none;
}

.biztech-signin-footer[b-abtjk9s9fe]  a:hover {
    color: var(--biztech-palette-primary);
    text-decoration: underline;
}

/* The phone: the form is the page, inside the main's 16px gutter. */
@media (max-width: 599.98px) {
    .biztech-signin-header[b-abtjk9s9fe] {
        padding: 16px;
    }

    .biztech-signin-main[b-abtjk9s9fe] {
        align-items: flex-start;
        padding: 8px 16px 40px;
    }
}

/* W25-04 · D7 · THE TENANT'S SIGN-IN PICTURE. Not drawn narrower than 960px: below that the column is the page, and a
   picture above it would push the fields below the fold. A width query, not a colour-scheme one (I16). */
.biztech-signin-art[b-abtjk9s9fe] {
    display: none;
}

@media (min-width: 960px) {
    .biztech-signin[data-signin-image][b-abtjk9s9fe] {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    /* Sticky, so on a tall page the picture stays beside the form rather than scrolling away. */
    .biztech-signin-art[b-abtjk9s9fe] {
        display: block;
        position: sticky;
        top: 0;
        block-size: 100vh;
        overflow: hidden;
    }

    .biztech-signin-image[b-abtjk9s9fe] {
        display: block;
        inline-size: 100%;
        block-size: 100%;
        object-fit: cover;
    }

    /* The caption over the picture's foot, on a panel of the page's own surface so it reads over any picture in either
       mode without a colour that only works on one of them. */
    .biztech-signin-art-caption[b-abtjk9s9fe] {
        position: absolute;
        inset-inline-start: 32px;
        inset-block-end: 32px;
        max-inline-size: min(28rem, calc(100% - 64px));
        box-sizing: border-box;
        padding: 16px 20px;
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: color-mix(in srgb, var(--biztech-palette-surface) 88%, transparent);
        backdrop-filter: blur(8px);
        border: 1px solid var(--biztech-palette-outline-subtle);
        color: var(--biztech-palette-text-primary);
        font-family: var(--biztech-font-family);
        font-size: var(--biztech-font-subtitle1-size);
        font-weight: var(--biztech-font-subtitle2-weight);
        line-height: var(--biztech-font-subtitle1-line-height);
        text-wrap: balance;
    }

    .biztech-signin[data-signin-image] .biztech-signin-header[b-abtjk9s9fe] {
        padding: 24px 40px;
    }
}
/* /Components/Layout/TenantChrome.razor.rz.scp.css */
/* W0-27 · the tenant's chrome. TOKENS ONLY - R3.1's sweep in PortalStyleSheetTests reads every
   *.razor.css in this project and refuses a hex or rgb() literal, with two allow-listed circuit-chrome
   blocks in app.css that this file is not one of. */

/* The chrome's own box. It exists only when there is chrome to show, which is what keeps an unconfigured
   tenant's footer at zero height rather than a permanently empty bordered strip - see the component's
   comment for why that lives here and not on the layout's <footer>. */
.biztech-chrome[b-z5u91wc0r2] {
    /* 12px and 1px: a whole multiple of the 4px base unit, and R5.6's fixed border width. Both are what
       R5.4's sweep in PortalStyleSheetTests accepts. */
    padding: 12px;
    text-align: center;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* NO `margin: 0` here, and UtilitySpecificityTests is what stops it going back in. BizTechCssVariables'
   document reset already zeroes p's margin, and a scoped restatement would be (0,2,0) against a utility
   class's (0,1,0) - so it would silently beat every biztech-mb-* a page passes this component, while the
   class stayed present in the markup and UtilityClassTests kept reporting it as used. */
.biztech-poweredby[b-z5u91wc0r2] {
    /* R4.3 · from the type scale, never a literal. T29 N22 removed a bare `font-size: 0.8125rem` from
       AnonymousLayout.razor.css for exactly this reason: 13px sat between Caption's 12px and Body2's
       14px for no recorded reason, and a literal does not follow the scale if the scale moves. */
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* Both links take Primary, and that is what satisfies the card's contrast clause WITHOUT introducing a
   pair anybody has to measure: PaletteContrast.RequiredPairs already tests Primary against Surface and
   against Background at 4.5:1, in both modes, and BizTechThemeOptions.Validate refuses to boot a
   configured palette that fails either. A bespoke accent here would be a pair nothing tests. */
.biztech-poweredby a[b-z5u91wc0r2],
.biztech-cta[b-z5u91wc0r2] {
    color: var(--biztech-palette-primary);
}

/* R3.11 · NO `outline: none` here or anywhere. The one focus ring is app.css's, on :focus-visible, and it
   reaches these anchors already - this file deliberately declares nothing about focus, so there is
   nothing to beat and nothing to lose. */
.biztech-cta[b-z5u91wc0r2] {
    display: inline-block;

    /* 4px, one step of the base unit. R5.4's sweep accepts a whole multiple of 4 or a named layout
       constant, and this is the former. */
    margin-block-start: 4px;

    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
}

/* 🔴 W1a-10 · F2.20. The static page links. A LIST, reset to look like a row of links: the <ul> is there so
   a screen reader is told this is a list of navigation destinations, and the reset is so a sighted reader is
   not shown bullets in a footer. Removing the element instead would trade the announcement for the styling,
   which is the wrong way round (R12.4 prefers the real element). */
.biztech-chrome-pages[b-z5u91wc0r2] {
    list-style: none;

    /* The document reset zeroes ul's margin and padding, so this file restates NEITHER - the same reasoning
       .biztech-poweredby's header gives for having no `margin: 0`: a scoped restatement is (0,2,0) against a
       utility class's (0,1,0) and would silently beat every biztech-m*-* a caller passes in. */
    display: flex;
    flex-wrap: wrap;
    justify-content: center;

    /* 4px and 12px, whole multiples of the 4px base unit, which is what R5.4's sweep accepts. The row gap
       matters as much as the column gap: these wrap at 375px (W1a-09's viewport), and wrapped rows touching
       each other read as one run-on line. */
    gap: 4px 12px;
    margin-block-start: 4px;
}

/* Primary, for the reason both links above take it: PaletteContrast.RequiredPairs already tests Primary
   against Surface and against Background at 4.5:1 in both modes, so this introduces no pair anybody has to
   measure. Caption size, because these are footer links rather than page content - the same step
   .biztech-poweredby takes, from the scale rather than a literal (R4.3). */
.biztech-chrome-page[b-z5u91wc0r2] {
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}
/* /Components/Layout/VisitorSignInLinks.razor.rz.scp.css */
/* W25-03 · I18 · the header's gap spaces this wrapper as one item, so the two links carry their own. */
.biztech-visitor-links[b-h8ab986b0l] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
/* /Components/Pages/AccessRules.razor.rz.scp.css */
/* /access-rules — the page's own look, on the other W19 lists' terms. Every rule names an element this file's own markup
   carries (I19); the seam's paper is reached through `::deep` from `.biztech-access-page`, a wrapper written here. Every
   colour and radius is a --biztech-* variable, so a tenant's palette and radius reach it in both modes. */

/* The views' track sits on its own line above the view's heading. The track is app.css's .biztech-segmented. */
.biztech-access-views[b-485kkxudpn] {
    margin-block-end: 16px;
}

/* The explanation's panel (AccessExplanationView) takes the tables' quiet edge and corners (W19-08). It keeps its own
   padding (I17). */
.biztech-access-page[b-485kkxudpn]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The count beside a section's heading. It is inside the heading's own text, so it needs no box of its own: an inline start
   margin, not a flex gap - a class on UiText would land on that component's root, which this sheet cannot reach (I19).
   Glanced at, not read, so it is secondary ink in tabular figures. */
.biztech-access-count[b-485kkxudpn] {
    margin-inline-start: 8px;
    color: var(--biztech-palette-text-secondary);
    font-weight: 400;
    font-variant-numeric: tabular-nums;
}

/* ── By role: a list of folding role rows ─────────────────────────────────────────────────────────────
   One frame - the quiet edge and corners twice the theme's radius the console's tables wear - with a hairline between
   roles. A role's head is one line: the name (the toggle), its count, and the way to change it at the end. Its keys open
   underneath at the full width, in as many columns as fit, so a long role is a few short columns. */
.biztech-access-roles[b-485kkxudpn] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-access-role + .biztech-access-role[b-485kkxudpn] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-access-role-head[b-485kkxudpn] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
    padding: 8px 16px;
}

/* The toggle's word is the role's name, so it reads at weight in the page's ink. */
.biztech-access-role-toggle[b-485kkxudpn]  .biztech-button-label {
    font-weight: 600;
}

.biztech-access-role-count[b-485kkxudpn] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    font-variant-numeric: tabular-nums;
}

.biztech-access-role-change[b-485kkxudpn] {
    margin-inline-start: auto;
    font-size: var(--biztech-font-body2-size);
}

.biztech-access-role-body[b-485kkxudpn] {
    padding: 4px 16px 16px;
}

.biztech-access-role-areas[b-485kkxudpn] {
    columns: 22rem;
    column-gap: 32px;
}

/* One area: its name in a narrow column and its actions beside it, kept whole within a column. */
.biztech-access-role-area[b-485kkxudpn] {
    display: grid;
    grid-template-columns: 9rem minmax(0, 1fr);
    align-items: baseline;
    gap: 8px;
    padding-block: 4px;
    break-inside: avoid;
}

.biztech-access-role-area-name[b-485kkxudpn] {
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
    color: var(--biztech-palette-text-secondary);
    overflow-wrap: anywhere;
}

.biztech-access-role-action[b-485kkxudpn] {
    display: inline-flex;
    align-items: center;
    padding: 0 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, transparent);
    color: var(--biztech-palette-text-primary);
    font-family: monospace;
    font-size: var(--biztech-font-caption-size);
    line-height: 20px;
}



/* A lookup's "found nothing" note, spaced from what follows by its own block. */
.biztech-access-notice[b-485kkxudpn] {
    margin-block-end: 16px;
}

/* §2a C3 · the lookup's filter bar aligns to its top rather than centring its row, so an error under one field moves nothing
   beside it; every label on the bar is clipped, so the controls start level. */
.biztech-access-lookup[b-485kkxudpn]  .biztech-toolbar {
    align-items: flex-start;
}
/* /Components/Pages/ActivityTrail.razor.rz.scp.css */
/* W19-15 · /activity's own look: one column of the lookup, the person, their range, their trail and its pager, on the other W19
   lists' terms. Every rule names an element this file's markup carries (I19), a child component's box is reached through
   `::deep` from a wrapper written here, and every colour and radius is a --biztech-* variable. */

/* I18: the column spaces its sections; none carries a margin of its own. */
.biztech-activity-body[b-e7tvbw23cm] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* The range's field-and-button row, aligned to its top so an error under a field moves nothing beside it, on the filter bar's
   card. Its two dates keep their visible labels: "From" and "To" are all that tell the boxes apart. */
.biztech-activity-row[b-e7tvbw23cm] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px 16px;
    box-sizing: border-box;
    padding: 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

/* A date is a column sized to a date. */
.biztech-activity-date[b-e7tvbw23cm] {
    flex: 0 1 14rem;
    min-inline-size: 0;
}

@media (max-width: 599.98px) {
    .biztech-activity-date[b-e7tvbw23cm] {
        flex-basis: 100%;
    }
}

/* The button beside a field lines up with its control, not its label: offset by the label block a field has and a button has
   not - body2's size times its line height, plus .biztech-field's 4px gap (W19-12). Only from sm, where they share a row. */
@media (min-width: 600px) {
    .biztech-activity-beside[b-e7tvbw23cm] {
        margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}

/* The person whose trail it is: the name, and the address and count under it. */
.biztech-activity-subject[b-e7tvbw23cm] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The trail and its pager, closer to each other than to the sections around them. */
.biztech-activity-trail[b-e7tvbw23cm] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A visited path, which can be long: it wraps at 375px rather than pushing the page wide (R13.7). */
.biztech-activity-path[b-e7tvbw23cm] {
    overflow-wrap: anywhere;
}

/* The case list's pager row: where you are on the left, Newer and Older together at the right. It wraps rather than scrolling. */
.biztech-activity-pager[b-e7tvbw23cm] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.biztech-activity-pager-controls[b-e7tvbw23cm] {
    display: flex;
    align-items: center;
    gap: 8px;
}
/* /Components/Pages/AdminAssistantPage.razor.rz.scp.css */
/* W22-08 · the admin assistant as a page, in W19's language (W19-04, W19-05): the quiet edge, twice the theme's radius on cards, glyphs
   in tinted squares, pill suggestions, and the assistant panel's own turns. Every colour, radius, shadow and duration is a --biztech-*
   variable, so a tenant's palette, radius, depth and motion reach it (ADR 0026).

   🔴 THE PAGE IS EXACTLY THE WINDOW UNDER THE APP BAR AND DOES NOT SCROLL. The document is what scrolls on every other console page
   (MainLayout.razor.css); here it would move the list and the box with the conversation. So the layout takes the window's height and
   clips, the chat column is the one scroller - the box pinned to its bottom - and the list scrolls inside itself. */

/* Said, not drawn: the conversation is the page (R12.4's clipped label, the composer's own mechanism). */
.biztech-admin-chat-title[b-uzgz83cd8m] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The list, the chat and the preview, edge to edge in the console's main area: the list a column against the navigation, the chat
   centred in the middle, the preview against the window's far edge. The page draws its own gutters, since the list must reach the edge
   it sits against.

   🔴 THREE TRACKS ALWAYS, AND THE TWO OUTER ONES SLIDE. A track that is added or removed cannot be animated, so the preview's track is
   always there - 0 while shut - and the list's is the list's width or the rail's. The tracks then move at the theme's Motion setting,
   as the console's own drawer slides (MainLayout.razor.css animates its margin for the same reason): each pane's contents keep their
   full width inside a column that clips them (the -full and -inner wrappers below), so they slide into view rather than squeeze and
   reflow on every frame. container-type gives the preview its width as a share of this layout (cqi). The three widths are
   component-local custom properties, not --biztech-*, which names only what the theme emitter declares (TokenSufficiencyTests).

   🔴 THE PREVIEW OPENS AT HALF OF WHAT THE RAIL LEAVES. Opening it folds the list to the rail, so the chat and the preview split the
   rest evenly. It was 46% of the layout capped at 52rem, which left the preview narrower than the chat on a wide window. The half is
   a fallback at each use, not a value on the layout: the layout's own cqi reads the window, since an element is not its own
   container, so the track came out a scrollbar wider than the contents inside it. The track takes it as a share of the grid (%),
   and the contents as a share of this container (cqi); both are the same width. A dragged width, set on the layout, replaces both.
   Opening the list again halves what the list leaves instead, so the chat and the preview both give it room, not the chat alone. */
.biztech-admin-chat-layout[b-uzgz83cd8m] {
    --admin-chat-side: 16rem;
    --admin-chat-rail: 56px;
    display: grid;
    grid-template-columns: var(--admin-chat-side) minmax(0, 1fr) 0px;
    position: relative;
    block-size: calc(100dvh - var(--biztech-content-block-start, 0px));
    overflow: hidden;
    container-type: inline-size;
    transition: grid-template-columns var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-admin-chat-layout[data-side="closed"][b-uzgz83cd8m] {
    grid-template-columns: var(--admin-chat-rail) minmax(0, 1fr) 0px;
}

.biztech-admin-chat-layout[data-preview="open"][b-uzgz83cd8m] {
    grid-template-columns: var(--admin-chat-side) minmax(0, 1fr) var(--admin-chat-preview, calc((100% - var(--admin-chat-side)) / 2));
}

.biztech-admin-chat-layout[data-side="closed"][data-preview="open"][b-uzgz83cd8m] {
    grid-template-columns: var(--admin-chat-rail) minmax(0, 1fr) var(--admin-chat-preview, calc((100% - var(--admin-chat-rail)) / 2));
}

/* ── The fold control ───────────────────────────────────────────────────────────────────────────────────────────────── */

/* 🔴 ONE ROUND BUTTON ON THE LIST'S EDGE, HALF OVER THE HAIRLINE, AT THE MIDDLE OF THE COLUMN - away from New conversation, so the two
   never sit side by side as two different shapes - and always there, so it is never hunted for. It rides the edge as the column slides,
   at the theme's Motion setting. On the surface with the quiet edge and the theme's card depth, so it reads as a control lying on the
   seam rather than part of either side. */
.biztech-admin-chat-edge[b-uzgz83cd8m] {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: calc(var(--admin-chat-side) - 16px);
    z-index: var(--biztech-layer-sticky);
    display: flex;
    transform: translateY(-50%);
    transition: inset-inline-start var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-admin-chat-layout[data-side="closed"] .biztech-admin-chat-edge[b-uzgz83cd8m] {
    inset-inline-start: calc(var(--admin-chat-rail) - 16px);
}

.biztech-admin-chat-edge[b-uzgz83cd8m]  .biztech-icon-button {
    inline-size: 32px;
    block-size: 32px;
    min-inline-size: 32px;
    padding-block: 0;
    padding-inline: 0;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    color: var(--biztech-palette-text-secondary);
}

/* 🔴 SOLID ON HOVER TOO. The seam's icon button lays a see-through tint over whatever is under it on hover, and here that is the
   hairline the button straddles - it showed through the circle. The tint is mixed into the surface instead, and the selector carries the
   layout so it outweighs the seam's own hover rule. */
.biztech-admin-chat-layout .biztech-admin-chat-edge[b-uzgz83cd8m]  .biztech-icon-button:hover {
    border-color: var(--biztech-palette-primary);
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

/* ── The preview pane ───────────────────────────────────────────────────────────────────────────────────────────────────── */

/* A column of the layout's height on the surface, ruled off from the chat by a hairline as the list is on the other side. Its head
   stays; its body scrolls. */
.biztech-admin-chat-preview[b-uzgz83cd8m] {
    position: relative;
    display: flex;
    justify-content: flex-start;
    min-block-size: 0;
    min-inline-size: 0;
    overflow: hidden;
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
    background: var(--biztech-palette-surface);
}

/* The pane's left edge as a handle: 8px of hit area over the hairline, drawn as a 2px primary line on hover, on focus and while it is
   dragged. Above the pane's contents, so a portal's frame under it never takes the pointer. */
.biztech-admin-chat-resize[b-uzgz83cd8m] {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: var(--biztech-layer-sticky);
    inline-size: 8px;
    cursor: col-resize;
    touch-action: none;
}

.biztech-admin-chat-resize[b-uzgz83cd8m]::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: 2px;
    background: transparent;
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-admin-chat-layout[data-side="closed"][b-uzgz83cd8m]  .biztech-admin-chat-resize-side {
    display: none;
}

.biztech-admin-chat-resize:hover[b-uzgz83cd8m]::after,
.biztech-admin-chat-resize:focus-visible[b-uzgz83cd8m]::after,
.biztech-admin-chat-layout[data-resizing] .biztech-admin-chat-resize[b-uzgz83cd8m]::after,
.biztech-admin-chat-layout[data-resizing][b-uzgz83cd8m]  .biztech-admin-chat-resize-side::after {
    background: var(--biztech-palette-primary);
}

/* 🔴 THE HANDLE KEEPS THE SHARED FOCUS RING, AND IT USED TO SUPPRESS IT. `outline: none` was declared here on the reasoning that
   the bar going primary (the rule above) already says where focus is - but R3.11 bans the property outright, and app.css's own note
   on the link hover is the precedent: a second channel is ADDED to the ring, never swapped for it. A separator a keyboard user
   resizes with the arrow keys is exactly the control that must say where it is. The bar still lights; the ring is now also there. */
.biztech-admin-chat-resize:focus-visible[b-uzgz83cd8m] {
    outline-offset: 0;
}

/* While the handle is dragged the columns follow the pointer exactly - no slide - and a portal's frame takes no pointer events, so the
   drag is not lost into it. */
.biztech-admin-chat-layout[data-resizing][b-uzgz83cd8m] {
    transition: none;
    cursor: col-resize;
    user-select: none;
}

.biztech-admin-chat-layout[data-resizing] .biztech-admin-chat-preview-inner[b-uzgz83cd8m]  .biztech-artifact-body {
    pointer-events: none;
}

.biztech-admin-chat-layout[data-resizing] .biztech-admin-chat-edge[b-uzgz83cd8m] {
    transition: none;
}

/* Shut, the track is 0 and the pane draws no edge of its own. */
.biztech-admin-chat-layout[data-preview="closed"] .biztech-admin-chat-preview[b-uzgz83cd8m] {
    border-inline-start-color: transparent;
}

/* The pane's contents at the open width, whatever the track is doing, so the slide reveals them rather than reflowing them. */
.biztech-admin-chat-preview-inner[b-uzgz83cd8m] {
    display: flex;
    flex: none;
    flex-direction: column;
    box-sizing: border-box;
    inline-size: calc(var(--admin-chat-preview, calc((100cqi - var(--admin-chat-rail)) / 2)) - 1px);
    min-block-size: 0;
}

/* With the list open the half is of what the list leaves, as the track's is. The contents follow the track at its pace while the pane
   is open, so the list opening or folding does not leave the pane's far edge clipped or bare for the slide. */
.biztech-admin-chat-layout[data-side="open"] .biztech-admin-chat-preview-inner[b-uzgz83cd8m] {
    inline-size: calc(var(--admin-chat-preview, calc((100cqi - var(--admin-chat-side)) / 2)) - 1px);
}

.biztech-admin-chat-layout[data-preview="open"] .biztech-admin-chat-preview-inner[b-uzgz83cd8m] {
    transition: inline-size var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-admin-chat-layout[data-resizing] .biztech-admin-chat-preview-inner[b-uzgz83cd8m] {
    transition: none;
}

.biztech-admin-chat-layout[b-uzgz83cd8m]  .biztech-admin-chat-rail-item .biztech-icon-button:hover {
    background: color-mix(in srgb, var(--biztech-palette-primary) 16%, var(--biztech-palette-primary-container));
}

.biztech-admin-chat-layout[data-side="open"][b-uzgz83cd8m]  .biztech-admin-chat-side-rail,
.biztech-admin-chat-layout[data-side="closed"][b-uzgz83cd8m]  .biztech-admin-chat-side-full {
    opacity: 0;
    pointer-events: none;
}

/* ── Motion ───────────────────────────────────────────────────────────────────────────────────────────────────────────── */

/* 🔴 EVERYTHING THAT MOVES ON THIS PAGE MOVES AT THE THEME'S MOTION SETTING, so a theme's None is still and its Expressive is slower.
   The two panes slide with their tracks (the layout's transition above) and the list and rail cross-fade; what arrives fades and rises
   in as it mounts - app.css's biztech-appear, the vocabulary every opened accordion, menu and dialog in the console already speaks:

   · a conversation row, when a new conversation joins the list
   · the empty conversation's greeting and box, on arrival and on New conversation, and its suggestions a beat after
   · each turn as it is asked, and the cards in it
   · the preview's contents, when another card's preview swaps in */
.biztech-admin-chat-preview-inner[b-uzgz83cd8m]  .biztech-proposal-preview,
.biztech-admin-chat-preview-inner[b-uzgz83cd8m]  .biztech-artifact-card {
    animation: biztech-appear var(--biztech-motion-duration, 120ms) ease-in-out;
}

@media (prefers-reduced-motion: reduce) {
    .biztech-admin-chat-preview-inner[b-uzgz83cd8m]  .biztech-proposal-preview,
    .biztech-admin-chat-preview-inner[b-uzgz83cd8m]  .biztech-artifact-card {
            animation: none;
        }

    .biztech-admin-chat-layout[b-uzgz83cd8m],
    .biztech-admin-chat-edge[b-uzgz83cd8m],
    .biztech-admin-chat-resize[b-uzgz83cd8m]::after,
    .biztech-admin-chat-preview[b-uzgz83cd8m] {
            transition: none;
        }
}

/* ── Below md ───────────────────────────────────────────────────────────────────────────────────────────────────────────── */

/* A phone's column has no width to share, so the rail stays in flow and the list and the preview each lie over the chat, sliding in
   from the edge they sit against - transform only, at the same Motion setting. */
@media (max-width: 959.98px) {
    .biztech-admin-chat-layout[b-uzgz83cd8m],
    .biztech-admin-chat-layout[data-side="closed"][b-uzgz83cd8m],
    .biztech-admin-chat-layout[data-preview="open"][b-uzgz83cd8m],
    .biztech-admin-chat-layout[data-side="closed"][data-preview="open"][b-uzgz83cd8m] {
            grid-template-columns: var(--admin-chat-rail) minmax(0, 1fr) 0px;
        }

    .biztech-admin-chat-layout[data-side="closed"][b-uzgz83cd8m]  .biztech-admin-chat-side-full {
            transform: translateX(-100%);
        }

        /* The fold control rides the open list's edge over the chat, or the rail's when it is folded. */
    .biztech-admin-chat-edge[b-uzgz83cd8m] {
            position: fixed;
            inset-block-start: calc(var(--biztech-content-block-start, 0px) + (100dvh - var(--biztech-content-block-start, 0px)) / 2);
            inset-inline-start: calc(min(18rem, 85vw) - 16px);
            z-index: calc(var(--biztech-layer-drawer) + 1);
        }

    .biztech-admin-chat-layout[data-side="closed"] .biztech-admin-chat-edge[b-uzgz83cd8m] {
            inset-inline-start: calc(var(--admin-chat-rail) - 16px);
        }

        /* A phone's preview fills the window, so it has no edge to drag. */
    .biztech-admin-chat-resize[b-uzgz83cd8m] {
            display: none;
        }

        /* The rail stays under the open list, so the column never empties. */
    .biztech-admin-chat-layout[data-side="open"][b-uzgz83cd8m]  .biztech-admin-chat-side-rail {
            opacity: 1;
        }

    .biztech-admin-chat-preview[b-uzgz83cd8m] {
            position: fixed;
            inset-block: var(--biztech-content-block-start, 0px) 0;
            inset-inline: 0;
            z-index: var(--biztech-layer-drawer);
            border-inline-start: none;
            transition: transform var(--biztech-motion-duration, 120ms) ease-in-out;
        }

    .biztech-admin-chat-layout[data-preview="closed"] .biztech-admin-chat-preview[b-uzgz83cd8m] {
            transform: translateX(100%);
        }

    .biztech-admin-chat-preview-inner[b-uzgz83cd8m],
    .biztech-admin-chat-layout[data-side="open"] .biztech-admin-chat-preview-inner[b-uzgz83cd8m] {
            inline-size: 100%;
        }
}
/* /Components/Pages/AgentAccess.razor.rz.scp.css */
/* W8-05 · F10.12 — the agent-access console. TOKENS ONLY: R3.1's sweep in PortalStyleSheetTests reads
   every *.razor.css in this project and refuses a hex or an rgb() literal. */

/* 🔴 THE CHECKBOX GRID, WHICH IS LEGACY'S CONTROL AND THE CARD'S "bulk is real work".
   RulesPermissionsPage.cshtml's own `.rp-pages-checks` is `repeat(auto-fill, minmax(180px, 1fr))` with a
   scroll cap, and this is that shape in this application's units - an operator who knows that screen
   meets the same control here.

   auto-fill rather than a fixed column count: a tenant may have three collections or thirty, and the
   grid has to be honest at both without a breakpoint per size. 14rem is wide enough for a collection
   name at the caption step without wrapping mid-word. */
.biztech-agent-collection-picks[b-el5iun7byc] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));

    /* 8px and 16px: whole multiples of the 4px base unit, which is what R5.4's sweep accepts. The row
       gap is tighter than the column gap because a checkbox and its label are one line - vertical air
       between them would read as more separation than there is. */
    gap: 8px 16px;

    /* 🔴 CAPPED AND SCROLLABLE, for the reason legacy caps its own at 220px: a tenant with thirty
       collections would otherwise push the Grant button below the fold, and a form whose submit control
       cannot be seen is one people abandon. The cap is in rem so it grows with the reader's type size. */
    max-height: 18rem;
    overflow-y: auto;

    /* R5.6's fixed border width. The box is a group of controls rather than a surface of its own, so it
       is outlined rather than filled - the UiPaper it sits inside already carries the surface. */
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    padding: 12px;
}

/* W19 · the page on the other W19 screens' terms. Every rule names an element this file's own markup carries (I19); the
   panels' boxes are reached through `::deep` from the wrapper written here. Every colour and radius is a --biztech-*
   variable. */

/* The page's sections are spaced by this container (I18): the look-up, the alerts, the agent, and each section under it. */
.biztech-agent-access[b-el5iun7byc] {
    display: grid;
    gap: 24px;
}

/* Every panel on the page - this file's and the two panels' it mounts - takes the tables' quiet edge and corners twice the
   theme's radius (W19-08). UiPaper keeps its own default for every other page. */
.biztech-agent-access[b-el5iun7byc]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* ── the look-up ───────────────────────────────────────────────────────────────────────────────────
   §2a C3 · on UiFilterBar. The bar centres its row; this one aligns to its top, so an error under the address moves nothing
   beside it - the address's label is clipped, so the box and Look up start level. */
.biztech-agent-lookup[b-el5iun7byc]  .biztech-toolbar {
    align-items: flex-start;
}

/* ── the agent ─────────────────────────────────────────────────────────────────────────────────────
   One card: a tinted glyph square, then the name over the address and the two facts. The glyph square is the portal tile's
   chip (W19-04). */
.biztech-agent-summary[b-el5iun7byc] {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-agent-summary-mark[b-el5iun7byc] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, transparent);
    color: var(--biztech-palette-primary);
}

.biztech-agent-summary-body[b-el5iun7byc] {
    display: grid;
    gap: 12px;
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* The facts: a label column and its values. One column under sm, where the label sits over its chips. */
.biztech-agent-facts[b-el5iun7byc] {
    display: grid;
    gap: 8px;
    margin: 0;
}

.biztech-agent-fact[b-el5iun7byc] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
}

@media (min-width: 600px) {
    .biztech-agent-fact[b-el5iun7byc] {
        grid-template-columns: 6rem minmax(0, 1fr);
        align-items: center;
        gap: 12px;
    }
}

.biztech-agent-fact dd[b-el5iun7byc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0;
}

/* ── the sections ──────────────────────────────────────────────────────────────────────────────────
   A heading and its sentence, then the section's table or panel, spaced by the container (I18). */
.biztech-agent-section[b-el5iun7byc] {
    display: grid;
    gap: 12px;
}

.biztech-agent-section-head[b-el5iun7byc] {
    display: grid;
    gap: 4px;
}

/* A key is a machine name: the code face, at the caption step. */
.biztech-agent-key[b-el5iun7byc] {
    font-family: var(--biztech-font-mono-family);
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

/* The row's verb at the row's end, with who granted it before it, so every row's button lines up down the column. */
.biztech-agent-row-actions[b-el5iun7byc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px 12px;
}

/* The grant form inside its panel: the heading, the grid of collections, then the date and the action. */
.biztech-agent-grant[b-el5iun7byc] {
    display: grid;
    gap: 16px;
}

.biztech-agent-grant-foot[b-el5iun7byc] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
}

.biztech-agent-grant-date[b-el5iun7byc] {
    flex: 0 1 16rem;
}
/* /Components/Pages/AgentCaseLauncher.razor.rz.scp.css */
/*
    W8-25 · F10.3 — the launcher's own sheet, and it exists because a class was styled by nothing.

    🔴 THE LAYOUT PAIR CARRIED `biztech-view-switch` AND NO RULE REACHED IT. That class is declared in
    Inquiries.razor.css, which is a SCOPED stylesheet — Blazor stamps its scope attribute only on markup
    Inquiries.razor renders, so the launcher's copy of the class matched nothing at all. Measured on the
    running stack: `border: 0px, padding: 0px, display: block` on the element that was supposed to be a
    segmented control. That is I19's trap read from the other side — the invariant catches a scoped rule
    reaching for a class that is not there, and this was a class reaching for a rule that was not.

    Copied rather than moved, deliberately: the operator console's Active/Archived switch is its own
    control on its own page, and hoisting one rule into app.css to serve two surfaces would make every
    later change to either a change to both. R14.1's layering puts a component's own geometry in its own
    sheet.

    🔴 NO GROUND COLOUR, AND TokenSufficiencyTests IS WHY THE FIRST DRAFT HAD ONE. That draft read
    --biztech-palette-surface-sunken, which this application does not declare — a var() that resolves to
    nothing paints nothing, with no error and no warning, so the sweep caught a rule that would have been
    silently inert. The operator console's switch uses a border and an inset and no ground; matching it
    is both correct and the same control in two places looking like one.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit, except the
    2px inset the segmented control needs — which is the same 2px Inquiries.razor.css already spends on
    the same idiom.
*/

/* 🔴 A SEGMENTED CONTROL, WHICH IS A DIFFERENT ARTEFACT FROM TWO BUTTONS THAT HAPPEN TO BE ADJACENT.
   The border and the inset ground are what say "these two are one control and exactly one is on" — the
   thing a pair of loose buttons cannot say, and the reason the first version read as two stray glyphs
   beside the tab strip.

   `inline-flex` so the control is only as wide as its segments; the tab row's own layout places it. */
.biztech-view-switch[b-7v9iahjl5x] {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* 🔴 THE SEGMENTS ARE SQUARE-ISH INSIDE A ROUNDED TRACK, which is what makes the selected one read as
   filling its slot rather than floating in it. Without this the button's own radius left a visible
   crescent of track at each corner of the filled segment.

   ::deep is required and MediaRoom.razor.css records the trap: the element is UiButton's own root,
   rendered by another component, so this file's scope attribute never reaches it unaided. */
.biztech-view-switch[b-7v9iahjl5x]  .biztech-button {
    border-radius: calc(var(--biztech-radius-default) - 2px);
    min-width: 36px;
}

/* An icon-only segment is a square, not a pill: UiButton's horizontal padding is sized for words, and
   with no words it left each glyph adrift in the middle of a wide button. */
.biztech-view-switch[b-7v9iahjl5x]  .biztech-button-label:empty {
    display: none;
}

.biztech-view-switch[b-7v9iahjl5x]  .biztech-button:has(.biztech-button-label:empty) {
    padding-inline: 8px;
}

/*
    W8-38 · the opening tile's introduction. W20-05 · D14 made it sanitised markup, for the reason
    PortalTilePageBody.razor.css gives beside .biztech-portal-tile-intro, so its line breaks are elements.
    NO COLOUR and NO SPACING of its own - the margin is biztech-mb-3 on the div.
*/

.biztech-launcher-intro[b-7v9iahjl5x] {
    white-space: normal;
}

/* W26-05 · D5 · THE OPENING TILE'S INTRO KEEPS THE INTRO MEASURE AT FULL WIDTH - the 48rem PortalTilePageBody and
   PortalItemPageBody give the same text. Start-aligned, as theirs is. From the standard measure, 71.25rem, where full
   first differs from standard. */
@media (min-width: 71.25rem) {
    [data-portal-width="full"] .biztech-launcher-intro[b-7v9iahjl5x] {
        max-inline-size: 48rem;
    }
}

/* 🔴 THE CURRENT SEGMENT IS TINTED, NOT FILLED, AND A PAGE WITH A PRIMARY BUTTON IS WHY.

   It was Filled + Primary, which is the same fill and ink UiButton gives the page's primary ACTION -
   so on /inquiries "Active" and "New case" were the same object to the eye: one is a state, the other
   is the thing to press. The tint and primary ink are what this application already uses for "this one
   is current" on the nav's active item and .biztech-selected's rows.

   12% rather than those two's 8%: they carry a 2px inset bar as well, and a segment inside a bordered
   track has nothing but its own ground to say it is on.

   Keyed on aria-current, which the markup already publishes - UiTab does the same rather than inventing
   a class for a state the DOM carries. */
.biztech-view-switch[b-7v9iahjl5x]  .biztech-button[aria-current="page"] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);

    /* 🔴 THE BORDER IS WHAT MAKES THIS WORK ON DARK, AND IT WAS ADDED AFTER MEASURING. The tint alone
       carries the state on light, where it reads 1.5:1 against the page; on dark the same 12% of a light
       blue over a near-black ground came to 1.19:1 - invisible, leaving the ink's colour as the only
       signal, which is the "colour alone" WCAG 1.4.1 rules out. The text itself was never at risk
       (5.06:1 on dark), but a state nobody can see is not a state.

       `border-color` only: .biztech-button-text already declares a transparent 1px border, so the
       segment's box does not change size and the track's 2px inset still holds. */
    border-color: var(--biztech-palette-primary);
}

/* 🔴 THE LAUNCHER IN THE PORTAL'S LOOK. A tile opens this page, so it should read as the next page of that portal: the
   title at the size an item page's title is (PortalItemPageBody's H4). PageHeader is shared with the console, so it
   is reached from this page's own root through ::deep and nowhere else - /inquiries is untouched. The case cards on
   the work tabs style themselves (CaseCard.razor.css): this page is the only one that draws them. */
.biztech-launcher[b-7v9iahjl5x]  .biztech-page-header-row h1 {
    font-size: var(--biztech-font-h4-size);
    font-weight: var(--biztech-font-h4-weight);
    line-height: var(--biztech-font-h4-line-height);
    letter-spacing: var(--biztech-font-h4-letter-spacing);
}

/* The work tabs in the same look. The filter toolbar is CaseWorkList's, shared with /inquiries, so it is reached only from
   this page's root. The list itself stands on UiListCard (guidelines §2a C4), which draws the card and the one-card-per-row
   reflow below md, so this sheet no longer restates either. */
.biztech-launcher[b-7v9iahjl5x]  .biztech-filters .biztech-toolbar {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The theme's case launcher tabs (ThemePortalLook): UiTabs' row with its rule and the current tab's underline, or a
   segmented track - an inset ring with the current tab tinted and ringed in the primary, .biztech-segmented's look.
   Here, on the launcher, so the console's tab rows keep their own; one class deeper than UiTabs' own rules. */
.biztech-launcher[b-7v9iahjl5x]  .biztech-tabs {
    border-block-end-color: var(--biztech-portal-tabs-rule, var(--biztech-palette-outline-subtle));
}

.biztech-launcher[b-7v9iahjl5x]  .biztech-tabs .biztech-tabs-list {
    padding: var(--biztech-portal-tabs-track-inset, 0);
    border-radius: var(--biztech-radius-default);
    box-shadow: inset 0 0 0 1px var(--biztech-portal-tabs-track, transparent);
}

.biztech-launcher[b-7v9iahjl5x]  .biztech-tabs .biztech-tab {
    border-radius: calc(var(--biztech-radius-default) * var(--biztech-portal-tab-radius-factor, 0));
}

.biztech-launcher[b-7v9iahjl5x]  .biztech-tabs .biztech-tab[aria-current="page"] {
    border-block-end-color: var(--biztech-portal-tab-indicator, var(--biztech-palette-primary));
    background: var(--biztech-portal-tab-current-ground, transparent);
    color: var(--biztech-portal-tab-current-ink, var(--biztech-palette-text-primary));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-tab-current-ring, transparent);
}

/* The theme's case list rows: the cells' height and every other row's ground, on the launcher's list only - the same
   table is the console's case list. From the width the table stops reflowing into stacked cards, whose padding is its
   own. */
@media (min-width: 960px) {
    .biztech-launcher[b-7v9iahjl5x]  .biztech-td {
        padding-block: var(--biztech-portal-row-inset, 8px);
    }
}

.biztech-launcher[b-7v9iahjl5x]  tbody tr:nth-child(even) .biztech-td {
    background: var(--biztech-portal-row-stripe, transparent);
}
/* /Components/Pages/AgentLibrary.razor.rz.scp.css */
/* W19-17 · the reader's library in the portal: the listing's table sits on W19's quiet card - the theme's box edge, twice
   its radius, the surface - where it lay on the page's ground. The card view's own cards stay as they are. The console's
   library, which mounts the same component, is not under this wrapper and keeps its look. */
.biztech-agent-library[b-dzopbmhhku]  [data-library-listing]:has(.biztech-table) {
    padding: 4px 16px;
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-agent-library[b-dzopbmhhku]  [data-library-listing] .biztech-table-row:last-child .biztech-td {
    border-block-end: 0;
}
/* /Components/Pages/AgentPermissions.razor.rz.scp.css */
/* W8-30 · the viewer's own permissions. TOKENS ONLY for colour (R3.1), whole multiples of the 4px base
   unit for space (R5.4). Every gap is the container's (I18) and every rule names markup this component
   writes itself (I19) - the groups and rows are plain elements here, not a child component's root. */

.biztech-own-access[b-t7bf098977] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* I18 · inside each panel, the heading and its list or sentence are spaced by the stack's gap, never
   by a margin on either - UiText resets its own margins, so without this they would touch. The role row
   is the same stack one level down: its <h3> over its sentences. */
.biztech-own-access-panel[b-t7bf098977] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* A role: the glyph beside its name and what it allows. */
.biztech-own-access-role[b-t7bf098977] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.biztech-own-access-role-words[b-t7bf098977] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-own-access-glyph[b-t7bf098977] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

.biztech-own-access-list[b-t7bf098977],
.biztech-own-access-sentences[b-t7bf098977] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-own-access-sentences[b-t7bf098977] {
    gap: 8px;
}

@media (min-width: 960px) {
    .biztech-own-access-sentences[b-t7bf098977] {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px 24px;
    }
}

/* A sentence with a tick before it, in the success colour, the text in secondary ink. */
.biztech-own-access-sentences > li[b-t7bf098977] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-own-access-tick[b-t7bf098977] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-success);
}

.biztech-own-access-row[b-t7bf098977] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    padding-top: 12px;
    border-top: 1px solid var(--biztech-palette-outline-subtle);

    /* A key or an organisation name has no break opportunity of its own; at 375px it must wrap rather
       than widen the row past the page (R13.3). */
    overflow-wrap: anywhere;
}

/* The chips wrap under the sentence at 375px rather than pushing the row wider than the page. */
.biztech-own-access-state[b-t7bf098977] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-own-access-row-words[b-t7bf098977] {
    display: flex;
    flex: 1 1 20rem;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* W19's quiet card for every panel on this page, reached from its own wrapper (I19). §2a C9 · its depth is the card
   shadow token, which the panels lacked. */
.biztech-own-access-page[b-t7bf098977]  .biztech-paper {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    box-shadow: var(--biztech-shadow-card);
}

/* A panel's title and its count, a pill in the primary's pale tone. */
.biztech-own-access-head[b-t7bf098977] {
    display: flex;
    align-items: center;
    gap: 8px;
}

.biztech-own-access-count[b-t7bf098977] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 24px;
    block-size: 24px;
    padding-inline: 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
}

/* Show all sits under the list, pulled back to the text's edge so it reads as the list's last line. */
.biztech-own-access-more[b-t7bf098977] {
    display: flex;
    margin-inline-start: -8px;
}

/* Nought is quiet ink - an empty group is not something to look at - where it took the primary like a count with rows. */
.biztech-own-access-count-none[b-t7bf098977] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, var(--biztech-palette-surface));
    color: var(--biztech-palette-text-secondary);
}

/* The first row sits under the panel's title, which already parts it; its own rule doubled that. */
.biztech-own-access-row:first-child[b-t7bf098977] {
    padding-top: 0;
    border-top: 0;
}

/* 24px inside each panel, where the utility's 16px crowded the title against the edge. */
.biztech-own-access-page[b-t7bf098977]  .biztech-paper {
    padding: 24px;
}
/* /Components/Pages/AgentPresentationDeliver.razor.rz.scp.css */
/* W27-03 · C2 · the subtitle's sentence over the picture, and the two panels, each spaced by its container (I18). */

.biztech-agent-deliver-subtitle[b-gvxyygxjoc] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-agent-deliver[b-gvxyygxjoc] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The delivery form on this portal page - DeckDeliveryPanel is shared with the console's, which keeps its look: W19's
   quiet card with room inside, the case type and its hint as one group, the customer's name and email side by side,
   and Start as the foot under a rule. */
.biztech-agent-deliver[b-gvxyygxjoc]  .biztech-paper {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    padding: 24px;
}

.biztech-agent-deliver[b-gvxyygxjoc]  [data-testid="deck-delivery-type"] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-block-end: 16px;
}

.biztech-agent-deliver[b-gvxyygxjoc]  .biztech-deck-delivery-fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 600px) {
    .biztech-agent-deliver[b-gvxyygxjoc]  .biztech-deck-delivery-fields {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.biztech-agent-deliver[b-gvxyygxjoc]  [data-testid="deck-delivery-start"] {
    margin-block-start: 24px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/AgentPresentations.razor.rz.scp.css */
/* W27-03 · C2 · the agent's decks as cards (ADR 0026), DeckLibrary's arrangement. Every gap is a container's (I18);
   no child carries a margin. */

.biztech-agent-decks[b-o9odu067kt] {
    display: flex;
    flex-direction: column;
    gap: 32px;
}

/* §2a C3 · the filter bar's hooks for tests and journeys take no box of their own, so the seam's search and field stay the
   bar's flex items and keep its widths. */
.biztech-agent-decks-hook[b-o9odu067kt] {
    display: contents;
}

.biztech-agent-decks-group[b-o9odu067kt] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A wrapping grid sized by the track: a phone at 375px gets one full-width column. */
.biztech-agent-decks-grid[b-o9odu067kt] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 16px;
}

.biztech-agent-decks-cell[b-o9odu067kt] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
}

/* The deck card on this portal page - DeckCard is shared with the console's library, which keeps its look: W19's quiet
   card, every card the row's height with its action at the foot, the name in the text's ink rather than an underlined
   link, and the empty cover a pale tone of the primary. */
.biztech-agent-decks-cell[b-o9odu067kt]  .biztech-deck-card {
    flex: 1 1 auto;
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-agent-decks-cell[b-o9odu067kt]  .biztech-deck-card-picture {
    background-color: color-mix(in srgb, var(--biztech-palette-primary) 8%, var(--biztech-palette-surface));
}

.biztech-agent-decks-cell[b-o9odu067kt]  .biztech-deck-card-body {
    flex: 1 1 auto;
    gap: 8px;
    padding: 16px 16px 12px;
}

.biztech-agent-decks-cell[b-o9odu067kt]  .biztech-deck-card-name {
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
    text-decoration: none;
}

.biztech-agent-decks-cell[b-o9odu067kt]  .biztech-deck-card-name:hover {
    color: var(--biztech-palette-primary);
    text-decoration: underline;
}

.biztech-agent-decks-cell[b-o9odu067kt]  .biztech-deck-card-actions {
    padding: 12px 16px 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W19's quiet card, for the deliveries and the empty states - the portal's configured box edge, which UiEmptyState's own
   card does not carry, so each empty state sits on this one with OnCard="false" (§2a C5, C11). */
.biztech-agent-decks-card[b-o9odu067kt] {
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    overflow: hidden;
}

.biztech-agent-deliveries[b-o9odu067kt] {
    display: flex;
    flex-direction: column;
}

.biztech-agent-delivery[b-o9odu067kt] {
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

.biztech-agent-delivery + .biztech-agent-delivery[b-o9odu067kt] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The case reference is the row's one link, coloured as the deck card's name is - not the browser's default blue. */
/* A delivery's row is its case's link: the glyph, the subject over its reference and when, the stage as a pill. */
.biztech-agent-case-link[b-o9odu067kt] {
    display: flex;
    align-items: center;
    gap: 12px;
    min-block-size: 44px;
    padding: 12px 16px;
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
}

.biztech-agent-case-link:hover[b-o9odu067kt] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 4%, transparent);
}

.biztech-agent-delivery-glyph[b-o9odu067kt] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

.biztech-agent-delivery-words[b-o9odu067kt] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-agent-delivery-subject[b-o9odu067kt] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-agent-delivery-meta[b-o9odu067kt] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    font-variant-numeric: tabular-nums;
}

.biztech-agent-delivery-stage[b-o9odu067kt] {
    flex: none;
    padding: 4px 12px;
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
    white-space: nowrap;
}

.biztech-agent-delivery-go[b-o9odu067kt] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Pages/AgentQaHistory.razor.rz.scp.css */
/* W8-30 · the asker's four figures and their answers. TOKENS ONLY for colour (R3.1's sweep), whole
   multiples of the 4px base unit for space (R5.4). Every gap is the container's (I18), and every rule
   names markup this component writes itself (I19) - nothing here reaches into a child component. */

/* W19-23 · the figures are the seam's stat tiles; this hands them the portal's configured box edge through the wrapper this
   page writes (I19), with the console's quiet edge when the portal names none. */
.biztech-qa-figures[b-w43c4yss6v]  .biztech-stat-tile {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
}

.biztech-qa-answer-facts dd[b-w43c4yss6v] {
    margin: 0;
}

.biztech-qa-answers[b-w43c4yss6v],
.biztech-qa-sources[b-w43c4yss6v] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-qa-sources[b-w43c4yss6v] {
    gap: 8px;
}

.biztech-qa-answer[b-w43c4yss6v] {
    display: flex;
    flex-direction: column;
    gap: 16px;

    /* The question, the answer and a source's title are free text from a person or a model; a long URL
       has no break opportunity of its own and would widen the card past a 375px page (R13.3). */
    overflow-wrap: anywhere;
}

.biztech-qa-answer-facts[b-w43c4yss6v] {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 24px;
    margin: 0;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-qa-answer-fact[b-w43c4yss6v] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-qa-answer-fact dd[b-w43c4yss6v] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* W19's quiet card for every panel on this page, reached from its own wrapper (I19). */
.biztech-qa[b-w43c4yss6v]  .biztech-paper {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The period: From, To and Apply on one row, the hint under them; the fields wrap under each other on a phone. */
.biztech-qa-period[b-w43c4yss6v] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-block-end: 24px;
}

/* §2a C1 · aligned to the row's TOP, so an error under one date does not lift that field above its neighbour; Apply drops
   by the label line the fields have and it has not, read from the tokens (PeriodFilter's arrangement). */
.biztech-qa-period-row[b-w43c4yss6v] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px;
}

.biztech-qa-period-apply[b-w43c4yss6v] {
    margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
}

.biztech-qa-period-field[b-w43c4yss6v] {
    flex: 0 1 14rem;
    min-inline-size: 0;
}

/* An answer's head: the glyph in the primary's pale square beside the question and when it was asked. */
.biztech-qa-answer-head[b-w43c4yss6v] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.biztech-qa-answer-glyph[b-w43c4yss6v] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

.biztech-qa-answer-title[b-w43c4yss6v] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* The answer under the question's title, indented to the title's edge rather than the glyph's. UiText's root, so ::deep
   from the article this page writes (I19). */
.biztech-qa-answer[b-w43c4yss6v]  .biztech-qa-answer-text {
    padding-inline-start: 44px;
    /* An answer written as lines - a list of steps - keeps them, where they ran together into one paragraph. */
    white-space: pre-line;
}

.biztech-qa-source[b-w43c4yss6v] {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-qa-sources-group[b-w43c4yss6v] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* 24px inside each card, where the utility's 16px crowded the question against the edge. */
.biztech-qa[b-w43c4yss6v]  .biztech-paper {
    padding: 24px;
}

/* The figure at the scale's h5 in the heavier weight, where h4's 34px read as a poster. */
[data-qa-value][b-w43c4yss6v] {
    font-weight: 600;
}
/* /Components/Pages/AgentTransmittals.razor.rz.scp.css */
/* The agent's transmittals: the table on UiListCard (§2a C4), whose edge takes the portal's configured box edge where one
   is set, and the last row's own rule dropped where it would double the card's edge. Every colour and radius is a token. */
.biztech-transmittals-list[b-mnfhqggyz0]  .biztech-list-card {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
}

.biztech-transmittals-list[b-mnfhqggyz0]  .biztech-table-row:last-child .biztech-td {
    border-block-end: 0;
}

.biztech-transmittals-list[b-mnfhqggyz0]  .biztech-td {
    padding-block: 12px;
}
/* /Components/Pages/AiAdminAuditDetail.razor.rz.scp.css */
/* W22-02 · D12. One admin turn, as a reviewer reads it.

   🔴 I18 - EACH COLUMN SPACES ITS CHILDREN. The turn's headings, sentences and caption, the list of proposals, and a proposal's own heading,
   summary, notes and text are each siblings in one flex column with a gap, and none carries a margin of its own - so the gaps cannot add up the
   way a gap plus a margin per child does. A <pre> zeroes the user agent's block margin (a declared exception in UtilitySpecificityTests).

   I19 - every rule names a class this component's own markup writes. */
.biztech-ai-admin-audit-turn[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* The reply's paragraphs and lists (AdminProseView), spaced as the panel's turn spaces them (I18), and wrapped at 375px (R13.7). */
.biztech-ai-admin-audit-reply[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    overflow-wrap: anywhere;
}

.biztech-ai-admin-audit-proposals[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-ai-admin-audit-proposal[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* The checked JSON, exactly as stored: monospace, wrapped so a long line does not push the page sideways at 375px (R13.7), and
   scrollable when it is tall so a large proposal does not push everything under it out of reach. */
.biztech-ai-admin-audit-text[b-i39tfkkdum] {
    box-sizing: border-box;
    margin: 0;
    padding: 8px;
    max-block-size: 24rem;
    overflow: auto;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* W19-15 · the page's column: the turn, the tool calls, the proposals and the figures, spaced by its gap (I18). */
.biztech-ai-admin-audit-detail[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* A section's heading and what it holds. */
.biztech-ai-admin-audit-section[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* A panel on the quiet card (W19-08). The page writes the card itself, so nothing reaches into a child component. */
.biztech-ai-admin-audit-card[b-i39tfkkdum] {
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* W19-15 · a tool call's arguments and result are JSON with no break points, and one ran past the table card's edge.
   Wrapped anywhere, in the face the checked JSON above uses, so each stays inside its cell. */
.biztech-ai-turn-json[b-i39tfkkdum] {
    overflow-wrap: anywhere;
    font-family: var(--biztech-font-mono-family);
}

/* W19-18 · a long tool payload, folded to its opening characters; it opens into .biztech-ai-admin-audit-text above. */
.biztech-ai-turn-fold[b-i39tfkkdum] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-ai-turn-fold > summary[b-i39tfkkdum] {
    cursor: pointer;
}

.biztech-ai-turn-fold-more[b-i39tfkkdum] {
    color: var(--biztech-palette-primary);
    font-family: var(--biztech-font-family);
    font-weight: var(--biztech-font-subtitle2-weight);
    white-space: nowrap;
}
/* /Components/Pages/AiAdminAuditList.razor.rz.scp.css */
/* W19-15 · /ai-audit/admin's own look: one column of the period and the turns, on the other W19 lists' terms. Every rule names
   an element this file's markup carries (I19), a child component's box is reached through `::deep` from a wrapper written here,
   and every colour and radius is a --biztech-* variable. */

/* I18: the column spaces its sections; none carries a margin of its own. */
.biztech-ai-admin-audit-body[b-qngt5cdb7x] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* The table, the empty block and the pager, spaced by the section. */
.biztech-ai-admin-audit-turns[b-qngt5cdb7x] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The case list's pager row: the page on the left, the two ways on at the right. It wraps at narrow widths rather than scrolling. */
.biztech-ai-admin-audit-pager[b-qngt5cdb7x] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.biztech-ai-admin-audit-pager-links[b-qngt5cdb7x] {
    display: flex;
    align-items: center;
    gap: 16px;
}

/* A way on, with its chevron beside its words. */
.biztech-ai-admin-audit-pager-link[b-qngt5cdb7x] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
/* /Components/Pages/AiAnswerAuditDetail.razor.rz.scp.css */
/* W19-15 · /ai-audit/{id}'s own look: one column of cards, each on the quiet edge (W19-08), spaced by the column (I18). Every
   rule names an element this file's markup carries (I19), and every colour and radius is a --biztech-* variable. */
.biztech-ai-audit-detail[b-mxuako74ux] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* A panel is this page's own section or div, so the edge is written on it directly - nothing reaches into a child component.
   Its heading, sentences and caption are spaced by its gap (W18-06 · D16's column, kept). */
.biztech-ai-audit-card[b-mxuako74ux] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* The verdict and the reviewer's decision: two cards, side by side from md - two facts, never one. */
.biztech-ai-audit-facts[b-mxuako74ux] {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

@media (min-width: 960px) {
    .biztech-ai-audit-facts[b-mxuako74ux] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The earlier questions, numbered by the list: the browser's own list margin is dropped so the column's gap spaces it. */
.biztech-ai-audit-turns[b-mxuako74ux] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding-inline-start: 24px;
}

/* The supplied and cited passages: a heading, a caption and the table, spaced by the column. */
.biztech-ai-audit-sources[b-mxuako74ux] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The outcome question and its error under it, closed to the field's own 4px. */
.biztech-ai-audit-question[b-mxuako74ux] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The reason is a sentence or two, so it is a column of the form's measure rather than the page's width. */
.biztech-ai-audit-reason[b-mxuako74ux] {
    max-inline-size: 36rem;
}

/* The review's foot: Record review and what it does, under a rule (W19-03). */
.biztech-ai-audit-foot[b-mxuako74ux] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/AiAnswerAuditList.razor.rz.scp.css */
/* W19-15 · /ai-audit's own look: one column of the period, the tallies, the two figure cards and the answers, on the other W19
   lists' terms. Every rule names an element this file's markup carries (I19), a child component's box is reached through
   `::deep` from a wrapper written here, and every colour and radius is a --biztech-* variable. */

/* I18: the column spaces its sections; none carries a margin of its own. */
.biztech-ai-audit-body[b-6ukneuhg88] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* A figure card on the quiet card (W19-08). Its bar and the captions
   under it are spaced by the card's own gap. */
.biztech-ai-audit-card[b-6ukneuhg88] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 20px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

/* Two across from md. A grid track sizes each card, so no rule reaches the bar inside. */
.biztech-ai-audit-dimensions[b-6ukneuhg88] {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

@media (min-width: 960px) {
    .biztech-ai-audit-dimensions[b-6ukneuhg88] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The answers: their heading and Clear on one row, then the table and the truncation line. */
.biztech-ai-audit-answers[b-6ukneuhg88] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-ai-audit-answers-head[b-6ukneuhg88] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

/* W19-15 · a date and a verdict each on one line: the narrow columns broke "15 Oct 2026, 07:14" and "Answered with a
   source" over two, and every row grew by a line. */
.biztech-ai-audit-one-line[b-6ukneuhg88] {
    white-space: nowrap;
}
/* /Components/Pages/AssetIntegrity.razor.rz.scp.css */
/* W19-15 · /library/integrity's own look, on W19-11's health report terms: the tallies first, then the two findings as
   tables on UiListCard (§2a C4), which draws the quiet card this sheet used to restate. Tokens only (R3.1); containers carry the gaps (I18); every class is this file's markup or is
   reached with ::deep from a wrapper it writes (I19). */

/* ── the sections ──────────────────────────────────────────────────────────────────────────────────── */
.biztech-integrity[b-g80vi12f7o] {
    display: flex;
    flex-direction: column;
    gap: 32px;
}

/* A heading, its sentence and its table, closer to each other than to the next section (R5.9). */
.biztech-integrity-section[b-g80vi12f7o] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* An id and a storage location are for an operator to look up: the code face, quiet ink, and free to break anywhere so a
   long key wraps inside its cell rather than widening the table. */
/* W19-15 · a key on one line, cut short with an ellipsis and whole in its title (and in the text, for copying), where
   each wrapped over three or four lines and made every row a block of code. */
.biztech-integrity-code[b-g80vi12f7o] {
    display: block;
    max-inline-size: 32rem;
    overflow: hidden;
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* /Components/Pages/AssigneeForm.razor.rz.scp.css */
/* T26's session badge, moved here from wwwroot/css/app.css by T29 N17.

   WHY IT MOVED. R14.1 ranks the four styling layers and says to go one layer down only when the one
   above cannot reach. app.css is layer 4 - the last resort - and it is for host-page chrome outside
   the component tree, markup rendered by a CHILD component, or third-party classes. This badge is
   none of those: it is a <span> in AssigneeForm.razor's own markup, which a component-scoped sheet
   reaches directly. It was in the global file because that is where its neighbours happened to be.

   The rules themselves are unchanged, and the three PortalStyleSheetTests that pin them now read
   this file instead. Same assertions, same values - only the file moved. */

/* Legacy's green SESSION badge, from the 2026-07-30 screenshot of the old form.

   It carries the CASE REFERENCE rather than a session code of its own. The case IS the session
   (design D2), so a second identifier meaning "this same case" would be one meaning too many for
   one thing - rule 5's argument, applied to a label. Nothing the old system showed is lost: the
   reference was already on this page, as body text. This makes it look like the badge it was.

   🔴 W16-16 · finding 5 REPAINTED IT AND LEFT EVERYTHING ELSE. It was the palette's SUCCESS role on its
   composed contrast partner, which made the loudest element on the one page a customer sees a case
   reference - louder than the h1 beside it - and spent a MEANING colour on a neutral identifier. ADR 0026:
   hierarchy by size and weight, never by hue. It is an outlined pill on the document's own ground now.

   PortalStyleSheetTests reads this rule BODY for the old role's name, so the token is named here in the
   file's prose and not inside the braces below. */
.biztech-session-badge[b-rykkqe4yhp] {
    display: inline-flex;
    align-items: center;

    /* T29 N22. Was 0.2rem 0.65rem - 3.2px and 10.4px, neither a multiple of the 4px base unit nor a
       named layout constant, so R5.4 allows it as neither. Rounded to the scale (4px / 12px) rather
       than registered as a constant: a registry of "because it was already this" is the failure mode
       the registry exists to prevent. One pixel taller, two wider. */
    padding: 0.25rem 0.75rem;

    /* The pill, one of the two radii R5.5 allows. */
    border-radius: 999px;

    /* text-primary over background is the pair PaletteContrast already measures and PortalGroundTests
       probes this very element for, so the badge stays legible in both modes without a colour of its own.
       R5.6 fixes a border at 1px. The idle modifier below is untouched and is still distinct: a FILLED grey
       against this outlined one. See the note above this rule for what it replaced and why. */
    background-color: var(--biztech-palette-background);
    color: var(--biztech-palette-text-primary);
    border: 1px solid var(--biztech-palette-outline);

    /* 0.75rem = 12px, the floor for body text. It was 0.72rem (11.52px), which made this badge
       small AND - before T24 gave --mud-palette-success a composed contrast partner - low
       contrast at 2.24:1. Those two defects compound; this fixes the half CSS owns. */
    font-size: 0.75rem;
    font-weight: 600;

    /* letter-spacing: 0.03em went with W16-16's finding 5: it was there to open up an all-caps literal
       ("SESSION:") that no longer exists, and tracking applied to ordinary sentence case just makes a small
       label harder to read. */

    /* nowrap so a reference never breaks mid-token; the header flex-wraps instead, which drops the
       badge onto its own line on a narrow screen rather than splitting it. */
    white-space: nowrap;
}

/* Left the session. Grey rather than green, because a live badge over a form that is no longer
   sharing is the one state this bar must not be able to show.

   T24 moved this off --mud-palette-text-disabled, which was the wrong token twice over. It is the
   colour of an INACTIVE CONTROL - WCAG 1.4.3 exempts those from contrast, and MudBlazor spends it in
   thirty places that are all disabled affordances - so it is deliberately dim, and it put this badge
   at 2.65:1 light and 1.24:1 dark. This badge is not a disabled control; it is a label reporting a
   real state, and text-secondary is the token that means "supporting copy, still legible": 7.86:1
   light, 8.50:1 dark. */
.biztech-session-badge-idle[b-rykkqe4yhp] {
    background-color: var(--biztech-palette-text-secondary);
    color: var(--biztech-palette-surface);
}

/* W3-17 · F6.21. The externally hosted form's frame. Full width, tall enough to hold a real form without
   the visitor scrolling a tiny box, and a 1px outline so it reads as a distinct surface (R5.6 fixes a
   border at 1px). The colour is the palette's, so it follows dark mode; the height is a 4px-scale multiple
   (40rem = 640px). No radius: the frame is content, not a control. */
.biztech-external-form[b-rykkqe4yhp] {
    width: 100%;
    min-height: 40rem;
    border: 1px solid var(--biztech-palette-outline);
}

/* 🔴 W16-16 · finding 3. A section is a <fieldset> so its <legend> can join the section's name to every
   control inside it - six labels on the client's form are duplicated across Customer and Spouse, and
   nothing associated either copy with its own section. The note at the call site in AssigneeForm.razor
   carries the reasoning; this rule removes the chrome the user agent draws for free.

   min-inline-size is the one that is NOT cosmetic. A fieldset's initial value is min-content rather than
   the 0 every other block gets, so a section whose widest field is a long label would refuse to shrink and
   put a phone into sideways scroll (R13.3, R13.7) - the defect AssigneeFormViewportTests exists to catch. */
.biztech-form-section[b-rykkqe4yhp] {
    border: 0;
    margin: 0;
    padding: 0;
    min-inline-size: 0;
}

/* A legend is not an ordinary block: the user agent takes it out of the fieldset's flow and shrink-wraps
   it, so the heading row inside would stop spanning the panel and a fold's toggle would stop sitting at
   the row's end. Declaring the display and the width puts it back where the row was drawn before the
   fieldset existed. */
.biztech-form-section-legend[b-rykkqe4yhp] {
    display: block;
    inline-size: 100%;
    padding: 0;
}

/* 🔴 W19 · THE PAGE LAYS ITSELF OUT, BECAUSE IT DECLARES FULL BLEED.

   One column at the layout's old 46rem measure while there is no session; with one, the work and a
   22rem rail for the conversation, side by side at md and up, the rail sticky so the chat stays in
   reach down a long form. Below md the rail follows the main column. The main column keeps block flow:
   its alerts and papers carry their own bottom margins, and a gap here would add to them (I18). */
.biztech-assignee[b-rykkqe4yhp] {
    box-sizing: border-box;
    display: grid;
    gap: 16px;
    align-items: start;
    inline-size: 100%;
    max-inline-size: 46rem;
    margin-inline: auto;
}

@media (min-width: 960px) {
    .biztech-assignee[data-rail="true"][b-rykkqe4yhp] {
        grid-template-columns: minmax(0, 1fr) 22rem;
        max-inline-size: 76rem;
    }

    .biztech-assignee__rail[b-rykkqe4yhp] {
        position: sticky;
        top: 16px;
    }
}

.biztech-assignee__main[b-rykkqe4yhp],
.biztech-assignee__rail[b-rykkqe4yhp] {
    min-inline-size: 0;
}

/* The header card: the title over the case's name, the reference at the far end, and a foot with who
   the link was sent to and the way to the case's history. The console's card - the quiet edge and
   corners twice the theme's radius - as every other card on this page now is. */
.biztech-assignee__head[b-rykkqe4yhp] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px 16px;
    padding: 24px;
    background: var(--biztech-palette-surface);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-assignee__title[b-rykkqe4yhp] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-assignee__meta[b-rykkqe4yhp] {
    flex: 1 0 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-block-start: 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* Every paper on the page - the form, the signatures, the pad, the chat - takes the same card. */
.biztech-assignee[b-rykkqe4yhp]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* 🔴 W19 · A SECTION STARTS WITH A RULE, as the operator's session form does: the name over a quiet
   line, so a long form reads as sections rather than as one run of fields with some labels in bold. */
.biztech-form-section-legend[b-rykkqe4yhp] {
    padding-block-end: 8px;
    margin-block-end: 12px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

/* The case history, opened in place under its link: a quiet panel on the page's own ground. */
.biztech-assignee__history[b-rykkqe4yhp] {
    margin-block-start: 12px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}
/* /Components/Pages/AssistantSettingsPage.razor.rz.scp.css */
/* W18-06. The settings screen: its groups down the page, spaced by the container (I18). W19-18 · the page's full width,
   as every other console page has it - it was one 48rem column with the right half of the page empty. */
.biztech-assistant-settings[b-wzfpnn3tcc] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19-18 · THE FACTS IN ONE CARD. Who may use each assistant and the daily limit are read-only and belong together, so they
   share one card in three columns, ruled between - where three separate cards side by side stretched the one-sentence
   daily limit to the height of the longest. The papers inside lose their own card: the wrapper is the card. */
.biztech-assistant-settings-access[b-wzfpnn3tcc] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    box-sizing: border-box;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-assistant-settings-access[b-wzfpnn3tcc]  .biztech-paper {
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}

.biztech-assistant-settings-access[b-wzfpnn3tcc]  .biztech-paper + .biztech-paper {
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W19-18 · THE SETTINGS AS ROWS, the settings-page pattern (UiSettingsRow since W19-20): one full-width card per group, its
   heading and intro in the left third and its controls in the right two thirds. Every row is the page's width, so cards differ only in height - the grid
   of two and three a row left ragged gaps between cards of very different heights. */
.biztech-assistant-settings-forms[b-wzfpnn3tcc] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19-20 · each group in this column is a UiSettingsRow, which holds the grid this sheet used to declare. */

.biztech-assistant-settings-stack[b-wzfpnn3tcc] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W28-14. A limit field and the hint under it: a column of their own, 4px apart (I18). */
.biztech-assistant-settings-limit-field[b-wzfpnn3tcc] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-assistant-settings-avatar[b-wzfpnn3tcc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
}

.biztech-assistant-settings-avatar-image[b-wzfpnn3tcc] {
    inline-size: 48px;
    block-size: 48px;
    border-radius: var(--biztech-radius-pill);
    object-fit: cover;
}

.biztech-assistant-settings-roles[b-wzfpnn3tcc] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* The browser's own 16px list margin sat on top of the stack's 16px gap - 32px above the list in the walk. */
    margin: 0;
    padding-inline-start: 24px;
}

/* W19 · a panel's heading, its lead and its settings, spaced by the panel's own gap rather than a margin under
   each heading and lead (I18). */
.biztech-assistant-settings-panel[b-wzfpnn3tcc] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19 · the panels - the template editor's among them - take the tables' quiet edge and corners (W19-08).
   UiPaper is a child component, reached through ::deep from this page's own column (I19). */
.biztech-assistant-settings[b-wzfpnn3tcc]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/Board.razor.rz.scp.css */
/* The summary at the filter bar's end: the count over the caption, right-aligned against the bar's edge. */
.biztech-board-summary[b-zleyofv5hx] {
    text-align: end;
}
/* /Components/Pages/BroadcastHost.razor.rz.scp.css */
/* W6-21 · F8.15. The broadcast host console.

   TOKENS ONLY — R3.1's sweep in PortalStyleSheetTests reads every *.razor.css in this project and refuses
   a hex or rgb() literal. Spacing is whole multiples of the 4px base unit, spelled as pixels, which is
   what R5.4 accepts and what StaticPage.razor.css and ChannelPage.razor.css beside it both do.

   🔴 NO prefers-color-scheme — invariant I16. Both modes come from the tokens the layout swaps.

   🔴 NO `margin: 0` RESET ON ANY <p> RULE. <p> is already in BizTechCssVariables' document reset, and
   restating it in a scoped sheet would beat every biztech-mb-* a caller passes — (0,2,0) against (0,1,0),
   silently. UtilitySpecificityTests named exactly that on ChannelPage's first draft.

   Every element here is declared in the razor file, so every rule is scoped; the one ::deep reaches UiPaper's own
   box from a wrapper this page writes. */

/* 🔴 THE REFUSAL IS BODY TEXT, NOT AN ERROR. A host who arrived twenty minutes early has done nothing
   wrong, and F8.27's complaint is precisely that the current window treats them as if they had. The
   sentence names the times and the leeway; the styling should not shout. §2a C5 · it is a UiEmptyState now, inside
   the console's card.

   §2a C9 · the card: UiPaper, on the console's quiet edge and corners twice the theme's radius, reached through ::deep
   from the wrapper this page writes (I19). Its contents are one column spaced by its gap (I18). */
.biztech-broadcast-card[b-ld94va5j1x]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-broadcast-console[b-ld94va5j1x] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
}

/* A failure's two sentences, spaced by their container's gap (I18) rather than a margin on each. */
.biztech-broadcast-failure[b-ld94va5j1x] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-broadcast-note[b-ld94va5j1x] {
    color: var(--biztech-palette-text-secondary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body1-size);
    font-weight: var(--biztech-font-body1-weight);
    line-height: var(--biztech-font-body1-line-height);
}

/* What the room is doing, and what went wrong. Both read as statements of fact — the severity a failure
   carries comes from UiAlert around it, not from this rule, so a stream state and a failure line are set
   identically and only their container differs. */
.biztech-broadcast-state[b-ld94va5j1x] {
    color: var(--biztech-palette-text-primary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
}
/* /Components/Pages/CaseHistory.razor.rz.scp.css */
/* W19 · the case history a customer reads from their link: a way back, a status line, and the events
   as a timeline. Every colour is a palette role, so a tenant's palette and both modes reach it. */

/* The way back sits above the heading, pulled to the panel's leading edge by its own text-button
   inset so the arrow lines up with the heading under it. */
.biztech-history__back[b-ntruqg8c1t] {
    margin-block-end: 8px;
    margin-inline-start: -8px;
}
/* /Components/Pages/CaseSelfStart.razor.rz.scp.css */
/*
    W25-02 · the start page's own spacing (I18): its heading, its sentence and its one button are spaced by the column's
    gap, never a margin per child. 16px, the gap between a page's blocks. Logical properties, no colour.
*/

.biztech-self-start[b-xodjnm5lf9] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The failure's alert and its Retry, spaced the same way. */
[data-self-start-error][b-xodjnm5lf9] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}

/* W19-17 · W19's quiet card - the theme's box edge, twice its radius, the surface - for the offer and for the refusal. */
.biztech-self-start-card[b-xodjnm5lf9] {
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

.biztech-self-start-offer[b-xodjnm5lf9] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
}

.biztech-self-start-lead[b-xodjnm5lf9] {
    display: flex;
    align-items: center;
    gap: 16px;
}

.biztech-self-start-glyph[b-xodjnm5lf9] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

/* Start as the card's foot, under a rule. */
.biztech-self-start-foot[b-xodjnm5lf9] {
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/CaseTypeBlueprintEditor.razor.rz.scp.css */
/*
    W19-03 · the case type editor's own look.

    Every colour is a --biztech-* role and every length a multiple of the 4px base unit (R5.1).
*/

/* ── the scope row ───────────────────────────────────────────────────────────────────────────────

   The sentence saying which documents this type owns, and the Builder/JSON switch at its trailing end.
   A second segmented track stacked under the tab strip read as a second level of tabs; on the row of
   the sentence it reads as a control over the content below. Wraps on a phone rather than squeezing
   the sentence. */
.biztech-case-type-editor-scope[b-2squq9tjcw] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    margin-block-end: 16px;
}

/* ── the Details tab ─────────────────────────────────────────────────────────────────────────────

   Three across on UiGrid (Md="4"), the create panel's identity row. It was one 640px column, which left
   the paper's right two thirds empty; the grid owns the layout now, so the section carries no class. */

/* A field and the sentence under it are one object: 4px, what .biztech-field puts between a label and
   its box. A copy of CaseTypePanel's .biztech-case-type-field, which I19 keeps out of reach here - two
   surfaces, so not yet a pattern (R8.2). */
.biztech-case-type-details-field[b-2squq9tjcw] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* ── the action row ──────────────────────────────────────────────────────────────────────────────

   The create panel's: a hairline over the row, so Save is not one more item under the last field.
   `outline-subtle`, because it divides related things inside one screen rather than bounding
   something a reader depends on seeing. The second copy of CaseTypePanel's .biztech-case-type-actions,
   for the reason the field rule above gives. */
.biztech-case-type-editor-actions[b-2squq9tjcw] {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-block-start: 16px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The panel takes the case list's card edge and corners (Inquiries.razor.css), so the case type screens and the lists
   they open from read as one set. It was UiPaper's full Outline edge, visibly heavier than the list's. Reached through
   a wrapper with no box of its own, because UiPaper is a component and this scope does not reach its element without
   ::deep. Fields inside keep their own Outline edge: that is the boundary a reader needs to see. */
.biztech-case-type-editor[b-2squq9tjcw] {
    display: contents;
}

.biztech-case-type-editor[b-2squq9tjcw]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/CaseTypeFormEditor.razor.rz.scp.css */
/* R14.1 layer 3 — the control bar is this page's own markup, and since the builder went back to one
   column it is the only thing here.

   Geometry and one ground. No type scale and no ink: UiButton and UiText carry theirs.

   🔴 NOTHING HERE REACHES A CHILD COMPONENT (I19, R14.1b). Blazor stamps the scope attribute on this file's
   own elements and on the LAST compound of every selector, so a rule aimed at a UiButton's root would
   compile to a selector matching nothing — silently, because the class really is in the markup. Every rule
   below names a div this file writes.

   Every length is a multiple of the 4px base unit (R5.1, R5.4), every colour is a semantic role read through
   --biztech-* (R3.1, R7.4), the radius is read from the variable (R5.5), and the breakpoint is MudBlazor's
   `md` (R13.1). */

.biztech-form-bar[b-0di162kgyl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;

    /* Spacing between siblings belongs to the container (I18), and the bar is a container of three groups. */
    margin-block-end: 16px;
    padding-block: 8px;
}

/* 🔴 THE TWO GROUPS ARE .biztech-segmented TRACKS NOW, from app.css, and their captions are gone. Each
   was a bordered segment around a grey label, a rule and its buttons, with the open one filled; the
   Delivery tab's Builder/JSON switch is the same control, and it answers "which is open" with a tinted
   pressed segment rather than a word beside it. */

/* The bar's leading side says what the open view is; everything that switches or writes sits at the
   trailing end, the Delivery tab's placement for its Builder/JSON switch. `min-width: 0` so a long
   sentence wraps rather than pushing the controls off a narrow screen. */
.biztech-form-bar-intro[b-0di162kgyl] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* `margin-inline-start: auto` rather than `justify-content: space-between` on the bar: R5.9 forbids
   pushing a label/value pair apart across a wide container, and the caption beside Save is one, so the
   gap goes BEFORE the group and not inside it. */
.biztech-form-bar-actions[b-0di162kgyl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    min-width: 0;

    margin-inline-start: auto;
}

/* Save ends the bar. It wears no segment: a bordered box around the one filled button on the page would
   be a second frame around something that already stands out (R3.6). */
.biztech-form-bar-save[b-0di162kgyl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

@media (min-width: 960px) {
    /* 🔴 STICKY, AND IT IS THE ONLY STICKY THING ON THIS SURFACE. Save used to render below the whole field
       list — 24 rows on customer-inquiry — so saving an edit to field 3 meant scrolling past 21 more to
       reach the button.

       It works because `.biztech-main` declares `overflow-x: clip`, which (unlike `hidden`) does NOT make an
       ancestor scroll container, so the document is still the scroller and `top` is measured against the
       viewport. Measured on the running stack: documentElement scrollHeight 1962 against clientHeight 791,
       with .biztech-main computing overflow-y: visible.

       Above `md` only. Below it the drawer is an overlay, the bar wraps to three rows, and a bar pinned to
       the top of a 375px screen is a bar eating the content it belongs to — R13.3's "every desktop-only rule
       must be reversed there", met by never declaring it. */
    .biztech-form-bar[b-0di162kgyl] {
        position: sticky;
        top: var(--biztech-content-block-start, 0px);
        z-index: var(--biztech-layer-sticky);

        /* Opaque, so rows pass BEHIND the bar rather than through it. The paper's surface, because the bar
           sits inside the editor's paper now - the page's ground here was a grey band across a white panel. */
        background: var(--biztech-palette-surface);

        /* 🔴 NO RULE UNDER IT. A full-width line in the page's strongest outline ran under the bar at
           rest, where nothing is behind it - dividing the bar from the content it controls. The ground
           is opaque, so rows scrolling under it still pass behind rather than through. */
    }
}

/* The panel takes the case list's card edge and corners (Inquiries.razor.css), so the case type screens and the lists
   they open from read as one set. It was UiPaper's full Outline edge, visibly heavier than the list's. Reached through
   a wrapper with no box of its own, because UiPaper is a component and this scope does not reach its element without
   ::deep. Fields inside keep their own Outline edge: that is the boundary a reader needs to see. */
.biztech-case-type-editor[b-0di162kgyl] {
    display: contents;
}

.biztech-case-type-editor[b-0di162kgyl]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/CaseTypes.razor.rz.scp.css */
/* §2a C4 · the table's card is UiListCard's, so this sheet does not restate its edge, corners or ground.

   A variant under its category: indented, with a quiet rule at its start, so a category and its variants read as one
   group. */
.biztech-case-type-variant[b-ge4f9hf0om] {
    padding-inline-start: 16px;
    border-inline-start: 2px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/ChannelPage.razor.rz.scp.css */
/* W6-19 · F8.23. The tenant's branded channel page.

   🔴 NO COLOURS OF ITS OWN. Every colour here is a token, so the page takes W0-25's resolved palette
   through AnonymousLayout and nothing else. A hex literal would fail R3.1's sweep in
   PortalStyleSheetTests anyway, but the reason is sharper than the rule: a colour on this page would be
   the channel-level palette the card's third `## Do not` forbids, arriving through a stylesheet instead
   of through a column.

   🔴 NO prefers-color-scheme — invariant I16. Both modes come from the tokens, which the layout swaps.

   Spacing is whole multiples of the 4px base unit, spelled as pixels, which is what R5.4's sweep accepts
   and what StaticPage.razor.css beside it does. There is no --biztech-space-* scale in this project and
   inventing one here would be a second convention.

   Every element below is declared in the razor file, so every rule is scoped and none needs ::deep —
   unlike StaticPage, whose body arrives as a MarkupString. */

.biztech-channel-title[b-9biwncrvn8] {
    margin: 0 0 16px 0;
    color: var(--biztech-palette-text-primary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-h5-size);
    font-weight: var(--biztech-font-h5-weight);
    line-height: var(--biztech-font-h5-line-height);
}

.biztech-channel-schedule-heading[b-9biwncrvn8] {
    margin: 0 0 8px 0;
    color: var(--biztech-palette-text-primary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-h6-size);
    font-weight: var(--biztech-font-h6-weight);
    line-height: var(--biztech-font-h6-line-height);
}

/* 🔴 A REAL LIST, and the markers are removed while the semantics are not. A screen reader announces how
   many broadcasts there are before reading them, which is the one thing a stack of divs cannot do — R12,
   and the reason this is not styled into a grid of boxes. */
.biztech-channel-schedule[b-9biwncrvn8] {
    margin: 0;
    padding: 0;
    list-style: none;

    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-channel-event[b-9biwncrvn8] {
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

/* 🔴 NO `margin: 0` HERE OR ON THE TWO RULES BELOW, and the absence is load-bearing. <p> is already in
   BizTechCssVariables' document reset; restating the reset in a scoped sheet would beat every
   biztech-mb-* a caller passes, at (0,2,0) against a utility class's (0,1,0), and silently — the class
   stays in the markup and only the rule stops applying. UtilitySpecificityTests is what says so, and it
   named these three rules the first time this file was written. */
.biztech-channel-event-name[b-9biwncrvn8] {
    color: var(--biztech-palette-text-primary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body1-size);
    font-weight: var(--biztech-font-h6-weight);
    line-height: var(--biztech-font-body1-line-height);
}

.biztech-channel-event-when[b-9biwncrvn8],
.biztech-channel-event-about[b-9biwncrvn8] {
    margin-block-start: 4px;
    color: var(--biztech-palette-text-secondary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
}

/* Both empty states — "the schedule is hidden from you" and "there is nothing scheduled" — take one
   appearance, because they are one kind of message. What differs is the sentence, which is the half that
   carries the information. */
.biztech-channel-empty[b-9biwncrvn8] {
    color: var(--biztech-palette-text-secondary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
}

/* 🔴 W6-23 · A SEPARATE CLASS FROM .biztech-channel-empty, AND THAT SEPARATION IS THE POINT.

   The rule above is about the SCHEDULE - "the schedule is hidden from you" and "there is nothing
   scheduled". This one is about the STREAM - before, due-with-nothing-arriving, and after. They read
   alike on purpose (same ink, same size: they are one kind of message) and they are two selectors,
   because they answer two questions and sit in two places on the page.

   The first draft reused the schedule's class and put this paragraph FIRST in the document, which
   quietly changed what `Find("p.biztech-channel-empty")` returned - W6-19's
   A_hidden_schedule_and_an_empty_one_are_different_sentences started reading the stream's sentence.
   Two meanings on one hook is rule 5's shape applied to a selector, and the failure mode is the same:
   the reader that disagrees is the one somebody debugs.

   The margin is this paragraph's own separation from the player or the badge above it. It is a whole
   multiple of the 4px base unit, spelled in pixels, which is what this file already does and what
   R5.4's sweep accepts. */
.biztech-channel-state[b-9biwncrvn8] {
    margin: 0 0 16px 0;
    color: var(--biztech-palette-text-secondary);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
}

/* 🔴 THE CHANNEL IN THE PORTAL'S LOOK, NOW THAT IT SITS IN THE PORTAL'S SHELL. The page uses the portal's full
   measure - a 48rem column left the right third of a wide screen empty - with the on-air state as a status card
   across it and the schedule as a grid of cards under it: two or three across as the width allows, one on a phone.
   Each card stacks its glyph, name, time and description, and keeps its recording state at its foot, so the cards
   of a row line up by their footers. Every colour is a --biztech-* token. */
.biztech-channel[b-9biwncrvn8] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-channel-way-back[b-9biwncrvn8] {
    align-self: flex-start;
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    text-decoration: none;
}

.biztech-channel-way-back:hover[b-9biwncrvn8] {
    text-decoration: underline;
}

.biztech-channel-head[b-9biwncrvn8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

.biztech-channel-head .biztech-channel-title[b-9biwncrvn8] {
    margin-block-end: 0;
    font-size: var(--biztech-font-h4-size);
    font-weight: var(--biztech-font-h4-weight);
    line-height: var(--biztech-font-h4-line-height);
    letter-spacing: var(--biztech-font-h4-letter-spacing);
}

.biztech-channel-status[b-9biwncrvn8] {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px 20px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-channel-status-glyph[b-9biwncrvn8],
.biztech-channel-event-glyph[b-9biwncrvn8] {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    inline-size: 44px;
    block-size: 44px;
    border-radius: calc(var(--biztech-radius-default) * 1.5);
    background: color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

.biztech-channel-status .biztech-channel-state[b-9biwncrvn8] {
    margin-block-end: 0;
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-body1-size);
    line-height: var(--biztech-font-body1-line-height);
}

.biztech-channel-schedule-heading[b-9biwncrvn8] {
    margin-block-start: 8px;
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: 600;
}

.biztech-channel .biztech-channel-schedule[b-9biwncrvn8] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: 16px;
}

.biztech-channel-schedule .biztech-channel-event[b-9biwncrvn8] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 20px;
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-channel-event-body[b-9biwncrvn8] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-channel-event-body .biztech-channel-event-name[b-9biwncrvn8] {
    font-weight: 600;
}

.biztech-channel-event-body .biztech-channel-event-when[b-9biwncrvn8],
.biztech-channel-event-body .biztech-channel-event-about[b-9biwncrvn8] {
    margin-block-start: 0;
}

/* The recording state is the card's footer: pushed to the bottom, the chip at the start and the action at the end. */
.biztech-channel-event-body[b-9biwncrvn8]  .biztech-recording-availability {
    display: flex;
    justify-content: space-between;
    margin-block-start: auto;
    padding-block-start: 12px;
}

/* When a recording is available the chip and the button do not fit one row of a card this narrow, so the button
   takes its own row across the card - the card's action, under the fact that makes it possible. */
.biztech-channel-event-body[b-9biwncrvn8]  .biztech-recording-link {
    flex: 1 1 100%;
    justify-content: center;
}
/* /Components/Pages/ChannelRecording.razor.rz.scp.css */
/* W6-25 · F8.28 · the recording page.

   Three rules, and every one of them is spacing. The player is RecordingPlayer.razor.css's, the
   refusal is UiAlert's, and the delete flow is UiButton's — this file owns the page's own rhythm and
   nothing else.

   🔴 I19: every class below appears in this page's own markup. There is deliberately no rule for
   `.biztech-alert` or for the player's classes: Blazor stamps this page's scope on the last compound,
   so a selector naming a child component's root is inert with no error and no warning. ScopedStyleReachTests
   is the sweep that holds it.

   I18: the spacing between the heading, the player, the refusal and the controls is the CONTAINER's
   gap. No child carries a margin, so nothing adds up.

   ChannelPage.razor.css is the sibling and the values match it deliberately — the two pages are read
   one after the other by the same visitor, and a heading that sat differently on each would read as a
   different site. */

/* 🔴 THE TWO RULES THAT STOOD HERE WERE `margin: 0` RESETS ON THE HEADING AND ON THE ALERT'S
   PARAGRAPHS, AND UtilitySpecificityTests WAS RIGHT TO REFUSE THEM.

   Blazor rewrites a scoped selector as `.x[b-xxxxxxxxxx]`, which is (0,2,0) against a utility class's
   (0,1,0) - so a reset here beats every spacing utility a page might pass, silently, because the
   utility class is still present in the markup. (The rule's message spells those utilities with a
   star, which must NOT be copied into a comment: the star-slash pair closes it early, and the first
   draft of this paragraph did exactly that - PortalStyleSheetTests read an unbalanced comment and
   ScopedStyleReachTests read the fragment left behind as a universal selector.) It names three ways
   out, and
   this file took the third: `h1` and `p` are ALREADY in BizTechCssVariables' document reset, so both
   rules were restatements of something the platform does once for every page.

   The classes went with them rather than being kept empty - UtilityClassTests refuses a biztech- class
   no stylesheet declares, and the elements are found by their data- hooks, which is what the tests
   select on anyway. */

.biztech-recording-back[b-z3uwgmhtlg] {
    /* W19-18 · the way back sits above the title, so it is as far from "Delete this recording permanently" as the page
       allows - §9's destructive pattern asks for separation, and the column's gap spaces it. */
    display: flex;
}

/* The recording page in the portal's look: the theme's page width, as the channel page takes, ChannelPage.razor.css's
   title size, the player's corners following the cards', and the way back as a plain primary link rather than the
   browser's own blue. It was held to 48rem, narrower than every other portal page. */
.biztech-recording[b-z3uwgmhtlg] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-recording-title[b-z3uwgmhtlg] {
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-h4-size);
    font-weight: var(--biztech-font-h4-weight);
    line-height: var(--biztech-font-h4-line-height);
    letter-spacing: var(--biztech-font-h4-letter-spacing);
}

.biztech-recording-back-link[b-z3uwgmhtlg] {
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    text-decoration: none;
}

.biztech-recording-back-link:hover[b-z3uwgmhtlg] {
    text-decoration: underline;
}

/* The page is a column, so its buttons would stretch to the column's width; a button is as wide as its words. */
.biztech-recording[b-z3uwgmhtlg]  .biztech-button {
    align-self: flex-start;
}

/* The same 44px floor for this page's own buttons - delete, confirm and keep - which the anonymous shell used to
   supply (BroadcastPlayer.razor.css carries the reason). */
@media (pointer: coarse) {
    .biztech-recording[b-z3uwgmhtlg]  .biztech-button.biztech-button-small,
    .biztech-recording[b-z3uwgmhtlg]  .biztech-button.biztech-button-medium {
        min-block-size: 44px;
    }
}
/* /Components/Pages/ComplianceDashboard.razor.rz.scp.css */
/* W19-15 · /compliance's own look: one column of the period, the tallies, the three dimensions and the drill-down, on the
   other W19 lists' terms. Every rule names an element this file's markup carries (I19), a child component's box is reached
   through `::deep` from a wrapper written here, and every colour and radius is a --biztech-* variable. */

/* I18: the column spaces its sections; none carries a margin of its own. */
.biztech-compliance-body[b-hng5wxlyao] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* A dimension on the quiet card (W19-08). */
.biztech-compliance-card[b-hng5wxlyao] {
    padding: 20px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
}

/* Three across from md, one under another below it. A grid track sizes each card, so no rule reaches the bar inside. */
.biztech-compliance-dimensions[b-hng5wxlyao] {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

@media (min-width: 960px) {
    .biztech-compliance-dimensions[b-hng5wxlyao] {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* The drill-down: its heading and Clear on one row, then the caption, the table and the truncation line, spaced by the column. */
.biztech-compliance-drill[b-hng5wxlyao] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-compliance-drill-head[b-hng5wxlyao] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
/* /Components/Pages/ComplianceEvidence.razor.rz.scp.css */
/* W19-15 · /compliance/evidence's own look: one column of the period, the export and its receipt, each panel on the quiet card
   (W19-08). Every rule names an element this file's markup carries (I19); every colour and radius is a --biztech-* variable. */

/* I18: the column spaces its sections; none carries a margin of its own. */
.biztech-evidence-body[b-c99dadjhdi] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* A panel is this page's own section, so the edge is written on it directly - nothing reaches into a child component. Its
   heading, sentences, alerts and lists are spaced by its gap. */
.biztech-evidence-card[b-c99dadjhdi] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* The cases a pack left out and the records that did not re-verify: lists, because how many there are is information, spaced
   from the alert above by the card's gap - so the browser's block margin goes and the indent stays (UtilitySpecificityTests). */
.biztech-evidence-list[b-c99dadjhdi] {
    margin: 0;
}

/* The digest, compared character by character with sha256sum's output: it wraps at 375px rather than pushing the page wide. */
.biztech-evidence-digest[b-c99dadjhdi] {
    overflow-wrap: anywhere;
}
/* /Components/Pages/CuratedAnswerEditor.razor.rz.scp.css */
/* W18-08 · D24. The curator's editor. Every space between siblings is the container's gap (I18); every rule names markup
   this file writes, or reaches a child component's box through ::deep from one (I19). Tokens only (R3.1). */

/* The note and the panel, or the panel alone, spaced by one gap. */
.biztech-curated-editor[b-en3lq5g14z] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-inline-size: 48rem;
}

/* W19 · the panel takes the tables' quiet edge and corners (W19-08); UiPaper is reached through ::deep. */
.biztech-curated-editor[b-en3lq5g14z]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-curated-editor-stack[b-en3lq5g14z] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-curated-editor-quotes[b-en3lq5g14z] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-curated-citation[b-en3lq5g14z] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* A citation's document and the control that removes it, on one line. */
.biztech-curated-citation-head[b-en3lq5g14z] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

/* A page number is a few digits; a field the citation's width for it was the widest thing in the box. */
.biztech-curated-page[b-en3lq5g14z] {
    max-inline-size: 12rem;
}

/* W19 · the search row: a 28rem field with its button beside it, aligned to the TOP and the button offset by one label
   line, so a message under the field would move nothing beside it. */
.biztech-curated-search[b-en3lq5g14z] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px 12px;
}

.biztech-curated-search-field[b-en3lq5g14z] {
    flex: 0 1 28rem;
    min-inline-size: 0;
}

.biztech-curated-search-button[b-en3lq5g14z] {
    display: inline-flex;
}

/* The offset only where field and button share a row: wrapped onto its own line on a phone, the button needs none. */
@media (min-width: 600px) {
    .biztech-curated-search-button[b-en3lq5g14z] {
        margin-top: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}

/* W19 · Save, Cancel and the caption: one wrapping row under a rule, so the actions read apart from the fields. */
.biztech-curated-save[b-en3lq5g14z] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-curated-results[b-en3lq5g14z] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The empty block stands where the form would, on the quiet card. */
.biztech-curated-editor-missing[b-en3lq5g14z] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}
/* /Components/Pages/CuratedAnswerList.razor.rz.scp.css */
/* W18-08 · D24. The curator's list. Every space between siblings is the container's gap (I18); every rule names markup
   this file writes, or reaches a child component's box through ::deep from one (I19). Tokens only (R3.1). */

/* The views' track sits above the list, a step off it. */
.biztech-curated-views[b-wekb93lnju] {
    margin-block-end: 16px;
}

/* The question, the answer under it and any stale reasons: one stack in one cell. */
.biztech-curated-answer[b-wekb93lnju] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

/* The answer under its question is a preview: two lines, then an ellipsis - the whole of it is a press away. */
.biztech-curated-answer[b-wekb93lnju]  .biztech-curated-answer-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Why an answer needs re-approval, under the answer in the primary ink - a reason a curator can act on, so it reads louder
   than the answer's preview above it. */
.biztech-curated-reasons[b-wekb93lnju] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-block-start: 4px;
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}

/* Re-approve and the menu, at the row's end so every row's trigger lines up down the column. */
.biztech-curated-actions[b-wekb93lnju] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Pages/DeckCreate.razor.rz.scp.css */
/* W27-05 · G5 · the one-step deck form's two composite cells. The grid spaces the fields (I18); these space a
   control from its own note, and the organisations from each other, by a container gap of their own. */
.biztech-deck-create-file[b-dof4hoiouf] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-deck-create-orgs[b-dof4hoiouf] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* W19-15 · the form on the console's quiet card - the edge, corners twice the theme's radius - through a wrapper this
   page owns, since UiPaper is the seam's (W19-08, I19). The paper keeps its own padding (I17). */
.biztech-deck-create[b-dof4hoiouf]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The fields, the import's stages and the foot, one column spaced by its gap (I18). */
.biztech-deck-create-body[b-dof4hoiouf] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The foot, under a rule: Create deck, Cancel, then what the press does, wrapping under them when narrow. */
.biztech-deck-create-foot[b-dof4hoiouf] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/DeckDeliver.razor.rz.scp.css */
/* W27-05 · G4 · the header's sentence and the deck's picture, one column spaced by its gap (I18). */
.biztech-deck-subtitle[b-ejbvoclsgr] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-15 · the picture is a thumbnail that says which deck this is, not a banner over the form. */
.biztech-deck-subtitle[b-ejbvoclsgr]  .biztech-deck-picture {
    max-inline-size: 12rem;
}

/* W19-15 · the delivery's column: the caption, the delivery panel and, once a delivery has started, the form panel,
   spaced by this gap (I18) rather than a margin on each. */
.biztech-deck-deliver[b-ejbvoclsgr] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Both panels take the console's quiet edge and corners twice the theme's radius, through this page's wrapper (W19-08,
   I19): the panels are shared with the agent's delivery page, which keeps its own look. */
.biztech-deck-deliver[b-ejbvoclsgr]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    padding: 24px;
}

/* The delivery form as the agent's delivery page draws it (W19-17): the case type and its hint as one group, the
   customer's name and email side by side from sm, and Start as the foot under a rule. */
.biztech-deck-deliver[b-ejbvoclsgr]  [data-testid="deck-delivery-type"] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-block-end: 16px;
}

.biztech-deck-deliver[b-ejbvoclsgr]  .biztech-deck-delivery-fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 600px) {
    .biztech-deck-deliver[b-ejbvoclsgr]  .biztech-deck-delivery-fields {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.biztech-deck-deliver[b-ejbvoclsgr]  [data-testid="deck-delivery-start"] {
    margin-block-start: 24px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/DeckEdit.razor.rz.scp.css */
/* W27-05 · G4 · the header's sentence and the deck's picture, one column spaced by its gap (I18). */
.biztech-deck-subtitle[b-spc3cd3l1k] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-15 · the picture is a thumbnail that says which deck this is, not a banner over the form. */
.biztech-deck-subtitle[b-spc3cd3l1k]  .biztech-deck-picture {
    max-inline-size: 12rem;
}
/* /Components/Pages/DeckLibrary.razor.rz.scp.css */
/* W27-05 · G7 · the console's deck list as cards (ADR 0026). Every gap is a container's (I18); no child carries a
   margin. */

/* The page's column: the tools, the no-match alert and each category, spaced by one gap. */
.biztech-deck-library[b-7nc6tg2j95] {
    display: flex;
    flex-direction: column;
    gap: 32px;
}

/* One category: its heading, the arrange hint, and its cards. */
.biztech-deck-library-group[b-7nc6tg2j95] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A wrapping grid sized by the track, the library tiles' rule: the number of columns is the viewport's answer,
   and a phone at 375px gets one full-width column. */
.biztech-deck-grid[b-7nc6tg2j95] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 16px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-deck-cell[b-7nc6tg2j95] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
}

/* The card being dragged reads as lifted out of the grid. */
.biztech-deck-dragging[b-7nc6tg2j95] {
    opacity: .5;
}

/* W19-15 · the deck card here is the agent's presentations' card (W19-17): every card the row's height, the name in the
   text's ink, an empty cover a pale tone of the primary, and the arrange buttons in a foot under a rule. DeckCard is
   shared, so its look is set by each page that draws it. */
.biztech-deck-cell[b-7nc6tg2j95]  .biztech-deck-card {
    flex: 1 1 auto;
    box-shadow: var(--biztech-shadow-card);
}

.biztech-deck-cell[b-7nc6tg2j95]  .biztech-deck-card-picture {
    background-color: color-mix(in srgb, var(--biztech-palette-primary) 8%, var(--biztech-palette-surface));
}

.biztech-deck-cell[b-7nc6tg2j95]  .biztech-deck-card-body {
    flex: 1 1 auto;
    gap: 8px;
    padding: 16px 16px 12px;
}

.biztech-deck-cell[b-7nc6tg2j95]  .biztech-deck-card-name {
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
    text-decoration: none;
}

.biztech-deck-cell[b-7nc6tg2j95]  .biztech-deck-card-name:hover {
    color: var(--biztech-palette-primary);
    text-decoration: underline;
}

.biztech-deck-cell[b-7nc6tg2j95]  .biztech-deck-card-actions {
    padding: 8px 12px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The order buttons at the foot's end, so Deliver keeps the start. */
.biztech-deck-library-order[b-7nc6tg2j95] {
    display: flex;
    gap: 4px;
    margin-inline-start: auto;
}
/* /Components/Pages/DeckViewer.razor.rz.scp.css */
/* W19-15 · the deck page's own geometry, on the other W19 screens' terms. Every selector names an element this file's
   markup carries (I19); a child component's box is reached through `::deep` from a wrapper written here. Every colour
   and radius is a --biztech-* variable.

   W0-75 deleted this file when its one rule outlived its markup; these rules each name markup DeckViewer.razor
   writes, which is what ScopedStyleReachTests asks. */

/* The page: the slide and its controls in the main column, the authoring panels in a side column, and who may use the
   deck across both, below. One column below lg, the slide first. Every gap is the grid's (I18). */
.biztech-deck-page[b-q9ypwshodj] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

@media (min-width: 1280px) {
    .biztech-deck-page[b-q9ypwshodj] {
        grid-template-columns: minmax(0, 1fr) 22rem;
    }

    .biztech-deck-entitlement[b-q9ypwshodj]  .biztech-deck-entitlement-body {
        grid-column: 1 / -1;
    }
}

/* The slide, then arranging and managing it, spaced by one gap. */
.biztech-deck-main[b-q9ypwshodj] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The arranger and the slide manager take the quiet edge, as the side column's panels do. */
.biztech-deck-main[b-q9ypwshodj]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The authoring region: its caption and up to six panels, one column spaced by its own gap. For a reader who may change
   nothing the region is an empty box; it then costs the column one gap. */
.biztech-deck-authoring[b-q9ypwshodj] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The entitlement panel draws nothing for a reader who may not grant; the wrapper then draws no box either, so the
   column spends no gap on it. */
.biztech-deck-entitlement[b-q9ypwshodj] {
    display: contents;
}

/* Every panel on the page takes the console's quiet edge and corners twice the theme's radius (W19-08). The panels keep
   their own padding (I17). */
.biztech-deck-authoring[b-q9ypwshodj]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The slide's frame takes the same edge here. DeckReadingArea also draws the customer's and the live session's decks,
   which keep the frame they have, so the rule is this page's rather than the component's. */
.biztech-deck-reading[b-q9ypwshodj]  .biztech-deck-reading-area {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/EducationArrange.razor.rz.scp.css */
/* W7-05 · the arrange page. I18: spacing between siblings belongs to the container - a gap, never a
   margin per child. The one rule names a class this component's own markup carries (I19). On the 4px
   grid, as KnowledgeMetrics beside it writes it. */

.biztech-education-arrange[b-6n6k574sxt] {
    display: grid;
    gap: 16px;
    min-width: 0;
}

/* W19-18 · every kind's table at the same column widths: a fixed layout, the box and the moves at their own widths and the
   name taking the rest. At desktop width only - below md the table reflows into one card per row (R13.3). */
@media (min-width: 960px) {
    .biztech-education-arrange-table[b-6n6k574sxt]  .biztech-table {
        table-layout: fixed;
    }

    .biztech-education-arrange-table[b-6n6k574sxt]  .biztech-education-arrange-select {
        inline-size: 6rem;
    }

    .biztech-education-arrange-table[b-6n6k574sxt]  .biztech-education-arrange-order {
        inline-size: 9rem;
    }
}

/* The box's "Select <name>" is its accessible name and is clipped on screen: the name is the next column. */
.biztech-education-arrange-table[b-6n6k574sxt]  .biztech-education-arrange-select .biztech-choice-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
/* /Components/Pages/EducationHub.razor.rz.scp.css */
/* W7-06 · the filter row, and nothing else.

   The cards are EducationItemFrame's and the grid is UiGrid's. A card style here would regress four
   merged cards - the card's own Do-not: "do not add a bespoke card component where W0-52's set has one."

   🔴 R5.8's 44px UNDER A COARSE POINTER, and the card asks for it on THIS page even though R5.8 exempts
   the operator console "by decision (mouse at a desk)". The card's ## Done when overrides that exemption
   in terms: "44px targets under a coarse pointer". Keyed on the POINTER rather than on the viewport,
   because a touch laptop needs the bigger target and a narrow desktop window does not - which is
   UiGalleryViewportTests' measured reason for setting IsMobile rather than a width. */

/* W19-18 · the row itself is app.css's filter bar inside UiToolbar's card (the library's and the case list's), where it
   was a grid of two equal tracks here. What stays is the 44px rule below. */

/* 🔴 ::deep, AND WITHOUT IT THIS BLOCK MATCHES NOTHING AT ALL. Blazor's CSS isolation stamps THIS
   component's scope attribute on the elements in THIS file's markup, and rewrites a selector by appending
   that attribute to its LAST element - so `.biztech-education-filters input` compiles to
   `... input[b-thisfile]`. The <input> and <select> are rendered by UiTextField and UiSelect, so they
   carry THEIR scope and never this one, and the rule is dead.

   Found by EducationHubViewportTests measuring 32px where R5.8 asks for 44 - which is the only thing that
   could have found it. The class is present in the markup so bUnit locates it, and the sheet is
   well-formed so the colour and length sweeps pass. Only a computed style says whether a rule applied.

   EducationItemFrame.razor.css records the same trap for its own title, CasePage.razor.css and
   MainNavMenu.razor.css both record it too - the second one "found on screen rather than in a test". */
@media (pointer: coarse) {
    .biztech-education-filters[b-8zcsfmtfpy]  input,
    .biztech-education-filters[b-8zcsfmtfpy]  select {
        min-height: 44px;
    }
}

/* A group's count: a quiet pill after its name. */
.biztech-education-count[b-8zcsfmtfpy] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 24px;
    block-size: 20px;
    padding-inline: 8px;
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, var(--biztech-palette-surface));
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
}

.biztech-education-group-head[b-8zcsfmtfpy] {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* An empty hub, a hub whose content is all withheld, and a filter that matched nothing: the shared empty block on the
   quiet card, where each was a bordered info alert. */
.biztech-education-state[b-8zcsfmtfpy] {
    border: 1px solid var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}
/* /Components/Pages/ErrorLog.razor.rz.scp.css */
/* W31-02 · /errors - the platform operator's error log. TOKENS ONLY (R3.1). Every rule names an element this file's markup
   carries (I19); a child component is sized from a wrapper written here. Columns are spaced by their container's gap, never
   by a margin per child (I18). */

/* I18: the page's column spaces the live region and the body; the live region's own column spaces an alert from
   the banner. An empty live region is a zero-height item, which costs one gap under the header and nothing else. */
.biztech-errors-page[b-tik5y8dh5e],
.biztech-errors-announcement[b-tik5y8dh5e] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* I18: the column spaces the filter bar and the results. */
.biztech-errors-body[b-tik5y8dh5e] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* A custom period's two days keep their visible labels on the filter bar: two date boxes side by side are told apart
   only by "From" and "To". */
.biztech-errors-date[b-tik5y8dh5e] {
    flex: 0 1 14rem;
    min-inline-size: 0;
}

@media (max-width: 599.98px) {
    .biztech-errors-date[b-tik5y8dh5e] {
        flex-basis: 100%;
    }
}

/* The heading line, the progress bar, the table and its pager. */
.biztech-errors-results[b-tik5y8dh5e] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* D1 · "3 new errors - Show": a line of its own above the list, never rows that move under the reader. */
.biztech-errors-banner[b-tik5y8dh5e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 8px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

/* The short type above its message; the message stays on one line and ends in an ellipsis. */
.biztech-errors-error[b-tik5y8dh5e] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
    max-inline-size: 32rem;
}

.biztech-errors-message[b-tik5y8dh5e] {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--biztech-palette-text-secondary);
}

/* A reference and its copy button, side by side. */
.biztech-errors-reference[b-tik5y8dh5e] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.biztech-errors-code[b-tik5y8dh5e] {
    font-family: var(--biztech-font-mono-family);
}

/* A path, a message type or a full reference can be long: it wraps rather than widening the page (R13.7). */
.biztech-errors-wrap[b-tik5y8dh5e] {
    overflow-wrap: anywhere;
}

.biztech-errors-pager[b-tik5y8dh5e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.biztech-errors-pager-buttons[b-tik5y8dh5e] {
    display: inline-flex;
    gap: 8px;
}

/* The open row: its facts, the rows sharing its reference, and the whole exception. */
.biztech-errors-detail[b-tik5y8dh5e] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-errors-facts[b-tik5y8dh5e] {
    display: grid;
    grid-template-columns: minmax(7rem, max-content) minmax(0, 1fr);
    gap: 4px 16px;
    margin: 0;
}

.biztech-errors-facts dt[b-tik5y8dh5e] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-errors-facts dd[b-tik5y8dh5e] {
    margin: 0;
    min-inline-size: 0;
}

@media (max-width: 599.98px) {
    .biztech-errors-facts[b-tik5y8dh5e] {
        grid-template-columns: minmax(0, 1fr);
    }
}

.biztech-errors-stack[b-tik5y8dh5e] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-errors-stack-head[b-tik5y8dh5e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

/* The whole exception: line breaks kept, scrolled inside itself in both directions, never widening the page. */
.biztech-error-detail[b-tik5y8dh5e] {
    max-block-size: 24rem;
    max-inline-size: 100%;
    overflow: auto;
    margin: 0;
    padding: 12px;
    white-space: pre;
    font-family: var(--biztech-font-mono-family);
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}
/* /Components/Pages/ExportTenant.razor.rz.scp.css */
/* W30-02 · D14 — the Export tenant page. TOKENS ONLY (R3.1).

   The choices' panel and the notes below it are spaced by this page's grid gap, never by a margin per child (I18). The panel's
   padding is its own biztech-pa-4 (I17). */
.biztech-tenant-export[b-t32x0h7umi] {
    display: grid;
    gap: 24px;
}

.biztech-tenant-export-notes[b-t32x0h7umi] {
    display: grid;
    gap: 8px;
}

.biztech-tenant-export-list[b-t32x0h7umi] {
    margin: 0;
    padding-inline-start: 20px;
}
/* /Components/Pages/FormTemplates.razor.rz.scp.css */
/*
    W3-25 · the per-version lists inside a library row.

    🔴 SCOPED RATHER THAN IN app.css, AND THAT IS R14.1's LAYER 4. These <ul>s are rendered by THIS
    component, so a scoped sheet reaches them - unlike a rule aimed at the surrounding <td>, which UiTd
    renders and which UiTable's own header explains a scoped sheet cannot touch.

    Three columns each hold one line per version and the row has to read ACROSS, so every line is the
    same height in all three. line-height rather than a fixed height: a chip and a caption differ in
    intrinsic height, and pinning the box would clip whichever is taller the first time somebody adds a
    longer marker.
*/

.biztech-form-versions[b-nuwbwztfpp] {
    list-style: none;

    /* A REAL declaration rather than `padding: 0`, following the four <ul> resets already in
       UtilitySpecificityTests' Declared set. A scoped selector is (0,2,0) against a utility class's
       (0,1,0), so `padding: 0` here would silently beat every biztech-pa-* a caller passes - which is
       the defect that whole test file exists to catch. Only the block margin needs the exemption. */
    margin: 0;
    padding-inline-start: 0;
}

.biztech-form-versions > li[b-nuwbwztfpp] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 1.75rem;
}

/* W27-04 · I18. The actions cell: the Open link (or its caption), then the Remove list, a gap apart - and the list's own lines
   a gap apart, so a second removable version does not touch the first. */
.biztech-form-actions[b-nuwbwztfpp] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-form-actions > .biztech-form-versions[b-nuwbwztfpp] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* 🔴 W0-63 · `.biztech-form-open` WAS HERE, AND IT REACHED NOTHING. It sat on a Blazor NavLink, which
   renders its own <a> and therefore carries none of this component's scope attribute - so the compiled
   `.biztech-form-open[b-…]` matched no element in the document. It also read `--biztech-primary`, a
   variable nothing declares. Both are answered by the global `.biztech-link` in app.css, which needs no
   ::deep because it is not scoped at all; the reasoning that was here moved with it. */
/* /Components/Pages/GoLive.razor.rz.scp.css */
/* W27-07 · /go-live - the three panels stacked, the page carrying the gaps between them (I18). Tokens only (R3.1). */
.biztech-go-live[b-vp7m2hju1q] {
    display: grid;
    gap: 16px;
}

/* W30-05 · D22 · the switched operator's line pointing a new tenant to the import wizard: the words, then the button. */
.biztech-go-live-import[b-vp7m2hju1q] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Pages/ImportTenant.razor.rz.scp.css */
/* W30-05 · the import wizard's page: the rail, then the body (the live region and the screen), spaced by the container (I18).
   Tokens only (R3.1); every class is this file's markup (I19). */
.biztech-import-wizard[b-e685w2pme3] {
    display: grid;
    /* W30-08 · the rail's ten tabs scroll inside their own viewport; an auto track would size to all of them and push the page wide. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    min-inline-size: 0;
}

.biztech-import-wizard-body[b-e685w2pme3] {
    min-inline-size: 0;
}

/* W30-08 · D14 · an earlier screen after the run has started: the line, then the screen, one gap apart. */
.biztech-import-wizard-screen[b-e685w2pme3] {
    display: grid;
    gap: 16px;
    min-inline-size: 0;
}

/* W30-08 · D14 · the line, then the way into the tenant at its own width. */
.biztech-import-started[b-e685w2pme3] {
    display: grid;
    gap: 16px;
    justify-items: start;
}

/* Walk finding · working in a tenant: the sentence, then the switch back at its own width. */
.biztech-import-inside-tenant[b-e685w2pme3] {
    display: grid;
    gap: 16px;
    justify-items: start;
}
/* /Components/Pages/Inquiries.razor.rz.scp.css */
/*
    W4-26 · the case list's Active/Archived switch.

    🔴 ONE RULE LEFT, AND THAT IS W8-24 RATHER THAN NEGLECT. Everything else in this sheet styled the
    filter toolbar, the chips and the sortable headings, and all of it moved to CaseWorkList.razor.css
    with the markup - I19: a scoped rule reaches its own component's markup and nothing else, so a rule
    left here would have compiled against this page's scope and matched nothing, silently.

    This one stays because its markup did: the switch sits in the tab strip's ViewSwitch slot, which is
    the operator console's and not the shared list's.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit.
*/

.biztech-view-switch[b-l6e5vpr3hw] {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
}

/* 🔴 THE CURRENT SEGMENT IS TINTED, NOT FILLED, AND A PAGE WITH A PRIMARY BUTTON IS WHY.

   It was Filled + Primary, which is the same fill and ink UiButton gives the page's primary ACTION -
   so on /inquiries "Active" and "New case" were the same object to the eye: one is a state, the other
   is the thing to press. The tint and primary ink are what this application already uses for "this one
   is current" on the nav's active item and .biztech-selected's rows.

   12% rather than those two's 8%: they carry a 2px inset bar as well, and a segment inside a bordered
   track has nothing but its own ground to say it is on.

   Keyed on aria-current, which the markup already publishes - UiTab does the same rather than inventing
   a class for a state the DOM carries. */
.biztech-view-switch[b-l6e5vpr3hw]  .biztech-button[aria-current="page"] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);

    /* 🔴 THE BORDER IS WHAT MAKES THIS WORK ON DARK, AND IT WAS ADDED AFTER MEASURING. The tint alone
       carries the state on light, where it reads 1.5:1 against the page; on dark the same 12% of a light
       blue over a near-black ground came to 1.19:1 - invisible, leaving the ink's colour as the only
       signal, which is the "colour alone" WCAG 1.4.1 rules out. The text itself was never at risk
       (5.06:1 on dark), but a state nobody can see is not a state.

       `border-color` only: .biztech-button-text already declares a transparent 1px border, so the
       segment's box does not change size and the track's 2px inset still holds. */
    border-color: var(--biztech-palette-primary);
}

/* W19 · the table's card is UiListCard's (§2a C4), drawn inside CaseWorkList, so this sheet does not restate its edge,
   corners or ground. What stays is this page's own: the theme's Depth on that card and on each phone-width row (W19-07),
   and the filter bar's edge matched to the card's.

   Reached through .biztech-case-list-table, this page's own wrapper around CaseWorkList, and nowhere else: the portal
   launcher composes the same list and styles it its own way. */
.biztech-case-list-table[b-l6e5vpr3hw] {
    display: contents;
}

/* The filter bar over the table takes the card's edge and corners, as the launcher's does, so the two read as one set. */
.biztech-case-list-table[b-l6e5vpr3hw]  .biztech-filters .biztech-toolbar {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

@media (min-width: 960px) {
    /* W19-07 · the table is this page's main panel, so it takes the theme's Depth as the cards beside it do. */
    .biztech-case-list-table[b-l6e5vpr3hw]  .biztech-list-card {
        box-shadow: var(--biztech-shadow-card);
    }
}

@media (max-width: 959.98px) {
    /* W19-07 · on a phone each row is a card of its own. */
    .biztech-case-list-table[b-l6e5vpr3hw]  .biztech-table-row {
        box-shadow: var(--biztech-shadow-card);
    }
}
/* /Components/Pages/KnowledgeCollectionCreate.razor.rz.scp.css */
/* W7-21 · F9.12. The create form's own look.

   🔴 I18. THE GAP BELONGS TO THE CONTAINER. The grid, a refusal and the action row sit on one column with
   one gap, rather than each carrying a margin that would add to the grid's.

   🔴 I19. EVERY SELECTOR ENDS ON MARKUP THIS FILE WRITES, or reaches a child component's box through
   `::deep` from a wrapper written here.

   The measure itself is `biztech-form` in app.css (R9.5), not a width here: this form is one column, so
   the panel's width and the field's width are the same number and capping the panel keeps the promise.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). */

/* W19 · the case list's card edge and corners (W19-08), so the form and the list it opens from read as one
   set. The wrapper has no box of its own; UiPaper is a component, reached through ::deep. */
.biztech-knowledge-create[b-vqv5gtxxcv] {
    display: contents;
}

.biztech-knowledge-create[b-vqv5gtxxcv]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    /* W19-15 · the card ends where the form's measure does, plus its own padding, as Add a resource's does; it ran the
       page's width with the fields stopping two-thirds across. */
    max-inline-size: calc(var(--biztech-form-measure) + 32px);
}

.biztech-knowledge-create-form[b-vqv5gtxxcv] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* The whole address under its field, 4px off it. */
.biztech-knowledge-create-address[b-vqv5gtxxcv] {
    padding-block-start: 4px;
}

/* The address in the primary ink, so the part that changes as the curator types stands out of the caption. */
.biztech-knowledge-create-path[b-vqv5gtxxcv] {
    color: var(--biztech-palette-text-primary);
    font-weight: 500;
}

/* Create, Cancel and the caption: one wrapping row under a rule, so the actions read apart from the fields. */
.biztech-knowledge-create-actions[b-vqv5gtxxcv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/KnowledgeCollections.razor.rz.scp.css */
/* W7-21 · F9.12. The collection list's own look.

   🔴 I18. THE GAP BELONGS TO THE CONTAINER, NEVER TO A CHILD. A margin per child would add to a gap and
   produce spacing nobody can trace to a declaration.

   🔴 I19. EVERY SELECTOR NAMES MARKUP THIS FILE WRITES. A child component's box (the table's rows) is
   reached through `::deep` from a wrapper written here, never by its own class alone.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). Every colour and radius is a --biztech-*
   variable. */

/* A name and what it is under it, one stack in one cell. */
.biztech-knowledge-name[b-sjihmkqkw8] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

/* The collection a hit lives in and its Withdrawn chip, on one line. */
.biztech-knowledge-hit-line[b-sjihmkqkw8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Pages/KnowledgeLibrary.razor.rz.scp.css */
/* W7-23 · D. The reader's two columns - the library and its search on the left, the preview on the right -
   and the search results. The search itself stands on UiFilterBar (§2a C3).

   Lengths are multiples of the 4px base unit (R5.1, R5.4). No colour is set here (R3), and there is no
   prefers-color-scheme (I16).

   🔴 I19. EVERY SELECTOR ENDS ON MARKUP THIS PAGE WRITES. The rail is a <div> this file declares; the pane is
   UiPaper, reached by the class this page hands it through Class rather than by an element selector into
   UiPaper's own markup. KnowledgeLibraryTree and KnowledgeItemPreview style themselves.

   🔴 I18. EVERY GAP IS A CONTAINER'S. No panel carries a margin. */

.biztech-knowledge-reader[b-14yh3wkb4h] {
    display: grid;

    /* One column below md (R13.1's 960px), stacked rather than squeezed: a 22rem rail beside a preview
       leaves the preview almost nothing at phone width. KnowledgeTree makes the same call at the same width. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}

.biztech-knowledge-reader-rail[b-14yh3wkb4h] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-knowledge-reader-pane[b-14yh3wkb4h] {
    min-inline-size: 0;
}

/* R5.8: a hit is a touch target. */
.biztech-knowledge-reader-hit[b-14yh3wkb4h] {
    display: inline-flex;
    align-items: center;
    min-block-size: 24px;
    font-weight: 500;
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
}

/* The whole row is the link's target: its box stretched over the row. */
.biztech-knowledge-reader-hit[b-14yh3wkb4h]::after {
    content: "";
    position: absolute;
    inset: 0;
}

.biztech-knowledge-reader-hit[aria-current="page"][b-14yh3wkb4h] {
    color: var(--biztech-palette-primary);
}

.biztech-knowledge-reader-hits[b-14yh3wkb4h] {
    list-style: none;
    margin: 0;
    padding-inline-start: 0;

    display: flex;
    flex-direction: column;
    gap: 2px;

    overflow-wrap: anywhere;
}

/* Below md, a chosen item's pane comes first: order on grid children this page writes. */
@media (max-width: 959.98px) {
    .biztech-knowledge-reader-chosen .biztech-knowledge-reader-pane[b-14yh3wkb4h] {
        order: -1;
    }
}

@media (min-width: 960px) {
    .biztech-knowledge-reader[b-14yh3wkb4h] {
        /* 22rem: a collection name and a third-level title both fit beside their glyphs. minmax(0, …) on
           both tracks so a long title wraps inside its column rather than widening the page. */
        grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    }
}

/* W18-06 · the chosen item's preview and "Ask about this document", spaced by the column rather than by a margin
   on either (I18, I19). The preview stretches; the button keeps its own width inside its span. */
.biztech-knowledge-reader-stack[b-14yh3wkb4h] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19's quiet card for every panel on this page - the subtle edge and twice the theme's radius - where each was the
   full outline. Reached from this page's own wrapper (I19). */
.biztech-knowledge[b-14yh3wkb4h]  .biztech-paper {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* A search result as a row the tree's shape: a grey glyph, the title in the body's ink and its collection under it, a
   tint on hover - where each was a tinted square and a primary-coloured link, heavier than the tree it replaces. */
.biztech-knowledge-hit-row[b-14yh3wkb4h] {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    min-block-size: 44px;
    padding-inline: 8px;
    border-radius: var(--biztech-radius-default);
}

.biztech-knowledge-hit-row:hover[b-14yh3wkb4h] {
    background-color: color-mix(in srgb, currentcolor 6%, transparent);
}

.biztech-knowledge-hit-glyph[b-14yh3wkb4h] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
}

.biztech-knowledge-hit-words[b-14yh3wkb4h] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
}

/* 20px inside each panel, where the utility's 16px crowded the contents against the edge; the rail is narrow, so not 24. */
.biztech-knowledge[b-14yh3wkb4h]  .biztech-paper {
    padding: 20px;
}

/* W19-23 · the library's panel: the search box at its top, then the results or the tree, one gap apart. */
.biztech-knowledge-reader-panel[b-14yh3wkb4h] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The box takes the rail's width, not the filter bar's 28rem. */
.biztech-knowledge-reader-search[b-14yh3wkb4h] {
    display: flex;
}

.biztech-knowledge-reader-search[b-14yh3wkb4h]  .biztech-filterbar-search {
    flex: 1 1 auto;
}
/* /Components/Pages/KnowledgeMetrics.razor.rz.scp.css */
/* W7-12 · the knowledge metrics page. I18: spacing between siblings belongs to the container - a gap,
   never a margin per child. Every rule here names a class this component's own markup carries (I19), or
   reaches a child component's box through ::deep from one. Values on the 4px grid; every colour and radius
   is a --biztech-* variable. */

.biztech-knowledge-metrics[b-q8xyege73b] {
    display: grid;
    gap: 16px;
}

.biztech-knowledge-metrics__figure[b-q8xyege73b] {
    display: grid;
    gap: 12px;
    min-width: 0;
}

.biztech-knowledge-metrics__heading[b-q8xyege73b] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-knowledge-metrics__list[b-q8xyege73b] {
    display: grid;
    gap: 8px;
    min-width: 0;

    /* The anchor target lands below the app bar rather than under it. */
    scroll-margin-top: 80px;
}

/* /Components/Pages/KnowledgeTree.razor.rz.scp.css */
/* W7-21 · F9.13. The collection page's two columns, and nothing else.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). Colours come from --biztech-* only (R3), and
   there are none here at all: this file places things and sets no colour. No prefers-color-scheme (I16).

   🔴 I19. EVERY SELECTOR ENDS ON MARKUP THIS PAGE WRITES. The grid's children are two <div>s this file
   declares, NOT KnowledgeItemTree, KnowledgeItemPanel or KnowledgeReviewPanel - a rule ending on a child
   component's root element is stamped with that component's scope and is inert, with no error and no
   warning. There is no `> *` here for the same reason: a scoped universal selector cannot be read as
   "the children this file wrote" by anybody looking at the stylesheet, which is what
   ScopedStyleReachTests' second sweep is for.

   🔴 I18. THE GAPS ARE THE CONTAINERS'. Neither column carries a margin, and neither panel does, so the
   space between them is one number in one place and cannot add up with anything. */

.biztech-knowledge-page[b-w0nuosbo5e] {
    display: grid;

    /* One column below md. R13.1 pins the breakpoints to 600/960 so a page never disagrees with its
       grid, and 959.98px is the max-width spelling that rule names. Stacked rather than squeezed,
       because a 20rem rail beside two panels leaves them about 15rem at phone width - LibraryFolders
       makes the same call at the same breakpoint. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;

    /* Each column is as tall as its own contents. Without this the rail's panel stretches to the height
       of the two panels beside it, which draws a mostly empty card down the left of the page. */
    align-items: start;
}

/* The rail's heading and its tree. A gap on the container, not a margin on the heading (I18). */
.biztech-knowledge-rail[b-w0nuosbo5e] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* The two panels, stacked. The curation panel first, because a reader arrives to ORGANISE more often
   than to review - and the review panel is the one that grows, so putting it second keeps the controls
   a curator uses at a stable height. */
.biztech-knowledge-panes[b-w0nuosbo5e] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

@media (min-width: 960px) {
    .biztech-knowledge-page[b-w0nuosbo5e] {
        /* 20rem is 320px: wide enough for a title at the eighth level, where the tree has already spent
           160px on indentation (KnowledgeItemTree.razor.css). minmax(0, …) on both tracks because a grid
           track's default minimum is auto, so a long title would push its column wider than the page
           rather than wrapping inside it. */
        grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    }
}

/* W19 · the rail and both panels take the tables' quiet edge and corners (W19-08), through the page's own
   grid and ::deep, since UiPaper is a child component (I19). The panels keep their own padding (I17). */
.biztech-knowledge-page[b-w0nuosbo5e]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The dense empty block in the rail sits a step below the caption above it. */
.biztech-knowledge-rail-empty[b-w0nuosbo5e] {
    padding-block: 16px;
}
/* /Components/Pages/LibraryFolders.razor.rz.scp.css */
/* W2-22b · F4.2. The folder page's two columns, and nothing else.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). Colours come from --biztech-* only (R3), and
   there are none here at all: this file places two things and sets no colour. No prefers-color-scheme
   (I16).

   🔴 I19. BOTH SELECTORS END ON MARKUP THIS PAGE WRITES. The grid's children are two <div>s this file
   declares, NOT LibraryFolderTree and LibraryFolderManager - a rule ending on a child component's root
   element is stamped with that component's scope and is inert, with no error and no warning. There is no
   `> *` here for the same reason: a scoped universal selector cannot be read as "the children this file
   wrote" by anybody looking at the stylesheet, which is what ScopedStyleReachTests' second sweep is for.

   🔴 I18. THE GAP IS THE GRID'S. Neither column carries a margin, so the space between them is one
   number in one place and cannot add up with anything. */

.biztech-folders[b-uftwanxlic] {
    display: grid;

    /* One column below md. R13.1 pins the breakpoints to 600/960 so a page never disagrees with its
       grid, and 959.98px is the max-width spelling that rule names. Stacked rather than squeezed,
       because a 20rem rail beside a form leaves the form about 15rem at phone width - PermissionTree's
       rail makes the same call at the same breakpoint. */
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;

    /* Each column is as tall as its own contents. Without this the rail's panel stretches to the height
       of the form beside it, which draws a mostly empty card down the left of the page. */
    align-items: start;
}

/* The rail's heading and its tree. A gap on the container, not a margin on the heading (I18). */
.biztech-folders-rail[b-uftwanxlic] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W27-05 · the search field and Collapse all, side by side and wrapping on a narrow rail. */
.biztech-folders-find[b-uftwanxlic] {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 8px;
}

/* W27-05 · the panel and the upload limit below it, one column spaced by its own gap (I18). */
.biztech-folders-pane[b-uftwanxlic] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

@media (min-width: 960px) {
    /* W27-05 · F4.2 · the settings stay in view beside a long tree. Sticky within the grid, 16px under the
       sticky app bar, and never taller than the viewport below it - a pane taller than that would stick with
       its foot off screen, so it scrolls inside itself instead. Below 960px the pane stacks under the tree
       and does not stick. */
    .biztech-folders-pane[b-uftwanxlic] {
        position: sticky;
        inset-block-start: calc(var(--biztech-content-block-start, 0px) + 16px);
        max-block-size: calc(100dvh - var(--biztech-content-block-start, 0px) - 32px);
        overflow-y: auto;
    }

    .biztech-folders[b-uftwanxlic] {
        /* 20rem is 320px: wide enough for a name at the eighth level, where the tree has already spent
           160px on indentation (LibraryFolderTree.razor.css). minmax(0, …) on both tracks because a
           grid track's default minimum is auto, so a long folder name or a long slug would push its
           column wider than the page rather than wrapping inside it. */
        grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    }
}

/* W19-15 · the rail's panel, the folder panel and the upload limit take the tables' quiet edge and corners (W19-08),
   through this page's own wrapper and `::deep` - none of the three is styled for any other page. Each keeps its own
   padding (I17). */
.biztech-folders[b-uftwanxlic]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/Login.razor.rz.scp.css */
/* W19-18 · the sign-in page's own pieces; the panel, fields and button are the layout's and the seam's.
   Every rule names an element this file's markup carries (I19). */

/* The recovery link at the end of the Password label row, in the label's size so the row stays one line. */
.biztech-signin-forgot[b-3zj2fov1p1] {
    font-size: var(--biztech-font-caption-size);
    white-space: nowrap;
}

/* The operator footnote: under a quiet rule, set apart from the form it is not part of. */
.biztech-signin-note[b-3zj2fov1p1] {
    margin-block-start: 24px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/NewTenant.razor.rz.scp.css */
/* W30-08 · D20 — New tenant's three starts. TOKENS ONLY (R3.1).

   🔴 I18. Each start owns its gap: heading, sentence and button stack in a column, and no child carries a margin. The grid owns
   the gaps between the starts. I19: every selector ends on a class this file's own markup writes. Lengths are multiples of the
   4px base unit (R5.1, R5.4). */

.biztech-new-tenant-start[b-2os5k0me37] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    block-size: 100%;
}

/* W19-23 · the card fills its grid cell, so the three starts are one height: the cell is this page's own element, and
   UiPaper's root is reached from it through ::deep (I19). */
.biztech-new-tenant-card-cell[b-2os5k0me37] {
    block-size: 100%;
}

.biztech-new-tenant-card-cell[b-2os5k0me37]  .biztech-paper {
    block-size: 100%;
}

/* §2a C9 · the start's glyph in the primary's tinted square. */
.biztech-new-tenant-mark[b-2os5k0me37] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, var(--biztech-palette-surface));
    color: var(--biztech-palette-primary);
}

/* While the operator is checked: the bar above the skeleton, the gap the container's (I18). */
.biztech-new-tenant-loading[b-2os5k0me37] {
    display: grid;
    gap: 16px;
    min-inline-size: 0;
}

/* The button at the card's foot, whatever the sentence's length. */
.biztech-new-tenant-action[b-2os5k0me37] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-block-start: auto;
}
/* /Components/Pages/OrganisationRecord.razor.rz.scp.css */
/* W23-02 · D21. The organisation record: four panels down the page, each a stack of fields spaced by its container (I18). */
/* W19-18 · the page's full width, as every console page has it - it was one 48rem column with the right half empty. */
.biztech-organisation-record[b-e4dj62wufi] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19-20 · each section is a UiSettingsRow: its heading in the start third, its fields (at most 40rem) in the end two -
   this sheet held a copy of that grid. */

/* The terms, read-only: a label beside each value. */
.biztech-organisation-record-terms[b-e4dj62wufi] {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 8px 24px;
}

/* W23-08 · R9.14. Every field read-only, one row each: a fixed label column so the values line up from row to row,
   and a value that wraps rather than widening the page at 375px. */
.biztech-organisation-record-text[b-e4dj62wufi] {
    grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
    overflow-wrap: anywhere;
}
/* /Components/Pages/OrganisationsDeleted.razor.rz.scp.css */
/* W19-18 · Restore at the row's right edge. The list's card and the empty block are UiListCard's and UiEmptyState's
   (W19-20). Reached through ::deep from this file's own wrapper (I19). */
@media (min-width: 960px) {
    .biztech-organisations-deleted[b-6l0xzru7b0]  .biztech-organisations-deleted-action {
        text-align: end;
    }
}
/* /Components/Pages/OrganisationsImport.razor.rz.scp.css */
/* W23-02 · D22. The import panel: its children spaced by the container, never a margin each (I18). */
.biztech-organisations-import[b-v2l0s1esmq] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19-18 · the columns it reads: a heading, a line and the names, spaced by the container (I18). */
.biztech-organisations-import-columns[b-v2l0s1esmq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-organisations-import-column-list[b-v2l0s1esmq] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.biztech-organisations-import-column-list code[b-v2l0s1esmq] {
    display: inline-block;
    padding: 2px 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}
/* /Components/Pages/People.razor.rz.scp.css */
/*
    W14-04 · F3.1 — /people's own geometry: the pager's row, then the list's look below.

    🔴 I18: THE GAP BELONGS TO THE CONTAINER. Two children sit in this row - the page count, then
    Previous and Next together - and spacing them with a margin per child would add to whatever the flow already
    gives them, which is the "24px down the rows and 16px across the columns" mismatch I18 records.

    🔴 I19: EVERY SELECTOR NAMES THIS COMPONENT'S OWN MARKUP, AND THE STAMPED COMPOUND IS LAST.
    .biztech-people-pager is written in People.razor; the rule reaches nothing inside UiButton, which
    is a child component whose root Blazor stamps with its OWN scope. A rule like
    `.biztech-people-pager > *` would be inert here for exactly that reason, and ScopedStyleReachTests
    sweeps for both shapes.

    The row wraps at narrow widths rather than scrolling: three short controls have nothing to clip,
    and R13.8's scroll region is for the TABLE above, which really can outgrow the viewport.
*/

.biztech-people-pager[b-2atoluroce] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 16px;
}

/* Previous and Next together at the row's end, the case list's pager. */
.biztech-people-pager-controls[b-2atoluroce] {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* W19-20 · the list's card and the empty block's are UiListCard's and UiEmptyState's now; this sheet kept a copy of both. */

/* The registration panels take the tables' quiet edge (W19-08). The panels keep their own padding (I17), and the gap
   between them and under them is this wrapper's (I18) - each panel carried its own bottom margin before. */
.biztech-people-registration[b-2atoluroce] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-block-end: 16px;
}

.biztech-people-registration[b-2atoluroce]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/Person.razor.rz.scp.css */
/* W19 · /people/{id}'s panels take the tables' quiet edge and corners twice the theme's radius (W19-08), so a person's
   tabs read as the same console as the list they open from. The wrapper is box-less and this page's own; each tab's
   UiPaper is reached through ::deep (I19), so no tab component changes for any other page. The panels keep their own
   padding (I17). */
.biztech-person-body[b-i3wqljicgp] {
    display: contents;
}

.biztech-person-body[b-i3wqljicgp]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* A note above the tabs, spaced from them by its own block. */
.biztech-person-note[b-i3wqljicgp] {
    margin-block-end: 12px;
}
/* /Components/Pages/PortalChooser.razor.rz.scp.css */
/* /portals — the list's own look. Every rule names an element this file's own markup carries (I19); a rule for a class only
   a child component renders reaches it through `::deep` from a wrapper this file owns, or not at all. Every colour, radius and
   duration is a --biztech-* variable, so a tenant's palette, radius and motion settings reach it in both modes. */

/* ── the two reports ────────────────────────────────────────────────────────────────────────────────

   A card each, so "Configuration health" and "Compare two portals" are told apart by what they are rather than by where they
   sit. One column until sm (600px): two cards at 375px are two columns of about 170px. */
.biztech-portal-reports[b-uj15aepq5v] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

@media (min-width: 600px) {
    .biztech-portal-reports[b-uj15aepq5v] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The cards take the table's quiet edge and corners (W19-08), so the reports and the list read as one set. */
.biztech-portal-reports[b-uj15aepq5v]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-portal-reports[b-uj15aepq5v]  .biztech-paper:hover {
    border-color: var(--biztech-palette-primary);
}

/* The whole card is the link: the title and its sentence on the left, the chevron on the right. The padding is on the anchor
   rather than the paper, so the full card is the hit area (I17: UiPaper has no padding of its own). */
.biztech-portal-report[b-uj15aepq5v] {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 16px;
    color: inherit;
    text-decoration: none;
    border-radius: inherit;
}

.biztech-portal-report-text[b-uj15aepq5v] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-portal-report[b-uj15aepq5v]  .biztech-portal-report-title {
    color: var(--biztech-palette-primary);
}

.biztech-portal-report:hover[b-uj15aepq5v]  .biztech-portal-report-title {
    text-decoration: underline;
}

/* The "go" mark: a round, tinted square, the portal launcher's vocabulary (W19-04). */
.biztech-portal-report-go[b-uj15aepq5v] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, transparent);
    color: var(--biztech-palette-primary);
}

/* The anchor is not .biztech-link, so it carries app.css's ring here. Inset, because the card's edge is right at its border. */
.biztech-portal-report:focus-visible[b-uj15aepq5v] {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: -2px;
}

/* ── the Live / Removed switch ─────────────────────────────────────────────────────────────────────
   The track is app.css's .biztech-segmented. The count beside each word is secondary ink, so the word is what is read and the
   number what is glanced at. */
.biztech-portal-views[b-uj15aepq5v] {
    display: flex;
    justify-content: flex-end;
    margin-block-end: 12px;
}

.biztech-portal-view-count[b-uj15aepq5v] {
    margin-inline-start: 8px;
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

/* The audience and its default chip on one line, spaced by the container (I18). */
.biztech-portal-audience[b-uj15aepq5v] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The menu, pushed to the row's end so every row's trigger lines up down the column. */
.biztech-portal-row-actions[b-uj15aepq5v] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Pages/PortalCompare.razor.rz.scp.css */
/*
    W8-03 · F10.17 — the drift report.

    🔴 W19-11 · IT HAD ONE RULE - THE TWO CHOOSERS - AND HAS A LOOK OF ITS OWN NOW: the pair on a card, three counts in Venn
    order that are the view switch, and the open group's table on the console's card. Spacing, colour and radius are still
    the tokens' (R7.x); nothing here restates a value the theme holds.

    R13.8 · nothing here declares a width, a height or a position on anything outside this component's own markup, so the
    main landmark keeps its width and nothing under #biztech-main clips. R13.1's breakpoints, mobile-first.
*/

/* 🔴 W0-75 · A GRID, AND IT WAS A FLEX ROW WHOSE CHILD RULE HAD NEVER APPLIED. "Equal halves rather
   than content-sized, so the pair does not jump as the names change length" was declared as
   `.biztech-compare-choosers > *` - and Blazor stamps the scope attribute on a selector's LAST compound,
   which here is the universal one. The children are UiSelect's roots, rendered by a child component, so
   `> *[b-xxxxxxxxxx]` matched nothing and the two choosers were content-sized after all: exactly the
   jump the comment says it prevents, at every width from 600px up.

   The fix is a grid rather than `::deep`, because equal tracks need no rule on a child at all - nothing
   has to reach an element this page does not own. PortalComposerCopyPanel.razor.css is the same pair of
   controls with the same defect and the same fix, and PortalComposerTilePanel.razor.css records what the
   shape cost the composer. `ScopedStyleReachTests` refuses a universal last compound now.

   minmax(0, 1fr) rather than 1fr: R13.8's grid trap, and a portal's name is exactly the long content
   that sets a track's minimum. */
/* W19-11 · the page's own column: the pair, the sentence, the three counts and the open group, spaced by the container (I18). */
.biztech-compare[b-btdfpbo2cu] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The pair's card takes the console's quiet edge and corners - the lists' own - through a wrapper this page owns (I19). */
.biztech-compare-card[b-btdfpbo2cu]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* One column below sm, then the two choosers with Swap between them, on the line their controls sit on. */
.biztech-compare-choosers[b-btdfpbo2cu] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

@media (min-width: 600px) {
    .biztech-compare-choosers[b-btdfpbo2cu] {
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
        align-items: end;
    }
}

.biztech-compare-swap[b-btdfpbo2cu] {
    display: flex;
    justify-content: center;
}

/* ── the three counts ─────────────────────────────────────────────────────────────────────────────────
   Venn order - only on the first, on both, only on the second - as many across as fit, three at desktop. */
.biztech-compare-groups[b-btdfpbo2cu] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
    gap: 16px;
}

/* W19-23 · a card that is a link, in the seam's stat tile's shape: what it counts with its side's dot, the figure, and a
   line under it - where a 4px bar along its top said which side it was. The quiet card of §2a C9. */
.biztech-compare-group[b-btdfpbo2cu] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out,
        background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-compare-group--left[b-btdfpbo2cu] {
    --biztech-compare-side: var(--biztech-palette-primary);
}

.biztech-compare-group--both[b-btdfpbo2cu] {
    --biztech-compare-side: var(--biztech-palette-success);
}

.biztech-compare-group--right[b-btdfpbo2cu] {
    --biztech-compare-side: var(--biztech-palette-secondary);
}

.biztech-compare-group:hover[b-btdfpbo2cu] {
    border-color: var(--biztech-palette-outline);
}

/* The open group: tinted, and its edge in the primary colour - the segmented track's own answer for "this one". */
.biztech-compare-group[aria-current="page"][b-btdfpbo2cu] {
    border-color: var(--biztech-palette-primary);
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, var(--biztech-palette-surface));
}

.biztech-compare-group:focus-visible[b-btdfpbo2cu] {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 2px;
}

.biztech-compare-group-head[b-btdfpbo2cu] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-compare-group-label[b-btdfpbo2cu] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 500;
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The side's colour as a small dot at the label's end; the label names the side, so the colour is never the only signal. */
.biztech-compare-group-side[b-btdfpbo2cu] {
    flex: none;
    inline-size: 8px;
    block-size: 8px;
    border-radius: 999px;
    background: var(--biztech-compare-side, var(--biztech-palette-outline-subtle));
}

.biztech-compare-group-figure[b-btdfpbo2cu] {
    font-size: var(--biztech-font-h4-size);
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.biztech-compare-group-detail[b-btdfpbo2cu] {
    overflow: hidden;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── the open group ─────────────────────────────────────────────────────────────────────────────────── */

/* An item can be a long address; it breaks anywhere rather than widening the table past its column. */
.biztech-compare-item[b-btdfpbo2cu] {
    overflow-wrap: anywhere;
}

/* A group with nothing in it keeps its card but quiets its figure, so the eye goes where the items are. */
.biztech-compare-group--none .biztech-compare-group-figure[b-btdfpbo2cu] {
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Pages/PortalComposer.razor.rz.scp.css */
/* 🔴 W1b-06 · F2.24 · the composer's two panes, and why the split is a grid rather than a float.

   NO overflow-x ANYWHERE IN THIS FILE (the outline pane's overflow-y below is a scroller, and hides nothing sideways). The card's ## Do not: "Do not use overflow-x: hidden to make a
   preview measurement pass, and do not weaken an existing viewport assertion to accommodate the
   composer's chrome." R13.8 states the general form - it hides the symptom and the diagnostic together -
   and here it would hide the one defect the preview exists to reveal. */

/* 🔴 W0-75 · ONE COLUMN, AND THIS FILE USED TO DESCRIBE TWO.

   The composer was `minmax(0, 1fr) minmax(0, 1fr)` above md: the arrangement on the left, a sticky
   preview pane on the right holding a 1440px iframe and three control groups. Read on a 1440px screen
   that gave the arrangement about 660px - so every tile panel's four-field geometry row wrapped - and
   scaled the preview down until the thing being previewed was the smallest element on the page.
   PortalPreview.razor is where the preview went, and its header carries the reasoning; what is left here
   is a page whose whole width arranges.

   The grid stays a grid rather than becoming nothing, because the track is what holds the trap below.

   minmax(0, 1fr) rather than 1fr, and this is the grid trap R13.8 exists around: a grid track's default
   minimum is `auto`, which is the CONTENT's minimum - so one wide child inside a `1fr` track would push
   the track past the page and the page sideways, at every viewport. */
/* 🔴 W20-06 · TWO PANES: AN OUTLINE BESIDE ONE ITEM'S EDITOR, AND THIS FILE DESCRIBED ONE COLUMN UNTIL NOW.

   20rem beside the editor at md and up - KnowledgeTree's rail and its measurement: about 824px of 1440 for the
   editor, which holds one item rather than the whole arrangement W0-75 measured at 660. One column below md, where
   the outline folds into a disclosure above the editor. minmax(0, …) on both tracks for the trap below.
   Borders, not shadows, for panes in flow (the design direction). */
/* W19-11 · the grid hidden under the page-wide preview: display beats the hidden attribute's own rule otherwise. */
.biztech-composer[hidden][b-3ww06owyyn] {
    display: none;
}

.biztech-composer[b-3ww06owyyn] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

@media (min-width: 960px) {
    .biztech-composer[b-3ww06owyyn] {
        grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
    }
}

/* W19-11 · wider on a laptop and up: at 20rem a tile's title wrapped at its third word beside an editor whose fields
   rarely use the width they have. */
@media (min-width: 1280px) {
    .biztech-composer[b-3ww06owyyn] {
        grid-template-columns: minmax(0, 24rem) minmax(0, 1fr);
    }
}

.biztech-composer-outline-pane[b-3ww06owyyn] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    padding: 12px 8px;
    min-inline-size: 0;
}

/* W19-11 · the outline was as tall as the portal - 19 tiles ran it to 2000px - so the editor sat at the top of a long
   page and the outline's lower half was a scroll away from it. Beside the editor it now stays in view and scrolls
   its own list, under the app bar; below md it is the folded disclosure above the editor, and in flow. */
@media (min-width: 960px) {
    .biztech-composer-outline-pane[b-3ww06owyyn] {
        position: sticky;
        inset-block-start: calc(var(--biztech-content-block-start, 0px) + 16px);
        max-block-size: calc(100dvh - var(--biztech-content-block-start, 0px) - 32px);
        overflow-y: auto;
        overscroll-behavior: contain;
        scrollbar-width: thin;
    }
}

/* The outline's scrollbar, drawn while it is being scrolled and not otherwise - the navigation rail's rule
   (MainLayout.razor.css). The colour changes, not the width, so nothing reflows when it appears. Both rules are gated
   on data-scroll-reveal, which biztech-rail.js sets when it attaches, so a pane it never reached keeps an ordinary bar. */
.biztech-composer-outline-pane[data-scroll-reveal][b-3ww06owyyn] {
    scrollbar-color: transparent transparent;
}

.biztech-composer-outline-pane[data-scroll-reveal][data-scrolling][b-3ww06owyyn] {
    scrollbar-color: var(--biztech-palette-outline) transparent;
}

.biztech-composer-editor-pane[b-3ww06owyyn] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The body under the header: the change list, the promise, and the panes - one gap carrier (I18). */
.biztech-composer-body[b-3ww06owyyn] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The level chip beside the h1: a word, not only a colour (R12.7). A tinted pill, the chip vocabulary of the lists. */
.biztech-composer-level[b-3ww06owyyn] {
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, transparent);
    color: var(--biztech-palette-primary);
    white-space: nowrap;
}

/* W19-11 · the review of changes in the editor's space: a heading row with the way back, then the list. The editor
   beside it is hidden with `hidden`, which the display below would outrank, so each puts it back. */
.biztech-composer-review[b-3ww06owyyn],
.biztech-composer-editor-views[b-3ww06owyyn] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-composer-review[hidden][b-3ww06owyyn],
.biztech-composer-editor-views[hidden][b-3ww06owyyn] {
    display: none;
}

.biztech-composer-review-head[b-3ww06owyyn] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
}

/* The page's standing rule, under the header: a quiet line with a lock, not a paragraph of body text. */
.biztech-composer-promise[b-3ww06owyyn] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* 🔴 I19 · every rule above names this page's own markup. The outline, the editor's groups and the preview each
   carry their own sheet beside their markup; ScopedStyleReachTests is the guard that keeps a rule from drifting
   into the wrong file. What follows is one rule that says ::deep and means it. */

/* 🔴 R5.8's 44px UNDER A COARSE POINTER, and PortalTilePageBody.razor.css records what it cost to find: a
   bare <a> is an inline element and CSS 2.1 §10.7 says min-height does not apply to one, so the
   declaration resolved and governed nothing - measured at 17px. The fix is the display, not the minimum.
   The composer is a dense surface of small controls, which is where a coarse pointer suffers most. */
@media (pointer: coarse) {
    .biztech-composer[b-3ww06owyyn]  button,
    .biztech-composer[b-3ww06owyyn]  a {
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }
}


/* W19-11 · the page-wide preview: the frame's own controls and its scroll region, at the content's full width. */
.biztech-composer-preview-page[b-3ww06owyyn] {
    min-inline-size: 0;
}
/* /Components/Pages/PortalCreate.razor.rz.scp.css */
/* /portals/new — the create form's own look. */

/* The case list's card edge and corners (W19-08), so the form and the list it opens from read as one set. Reached through a
   wrapper with no box of its own, because UiPaper is a component and this scope does not reach its element without ::deep. */
.biztech-portal-create[b-njisz9b23i] {
    display: contents;
}

.biztech-portal-create[b-njisz9b23i]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* Two named groups, a refusal and the action row, spaced by the container rather than a margin per child (I18). 24px is
   6 x 4 on the base unit (R5.1). */
.biztech-portal-create-form[b-njisz9b23i] {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* Each group spaces its heading, grid and caption by a gap rather than a margin per child (I18). The heading's own 12px
   margin (.biztech-section-title, app.css) is zeroed here so the gap is the only space. */
.biztech-portal-create-section[b-njisz9b23i] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-portal-create-section[b-njisz9b23i]  .biztech-section-title {
    margin-block-end: 0;
}

/* A hairline between the groups — CaseTypePanel's answer for the same shape. */
.biztech-portal-create-section + .biztech-portal-create-section[b-njisz9b23i] {
    padding-block-start: 24px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The address preview under its field, 4px off it - the distance the checkbox's own Hint keeps from its box. */
.biztech-portal-create-address-hint[b-njisz9b23i] {
    padding-block-start: 4px;
}

/* The address in the primary ink, so the part that changes as the reader types stands out of the caption around it. One font
   family (R4.2), so weight and ink rather than a monospace face. */
.biztech-portal-create-address[b-njisz9b23i] {
    color: var(--biztech-palette-text-primary);
    font-weight: 500;
}

/* A checkbox beside a labelled field starts one label too high (I20): offset it by the label block it lacks, calculated from
   the tokens that make that label, at md where the two share a row. */
@media (min-width: 960px) {
    .biztech-portal-create-choice[b-njisz9b23i] {
        margin-block-start: calc(
            var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}

/* Create, Cancel and the caption: one wrapping row under a rule, so the actions read apart from the fields. */
.biztech-portal-create-actions[b-njisz9b23i] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/PortalExport.razor.rz.scp.css */
/* W20-07 · the export page: one panel per source, the links in a wrapping row. Tokens only (R3.1); I18 · containers
   carry the gaps, so no child sets a margin to space itself. */

.biztech-portal-export[b-r6p595nvi3] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-inline-size: var(--biztech-form-measure);
}

/* One column per panel: the heading, the sentence and the links, spaced by the container rather than each other. */
.biztech-portal-export-panel[b-r6p595nvi3] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-portal-export-links[b-r6p595nvi3] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* W22-07 · D30 · the not-included checklist, at the body size the captions use. I18 · the panel's gap spaces it, so no margin. */
.biztech-portal-export-checklist[b-r6p595nvi3] {
    margin: 0;
    padding-inline-start: 1.25rem;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-portal-export-caption[b-r6p595nvi3] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Pages/PortalHealth.razor.rz.scp.css */
/* W19-11 · /portals/health - the report's own look: the view switch, the verdict filter, the sweep's progress
   line and the rule's disclosure. Tokens only (R3.1); containers carry the gaps (I18); every class is this file's markup (I19). */

/* ── the view switch and the filter ─────────────────────────────────────────────────────────────────── */
/* The last check's status line on the left, the switch on the right; on a phone the line wraps above the switch. */
.biztech-health-views[b-s1klg2vg3v] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-block-end: 16px;
}

/* Empty until a check has run, and still a flex item then, so the switch keeps the row's end. */
.biztech-health-status[b-s1klg2vg3v] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-health-status-dot[b-s1klg2vg3v] {
    flex: none;
    inline-size: 8px;
    block-size: 8px;
    border-radius: 999px;
    background: var(--biztech-palette-success);
}

.biztech-health-status-dot--bad[b-s1klg2vg3v] {
    background: var(--biztech-palette-error);
}

.biztech-health-view-count[b-s1klg2vg3v] {
    margin-inline-start: 8px;
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

/* The verdict filter: the segmented track, wrapping on a phone rather than overflowing it. */
.biztech-health-filter[b-s1klg2vg3v] {
    display: inline-flex;
    flex-wrap: wrap;
    margin-block-end: 12px;
}

/* ── the sweep's progress line, and what it found ──────────────────────────────────────────────────── */
.biztech-health-announcement[b-s1klg2vg3v] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-block-end: 16px;
}

.biztech-health-announcement:empty[b-s1klg2vg3v] {
    display: none;
}

/* What a sweep costs, at the top of the menu's panel, above the portals to choose from (R9.2). */
.biztech-health-check-note[b-s1klg2vg3v] {
    max-inline-size: 18rem;
    padding: 8px 12px;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}

/* ── how a link is judged ─────────────────────────────────────────────────────────────────────────── */
.biztech-health-rule[b-s1klg2vg3v] {
    margin-block-end: 16px;
}

.biztech-health-rule > summary[b-s1klg2vg3v] {
    cursor: pointer;
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: 500;
}

.biztech-health-rule[open] > summary[b-s1klg2vg3v] {
    margin-block-end: 8px;
}
/* /Components/Pages/PortalImport.razor.rz.scp.css */
/* W20-07 · the import page: the file, the report, the address, the one submit. Tokens only (R3.1); I18.

   W19-11 · three numbered steps, each on a card with the console's quiet edge and corners twice the theme's radius - the
   lists' and the new portal page's own edge, so the import reads as one of the portal screens rather than a bare form. */

/* The steps hold a field, a short report and a button, so a card the screen's width was mostly empty surface. 64rem is the
   form measure plus room for three report tiles across; on a narrower screen the cards take what there is. */
.biztech-portal-import[b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-inline-size: 64rem;
}

.biztech-portal-import[b-853e1dvn4k]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The live region is always there (R12.6a); empty, it takes no gap slot, and its own children carry its gap. Selected
   by its attribute, because PortalPageShellTests' positional check reads a bare <div aria-live="polite">. */
.biztech-portal-import > [aria-live][b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-portal-import > [aria-live]:empty[b-853e1dvn4k] {
    display: none;
}

/* ── a step ──────────────────────────────────────────────────────────────────────────────────────────
   Its head, then its controls, spaced by the step's own gap. The controls of steps 1 and 3 keep the form measure (R5): a file
   field or an address 1,400px wide says nothing more than one 60rem wide. */
.biztech-portal-import-step[b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-portal-import-measure[b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-inline-size: var(--biztech-form-measure);
}

.biztech-portal-import-step-head[b-853e1dvn4k] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.biztech-portal-import-step-title[b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

/* The step's number in the tinted circle the portal launcher's glyphs use (W19-04); filled once the step is done. */
.biztech-portal-import-step-number[b-853e1dvn4k] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 28px;
    block-size: 28px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-portal-import-step-number--done[b-853e1dvn4k] {
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
}

/* W22-07 · D32 · the paste box and its Read, stacked; the editor's own box is UiCodeEditor's (I19). Stretched, not flex-start:
   an empty editor has no content width, so flex-start shrank it to a sliver. Read's own wrapper is a block, so the button keeps
   its own width. */
.biztech-portal-import-paste[b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The address and the whole address it will answer, a step apart. */
.biztech-portal-import-slug[b-853e1dvn4k] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-portal-import-address[b-853e1dvn4k] {
    color: var(--biztech-palette-text-primary);
    font-weight: 500;
}

.biztech-portal-import-notes[b-853e1dvn4k] {
    margin: 0;
    padding-inline-start: 1.25rem;
}

.biztech-portal-import-actions[b-853e1dvn4k] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}
/* /Components/Pages/Processes.razor.rz.scp.css */
/* The drawing's panel takes the case list's card edge and corners (Inquiries.razor.css), so this page and the case
   type list it opens from read as one set. It was UiPaper's full Outline edge, visibly heavier than the list's.
   Reached through a wrapper with no box of its own, because UiPaper is a component and this page's scope does not
   reach its element without ::deep. The map's own nodes keep their Outline edge: those are shapes a reader needs to
   see. */
.biztech-process-drawing[b-jed7psqyi5] {
    display: contents;
}

.biztech-process-drawing[b-jed7psqyi5]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Pages/QuizTake.razor.rz.scp.css */
/* W19-18 · the quiz sheet. Every rule names an element this file's own markup carries (I19); the prompt is a legend
   UiRadioGroup or this file's fieldset renders, reached through `::deep` from the sheet's wrapper.

   A question's prompt is what the reader answers, so it reads in the page's ink at the subtitle size, where it was the
   caption-sized secondary grey app.css gives a field label. */
.biztech-quiz-sheet[b-kid6fj3fif]  .biztech-choice-group-legend {
    padding-block-end: 4px;
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    line-height: var(--biztech-font-subtitle1-line-height);
    color: var(--biztech-palette-text-primary);
}
/* /Components/Pages/ResourceCreate.razor.rz.scp.css */
/* W2-20 · `/library/new`. One rule, and it is the one the grid cannot supply.

   The file cell holds two things rather than one: the picker, and the platform's sentence about whether
   what you attach is scanned. The sentence is not a second field — it is this control's footnote — so it
   must sit closer to the picker than the picker sits to its neighbours. The grid's 16px gap spaces
   FIELDS; 4px spaces a control from its own note, and that is `.biztech-field`'s own row gap, read as
   the same scale step rather than as a number chosen here.

   🔴 THE CLASS IS ON A <div> THIS PAGE WRITES, NOT ON THE <UiGridItem> AROUND IT, AND I19 IS WHY.
   Blazor stamps its scope attribute only on elements the component renders itself, so the same rule
   aimed at a class passed through `<UiGridItem Class="...">` would compile to
   `.biztech-resource-file[b-xxxxxxxxxx]` against a div carrying no such attribute: no error, no warning,
   and markup that reads exactly as though it asked for a gap. `ScopedStyleReachTests` sweeps for the
   shape; this file records why the extra element is not redundant.

   No padding, no colour and no border: the cell is a layout container and everything visible in it
   belongs to the seam. */
.biztech-resource-file[b-l1yuh4egsy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* W27-05 · the upload's polite status region and the form, one column spaced by its gap (I18). */
.biztech-resource-create[b-l1yuh4egsy] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* W19-15 · the form's card takes the console's quiet edge and corners twice the theme's radius (W19-08), where it drew
   the paper's full-strength outline. */
.biztech-resource-create[b-l1yuh4egsy]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* W27-05 · the single file's bar and its percentage, spaced by the container's gap (DeckImportStages' rule). */
.biztech-resource-progress[b-l1yuh4egsy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* W19-15 · the form's actions in a foot under a rule, with the caption saying what the press does below them - the
   shape every W19 form's foot has. The rule is the quiet edge; the gaps are the foot's (I18). */
.biztech-resource-foot[b-l1yuh4egsy] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-block-start: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/ResourceLibrary.razor.rz.scp.css */
/* W19-15 · /library's own geometry: one column under the header, spaced by its gap (I18). The control bar, the failed
   alert, the publish panel and the listing each carried a margin of their own - or none - so the space between them
   was whatever each child happened to say. Both selectors name elements ResourceLibrary.razor writes (I19); what sits
   inside them is spaced by the gap whichever component rendered it. */
.biztech-library-body[b-8bmuk20gha] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

/* The share panel, the listing and its pager, one column on the same gap. */
.biztech-library-listing[b-8bmuk20gha] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}
/* /Components/Pages/RoleEditor.razor.rz.scp.css */
/* W14-03 · /roles/{id}. Specimen 14's save bar and specimen 16's copy chooser.

   🔴 I19. EVERY SELECTOR NAMES A CLASS THIS FILE'S OWN MARKUP WRITES. No `> *`; a child component's box is
   reached only through `::deep` from a wrapper this file writes, and named by that child's own class - a
   scoped rule ending in another component's element is stamped on markup this file did not write and is
   silently inert.

   W19 · the page takes the other W19 screens' look: the quiet edge (outline-subtle) at twice the theme's
   radius on every panel, the shared empty block, and every colour and radius a --biztech-* variable. */

/* ── the panels ──────────────────────────────────────────────────────────────────────────────────── */

/* The tree's panel takes the tables' quiet edge (W19-08). It keeps its own padding (I17). */
.biztech-role-tree[b-ry1nsok1gq]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* An empty role is the shared block on the same card, standing above the tree. */
.biztech-role-empty[b-ry1nsok1gq] {
    margin-block-end: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* The heading and its sentence, spaced by the container (I18). */
.biztech-role-empty-words[b-ry1nsok1gq] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

/* W27-02 · the reach notes, the revoke refusal and the timing sentence above the tree, one under the other with the gap
   here rather than a margin on each (I18), and the tree's distance below as .biztech-role-copy keeps it. */
.biztech-role-notes[b-ry1nsok1gq] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    margin-block-end: 16px;
}

/* ── Copy from an existing role ─────────────────────────────────────────────────────────────────────
   The trigger, a warning when it would replace unsaved changes, and the sources, one under the other with the gap here
   rather than a margin on each (I18). Inside the empty block they centre with it; above the tree they start at the
   leading edge. */
.biztech-role-copy[b-ry1nsok1gq] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    margin-block-end: 16px;
}

.biztech-role-empty .biztech-role-copy[b-ry1nsok1gq] {
    align-items: center;
    margin-block-end: 0;
}

/* The sources are a framed list of rows on the quiet card, a hairline between them. */
.biztech-copy-sources[b-ry1nsok1gq] {
    display: flex;
    flex-direction: column;
    inline-size: min(100%, 28rem);
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    overflow: hidden;
}

.biztech-copy-sources li + li[b-ry1nsok1gq] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* Each row is the seam's text button stretched across the list, and its label - the seam's own span around the two
   below - spread so the name sits at the start and the count at the end. */
.biztech-copy-sources[b-ry1nsok1gq]  .biztech-copy-source {
    inline-size: 100%;
    border-radius: 0;
    text-align: start;
}

.biztech-copy-sources[b-ry1nsok1gq]  .biztech-copy-source .biztech-button-label {
    display: flex;
    flex: 1 1 auto;
    justify-content: space-between;
    min-inline-size: 0;
}

.biztech-copy-source-name[b-ry1nsok1gq] {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.biztech-copy-source-count[b-ry1nsok1gq] {
    flex: none;
    margin-inline-start: 16px;
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

/* ── what a Save will write ─────────────────────────────────────────────────────────────────────────
   On the count's own line while a difference stands, so arriving work moves nothing: the count in the page's ink at
   weight, the given/withdrawn split in the secondary ink. Save and Discard are the header's actions. */
/* The arriving part's figures are tabular, so the line does not shift width as a count ticks over; it reads in the page's ink
   against the secondary ink of the count before it, and the separator between them stays secondary. */
.biztech-savebar[b-ry1nsok1gq] {
    font-variant-numeric: tabular-nums;
}

.biztech-savebar-sep[b-ry1nsok1gq] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-savebar-count[b-ry1nsok1gq] {
    color: var(--biztech-palette-text-primary);
}

.biztech-savebar-total[b-ry1nsok1gq] {
    font-weight: 600;
}

.biztech-savebar-split[b-ry1nsok1gq] {
    color: var(--biztech-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

/* The read-only note, spaced from the tree by its own block. */
.biztech-role-note[b-ry1nsok1gq] {
    margin-block-end: 16px;
}
/* /Components/Pages/Roles.razor.rz.scp.css */
/* W19 · /roles' own look, on the other W19 lists' terms. Every rule names an element this file's own markup carries (I19); a
   child component's box is reached through `::deep` from a wrapper written here. Every colour and radius is a --biztech-*
   variable, so a tenant's palette and radius reach it in both modes. */

/* W19-20 · the list's card and the empty block's are UiListCard's and UiEmptyState's now; this sheet kept a copy of both. */

/* ── New role ──────────────────────────────────────────────────────────────────────────────────────
   The panel takes the tables' quiet edge (W19-08) and keeps its own padding (I17). */
.biztech-roles-create[b-63pl9wwbsg] {
    margin-block-end: 16px;
}

.biztech-roles-create[b-63pl9wwbsg]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The heading, the row and the note, spaced by the container (I18). */
.biztech-roles-create-body[b-63pl9wwbsg] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The name and its two actions on one line above sm, the actions under the field below it. The field is a column rather
   than the panel's width: a role name is a few words. */
.biztech-roles-create-row[b-63pl9wwbsg] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px 16px;
}

.biztech-roles-create-field[b-63pl9wwbsg] {
    flex: 1 1 18rem;
    max-inline-size: 28rem;
    min-inline-size: 0;
}

/* The buttons line up with the field's control, not its label: offset by the label block the field has and the buttons do
   not, read from the tokens that make it (I20's arithmetic - body2's size times its line height, plus the field's 4px gap). */
.biztech-roles-create-actions[b-63pl9wwbsg] {
    display: flex;
    align-items: center;
    gap: 8px;
}

@media (min-width: 600px) {
    .biztech-roles-create-actions[b-63pl9wwbsg] {
        margin-block-start: calc(var(--biztech-font-body2-size) * var(--biztech-font-body2-line-height) + 4px);
    }
}
/* /Components/Pages/SearchIndex.razor.rz.scp.css */
/* W17-05 · found driving the page at 375px: PageHeader's shared [data-page-actions] row is `nowrap`,
   and this page's three action labels (38 characters combined) overflowed it by 24px, clipping
   "Rebuild all" — the first console header long enough to hit that limit (Inquiries' New case/Refresh/
   Export is 21). [data-page-actions] is Components/Layout/PageHeader.razor's own markup, outside this
   card's projects:, so the fix stays on this page's own wrapper rather than widening the shared row.

   A flex item's default min-width is its content's width (`auto`), which is exactly what stopped the
   wrapper below from shrinking — `min-width: 0` is what lets PageHeader's nowrap parent shrink this
   one flex item to the space actually available, and `biztech-flex-wrap` (declared already, in
   app.css) is what then lets ITS OWN three buttons reflow onto a second line inside that shrunk box.
   No @media query: this also protects the row between `sm` and `md`, where the drawer is present and
   the same three labels are just as long. */
.biztech-search-index-actions[b-kdir7535ks] {
    min-width: 0;
}

/* The one note that stands where the table would when no index is kept apart from the database. */
.biztech-search-index-note[b-kdir7535ks] {
    margin-block-end: 16px;
}
/* /Components/Pages/SearchVectors.razor.rz.scp.css */
/* W18-09 · the store panel: AgentQaHistory's figure grid, a fact per outlined cell - a fact inside the page's
   surface, not a surface of its own. auto-fit, so 375px is one column and 1440px one row, with no @media. */
.biztech-vector-facts[b-cfrhw9zu0g] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 16px;
    margin: 0;
}

/* W19 · a tile in the quiet edge and corners on the page's surface, as W19-11's health tallies are, so the store's
   facts read as the console's other figure rows do. */
.biztech-vector-fact[b-cfrhw9zu0g] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    padding: 12px 16px;
}

.biztech-vector-fact dd[b-cfrhw9zu0g] {
    margin: 0;
}

/* A collection name is one long token (passages_openai_text-embedding-3-large_3072). R4.7 prefers wrapping to
   truncation, and a token has no break opportunity of its own - so it may break anywhere rather than push the
   page wider than the phone it is on. On a <dd> and a <div> the page writes itself, and inherited from there:
   handed to UiText as Class, the scoped rule never reached it (found by the W18-09 UI invariant review). */
.biztech-vector-name[b-cfrhw9zu0g] {
    overflow-wrap: anywhere;
}

/* The two breakdown tables side by side where there is room, stacked where there is not. */
.biztech-vector-breakdown[b-cfrhw9zu0g] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 16px;
}

/* W19 · a composer note above the tables, spaced like the alerts beside it. */
.biztech-vector-note[b-cfrhw9zu0g] {
    margin-block-end: 16px;
}
/* /Components/Pages/SessionLeft.razor.rz.scp.css */
/* W19 · the left-the-session message: a centred column with the console's empty-state rhythm. 48px
   above and below inside the layout's panel, 8px between the lines, and the action a step further
   down - the shared empty block's numbers (app.css), on a page that is one message. */
.biztech-left[b-5gm9c5u2bm] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding-block: 48px;
    text-align: center;
}

/* A 64px tinted chip with the leave glyph - the primary container and its ink, the pair
   PaletteContrast holds at 4.5:1 - so the page says what happened before it is read. */
.biztech-left__mark[b-5gm9c5u2bm] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 64px;
    block-size: 64px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-left__action[b-5gm9c5u2bm] {
    margin-block: 8px;
}
/* /Components/Pages/SessionReview.razor.rz.scp.css */
/*
    W6-58 · F8.21 · the finished session's review. Layout only: colour and type come from UiText, UiPaper
    and the tokens (R3.1); every length is on the 4px base unit (R5.4).

    I18: the space between the review's panels, and between its people, belongs to the CONTAINER as a gap
    - never a margin on each child. I19: both selectors name markup this component writes itself.
*/
.biztech-review[b-ae4zorqted] {
    display: grid;
    gap: 16px;
}

.biztech-review-people[b-ae4zorqted] {
    display: grid;
    gap: 12px;

    /* The <ul>'s own reset - PersonPermissions' decision: how many people were on the case is
       information, not bullets in prose. Declared in UtilitySpecificityTests. */
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}
/* /Components/Pages/SessionViewer.razor.rz.scp.css */
/* W19 · the stage-focus track in the band, before Leave session, centred on the band's line - the
   operator's pane draws the same (AgentSessionBody.razor.css), and a scoped sheet cannot share it. */
.biztech-session-bar-switch[b-ixjd01cj5k] {
    display: inline-flex;
    align-items: center;
    margin-inline-end: 8px;
}

/* The document asks span the toolbar row rather than shrinking to their content. */
.biztech-session-asks-row[b-ixjd01cj5k] {
    flex: 1 1 100%;
}

/* Save answers and its caption: the agent pane's foot (AgentSessionBody.razor.css), so both sides match. */
.biztech-session-save[b-ixjd01cj5k] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding-block-start: 1rem;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Pages/TenantCreate.razor.rz.scp.css */
/* W23-04 · amendment 1, G3 — onboarding from the UI. TOKENS ONLY (R3.1).

   🔴 I18. Each row owns its gap: the action row (submit, cancel, R9.2's caption) and each report line (the outcome chip
   and its sentence). I19: every selector ends on a class this file's own markup writes.

   Lengths are multiples of the 4px base unit (R5.1, R5.4). */

/* W19-23 · the form's card and the report under it end at the form measure, the width the fields always had: the card ran
   the page's width with the fields capped inside it, leaving its right part empty. `max-inline-size` rather than a width, so
   a phone still gets the whole viewport. */
.biztech-tenant-create[b-njllf8wvy0] {
    /* The measure is the fields'; the card adds its 16px padding (biztech-pa-4) and 1px edge on each side, 34px in all,
       rounded up to the 4px scale (R5.1). */
    max-inline-size: calc(var(--biztech-form-measure) + 36px);
}

/* The form is a column whose gap spaces the field grid from the action row: the container's, not a margin on the row,
   which the report's own 12px gap would otherwise add to. */
.biztech-tenant-create-form[b-njllf8wvy0] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-tenant-create-actions[b-njllf8wvy0] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-onboarding-report[b-njllf8wvy0] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A list by role on <div>s, so there is no user-agent list margin or padding to reset - a scoped reset would outrank
   the utility layer (UtilitySpecificityTests). */
.biztech-onboarding-steps[b-njllf8wvy0] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-onboarding-step[b-njllf8wvy0] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* Chrome walk F2: a failed step's Details takes a line of its own under the chip and the sentence. */
.biztech-onboarding-step-details[b-njllf8wvy0] {
    flex-basis: 100%;
}
/* /Components/Pages/TenantRecord.razor.rz.scp.css */
/* W23-04 · amendment 1, G4 — one tenant's record. TOKENS ONLY (R3.1).

   🔴 I18. Every row and stack owns its gap: the page's column of settings rows, the action rows, each host line and the add-a-host row. No child carries a margin. I19: every selector ends
   on a class this file's own markup writes. Lengths are multiples of the 4px base unit (R5.1, R5.4). */

.biztech-tenant-record[b-652n0xsbw0] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-tenant-actions[b-652n0xsbw0] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* I20: the add-a-host block is a column - the field-and-button row, then the checkbox, then the caption - and the row
   aligns on the CONTROL's lower edge, so the button sits beside the input rather than beside its label. */
.biztech-tenant-host-add[b-652n0xsbw0] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-tenant-host-add-row[b-652n0xsbw0] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px;
}

/* Lists by role on <div>s, so there is no user-agent list margin or padding to reset - a scoped reset would outrank
   the utility layer (UtilitySpecificityTests). */
.biztech-tenant-hosts[b-652n0xsbw0],
.biztech-tenant-organisations[b-652n0xsbw0] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-tenant-host[b-652n0xsbw0] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* W27-01 · a host with its packs. host's status beneath it: one column, one gap (I18). */
.biztech-tenant-host-entry[b-652n0xsbw0] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* W31-03 · D8. Restore after a release: the new short name's field, then the action row - one column, one gap (I18). */
.biztech-tenant-restore[b-652n0xsbw0] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Pages/Tenants.razor.rz.scp.css */
/* W23-04 · amendment 1, G2 — the Tenants list. TOKENS ONLY (R3.1).

   The state cell's chips and its Retry link sit in one row this component owns, spaced by the row's gap and never by a
   margin per child (I18), and wrapping on a narrow screen rather than widening the table. */
.biztech-tenant-state[b-alzqb9dnox] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* W19-23 · the Active / Deleted switch at the list's top end, where the case list keeps its own. */
.biztech-tenants-views[b-alzqb9dnox] {
    display: flex;
    justify-content: flex-end;
}
/* /Components/Pages/Themes.razor.rz.scp.css */
/* W21-04 · the theme editor's page furniture. Layout only: colour and type come from the seam's
   tokens, spacing between siblings is a gap on the container, and every length is a scale step. */

/* The header's actions: Discard and Save, while something differs - and the App / Portal / Brand track under the header. */
.biztech-theme-toolbar[b-pogznlg1e5] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The view track sits at the trailing edge, where it stood when it was in the header, and a step above the workspace or the brand
   panels. The step was only the workspace's while the brand view's column also had a 16px gap; that gap stood between the header
   and the track as well, on top of the header's own 24px, and moved the track down whenever Brand was pressed. The step is now
   the track's on every view, and the brand column has no gap. */
.biztech-theme-views[b-pogznlg1e5] {
    justify-content: flex-end;
    margin-block-end: 16px;
}

/* Two panes in a frame the height of what is left of the viewport: the settings pane scrolls on its
   own and the preview stays beside it, each taking half the width.

   🔴 THE ROW IS minmax(0, 1fr), AND THAT IS THE FIX FOR THE PAGE GROWING. An implicit grid row is
   `auto`, which sizes to its content: opening a section made the row as tall as every setting, the
   workspace spilled past the window, and the whole page scrolled past the end of the drawer - a band
   of empty page under the shell. A row that may shrink to nothing keeps the frame its own height and
   leaves the overflow to the settings pane's scroller.

   The frame's height is what the viewport leaves: the page is a column of the header and the
   workspace inside `.biztech-theme-page`, whose height is the viewport less the app bar and the
   container's 16px top and bottom, so a header that grows a row of buttons takes its height from
   the workspace rather than from the page. Below md the frame lets go and the page scrolls, preview
   first, so the change is seen before the control that made it. */
.biztech-theme-page[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    block-size: calc(100dvh - var(--biztech-content-block-start, 0px) - 32px);
    min-block-size: 480px;
}

/* 🔴 THE BRAND VIEW IS NOT A WORKSPACE. Held to the viewport's height, its two panels overflowed the page box rather
   than the grid row it sits in, so the document grew past the shell's main row: the sticky drawer, bounded by that
   row, scrolled away with the page. It has no panes to scroll, so it takes its content's height. */
.biztech-theme-page--flow[b-pogznlg1e5] {
    block-size: auto;
}

.biztech-theme-workspace[b-pogznlg1e5] {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    /* No column gap: the 24px between the panes is the settings' own end padding (the tab row's trailing slot and the
       scroller below), so the settings' scrollbar sits at the edge of their column rather than against their controls. */
    gap: 24px 0;
    min-block-size: 0;
}

/* The scope select has no visible label: its line pushed the tab row taller than the preview pane's head, and Design and JSON
   no longer sat level with the pane's name. The label is still the select's name - said, not drawn (R12.4's clipped label). */
[data-theme-scopes][b-pogznlg1e5]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

[data-theme-views][b-pogznlg1e5]  .biztech-tabs-trailing {
    padding-inline-end: 24px;
}

.biztech-theme-workspace-pane[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-block-size: 0;
}

/* 🔴 THE PANE RESERVES ROOM FOR A FOCUS RING AT ITS START, AND THE NEGATIVE MARGIN IS WHAT KEEPS THE
   CONTENT WHERE IT WAS.

   `overflow-y: auto` alone does not scroll one axis: CSS computes the other from `visible` to `auto`,
   so this pane clipped HORIZONTALLY as well. Its content box and its first controls both began at the
   same x, so every ring drawn outside a border box was cut off at the left — the code editor lost the
   whole left side of its 2px ring, and Format and Validate lost 4px of theirs, app.css's shared ring
   standing off at `outline-offset: 2px`. The buttons were losing it before the editor existed.

   8px is the room, matching the end padding that already keeps content off the scrollbar. The pane
   then moves 8px back toward the start, so its content still lines up with the tabs above it — those
   are outside this pane and did not move. The 8px comes out of the page container's own inline
   padding, which is 16px, so nothing is pushed off the page. */
/* 🔴 overscroll-behavior: contain. A pane scrolled to its end handed the rest of the wheel to the document, which
   could move by the footer's height - and the app bar and the drawer, sticky only within their own grid rows, went up
   with it. The settings pane is long enough on the Portal view for anyone to reach its end. Each pane keeps its own
   scroll; the footer is still reached by scrolling outside them. */
.biztech-theme-workspace-scroll[b-pogznlg1e5] {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    margin-inline-start: -8px;
    padding-inline: 8px 24px;
    /* Room under the last section, so its edge and its Depth shadow are not cut by the pane's own bottom edge. */
    padding-block-end: 16px;
}

/* The pane's scrollbar, drawn while it is being scrolled and not otherwise - the navigation rail's rule
   (MainLayout.razor.css), for the same reason: a permanently drawn thumb beside settings nobody is scrolling.
   The colour changes, not the width, so the gutter stays put and nothing reflows when it appears. Both rules
   are gated on data-scroll-reveal, which biztech-rail.js sets when it attaches - so a pane the module never
   reached keeps the user agent's ordinary scrollbar rather than one that can never be seen. */
.biztech-theme-workspace-scroll[data-scroll-reveal][b-pogznlg1e5] {
    scrollbar-color: transparent transparent;
}

.biztech-theme-workspace-scroll[data-scroll-reveal][data-scrolling][b-pogznlg1e5] {
    scrollbar-color: var(--biztech-palette-outline) transparent;
}

/* 🔴 scrollbar-gutter: stable, AND IT IS WHAT STOPS THE PREVIEW SHAKING. Both miniatures are scaled to this column's width
   (biztech-fit.js), so their height follows the width. Where scrollbars take room, a miniature just taller than the column
   brought the scrollbar in, the narrower column scaled it short enough to fit, the scrollbar left, and round again on every
   frame. The gutter is kept whether the column scrolls or not, so its width never changes with the miniature's height. */
.biztech-theme-workspace-preview[b-pogznlg1e5] {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-gutter: stable;
    padding: 16px 4px 16px 24px;
    /* The rule between the settings and the preview: on the body, not the pane, so it starts at the head's foot - level with the
       settings' tab row line - and runs to the bottom, never up beside the Preview strip. */
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The preview pane, the Setup assistant's preview pane's shape (AdminAssistantPage.razor.css): a column of the workspace's
   height, ruled off from the settings by a hairline, its head staying and its body scrolling. */
.biztech-theme-preview-pane[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    min-block-size: 0;
    min-inline-size: 0;
}

/* The pane's name on the leading side and its switch on the trailing one, on a strip of the surface - the artifact head's - with
   no rule under it and no edge beside the settings. 48px tall, the settings' tab row's height (UiTabs' floor), so the name sits
   level with Design and JSON. */
.biztech-theme-preview-head[b-pogznlg1e5] {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    box-sizing: content-box;
    block-size: 48px;
    padding-block: 0;
    padding-inline: 24px 4px;
    background: var(--biztech-palette-surface);
}

/* The pane's name with the contrast line beside it. */
.biztech-theme-preview-titles[b-pogznlg1e5] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 16px;
    min-inline-size: 0;
}

/* The head names the pane, so the canvas's own heading goes. */
.biztech-theme-preview-pane[b-pogznlg1e5]  .biztech-theme-canvas-head {
    display: none;
}

/* The mode switch: one outlined pill holding two glyph buttons, the pressed one tinted - the assistant's preview switch.
   ::deep: UiIconButton renders the buttons (I19). */
.biztech-theme-preview-switch[b-pogznlg1e5] {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
}

.biztech-theme-preview-switch[b-pogznlg1e5]  .biztech-icon-button {
    inline-size: 28px;
    block-size: 28px;
    min-inline-size: 28px;
    padding-block: 0;
    padding-inline: 0;
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-preview-switch[b-pogznlg1e5]  .biztech-icon-button[aria-pressed="true"] {
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

/* Between 960px and 1600px, half and half left the preview too narrow to judge a theme by, its
   card's buttons wrapping. There the preview takes three fifths and the settings keep a 300px floor, which still
   fits two preset cards a row and one colour picker with its Inherit button. Wider screens keep half and half, and
   below 960px the two stack (the block after this). */
@media (min-width: 960px) and (max-width: 1599.98px) {
    .biztech-theme-workspace[b-pogznlg1e5] {
        grid-template-columns: minmax(300px, 2fr) minmax(0, 3fr);
    }
}

@media (max-width: 959.98px) {
    .biztech-theme-page[b-pogznlg1e5] {
        block-size: auto;
    }

    .biztech-theme-workspace[b-pogznlg1e5] {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: none;
    }

    .biztech-theme-workspace-scroll[b-pogznlg1e5],
    .biztech-theme-workspace-preview[b-pogznlg1e5] {
        overflow-y: visible;
    }

    .biztech-theme-preview-pane[b-pogznlg1e5] {
        order: -1;
    }

    .biztech-theme-workspace-preview[b-pogznlg1e5] {
        border-inline-start: none;
    }

    .biztech-theme-preview-head[b-pogznlg1e5],
    .biztech-theme-workspace-preview[b-pogznlg1e5] {
        padding-inline-end: 0;
    }

    .biztech-theme-workspace-scroll[b-pogznlg1e5] {
        padding-inline-end: 8px;
    }

    .biztech-theme-preview-head[b-pogznlg1e5],
    .biztech-theme-workspace-preview[b-pogznlg1e5] {
        padding-inline-start: 0;
    }

    [data-theme-views][b-pogznlg1e5]  .biztech-tabs-trailing {
        padding-inline-end: 0;
    }
}

/* The JSON tab. */
.biztech-theme-code[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-theme-code-errors[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: var(--biztech-palette-error);
}

.biztech-theme-code-errors code[b-pogznlg1e5] {
    font-family: var(--biztech-font-mono-family);
}

/* Format and Validate, on one row above the editor. */
.biztech-theme-code-actions[b-pogznlg1e5] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The key list in the JSON tab: a caption column and a wrapping run of key buttons. */
.biztech-theme-keys[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-theme-key-group[b-pogznlg1e5] {
    display: grid;
    grid-template-columns: 96px 1fr;
    align-items: baseline;
    gap: 4px 8px;
}

.biztech-theme-key-chips[b-pogznlg1e5] {
    display: flex;
    flex-wrap: wrap;
    gap: 0 4px;
}

/* W19-07 · the Save as preset card: its fields in a column, the actions at its end. */
.biztech-theme-preset-dialog[b-pogznlg1e5] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-theme-preset-dialog-actions[b-pogznlg1e5] {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Pages/UiGallery.razor.rz.scp.css */
/* W20-07 · I18 · the code editor's section on /ui: the heading, the sentence and the three specimens spaced by their
   container, and the first specimen's editor and its echo likewise. The gallery's other sections predate this sheet
   and keep their own utility margins. Tokens and the 4px scale only (R3.1). */

.biztech-gallery-code[b-eozt0llz86] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-gallery-code-specimen[b-eozt0llz86] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Portals/AppSection.razor.rz.scp.css */
/*
    W25-01 · the frame a published app is drawn in.

    EmbeddedPageSection's rule, for its reasons: full inline size and an ASPECT RATIO rather than a height, so the
    frame scales from a phone to the tile page without assuming a grid track; a 320px floor, because 16/9 of a 343px
    content width is too short to use a calculator in; no border, because a frame is not a control; the palette's own
    radius so the app does not overhang UiPaper's corners.

    NO colour — what paints inside this box is the tenant's app — and logical properties only, so
    PortalHomeRenderTests' ban on the string `height` holds here too.
*/

.biztech-portal-app-frame[b-oz34mmb51t] {
    aspect-ratio: 16 / 9;
    border: 0;
    border-radius: var(--biztech-radius-default);
    display: block;
    inline-size: 100%;
    min-block-size: 320px;
}
/* /Components/Portals/DocumentViewerSection.razor.rz.scp.css */
/* The theme's document viewer height on a portal page (ThemePortalLook), handed to the panel inside, which reads it in
   place of its own 24rem. The dialog that opens the same panel from the console sets nothing and keeps 24rem. */
[data-portal-document][b-6exxzi91f9] {
    --biztech-document-view-height: var(--biztech-portal-viewer-height, 24rem);
}

/* On a portal page the section's card is the surface and its title the heading, so the viewer drew a box inside the card
   and the file's name as a second heading of the same size. Here the viewer has no frame of its own, the name is a quiet
   line under the title (still the h3 under the section's h2), and the status line, empty while the frame shows, holds
   no height of its own. The library's dialog keeps all three. */
[data-portal-document][b-6exxzi91f9] {
    --biztech-document-viewer-padding: 0px;
    --biztech-document-viewer-gap: 0px;
}

[data-portal-document][b-6exxzi91f9]  .biztech-document-viewer {
    border-color: transparent;
    background-color: transparent;
}

[data-portal-document][b-6exxzi91f9]  .biztech-document-viewer-head > :first-child {
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
    letter-spacing: var(--biztech-font-body2-letter-spacing);
    color: var(--biztech-palette-text-secondary);
}

[data-portal-document][b-6exxzi91f9]  .biztech-document-status {
    min-height: 0;
    margin-top: 0;
}

[data-portal-document][b-6exxzi91f9]  .biztech-document-frame {
    margin-top: 12px;
}
/* /Components/Portals/EditablePdfSection.razor.rz.scp.css */
/*
    W1b-01 · F2.6 · the pager beneath a fillable PDF page.

    ONE RULE, BECAUSE THERE IS ONE ELEMENT THIS FILE OWNS. The overlay's own geometry is
    PdfFormOverlay.razor.css's - it positions controls over a rendered page and scrolls ITSELF rather than
    the page body, so a 1240px page at 150dpi does not give a narrow viewport a horizontal scrollbar. That
    file is W3-18's and is mounted unchanged; nothing here reaches into it.

    THE PAGER IS A ROW THAT WRAPS, which is what makes it correct at 375px without a media query: below
    the width where three items fit, the announced indicator drops to its own line rather than squeezing
    the two controls under their 44px touch target (R13.5). space-between rather than a gap on each side,
    so the two controls sit at the edges a thumb reaches.

    align-items: center, because the indicator is text and the controls are buttons - their line boxes
    differ, and without this the words sit high against the buttons' padding.

    NO COLOUR, which PortalStyleSheetTests' hex sweep requires of every sheet under Components/. NO
    overflow and NO position: sticky. Every length is a multiple of the 4px base unit - 8px here, which is
    the same step the image-card gallery's cell gap uses and for the same reason: there is no --biztech-space-*
    token to read, and a var() that resolves to nothing falls back to nothing at all.
*/

.biztech-portal-pdf-pager[b-49ga13j53e] {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: space-between;
}

/*
    🔴 W8-31 · WHAT FINISHES THE FORM: the two actions, the caption and the outcome. The PARENT owns every
    gap (I18) - no margin on a child - and the actions share a row that wraps, so Download and "Email it to
    me" sit side by side where they fit and stack at 375px without a media query, each keeping its 44px
    target (R13.5). flex-start rather than space-between: these are two choices read left to right, not the
    pager's two ends. 8px again, the base unit's step this file already uses.
*/
.biztech-portal-pdf-finish[b-49ga13j53e] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-portal-pdf-actions[b-49ga13j53e] {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: flex-start;
}
/* /Components/Portals/EmbeddedPageSection.razor.rz.scp.css */
/*
    W1b-01 · F2.7 · the frame an external page is drawn in.

    🔴 NO FIXED SIZE, WHICH IS THE WHOLE REASON THIS SHEET EXISTS. Legacy draws this page as an iframe at
    a hard 959 x 743px inside a body pinned to the same two figures - Views/Home/GenericIframeUI.cshtml:21
    and :31 - and that is the non-responsive shape the card replaces. Its words: "nothing here may assume
    a fixed height or a grid track", because the same renderer has to be correct on the tile page at
    71.25rem AND inside W1b-06's preview at whatever width that gives it.

    So: full inline size, and an ASPECT RATIO rather than a height. 16/9 matches
    PortalSectionThumbnail's, and the reason is the same kind of reason - it is the ratio the content
    tends to want - but it is doing different work here. A frame with no height at all collapses to
    150px, which is the HTML default for a replaced element and is not a design decision anybody made;
    a frame with a fixed height clips a partner's page on a phone. A ratio scales.

    A MINIMUM, though, because a ratio alone is not enough at 375px: 16/9 of a 343px content width is
    193px, which is not enough of somebody's benefits page to be worth framing. 320px is the floor -
    a multiple of the 4px base unit, and the width the narrowest supported viewport gives the content,
    so a frame is never shorter than the page is wide.

    NO BORDER, because a frame is not a control. The border-radius is the palette's own so the framed
    document does not overhang UiPaper's corners.

    NO overflow, NO position: sticky, and NO COLOUR - PortalStyleSheetTests' hex sweep requires the last
    of every sheet under Components/, and there is nothing to declare: what paints inside this box is
    somebody else's document.

    LOGICAL PROPERTIES: inline-size rather than width, on PortalSectionThumbnail's and PortalCard's
    line - which is what lets PortalHomeRenderTests ban the string `height` outright as R13.3's
    container-height check.
*/

.biztech-portal-embed-frame[b-dfhk711y1l] {
    aspect-ratio: 16 / 9;
    border: 0;
    border-radius: var(--biztech-radius-default);
    display: block;
    inline-size: 100%;
    min-block-size: 320px;
}

/* The title, the frame and the way out were stacked with nothing between them, so the link sat on the frame's bottom
   edge. 12px apart, the inline item's gap (PortalItemOutlet.razor.css); the frame keeps the full width, the link only its
   words, its glyph on the text's middle. */
.biztech-portal-embed[b-dfhk711y1l] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
}

.biztech-portal-embed > [data-portal-embed-status][b-dfhk711y1l] {
    align-self: stretch;
}

.biztech-portal-embed-link[b-dfhk711y1l] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
/* /Components/Portals/PortalCard.razor.rz.scp.css */
/* W20-05 · D1 · one card, four faces.

   The CELL is PortalTileCard.razor.css's tile: a column flex box that fills its grid cell, a link that fills the box,
   and a paper that fills the link - so every cell in a row is the same height whatever its title wraps to. Its
   PLACEMENT is not here: the layout knows the grid and owns the rules (PortalItemLayout.razor.css).

   🔴 THE PORTAL'S CARD LOOK, AND WHERE EACH VALUE COMES FROM. A card is a white surface with a quiet edge, corners
   twice the theme's radius, a tinted icon square, a 16px semibold title over its description, and a round button at
   the far edge that says where the card goes - always drawn (R13.4), and filled with the primary colour under the
   pointer. Under the pointer a launcher tile also takes the raised shadow, the board card's licence in ADR 0026 D-E
   (InFlowElevationTests holds the row). Every colour, radius, shadow and duration is a theme variable,
   so a tenant's palette, radius, elevation and motion settings all reach it; the doubled radius is a multiple of the
   theme's, so a square theme stays square.

   The edge is outline-subtle rather than outline: a card is identified by its title, its description and the round
   button, so its border is not the only thing that says it is there (WCAG 1.4.11 asks 3:1 of a boundary that is).

   No hover-ONLY affordance (PortalHomeRenderTests): every :hover rule here changes how something already drawn looks,
   never whether it is drawn. NO colour literal and NO overflow (R13.8). */

.biztech-portal-tile[b-sn4cmzmjm8],
.biztech-portal-row[b-sn4cmzmjm8],
.biztech-portal-image-card[b-sn4cmzmjm8],
.biztech-portal-app-icon[b-sn4cmzmjm8] {
    box-sizing: border-box;
    min-inline-size: 0;
    display: flex;
    flex-direction: column;
}

/* 🔴 F14.22's EDIT BUTTON, BESIDE THE CHEVRON, INSIDE THE CARD. EditableRegion draws it as a SIBLING of the card's
   link - an administrator-only text button with a wrench - because a link inside a link is invalid HTML. It hung under
   the card and pushed the row apart; set on the card's top edge it read as a badge stuck on. So the tile is a one-cell
   grid that holds both, the link filling the cell and the button laid over it at the card's end, a second round
   button just before the chevron: the same 32px circle in a quiet outline, so the two read as the card's pair of
   actions. A tile carrying the button keeps room for it, so a long title never runs under it. Its label stays in the markup, clipped from view, so its accessible name is still the record type's
   ("Edit portal item"); the wrench is always drawn (R13.4). A customer never holds the key, so a customer's tile has
   no button at all (PortalCardRegionRenderTests). */
.biztech-portal-tile[b-sn4cmzmjm8] {
    display: grid;
    grid-template: minmax(0, 1fr) / minmax(0, 1fr);
}

.biztech-portal-tile-link[b-sn4cmzmjm8],
.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-paper,
.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button {
    grid-area: 1 / 1;
}

.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button {
    align-self: center;
    justify-self: end;
    inline-size: 32px;
    margin-inline-end: 56px;
    padding: 4px;
    gap: 0;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-secondary);
}

/* The chevron's weight rather than the seam's 20px glyph, so the pair reads as one size. */
.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
    font-size: 16px;
}

.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button:hover {
    border-color: var(--biztech-palette-primary);
    color: var(--biztech-palette-primary);
}

.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button .biztech-button-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    white-space: nowrap;
    clip-path: inset(50%);
}

/* Room for it - the chevron's 12px, the button's 32px and 8px between them - only where the button IS, which is only
   for an administrator: a customer's tile is byte for byte an uneditable one, so nothing in its markup may say
   "editable". The condition is asked of the rendered page instead (R13.6): the card's link followed by a SECOND
   anchor, which only EditableRegion draws. Named by this file's own class and an element, never by the button's
   class, which is the seam's markup rather than this component's (I19). The child combinator, for
   SessionStage.razor.css's reason: a descendant :has() would also match an anchor inside the card. */
.biztech-portal-tile:has(> .biztech-portal-tile-link + a) .biztech-portal-face-go[b-sn4cmzmjm8],
.biztech-portal-tile:has(.biztech-portal-start-title):has(> a) .biztech-portal-face-go[b-sn4cmzmjm8] {
    margin-inline-start: 52px;
}

/* A tall tile draws its face at its foot, under the art, so the button sits there too, centred on the 48px chip row. */
.biztech-portal-tile-tall[b-sn4cmzmjm8]  .biztech-button {
    align-self: end;
    margin-block-end: 24px;
}

/* A narrow tile puts the chevron in its top corner, so the button sits beside it there. */
@container (max-width: 300px) {
    .biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button {
        align-self: start;
        margin-block-start: 16px;
    }

    .biztech-portal-tile:has(> .biztech-portal-tile-link + a) .biztech-portal-face-go[b-sn4cmzmjm8],
    .biztech-portal-tile:has(.biztech-portal-start-title):has(> a) .biztech-portal-face-go[b-sn4cmzmjm8] {
        margin-inline-start: 0;
    }

}

.biztech-portal-tile-link[b-sn4cmzmjm8],
.biztech-portal-row-link[b-sn4cmzmjm8] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-inline-size: 0;
    text-decoration: none;
    color: inherit;
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* W25 walk · a card that starts its case on a press. The button takes away what a button adds of its own - border, fill,
   font, centring and padding: the document reset owns a button's margin, NOT its padding, so the user agent's would
   push the title off its column. An app icon's own padding is declared after this and wins on source order. Its focus
   ring is app.css's, in the one shared list (R3.10). */
.biztech-portal-start-now[b-sn4cmzmjm8] {
    appearance: none;
    box-sizing: border-box;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: inherit;
    cursor: pointer;
}

/* An app icon is one button and fills its cell, as the anchor it replaces does. */
.biztech-portal-app-icon-link.biztech-portal-start-now[b-sn4cmzmjm8] {
    inline-size: 100%;
}

.biztech-portal-start-now[aria-disabled="true"][b-sn4cmzmjm8] {
    cursor: progress;
}

/* 🔴 THE TITLE IS THE BUTTON, AND ITS LAYER IS THE CARD. On a tile, a row or an image card the heading holds the button
   (an interactive element may not hold a heading), and the button's ::after is laid over the whole card, so a press
   anywhere on it presses the button - the target the link it replaces had. The card is the layer's containing block, and
   nothing between them is positioned. The in-place edit control is positioned too, and later in the tree, so it paints
   above the layer and keeps its own press. */
.biztech-portal-tile:has(.biztech-portal-start-title)[b-sn4cmzmjm8],
.biztech-portal-row:has(.biztech-portal-start-title)[b-sn4cmzmjm8],
.biztech-portal-image-card:has(.biztech-portal-start-title)[b-sn4cmzmjm8] {
    position: relative;
}

.biztech-portal-start-title[b-sn4cmzmjm8]::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-portal-row .biztech-portal-start-title[b-sn4cmzmjm8]::after {
    border-radius: calc(var(--biztech-radius-default) * 1.5);
}

.biztech-portal-tile:has(.biztech-portal-start-title)[b-sn4cmzmjm8]  .biztech-button {
    position: relative;
}

/* W8-22 · a cell's content is centred in the cell, so a one-line tile beside a taller neighbour does not hug the top
   of a box the height of its row. */
.biztech-portal-tile[b-sn4cmzmjm8]  .biztech-paper,
.biztech-portal-row[b-sn4cmzmjm8]  .biztech-paper {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 12px;
    flex: 1 1 auto;

    /* The theme's card edge (ThemePortalLook): this quiet edge, or none. The shadow stays the paper's own - the
       theme's Depth (ADR 0026 D-E). */
    border-color: var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    transition:
        border-color var(--biztech-motion-duration, 120ms) ease-in-out,
        box-shadow var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* A row sits in a list, so it is a step tighter: smaller corners. */
.biztech-portal-row[b-sn4cmzmjm8]  .biztech-paper {
    border-radius: calc(var(--biztech-radius-default) * 1.5);
}

.biztech-portal-row-link[b-sn4cmzmjm8] {
    border-radius: calc(var(--biztech-radius-default) * 1.5);
}

.biztech-portal-row-link:hover[b-sn4cmzmjm8]  .biztech-paper,
.biztech-portal-row:has(.biztech-portal-start-title):hover[b-sn4cmzmjm8]  .biztech-paper {
    border-color: var(--biztech-portal-card-hover-edge, var(--biztech-palette-primary-container));
}

/* No lift: a 2px rise on every tile the pointer crossed made a launcher of fifteen tiles twitch as it moved over
   them. The edge, the soft shadow and the round button are enough to say which tile is under the pointer. */
.biztech-portal-tile-link:hover[b-sn4cmzmjm8]  .biztech-paper,
.biztech-portal-tile:has(.biztech-portal-start-title):hover[b-sn4cmzmjm8]  .biztech-paper {
    border-color: var(--biztech-portal-card-hover-edge, var(--biztech-palette-primary-container));
    box-shadow: var(--biztech-portal-card-hover-shadow, var(--biztech-shadow-raised));
}

/* The chip, the words and the round button, in one row - a grid, so the description sits under the title rather than
   under the chip. Rows 1 and 4 take the free space equally, so the title and its description are one block centred
   on the chip whether or not there is a description. Every child is placed explicitly: with no chip, column 1 is
   empty and zero wide, and the title still lands in column 2.

   The words wrap inside the column that is left: a title wider than its cell ran over the cell's border ("Learning
   library" at three columns). The 16px beside the chip is the chip's own margin rather than a column gap, so a card
   with no chip does not indent its title by a gap with nothing in it. */
.biztech-portal-face[b-sn4cmzmjm8] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: 1fr auto auto 1fr;
    min-inline-size: 0;
}

.biztech-portal-face[b-sn4cmzmjm8]  .biztech-portal-chip-mark,
.biztech-portal-face[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
    grid-column: 1;
    grid-row: 1 / -1;
    margin-inline-end: 16px;
}

.biztech-portal-face[b-sn4cmzmjm8]  :is(h1, h2, h3, h4, h5, h6) {
    grid-column: 2;
    grid-row: 2;
    font-weight: 600;
    letter-spacing: -0.01em;
    overflow-wrap: break-word;
}

.biztech-portal-face-description[b-sn4cmzmjm8] {
    grid-column: 2;
    grid-row: 3;
    padding-block-start: 4px;
    overflow-wrap: break-word;
}

/* The round button. Its ground is the page's, a step off the card's surface, and under the pointer it takes the
   primary colour with its own ink - a pair PaletteContrast holds. */
.biztech-portal-face-go[b-sn4cmzmjm8] {
    grid-column: 3;
    grid-row: 1 / -1;
    align-self: center;
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    margin-inline-start: 12px;
    border-radius: var(--biztech-radius-pill);

    /* The theme's open button (ThemePortalLook): this round ground, or none - the chevron alone. */
    background: var(--biztech-portal-card-go-ground, var(--biztech-palette-background));
    color: var(--biztech-palette-text-primary);
    transition:
        background-color var(--biztech-motion-duration, 120ms) ease-in-out,
        color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-portal-tile-link:hover .biztech-portal-face-go[b-sn4cmzmjm8],
.biztech-portal-row-link:hover .biztech-portal-face-go[b-sn4cmzmjm8],
.biztech-portal-tile:has(.biztech-portal-start-title):hover .biztech-portal-face-go[b-sn4cmzmjm8],
.biztech-portal-row:has(.biztech-portal-start-title):hover .biztech-portal-face-go[b-sn4cmzmjm8] {
    background: var(--biztech-portal-card-go-hover-ground, var(--biztech-palette-primary));
    color: var(--biztech-portal-card-go-hover-ink, var(--biztech-palette-on-primary));
}

/* A chevron drawn from two borders of a square turned 45 degrees, nudged left so its point sits on the centre. */
.biztech-portal-face-chevron[b-sn4cmzmjm8] {
    box-sizing: border-box;
    inline-size: 8px;
    block-size: 8px;
    margin-inline-end: 4px;
    border-block-start: 2px solid currentColor;
    border-inline-end: 2px solid currentColor;
    rotate: 45deg;
}

/* 🔴 A NARROW TILE STACKS: the chip above the words, the round button in the top corner. A one- or two-column tile on
   a twelve-column launcher left its title a word wide beside the chip - "Opens / in a / new / tab". Measured against
   the CELL rather than the viewport, because the cell's width is set by the tenant's spans, not by the screen; the
   cell is a size container in PortalItemLayout.razor.css. */
@container (max-width: 300px) {
    .biztech-portal-face[b-sn4cmzmjm8] {
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-rows: auto auto auto;
        row-gap: 12px;
    }

    .biztech-portal-face[b-sn4cmzmjm8]  .biztech-portal-chip-mark,
    .biztech-portal-face[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
        grid-column: 1;
        grid-row: 1;
        margin-inline-end: 0;
    }

    .biztech-portal-face[b-sn4cmzmjm8]  :is(h1, h2, h3, h4, h5, h6) {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .biztech-portal-face-description[b-sn4cmzmjm8] {
        grid-column: 1 / -1;
        grid-row: 3;
        padding-block-start: 0;
        margin-block-start: -8px;
    }

    .biztech-portal-face-go[b-sn4cmzmjm8] {
        grid-column: 2;
        grid-row: 1;
        align-self: start;
    }

    /* No chip: the title takes the first row, beside the round button, rather than sitting under an empty one. */
    .biztech-portal-face-bare[b-sn4cmzmjm8]  :is(h1, h2, h3, h4, h5, h6) {
        grid-column: 1;
        grid-row: 1;
        align-self: center;
    }

    .biztech-portal-face-bare .biztech-portal-face-description[b-sn4cmzmjm8] {
        grid-row: 2;
    }
}

/* A tall tile's upper half: a dotted ground in the outline-subtle ink, running to the card's edges above the face. */
.biztech-portal-tile-art[b-sn4cmzmjm8] {
    display: none;
    flex: 1 1 140px;
    margin: -16px -16px 4px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    border-start-start-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    border-start-end-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    background-color: var(--biztech-portal-tile-ground, var(--biztech-palette-background));
    background-image: var(--biztech-portal-tile-pattern, radial-gradient(var(--biztech-palette-outline-subtle) 1px, transparent 1px));
    background-size: var(--biztech-portal-tile-pattern-size, 16px 16px);
}

/* Only where the placement that made the tile tall is in force: below 960px the launcher is one or two columns in rank
   order (PortalItemLayout.razor.css), the tile is no taller than its neighbours, and the art would be empty space. */
@media (min-width: 960px) {
    .biztech-portal-tile-art[b-sn4cmzmjm8] {
        display: block;
    }
}

/* A row's chip is a step smaller than a launcher cell's. */
.biztech-portal-row[b-sn4cmzmjm8]  .biztech-portal-chip-mark,
.biztech-portal-row[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-radius-default);
}

/* The glyph's box follows the theme's icon box (ThemePortalLook); an uploaded mark keeps the corners above. */
.biztech-portal-row[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
    border-radius: var(--biztech-portal-icon-radius-row, var(--biztech-radius-default));
}

.biztech-portal-row[b-sn4cmzmjm8]  .biztech-portal-chip-glyph .biztech-icon {
    inline-size: 20px;
    block-size: 20px;
    font-size: 20px;
}

/* An image card: the picture to the card's edges, its corners following the card's, and the words padded beneath. */
.biztech-portal-image-card[b-sn4cmzmjm8]  .biztech-paper {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    border-color: var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-portal-image-card[b-sn4cmzmjm8]  .biztech-portal-thumb {
    border-start-start-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    border-start-end-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    border-end-start-radius: 0;
    border-end-end-radius: 0;
}

.biztech-portal-image-card-body[b-sn4cmzmjm8] {
    display: flex;
    flex-direction: column;

    /* W25-04 · D16 · it fills the card, so an action label's auto margin has room to sit at the foot. */
    flex: 1 1 auto;
    gap: 4px;
}

.biztech-portal-image-card-body[b-sn4cmzmjm8]  :is(h1, h2, h3, h4, h5, h6) {
    font-weight: 600;
}

/* W25-04 · D16 · an image card's action: the card's one link, at its foot, in the brand colour so it reads as the
   thing to press, and pushed down so a row of cards lines its actions up. Its distance from the words above is the
   body's gap, never a padding of its own (I18). */
.biztech-portal-image-card-action[b-sn4cmzmjm8] {
    align-self: flex-start;
    margin-block-start: auto;
    font-weight: 600;
    color: var(--biztech-palette-primary);
    text-decoration: none;
}

.biztech-portal-image-card-action:hover[b-sn4cmzmjm8],
.biztech-portal-image-card-action:focus-visible[b-sn4cmzmjm8] {
    text-decoration: underline;
}

.biztech-portal-title-link[b-sn4cmzmjm8] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: inherit;
    text-decoration: none;
}

.biztech-portal-title-link:hover[b-sn4cmzmjm8],
.biztech-portal-image-card:has(.biztech-portal-start-title):hover .biztech-portal-title-link[b-sn4cmzmjm8] {
    color: var(--biztech-palette-primary);
    text-decoration: underline;
}

/* An app icon is its glyph over its title, centred - PortalAppMenuTile's button, as a link; the unavailable one
   stacks the same way, so the two states line up side by side. */
.biztech-portal-app-icon[b-sn4cmzmjm8] {
    align-items: center;
    gap: 8px;
    text-align: center;
}

.biztech-portal-app-icon-link[b-sn4cmzmjm8] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 12px 8px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    text-align: center;
    text-decoration: none;
    color: inherit;
}

/* The box and its glyph at the theme's app icon size (ThemePortalLook): today's 48px and 24px unset. Only here, so a
   tile's or a row's chip keeps its own size. */
.biztech-portal-app-icon[b-sn4cmzmjm8]  .biztech-portal-chip-glyph,
.biztech-portal-app-icon[b-sn4cmzmjm8]  .biztech-portal-chip-mark {
    inline-size: var(--biztech-portal-app-icon-size, 48px);
    block-size: var(--biztech-portal-app-icon-size, 48px);
}

.biztech-portal-app-icon[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out, color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-portal-app-icon[b-sn4cmzmjm8]  .biztech-portal-chip-glyph .biztech-icon {
    inline-size: var(--biztech-portal-app-icon-glyph, 24px);
    block-size: var(--biztech-portal-app-icon-glyph, 24px);
    font-size: var(--biztech-portal-app-icon-glyph, 24px);
}

.biztech-portal-app-icon [data-portal-item-title][b-sn4cmzmjm8] {
    font-weight: var(--biztech-portal-app-icon-title-weight, 400);
}

/* 🔴 NO GROUND OF ITS OWN UNDER THE POINTER. It painted the surface behind the glyph and the title, a box as wide as
   the title, so every icon in a set took a different box. The box is the glyph's: the theme can fill it (iconHover),
   and the title takes the icon's colour either way, so the hover always shows. */
.biztech-portal-app-icon-link:hover[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
    background: var(--biztech-portal-icon-hover-ground, var(--biztech-portal-icon-ground));
    color: var(--biztech-portal-icon-hover-ink, var(--biztech-portal-icon-ink));
}

.biztech-portal-app-icon-link:hover [data-portal-item-title][b-sn4cmzmjm8] {
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));
}

@media (prefers-reduced-motion: reduce) {
    .biztech-portal-tile[b-sn4cmzmjm8]  .biztech-paper,
    .biztech-portal-face-go[b-sn4cmzmjm8],
    .biztech-portal-app-icon[b-sn4cmzmjm8]  .biztech-portal-chip-glyph {
        transition: none;
    }
}

/* R13.4 · the coarse-pointer 44px floor, PortalTileCard's, on every face's link. */
@media (pointer: coarse) {
    .biztech-portal-tile-link[b-sn4cmzmjm8],
    .biztech-portal-row-link[b-sn4cmzmjm8],
    .biztech-portal-app-icon-link[b-sn4cmzmjm8] {
        min-block-size: 44px;
    }

    /* PortalTileCard's floor for what a tile holds besides its own link - the in-place editing control. Not the title's
       start button: its target is the whole tile, through its stretched layer, and a 44px inline-flex box would move the
       title in its heading. */
    .biztech-portal-tile[b-sn4cmzmjm8]  a:not(.biztech-portal-tile-link),
    .biztech-portal-tile[b-sn4cmzmjm8]  button:not(.biztech-portal-start-now) {
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }

    .biztech-portal-tile[b-sn4cmzmjm8]  .biztech-button {
        min-inline-size: 44px;
    }

    /* An image card's links, and its start buttons - the action at its foot, or the title - which take their place. */
    .biztech-portal-image-card[b-sn4cmzmjm8]  a,
    .biztech-portal-image-card .biztech-portal-start-now[b-sn4cmzmjm8] {
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }
}
/* /Components/Portals/PortalChangeSummary.razor.rz.scp.css */
/* W22-03 · the what-changed card. A gapped column of its own (I18): the card gaps this component as one child and cannot reach
   inside it (I19), so the heading pair, the list and the "more" link are spaced here. */

.biztech-change-summary[b-t5b3jz8xuf] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* The list keeps the browser's marker and indent; its block margin would be a second spacing on top of the gap - and, as the column's
   last child, a 1em sitting on the card's own padding - so only the margin goes. */
.biztech-change-summary-list[b-t5b3jz8xuf] {
    margin: 0;
}
/* /Components/Portals/PortalComposerAddPagePanel.razor.rz.scp.css */
/* W20-03 · adding a footer page. I18 - spaced by its containers' gaps. */
.biztech-composer-add-page[b-toavgq84br] {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Four short fields, equal columns that wrap together; a declared floor, for R13.8's reason. */
.biztech-composer-add-page-fields[b-toavgq84br] {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1rem;
  align-items: start;
}
/* /Components/Portals/PortalComposerAddressLine.razor.rz.scp.css */
/* W19-11 · moved with its markup out of PortalComposer.razor.css; every rule ends on this component's own markup (I19). */

/* The address strip under the h1: where the item is shown and what it opens. It wraps; a long address breaks. */
.biztech-composer-addresses[b-h2pgveb7jj] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin: 8px 0 0;
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
    overflow-wrap: anywhere;
}

/* W19-11 · an upper-case label over a bare monospace run read as a form's field dump; the label is a quiet word
   now and the address sits in a code chip beside it. */
.biztech-composer-address-label[b-h2pgveb7jj] {
    font-weight: 600;
}

.biztech-composer-address code[b-h2pgveb7jj] {
    padding: 2px 8px;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 10%, transparent);
    color: var(--biztech-palette-text-primary);
}

/* Each address: its label and its value, a gap apart. Razor trims the whitespace between a tag and a code block,
   so a space in the markup could not be relied on - measured on the stack as "OPENS/portal/main". */
.biztech-composer-address[b-h2pgveb7jj] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerAddSectionPanel.razor.rz.scp.css */
/* W16-11 · 1 — the add form's own rhythm.

   I18: the space between siblings belongs to the CONTAINER as a gap, never to each child as a margin -
   "the two add up", which is the defect this panel's own ancestors have paid for twice. And I17: UiPaper
   carries NO padding of its own, so the biztech-pa-3 on it is what keeps these fields off its border.

   12px, which is the step the sibling groups on the tile panel use for the members of ONE setting - a
   type, a title and one reference are one act rather than three unrelated controls. */
.biztech-composer-add-section[b-mmu2id6fp8] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Add, Cancel and the caption on one line, with the caption taking the slack.

   align-items: center rather than baseline: the two buttons and a caption have different line boxes, and
   a baseline alignment hangs the caption off the buttons' text rather than centring it in the row.

   flex-wrap, because at 375px "Added when you press Add. Nothing is published until you publish the
   portal." is longer than the row - and a caption that pushed Cancel off the panel would take the only
   way out of the form with it. */
.biztech-composer-add-actions[b-mmu2id6fp8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
}
/* /Components/Portals/PortalComposerAddTilePanel.razor.rz.scp.css */
/* W16-11 · 2 — the add-tile form's own rhythm.

   I18: the space between siblings belongs to the CONTAINER as a gap, never to each child as a margin -
   "the two add up". And I17: UiPaper carries no padding of its own, so the biztech-pa-3 on it is what
   keeps these controls off its border.

   12px, which is the step the sibling groups on the tile panel use for the members of ONE setting. */
.biztech-composer-add-tile[b-8bv8wtvsm9] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Add and Cancel on one line. */
.biztech-composer-add-tile-actions[b-8bv8wtvsm9] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
}

/* An option's name over what it does, the second line in body text's secondary ink rather than a caption. */
.biztech-composer-add-tile-option[b-8bv8wtvsm9] {
    display: flex;
    flex-direction: column;
}

.biztech-composer-add-tile-option-hint[b-8bv8wtvsm9] {
    color: var(--biztech-palette-text-secondary);
}
/* /Components/Portals/PortalComposerAppFields.razor.rz.scp.css */
/*
    W25-01 · the app field group's own spacing (I18). The class names a group the composer's other field groups use, but
    their rules are scoped to their own components and do not reach this one - so the column and its gap are declared
    here, with the 8px every composer field group uses. Logical properties, no colour.
*/

.biztech-composer-field-group[b-veqs3r79xi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

[data-app-upload][b-veqs3r79xi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* W25-01 Part B · I18. The status region (an alert, the draft sentence and its review) and the open-mode choice (the
   radios and the new-tab-only sentence) space their own children, as the upload block above does. */
[data-app-status][b-veqs3r79xi],
[data-app-open-mode][b-veqs3r79xi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Portals/PortalComposerCardFile.razor.rz.scp.css */
/* W20-06 · a file on a card. W19-11 · what is chosen as a thumbnail with its buttons beside it, and the library search
   under it with its results as a grid of thumbnails. I18 · every container carries its own gap. I19 · PortalLogo and the
   seam's controls are other components' roots, sized by the tracks here and reached only through ::deep from a wrapper
   this file owns. */
.biztech-card-file[b-klnw2zkoae] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-card-file-label[b-klnw2zkoae] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-card-file-current[b-klnw2zkoae] {
    display: flex;
    align-items: center;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-card-file-thumb[b-klnw2zkoae] {
    position: relative;
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 64px;
    block-size: 64px;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 6%, var(--biztech-palette-surface));
    color: var(--biztech-palette-text-secondary);
}

.biztech-card-file-thumb[b-klnw2zkoae]  .biztech-portal-logo {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    background: var(--biztech-palette-surface);
}

.biztech-card-file-thumb[b-klnw2zkoae]  .biztech-portal-logo-image {
    max-inline-size: 100%;
    max-block-size: 100%;
    object-fit: contain;
}

/* The glyph a file without a picture shows; a picture, once it resolves, covers it. */
.biztech-card-file-fallback[b-klnw2zkoae] {
    display: inline-flex;
}

.biztech-card-file-side[b-klnw2zkoae] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-card-file-name[b-klnw2zkoae] {
    font-size: var(--biztech-font-body2-size);
    color: var(--biztech-palette-text-secondary);
    overflow-wrap: anywhere;
}

.biztech-card-file-actions[b-klnw2zkoae] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
}

.biztech-card-file-browser[b-klnw2zkoae] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 4%, var(--biztech-palette-surface));
}

.biztech-card-file-search[b-klnw2zkoae] {
    display: flex;
    align-items: flex-end;
    gap: 8px;
}

.biztech-card-file-term[b-klnw2zkoae] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-card-file-cancel[b-klnw2zkoae] {
    flex: none;
}

.biztech-card-file-empty[b-klnw2zkoae] {
    font-size: var(--biztech-font-body2-size);
    color: var(--biztech-palette-text-secondary);
}

.biztech-card-file-grid[b-klnw2zkoae] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-card-file-hit[b-klnw2zkoae] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    inline-size: 100%;
    padding: 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    font: inherit;
    cursor: pointer;
}

.biztech-card-file-hit:hover[b-klnw2zkoae] {
    border-color: var(--biztech-palette-primary);
}

.biztech-card-file-hit-chosen[b-klnw2zkoae] {
    border-color: var(--biztech-palette-primary);
    background: var(--biztech-palette-primary-container);
}

.biztech-card-file-hit .biztech-card-file-thumb[b-klnw2zkoae] {
    inline-size: 100%;
    block-size: 72px;
}

.biztech-card-file-hit-title[b-klnw2zkoae] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    text-align: center;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
}
/* /Components/Portals/PortalComposerCardGroup.razor.rz.scp.css */
/* W20-06 · the Card group's two rows that are not one field each. I19 · every selector ends on this file's markup. */

/* The label and the key, side by side above sm. minmax(0, 1fr) so a long value wraps inside its track (R13.8). */
.biztech-composer-card-identity[b-tqphcfvqzq] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

@media (min-width: 600px) {
    .biztech-composer-card-identity[b-tqphcfvqzq] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The glyph beside its select, aligned at the END - I20: a field is a label above a control and the glyph has no
   label block, so aligned at the start it would line up with the select's label rather than its control. */
[data-tile-icon][b-tqphcfvqzq] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    align-items: end;
}

/* The card's two files, apart as the setting body spaces its fields (16px), so the image's Remove does not sit on the
   picture's search. Found by the UI review. */
.biztech-composer-card-files[b-tqphcfvqzq] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-composer-icon-preview[b-tqphcfvqzq] {
    display: flex;
    align-items: center;
    block-size: var(--biztech-control-height);
}

/* /Components/Portals/PortalComposerCaseLauncherPanel.razor.rz.scp.css */
/* W8-25 · F10.3 · W16-11 · 5 — the case launcher group's own rules, moved here with its markup.

   🔴 THE MOVE IS I19 RATHER THAN TIDYING, AND THE TWO ::deep RULES AT THE BOTTOM ARE WHY IT MATTERS
   MOST HERE. A scoped rule reaches this component's own markup and nothing else, and the compound Blazor
   stamps is the selector's LAST one. Left in PortalComposerTilePanel.razor.css after the markup moved,
   every rule below would have been stamped with the PARENT's scope and matched nothing - and the ::deep
   pair would have been inert TWICE over, since the element they reach for is UiRadioGroup's root inside
   a component the parent no longer renders. No error, no warning, and a class with no effective rule
   renders exactly like a class with none. ScopedStyleReachTests is the sweep that says so. */

/* 🔴 W8-25 · ONE GROUP'S OWN RHYTHM, AND IT IS I18's LESSON APPLIED BEFORE THE DEFECT RATHER THAN AFTER.
   `.biztech-composer-tile-body` spaces the groups from their siblings at 16px; nothing spaces a group's
   own heading, radios, tab rows, checkboxes and select from each other — which is exactly the
   `panel-child-gaps=0,0,0,12,12` this panel already measured once, one nesting level down.

   12px rather than 16px, deliberately: these are the members of ONE setting, and spacing them as widely
   as the panel spaces whole controls would read as five unrelated things rather than one group. R5's
   step below the stack's own.

   🔴 DECLARED HERE AND ALSO IN PortalComposerTileDisplayPanel.razor.css, AND THAT DUPLICATION IS THE
   CORRECT ANSWER RATHER THAN A SHORTCUT. Both groups are their own component now, and a scoped rule
   cannot be shared between two scopes. The alternative is a `biztech-*` utility in app.css, which is a
   guardrail file (UtilityClassTests declares the set) and a change no card should make to avoid three
   lines. */
.biztech-composer-group[b-aet0546lzy] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W31 · I18 · "Which types" and "Filters to show" are a heading, a hint and a row of boxes in a bare div, so they sat
   flush against each other; the wrapper carries the 4px gap a field and what is written under it take. */
.biztech-composer-choice-block[b-aet0546lzy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The filter checkboxes are four short words; a column of four wasted the width the group now has. */
.biztech-composer-choice-row[b-aet0546lzy] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
}

/* 🔴 W8-25 · TABS TAKES A COLUMN AND THE OTHER THREE STACK BESIDE IT, AND A BROWSER SAID SO.

   The first arrangement was a 2x2 of the four settings. Their heights are roughly 1.5, 4, 1.5 and 2
   rows, and a grid aligns every row to its tallest cell - so the two short ones sat marooned in the
   middle of their own whitespace and the group read as unfinished rather than as spacious. Reported as
   "unorganized/broken", which is exactly what an unequal 2x2 looks like.

   Tabs is the tall one: a legend and three rows of a checkbox with two ordering buttons. Giving it a
   column of its own and stacking the other three in the first means both columns end within a row of
   each other, which is the thing a grid of unequal cells cannot do.

   One column below sm, for the ladder everything else in this panel follows: at 375px two tracks are
   150px each and "Assigned to me" with two buttons does not fit one. */
.biztech-composer-launcher-grid[b-aet0546lzy] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px 24px;
    align-items: start;
}

@media (min-width: 600px) {
    .biztech-composer-launcher-grid[b-aet0546lzy] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The three short settings, as one column. */
.biztech-composer-launcher-column[b-aet0546lzy] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* 🔴 A SELECT WHOSE LONGEST ANSWER IS "Last 120 days" DOES NOT NEED HALF THE PANEL, AND A BROWSER
   MEASURED THE ONE THAT TOOK IT: 595px of control for a value of nine characters, with the caret
   marooned at the far right edge of a field the eye has to travel to.

   A max rather than a fixed width, so it still shrinks with the column at narrow widths - which is the
   whole reason the launcher grid collapses to one column below 600px. 320px is comfortably past the
   longest label at the body size and on the 4px scale (R5).

   The two date fields on the case list are NOT given this: those are date inputs with a picker button,
   and the platform's native control decides its own comfortable width. */
.biztech-composer-launcher-column [data-tile-launcher-preset][b-aet0546lzy] {
    max-inline-size: 320px;
}

/* One tab: its include box and the two ordering buttons, on one line.

   🔴 NOT I20's CASE, AND WORTH SAYING SO BECAUSE IT LOOKS LIKE IT. That invariant offsets a
   `.biztech-choice` sharing a grid row with a `.biztech-field`, because a field is a label ABOVE a
   control and a checkbox is a box BESIDE a word — so the box would line up with the neighbour's label.
   Here the checkbox's neighbours are two icon buttons, which carry no label block at all, so centring
   is the whole of it. */
.biztech-composer-tab-row[b-aet0546lzy] {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* 🔴 THE NAME TAKES THE SLACK SO THE TWO ARROWS LINE UP DOWN THE COLUMN, AND A BROWSER MEASURED THE
   ROW THAT DID NOT: the buttons sat at x 1025, 957 and 960 on three rows, because each followed a
   label of a different length and nothing took the remaining width. A control column that moves under
   the cursor from row to row is what "disabled at the ends rather than hidden" avoids on the other
   axis, and the same argument applies here.

   min-inline-size: 0 so a long tab label shrinks its own cell rather than pushing the arrows out of
   the panel - UiGridItem's base rule, for the reason it gives about grid and flex children. */
.biztech-composer-tab-name[b-aet0546lzy] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* 🔴 TWO OPTIONS SIDE BY SIDE, NOT STACKED. UiRadioGroup lays its options out in a column, which is
   right for a list of five and wrong for a pair of one-word answers - "Grid" over "List" took two rows
   to say what one says, under a legend longer than both. The legend keeps its own line. */
.biztech-composer-launcher-grid[b-aet0546lzy]  .biztech-choice-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 16px;
}

.biztech-composer-launcher-grid[b-aet0546lzy]  .biztech-choice-group-legend {
    flex-basis: 100%;
}
/* /Components/Portals/PortalComposerChangeList.razor.rz.scp.css */
/* W20-06 · the change list: a bordered panel in flow, one line per change. I18 · containers carry the gaps. */

.biztech-composer-changes[b-uaoku7zn9j] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    min-inline-size: 0;
}

.biztech-composer-changes-list[b-uaoku7zn9j] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

/* W19-11 · rows under hairlines, the line on the left and its action on the right. */
.biztech-composer-changes-list li[b-uaoku7zn9j] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
    padding-block: 8px;
    font-size: var(--biztech-font-body2-size);
}

.biztech-composer-changes-list li + li[b-uaoku7zn9j] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-composer-changes-problem[b-uaoku7zn9j] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--biztech-palette-text-primary);
}

.biztech-composer-changes-problem[b-uaoku7zn9j]  .biztech-icon {
    color: var(--biztech-palette-warning);
}

/* The Undo button's full name for a screen reader, which hears what it undoes; the eye reads the line beside it. */
.biztech-composer-changes-sr[b-uaoku7zn9j] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* W20-06 · I18 · the wrapper carries the gap between its children. */
.biztech-composer-field-group[b-uaoku7zn9j] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerCopyPanel.razor.rz.scp.css */
/*
    W8-03 · F10.17 — the copy panel's two choosers.

    🔴 THIS FILE DECLARES ONE THING, AND WHAT IT DOES NOT DECLARE IS THE INTERESTING HALF. The fieldset's
    border and the legend's padding are app.css's .biztech-choice-group / -legend, written for UiRadioGroup
    - the same element doing the same job one control over. Restating them here is what
    UtilitySpecificityTests refuses: Blazor rewrites a scoped selector as `.x[b-xxxxxxxxxx]`, (0,2,0)
    against a utility class's (0,1,0), so a local `margin: 0` would silently beat every biztech-mb-* a
    caller passed the component while the class stayed visible in the markup.

    Everything else is the seam's too: UiPaper, UiSelect, UiCheckbox, UiButton and the biztech-* spacing
    utilities.

    A literal gap rather than var(--biztech-space-3): there is no spacing token. TokenSufficiencyTests
    catches a var() that resolves to nothing, which paints nothing with no error and no warning, and it
    caught this one.

    R13.1's breakpoints, mobile-first: one column below sm, because two selects side by side at 375px
    leave neither wide enough to read a portal's name in. PortalCompare.razor.css makes the same choice
    for the same pair of controls.
*/

/* 🔴 W0-75 · A GRID, FOR THE REASON PortalCompare.razor.css SPELLS OUT AT LENGTH: the equal-halves
   rule was `.biztech-copy-choosers > *`, whose last compound is what carries the scope attribute, and
   the children are UiSelect's roots. It matched nothing, so the two choosers were content-sized and did
   jump as a portal's name changed length. Equal grid tracks need no child rule, so there is nothing left
   to reach an element this component does not own. */
.biztech-copy-choosers[b-8vzxbrlhu1] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
}

@media (min-width: 600px) {
    .biztech-copy-choosers[b-8vzxbrlhu1] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* The checkboxes stack; the fieldset's own reset is the seam's, above. */
.biztech-copy-sections[b-8vzxbrlhu1] {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
/* /Components/Portals/PortalComposerDraftNotice.razor.rz.scp.css */
/* W19-11 · the saved-draft bar: a glyph in a tinted circle beside two lines of text, on a quiet tint with no frame.
   I18 · the bar carries the gap between its glyph and its text. */
.biztech-composer-draft[b-1mns4zonsa] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 16px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
}

.biztech-composer-draft-mark[b-1mns4zonsa] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 14%, transparent);
    color: var(--biztech-palette-primary);
}

.biztech-composer-draft-text[b-1mns4zonsa] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The lead sentence on a line of its own, in body ink and weight. */
.biztech-composer-draft-lead[b-1mns4zonsa] {
    display: block;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    font-weight: 600;
    color: var(--biztech-palette-text-primary);
}

.biztech-composer-draft-also[b-1mns4zonsa] {
    display: block;
    color: var(--biztech-palette-warning);
}
/* /Components/Portals/PortalComposerGridPanel.razor.rz.scp.css */
/* W16-12 · 2 — the grid editor's own rules.

   🔴 EVERY SELECTOR HERE NAMES A CLASS THIS COMPONENT'S OWN MARKUP CARRIES (I19). A scoped rule is
   stamped on the selector's LAST compound, so a rule for a class that appears only in a child component
   never lands - no error, no warning, and a class with no effective rule renders exactly like a class
   with none. ScopedStyleReachTests is the sweep that says so. The two number fields are reached through
   their own WRAPPERS rather than through UiNumberField's root, for the same reason
   PortalComposerTileGeometryPanel reaches its four through grid tracks.

   I18 · four containers, four gaps, and no child carries a margin. biztech-pa-* spaces a panel from its
   border and nothing spaces its contents from each other - W0-75 measured the tile panel at
   `panel-child-gaps=0,0,0,12,12` for exactly that reason, and PortalComposerLauncherPanel shipped the
   same absence once. */
.biztech-grid-editor[b-szth8hm7h1] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-grid-editor-heading[b-szth8hm7h1] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.biztech-grid-editor-fields[b-szth8hm7h1] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* TWO FIELDS, TWO TRACKS, AND THEY STAY TWO AT EVERY WIDTH. The geometry row one panel down drops from
   four tracks to two below sm because four 69px tracks give every label three lines; two tracks of a
   375px panel are about 170px each, which holds "Columns" and a spinner comfortably. There is no width
   at which stacking these two buys anything.

   minmax(0, 1fr) rather than 1fr - R13.8's grid trap: a track's default minimum is its content's
   minimum, and a spinner plus two digits would push the track past the panel.

   align-items: end, which is load-bearing when one box is complaining: a refusal renders inside
   UiNumberField beneath its input, so the two controls would otherwise sit at different heights.
   Bottom-aligned they share an edge whatever the message did - the geometry row's own reasoning. */
.biztech-grid-editor-row[b-szth8hm7h1] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    align-items: end;
}
/* /Components/Portals/PortalComposerHeaderActions.razor.rz.scp.css */
/* W19-11 · the composer's header row: the More menu, the change count, Preview and Publish (W19-23: the save state moved
   beside the title, PortalComposerSaveStatus). Moved
   with the markup out of PortalComposer.razor.css; every rule ends on this component's own markup (I19). */

/* The header's actions: one group that wraps rather than running past the landmark at 375 and 768 (R13.7). */
.biztech-composer-actions[b-tqkl34qwzj] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    min-inline-size: 0;
}

/* W28-18 · D6: why a press on Publish was refused, in a sentence beside it - in the error ink, as a field's refusal is
   (§2a C1). It wraps rather than widening the row (I19: this component's own span). */
.biztech-composer-publish-why[b-tqkl34qwzj] {
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-error);
    max-inline-size: 22rem;
    text-align: end;
}
/* /Components/Portals/PortalComposerHeadingChoice.razor.rz.scp.css */
/* W31 · I18 · I19 · the heading choice's wrapper carried biztech-composer-field with no rule in this component's scope,
   so the switch and what is written under it sat flush. A scoped rule cannot be shared between two scopes, so the class
   is declared here as PortalComposerOpensGroup.razor.css declares it. */
.biztech-composer-field[b-rc67kouyrt] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerHoldsGroup.razor.rz.scp.css */
/* W20-06 · the portal's footer pages: a heading and the list under it. I18 · the block carries its own gap, as the
   setting group's body carries the gap between this block and its siblings. */

.biztech-composer-holds-pages[b-39my7xc0hi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* The footer pages: rows under hairlines inside one quiet frame, each row a link to that page's editor. */
.biztech-composer-holds-page-list[b-39my7xc0hi] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-inline-start: 0;
    overflow: hidden;
    list-style: none;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-composer-holds-page-list li + li[b-39my7xc0hi] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-composer-holds-page[b-39my7xc0hi] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    color: var(--biztech-palette-text-secondary);
    text-decoration: none;
}

.biztech-composer-holds-page:hover[b-39my7xc0hi] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 4%, transparent);
}

.biztech-composer-holds-page-text[b-39my7xc0hi] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-composer-holds-page-title[b-39my7xc0hi] {
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-composer-holds-page-kind[b-39my7xc0hi] {
    font-size: var(--biztech-font-caption-size);
}

/* W20-06 · I18 · the wrapper carries the gap between its children. */
.biztech-composer-field-group[b-39my7xc0hi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W19-11 · a link's card: a glyph in a tinted circle beside its type and one line saying it holds nothing. */
.biztech-composer-holds-link[b-39my7xc0hi] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 4%, var(--biztech-palette-surface));
}

.biztech-composer-holds-link-mark[b-39my7xc0hi] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
}

.biztech-composer-holds-link-text[b-39my7xc0hi] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-composer-holds-link-title[b-39my7xc0hi] {
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
}
/* /Components/Portals/PortalComposerIntakeGroup.razor.rz.scp.css */
/*
    W25-02 · the Submissions group's own spacing (I18). Its column and gap are declared here, with the 8px every composer
    field group uses, because the other groups' rules are scoped to their own components and do not reach this one.
    The assignee block, and the button with its caption, space their own children the same way. Logical properties, no
    colour.
*/

.biztech-composer-field-group[b-11fll0a41r] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W25 walk · I18 · the keys an app must send: a sentence and what is listed under it (4px), carried by the wrapper's gap,
   as PortalComposerOpensGroup's field does. */
.biztech-composer-field[b-11fll0a41r] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* The keys are a list because how many there are is information, not bullets in prose. The wrapper's gap spaces them
   from the sentence above, so the browser's block margin would sit on top of it; the indent is kept. A declared reset
   (UtilitySpecificityTests). */
.biztech-intake-keys[b-11fll0a41r] {
    margin: 0;
}

[data-intake-assignee][b-11fll0a41r],
[data-intake-assign][b-11fll0a41r] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Portals/PortalComposerItemEditor.razor.rz.scp.css */
/* W20-06 · the six groups, stacked. I18 · the editor carries the gap between them; no group a margin. */
.biztech-composer-editor[b-w1q7z1pla9] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerItemKey.razor.rz.scp.css */
/* W20-04 · the key field, its sentence and its button, one under the other. The spacing is the container's
   (I18) - a gap, never a margin per child - and the button sits in its own row so it keeps its own width. */
.biztech-composer-item-key[b-18ns8mucdn] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
}

/* W19-11 · the box takes the row and Rename keeps its width, its foot on the box's line. */
.biztech-composer-item-key-row[b-18ns8mucdn] {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-composer-item-key-box[b-18ns8mucdn] {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-composer-item-key-action[b-18ns8mucdn] {
    flex: none;
}
/* /Components/Portals/PortalComposerItemList.razor.rz.scp.css */
/* W20-06 · the Holds group's list of what an item holds. W19-11 · rows under hairlines inside one quiet frame, each a
   whole-row link - the footer pages' list. I18 · the list carries the spacing; no item a margin. */

.biztech-composer-item-list[b-5j0ibsciay] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-inline-start: 0;
    overflow: hidden;
    list-style: none;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-composer-item-list li + li[b-5j0ibsciay] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-composer-item-list-row[b-5j0ibsciay] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    color: var(--biztech-palette-text-secondary);
    text-decoration: none;
}

.biztech-composer-item-list-row:hover[b-5j0ibsciay] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 4%, transparent);
}

/* The outline's section colour, so a row reads as the same thing it is in the outline. */
.biztech-composer-item-list-mark[b-5j0ibsciay] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-secondary);
}

.biztech-composer-item-list-text[b-5j0ibsciay] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-inline-size: 0;
}

.biztech-composer-item-list-title[b-5j0ibsciay] {
    color: var(--biztech-palette-text-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
    overflow-wrap: anywhere;
}

.biztech-composer-item-list-what[b-5j0ibsciay] {
    font-size: var(--biztech-font-caption-size);
}
/* /Components/Portals/PortalComposerJsonChoices.razor.rz.scp.css */
/* W22-07 · D26 · a held edit's choices: the heading, then the shared choice list, spaced by this stack (I18). */

.biztech-composer-json-choices[b-lg1e0pw9uq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Portals/PortalComposerJsonProblems.razor.rz.scp.css */
/* W20-07 · the JSON view's problem list. Tokens only (R3.1); I18 · the list carries its gap. Empty, it takes no height,
   so the view's own gap does not double under the editor. */

.biztech-composer-json-problems[b-trzkm8b3n2] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    font-size: var(--biztech-font-body2-size);
}

.biztech-composer-json-problems:empty[b-trzkm8b3n2] {
    display: none;
}

.biztech-composer-json-problems li[b-trzkm8b3n2] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
}

/* The word beside the gutter's colour (R3.3): "Error" or "Warning", never colour alone. */
.biztech-composer-json-severity[b-trzkm8b3n2] {
    font-weight: var(--biztech-font-subtitle2-weight);
}
/* /Components/Portals/PortalComposerJsonView.razor.rz.scp.css */
/* W20-07 · the JSON view: a scope row, a toolbar, the status line, the editor, and the problems under it. Tokens only
   (R3.1). I18 · the view carries its gap, so no child sets a margin to space itself. The editor's own box is
   UiCodeEditor's, and nothing here reaches inside it (I19). */

.biztech-composer-json[b-fnxjpbfv5e] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* Wraps at 375 rather than pushing the landmark (R13.8): four buttons and a caption do not fit one narrow line. */
.biztech-composer-json-actions[b-fnxjpbfv5e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding: 4px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 4%, var(--biztech-palette-surface));
}

/* Pushes Compare to the strip's far end, and collapses when the strip wraps. */
.biztech-composer-json-actions-spacer[b-fnxjpbfv5e] {
    flex: 1 1 0;
}

/* Empty while there is nothing to say - the region exists before there is (R12.6a) - so it takes no height then. */
.biztech-composer-json-status[b-fnxjpbfv5e],
.biztech-composer-json-cursor[b-fnxjpbfv5e] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-composer-json-status:empty[b-fnxjpbfv5e],
.biztech-composer-json-cursor:empty[b-fnxjpbfv5e] {
    display: none;
}
/* /Components/Portals/PortalComposerLinkFields.razor.rz.scp.css */
/*
    W25-04 · the link fields' own spacing (I18). The class names a group the composer's other field groups use, but their
    rules are scoped to their own components and do not reach this one (I19) - so the column and its gap are declared
    here, with the 8px every composer field group uses. Logical properties, no colour.
*/

.biztech-composer-field-group[b-hl3ttfs538] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerLogoField.razor.rz.scp.css */
/* W20-09 · the composer's logo field. W19-11 · PortalComposerCardFile draws the logo and the library; this sheet spaces
   the field and keeps the upload box to a sensible width under the buttons. */
.biztech-composer-logo[b-ldtpem05wq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-composer-logo-upload[b-ldtpem05wq] {
    max-inline-size: 24rem;
}
/* /Components/Portals/PortalComposerMeetingFields.razor.rz.scp.css */
/* W26-03 · I18 · the meeting address and what is written under it (4px): the wrapper carries the gap. The Page group's own
   rule cannot reach this component's markup (I19), so the rule is declared here, as each composer group declares its own. */
.biztech-composer-field[b-en0xczyq35] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerNote.razor.rz.scp.css */
/* W19-11 · a composer note. I19 · every rule ends on this component's markup; the lead's weight is the caller's span,
   reached with ::deep from the body this component owns. */
/* The mark centred on the words beside it, one line or several: lined up with the first line instead, it sat off-centre
   whenever the text and the 32px mark were not the same height. */
.biztech-composer-note[b-6wtuiozs3i] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-info) 8%, var(--biztech-palette-surface));
}

.biztech-composer-note-caution[b-6wtuiozs3i] {
    background: color-mix(in srgb, var(--biztech-palette-warning) 10%, var(--biztech-palette-surface));
}

.biztech-composer-note-mark[b-6wtuiozs3i] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-info) 14%, transparent);
    color: var(--biztech-palette-info);
}

.biztech-composer-note-caution .biztech-composer-note-mark[b-6wtuiozs3i] {
    background: color-mix(in srgb, var(--biztech-palette-warning) 16%, transparent);
    color: var(--biztech-palette-warning);
}

.biztech-composer-note-body[b-6wtuiozs3i] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-composer-note-body[b-6wtuiozs3i]  .biztech-composer-note-title {
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
}

.biztech-composer-note-action[b-6wtuiozs3i] {
    display: flex;
}

/* A caller's lead and its sentence, stacked: the caller's span, reached from the body this component owns. */
.biztech-composer-note-body[b-6wtuiozs3i]  .biztech-composer-note-text {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Portals/PortalComposerOpensGroup.razor.rz.scp.css */
/* W20-06 · PortalComposerOpensGroup's own spacing - a scoped rule reaches only this component's markup (I19). */

/* W20-06 · I18 · a field and what is written under it (4px), or a group of them (8px): the wrapper carries the gap. */
.biztech-composer-field[b-khc2ehik51] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-composer-field-group[b-khc2ehik51] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W19-11 · the typed address's note: a glyph and one or two lines of secondary text, with no frame. */
.biztech-composer-opens-note[b-khc2ehik51] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}

.biztech-composer-opens-note[b-khc2ehik51]  .biztech-icon {
    flex: none;
    inline-size: 16px;
    block-size: 16px;
    color: var(--biztech-palette-info);
}
/* /Components/Portals/PortalComposerOutline.razor.rz.scp.css */
/* W20-06 · the outline.

   I19 · every selector ends on markup this component writes. The filter field, the icon buttons and UiText are
   other components' roots and are sized by their tracks, never reached into. I18 · lists and rows carry their own
   gaps. Borders and colour come from --biztech-* only; no prefers-color-scheme (I16).

   🔴 BELOW md THE OUTLINE IS A DISCLOSURE ABOVE THE EDITOR; AT md AND ABOVE IT IS ALWAYS SHOWN. The summary is
   hidden there, so nothing can fold it, and biztech-composer.js only ever folds it on a narrow screen. */

.biztech-outline-fold[b-al11qpj7ry] {
    min-inline-size: 0;
}

.biztech-outline-fold-summary[b-al11qpj7ry] {
    cursor: pointer;
    font-weight: 600;
    padding-block: 8px;
}

@media (min-width: 960px) {
    .biztech-outline-fold-summary[b-al11qpj7ry] {
        display: none;
    }
}

.biztech-outline[b-al11qpj7ry] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-outline-tree[b-al11qpj7ry] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    min-inline-size: 0;
}

/* W19-11 · THE LEVELS, BY INDENT AND A GUIDE LINE. A 12px step with nothing else marking it left a tile, its sections
   and a group's members reading as one ragged list. The tiles sit flush under the portal, which heads the outline;
   each list under a tile or a group is indented to its parent's glyph and hangs from a hairline guide, so where a
   level starts and stops is drawn rather than inferred. */
.biztech-outline-tiles[b-al11qpj7ry] {
    padding-block-start: 4px;
}

/* The guide stands under the parent's glyph: a tile's at 40px (its chevron slot, then its row's own 8px), a section's
   at 16px. */
.biztech-outline-tiles .biztech-outline-tree[b-al11qpj7ry] {
    margin-inline-start: 16px;
    padding-inline-start: 4px;
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-outline-tiles .biztech-outline-children > .biztech-outline-tree[b-al11qpj7ry] {
    margin-inline-start: 40px;
}

/* An add under a tile lines up with that tile's sections. */
.biztech-outline-tile > .biztech-outline-add[b-al11qpj7ry] {
    padding-inline-start: 40px;
}

/* A tile's row leaves room at its start for the chevron that opens its sections. */
.biztech-outline-tile[b-al11qpj7ry] {
    position: relative;
}

.biztech-outline-tile > .biztech-outline-row[b-al11qpj7ry] {
    padding-inline-start: 32px;
}

.biztech-outline-row[b-al11qpj7ry] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 4px 8px;
    border-radius: var(--biztech-radius-default);
    min-inline-size: 0;
}

.biztech-outline-row:hover[b-al11qpj7ry] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 4%, var(--biztech-palette-surface));
}

/* The selected row: a tint and its title in the heavier weight - the colour is not the only channel, aria-current
   says it too. W19-11 · the inset bar it also drew sat beside the row's own level marker, two bars on one edge. */
.biztech-outline-row-selected[b-al11qpj7ry],
.biztech-outline-row-selected:hover[b-al11qpj7ry] {
    background: var(--biztech-palette-primary-container);
}

.biztech-outline-row-selected .biztech-outline-text a[b-al11qpj7ry] {
    font-weight: 600;
}

/* W19-11 · each level's glyph in its level's colour - the portal a house, a tile a grid, a section a page, a group a
   folder, a member a file - where a 4px bar of four near colours was the only mark of a level. The level is also a
   hidden word in the link (R12.7). */
.biztech-outline-marker[b-al11qpj7ry] {
    display: inline-flex;
    flex: none;
    padding-block-start: 2px;
}

.biztech-outline-marker[b-al11qpj7ry]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
}

.biztech-outline-marker-portal[b-al11qpj7ry],
.biztech-outline-marker-page[b-al11qpj7ry] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-outline-marker-tile[b-al11qpj7ry] {
    color: var(--biztech-palette-primary);
}

.biztech-outline-marker-section[b-al11qpj7ry] {
    color: var(--biztech-palette-secondary);
}

.biztech-outline-marker-child[b-al11qpj7ry] {
    color: var(--biztech-palette-tertiary);
}

/* The portal heads the outline: its row is the title over the tiles, a hairline under it. */
[data-outline-row="portal"] > .biztech-outline-row[b-al11qpj7ry] {
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    border-end-start-radius: 0;
    border-end-end-radius: 0;
}

[data-outline-row="portal"] > .biztech-outline-row .biztech-outline-text a[b-al11qpj7ry] {
    font-weight: 600;
}

.biztech-outline-text[b-al11qpj7ry] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* W19-11 · two lines at most: a tile titled with a whole sentence ran to six lines and pushed its controls apart.
   The title attribute and the editor's h1 carry the rest. */
.biztech-outline-text a[b-al11qpj7ry] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
    overflow-wrap: anywhere;
}

.biztech-outline-text a:hover[b-al11qpj7ry] {
    text-decoration: underline;
}

.biztech-outline-summary[b-al11qpj7ry] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 8px;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    overflow-wrap: anywhere;
}

.biztech-outline-badge[b-al11qpj7ry] {
    display: inline-flex;
    align-items: center;
}

.biztech-outline-badge[b-al11qpj7ry]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
}

/* An unpublished change: a small word in a tinted pill, which says what it is where a dot did not. */
.biztech-outline-badge--changed[b-al11qpj7ry] {
    padding-inline: 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
    font-weight: 600;
}

.biztech-outline-badge--problem[b-al11qpj7ry] {
    color: var(--biztech-palette-warning);
}

.biztech-outline-badge--narrowed[b-al11qpj7ry] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-outline-actions[b-al11qpj7ry] {
    display: flex;
    flex: none;
    gap: 2px;
}

/* W19-11 · the row's one menu trigger sits in a slot of its own at the row's end, in flow, so it never covers the
   title. With a mouse it shows on the row being pointed at, focused or selected (opacity, not display, so the slot
   holds and a keyboard reaches it); a touch screen has no hover, so there it always shows. */
@media (hover: hover) and (pointer: fine) {
    .biztech-outline-actions[b-al11qpj7ry] {
        opacity: 0;
        transition: opacity var(--biztech-motion-duration, 120ms) ease;
    }

    .biztech-outline-row:hover .biztech-outline-actions[b-al11qpj7ry],
    .biztech-outline-row:focus-within .biztech-outline-actions[b-al11qpj7ry],
    .biztech-outline-row-selected .biztech-outline-actions[b-al11qpj7ry] {
        opacity: 1;
    }
}

/* W19-11 · a tile's sections open from a chevron at the start of the tile's row: the summary is lifted out of the
   flow onto the slot the row leaves for it, and turns a quarter when open. */
.biztech-outline-children > summary[b-al11qpj7ry] {
    position: absolute;
    inset-block-start: 4px;
    inset-inline-start: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 24px;
    block-size: 24px;
    border-radius: 999px;
    list-style: none;
    cursor: pointer;
    color: var(--biztech-palette-text-secondary);
}

.biztech-outline-children > summary[b-al11qpj7ry]::-webkit-details-marker {
    display: none;
}

.biztech-outline-children > summary:hover[b-al11qpj7ry] {
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 8%, transparent);
    color: var(--biztech-palette-text-primary);
}

.biztech-outline-children > summary[b-al11qpj7ry]  .biztech-icon {
    transition: transform var(--biztech-motion-duration, 120ms) ease;
}

.biztech-outline-children[open] > summary[b-al11qpj7ry]  .biztech-icon {
    transform: rotate(90deg);
}

.biztech-outline-children > .biztech-outline-tree[b-al11qpj7ry] {
    margin-block-start: 2px;
}

.biztech-outline-add[b-al11qpj7ry] {
    padding: 2px 8px 2px 16px;
}

/* An add is a quiet action in the list's own type, with a glyph where a literal "+" was. */
.biztech-outline-add a[b-al11qpj7ry] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px;
    border-radius: 999px;
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
    text-decoration: none;
}

.biztech-outline-add a:hover[b-al11qpj7ry] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 8%, transparent);
}

.biztech-outline-pages[b-al11qpj7ry] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    padding-block-start: 12px;
}

/* Present for a screen reader and occupying no space - the clip idiom, never display:none. */
.biztech-outline-sr[b-al11qpj7ry] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* W20-07 · D16 · the JSON view's cursor is in this row. W19-11 · a worded pill on the summary line in the tertiary
   colour, which is not the selection's, where an inset bar on the rounded row drew a dark bracket. */
.biztech-outline-badge--cursor[b-al11qpj7ry] {
    padding-inline: 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-tertiary) 14%, transparent);
    color: var(--biztech-palette-tertiary);
    font-weight: 600;
}
/* /Components/Portals/PortalComposerPageGroup.razor.rz.scp.css */
/* W20-06 · the Page group's three checkboxes, two-up above md where each hint has room to read.
   I19 · the selector ends on this file's markup; the checkboxes' own roots are UiCheckbox's, so the grid track
   sizes them and no rule reaches into them. */

.biztech-composer-page-flags[b-tj7xs6vohu] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

@media (min-width: 960px) {
    .biztech-composer-page-flags[b-tj7xs6vohu] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* W20-06 · I18 · a field and what is written under it (4px), or a group of them (8px): the wrapper carries the gap. */
.biztech-composer-field[b-tj7xs6vohu] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-composer-field-group[b-tj7xs6vohu] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* W19-11 · the portal's Page group in titled blocks: each a column carrying its own gap (I18), the second and later
   under a hairline, so where one topic ends is drawn. */
.biztech-composer-page-blocks[b-tj7xs6vohu] {
    display: flex;
    flex-direction: column;
    gap: 24px;
    min-inline-size: 0;
}

.biztech-composer-page-block[b-tj7xs6vohu] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

.biztech-composer-page-block + .biztech-composer-page-block[b-tj7xs6vohu] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    padding-block-start: 24px;
}
/* /Components/Portals/PortalComposerPlacementGroup.razor.rz.scp.css */
/* W20-06 · the four grid fields, moved from PortalComposerTileGeometryPanel with their rule.

   Two by two below sm, four across above: a field is a label above a control, and at ~360px "Rows tall" and
   "Columns wide" wrap to two lines while "Row" and "Column" do not - so the row aligns at the END, where every
   control shares an edge whatever its label did. minmax(0, 1fr) is R13.8's grid trap. I19 · the selector ends on
   this file's own markup; each data-geometry-* wrapper holds one field and is sized by its track. */
.biztech-composer-geometry[b-2ep18lfw87] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    align-items: end;
}

@media (min-width: 600px) {
    .biztech-composer-geometry[b-2ep18lfw87] {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}
/* /Components/Portals/PortalComposerPreviewFrame.razor.rz.scp.css */
/* 🔴 W1b-06 · F2.24 · W20-06 · the preview frame in the editor's space.

   NO overflow-x: hidden ANYWHERE IN THIS FILE (the composer's ## Do not): it would hide the one defect the
   preview exists to reveal. The scroll region below scrolls; it does not clip. */

.biztech-composer-preview[b-5nr24cpp45] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* The width group and the pop-out link wrap together, aligned at the end: the radio group carries a legend and a
   row where the link carries a caption, so aligning their tops would leave the shorter one floating. */
.biztech-composer-preview-controls[b-5nr24cpp45] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px 24px;
}

.biztech-composer-preview-popout[b-5nr24cpp45] {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.biztech-composer-preview-popout a[b-5nr24cpp45] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--biztech-palette-primary);
    font-weight: 600;
    text-decoration: none;
}

.biztech-composer-preview-popout a:hover[b-5nr24cpp45] {
    text-decoration: underline;
}

/* 🔴 D9 · THE REGION SCROLLS AT THE CHOSEN WIDTH. overflow-x: auto rather than hidden: the frame keeps its true
   viewport and the reader pans to see it. It is focusable and named in the markup (R12.2). */
.biztech-composer-preview-scroll[b-5nr24cpp45] {
    overflow-x: auto;
    min-inline-size: 0;
}

/* A border and a height. The border is what says where the previewed document ends - outline, the role held to 3:1
   against both grounds (R3.6). The height is fixed: an iframe cannot size itself to a document without script
   measuring across the boundary. No max-inline-size: the width is the width (D9). */
.biztech-composer-preview-frame[b-5nr24cpp45] {
    display: block;
    block-size: 70vh;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background-color: var(--biztech-palette-surface);
}

/* W19-11 · Fit: the frame is the region's width, so nothing scrolls sideways - its 1px border counted inside it, or
   the two pixels alone would scroll. */
.biztech-composer-preview-frame-fit[b-5nr24cpp45] {
    box-sizing: border-box;
    inline-size: 100%;
}
/* /Components/Portals/PortalComposerSaveStatus.razor.rz.scp.css */
/* W19-23 · the autosave's state beside the composer's title. Every rule ends on this component's own markup (I19). */

/* The save state's region is always present (R12.6a) and takes no room while it has nothing to say. */
.biztech-composer-saved.biztech-composer-saved--none[b-w7uj1l6k4u] {
    display: none;
}

/* The autosave's state: a dot coloured by state beside the word (the word is what is read). W19-11 · plain text, with
   no pill: a pill read as one more button. */
.biztech-composer-saved[b-w7uj1l6k4u] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
    white-space: nowrap;
}

.biztech-composer-saved-dot[b-w7uj1l6k4u] {
    inline-size: 8px;
    block-size: 8px;
    border-radius: 999px;
    background: var(--biztech-palette-success);
}

.biztech-composer-saved--saving .biztech-composer-saved-dot[b-w7uj1l6k4u],
.biztech-composer-saved--pending .biztech-composer-saved-dot[b-w7uj1l6k4u] {
    background: var(--biztech-palette-warning);
}

.biztech-composer-saved--stopped .biztech-composer-saved-dot[b-w7uj1l6k4u] {
    background: var(--biztech-palette-error);
}
/* /Components/Portals/PortalComposerSectionReferenceFields.razor.rz.scp.css */
/* 🔴 W1b-10 · I18 - THE FIELDS OF ONE REFERENCE ARE SPACED BY THEIR CONTAINER, AND THEY WERE NOT
   SPACED AT ALL. A destination section now draws up to three labelled controls in this wrapper - the
   page picker, then "Which tile's page" or "Which case type" - and the file types draw a search box over
   their select. The wrapper had no display rule and .biztech-field carries no outer margin, so they
   stacked touching: W0-75's "controls touching inside a padded panel", measured then as
   panel-child-gaps=0.

   The gap is the container's (I18), never a margin per child. The attribute is this component's own
   markup, so the scope reaches it (I19), and it composes with PortalComposerSectionPanel's
   ::deep [data-section-reference] { flex: 1 1 24rem }, which sizes this wrapper as an item and says
   nothing about its children. 12px is the composer's own step between controls. */
[data-section-reference][b-z95ns6zdvt] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
/* /Components/Portals/PortalComposerSettingGroup.razor.rz.scp.css */
/* W20-06 · one setting group: a bordered section in flow - borders rather than shadows for panes in flow
   (the design direction) - its trigger, and its body.

   I19 · every selector ends on markup this component writes. The trigger's own root is UiButton's, so it is
   reached with ::deep on the class this file passes it, never with `> *`. */

.biztech-composer-setting[b-945pcp68v2] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    min-inline-size: 0;
}

/* The whole row is the target, and its label wraps rather than pushing the pane sideways. */
.biztech-composer-setting[b-945pcp68v2]  .biztech-composer-setting-trigger {
    inline-size: 100%;
    justify-content: flex-start;
    text-align: start;
    min-block-size: 56px;
    block-size: auto;
    padding-block: 8px;
    padding-inline: 16px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    white-space: normal;
}

.biztech-composer-setting-name[b-945pcp68v2] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
    min-inline-size: 0;
}

/* I18 · the body's one gap carrier. */
.biztech-composer-setting-body[b-945pcp68v2] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    min-inline-size: 0;
}

/* The body is toggled with `hidden`, and the display above outranks the user agent's [hidden] - so this puts it back. */
.biztech-composer-setting-body[hidden][b-945pcp68v2] {
    display: none;
}

/* The group's number and name carry the heading's weight inside the button, which sets its own type. */
.biztech-composer-setting-title[b-945pcp68v2] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font: inherit;
    font-weight: 600;
}

/* W19-11 · the group's number in a small tinted circle, the step mark the import page uses, rather than a bare
   digit run into the name. The space after it stays in the markup, so the heading still reads "2 Opens". */
.biztech-composer-setting-number[b-945pcp68v2] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 24px;
    block-size: 24px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-caption-size);
}
/* /Components/Portals/PortalComposerSuits.razor.rz.scp.css */
/* W31-06 · P10 · the Suits line can hold two sentences (who the screen suits, and that v1's Presentations page is Cases);
   they stack as lines with the container's gap between them rather than running together. */
[data-portal-destination-suits][b-nyc2fdinoo] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Portals/PortalComposerTextWithPreview.razor.rz.scp.css */
/* W19-11 · a formatted text box's title and its Write / Preview toggle on one row. I19 · the seam's controls are reached
   only through ::deep from wrappers this component writes. */
.biztech-text-with-preview-head[b-eoyxm28flj] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-text-with-preview-title[b-eoyxm28flj] {
    font-weight: 600;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

/* The toggle's legend and the box's label, present for a screen reader and occupying no space - the clip idiom. */
.biztech-text-with-preview-views[b-eoyxm28flj]  .biztech-choice-group-legend,
.biztech-text-with-preview-box[b-eoyxm28flj]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* W27-06 · the box and its caption, and the warnings, each a column at the scale's 4px step (I18: the gap is the
   container's, never a child's margin), so the caption sits with the box it describes. */
.biztech-text-with-preview-box[b-eoyxm28flj],
.biztech-text-with-preview-live[b-eoyxm28flj] {
    display: grid;
    gap: 4px;
}

/* Under the HTML box: the allowed tags in quiet type, and what Publish will remove or refuse in the warning ink. */
.biztech-text-with-preview-caption[b-eoyxm28flj],
.biztech-text-with-preview-warning[b-eoyxm28flj] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}

.biztech-text-with-preview-caption[b-eoyxm28flj] {
    color: var(--biztech-palette-text-secondary);
}

/* The ink stays the primary text role (4.5:1 in both themes); the warning role marks the edge, so colour is never the
   only signal (R3.3) - the sentence says what happens. */
.biztech-text-with-preview-warning[b-eoyxm28flj] {
    padding-inline-start: 8px;
    border-inline-start: 4px solid var(--biztech-palette-warning);
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
}
/* /Components/Portals/PortalComposerTilePreview.razor.rz.scp.css */
/* W16-11 · 3 — the frame's own stack, for the arms that are not a tile page.

   PortalTilePageBody brings its own layout; a named destination is a heading and one or two short
   paragraphs, and nothing spaced them. I18: the space between siblings belongs to the CONTAINER as a
   gap, never to each child as a margin - "the two add up", which is the defect this panel's own
   ancestors have already paid for twice.

   16px, which is the step R5 gives a block of prose under a heading - the same figure
   .biztech-composer-tile-body uses for the groups it stacks. */
.biztech-composer-destination[b-tpejy6u4bx] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
/* /Components/Portals/PortalComposerUnavailable.razor.rz.scp.css */
/* W20-06 · PortalComposerUnavailable's own spacing - a scoped rule reaches only this component's markup (I19). */

/* W20-06 · I18 · the wrapper carries the gap between its children. */
.biztech-composer-field[b-2j8anh6om7] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerWhoGroup.razor.rz.scp.css */
/* W20-06 · the people "Who sees it" names, and the people a search found. I18 · the containers carry the gaps. */

.biztech-composer-who[b-zgmlgzi790] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* W19-11 · people as rows in one framed list under hairlines, the footer pages' list, where a loose stack of lines put
   each name and its button far apart. */
.biztech-composer-who-list[b-zgmlgzi790] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-composer-who-list li[b-zgmlgzi790] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
    padding: 8px 12px;
    min-inline-size: 0;
}

.biztech-composer-who-list li + li[b-zgmlgzi790] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-composer-who-person[b-zgmlgzi790] {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
}

.biztech-composer-who-name[b-zgmlgzi790] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-composer-who-email[b-zgmlgzi790] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    overflow-wrap: anywhere;
}

/* W20-06 · I18 · the wrapper carries the gap between its children. */
.biztech-composer-field[b-zgmlgzi790] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}
/* /Components/Portals/PortalComposerWhoStatus.razor.rz.scp.css */
/* W19-11 · the status card: a glyph in a tinted circle, a bold line saying who sees it, what naming does, and the note
   that it is not staged. Tinted primary once anybody is named, so a narrowed item reads differently at a glance. */
.biztech-composer-who-status[b-5cbn7egru0] {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 4%, var(--biztech-palette-surface));
}

.biztech-composer-who-status-narrowed[b-5cbn7egru0] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 6%, var(--biztech-palette-surface));
}

.biztech-composer-who-status-mark[b-5cbn7egru0] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
}

.biztech-composer-who-status-text[b-5cbn7egru0] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-composer-who-status-title[b-5cbn7egru0] {
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
}

.biztech-composer-who-status-note[b-5cbn7egru0] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--biztech-font-caption-size);
}

.biztech-composer-who-status-note[b-5cbn7egru0]  .biztech-icon {
    inline-size: 16px;
    block-size: 16px;
    color: var(--biztech-palette-warning);
}
/* /Components/Portals/PortalEmbeddedDestination.razor.rz.scp.css */
/*
    W1b-09 · B2 · the frame a tile's typed address is drawn in, on the page that tile opens.

    🔴 EmbeddedPageSection.razor.css's RULE, NOT A SECOND OPINION ABOUT FRAMES. Every declaration below
    is that sheet's, and its reasoning holds unchanged one level up:

      aspect-ratio rather than a height, because a frame with no height collapses to 150px - the HTML
      default for a replaced element, which is not a decision anybody made - and a fixed height clips a
      partner's page on a phone. Legacy's own figure is a hard 959 x 743px
      (Views/Home/GenericIframeUI.cshtml:21, :31), which is the non-responsive shape this replaces.

      min-block-size, because a ratio alone is not enough at 375px: 16/9 of a 343px content width is
      193px, which is not enough of somebody's page to be worth framing. 320px is a multiple of the 4px
      base unit and the width the narrowest supported viewport gives the content, so a frame is never
      shorter than the page is wide.

      No border, because a frame is not a control. The radius is the palette's own so the framed
      document does not overhang the surface's corners.

    🔴 A SECOND SHEET RATHER THAN A SHARED CLASS, AND I19 IS WHY. A scoped rule reaches THIS component's
    own markup and nothing else, and the compound Blazor stamps is the selector's LAST one - so naming
    .biztech-portal-embed-frame here would match nothing at all, silently, because that class appears in
    EmbeddedPageSection's markup rather than in this file's. No error, no warning, and a class with no
    effective rule renders exactly like a class with none. ScopedStyleReachTests is the sweep that
    refuses it.

    NO COLOUR, which PortalStyleSheetTests' hex sweep requires of every sheet under Components/ - and
    there is nothing to declare: what paints inside this box is somebody else's document.

    LOGICAL PROPERTIES, on PortalCard's and PortalSectionThumbnail's line, which is what lets the
    render suites ban the string `height` outright as R13.3's container-height check.
*/

.biztech-portal-tile-embed-frame[b-e8770rskyd] {
    aspect-ratio: 16 / 9;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    box-sizing: border-box;
    display: block;
    inline-size: 100%;
    min-block-size: 320px;
}

/* The frame and its way out, 12px apart through the gap (I18). The way out was an unstyled link in the browser's own
   blue flush under the frame; it is the portal's pill, the shape the meeting link takes, so it reads as the action
   it is. */
.biztech-portal-embed[b-e8770rskyd] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-portal-embed-escape[b-e8770rskyd] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    align-self: flex-start;
    padding: 8px 16px;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    text-decoration: none;
}
/* /Components/Portals/PortalHealthFindingList.razor.rz.scp.css */
/*
    W1b-07 · F2.25 — the rows behind each finding's count.

    🔴 W22-03 · MOVED HERE FROM PortalHealth.razor.css WITH THE MARKUP IT STYLES. The finding rows are drawn by
    PortalHealthFindingList now - for the health page and for the admin assistant's health fact card - and a
    scoped rule reaches only its own component's markup (§2 I19), so the rules travelled with the <ul>s rather
    than staying behind as rules for markup the page no longer renders. The compact form's link rows use the
    same list, for the same reasons.

    🔴 SCOPED RATHER THAN IN app.css, AND THAT IS R14.1's LAYER 4. These <ul>s are rendered by THIS
    component, so a scoped sheet reaches them - the same standing FormTemplates.razor.css's per-version
    lists have, and the same reason: a rule aimed at markup another component renders would not carry this
    component's scope attribute and would match nothing.

    A LIST rather than a stack of divs, because it is one (R12.4's "native elements first"): a screen
    reader announces "list, 50 items", which is the one piece of context a reader of a capped finding most
    needs.

    🔴 NO `margin: 0`, AND ITS ABSENCE IS A DECISION UtilitySpecificityTests MADE FOR ME.
    That reset went in by reflex, copied from FormTemplates.razor.css, and the suite refused it: a scoped
    selector compiles to `.x[b-xxxxxxxxxx]`, which is (0,2,0) against a utility class's (0,1,0), so
    zeroing a box-model property here beats every biztech-mb- or biztech-pa- utility a caller passes
    (spelled without a wildcard on purpose: a `*` before a `/` closes this comment, which is what
    PortalStyleSheetTests caught the first draft of this paragraph doing) - silently, because
    the class is still in the markup. Six <ul> exemptions are declared in that file's `Declared` set and a
    seventh was available, but the browser's block margin above a list of rows is SEPARATION THIS PAGE
    WANTS rather than noise nobody chose - so the right answer was to stop resetting it, not to earn an
    exemption for doing so.
*/

.biztech-health-rows[b-abcbctlhwi] {
    list-style: none;

    /* The list indent alone, because the marker it indents for is gone. Not a reset of a property the
       utility layer owns - see the header. */
    padding-inline-start: 0;
}

/* Each row is a thing and, sometimes, where it is and why it is here - so the lines group visually rather
   than running together into one paragraph of ids. */
.biztech-health-rows > li[b-abcbctlhwi] {
    padding-block: 4px;
}

/* `outline-subtle` rather than a `divider` token, which this platform does not have: the palette declares
   outline and outline-subtle, and TokenSufficiencyTests is what said so - a var() naming a token nothing
   declares paints nothing, with no error and no warning. */
.biztech-health-rows > li + li[b-abcbctlhwi] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* W22-03 · THE COMPACT FORM, in the admin assistant's health card. A gapped column of its own (I18): the card gaps this component as
   one child and cannot reach inside it (I19), and an inline "more" link beside a margin-less heading had no space at all. */
.biztech-health-compact[b-abcbctlhwi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* ...and inside that column the lists' user-agent block margin is a second spacing on top of the gap, so it goes - on the compact
   lists only. The page's lists keep it: their header above says why that margin is separation the page wants. */
.biztech-health-rows-compact[b-abcbctlhwi] {
    margin: 0;
}

/* ── W19-11 · the page's form ────────────────────────────────────────────────────────────────────────
   The findings as cards in one column: a card per finding with rows, then one naming those with none. The quiet edge and
   corners twice the theme's radius - the console's card. */
.biztech-health-findings[b-abcbctlhwi] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-health-finding[b-abcbctlhwi] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* The title and, at the line's end, how many it found - a pill in the warning tone, or the success tone on the clear card. */
.biztech-health-finding-head[b-abcbctlhwi] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-health-finding-count[b-abcbctlhwi] {
    margin-inline-start: auto;
    padding-inline: 8px;
    border-radius: 999px;
    background: var(--biztech-palette-warning-container);
    color: var(--biztech-palette-on-warning-container);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.biztech-health-finding-count--clear[b-abcbctlhwi] {
    background: var(--biztech-palette-success-container);
    color: var(--biztech-palette-on-success-container);
}

/* The page's rows: what it is and where on the left, the way to the composer on the right of the first line. */
.biztech-health-findings .biztech-health-rows > li[b-abcbctlhwi] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 12px;
    align-items: start;
    padding-block: 8px;
}

.biztech-health-findings .biztech-health-rows > li[b-abcbctlhwi]  .biztech-button {
    grid-column: 2;
    grid-row: 1 / span 3;
    align-self: center;
}

/* The findings with nothing in them, as a wrapping run of names rather than a panel apiece; each name's title says what it
   would have reported. */
.biztech-health-clear[b-abcbctlhwi] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-health-clear > li[b-abcbctlhwi] {
    padding: 2px 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: 999px;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
}

/* An address breaks anywhere rather than pushing the table wider than its column. */
.biztech-health-url[b-abcbctlhwi] {
    overflow-wrap: anywhere;
}
/* /Components/Portals/PortalImportReportView.razor.rz.scp.css */
/* W20-07 · the import report: one short list per kind of finding. Tokens only (R3.1); I18 · containers carry the gaps. */

/* W19-11 · the short lists as tiles, as many across as fit at 16rem each; the choices and the checklist span the row. */
.biztech-import-report[b-92s2uwk7rh] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
    gap: 12px;
}

.biztech-import-list[b-92s2uwk7rh] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* The title, its tone dot before it and its count at the end of the line. */
.biztech-import-list-head[b-92s2uwk7rh] {
    display: flex;
    align-items: center;
    gap: 8px;
}

.biztech-import-tone[b-92s2uwk7rh] {
    flex: none;
    inline-size: 8px;
    block-size: 8px;
    border-radius: 999px;
    background: var(--biztech-palette-text-secondary);
}

.biztech-import-tone--good[b-92s2uwk7rh] {
    background: var(--biztech-palette-success);
}

.biztech-import-tone--look[b-92s2uwk7rh] {
    background: var(--biztech-palette-warning);
}

.biztech-import-tone--refused[b-92s2uwk7rh] {
    background: var(--biztech-palette-error);
}

.biztech-import-count[b-92s2uwk7rh] {
    margin-inline-start: auto;
    padding-inline: 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 14%, transparent);
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    font-variant-numeric: tabular-nums;
}

/* The lines as rows under a hairline, not bullets: a list of findings reads down a column, and the rule between two is what
   separates a sentence that wraps from the next one. */
.biztech-import-list ul[b-92s2uwk7rh] {
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-import-list li[b-92s2uwk7rh] {
    padding-block: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-import-list li:last-child[b-92s2uwk7rh] {
    padding-block-end: 0;
}

.biztech-import-choices[b-92s2uwk7rh] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-inline-size: var(--biztech-form-measure);
}

/* W22-07 · D30 · the checklist: its lines, then its two links side by side, wrapping on a phone. I18 · the stack carries
   the space between them. */
.biztech-import-checklist[b-92s2uwk7rh] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-import-links[b-92s2uwk7rh] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Portals/PortalItemChip.razor.rz.scp.css */
/* W20-05 · the launcher chip's rules, over the item card: one look for a chip at every level.

   🔴 THE GLYPH IS THE PRIMARY COLOUR ON A WASH OF THE PRIMARY CONTAINER. It sat on the page's grey ground inside a
   grey border, which made every chip on a launcher the same pale square. The wash is the container mixed halfway
   into the surface, so it is lighter than the container in light mode and darker in dark mode; the glyph is a
   non-text graphic, held to 3:1, and computed on the shipped palette it reads 7.1:1 light and 4.6:1 dark.

   An uploaded MARK keeps the neutral ground and its border: it is a tenant's own picture, drawn in its own colours,
   and a tint behind it would change them. */

.biztech-portal-chip-mark[b-ivc1uwonpc],
.biztech-portal-chip-glyph[b-ivc1uwonpc] {
    box-sizing: border-box;
    flex: 0 0 auto;
    inline-size: 48px;
    block-size: 48px;
    border-radius: calc(var(--biztech-radius-default) * 1.5);
}

/* The theme's icon box (ThemePortalLook) shapes the glyph's box only: an uploaded mark keeps its own. */
.biztech-portal-chip-glyph[b-ivc1uwonpc] {
    border-radius: var(--biztech-portal-icon-radius, calc(var(--biztech-radius-default) * 1.5));
}

.biztech-portal-chip-mark[b-ivc1uwonpc] {
    display: block;
    object-fit: contain;
    padding: 4px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    background: var(--biztech-palette-background);
}

.biztech-portal-chip-glyph[b-ivc1uwonpc] {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--biztech-portal-icon-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));

    /* The ring box's edge (ThemePortalLook), inset so the box keeps its size; transparent for every other box. */
    box-shadow: inset 0 0 0 2px var(--biztech-portal-icon-edge, transparent);
}

.biztech-portal-chip-glyph[b-ivc1uwonpc]  .biztech-icon {
    inline-size: 24px;
    block-size: 24px;
    font-size: 24px;
}
/* /Components/Portals/PortalItemLayout.razor.rz.scp.css */
/* W20-05 · the five layouts.

   GRID is PortalGrid.razor.css's container (one column below `sm`, two between `sm` and `md`, the declared count from
   `md`) and PortalTileCard.razor.css's placement, unchanged - both moved here because the cell carrying the placement
   is this component's own markup, so the rules reach it without ::deep (I19). Below 960px no placement is declared
   at all, so cells flow in DOM order, which is rank order.

   LIST is the section container's stack; ACCORDION is PortalButtonMenuTile's column; APP ICONS is
   PortalAppMenuTile's auto-filling grid; IMAGE CARDS is CarouselSection's 1 / 2 / 4 track (UiGridItem Xs12 Sm6 Md3),
   written as a grid of its own so every cell stays a direct child of the layout.

   Spacing between siblings is the container's gap, never a margin per child (I18). NO overflow, NO colour (R13.8). */

/* Every gap between items is the theme's portal spacing (ThemePortalLook) - three steps, each today's value at its
   middle one. */
.biztech-portal-grid[b-jery9a09z8] {
    display: grid;

    grid-template-columns: 1fr;

    gap: var(--biztech-portal-gap, 16px);
    box-sizing: border-box;
}

@media (min-width: 600px) {
    .biztech-portal-grid[b-jery9a09z8] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 960px) {
    .biztech-portal-columns-1[b-jery9a09z8] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
    .biztech-portal-columns-2[b-jery9a09z8] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .biztech-portal-columns-3[b-jery9a09z8] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .biztech-portal-columns-4[b-jery9a09z8] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .biztech-portal-columns-5[b-jery9a09z8] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .biztech-portal-columns-6[b-jery9a09z8] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
    .biztech-portal-columns-7[b-jery9a09z8] { grid-template-columns: repeat(7, minmax(0, 1fr)); }
    .biztech-portal-columns-8[b-jery9a09z8] { grid-template-columns: repeat(8, minmax(0, 1fr)); }
    .biztech-portal-columns-9[b-jery9a09z8] { grid-template-columns: repeat(9, minmax(0, 1fr)); }
    .biztech-portal-columns-10[b-jery9a09z8] { grid-template-columns: repeat(10, minmax(0, 1fr)); }
    .biztech-portal-columns-11[b-jery9a09z8] { grid-template-columns: repeat(11, minmax(0, 1fr)); }
    .biztech-portal-columns-12[b-jery9a09z8] { grid-template-columns: repeat(12, minmax(0, 1fr)); }
    .biztech-portal-columns-13[b-jery9a09z8] { grid-template-columns: repeat(13, minmax(0, 1fr)); }
    .biztech-portal-columns-14[b-jery9a09z8] { grid-template-columns: repeat(14, minmax(0, 1fr)); }
    .biztech-portal-columns-15[b-jery9a09z8] { grid-template-columns: repeat(15, minmax(0, 1fr)); }
    .biztech-portal-columns-16[b-jery9a09z8] { grid-template-columns: repeat(16, minmax(0, 1fr)); }
    .biztech-portal-columns-17[b-jery9a09z8] { grid-template-columns: repeat(17, minmax(0, 1fr)); }
    .biztech-portal-columns-18[b-jery9a09z8] { grid-template-columns: repeat(18, minmax(0, 1fr)); }
    .biztech-portal-columns-19[b-jery9a09z8] { grid-template-columns: repeat(19, minmax(0, 1fr)); }
    .biztech-portal-columns-20[b-jery9a09z8] { grid-template-columns: repeat(20, minmax(0, 1fr)); }
    .biztech-portal-columns-21[b-jery9a09z8] { grid-template-columns: repeat(21, minmax(0, 1fr)); }
    .biztech-portal-columns-22[b-jery9a09z8] { grid-template-columns: repeat(22, minmax(0, 1fr)); }
    .biztech-portal-columns-23[b-jery9a09z8] { grid-template-columns: repeat(23, minmax(0, 1fr)); }
    .biztech-portal-columns-24[b-jery9a09z8] { grid-template-columns: repeat(24, minmax(0, 1fr)); }
}

@media (min-width: 960px) {
    
    .biztech-portal-row-1[b-jery9a09z8] { grid-row-start: 1; }
    .biztech-portal-row-2[b-jery9a09z8] { grid-row-start: 2; }
    .biztech-portal-row-3[b-jery9a09z8] { grid-row-start: 3; }
    .biztech-portal-row-4[b-jery9a09z8] { grid-row-start: 4; }
    .biztech-portal-row-5[b-jery9a09z8] { grid-row-start: 5; }
    .biztech-portal-row-6[b-jery9a09z8] { grid-row-start: 6; }
    .biztech-portal-row-7[b-jery9a09z8] { grid-row-start: 7; }
    .biztech-portal-row-8[b-jery9a09z8] { grid-row-start: 8; }
    .biztech-portal-row-9[b-jery9a09z8] { grid-row-start: 9; }
    .biztech-portal-row-10[b-jery9a09z8] { grid-row-start: 10; }
    .biztech-portal-row-11[b-jery9a09z8] { grid-row-start: 11; }
    .biztech-portal-row-12[b-jery9a09z8] { grid-row-start: 12; }
    .biztech-portal-row-13[b-jery9a09z8] { grid-row-start: 13; }
    .biztech-portal-row-14[b-jery9a09z8] { grid-row-start: 14; }
    .biztech-portal-row-15[b-jery9a09z8] { grid-row-start: 15; }
    .biztech-portal-row-16[b-jery9a09z8] { grid-row-start: 16; }
    .biztech-portal-row-17[b-jery9a09z8] { grid-row-start: 17; }
    .biztech-portal-row-18[b-jery9a09z8] { grid-row-start: 18; }
    .biztech-portal-row-19[b-jery9a09z8] { grid-row-start: 19; }
    .biztech-portal-row-20[b-jery9a09z8] { grid-row-start: 20; }
    .biztech-portal-row-21[b-jery9a09z8] { grid-row-start: 21; }
    .biztech-portal-row-22[b-jery9a09z8] { grid-row-start: 22; }
    .biztech-portal-row-23[b-jery9a09z8] { grid-row-start: 23; }
    .biztech-portal-row-24[b-jery9a09z8] { grid-row-start: 24; }

    .biztech-portal-col-1[b-jery9a09z8] { grid-column-start: 1; }
    .biztech-portal-col-2[b-jery9a09z8] { grid-column-start: 2; }
    .biztech-portal-col-3[b-jery9a09z8] { grid-column-start: 3; }
    .biztech-portal-col-4[b-jery9a09z8] { grid-column-start: 4; }
    .biztech-portal-col-5[b-jery9a09z8] { grid-column-start: 5; }
    .biztech-portal-col-6[b-jery9a09z8] { grid-column-start: 6; }
    .biztech-portal-col-7[b-jery9a09z8] { grid-column-start: 7; }
    .biztech-portal-col-8[b-jery9a09z8] { grid-column-start: 8; }
    .biztech-portal-col-9[b-jery9a09z8] { grid-column-start: 9; }
    .biztech-portal-col-10[b-jery9a09z8] { grid-column-start: 10; }
    .biztech-portal-col-11[b-jery9a09z8] { grid-column-start: 11; }
    .biztech-portal-col-12[b-jery9a09z8] { grid-column-start: 12; }
    .biztech-portal-col-13[b-jery9a09z8] { grid-column-start: 13; }
    .biztech-portal-col-14[b-jery9a09z8] { grid-column-start: 14; }
    .biztech-portal-col-15[b-jery9a09z8] { grid-column-start: 15; }
    .biztech-portal-col-16[b-jery9a09z8] { grid-column-start: 16; }
    .biztech-portal-col-17[b-jery9a09z8] { grid-column-start: 17; }
    .biztech-portal-col-18[b-jery9a09z8] { grid-column-start: 18; }
    .biztech-portal-col-19[b-jery9a09z8] { grid-column-start: 19; }
    .biztech-portal-col-20[b-jery9a09z8] { grid-column-start: 20; }
    .biztech-portal-col-21[b-jery9a09z8] { grid-column-start: 21; }
    .biztech-portal-col-22[b-jery9a09z8] { grid-column-start: 22; }
    .biztech-portal-col-23[b-jery9a09z8] { grid-column-start: 23; }
    .biztech-portal-col-24[b-jery9a09z8] { grid-column-start: 24; }

    
    .biztech-portal-rowspan-1[b-jery9a09z8] { grid-row-end: span 1; }
    .biztech-portal-rowspan-2[b-jery9a09z8] { grid-row-end: span 2; }
    .biztech-portal-rowspan-3[b-jery9a09z8] { grid-row-end: span 3; }
    .biztech-portal-rowspan-4[b-jery9a09z8] { grid-row-end: span 4; }
    .biztech-portal-rowspan-5[b-jery9a09z8] { grid-row-end: span 5; }
    .biztech-portal-rowspan-6[b-jery9a09z8] { grid-row-end: span 6; }
    .biztech-portal-rowspan-7[b-jery9a09z8] { grid-row-end: span 7; }
    .biztech-portal-rowspan-8[b-jery9a09z8] { grid-row-end: span 8; }
    .biztech-portal-rowspan-9[b-jery9a09z8] { grid-row-end: span 9; }
    .biztech-portal-rowspan-10[b-jery9a09z8] { grid-row-end: span 10; }
    .biztech-portal-rowspan-11[b-jery9a09z8] { grid-row-end: span 11; }
    .biztech-portal-rowspan-12[b-jery9a09z8] { grid-row-end: span 12; }
    .biztech-portal-rowspan-13[b-jery9a09z8] { grid-row-end: span 13; }
    .biztech-portal-rowspan-14[b-jery9a09z8] { grid-row-end: span 14; }
    .biztech-portal-rowspan-15[b-jery9a09z8] { grid-row-end: span 15; }
    .biztech-portal-rowspan-16[b-jery9a09z8] { grid-row-end: span 16; }
    .biztech-portal-rowspan-17[b-jery9a09z8] { grid-row-end: span 17; }
    .biztech-portal-rowspan-18[b-jery9a09z8] { grid-row-end: span 18; }
    .biztech-portal-rowspan-19[b-jery9a09z8] { grid-row-end: span 19; }
    .biztech-portal-rowspan-20[b-jery9a09z8] { grid-row-end: span 20; }
    .biztech-portal-rowspan-21[b-jery9a09z8] { grid-row-end: span 21; }
    .biztech-portal-rowspan-22[b-jery9a09z8] { grid-row-end: span 22; }
    .biztech-portal-rowspan-23[b-jery9a09z8] { grid-row-end: span 23; }
    .biztech-portal-rowspan-24[b-jery9a09z8] { grid-row-end: span 24; }

    .biztech-portal-colspan-1[b-jery9a09z8] { grid-column-end: span 1; }
    .biztech-portal-colspan-2[b-jery9a09z8] { grid-column-end: span 2; }
    .biztech-portal-colspan-3[b-jery9a09z8] { grid-column-end: span 3; }
    .biztech-portal-colspan-4[b-jery9a09z8] { grid-column-end: span 4; }
    .biztech-portal-colspan-5[b-jery9a09z8] { grid-column-end: span 5; }
    .biztech-portal-colspan-6[b-jery9a09z8] { grid-column-end: span 6; }
    .biztech-portal-colspan-7[b-jery9a09z8] { grid-column-end: span 7; }
    .biztech-portal-colspan-8[b-jery9a09z8] { grid-column-end: span 8; }
    .biztech-portal-colspan-9[b-jery9a09z8] { grid-column-end: span 9; }
    .biztech-portal-colspan-10[b-jery9a09z8] { grid-column-end: span 10; }
    .biztech-portal-colspan-11[b-jery9a09z8] { grid-column-end: span 11; }
    .biztech-portal-colspan-12[b-jery9a09z8] { grid-column-end: span 12; }
    .biztech-portal-colspan-13[b-jery9a09z8] { grid-column-end: span 13; }
    .biztech-portal-colspan-14[b-jery9a09z8] { grid-column-end: span 14; }
    .biztech-portal-colspan-15[b-jery9a09z8] { grid-column-end: span 15; }
    .biztech-portal-colspan-16[b-jery9a09z8] { grid-column-end: span 16; }
    .biztech-portal-colspan-17[b-jery9a09z8] { grid-column-end: span 17; }
    .biztech-portal-colspan-18[b-jery9a09z8] { grid-column-end: span 18; }
    .biztech-portal-colspan-19[b-jery9a09z8] { grid-column-end: span 19; }
    .biztech-portal-colspan-20[b-jery9a09z8] { grid-column-end: span 20; }
    .biztech-portal-colspan-21[b-jery9a09z8] { grid-column-end: span 21; }
    .biztech-portal-colspan-22[b-jery9a09z8] { grid-column-end: span 22; }
    .biztech-portal-colspan-23[b-jery9a09z8] { grid-column-end: span 23; }
    .biztech-portal-colspan-24[b-jery9a09z8] { grid-column-end: span 24; }
}

/* Every cell is a column flex box that lets its card fill it, so cards in a row are the same height - and a size
   container, so a card can lay itself out by the width of its own cell (PortalCard.razor.css stacks a narrow one). Its
   inline size comes from the grid track or the list's width, never from its content, which is what an inline-size
   container requires. */
.biztech-portal-cell[b-jery9a09z8] {
    box-sizing: border-box;
    min-inline-size: 0;
    display: flex;
    flex-direction: column;
    container-type: inline-size;
}

/* W31-05 · D12 · A HEADING SPANS ITS ROW. Every column of whichever layout holds it - a one-column grid below 600px,
   where it is already the whole row, then two, then the declared count - so the cards after it start a new row. It
   carries only its row from the composer (PortalItemLayout.Placement), never a column. Its space above and below is
   the container's gap (I18); padding-block-start adds a little more above, so it reads as the start of the next group. */
.biztech-portal-heading-cell[b-jery9a09z8] {
    grid-column: 1 / -1;
    padding-block-start: var(--biztech-portal-gap-small, 8px);
}

/* No margin here: UiText.razor.css already zeroes the heading's user-agent margin at the utility layer's specificity,
   and a scoped margin: 0 outranked every biztech-m* utility (UtilitySpecificityTests). The cell's space is the grid's
   gap and its own padding above. */
.biztech-portal-heading-cell[b-jery9a09z8]  .biztech-portal-heading {
    overflow-wrap: anywhere;
}

.biztech-portal-cell[b-jery9a09z8]  .biztech-portal-tile,
.biztech-portal-cell[b-jery9a09z8]  .biztech-portal-row,
.biztech-portal-cell[b-jery9a09z8]  .biztech-portal-image-card {
    flex: 1 1 auto;
}

/* 12px between rows rather than 24: a list's rows are one list, and at 24px each read as a card of its own. */
.biztech-portal-list[b-jery9a09z8],
.biztech-portal-accordion[b-jery9a09z8] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--biztech-portal-gap-list, 12px);
}

.biztech-portal-accordion[b-jery9a09z8] {
    gap: var(--biztech-portal-gap-small, 8px);
}

/* 🔴 AN ACCORDION ON A PAGE IS A FRAMED LIST OF FOLDS. Its toggles were text buttons floating on the page's ground,
   so a closed accordion read as a column of loose links, and an open one put its panel under the link with nothing
   to say where the fold ended. Each fold is now a bordered surface: the toggle is its full-width header, and an open
   fold's header takes the primary ink. The launcher's accordion is a column of cards and is not this. */
/* The theme's accordion style (ThemePortalLook): these bordered boxes, a line between folds and no box, or boxes whose
   header is the primary's pale tone. The header's ground is on the toggle's wrapper, so the button's own hover tint
   still draws over it. */
.biztech-portal-fold[b-jery9a09z8] {
    border: 1px solid var(--biztech-portal-fold-edge, var(--biztech-palette-outline-subtle));
    border-block-end-color: var(--biztech-portal-fold-divider, var(--biztech-palette-outline-subtle));
    border-radius: var(--biztech-portal-fold-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-fold-ground, var(--biztech-palette-surface));
}

.biztech-portal-fold [data-portal-accordion-toggle][b-jery9a09z8] {
    display: flex;
    border-radius: var(--biztech-portal-fold-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-fold-head-ground, transparent);
}

.biztech-portal-fold [data-portal-accordion-toggle][b-jery9a09z8]  .biztech-button {
    flex: 1 1 auto;
    justify-content: space-between;
    padding: 16px 20px;
    border-radius: var(--biztech-portal-fold-radius, calc(var(--biztech-radius-default) * 1.5));
    color: var(--biztech-portal-fold-head-ink, var(--biztech-palette-text-primary));
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: 600;
    text-align: start;
    white-space: normal;
}

.biztech-portal-fold [data-portal-accordion-toggle][b-jery9a09z8]  .biztech-button[aria-expanded="true"] {
    color: var(--biztech-portal-fold-open-ink, var(--biztech-palette-primary));
    border-end-start-radius: 0;
    border-end-end-radius: 0;
}

/* An open fold's content sits inside the fold's own frame, so what it holds draws no frame of its own, and a text
   item does not repeat the title its toggle already shows - the toggle names the panel (aria-controls). */
.biztech-portal-fold-panel[b-jery9a09z8] {
    padding: 0 4px 4px;
}

/* W28-15 · a fold whose only content is one text section shows it with no toggle: the title and the text, padded as the
   toggle is, the text inside a .biztech-portal-fold-panel so the two rules below reach it. */
.biztech-portal-fold-text[b-jery9a09z8] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    /* The panel inside adds 0 4px 4px of its own, so 16px 16px 12px here lands the title and the text where the toggle's
       16px 20px does. */
    padding: 16px 16px 12px;
}

/* Two classes deep, so it outweighs RichContentSection's own card rule rather than tying with it on sheet order.
   The shadow and ground go too: with only the border cleared, a theme's Depth still drew a card inside the fold. */
.biztech-portal-fold .biztech-portal-fold-panel[b-jery9a09z8]  .biztech-paper {
    border-color: transparent;
    background: transparent;
    --biztech-shadow-card: none;
}

/* A group opened in a fold drew its own title as a heading under the toggle that already shows it, at the panel's 4px
   edge rather than its rows' 16px. The fold's toggle names it; the section keeps its aria-label. */
.biztech-portal-fold-panel[b-jery9a09z8]  > [data-portal-item] > .biztech-portal-group {
    padding-block-start: 0;
}

.biztech-portal-fold-panel[b-jery9a09z8]  > [data-portal-item] > .biztech-portal-group > :first-child {
    display: none;
}

.biztech-portal-fold-panel[b-jery9a09z8]  .biztech-portal-rich > :is(h1, h2, h3, h4, h5, h6) {
    display: none;
}

/* An accordion row's toggle and its open panel, likewise - but a fold's panel is padded inside its frame, so the
   frame owns the spacing there. */
.biztech-portal-accordion .biztech-portal-cell[b-jery9a09z8] {
    gap: 8px;
}

.biztech-portal-accordion .biztech-portal-fold[b-jery9a09z8] {
    gap: 12px;
}

.biztech-portal-app-icons[b-jery9a09z8] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
    gap: var(--biztech-portal-gap-small, 8px);
}

/* W25-04 · D16 · A COLUMN COUNT, WHEN THE PAGE SETS ONE, from `sm` up; below it the set still fills its row. Two classes,
   so it outranks the auto-filling rule above whatever the source order.
   🔴 EACH COLUMN IS AT MOST AN ICON'S WIDTH, AND THE SET IS CENTRED. A share of the page each, two icons on a standard
   page sat 550px apart, two halves of the page rather than one set. 10rem holds the large app icon (88px) and a bold
   two-word title; the count is still the page's. */
@media (min-width: 600px) {
    .biztech-portal-app-icons[class*="biztech-portal-columns-"][b-jery9a09z8] { justify-content: center; }
    .biztech-portal-app-icons.biztech-portal-columns-1[b-jery9a09z8] { grid-template-columns: repeat(1, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-2[b-jery9a09z8] { grid-template-columns: repeat(2, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-3[b-jery9a09z8] { grid-template-columns: repeat(3, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-4[b-jery9a09z8] { grid-template-columns: repeat(4, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-5[b-jery9a09z8] { grid-template-columns: repeat(5, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-6[b-jery9a09z8] { grid-template-columns: repeat(6, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-7[b-jery9a09z8] { grid-template-columns: repeat(7, minmax(0, 10rem)); }
    .biztech-portal-app-icons.biztech-portal-columns-8[b-jery9a09z8] { grid-template-columns: repeat(8, minmax(0, 10rem)); }
}

/* 🔴 W20-06 · A TOGGLE FILLS ITS CELL AND WRAPS ITS TITLE. UiButton is nowrap and sized to its content, and the cell
   is min-inline-size: 0, so a title wider than 8rem - "Before you start" with its glyph, 142px in a 132px cell -
   spilled into the next cell. PortalLayoutViewportTests.An_app_icon_toggle_fits_its_cell measures it. */
.biztech-portal-app-icons [data-portal-app-toggle][b-jery9a09z8] {
    display: flex;
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* An app icon on a page is a square tile: its glyph above its title, both centred. It was an outlined button with the
   glyph beside a wrapped title, which on a row of five read as a toolbar. The open one is ringed in the primary
   colour, so the panel below the set says whose it is. No :hover and no colour of its own, by rule
   (PortalMenuTileRenderTests), and no minimum height: the touch floor is the tile's.

   Its height is its content's. The portal's medium button is fixed to the Control height (app.css), which held the
   tile at 40px while its glyph and a wrapped title spilled out above and below the edge. */
.biztech-portal-app-icons [data-portal-app-toggle][b-jery9a09z8]  .biztech-button {
    block-size: auto;
    flex: 1 1 auto;
    flex-direction: column;
    justify-content: center;
    gap: 8px;
    min-inline-size: 0;
    padding: 24px 8px;

    /* The portal's card edge (Items), as every other tile's. */
    border-color: var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    font-weight: 600;
    color: var(--biztech-palette-text-primary);
    white-space: normal;
    overflow-wrap: anywhere;
}

.biztech-portal-app-icons [data-portal-app-toggle][b-jery9a09z8]  .biztech-button .biztech-icon {
    inline-size: 28px;
    block-size: 28px;
    color: var(--biztech-palette-primary);
}

/* The open one: a primary edge, drawn as an inset ring so the tile does not grow, and primary ink. */
.biztech-portal-app-icons [data-portal-app-toggle][b-jery9a09z8]  .biztech-button[aria-expanded="true"] {
    border-color: var(--biztech-palette-primary);
    box-shadow: inset 0 0 0 1px var(--biztech-palette-primary);
    color: var(--biztech-palette-primary);
}

/* The icon set and its open panel, 16px apart through the container's gap (I18), not a margin on the panel. */
.biztech-portal-app-set[b-jery9a09z8] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-portal-gallery[b-jery9a09z8] {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--biztech-portal-gap, 16px);
}

@media (min-width: 600px) {
    .biztech-portal-gallery[b-jery9a09z8] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 960px) {
    .biztech-portal-gallery[b-jery9a09z8] {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* W26-05 · D1, D6 · FULL WIDTH ADDS COLUMNS, NOT WIDER TILES. When the theme lets the page run the screen's width
   (the shell's data-portal-width, absent at every other step), the grid fills as many tracks of a standard tile's
   width - 22rem, (1140 - 2 x 24 - 2 x 16) / 3 - as fit, and the composer's placement is dropped so tiles flow in
   rank order, exactly as they do below 960px. The gallery does the same at its own quarter-track, 16rem. An icon
   set with no count already auto-fills; one with a count keeps it (W25-04 · D16). From 71.25rem only - the standard
   measure, below which the two steps' frames are the same width - so below it full draws the composer's own grid,
   exactly as standard does (PortalFullWidthViewportTests measures 375, 768 and 1024). */
@media (min-width: 71.25rem) {
    [data-portal-width="full"] .biztech-portal-grid[b-jery9a09z8] {
        grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
    }

    [data-portal-width="full"] .biztech-portal-grid > .biztech-portal-cell[b-jery9a09z8] {
        grid-area: auto;
    }

    /* The placement is dropped, but a heading still spans its row (W31-05 · D12). */
    [data-portal-width="full"] .biztech-portal-grid > .biztech-portal-heading-cell[b-jery9a09z8] {
        grid-column: 1 / -1;
    }

    [data-portal-width="full"] .biztech-portal-gallery[b-jery9a09z8] {
        grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    }
}

/* 🔴 W31-09 · D15 · PICTURE CARDS TAKE THE PAGE'S COLUMN COUNT. The gallery's 1, 2, then 4 columns above ignored it, and
   the biztech-portal-columns-* classes near the top of this sheet lose to .biztech-portal-gallery on order. So the
   count is the gallery's own compound class (0,2,0), from 960px - where the 4 used to start - and after the full-width
   auto-fill, so a counted gallery keeps its count there too, as a counted icon set does. Below 960px it stays 1 then 2. */
@media (min-width: 960px) {
    .biztech-portal-gallery.biztech-portal-columns-1[b-jery9a09z8] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-2[b-jery9a09z8] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-3[b-jery9a09z8] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-4[b-jery9a09z8] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-5[b-jery9a09z8] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-6[b-jery9a09z8] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-7[b-jery9a09z8] { grid-template-columns: repeat(7, minmax(0, 1fr)); }
    .biztech-portal-gallery.biztech-portal-columns-8[b-jery9a09z8] { grid-template-columns: repeat(8, minmax(0, 1fr)); }
}
/* /Components/Portals/PortalItemOutlet.razor.rz.scp.css */
/* W20-05 · an item drawn in place: a group's heading over its layout, or content's picture, renderer and small
   print - each a column whose siblings are spaced by the container's gap, never a margin per child (I18).

   A group has no frame of its own, so the 12px above its heading is what separates it from the row or group before
   it in a list whose own gap is 12px - one distance, on the group, rather than a margin on whatever precedes it. */

.biztech-portal-group[b-imi3mdhqzb],
.biztech-portal-inline[b-imi3mdhqzb] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-portal-group[b-imi3mdhqzb] {
    padding-block-start: 12px;
}

/* 🔴 EVERY CONTENT RENDERER, IN THE PORTAL CARD'S LOOK, FROM THE ONE PLACE THAT WRAPS THEM ALL. The PDF form, the
   document, the presentation and the framed page each draw their own UiPaper and their own links, and none of them
   followed the cards around them: a full-strength outline, the seam's small corners, links in the browser's own blue,
   and the document viewer's preview drawn as a box inside the box. They are styled here rather than in four sheets
   so the next renderer registered with IPortalContentRendererRegistry arrives looking like the rest. */
/* The theme's content box edge (ThemePortalLook): this quiet edge, or none; the shadow stays the paper's Depth. A paper
   inside one keeps the transparent edge below. */
.biztech-portal-inline[b-imi3mdhqzb]  .biztech-paper {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    padding: 16px;
}

.biztech-portal-inline[b-imi3mdhqzb]  .biztech-paper .biztech-paper {
    border-color: transparent;
}

.biztech-portal-inline[b-imi3mdhqzb]  a:not(.biztech-button) {
    color: var(--biztech-palette-primary);
    text-underline-offset: 2px;
}
/* /Components/Portals/PortalItemPageBody.razor.rz.scp.css */
/* W20-05 · an item's own page: PortalTilePageBody.razor.css's rules, unchanged - the chip beside the h1, the
   introduction as formatted text, and the coarse-pointer 44px floor on everything the page links or presses. */

/* The page is one column: trail, header, introduction, meeting link and what it holds, 24px apart through the gap
   (I18) - the 24px biztech-mb-3 gave the header and the introduction on the tile page. */
.biztech-portal-item-page[b-o04vucx9gr] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 24px;
}

/* PortalTilePageBody.razor.css's header, intro and meeting link, unchanged. The chip beside the heading, CENTRED on it. `flex-end` against a 24px heading left the chip standing 12px
   above the title's line, which read as two things misaligned rather than as legacy's baseline; at H4 the
   heading's line box is close to the chip's height, so centring is what lines the two up. A heading that wraps
   to two lines at 375px stays centred on the chip, which is the reading a two-line title wants anyway. */
.biztech-portal-item-page-header[b-o04vucx9gr] {
    display: flex;
    align-items: center;
    gap: 16px;
}

.biztech-portal-item-page-header[b-o04vucx9gr]  .biztech-portal-chip-mark,
.biztech-portal-item-page-header[b-o04vucx9gr]  .biztech-portal-chip-glyph {
    inline-size: 64px;
    block-size: 64px;
}

.biztech-portal-item-page-header[b-o04vucx9gr]  .biztech-portal-chip-glyph .biztech-icon {
    inline-size: 32px;
    block-size: 32px;
    font-size: 32px;
}

/* The tenant's introduction as the page's lead: a step up in size and a step down in ink from the content
   below it, held to a reading measure so a long one does not run the container's full 1140px. */
.biztech-portal-item-intro[b-o04vucx9gr] {
    white-space: normal;
    max-inline-size: 48rem;
    color: var(--biztech-portal-lead-intro, var(--biztech-palette-text-secondary));
    font-size: var(--biztech-font-body1-size);
    line-height: 1.6;
}

/* The meeting link as a pill rather than an underlined line of text, so a visitor sees it as the action it is. */
.biztech-portal-meeting[b-o04vucx9gr] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    align-self: flex-start;
    padding: 8px 16px;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    text-decoration: none;
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-portal-meeting:hover[b-o04vucx9gr] {
    background: color-mix(in srgb, var(--biztech-palette-primary-container) 45%, transparent);
}

@media (pointer: coarse) {
    .biztech-portal-item-page[b-o04vucx9gr]  a,
    .biztech-portal-item-page[b-o04vucx9gr]  button {
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }
}

/* The lead: the heading and the introduction, drawn by the theme's inner-page heading (ThemePortalLook). Plain - unset -
   is no ground, no padding and the page's own inks, 24px apart as they were as the page's own children. The welcome
   band takes the welcome card's ground, inks, pattern and padding, with its corners and its 12px. */
.biztech-portal-lead[b-o04vucx9gr] {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--biztech-portal-lead-gap, 24px);
    padding: var(--biztech-portal-lead-padding, 0);
    border-radius: calc(var(--biztech-radius-default) * 2.5);
    background: var(--biztech-portal-lead-ground, transparent);
    color: var(--biztech-portal-lead-ink, var(--biztech-palette-text-primary));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-lead-edge, transparent);
}

.biztech-portal-lead[b-o04vucx9gr]::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline: 40% 0;

    /* The pattern fades in from nothing at its start to full strength at the card's far edge, so it has no hard
       edge across the middle of the card. Towards the inline end: right in a left-to-right page, left in a
       right-to-left one. */
    mask-image: linear-gradient(to right, transparent, currentColor 70%);
    border-start-end-radius: inherit;
    border-end-end-radius: inherit;
    background-image: var(--biztech-portal-lead-pattern, none);
    background-size: var(--biztech-portal-lead-pattern-size, 16px 16px);
    pointer-events: none;
}

.biztech-portal-item-page-header[b-o04vucx9gr],
.biztech-portal-item-intro[b-o04vucx9gr] {
    position: relative;
}

@media (max-width: 599.98px) {
    .biztech-portal-lead[b-o04vucx9gr] {
        padding: var(--biztech-portal-lead-padding-phone, 0);
    }
}

.biztech-portal-lead:dir(rtl)[b-o04vucx9gr]::before {
    mask-image: linear-gradient(to left, transparent, currentColor 70%);
}
/* /Components/Portals/PortalLogo.razor.rz.scp.css */
/* W20-09 · a portal's logo. A light plate behind it when Plate is true, the default, which is the composer's preview:
   the plate is on-primary in light mode and primary text in dark, both light, so a logo drawn for a light ground reads
   on a coloured one. The title band passes Plate="false" and draws no plate - the library's renditions are already
   flattened onto white - and PortalWelcomeCard sets the image's size there. Tokens only.

   One dimension constrained and the image keeps its ratio (R11.6): 32px tall, at most 192px wide, contained; on a
   phone 24px and 136px. */
.biztech-portal-logo[b-vl4rtv7p1t] {
    display: inline-flex;
    align-items: center;
}

.biztech-portal-logo-plate[b-vl4rtv7p1t] {
    padding: 8px 12px;
    border-radius: var(--biztech-radius-default);
    background: light-dark(var(--biztech-palette-on-primary), var(--biztech-palette-text-primary));
}

.biztech-portal-logo-image[b-vl4rtv7p1t] {
    display: block;
    block-size: 32px;
    max-inline-size: 192px;
    object-fit: contain;
}

@media (max-width: 599.98px) {
    .biztech-portal-logo-image[b-vl4rtv7p1t] {
        block-size: 24px;
        max-inline-size: 136px;
    }
}
/* /Components/Portals/PortalMissingReferenceChoices.razor.rz.scp.css */
/* W22-07 · D26 · one block per missing reference, each a short stack of its own controls. Tokens only (R3.1); I18 · the
   containers carry the gaps, never a margin per child. */

.biztech-import-choice-list[b-6qm34hvadm] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-import-choice[b-6qm34hvadm] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Portals/PortalSectionThumbnail.razor.rz.scp.css */
/*
    W1b-03 · F2.17 · one section's picture.

    🔴 THERE IS ONE RULE HERE BECAUSE THERE IS ONE ELEMENT. Unlike EducationItemFrame.razor.css, which
    declares the same box twice so a picture and its designed absence cannot disagree about it, this
    component renders NOTHING when there is no picture - see the component's header for why a portal
    section is not a card in a grid and a reserved empty box would be a visible gap.

    R11.7's five, and the three that belong in a stylesheet:

      ASPECT RATIO. 16/9, matching the education hub's, because the ported thumbnails are the same kind
      of thing - 17 image values across 101 legacy rows, all uploads by an administrator rather than
      generated crops. Declared so the box does not resize under the reader when the data: URI arrives
      out of OnAfterRenderAsync, which is the same reason that file gives.

      OBJECT-FIT. cover, so an author's upload is cropped rather than distorted. The alternative,
      contain, letterboxes into whatever paints behind - which on a tile is UiPaper's surface, so a
      portrait would sit in two grey bars nobody chose.

      LOADING. Not here - `loading="lazy"` is an attribute and lives in the markup.

    LOGICAL PROPERTIES: inline-size rather than width, block-size rather than height. PortalCard's
    own sheet takes the same line and records that it is what lets PortalHomeRenderTests ban the string
    `height` outright as R13.3's container-height check.

    NO COLOUR. Nothing here declares one, which is what PortalStyleSheetTests' hex sweep and
    PortalHomeRenderTests' two theory lists require of any sheet under Components/ - both enumerate the
    directory off disk, so this file is swept with no edit anywhere. There is nothing to declare: F2.18's
    measured option set contains no colour, no spacing and no radius, so a tenant cannot recolour this box
    and the radius is the palette's own.

    Every length is a multiple of the 4px base unit or a token. NO overflow, NO position: sticky.
*/

/* The theme's picture shape (ThemePortalLook); 16:9 unless it names another. */
.biztech-portal-thumb[b-ougb3bz81y] {
    aspect-ratio: var(--biztech-portal-picture-ratio, 16 / 9);
    border-radius: var(--biztech-radius-default);
    display: block;
    inline-size: 100%;
    object-fit: cover;
}
/* /Components/Portals/PortalStaticPageBody.razor.rz.scp.css */
/* W1a-10 · F2.20. The static page's body.

   TOKENS ONLY - R3.1's sweep in PortalStyleSheetTests reads every *.razor.css in this project and refuses
   a hex or rgb() literal, with two allow-listed circuit-chrome blocks in app.css that this file is not
   one of.

   🔴 EVERY RULE THAT REACHES INSIDE THE ARTICLE USES ::deep, AND THIS WAS FOUND ON SCREEN RATHER THAN IN A
   TEST - the third time this project has learned it, after MainNavMenu.razor.css and
   CasePage.razor.css, both of which say the same thing in their own headers.

   Blazor's scoped-CSS attribute is stamped on elements the RAZOR FILE declares. The body's elements are not
   declared here: they arrive as a MarkupString from a tenant's own document, so they carry no attribute at
   all. Without ::deep, `.biztech-static-page h2` compiles to `.biztech-static-page h2[b-xxxxxxxxxx]` and
   matches NOTHING, silently - the page renders with browser default spacing and every rule below is dead
   text. That is exactly what the first browser pass on this card showed: headings flush against the h1 and
   paragraphs with no rhythm, while the bUnit suite was green, because a render test asserts the DOM and
   never resolves a stylesheet.

   `.biztech-static-page ::deep h2` compiles to `.biztech-static-page[b-xxxxxxxxxx] h2` - the article keeps
   its scope, and the descendant match does not need one. The article itself is declared in the razor file,
   so the first rule below needs no ::deep. */

/* The article element's own box. Declared here, so scoped, so no ::deep. */
.biztech-static-page[b-j6mrd9a2ro] {
    /* R5.2's readable measure. 68ch rather than a pixel width because the constraint is CHARACTERS per line
       - the thing that actually governs reading - and it stays correct when the type scale moves. */
    max-inline-size: 68ch;
}

/* 🔴 VERTICAL RHYTHM, BY ELEMENT RATHER THAN BY `> * + *`. A universal-sibling rule would have to reach
   through ::deep too, and it would then apply at every depth rather than to the article's own children,
   because ::deep drops the scope for everything to its right. Naming the elements a prose document actually
   contains is both narrower and legible - and it bounds this file, which is the point: a rule for every
   element a tenant might type is a stylesheet nobody can keep true. What is not listed keeps the document
   reset in app.css, and F2.18's per-section branding is W1b's. */
.biztech-static-page[b-j6mrd9a2ro]  p,
.biztech-static-page[b-j6mrd9a2ro]  ul,
.biztech-static-page[b-j6mrd9a2ro]  ol,
.biztech-static-page[b-j6mrd9a2ro]  blockquote {
    /* 12px, three steps of the 4px base unit, which is what R5.4's sweep accepts. */
    margin-block-end: 16px;
}

/* Headings take MORE space above than below, so a section reads as belonging to the text under it rather
   than floating between two. 20px and 4px, both whole multiples of the base unit. */
.biztech-static-page[b-j6mrd9a2ro]  h2,
.biztech-static-page[b-j6mrd9a2ro]  h3 {
    margin-block-start: 32px;
    margin-block-end: 8px;
}

/* An author's headings take the type scale rather than the browser's defaults, so a tenant's privacy notice
   is set in the same faces as the page it renders inside. Two levels only: a static page is prose, and a
   document that needs h5 is a document that needs restructuring rather than a stylesheet rule. */
.biztech-static-page[b-j6mrd9a2ro]  h2 {
    font-size: var(--biztech-font-h6-size);
    font-weight: var(--biztech-font-h6-weight);
    line-height: var(--biztech-font-h6-line-height);
}

.biztech-static-page[b-j6mrd9a2ro]  h3 {
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle1-weight);
    line-height: var(--biztech-font-subtitle1-line-height);
}

/* Body text at the scale's body1, so a tenant's prose is not left at whatever the browser defaults to. */
.biztech-static-page[b-j6mrd9a2ro]  p,
.biztech-static-page[b-j6mrd9a2ro]  li {
    font-size: var(--biztech-font-body1-size);
    /* Looser than the scale's body1 for running prose: a page read top to bottom, not a line in a form. */
    line-height: 1.7;
    color: var(--biztech-palette-text-primary);
}

/* The first block sits on the head's own spacing, and the last adds nothing under the card's padding. */
.biztech-static-page[b-j6mrd9a2ro]  > :first-child {
    margin-block-start: 0;
}

.biztech-static-page[b-j6mrd9a2ro]  > :last-child {
    margin-block-end: 0;
}

/* A list needs its markers back: the document reset in app.css strips them from every ul, which is right
   for navigation and wrong for a tenant's prose. Scoped to this article, so only authored content gets them.
   16px of inline padding is four steps of the base unit and is what stops a marker sitting outside the
   measure. */
.biztech-static-page[b-j6mrd9a2ro]  ul,
.biztech-static-page[b-j6mrd9a2ro]  ol {
    padding-inline-start: 16px;
}

.biztech-static-page[b-j6mrd9a2ro]  ul {
    list-style: disc;
}

.biztech-static-page[b-j6mrd9a2ro]  ol {
    list-style: decimal;
}

/* An author's links take Primary, which satisfies contrast WITHOUT introducing a pair anybody has to
   measure: PaletteContrast.RequiredPairs already tests Primary against Surface and against Background at
   4.5:1 in both modes, and BizTechThemeOptions.Validate refuses to boot a palette that fails either. The
   reasoning is TenantChrome.razor.css's, and copying the decision rather than the value is the point.

   R3.11 · nothing here declares anything about focus, so app.css's one :focus-visible ring reaches these
   anchors with nothing to beat. */
.biztech-static-page[b-j6mrd9a2ro]  a {
    color: var(--biztech-palette-primary);
    /* A softer underline, set off the text, that firms up under the pointer: the browser's default sat on the
       descenders at full strength. */
    text-decoration-color: color-mix(in srgb, var(--biztech-palette-primary) 40%, transparent);
    text-decoration-thickness: 1px;
    text-underline-offset: 4px;
}

.biztech-static-page[b-j6mrd9a2ro]  a:hover {
    text-decoration-color: currentcolor;
}

/* The page's head: the title a step down from the scale's h1 - the card is narrow, and the h1 crowded it - with a
   short primary rule under it and the text 24px below. */
.biztech-static-head[b-j6mrd9a2ro] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-block-end: 24px;
}

.biztech-static-title[b-j6mrd9a2ro] {
    font-size: var(--biztech-font-h4-size);
    font-weight: var(--biztech-font-h4-weight);
    line-height: var(--biztech-font-h4-line-height);
    letter-spacing: var(--biztech-font-h4-letter-spacing);
    color: var(--biztech-palette-text-primary);
}

.biztech-static-head[b-j6mrd9a2ro]::after {
    content: "";
    inline-size: 40px;
    block-size: 4px;
    border-radius: 999px;
    background: var(--biztech-palette-primary);
}
/* /Components/Portals/PortalTextPreview.razor.rz.scp.css */
/* W20-03 · I18 - the caption and the previewed text are spaced by their container, not by a margin on each. */
.biztech-text-preview-body[b-dp6n68t03c] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Portals/PortalTilePageBody.razor.rz.scp.css */
/* 🔴 W1b-08 · F2.19 · the tile page's own two rules, and why it needs so few.

   The page sits inside PortalLayout's centred container, so it declares no width, no max-width, no
   gutter and no vertical rhythm: R5.3 and R5.10 put all four on the container, and a page adding its own
   would be "describing a spacing system that does not exist". The sections below the header are
   PortalItemOutlet's, and every tile behaviour's chrome is W1b-02's component.

   NO overflow, NO position, NO colour, NO height (R13.8, R14.1 layer 1). */

/* One column - trail, header, introduction, meeting link and what the tile holds - 24px apart through the gap
   (I18), as an item's own page is. The header and the introduction each carried biztech-mb-3 and the meeting
   link carried nothing, so it sat flush against the first section under it. */
.biztech-portal-tile-page[b-wy9f9r51wk] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 24px;
}

/* The chip beside the heading, CENTRED on it. `flex-end` against a 24px heading left the chip standing 12px
   above the title's line, which read as two things misaligned rather than as legacy's baseline; at H4 the
   heading's line box is close to the chip's height, so centring is what lines the two up. A heading that wraps
   to two lines at 375px stays centred on the chip, which is the reading a two-line title wants anyway. */
.biztech-portal-tile-page-header[b-wy9f9r51wk] {
    display: flex;
    align-items: center;
    gap: 16px;
}

.biztech-portal-tile-page-header[b-wy9f9r51wk]  .biztech-portal-chip-mark,
.biztech-portal-tile-page-header[b-wy9f9r51wk]  .biztech-portal-chip-glyph {
    inline-size: 64px;
    block-size: 64px;
}

.biztech-portal-tile-page-header[b-wy9f9r51wk]  .biztech-portal-chip-glyph .biztech-icon {
    inline-size: 32px;
    block-size: 32px;
    font-size: 32px;
}

/* The tenant's introduction as the page's lead: a step up in size and a step down in ink from the content
   below it, held to a reading measure so a long one does not run the container's full 1140px. */
.biztech-portal-tile-intro[b-wy9f9r51wk] {
    max-inline-size: 48rem;
    color: var(--biztech-portal-lead-intro, var(--biztech-palette-text-secondary));
    font-size: var(--biztech-font-body1-size);
    line-height: 1.6;
}

/* The meeting link as a pill rather than an underlined line of text, so a visitor sees it as the action it is. */
.biztech-portal-meeting[b-wy9f9r51wk] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    align-self: flex-start;
    padding: 8px 16px;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-pill);
    color: var(--biztech-palette-primary);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    text-decoration: none;
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-portal-meeting:hover[b-wy9f9r51wk] {
    background: color-mix(in srgb, var(--biztech-palette-primary-container) 45%, transparent);
}

/* 🔴 R5.8's 44px, UNDER A COARSE POINTER ONLY, AND THIS RULE IS WHY THIS FILE EXISTS AT ALL.
   PortalCard.razor.css carries the identical block for every card's links, and the reason it took to
   find: a bare <a> is an INLINE element, and CSS 2.1 §10.7 says min-height does not apply to one - so
   the declaration resolved and then governed nothing, measured at 17px at all three widths. The fix is
   the display, not the minimum.

   That block reaches only what a card renders. This header's meeting link and what an item drawn in
   place holds are not a card's, so they would have no target floor at all - silently, with every render
   test still green. Hence the second copy, deliberately, with the same values.

   ::deep, because the affordances are a section renderer's markup or W1b-02's rather than this file's -
   and without it the rule would be scoped to elements this page does not render, which is R14.1a's
   "present and inert" failure.

   🔴 AND THE SELECTOR IS THE PAGE'S WRAPPER, NOT ITS HEADER, WHICH THIS FILE GOT WRONG ONCE. The first
   draft scoped it to .biztech-portal-tile-page-header - so it reached the meeting link and NOTHING
   ELSE: the page's items render in the BODY, below that div, and their rows are the majority of the tap
   targets on this page. Present, resolved, and governing almost
   nothing - which is the same failure class the paragraph above describes, arrived at from the other
   direction. The wrapper div exists for this rule.

   inline-flex rather than block: an affordance inside a section's prose must not claim the whole line,
   and align-items keeps the label centred in the 44px box rather than sitting at its top. */
@media (pointer: coarse) {
    .biztech-portal-tile-page[b-wy9f9r51wk]  a,
    .biztech-portal-tile-page[b-wy9f9r51wk]  button {
        display: inline-flex;
        align-items: center;
        min-block-size: 44px;
    }
}

/*
    🔴 W1b-09 · PART D · THE INTRODUCTION'S LINE BREAKS, AND THIS ONE DECLARATION IS WHY THE COLUMN CAN
    BE PLAIN TEXT AT ALL.

    Legacy renders DashboardIcon.IconHeaderDescription through Html.Raw, so the column is nominally
    HTML - but measured 2026-09-22, the only markup in any of the 4 live rows is <br>. pre-line carries
    every one of them: newlines become breaks, runs of spaces collapse, and nothing else in the value is
    interpreted. That is what lets PortalTilePageBody render @introduction as CONTENT rather than a
    MarkupString, which would have meant a second sanitised-HTML surface beside RichContent for four
    rows.

    A fifth row carrying real markup is a change request against this clause, never a silent Html.Raw.

    NO COLOUR and NO SPACING of its own: the margin is biztech-mb-3 on the same div (R14.1's layer
    order - the utility layer first), and the ink is UiText's.
*/

.biztech-portal-tile-intro[b-wy9f9r51wk] {
    /* W20-05 · D14. The introduction is markup now, so its line breaks are <br> and <p>, and pre-line would
       double every newline the sanitiser leaves between tags. */
    white-space: normal;
}

/* The lead: the heading and the introduction, drawn by the theme's inner-page heading (ThemePortalLook). Plain - unset -
   is no ground, no padding and the page's own inks, 24px apart as they were as the page's own children. The welcome
   band takes the welcome card's ground, inks, pattern and padding, with its corners and its 12px. */
.biztech-portal-lead[b-wy9f9r51wk] {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--biztech-portal-lead-gap, 24px);
    padding: var(--biztech-portal-lead-padding, 0);
    border-radius: calc(var(--biztech-radius-default) * 2.5);
    background: var(--biztech-portal-lead-ground, transparent);
    color: var(--biztech-portal-lead-ink, var(--biztech-palette-text-primary));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-lead-edge, transparent);
}

.biztech-portal-lead[b-wy9f9r51wk]::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline: 40% 0;

    /* The pattern fades in from nothing at its start to full strength at the card's far edge, so it has no hard
       edge across the middle of the card. Towards the inline end: right in a left-to-right page, left in a
       right-to-left one. */
    mask-image: linear-gradient(to right, transparent, currentColor 70%);
    border-start-end-radius: inherit;
    border-end-end-radius: inherit;
    background-image: var(--biztech-portal-lead-pattern, none);
    background-size: var(--biztech-portal-lead-pattern-size, 16px 16px);
    pointer-events: none;
}

.biztech-portal-tile-page-header[b-wy9f9r51wk],
.biztech-portal-tile-intro[b-wy9f9r51wk] {
    position: relative;
}

@media (max-width: 599.98px) {
    .biztech-portal-lead[b-wy9f9r51wk] {
        padding: var(--biztech-portal-lead-padding-phone, 0);
    }
}

.biztech-portal-lead:dir(rtl)[b-wy9f9r51wk]::before {
    mask-image: linear-gradient(to left, transparent, currentColor 70%);
}
/* /Components/Portals/PortalVisitorInvitation.razor.rz.scp.css */
/* W25-03 · I18 · the title, the sentence and the link stack with a gap: the reset zeroes heading and paragraph margins,
   and UiPaper has no gap of its own. On an element this component draws, so the scope reaches it (I19). */
.biztech-portal-visitor-invitation[b-0dg7n140t5] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}
/* /Components/Portals/PortalWelcomeCard.razor.rz.scp.css */
/* 🔴 W8-22 · F2.21 · the portal's heading and whatever its host puts beside it.

   ONE RULE, AND IT IS HERE RATHER THAN IN UTILITIES FOR ONE REASON: flex-wrap. `biztech-d-flex`,
   `biztech-align-center` and `biztech-gap-3` all exist and would have done the rest, but the heading is
   a TENANT'S OWN NAME - "Whann Garcia Insurance Agency Platform" is three lines at 375px - and a row
   that cannot wrap is R13.8's own failure: the aside would be squeezed into a column beside it, or the
   page would scroll sideways. R14.1's layer order asks for the layer above first; this is the case where
   it cannot reach.

   `center` rather than `baseline`: the aside is a pill with its own padding, and aligning two boxes of
   different heights on their text baselines leaves the shorter one's border sitting high.

   12px, a whole multiple of the 4px base unit (R5.4) and the same gap the tile page's own header uses
   between its chip and its heading.

   NO colour, NO overflow, NO height (R13.8, R14.1 layer 1). The h1's ink is W0-71's - hierarchy by size
   and weight, never by hue - and PageTitleInkTests is what enforces that this file adds none.

   🔴 EVERY SELECTOR ENDS ON A CLASS THIS COMPONENT'S OWN MARKUP CARRIES (I19). The aside is a
   RenderFragment somebody else wrote, so nothing here reaches inside it: its own component styles
   itself, which is why AgentOrganisationSwitcher keeps its own scoped sheet rather than being styled
   from here. */
.biztech-portal-welcome-heading[b-syyraau22j] {
    display: flex;
    align-items: center;
    justify-content: var(--biztech-portal-welcome-justify, flex-start);
    flex-wrap: wrap;
    gap: 12px;
}

/* The band: the primary colour with its own ink in light mode. In dark mode the primary is a light blue, and a light
   band on a dark page was the brightest thing on the screen, so the band takes the primary container there, with the
   page's own inks on it. light-dark() follows the color-scheme UiThemeTokens declares on the root (R7.8), never the OS
   (I16). It holds the heading row over the welcome, 12px apart through the gap (I18)
   and 16px above the grid. Corners two and a half times the theme's radius - the largest surface on the page takes
   the largest corners - and a dot pattern over its right half, drawn in the band's ink at low strength, so a band
   with a short name and no welcome is not a flat block. */
.biztech-portal-hero[b-syyraau22j] {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-block-end: 16px;
    padding: var(--biztech-portal-welcome-padding, 40px);
    border-radius: calc(var(--biztech-radius-default) * 2.5);

    /* The theme's welcome card (ThemePortalLook) chooses the fill and its inks together, from pairs the contrast gate
       already holds; unset it is the primary band described above. The edge is an inset ring rather than a border, so
       a fill that has one - the surface - is the same size as one that does not. */
    background: var(--biztech-portal-welcome-ground, light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container)));
    color: var(--biztech-portal-welcome-ink, light-dark(var(--biztech-palette-on-primary), var(--biztech-palette-text-primary)));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-welcome-edge, transparent);
    text-align: var(--biztech-portal-welcome-align, start);
}

.biztech-portal-hero[b-syyraau22j]::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline: 40% 0;

    /* The pattern fades in from nothing at its start to full strength at the card's far edge, so it has no hard
       edge across the middle of the card. Towards the inline end: right in a left-to-right page, left in a
       right-to-left one. */
    mask-image: linear-gradient(to right, transparent, currentColor 70%);
    border-start-end-radius: inherit;
    border-end-end-radius: inherit;
    background-image: var(--biztech-portal-welcome-pattern, radial-gradient(color-mix(in srgb, currentColor 18%, transparent) 1px, transparent 1px));
    background-size: var(--biztech-portal-welcome-pattern-size, 16px 16px);
    pointer-events: none;
}

/* The way out, in the band's top corner: pulled up and across into the band's padding, so it costs the heading below
   it no width, and in flow, so on a phone it sits above a long name rather than over it. */
.biztech-portal-hero-exit[b-syyraau22j] {
    position: relative;
    align-self: flex-end;
    margin-block: -20px -4px;
    margin-inline-end: -20px;
}

/* Above the pattern. */
.biztech-portal-welcome-heading[b-syyraau22j],
.biztech-portal-welcome[b-syyraau22j] {
    position: relative;
}

.biztech-portal-welcome-heading[b-syyraau22j]  h1 {
    font-size: var(--biztech-portal-welcome-heading-size, clamp(2rem, 5vw, 2.5rem));
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.03em;
}

/* The welcome is the band's lead paragraph: the band's ink a step back toward the band - 6.9:1 light and 4.8:1 dark
   on the shipped palette - at a reading measure. */
.biztech-portal-welcome[b-syyraau22j] {
    max-inline-size: 40rem;
    margin-inline: var(--biztech-portal-welcome-measure-margin, 0);
    color: var(--biztech-portal-welcome-lead, light-dark(
        color-mix(in srgb, var(--biztech-palette-on-primary) 85%, var(--biztech-palette-primary)),
        var(--biztech-palette-text-secondary)));
    font-size: var(--biztech-font-body1-size);
    line-height: 1.55;
}

.biztech-portal-welcome[b-syyraau22j]  p,
.biztech-portal-welcome[b-syyraau22j]  ul,
.biztech-portal-welcome[b-syyraau22j]  ol {
    margin-block: 0 8px;
}

.biztech-portal-welcome[b-syyraau22j]  p:last-child,
.biztech-portal-welcome[b-syyraau22j]  ul:last-child,
.biztech-portal-welcome[b-syyraau22j]  ol:last-child {
    margin-block-end: 0;
}

.biztech-portal-welcome[b-syyraau22j]  strong,
.biztech-portal-welcome[b-syyraau22j]  b,
.biztech-portal-welcome[b-syyraau22j]  a {
    color: inherit;
}

@media (max-width: 599.98px) {
    .biztech-portal-hero[b-syyraau22j] {
        padding: var(--biztech-portal-welcome-padding-phone, 28px 20px);
    }

    .biztech-portal-hero-exit[b-syyraau22j] {
        margin-block-start: -12px;
        margin-inline-end: -8px;
    }
}

/* 🔴 W20-09 · THE LOGO COLUMN. With a logo the band lays out in a row: the logo at its left, at the height of a heading
   and a welcome, and the words in their own column beside it, laid out exactly as a band without a logo lays them and
   centred against the logo.

   136px tall, its width following its own shape up to 240px - a square logo is a 136px square, a wide one a 240px
   strip - with the corners rounded on the image itself. A fixed height rather than "as tall as the words": CSS cannot
   size a column from its neighbour's height without the image then stretching the band, and 136px is a heading and a
   two-line welcome at this width. A longer welcome makes the band taller and the logo stays centred beside it.

   No plate behind it in the band: the library's renditions are already flattened onto white (SkiaRasterImageResizer),
   so the image is its own light tile in both modes. Read with :has(), so a logo the library cannot draw leaves no
   empty column and no gap. */
/* The theme's logo settings (ThemePortalLook) choose the side, the size and the corners; unset is the column at the
   start, 136px tall, with the corners described above. */
.biztech-portal-hero:has(.biztech-portal-logo)[b-syyraau22j] {
    flex-direction: var(--biztech-portal-welcome-logo-direction, row);
    align-items: var(--biztech-portal-welcome-logo-align, center);
    justify-content: var(--biztech-portal-welcome-justify, flex-start);
    gap: 32px;
}

.biztech-portal-hero-logo[b-syyraau22j] {
    position: relative;
    display: flex;
    flex: 0 0 auto;
}

/* Until the library answers, and when it cannot draw the logo, the column holds nothing - and an empty child would
   still take the band's gap. */
.biztech-portal-hero-logo:not(:has(.biztech-portal-logo))[b-syyraau22j] {
    display: none;
}

.biztech-portal-hero-logo[b-syyraau22j]  .biztech-portal-logo-image {
    block-size: var(--biztech-portal-welcome-logo-height, 136px);
    inline-size: auto;
    max-inline-size: var(--biztech-portal-welcome-logo-width, 240px);
    border-radius: var(--biztech-portal-welcome-logo-radius, calc(var(--biztech-radius-default) * 1.5));
    object-fit: contain;
}

.biztech-portal-hero-body[b-syyraau22j] {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}

/* On a phone the logo sits above the words, smaller, so the band does not become a narrow column of text. */
@media (max-width: 599.98px) {
    .biztech-portal-hero:has(.biztech-portal-logo)[b-syyraau22j] {
        flex-direction: column;
        align-items: stretch;
        gap: 16px;
    }

    .biztech-portal-hero-logo[b-syyraau22j]  .biztech-portal-logo-image {
        block-size: 72px;
        max-inline-size: 160px;
    }
}

.biztech-portal-hero:dir(rtl)[b-syyraau22j]::before {
    mask-image: linear-gradient(to left, transparent, currentColor 70%);
}
/* /Components/Portals/RichContentSection.razor.rz.scp.css */
/* A tenant's formatted text, as prose. The sanitiser's allow-list lets a tenant write paragraphs, lists and links,
   and nothing styled them: paragraphs ran together with no space between, and a link drew in the browser's own
   blue. The rules reach the sanitised markup through ::deep because it is a MarkupString, which Blazor stamps
   with no scope attribute at all (I19).

   Every colour is a token and every length a 4px multiple. NO overflow. */

/* The card the text sits on: the portal card's quiet edge and doubled corners (PortalCard.razor.css), reached through
   ::deep because the paper is the seam's element and this wrapper is this file's. */
.biztech-portal-rich-card[b-prawoxsc99]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-portal-rich[b-prawoxsc99] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-portal-prose[b-prawoxsc99] {
    color: var(--biztech-palette-text-secondary);
    line-height: 1.6;
}

.biztech-portal-prose[b-prawoxsc99]  p,
.biztech-portal-prose[b-prawoxsc99]  ul,
.biztech-portal-prose[b-prawoxsc99]  ol {
    margin-block: 0 12px;
}

.biztech-portal-prose[b-prawoxsc99]  p:last-child,
.biztech-portal-prose[b-prawoxsc99]  ul:last-child,
.biztech-portal-prose[b-prawoxsc99]  ol:last-child {
    margin-block-end: 0;
}

.biztech-portal-prose[b-prawoxsc99]  ul,
.biztech-portal-prose[b-prawoxsc99]  ol {
    padding-inline-start: 24px;
}

.biztech-portal-prose[b-prawoxsc99]  li + li {
    margin-block-start: 4px;
}

.biztech-portal-prose[b-prawoxsc99]  strong,
.biztech-portal-prose[b-prawoxsc99]  b {
    color: var(--biztech-palette-text-primary);
}

.biztech-portal-prose[b-prawoxsc99]  a {
    color: var(--biztech-palette-primary);
    text-underline-offset: 2px;
}

/* W26-05 · D5 · A TEXT SECTION KEEPS R4.6's PROSE MEASURE WHEN THE PAGE RUNS FULL WIDTH. At every other step the
   page's own measure already bounds it; at full only the frame widens, so the prose takes the 46rem the layout
   constant registry gives it - start-aligned, under its heading. From the standard measure, 71.25rem, where full
   first differs from standard. */
@media (min-width: 71.25rem) {
    [data-portal-width="full"] .biztech-portal-prose[b-prawoxsc99] {
        max-inline-size: 46rem;
    }
}
/* /Components/Portals/TemplateBackedSection.razor.rz.scp.css */
/*
    W1a-07 · a template-backed section's thumbnail.

    🔴 R11.7 IN FULL, AND IT IS NOT DECIDED HERE FOR THE FIRST TIME. That rule says entity imagery
    "needs a decided aspect ratio, object-fit, srcset/sizes, loading=lazy and a fallback - it is not a
    side effect of a feature". W7-02's EducationItemFrame.razor.css made those choices and this reuses
    them rather than making a second set: 16/9 because the catalogue is decks and slide stills rather
    than portraits, and object-fit: cover because a thumbnail is whatever an author uploaded, so
    cropping it beats distorting a slide. srcset is deliberately absent for that file's reason - there
    is one stored object per template, and a srcset naming one candidate promises the browser a choice
    it does not have. loading=lazy is on the element, and the fallback is that there is NO element at
    all when there is nothing to show.

    🔴 max-width, WHICH EducationItemFrame DOES NOT NEED AND THIS DOES. Its cards sit inside a
    UiGridItem at Xs=12 Sm=6 Md=4, so the column bounds the picture. A portal section is full-width and
    standalone today, so width: 100% alone would render a 16:9 image across the whole page and bury the
    text under it. 240px is the bound, and W1a-08 owns the grid this eventually sits in - at which
    point the column may make this line unnecessary, which is a thing for that card to check rather
    than for this one to guess.

    No aspect-ratio'd placeholder for the missing case, and that is the same reasoning read the other
    way: EducationItemFrame draws one because its cards sit in a grid that must not reflow when a
    thumbnail resolves late. Nothing here is aligned against anything, so a placeholder would be a box
    with no layout to hold.

    Every colour is a --biztech-* role and every length is a multiple of the 4px base unit, which is
    what PortalStyleSheetTests' two sweeps require of any scoped sheet - they pick this file up with no
    edit.
*/

.biztech-portal-template-thumb[b-tzmyykivzu] {
    aspect-ratio: 16 / 9;
    border-radius: var(--biztech-radius-default);
    display: block;
    max-width: 240px;
    object-fit: cover;
    width: 100%;
}
/* /Components/Presentations/DeckCard.razor.rz.scp.css */
/* W27-05 · G7 · one deck as a card (ADR 0026): a bordered surface, the picture's frame on top, then the name,
   the description and the facts, spaced by the column's gap (I18) - no child carries a margin. The library
   tiles' geometry, so a deck and a document read as the same kind of object. */
/* W19-15 · the quiet edge and corners twice the theme's radius, the console lists' card (People.razor.css), where it
   was the full outline at the theme's radius. `position: relative` holds the name's stretched press area below. */
.biztech-deck-card[b-kd3y91rmo3] {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background-color: var(--biztech-palette-surface);
    /* §2a C9 · an in-flow card's depth is the card shadow token, which this card lacked. */
    box-shadow: var(--biztech-shadow-card);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* Under the pointer the edge takes the primary, so the card reads as the thing that opens; the look of something
   already drawn changes, nothing appears. */
.biztech-deck-card:hover[b-kd3y91rmo3],
.biztech-deck-card:focus-within[b-kd3y91rmo3] {
    border-color: var(--biztech-palette-primary);
}

/* The frame is reserved before the picture arrives (it is read after the cards are drawn), so nothing below
   moves when it does. Drawn empty when there is no picture, so a row of cards keeps one shape. */
.biztech-deck-card-picture[b-kd3y91rmo3] {
    position: relative;
    aspect-ratio: 16 / 9;
    background-color: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, transparent);
}

.biztech-deck-card-picture img[b-kd3y91rmo3] {
    position: absolute;
    inset: 0;
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

/* I17 · the card's own padding, on the element this file writes. */
.biztech-deck-card-body[b-kd3y91rmo3] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 16px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* W19-15 · the card opens its deck. The name stays the one anchor - what a screen reader announces and what
   middle-click opens (R9.18) - and its ::after covers the card, so a press anywhere on it is a press on the link.
   Body ink rather than the link colour: the whole card is the affordance now, and a primary title on every card was
   a column of links. Nothing here takes the browser's focus outline away (R3.11); app.css's shared ring
   does not list this link yet, so :focus-within above is what colours the card's edge for a keyboard reader. */
.biztech-deck-card-name[b-kd3y91rmo3] {
    font-weight: 600;
    color: var(--biztech-palette-text-primary);
    text-decoration: none;
}

.biztech-deck-card-name[b-kd3y91rmo3]::after {
    content: "";
    position: absolute;
    inset: 0;
}

/* The card's own controls sit above the stretched link, so a press on one is that control's rather than the card's.
   margin-top: auto keeps them on the card's foot when a neighbour's description is longer. */
.biztech-deck-card-actions[b-kd3y91rmo3] {
    position: relative;
    z-index: var(--biztech-layer-affordance);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-block-start: auto;
    padding: 0 16px 12px;
}

/* The slides glyph centred in a frame with no cover. */
.biztech-deck-card-placeholder[b-kd3y91rmo3] {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: color-mix(in srgb, var(--biztech-palette-text-primary) 35%, transparent);
}

/* At 40px, a row glyph's 24px read as a speck in the frame. */
.biztech-deck-card-placeholder[b-kd3y91rmo3]  .biztech-icon {
    inline-size: 40px;
    block-size: 40px;
}
/* /Components/Presentations/DeckDeliveryPanel.razor.rz.scp.css */
/*
    W6-29 · F7.31 · F5.4. The delivery panel's one rule.

    🔴 EVERY COLOUR IS A --biztech-palette-* ROLE AND THE RADIUS IS --biztech-radius-default, which
    PortalStyleSheetTests sweeps scoped sheets for. There are no spacing variables in this system, so
    lengths are literal rem — DeckReadingArea.razor.css beside this one makes the same note.
*/

/* The customer's three fields: the container owns the gap (I18), never a margin per field. */
.biztech-deck-delivery-fields[b-ixoi1sbj6i] {
    display: grid;
    gap: 0.75rem;
}

.biztech-deck-delivery-link[b-ixoi1sbj6i] {
    /*
        A customer's link is a base URI plus /i/ plus a GUID plus /presentation - about seventy characters
        with no space in it, which is precisely the string a browser will NOT break. Without this it
        overflows the paper on a narrow viewport and the presenter cannot see the end of the thing they
        are meant to copy.

        `anywhere` rather than `break-word`: the second only breaks when the word is alone on a line, and
        this one sits in a paragraph beside the sentence above it.
    */
    overflow-wrap: anywhere;

    /*
        Monospace, because this is a string a human copies and sometimes reads back over a phone. The
        stack is the one app.css uses for code; there is no --biztech-font-mono token to name.
    */
    font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;

    /*
        Set apart from the sentence above it, so it reads as the thing to copy rather than as more prose.
    */
    margin-top: 0.5rem;
    padding: 0.5rem;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background-color: var(--biztech-palette-surface);
}
/* /Components/Presentations/DeckEntitlementPanel.razor.rz.scp.css */
/* W19-15 · the panel's heading, then the table or the empty block, one column spaced by its gap (I18) - the heading
   carried a bottom margin. §2a C4 · the card is UiListCard's (or UiEmptyState's); this section draws no box. */
.biztech-deck-entitlement-body[b-cdgq2cp7mv] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
}
/* /Components/Presentations/DeckFileUpload.razor.rz.scp.css */
/* W27-05 · G2 · the deck file control, its caption and its stage strip: one column spaced by its own gap
   (I18). The paper around it carries the padding (I17). */
.biztech-deck-file[b-3qkjtgnrig] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}
/* /Components/Presentations/DeckImportStages.razor.rz.scp.css */
/* W27-05 · G2 · the stage's words above its bar, spaced by the container's gap (I18). */
.biztech-import-stages[b-u88ls117gm] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Presentations/DeckPicture.razor.rz.scp.css */
/* W27-05 · G4 · the deck's picture on its page: a 16:9 frame, the shape the deck cards use, bounded so it reads
   as the deck's mark rather than a banner. */
/* W19-15 · corners twice the theme's radius, as the deck cards now have, so the picture keeps their shape. */
.biztech-deck-picture[b-i2pojtyblu] {
    inline-size: min(100%, 360px);
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, transparent);
}

.biztech-deck-picture img[b-i2pojtyblu] {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}
/* /Components/Presentations/DeckReadingArea.razor.rz.scp.css */
/*
    W5-04's reading surface, moved here by W6-29 with the markup it styles.

    🔴 THE MOVE WAS FORCED RATHER THAN TIDY, AND NO TEST WOULD HAVE CAUGHT LEAVING IT BEHIND. Blazor's CSS
    isolation stamps a scope attribute on the elements written in a component's OWN file, and the generated
    selector carries it - so `.biztech-deck-reading-area[b-abc123]` in DeckViewer.razor.css stops matching
    the moment the element is rendered by DeckReadingArea instead. bUnit applies no stylesheet, so all 198
    Deck render tests stay green while the running page loses its frame, its 24rem floor and its
    touch-action. Found by reading the isolation rule rather than by a red test.

    🔴 EVERY COLOUR IS A --biztech-palette-* ROLE AND THE RADIUS IS --biztech-radius-default.
    PortalStyleSheetTests sweeps scoped sheets for both, and it earned its keep in the file these rules came
    from: it first shipped with `var(--biztech-radius-md)`, a token that does not exist. There are no spacing
    variables in this system, so lengths are literal rem.
*/

.biztech-deck-reading-area[b-6req186qvf] {
    /*
        🔴 pan-y, NOT none. R13.5's reasoning applied to a swipe rather than a canvas: `none` would take
        the browser's vertical scroll away from the reading area, so a reader on a phone could not scroll
        the page while their finger happened to be over the picture. `pan-y` keeps vertical scrolling with
        the browser and leaves the horizontal axis to the swipe handler.
    */
    touch-action: pan-y;

    /* 🔴 W14-01 · THE FRAME MEASURES ITS OWN PADDING, AND WITHOUT THIS THE CAP BELOW LIES.

       `block-size` is the CONTENT box by default, so 1rem of padding on each side plus a 1px border made
       this box 34px taller than the number it was handed - measured at 433px against a 399px cap, which
       put the Previous/Next controls 7px under the fold on the presenter's pane. The cap is a claim about
       how much WINDOW the frame may take, so the frame is what has to be measured. */
    box-sizing: border-box;

    display: flex;
    align-items: center;
    justify-content: center;

    /*
        🔴 W14-01. HOW MUCH SCREEN A SLIDE MAY HAVE, DECLARED ONCE AND READ THREE TIMES.

        The floor below and this ceiling are the same number seen from both ends: a reading area is never
        SHORTER than 24rem, and never TALLER than the viewport less that same 24rem. One constant, so the
        two cannot drift apart, and the frame, the picture and the video all size from it rather than each
        keeping its own idea of how much screen there is.

        Custom properties inherit, so declaring it here reaches the <img> below AND SlidePlayer's <video>,
        which is a child component a selector could never reach (I19). MainLayout's
        --biztech-control-height is the in-repo precedent for narrowing a value by element rather than by
        :root.

        `dvh`, not `vh`. On a phone `vh` is the address bar's height LIE - it measures the viewport as if
        the bar were hidden - so a slide sized to it is cut off exactly where the chrome sits.

        🔴 THE RESERVE IS THE KNOB, AND IT HAS TO BE, BECAUSE THE FOUR SURFACES THIS COMPONENT
        RENDERS ON DO NOT PUT THE SAME AMOUNT OF CHROME ABOVE IT. Measured at 1520x783 on 2026-09-11:
        the customer's pane spends ~300px above and below the frame; the live session pane spends ~424,
        because it also carries a session bar, a presenter toolbar and a presence alert. A single number
        that clears the session pane costs the customer's ~150px of slide for nothing, and one that suits
        the customer's leaves the session's controls BELOW THE FOLD AT EVERY WINDOW SIZE - the reserve and
        the cap both move with the viewport, so that shortfall is a constant rather than something a
        bigger screen fixes.

        17rem is the default because it is what the plain reading surfaces cost. Re-measured on
        2026-09-11 after the deck's name stopped being painted: the frame now starts at y=204 on the
        customer's pane where it started at 235, and 204 + the cap + 48px of controls has to clear the
        fold - so the reserve is 252px plus a margin, rounded to the 4px base unit. SessionStage declares
        its own on its own column and it INHERITS from there, which is the one direction that works: a
        child cannot tell its parent how much room it needs. */
    --biztech-deck-reading-block: calc(100dvh - var(--biztech-deck-reserved-block, 17rem));

    /*
        One slide fills the reading area, which is the card's first sentence. A min-height rather than a
        fixed one, so a portrait slide is not cropped and the frame does not collapse when a slide's image
        is unavailable and an alert takes its place - a reading area that changed size between slides would
        move the controls under the reader's cursor.

        🔴 AND min WINS OVER max WHEN THEY CONFLICT, which is the cascade rather than an accident:
        on a window shorter than 48rem the ceiling computes below this floor, CSS resolves min last, and
        the frame holds its 24rem instead of collapsing to nothing.
    */
    min-block-size: 24rem;

    /*
        🔴 W14-01. THE CEILING, AND WITHOUT IT A WIDER WINDOW MADE THE SLIDE TALLER.

        `max-width: 100%` on the picture is a bound on ONE axis; its height came from its width, so more
        screen sideways bought a taller picture and the reader had to scroll a PRESENTATION to see the
        page they were on. Measured in Chrome on 2026-09-11 on both surfaces: a 1500x843 slide laid out
        1071x602 in a 1520px window and ran off the bottom of a 1920px one, with the Previous/Next
        controls below the fold on the live session pane.

        🔴 block-size, AND THIS IS THE THIRD ANSWER TO ONE QUESTION - EACH ASKED FOR, EACH
        MEASURED, AND THE TRADE IS NOW CHOSEN RATHER THAN DISCOVERED.

          1. `max-block-size` originally. The frame hugged the picture, so it CHANGED HEIGHT between
             slides and the controls under it moved.
          2. `block-size`, for "the slide frame also should take maximum space as possible". Fixed
             height - and a wide-short slide then sat in a frame taller than it needed.
          3. `max-block-size` again, for that empty space. Which brought the jumping back, photographed
             on 2026-09-11 as two screenshots of the same deck with the frame at two different heights.
          4. `block-size`, asked for in those words: "keep the slide area fixed. changing depend on the
             slide image height."

        🔴 THE TWO CANNOT BOTH BE HAD, and this is the honest statement of which was chosen. A
        frame that hugs every picture is a frame that moves; a frame that never moves is a frame that is
        sometimes bigger than what is in it. A deck is a sequence read in order, so the box the reader is
        looking at - and the arrows under it - staying still is worth more than the padding it costs on a
        wide slide. The picture is centred in it, at the largest size the column allows.
    */
    block-size: var(--biztech-deck-reading-block);

    padding: 1rem;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background-color: var(--biztech-palette-surface);
}

/* 🔴 W14-01 · ONE FRAME ROUND A SLIDE, AND THE PRESENTER'S PANE HAD TWO.

   Measured in Chrome on 2026-09-11, walking the ancestors of this element on /session/{caseId}: two
   borders, both `0.8px rgb(131, 142, 154)` with an 8px radius - this one, and the work area's UiPaper
   16px outside it. A box drawn inside an identical box, which is a reflex rather than a decision. The
   customer's pane walked to ONE, because nothing wraps the deck there.

   🔴 THE HOST SAYS SO, AND TWO EARLIER SPELLINGS DID NOT. First
   `.biztech-paper .biztech-deck-reading-area` in app.css - which LOST: it is (0,2,0) and the scoped base
   rule compiles to `.biztech-deck-reading-area[b-xxxxxxxxxx]`, also (0,2,0) because an attribute counts
   where a class does, and the scoped bundle is linked after app.css in _Host.cshtml. The browser drew
   two frames with the fix applied and the stylesheet reading correctly; W14-03 measured the same shape
   in the other direction on every numeric header in the application.

   Then the same selector in THIS file, which compiles to (0,3,0) and works - and
   ScopedStyleReachTests.No_scoped_rule_names_a_class_its_own_markup_does_not_carry refused it, rightly.
   `.biztech-paper` is UiPaper's class, and the sweep cannot tell an ancestor from a target: the shape it
   forbids is the shape that silently matches nothing, and being correct this once is not something a
   reader can check from the stylesheet.

   So the decision is DECLARED instead of inferred. `Framed="false"` is a parameter a host sets when it
   frames the deck itself, and this class is in this component's own markup - which is what makes the
   rule legible and the guard satisfied at the same time. It is also the better statement: "the pane
   around me already drew a box" is something only the pane knows.

   The padding stays. It is what holds a slide off the line, and the paper's own padding is outside it. */
.biztech-deck-reading-area-bare[b-6req186qvf] {
    border: 0;
    border-radius: 0;
}

.biztech-deck-image[b-6req186qvf] {
    /*
        Contained rather than covered: a slide is a document page, so seeing all of it matters more than
        filling the frame. `cover` would crop whatever the author put at the edges.
    */
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;

    /*
        🔴 W14-01. THE PICTURE READS THE FRAME'S NUMBER, BECAUSE THE FRAME'S CEILING DOES NOT
        REACH IT.

        `max-height: 100%` above looks like it should do this and cannot: a percentage height resolves
        against the containing block's SPECIFIED height, and the frame's stays `auto` however it is
        capped - so that line computes to no bound at all, and the frame would clip the slide rather than
        fit it. This is the same number the frame uses, less the 1rem of padding on each side that the
        frame draws inside its own border.
    */
    max-block-size: calc(var(--biztech-deck-reading-block) - 2rem);

    /*
        🔴 W14-01. THE MOMENT THE <img> CARRIES width AND height, THE THREE ABOVE LETTERBOX IT.

        A slide with a display copy now renders width="1920" height="800" so the browser can reserve the
        right box before the bytes arrive. Those attributes also set the element's USED size while CSS
        leaves both auto unsaid: `max-width: 100%` shrinks the width to the container and nothing shrinks
        the height, so the box laid out 1071x800 with the picture drawn 1071x446 inside it.
        `object-fit: contain` is why it never looked stretched - it looked like 354px of empty space
        above and below, and the reading area grew from 636px to 834px to hold it. Measured in Chrome on
        2026-09-11 on the customer's pane of a real delivery; slides with no display copy, which carry
        neither attribute, were right on the same screen.

        These two hand the sizing back to CSS and give up nothing: the attributes still supply
        `aspect-ratio: auto 1920 / 800` and the intrinsic size used before load, so the box is the right
        SHAPE from the first render, which is the whole reason they are in the markup.

        Both, not just height. `max-height: 100%` bounds a tall slide, and a height clamped against a
        width the attribute has fixed is the same distortion the other way up.
    */
    width: auto;
    height: auto;
}

/* 🔴 W14-01 · THREE ITEMS NOW, NOT TWO: previous, where you are, next.

   The position strip moved in here from above the picture, where it was a slide's height away from the
   buttons that change it. align-items keeps the label on the arrows' centre line - it is Body2 text
   beside two 32px controls, so without it the row aligns on the text baseline and the label sits high.

   The gap widens around the label rather than the buttons, because the two arrows are a PAIR and the
   label is what they act on: 0.5rem holds the pair together and the margin below spaces the label from
   each side. */
.biztech-deck-controls[b-6req186qvf] {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    justify-content: center;
    margin-top: 1rem;
}

.biztech-deck-controls [role="status"][b-6req186qvf] {
    margin-inline: 0.5rem;
}

/* 🔴 W16-08 · finding 2 · R13.3. ON A PHONE THE FRAME HUGS THE SLIDE, AND THE TRADE ABOVE IS INVERTED
   ON PURPOSE RATHER THAN FORGOTTEN.

   `block-size` above is W14-01's FOURTH answer to one question, chosen in the reader's own words -
   "keep the slide area fixed" - because a deck is a sequence read in order, and a frame that hugs every
   picture is a frame that MOVES between slides, taking the arrows under the reader's cursor with it.
   Every word of that argument is still true on a laptop and none of it is reopened here.

   🔴 MEASURED AT 390x844 ON 2026-09-14, AND RE-MEASURED IN CHROMIUM AGAINST THESE COMPILED SHEETS
   BEFORE AND AFTER THIS BLOCK. A 16:9 slide, frame height against picture height:

                    reserve   frame    picture        dead band
     before   plain  17rem    572.0    356 x 200.2    371.8px
              staged 19rem    540.0    356 x 200.2    339.8px
     after    both    2rem    234.2    356 x 200.2     34.0px

   The slide already filled the WIDTH - the card's evidence table records no sideways overflow anywhere
   - so what it did not have was the height: 200px of an 844px screen is 23.7%, which is the card's
   "roughly a fifth", with 372px of empty band around it. After, the band is 34px, and that is not a
   residue: it is this frame's own `padding: 1rem` on each side plus its 1px borders. The frame hugs.

   What "the frame never moves" is worth changes with the screen. On a laptop it costs some padding
   around a wide slide. On a phone it costs two thirds of the viewport, and the Previous/Next controls
   it was protecting are below the fold at that size anyway. R13.3 names container height FIRST in its
   list of desktop-only rules that must be reversed below sm, and `.biztech-board`'s own
   `min-height: 0` / `max-height: none` in app.css is the same reversal on the same reasoning.

   🔴 THE THIRD LINE IS THE ONE THAT REACHES THE PICTURE, AND IT IS THE KNOB THIS FILE ALREADY CALLS THE
   KNOB. `.biztech-deck-image` below and SlidePlayer's `.biztech-slide-player` both cap themselves at
   `calc(var(--biztech-deck-reading-block) - 2rem)` - the video by INHERITANCE, because it belongs to a
   child component and no selector here can reach it (I19). 2rem is this frame's own padding, so the cap
   reads "the phone's viewport, less the border I draw": it binds on nothing landscape, and still stops
   a tall slide running past the fold.

   🔴 AND THE PORTRAIT CASE IS WHAT PROVES THIS LINE IS LOAD-BEARING RATHER THAN TIDY. Same probe, a
   1080x1920 slide at 390x844:

     before   picture 303.8 x 540.0   <- capped at the desktop reserve, and NARROWED to fit that cap
     after    picture 356.0 x 632.9   <- the full width the column allows

   Reversing only the frame would have left a portrait slide clamped at 540px inside a frame that now
   hugs - the same defect one element in, and 52px of width lost sideways for it.

   🔴 AND IT BEATS SessionStage's 19rem WITHOUT OUT-SPECIFYING ANYTHING. That value is declared on
   `.biztech-session-stage__main:has(> .biztech-session-stage__toolbar)` and reaches this element by
   INHERITANCE. A value declared on the element ITSELF always wins over one it inherits, whatever the
   ancestor's selector looks like - so the two never compete, and this needs no `!important` and no
   specificity contest. That is also why the RESERVE is the knob and the derived block is not: one of
   them is settable from outside, and the other is computed.

   MEASURED rather than reasoned: in the probe's staged case the computed
   --biztech-deck-reserved-block reads `19rem` before this block and `2rem` after it, with the stage's
   rule untouched in both runs. That is the one claim PortalStyleSheetTests cannot make, which is why it
   is written here.

   🔴 WHAT NO TEST IN THIS REPOSITORY CHECKS, STATED RATHER THAN IMPLIED. No Playwright suite can put a
   slide on screen - PortalBrowserFixture records W16-04 building the delivery stubs, hitting
   Tenants.Require() and reverting them - so the claim above is asserted as CSS by
   PortalStyleSheetTests.The_decks_reserved_block_comes_off_on_a_phone and confirmed once by hand in
   Chromium. A browser suite for this surface is that harness card's, not this one's. */
@media (max-width: 599.98px) {
    .biztech-deck-reading-area[b-6req186qvf] {
        block-size: auto;
        min-block-size: 0;
        --biztech-deck-reserved-block: 2rem;
    }
}
/* /Components/Presentations/DeckSourceFiles.razor.rz.scp.css */
/* W27-05 · G3 · the source-file panel: heading, list and note in one column spaced by its gap (I18); each file
   a column of its facts, its actions, its replace control and (while it runs) its stages. The paper carries the
   padding (I17). */
.biztech-source-files[b-pecd0wqw1e] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-15 · one frame with a hairline between files - the quiet edge and corners twice the theme's radius, W19-12's
   framed list of roles - where the files were loose blocks 16px apart. */
.biztech-source-file-list[b-pecd0wqw1e] {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-source-file[b-pecd0wqw1e] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding: 12px 16px;
}

.biztech-source-file + .biztech-source-file[b-pecd0wqw1e] {
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* The file's glyph, its name and facts, and its actions at the row's end, wrapping under the name on a phone. */
.biztech-source-file-head[b-pecd0wqw1e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    min-inline-size: 0;
}

/* The kind's glyph in a tinted square, the console's mark for a file. */
.biztech-source-file-mark[b-pecd0wqw1e] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    flex: none;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-primary) 10%, transparent);
    color: var(--biztech-palette-primary);
}

.biztech-source-file-actions[b-pecd0wqw1e] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-source-file-facts[b-pecd0wqw1e] {
    flex: 1 1 12rem;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}
/* /Components/Presentations/SlideArranger.razor.rz.scp.css */
/*
    W5-16 · F5.15. The author's controls, laid out like the reader's.

    A copy of .biztech-deck-controls' four declarations rather than a shared class, and that is a CSS
    isolation fact rather than a preference: Blazor scopes a sheet to the elements of its OWN component, so
    DeckViewer.razor.css's rule cannot reach anything rendered here. UiIconButton's own header records the
    same constraint one level down - "a class defined in UiText.razor.css cannot reach an element rendered
    here. Every component in this folder declares the classes it names."

    No colour and no radius token, so PortalStyleSheetTests' sweep of scoped sheets has nothing to find -
    the decision .biztech-deck-title-hidden's comment already records for this feature area.
*/

.biztech-slide-arranger[b-lsz65d9ftl] {
    display: flex;
    gap: 0.5rem;
}

/* W19-15 · the caption and the buttons share one row: the caption at the start, the buttons at the end, centred on one
   line. W14-01's 0.25rem between a caption above and the row below has no job once they sit side by side. */
.biztech-slide-arranger-row[b-lsz65d9ftl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

/* 🔴 W16-09 · FINDING 5 put the distance from the upload control above on this group, as a 1rem top margin, because a
   margin inside the padded panel added to its padding. W19-15 moved it once more, to the deck page's column gap: a
   margin on one panel added to the gap the page now puts between all of them (I18). */

/* 🔴 W14-01 · THE CAPTION NAMES THE ROW IT DESCRIBES. Photographed on /decks/{id} on 2026-09-11: three glyphs floating
   between two upload fields with no heading and no caption - a screen reader knew what each did and a person looking
   knew nothing, which is R9.2's affordance caption missing rather than a label. W14-01 centred it over the row;
   W19-15 sets it beside the buttons, at the row's start. */
.biztech-slide-arranger-caption[b-lsz65d9ftl] {
    min-inline-size: 0;
}
/* /Components/Presentations/SlideManager.razor.rz.scp.css */
/* W27-05 · G6 · the slide manager: the toggle, the hint, the tools and the grid in one column spaced by its gap
   (I18). The paper carries the padding (I17). */
.biztech-slide-manager[b-f2uei5g6y3] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* A wrapping grid of thumbnails, sized by the track, so 20 slides fit a laptop screen in a few rows and a phone
   gets two columns. */
.biztech-slide-grid[b-f2uei5g6y3] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 12px;
    margin: 0;
    padding-inline-start: 0;
    list-style: none;
}

.biztech-slide-cell[b-f2uei5g6y3] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    cursor: grab;
}

/* The picture's frame, reserved before it arrives so the grid does not move. W19-15 · the quiet edge the page's panels
   now carry, so a grid of twenty frames does not out-draw the panel round it. */
.biztech-slide-thumb[b-f2uei5g6y3] {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background-color: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, transparent);
}

.biztech-slide-thumb img[b-f2uei5g6y3] {
    position: absolute;
    inset: 0;
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: contain;
}

.biztech-slide-facts[b-f2uei5g6y3] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

/* The slide being dragged reads as lifted out of the grid. */
.biztech-slide-dragging[b-f2uei5g6y3] {
    opacity: .5;
}
/* /Components/Presentations/SlidePlayer.razor.rz.scp.css */
/*
    W5-05 · F5.5. The player's own size, and the reason this file exists at all.

    🔴 A CLASS IN MARKUP WITH NO RULE ANYWHERE, WHICH A REVIEW FOUND AND NO TEST COULD HAVE.
    SlidePlayer named .biztech-slide-player on its <video> and nothing declared it. Every sweep in
    PortalStyleSheetTests reads the rules that EXIST and asserts things about them; none asked whether a
    class in the markup HAS one, so a class that styles nothing was invisible to all of them.

    It is not cosmetic. preload="metadata" resolves the intrinsic size, .biztech-deck-reading-area is a
    flex container with no max-width on its item, and a flex item does not shrink below its intrinsic
    width without one - so a 1920-wide recording lays out 1920 wide, and at R13.7's 375px floor the
    player overflows the main landmark five times over. That is R13.8's failure on this feature's happy
    path, and no viewport suite opens the deck viewer at all.

    🔴 HERE RATHER THAN IN DeckViewer.razor.css, and that is forced rather than tidy: CSS isolation
    stamps the scope attribute on DeckViewer's own elements only, so a rule there would need ::deep to
    reach a child component's <video>. The element's own component owns the element's own size.
*/
.biztech-slide-player[b-set0q5x7lk] {
    /*
        The three declarations .biztech-deck-image carries, for its reasons. Contained rather than
        covered: a recording is content to be seen whole, and `cover` would crop whatever is at the
        edges. Percentages rather than lengths, so there is nothing here for R5.4's scale to measure.
    */
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;

    /*
        🔴 W14-01. THE SAME CEILING AS THE PICTURE, READ FROM THE FRAME THAT DRAWS BOTH.

        `max-height: 100%` has the same nothing-happens problem here: the reading area's height stays
        `auto` for percentage resolution, so a 1080-tall recording took its height from its width exactly
        as a slide did. --biztech-deck-reading-block is declared on .biztech-deck-reading-area in
        DeckReadingArea.razor.css and INHERITS into this component - which is how one number reaches a
        child component's element when a selector cannot (I19). The 2rem is that frame's own padding.
    */
    max-block-size: calc(var(--biztech-deck-reading-block) - 2rem);
}
/* /Components/Presentations/TemplateThumbnailUpload.razor.rz.scp.css */
/* W27-05 · G4 · the stored picture's preview above the field. Bounded so a tall picture cannot push the field
   off screen; the 16:9 frame the deck cards use, so the author sees the picture as it is listed. */
.biztech-thumbnail[b-m4qpuiqzmb] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* W19-15 · corners twice the theme's radius, as the deck cards now have, so the picture keeps their shape. */
.biztech-thumbnail-preview[b-m4qpuiqzmb] {
    inline-size: min(100%, 320px);
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 6%, transparent);
}

.biztech-thumbnail-preview img[b-m4qpuiqzmb] {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}
/* /Components/Tenancy/GoLiveChecklistView.razor.rz.scp.css */
/* W27-07 · the go-live checklist: a heading with Recheck beside it, then one row per item - its state, its words, its fix.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-go-live-checklist[b-atae9ewkc8] {
    display: grid;
    gap: 12px;
}

.biztech-go-live-checklist-head[b-atae9ewkc8] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.biztech-go-live-items[b-atae9ewkc8] {
    display: grid;
    gap: 8px;
}

.biztech-go-live-item[b-atae9ewkc8] {
    display: grid;
    grid-template-columns: 8rem 1fr auto;
    align-items: start;
    gap: 12px;
    padding-block: 8px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-go-live-item-text[b-atae9ewkc8] {
    display: grid;
    gap: 2px;
}

@media (max-width: 600px) {
    .biztech-go-live-item[b-atae9ewkc8] {
        grid-template-columns: 1fr;
    }
}
/* /Components/Tenancy/Imports/ImportCheckScreen.razor.rz.scp.css */
/* W30-05 · P3 · Check: the summary, the four kinds with their rows, and the actions.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-check[b-xhbh2er6mf],
.biztech-import-check-panel[b-xhbh2er6mf],
.biztech-import-row[b-xhbh2er6mf],
.biztech-import-row-form[b-xhbh2er6mf] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-check[b-xhbh2er6mf] {
    gap: 16px;
}

.biztech-import-row[b-xhbh2er6mf] {
    padding-block-start: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    overflow-wrap: anywhere;
}

.biztech-import-row-change[b-xhbh2er6mf] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px;
}

.biztech-import-summary[b-xhbh2er6mf] {
    display: grid;
    grid-template-columns: minmax(0, max-content) minmax(0, 1fr);
    gap: 4px 16px;
    overflow-wrap: anywhere;
}

.biztech-import-summary-term[b-xhbh2er6mf] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-import-exact[b-xhbh2er6mf] {
    display: grid;
    gap: 4px;
}

.biztech-import-exact summary[b-xhbh2er6mf] {
    cursor: pointer;
    color: var(--biztech-palette-text-secondary);
}

.biztech-import-check-actions[b-xhbh2er6mf] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* W30-08 · card item 1. Each unfinished import of the same package on its own line, its Open it link beside the sentence. */
.biztech-import-check-unfinished[b-xhbh2er6mf] {
    display: grid;
    gap: 4px;
}
/* /Components/Tenancy/Imports/ImportChooseScreen.razor.rz.scp.css */
/* W30-05 · P5 · Choose: the presets, then a panel per section holding its toggle and its items, and an item's two ways out.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-choose[b-phxr6fw0bm],
.biztech-import-choose-panel[b-phxr6fw0bm],
.biztech-import-choose-section[b-phxr6fw0bm],
.biztech-import-choose-items[b-phxr6fw0bm],
.biztech-import-choose-item[b-phxr6fw0bm],
.biztech-import-choose-dependants[b-phxr6fw0bm] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-choose[b-phxr6fw0bm] {
    gap: 16px;
}

/* The section's box lives in a button, which is the press (UiTriStateBox takes none). A native button, reset to read as a row. */
.biztech-import-choose-toggle[b-phxr6fw0bm] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-block-size: 44px;
    padding: 4px 8px;
    border: 0;
    border-radius: var(--biztech-radius-default);
    background: none;
    color: inherit;
    font: inherit;
    font-weight: 600;
    text-align: start;
    cursor: pointer;
}

.biztech-import-choose-toggle:focus-visible[b-phxr6fw0bm] {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 2px;
}

.biztech-import-choose-items[b-phxr6fw0bm] {
    padding-inline-start: 16px;
}

.biztech-import-choose-dependants[b-phxr6fw0bm] {
    padding: 8px 12px;
    border-inline-start: 2px solid var(--biztech-palette-warning);
    overflow-wrap: anywhere;
}

/* Walk finding: an item's box with its "Saving…" beside it while its choice is saved. */
.biztech-import-choose-box[b-phxr6fw0bm] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-choose-ways[b-phxr6fw0bm],
.biztech-import-choose-actions[b-phxr6fw0bm] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Tenancy/Imports/ImportContactScreen.razor.rz.scp.css */
/* W30-08 · P5b · Contact and joining: two panels, each value with its "from the package" mark under it. Tokens only (R3.1); the
   containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-contact[b-pcxnen2rdl],
.biztech-import-contact-panel[b-pcxnen2rdl],
.biztech-import-contact-field[b-pcxnen2rdl] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-contact[b-pcxnen2rdl] {
    gap: 16px;
}

.biztech-import-contact-field[b-pcxnen2rdl] {
    gap: 4px;
    max-inline-size: 40rem;
}

.biztech-import-contact-actions[b-pcxnen2rdl] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
}
/* /Components/Tenancy/Imports/ImportCustomiseScreen.razor.rz.scp.css */
/* W30-05 · P5 · Customise: Brand, Words and Who can join, each a panel; the two previews side by side, stacked at phone width.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-customise[b-j10hug3w6n],
.biztech-import-customise-panel[b-j10hug3w6n],
.biztech-import-customise-contrast[b-j10hug3w6n],
.biztech-import-customise-slots[b-j10hug3w6n],
.biztech-import-customise-organisation[b-j10hug3w6n],
.biztech-import-customise-record[b-j10hug3w6n] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-customise[b-j10hug3w6n],
.biztech-import-customise-record[b-j10hug3w6n] {
    gap: 16px;
}

/* W30-08 · D8: an organisation's slots, folded under its name. */
.biztech-import-customise-organisation > summary[b-j10hug3w6n] {
    cursor: pointer;
}

.biztech-import-customise-actions[b-j10hug3w6n] {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}

.biztech-import-customise-field[b-j10hug3w6n] {
    max-inline-size: 40rem;
}

.biztech-import-customise-name[b-j10hug3w6n] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
}

/* Gap (c): the four colours, two to a row where they fit, one at phone width. */
.biztech-import-customise-colours[b-j10hug3w6n] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: 8px 16px;
    max-inline-size: 40rem;
}

.biztech-import-customise-previews[b-j10hug3w6n] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: 16px;
}

.biztech-import-customise-preview[b-j10hug3w6n] {
    display: grid;
    gap: 4px;
    min-inline-size: 0;
}
/* /Components/Tenancy/Imports/ImportNamesScreen.razor.rz.scp.css */
/* W30-08 · P5b · Names: one panel per kind, each name a field. Tokens only (R3.1); the containers carry the gaps (I18); every class is
   this file's markup (I19). */
.biztech-import-names[b-hq4rianj5r],
.biztech-import-names-panel[b-hq4rianj5r],
.biztech-import-names-row[b-hq4rianj5r] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-names[b-hq4rianj5r] {
    gap: 16px;
}

.biztech-import-names-row[b-hq4rianj5r] {
    gap: 4px;
    max-inline-size: 40rem;
}

.biztech-import-names-actions[b-hq4rianj5r] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
}
/* /Components/Tenancy/Imports/ImportReviewScreen.razor.rz.scp.css */
/* W30-05 · P6 · Review: the counts, the items folded by section, what was defaulted, ticked and left out, and Import.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-review[b-j2inq447m0],
.biztech-import-review-panel[b-j2inq447m0] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-review[b-j2inq447m0] {
    gap: 16px;
}

.biztech-import-review-list[b-j2inq447m0] {
    display: grid;
    gap: 4px;
    padding-inline-start: 16px;
    overflow-wrap: anywhere;
}

.biztech-import-review-actions[b-j2inq447m0] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Tenancy/Imports/ImportRunScreen.razor.rz.scp.css */
/* W30-05 · P6 · Importing and Done: the steps and their sections, the controls, the failed rows, and Done's four ways in.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-run[b-7ezdgvsmuz],
.biztech-import-run-panel[b-7ezdgvsmuz],
.biztech-import-run-step[b-7ezdgvsmuz],
.biztech-import-run-look[b-7ezdgvsmuz],
.biztech-import-run-notes[b-7ezdgvsmuz] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-import-run[b-7ezdgvsmuz] {
    gap: 16px;
}

.biztech-import-run-list[b-7ezdgvsmuz] {
    display: grid;
    gap: 4px;
    padding-inline-start: 16px;
    overflow-wrap: anywhere;
}

.biztech-import-run-address[b-7ezdgvsmuz],
.biztech-import-run-failed[b-7ezdgvsmuz] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* W31-10 · the notes fold under Publish; their summary is the control. */
.biztech-import-run-notes-summary[b-7ezdgvsmuz] {
    cursor: pointer;
}

.biztech-import-run-actions[b-7ezdgvsmuz],
.biztech-import-run-ways[b-7ezdgvsmuz],
.biztech-import-run-row-actions[b-7ezdgvsmuz] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Tenancy/Imports/ImportTenantStepScreen.razor.rz.scp.css */
/* W30-05 · P4 · Tenant: the form, the address, the offered hosts, the closed line and the main button.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-tenant-panel[b-92ggxuvepu] {
    display: grid;
    gap: 16px;
    min-inline-size: 0;
    max-inline-size: 40rem;
}

.biztech-import-tenant-address[b-92ggxuvepu] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

.biztech-import-tenant-hosts[b-92ggxuvepu] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

/* W30-08 · D14 · the confirmed tenant, read back once the run has started: terms beside their values, as Check's summary. */
.biztech-import-tenant-record[b-92ggxuvepu] {
    display: grid;
    grid-template-columns: minmax(0, max-content) minmax(0, 1fr);
    gap: 4px 16px;
    overflow-wrap: anywhere;
}

.biztech-import-tenant-term[b-92ggxuvepu] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-import-tenant-actions[b-92ggxuvepu] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Tenancy/Imports/ImportUploadScreen.razor.rz.scp.css */
/* W30-05 · P1 · Upload: three panels, the drop region around the real file input, and the status under it.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-import-upload[b-ftpu2b9e8z] {
    display: grid;
    gap: 16px;
    min-inline-size: 0;
}

/* W30-08 · D12 · In progress and Finished are each a group of the Imports panel, laid out like the panel itself. */
.biztech-import-upload-panel[b-ftpu2b9e8z],
.biztech-import-upload-group[b-ftpu2b9e8z],
.biztech-import-upload-status[b-ftpu2b9e8z] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

/* D3 · THE DROP REGION. A dashed edge from the tokens around the file field and its sentence; the module marks it while a file is
   dragged over it, and the edge firms. The field inside stays the keyboard path, so the focus ring is the field's own. */
.biztech-import-drop[b-ftpu2b9e8z] {
    display: grid;
    gap: 8px;
    padding: 16px;
    border: 1px dashed var(--biztech-palette-outline);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-background);
    transition: border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* W30 review S11 · a recent package's two actions, Check and Discard: the row carries the gap (I18), and wraps at 375px. */
.biztech-import-recent-actions[b-ftpu2b9e8z] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* D12 · the Finished disclosure sits at its text's width rather than stretching across the grid. */
.biztech-import-upload-toggle[b-ftpu2b9e8z] {
    justify-self: start;
}

.biztech-import-drop[data-dragging][b-ftpu2b9e8z] {
    border-color: var(--biztech-palette-primary);
    border-style: solid;
}
/* /Components/Tenancy/Imports/ImportWizardLoading.razor.rz.scp.css */
/* W30-05 · walk finding · the wizard's loading part: the stage sentence above its bar.
   Tokens only (R3.1); the container carries the gap (I18); every class is this file's markup (I19). */
.biztech-import-loading[b-c7pkxbv0q5] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}
/* /Components/Tenancy/OrganisationBrandingSection.razor.rz.scp.css */
/* W23-08 · D13. A hub section: a stack spaced by its container (I18), rows of a name beside its state. */
.biztech-organisation-hub[b-cmcc2o8bmb] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-organisation-hub-rows[b-cmcc2o8bmb] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The name takes what is left and may wrap; the state keeps its own width, so 375px never scrolls sideways. */
.biztech-organisation-hub-row[b-cmcc2o8bmb] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
}

.biztech-organisation-hub-links[b-cmcc2o8bmb] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Tenancy/OrganisationOwnedSection.razor.rz.scp.css */
/* W23-08 · D13. A hub section: a stack spaced by its container (I18), rows of a name beside its count and link. */
.biztech-organisation-hub[b-z3fd3mb1dh] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-organisation-hub-rows[b-z3fd3mb1dh] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The name takes what is left and may wrap; the count and link keep their own width, so 375px never scrolls sideways. */
.biztech-organisation-hub-row[b-z3fd3mb1dh] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
}

.biztech-organisation-hub-state[b-z3fd3mb1dh] {
    display: flex;
    align-items: center;
    gap: 8px;
}
/* /Components/Tenancy/OrganisationPeopleSection.razor.rz.scp.css */
/* W23-08 · D13. A hub section: a stack spaced by its container (I18). */
.biztech-organisation-hub[b-n2cu9mblqr] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-organisation-hub-links[b-n2cu9mblqr] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Tenancy/OrganisationPortalsSection.razor.rz.scp.css */
/* W23-08 · D13. A hub section: a stack spaced by its container (I18), rows of a name beside its state. */
.biztech-organisation-hub[b-ywrk93upm7] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-organisation-hub-rows[b-ywrk93upm7] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* The name takes what is left and may wrap; the state keeps its own width, so 375px never scrolls sideways. */
.biztech-organisation-hub-row[b-ywrk93upm7] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
}

.biztech-organisation-hub-name[b-ywrk93upm7] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    overflow-wrap: anywhere;
}

.biztech-organisation-hub-state[b-ywrk93upm7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
/* /Components/Tenancy/TenantExportChoices.razor.rz.scp.css */
/* W30-02 · D14 — the export's choices. TOKENS ONLY (R3.1).

   One column, spaced by the container's gap and never by a margin per child (I18); the two buttons wrap on a phone rather than
   widen the dialog. */
.biztech-tenant-export-choices[b-w97h0shjb0] {
    display: grid;
    gap: 16px;
}

.biztech-tenant-export-actions[b-w97h0shjb0] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* /Components/Tenancy/TenantPackagePlanView.razor.rz.scp.css */
/* W27-07 · Import a package: the pick, the messages, the dry run grouped by section, Apply, then tenant.json.
   Tokens only (R3.1); the containers carry the gaps (I18); every class is this file's markup (I19). */
.biztech-tenant-package[b-5e2x8j0vao] {
    display: grid;
    gap: 16px;
}

.biztech-tenant-package-messages[b-5e2x8j0vao],
.biztech-tenant-package-plan[b-5e2x8j0vao],
.biztech-tenant-package-apply[b-5e2x8j0vao] {
    display: grid;
    gap: 8px;
}

.biztech-tenant-package-pick[b-5e2x8j0vao] {
    max-width: 40rem;
}

.biztech-tenant-package-problems[b-5e2x8j0vao] {
    display: grid;
    gap: 4px;
}
/* /Components/Tenancy/TenantPackageRowsTable.razor.rz.scp.css */
/* W30-05 · D9 · the dry run's rows by section, for /go-live's table and the import wizard's Review.
   Tokens only (R3.1); the section carries its own gap (I18); every class is this file's markup (I19). */
.biztech-tenant-package-section[b-rajch7xqu0] {
    display: grid;
    gap: 8px;
    min-inline-size: 0;
}

details.biztech-tenant-package-section > summary[b-rajch7xqu0] {
    cursor: pointer;
    font-weight: 600;
}
/* /Components/Tenancy/TenantPackHostStatus.razor.rz.scp.css */
/*
    W27-01 · A1. A host's apps host under it: indented by padding (I17), a column with one gap (I18), nothing per child.
    Logical properties, no colour.
*/

.biztech-pack-host[b-iouf7ouzjf] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    padding-inline-start: 16px;
    min-inline-size: 0;
}

.biztech-pack-host-name[b-iouf7ouzjf] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
}

.biztech-pack-host-checks[b-iouf7ouzjf] {
    display: grid;
    gap: 4px;
}

.biztech-pack-host-check[b-iouf7ouzjf] {
    display: grid;
    grid-template-columns: minmax(6rem, max-content) 1fr;
    gap: 8px;
}

.biztech-pack-host-check-label[b-iouf7ouzjf] {
    font-weight: 600;
}

/* W31-01 · A3. The published apps under the host's checks: one list, a column with one gap, nothing per child. */
.biztech-pack-host-apps[b-iouf7ouzjf] {
    display: grid;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-pack-host-app-list[b-iouf7ouzjf] {
    display: grid;
    gap: 4px;
}

/* Name and address beside the state where there is room, the state beneath on a phone: wrapping, not a breakpoint. */
.biztech-pack-host-app[b-iouf7ouzjf] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.biztech-pack-host-app-name[b-iouf7ouzjf] {
    display: grid;
    flex: 1 1 16rem;
    min-inline-size: 0;
}

.biztech-pack-host-app-address[b-iouf7ouzjf] {
    overflow-wrap: anywhere;
}

.biztech-pack-host-check-result[b-iouf7ouzjf] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    overflow-wrap: anywhere;
}
/* /Components/Themes/TenantChatPanel.razor.rz.scp.css */
/* W31 · the panel's head, its failure or its form, spaced by this container's gap (I18) - TenantChromePanel's rhythm. */
.biztech-tenant-chat[b-vjy436lg8s] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-tenant-chat-head[b-vjy436lg8s] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* W31-05 · §4. The row's fields and its action, spaced by this container's gap (I18), never a margin on either. */
.biztech-tenant-chat-stack[b-vjy436lg8s] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
/* /Components/Themes/TenantChromePanel.razor.rz.scp.css */
/* W25-04 · A10. The tenant's chrome. Every gap is the container's (I18); every length a 4px multiple. */
.biztech-theme-chrome[b-z7n8rk3iv4] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Two short forms to a row where they fit; one on a phone. */
/* W19-18 · two columns, so the tag line and the call to action share the row half and half. auto-fit made a track per
   320px, and the full-width script block kept every track open - two cards on a third of the width each, the rest empty. */
.biztech-theme-chrome-grid[b-z7n8rk3iv4] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 720px) {
    .biztech-theme-chrome-grid[b-z7n8rk3iv4] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* A block is a card with the tables' edge (W19-08), the logo slots' shape beside it. */
.biztech-theme-chrome-block[b-z7n8rk3iv4] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The operator's script is a different kind of thing - one address and where it loads - and takes the whole row. */
.biztech-theme-chrome-block--wide[b-z7n8rk3iv4] {
    grid-column: 1 / -1;
}

.biztech-theme-chrome-actions[b-z7n8rk3iv4] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The heading and its sentence, spaced by their container (I18). */
.biztech-theme-chrome-head[b-z7n8rk3iv4] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Themes/ThemeBrandView.razor.rz.scp.css */
/* W25-04 · A10. The Brand view: two panels, one column, spaced by the container (I18). */
.biztech-theme-brand[b-dxwg9sumjx] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The two panels take the tables' card edge (Inquiries.razor.css): the outline-subtle line at twice the theme's radius. UiPaper's
   own edge is the full Outline, which drew both panels in a heavier line than every card on the pages around them - their own
   slots and blocks included. ::deep: each panel's UiPaper is rendered by the panel (I19). */
.biztech-theme-brand[b-dxwg9sumjx]  > .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}
/* /Components/Themes/ThemeContrastLine.razor.rz.scp.css */
/* W21-04 · the contrast line: a caption in the success ink, or the error ink while any colour is refused. */
.biztech-theme-contrast[b-io58gtcxdk] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-inline-size: 0;
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-success);
}

.biztech-theme-contrast-failing[b-io58gtcxdk] {
    color: var(--biztech-palette-error);
}
/* /Components/Themes/ThemeImageField.razor.rz.scp.css */
/* W25-04 · A11. A picture in the theme: the frame, then its actions, spaced by this container (I18). The fieldset's
   own border, margin and padding are taken away by app.css's .biztech-choice-group, the one shared reset. */
.biztech-theme-image-field[b-eb6y7knnac] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-inline-size: 0;
}

/* The frame is the size of what it shows, whether or not anything is set, so the light and dark pictures sit as a
   pair and a field does not grow when a picture arrives. The tables' card edge (W19-08). */
.biztech-theme-image-frame[b-eb6y7knnac] {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    inline-size: 100%;
    max-inline-size: 360px;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-background);
}

/* Nothing set: a dashed edge, which reads as a place for something rather than as a card. */
.biztech-theme-image-frame--empty[b-eb6y7knnac] {
    border-style: dashed;
    border-color: var(--biztech-palette-outline);
}

.biztech-theme-image-preview[b-eb6y7knnac] {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

/* The tenant's picture, inherited: drawn so the person sees what the portal will show, and faded so it does not read
   as this scope's own. The note under the frame says it in words as well. */
.biztech-theme-image-preview--inherited[b-eb6y7knnac] {
    opacity: 0.55;
}

.biztech-theme-image-empty[b-eb6y7knnac] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

/* The primary container and its ink, the pair PaletteContrast holds at 4.5:1 - SessionLeft's chip, smaller. */
.biztech-theme-image-mark[b-eb6y7knnac] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary-container);
    color: var(--biztech-palette-on-primary-container);
}

.biztech-theme-image-actions[b-eb6y7knnac] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* 🔴 THE PICKER'S BUTTON ALONE. UiFileField draws a label and a bordered box holding the browser's button and its
   "No file chosen"; here the legend already names the field, and "no file" was false under a set picture. The label is
   kept for a screen reader and hidden from sight; the box loses its edge and fill, and its text is transparent, so
   what shows is app.css's outlined ::file-selector-button, which paints its own colour. The input is still the
   focusable control, so the one shared focus ring applies unchanged (N6). ::deep, as UiFileField renders them (I19). */
.biztech-theme-image-upload[b-eb6y7knnac]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-theme-image-upload[b-eb6y7knnac]  .biztech-input[type="file"] {
    inline-size: auto;
    border-color: transparent;
    background: transparent;
    color: transparent;
    font-size: 0;
}

/* The box's inline padding would set the button 12px in from the card's edge, and its transparent "No file chosen"
   still took its width. A font size of nought collapses the text (the button declares its own size in app.css), and
   the wrapper steps back by app.css's 12px so the button lines up with everything above it. */
.biztech-theme-image-upload[b-eb6y7knnac] {
    margin-inline-start: -12px;
}
/* /Components/Themes/ThemeLogosPanel.razor.rz.scp.css */
/* W25-04 · A10. The logo set. Every gap is the container's (I18), every length a 4px multiple, every colour a token. */
.biztech-theme-logos[b-lji9jogewy] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* As many slot cards to a row as fit: two at the console's usual width, one on a phone. */
.biztech-theme-logo-grid[b-lji9jogewy] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 16px;
}

/* A slot is a card with the tables' edge (W19-08): the outline-subtle line at twice the theme's radius. */
.biztech-theme-logo-slot[b-lji9jogewy] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-inline-size: 0;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* The two grounds share the card's width evenly, each with its name under it. */
.biztech-theme-logo-previews[b-lji9jogewy] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.biztech-theme-logo-ground[b-lji9jogewy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

/* The mark on the two grounds it is drawn on: the page's own, and the brand colour the reverse mark sits on. */
.biztech-theme-logo-preview[b-lji9jogewy] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: 72px;
    padding: 8px 12px;
    border-radius: var(--biztech-radius-default);
    border: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-theme-logo-preview-page[b-lji9jogewy] {
    background: var(--biztech-palette-background);
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-logo-preview-brand[b-lji9jogewy] {
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
}

.biztech-theme-logo-preview img[b-lji9jogewy] {
    max-inline-size: 100%;
    max-block-size: 48px;
    object-fit: contain;
}

.biztech-theme-logo-actions[b-lji9jogewy] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The heading and its sentence, spaced by their container (I18). */
.biztech-theme-logos-head[b-lji9jogewy] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* 🔴 THE PICKER'S BUTTON ALONE - ThemeImageField's rule. The label is kept for a screen reader and hidden from sight;
   the box loses its edge and fill and its "No file chosen" goes transparent, so what shows is app.css's outlined
   ::file-selector-button. The input stays the focusable control, so the shared focus ring applies (N6). */
.biztech-theme-logo-upload[b-lji9jogewy]  .biztech-field-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.biztech-theme-logo-upload[b-lji9jogewy]  .biztech-input[type="file"] {
    inline-size: auto;
    border-color: transparent;
    background: transparent;
    color: transparent;
    font-size: 0;
}

/* The box's inline padding would set the button 12px in from the card's edge, and its transparent "No file chosen"
   still took its width. A font size of nought collapses the text (the button declares its own size in app.css), and
   the wrapper steps back by app.css's 12px so the button lines up with everything above it. */
.biztech-theme-logo-upload[b-lji9jogewy] {
    margin-inline-start: -12px;
}

/* The slot's name and its Remove on one line, the action at the end. */
.biztech-theme-logo-slot-head[b-lji9jogewy] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-block-size: 32px;
}
/* /Components/Themes/ThemePortalPreview.razor.rz.scp.css */
/* The portal miniature. Every rule that a portal setting drives reads the variable the portal's own sheet reads, with
   the same fallback: PortalLayout.razor.css for the header, PortalWelcomeCard.razor.css for the welcome,
   PortalCard.razor.css and PortalItemChip.razor.css for the items, PortalItemPageBody.razor.css, PortalItemOutlet.razor.css
   and DocumentViewerSection.razor.css for the inner page. The sizes are the portal's own; the whole miniature is
   scaled down to the preview below. */
/* 🔴 MinimumHeight · 640px, the console miniature's (ThemePreviewCanvas.razor.css): both are pictures of a 1080px page at the
   home page's height, so switching between the App and Portal views does not jump. It was 280px, and the console's was its own
   content, a strip under half this one's height. The page between the header and the footer takes what is left. */
.biztech-theme-portal[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    min-block-size: 640px;
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
}

/* W25 walk · the tenant's background picture under the scrim, painted exactly as PortalLayout.razor.css paints the shell:
   the page's own ground laid over the picture at the scrim's strength, as the element's own background. The properties
   come from the parent frame (the miniature's style attribute is biztech-fit.js's), and the attribute is present only
   when the mode being previewed has a picture. No layer of its own, and so nothing to stack. */
.biztech-theme-portal[data-theme-portal-background][b-pntlvd3cf3] {
    background-image:
        linear-gradient(
            color-mix(in srgb, var(--biztech-palette-background) calc(var(--portal-background-scrim) * 100%), transparent),
            color-mix(in srgb, var(--biztech-palette-background) calc(var(--portal-background-scrim) * 100%), transparent)),
        var(--portal-background);
    background-size: cover;
    background-position: center;
}

/* Drawn at 1080px and scaled to the preview by biztech-fit.js, which sets data-fit once it is live: a laptop's three tiles
   to a row, every size the page's own, and no scrollbar beside the settings pane's. It was 960px, the portal's narrow
   width; at that scale the home page was a little taller than a laptop's preview pane, which then scrolled. zoom rather
   than transform, so the box the preview lays out is the scaled one and nothing below it is pushed down. */
.biztech-theme-portal[data-fit][b-pntlvd3cf3] {
    /* 1 until the module measures the preview; it then writes the ratio on the element itself, which wins. */
    --biztech-fit-zoom: 1;

    inline-size: 1080px;
    zoom: var(--biztech-fit-zoom);
}

.biztech-theme-portal-header[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 24px;
    background: var(--biztech-portal-header-ground, color-mix(in srgb, var(--biztech-palette-surface) 86%, transparent));
    backdrop-filter: var(--biztech-portal-header-filter, blur(12px));
    color: var(--biztech-portal-header-ink, var(--biztech-palette-text-primary));
    border-block-end: 1px solid var(--biztech-portal-header-edge, var(--biztech-palette-outline));
    font-weight: 600;
}

/* W26-02. Five eighths of the header mark's theme height - today's 20px at the 2rem default - so the logo size shows here. */
.biztech-theme-portal-mark[b-pntlvd3cf3] {
    inline-size: calc(var(--biztech-portal-header-logo-height, 2rem) * 0.625);
    block-size: calc(var(--biztech-portal-header-logo-height, 2rem) * 0.625);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-portal-header-mark, var(--biztech-palette-primary));
}

.biztech-theme-portal-page[b-pntlvd3cf3] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
}

/* The welcome card, and an inner page's lead drawn like it, at the phone padding the portal gives them. */
.biztech-theme-portal-welcome[b-pntlvd3cf3],
.biztech-theme-portal-inner-lead[b-pntlvd3cf3] {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 8px;
    border-radius: calc(var(--biztech-radius-default) * 2.5);
}

.biztech-theme-portal-welcome[b-pntlvd3cf3] {
    /* The phone padding, a step tighter than the desktop's, so the home page fits a laptop's preview without a
       scrollbar; compact, standard and tall still differ. */
    padding: var(--biztech-portal-welcome-padding-phone, 28px 20px);
    background: var(--biztech-portal-welcome-ground, light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container)));
    color: var(--biztech-portal-welcome-ink, light-dark(var(--biztech-palette-on-primary), var(--biztech-palette-text-primary)));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-welcome-edge, transparent);
    text-align: var(--biztech-portal-welcome-align, start);

    /* With its logo, as PortalWelcomeCard.razor.css lays the card out when the portal has one. */
    flex-direction: var(--biztech-portal-welcome-logo-direction, row);
    align-items: var(--biztech-portal-welcome-logo-align, center);
    justify-content: var(--biztech-portal-welcome-justify, flex-start);
    gap: 32px;
}

.biztech-theme-portal-welcome-body[b-pntlvd3cf3] {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    align-items: var(--biztech-portal-welcome-justify, flex-start);
    gap: 12px;
    min-inline-size: 0;
}

/* The stand-in logo: a box in the card's own ink - light on a brand fill, dark on a pale one - with a mark cut into it
   in the card's fill, so it reads as a logo on any fill, at the theme's logo height and corners. */
.biztech-theme-portal-logo[b-pntlvd3cf3] {
    position: relative;
    display: flex;
    flex: 0 0 auto;
}

.biztech-theme-portal-logo-image[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    justify-content: center;

    /* Three quarters of the theme's logo height, for the same fit; small, medium and large keep their proportions. */
    block-size: calc(var(--biztech-portal-welcome-logo-height, 136px) * 0.75);
    aspect-ratio: 1;
    border-radius: var(--biztech-portal-welcome-logo-radius, calc(var(--biztech-radius-default) * 1.5));
    background: currentColor;
}

.biztech-theme-portal-logo-image[b-pntlvd3cf3]::before {
    content: "";
    inline-size: 40%;
    aspect-ratio: 1;
    border-radius: 999px;
    border: 8px solid var(--biztech-portal-welcome-ground, light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container)));
}

.biztech-theme-portal-welcome[b-pntlvd3cf3]::before,
.biztech-theme-portal-inner-lead[b-pntlvd3cf3]::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline: 40% 0;

    /* The pattern fades in from nothing at its start to full strength at the card's far edge, so it has no hard
       edge across the middle of the card. Towards the inline end: right in a left-to-right page, left in a
       right-to-left one. */
    mask-image: linear-gradient(to right, transparent, currentColor 70%);
    border-start-end-radius: inherit;
    border-end-end-radius: inherit;
    background-size: 16px 16px;
    pointer-events: none;
}

.biztech-theme-portal-welcome[b-pntlvd3cf3]::before {
    background-size: var(--biztech-portal-welcome-pattern-size, 16px 16px);
    background-image: var(--biztech-portal-welcome-pattern, radial-gradient(color-mix(in srgb, currentColor 18%, transparent) 1px, transparent 1px));
}

.biztech-theme-portal-lead[b-pntlvd3cf3],
.biztech-theme-portal-inner-head[b-pntlvd3cf3],
.biztech-theme-portal-inner-intro[b-pntlvd3cf3] {
    position: relative;
}

.biztech-theme-portal-title[b-pntlvd3cf3] {
    font-size: var(--biztech-portal-welcome-heading-size, clamp(2rem, 5vw, 2.5rem));
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.03em;
}

.biztech-theme-portal-lead[b-pntlvd3cf3] {
    max-inline-size: 40rem;
    font-size: var(--biztech-font-body1-size);
    color: var(--biztech-portal-welcome-lead, light-dark(
        color-mix(in srgb, var(--biztech-palette-on-primary) 85%, var(--biztech-palette-primary)),
        var(--biztech-palette-text-secondary)));
}

.biztech-theme-portal-grid[b-pntlvd3cf3] {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--biztech-portal-gap, 16px);
}

.biztech-theme-portal-card[b-pntlvd3cf3],
.biztech-theme-portal-box[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    justify-content: center;
    padding: 16px;
    border: 1px solid var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    color: var(--biztech-palette-text-primary);
}

/* The first card is drawn as the hover state, so the hover setting is seen without a pointer: its edge and its button.
   Not its shadow - an in-flow miniature takes none but the theme's card shadow (ADR 0026 D-E). */
.biztech-theme-portal-card:first-child[b-pntlvd3cf3] {
    border-color: var(--biztech-portal-card-hover-edge, var(--biztech-palette-primary-container));
}

.biztech-theme-portal-card-tall[b-pntlvd3cf3] {
    grid-row: span 2;
}

.biztech-theme-portal-art[b-pntlvd3cf3] {
    flex: 1 1 64px;
    margin: -16px -16px 4px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
    border-start-start-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    border-start-end-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    background-color: var(--biztech-portal-tile-ground, var(--biztech-palette-background));
    background-image: var(--biztech-portal-tile-pattern, radial-gradient(var(--biztech-palette-outline-subtle) 1px, transparent 1px));
    background-size: var(--biztech-portal-tile-pattern-size, 16px 16px);
}

/* The theme's picture shape, uncapped: a height limit here would cut every shape to the same box. */
.biztech-theme-portal-picture[b-pntlvd3cf3] {
    display: block;
    aspect-ratio: var(--biztech-portal-picture-ratio, 16 / 9);
    margin: -16px -16px 0;
    border-start-start-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    border-start-end-radius: calc(var(--biztech-radius-default) * 2 - 1px);
    background: linear-gradient(135deg, var(--biztech-palette-primary-container), var(--biztech-palette-tertiary));
}

.biztech-theme-portal-face[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    gap: 16px;
    min-inline-size: 0;
}

.biztech-theme-portal-icon[b-pntlvd3cf3] {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 48px;
    block-size: 48px;
    border-radius: var(--biztech-portal-icon-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-icon-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));

    /* The ring box's edge, as PortalItemChip draws it. */
    box-shadow: inset 0 0 0 2px var(--biztech-portal-icon-edge, transparent);
}

/* An App icons page, as PortalItemLayout and PortalCard draw it: columns an icon wide, the set centred. */
.biztech-theme-portal-apps[b-pntlvd3cf3] {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--biztech-portal-gap-small, 8px);
}

.biztech-theme-portal-app[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    inline-size: 10rem;
    padding: 12px 8px;
    text-align: center;
}

.biztech-theme-portal-app-icon[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--biztech-portal-app-icon-size, 48px);
    block-size: var(--biztech-portal-app-icon-size, 48px);
    border-radius: var(--biztech-portal-icon-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-icon-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));
    box-shadow: inset 0 0 0 2px var(--biztech-portal-icon-edge, transparent);
}

.biztech-theme-portal-app-icon[b-pntlvd3cf3]  .biztech-icon {
    inline-size: var(--biztech-portal-app-icon-glyph, 24px);
    block-size: var(--biztech-portal-app-icon-glyph, 24px);
    font-size: var(--biztech-portal-app-icon-glyph, 24px);
}

.biztech-theme-portal-app-title[b-pntlvd3cf3] {
    font-weight: var(--biztech-portal-app-icon-title-weight, 400);
}

.biztech-theme-portal-app-hover .biztech-theme-portal-app-icon[b-pntlvd3cf3] {
    background: var(--biztech-portal-icon-hover-ground, var(--biztech-portal-icon-ground));
    color: var(--biztech-portal-icon-hover-ink, var(--biztech-portal-icon-ink));
}

.biztech-theme-portal-app-hover .biztech-theme-portal-app-title[b-pntlvd3cf3] {
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));
}

.biztech-theme-portal-words[b-pntlvd3cf3] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
}

.biztech-theme-portal-name[b-pntlvd3cf3] {
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: 600;
}

.biztech-theme-portal-text[b-pntlvd3cf3] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-theme-portal-go[b-pntlvd3cf3] {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-portal-card-go-ground, var(--biztech-palette-background));
    color: var(--biztech-palette-text-primary);
}

/* The hovered card's button, as the portal fills it under the pointer. */
.biztech-theme-portal-card:first-child .biztech-theme-portal-go[b-pntlvd3cf3] {
    background: var(--biztech-portal-card-go-hover-ground, var(--biztech-palette-primary));
    color: var(--biztech-portal-card-go-hover-ink, var(--biztech-palette-on-primary));
}

.biztech-theme-portal-chevron[b-pntlvd3cf3] {
    box-sizing: border-box;
    inline-size: 8px;
    block-size: 8px;
    margin-inline-end: 2px;
    border-block-start: 2px solid currentColor;
    border-inline-end: 2px solid currentColor;
    rotate: 45deg;
}

/* The trail back home, as PageBreadcrumb draws it above an inner page's heading. */
.biztech-theme-portal-crumb[b-pntlvd3cf3] {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
}

/* The back button and the trail, as app.css draws .biztech-breadcrumb-row and .biztech-breadcrumb-back. */
.biztech-theme-portal-crumb-row[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-theme-portal-back[b-pntlvd3cf3] {
    display: var(--biztech-portal-back-button, none);
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border: 1px solid var(--biztech-palette-primary);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-primary);
}

.biztech-theme-portal-inner-lead[b-pntlvd3cf3] {
    gap: calc(var(--biztech-portal-lead-gap, 24px) / 2);
    padding: var(--biztech-portal-lead-padding, 0);
    background: var(--biztech-portal-lead-ground, transparent);
    color: var(--biztech-portal-lead-ink, var(--biztech-palette-text-primary));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-lead-edge, transparent);
}

.biztech-theme-portal-inner-lead[b-pntlvd3cf3]::before {
    background-size: var(--biztech-portal-lead-pattern-size, 16px 16px);
    background-image: var(--biztech-portal-lead-pattern, none);
}

.biztech-theme-portal-inner-head[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    gap: 12px;
}

.biztech-theme-portal-inner-title[b-pntlvd3cf3] {
    font-size: 2rem;
    font-weight: 600;
    line-height: 1.1;
}

.biztech-theme-portal-inner-intro[b-pntlvd3cf3] {
    color: var(--biztech-portal-lead-intro, var(--biztech-palette-text-secondary));
}

.biztech-theme-portal-box[b-pntlvd3cf3] {
    border-color: var(--biztech-portal-box-edge, var(--biztech-palette-outline-subtle));
}

/* The document viewer's height at a quarter: short, standard and tall still differ, in a frame this size. */
.biztech-theme-portal-document[b-pntlvd3cf3] {
    display: block;
    block-size: calc(var(--biztech-portal-viewer-height, 24rem) / 4);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-background);
}

/* The page's accordion, as PortalItemLayout.razor.css draws its folds. */
.biztech-theme-portal-folds[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    gap: var(--biztech-portal-gap-small, 8px);
}

.biztech-theme-portal-fold[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--biztech-portal-fold-edge, var(--biztech-palette-outline-subtle));
    border-block-end-color: var(--biztech-portal-fold-divider, var(--biztech-palette-outline-subtle));
    border-radius: var(--biztech-portal-fold-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-fold-ground, var(--biztech-palette-surface));
}

.biztech-theme-portal-fold-head[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-radius: var(--biztech-portal-fold-radius, calc(var(--biztech-radius-default) * 1.5));
    background: var(--biztech-portal-fold-head-ground, transparent);
    color: var(--biztech-portal-fold-head-ink, var(--biztech-palette-text-primary));
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: 600;
}

.biztech-theme-portal-fold-open[b-pntlvd3cf3] {
    border-end-start-radius: 0;
    border-end-end-radius: 0;
    color: var(--biztech-portal-fold-open-ink, var(--biztech-palette-primary));
}

.biztech-theme-portal-fold-body[b-pntlvd3cf3] {
    padding: 12px 20px 16px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-portal-chevron-down[b-pntlvd3cf3] {
    rotate: 135deg;
}

.biztech-theme-portal-chevron-up[b-pntlvd3cf3] {
    rotate: -45deg;
}

/* The footer, as PortalLayout.razor.css draws it, with its page links. */
.biztech-theme-portal-footer[b-pntlvd3cf3] {
    display: flex;
    justify-content: center;
    gap: 24px;
    padding: 8px 24px;
    background: var(--biztech-portal-footer-ground, var(--biztech-palette-surface));
    color: var(--biztech-portal-footer-ink, var(--biztech-palette-text-primary));
    border-block-start: 1px solid var(--biztech-portal-footer-edge, var(--biztech-palette-outline-subtle));
}

.biztech-theme-portal-footer-link[b-pntlvd3cf3] {
    color: var(--biztech-portal-footer-link, var(--biztech-palette-text-secondary));
}

/* The width sketch: a 1440px screen drawn as blocks, its column the theme's share of it - two thirds narrow, about
   four fifths standard, all of it wide - with the page's ground either side. Blocks rather than the page's words,
   because words squeezed into a narrower column read as a broken page rather than a narrower one. */
.biztech-theme-portal-sketch[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding-block-end: 24px;
}

.biztech-theme-portal-sketch-screen[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    gap: 24px;
    padding-block-end: 24px;
}

.biztech-theme-portal-sketch-header[b-pntlvd3cf3] {
    block-size: 56px;
    background: var(--biztech-portal-header-ground, color-mix(in srgb, var(--biztech-palette-surface) 86%, transparent));
    border-block-end: 1px solid var(--biztech-portal-header-edge, var(--biztech-palette-outline));
}

.biztech-theme-portal-sketch-column[b-pntlvd3cf3] {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: var(--biztech-portal-gap, 16px);
    inline-size: calc(100% * var(--biztech-portal-measure-share, 0.792));
    margin-inline: auto;
    padding-inline: 16px;
    border-inline: 1px dashed var(--biztech-palette-outline-subtle);
    transition: inline-size var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-theme-portal-sketch-welcome[b-pntlvd3cf3] {
    block-size: 160px;
    border-radius: calc(var(--biztech-radius-default) * 2.5);
    background: var(--biztech-portal-welcome-ground, light-dark(var(--biztech-palette-primary), var(--biztech-palette-primary-container)));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-welcome-edge, transparent);
}

.biztech-theme-portal-sketch-grid[b-pntlvd3cf3] {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--biztech-portal-gap, 16px);
}

.biztech-theme-portal-sketch-cell[b-pntlvd3cf3] {
    block-size: 120px;
    border: 1px solid var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-theme-portal-sketch-caption[b-pntlvd3cf3] {
    text-align: center;
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-body1-size);
}

@media (prefers-reduced-motion: reduce) {
    .biztech-theme-portal-sketch-column[b-pntlvd3cf3] {
        transition: none;
    }
}

.biztech-theme-portal-welcome:dir(rtl)[b-pntlvd3cf3]::before,
.biztech-theme-portal-inner-lead:dir(rtl)[b-pntlvd3cf3]::before {
    mask-image: linear-gradient(to left, transparent, currentColor 70%);
}

/* The case launcher, as AgentCaseLauncher.razor.css and CaseTemplateCard.razor.css draw it. */
.biztech-theme-portal-tabs[b-pntlvd3cf3] {
    display: flex;
    gap: 4px;
    align-self: flex-start;
    padding: var(--biztech-portal-tabs-track-inset, 0);
    border-radius: var(--biztech-radius-default);
    box-shadow: inset 0 0 0 1px var(--biztech-portal-tabs-track, transparent);
}

.biztech-theme-portal-tabs:has(.biztech-theme-portal-tab)[b-pntlvd3cf3] {
    border-block-end: 1px solid var(--biztech-portal-tabs-rule, var(--biztech-palette-outline-subtle));
}

.biztech-theme-portal-tab[b-pntlvd3cf3] {
    padding: 8px 12px;
    border-block-end: 2px solid transparent;
    border-radius: calc(var(--biztech-radius-default) * var(--biztech-portal-tab-radius-factor, 0));
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-portal-tab-current[b-pntlvd3cf3] {
    border-block-end-color: var(--biztech-portal-tab-indicator, var(--biztech-palette-primary));
    background: var(--biztech-portal-tab-current-ground, transparent);
    color: var(--biztech-portal-tab-current-ink, var(--biztech-palette-text-primary));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-tab-current-ring, transparent);
    font-weight: 600;
}

.biztech-theme-portal-case[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    align-items: var(--biztech-portal-case-align, stretch);
    gap: 12px;
    padding: 20px;
    border: 1px solid var(--biztech-portal-card-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    color: var(--biztech-palette-text-primary);
    text-align: var(--biztech-portal-case-text-align, start);
}

.biztech-theme-portal-case .biztech-theme-portal-icon[b-pntlvd3cf3] {
    inline-size: 44px;
    block-size: 44px;
}

.biztech-theme-portal-case-facts[b-pntlvd3cf3] {
    display: var(--biztech-portal-case-details, flex);
    justify-content: var(--biztech-portal-case-justify, flex-start);
    gap: 16px;
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-portal-start[b-pntlvd3cf3] {
    display: inline-flex;
    align-items: center;
    align-self: var(--biztech-portal-case-justify, flex-start);
    gap: 4px;
    padding: 4px 12px 4px 16px;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-portal-start-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-start-ink, var(--biztech-palette-primary));
    box-shadow: inset 0 0 0 1px var(--biztech-portal-start-ring, transparent);
    font-weight: 600;
}

.biztech-theme-portal-table[b-pntlvd3cf3] {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

.biztech-theme-portal-table-head[b-pntlvd3cf3],
.biztech-theme-portal-table-row[b-pntlvd3cf3] {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    gap: 12px;
    padding: var(--biztech-portal-row-inset, 8px) 12px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-theme-portal-table-head[b-pntlvd3cf3] {
    color: var(--biztech-palette-text-secondary);
    font-weight: 600;
}

.biztech-theme-portal-table-row:last-child[b-pntlvd3cf3] {
    border-block-end: none;
}

.biztech-theme-portal-table-row:nth-child(odd)[b-pntlvd3cf3] {
    background: var(--biztech-portal-row-stripe, transparent);
}

/* The install suggestion, as InstallPrompt.razor.css draws it. */
.biztech-theme-portal-install[b-pntlvd3cf3] {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 12px 12px 16px;
    border: 1px solid var(--biztech-portal-install-edge, var(--biztech-palette-outline-subtle));
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-portal-install-ground, var(--biztech-palette-surface));
    color: var(--biztech-portal-install-ink, var(--biztech-palette-text-primary));
}

.biztech-theme-portal-install-glyph[b-pntlvd3cf3] {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 40px;
    block-size: 40px;
    border-radius: var(--biztech-portal-icon-radius-row, var(--biztech-radius-default));
    background: var(--biztech-portal-icon-ground, color-mix(in srgb, var(--biztech-palette-primary-container) 55%, var(--biztech-palette-surface)));
    color: var(--biztech-portal-icon-ink, var(--biztech-palette-primary));
}

.biztech-theme-portal-install-text[b-pntlvd3cf3] {
    flex: 1 1 auto;
    font-size: var(--biztech-font-body1-size);
}

.biztech-theme-portal-install-action[b-pntlvd3cf3] {
    padding: 8px 16px;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-portal-install-action-ground, var(--biztech-palette-primary));
    color: var(--biztech-portal-install-action-ink, var(--biztech-palette-on-primary));
    font-weight: 600;
}
/* /Components/Themes/ThemePreviewCanvas.razor.rz.scp.css */
/* W21-04 · the preview canvas: a header with the mode switch, a framed miniature of the console, and
   the contrast line. The frame is the page's own background, so surfaces read against it as they do
   in the app. Every length a scale step; the app bar is the theme's own height. */
.biztech-theme-canvas[b-9yi39f2i8w] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-theme-canvas-head[b-9yi39f2i8w] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-theme-canvas-frame[b-9yi39f2i8w] {
    overflow: hidden;
    /* The case list's card edge and corners (Inquiries.razor.css), so the frame reads as one of the console's cards.
       It was the full Outline edge, visibly heavier than every other card. */
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-background);
    color: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);

    /* No color-scheme here: the frame's own variable block (EmitScoped) declares the preview mode's, so light-dark()
       in the portal's welcome card and the native controls follow the preview's Light and Dark rather than the
       application's mode. An inherit here out-ranked that block and made the preview follow the app instead. */

    /* The miniature is the console, so it takes the console's control height: 32px unless the theme names one
       (MainLayout's rule). Out-ranks the scoped variable block's own control-height, which is the 40px the pages
       outside the console use. */
    --biztech-control-height: var(--biztech-console-control-height);

    /* The theme's drawer width, as the console draws it: the miniature is a 1080px page scaled as a whole, so the rail
       is no longer scaled on its own. It was 0.6 of the width while the miniature reflowed into half a page. */
    --biztech-theme-canvas-drawer-width: var(--biztech-drawer-width, 272px);
}

/* 🔴 MinimumHeight · 640px, the portal miniature's (ThemePortalPreview.razor.css), so the App and Portal views are the same
   picture size and switching does not jump. W19-14 · the drawer and the page side by side, as the console is now. */
.biztech-theme-canvas-console[b-9yi39f2i8w] {
    display: grid;
    grid-template-columns: auto 1fr;
    min-block-size: 640px;
}

/* Drawn at 1080px, the portal miniature's width, and scaled to the frame by biztech-fit.js, which sets data-fit once it is live; a failed import leaves it at
   the frame's width (R9.11). zoom rather than transform, so the frame's box is the scaled one. */
.biztech-theme-canvas-console[data-fit][b-9yi39f2i8w] {
    /* 1 until the module measures the frame; it then writes the ratio on the element itself, which wins. */
    --biztech-fit-zoom: 1;

    inline-size: 1080px;
    zoom: var(--biztech-fit-zoom);
}

/* W19-14 · the drawer's head: the mark, the product's name and the fold control, as the console's drawer heads itself. */
.biztech-theme-canvas-drawer-head[b-9yi39f2i8w] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 4px 8px 8px;
    font-family: var(--biztech-font-family);
    font-weight: 600;
    white-space: nowrap;
}

.biztech-theme-canvas-brand[b-9yi39f2i8w] {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
}

/* The product's name as the drawer sets it: the second word in the primary colour. */
.biztech-theme-canvas-brand-accent[b-9yi39f2i8w] {
    color: var(--biztech-palette-primary);
    font-weight: 400;
}

/* W26-02. Five eighths of the mark's theme height - today's 20px at the 2rem default - capped as the real mark is by the
   bar's height less 8px each side, at the same scale. */
.biztech-theme-canvas-mark[b-9yi39f2i8w] {
    inline-size: calc(var(--biztech-appbar-logo-height, 2rem) * 0.625);
    block-size: calc(var(--biztech-appbar-logo-height, 2rem) * 0.625);
    max-inline-size: calc((var(--biztech-appbar-height, 64px) - 16px) * 0.625);
    max-block-size: calc((var(--biztech-appbar-height, 64px) - 16px) * 0.625);
    flex: none;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-primary);
}

/* The page beside the drawer. */
.biztech-theme-canvas-body[b-9yi39f2i8w] {
    min-inline-size: 0;
}

.biztech-theme-canvas-drawer[b-9yi39f2i8w] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    box-sizing: border-box;
    inline-size: var(--biztech-theme-canvas-drawer-width);
    padding: 8px;
    overflow: hidden;
    background: var(--biztech-palette-drawer-background);
    border-inline-end: 1px solid var(--biztech-palette-outline-subtle);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
}

/* The console's fold, in miniature: the drawer narrows to its rail of glyphs at the theme's motion duration, so Motion is
   seen by toggling it. Every row is nowrap and the drawer clips, so nothing inside rewraps as it narrows. */
.biztech-theme-canvas-drawer[b-9yi39f2i8w] {
    transition: inline-size var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-theme-canvas-drawer-closed[b-9yi39f2i8w] {
    inline-size: 64px;
}

.biztech-theme-canvas-drawer-closed .biztech-theme-canvas-brand[b-9yi39f2i8w],
.biztech-theme-canvas-drawer-closed .biztech-theme-canvas-words[b-9yi39f2i8w],
.biztech-theme-canvas-drawer-closed .biztech-theme-canvas-nav-child[b-9yi39f2i8w] {
    display: none;
}

.biztech-theme-canvas-drawer-closed .biztech-theme-canvas-drawer-head[b-9yi39f2i8w] {
    flex-direction: column;
    padding-inline: 0;
}

.biztech-theme-canvas-drawer-body[b-9yi39f2i8w] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
}

/* The organisation switcher: an outlined field-like row, as the console's drawer draws it. */
.biztech-theme-canvas-switcher[b-9yi39f2i8w] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-block-end: 8px;
    padding: 8px 12px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    white-space: nowrap;
}

/* The mode and the account at the drawer's foot, under a rule. */
.biztech-theme-canvas-foot[b-9yi39f2i8w] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-block-start: auto;
    padding-block-start: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

.biztech-theme-canvas-nav[b-9yi39f2i8w] {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-radius: var(--biztech-radius-default);
    color: var(--biztech-palette-text-primary);
    white-space: nowrap;
}

/* A group holding the current page, in the primary ink; its entries carry no glyph and sit under its name. */
.biztech-theme-canvas-nav-group[b-9yi39f2i8w] {
    color: var(--biztech-palette-primary);
    font-weight: 600;
}

.biztech-theme-canvas-nav-child[b-9yi39f2i8w] {
    padding-inline-start: 40px;
}

.biztech-theme-canvas-nav-current[b-9yi39f2i8w] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 16%, transparent);
    color: var(--biztech-palette-primary);
    font-weight: 600;
}

.biztech-theme-canvas-content[b-9yi39f2i8w] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
}

.biztech-theme-canvas-page-head[b-9yi39f2i8w] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

/* The case list's rows: three columns, a rule between rows, the header in the secondary ink. */
.biztech-theme-canvas-content[b-9yi39f2i8w]  .biztech-theme-canvas-table {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.biztech-theme-canvas-table-row[b-9yi39f2i8w] {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    gap: 16px;
    padding: 12px 16px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
    font-size: var(--biztech-font-body2-size);
}

.biztech-theme-canvas-table-head[b-9yi39f2i8w] {
    border-block-start: none;
    color: var(--biztech-palette-text-secondary);
    font-weight: 600;
}

.biztech-theme-canvas-card[b-9yi39f2i8w] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-theme-canvas-row[b-9yi39f2i8w] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

@media (max-width: 599.98px) {
    .biztech-theme-canvas-console[b-9yi39f2i8w] {
        grid-template-columns: 1fr;
    }

    .biztech-theme-canvas-drawer[b-9yi39f2i8w] {
        display: none;
    }
}

/* The miniature's card takes the console's card edge and corners, so the preview shows the panels as the app draws
   them now: the case list's and the case screens' cards are on outline-subtle at twice the radius. Its shadow is
   UiPaper's own - the theme's Depth - so Depth is seen here as it is on every page. */
.biztech-theme-canvas-content[b-9yi39f2i8w]  .biztech-paper {
    border-color: var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
}

/* R6.8: the OS's reduced-motion choice wins over the theme's, as it does on the console's drawer. */
@media (prefers-reduced-motion: reduce) {
    .biztech-theme-canvas-drawer[b-9yi39f2i8w] {
        transition: none;
    }
}
/* /Components/Themes/ThemeSettingsPanel.razor.rz.scp.css */
/* W21-04 · the settings pane: sections as disclosures, each summary a name on the left and the
   section's current value on the right; the body a column of controls. Every length a scale step. */
.biztech-theme-settings[b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.biztech-theme-section-open[b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-block-end: 8px;
}

.biztech-theme-section[b-aygl80l72b] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);

    /* W19-07 · each settings section is a panel on the page, so it takes the theme's Depth as a card does. */
    box-shadow: var(--biztech-shadow-card);
}

.biztech-theme-section > summary[b-aygl80l72b] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-block-size: 48px;
    padding-inline: 16px;
    cursor: pointer;
    list-style: none;
    font-family: var(--biztech-font-family);
}

.biztech-theme-section > summary[b-aygl80l72b]::-webkit-details-marker {
    display: none;
}

.biztech-theme-section > summary[b-aygl80l72b]::after {
    content: "";
    flex: none;
    inline-size: 8px;
    block-size: 8px;
    border-inline-end: 2px solid currentcolor;
    border-block-end: 2px solid currentcolor;
    transform: rotate(45deg);
    color: var(--biztech-palette-text-secondary);

    /* W19-07 · turns at the theme's motion duration rather than flipping. */
    transition: transform var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-theme-section[open] > summary[b-aygl80l72b]::after {
    transform: rotate(-135deg);
}

.biztech-theme-section-name[b-aygl80l72b] {
    flex: 1 1 auto;
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    color: var(--biztech-palette-text-primary);
}

.biztech-theme-section-value[b-aygl80l72b] {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-section-body[b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 0 16px 16px;
}

/* The colour pickers flow into as many columns as the panel has room for, rather than one tall column with the
   right half empty. 248px is one picker's whole row - the 40px swatch, the 112px hex field and the Inherit button
   with their 8px gaps - so Inherit appearing never pushes a picker wider than its column. Aligned to the start, so
   a picker showing an error under it does not stretch its neighbours. */
.biztech-theme-swatches[b-aygl80l72b] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
    align-items: start;
    gap: 12px 16px;
}

.biztech-theme-dot[b-aygl80l72b] {
    inline-size: 12px;
    block-size: 12px;
    border-radius: 999px;
    border: 1px solid var(--biztech-palette-outline);
}

.biztech-theme-dot-primary[b-aygl80l72b] { background: var(--biztech-palette-primary); }
.biztech-theme-dot-secondary[b-aygl80l72b] { background: var(--biztech-palette-secondary); }
.biztech-theme-dot-tertiary[b-aygl80l72b] { background: var(--biztech-palette-tertiary); }

.biztech-theme-presets[b-aygl80l72b] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    /* Every row as tall as the tallest card, so a card that wraps onto a second row is the same size as the
       first row's rather than as short as its own text. */
    grid-auto-rows: 1fr;
    gap: 8px;
}

.biztech-theme-card[b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    padding: 12px;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);
    text-align: start;
    cursor: pointer;
}

.biztech-theme-card:hover:not(:disabled)[b-aygl80l72b] {
    border-color: var(--biztech-palette-primary);
}

.biztech-theme-card[aria-pressed="true"][b-aygl80l72b] {
    border-color: var(--biztech-palette-primary);
    box-shadow: inset 0 0 0 1px var(--biztech-palette-primary);
}

.biztech-theme-card:disabled[b-aygl80l72b] {
    cursor: default;
    color: var(--biztech-palette-text-disabled);
}

.biztech-theme-card-name[b-aygl80l72b] {
    font-size: var(--biztech-font-body2-size);
    font-weight: 600;
}

.biztech-theme-card-note[b-aygl80l72b] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

.biztech-theme-exact > summary[b-aygl80l72b] {
    cursor: pointer;
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
    color: var(--biztech-palette-primary);
}

.biztech-theme-exact[open][b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.biztech-theme-errors[b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: var(--biztech-palette-error);
}

/* W19-07 · the presets heading with "Save as preset" at its end, and a saved preset's card with its
   delete pinned to the card's corner, beside the card rather than inside it. */
.biztech-theme-presets-head[b-aygl80l72b] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.biztech-theme-card-wrap[b-aygl80l72b] {
    position: relative;
    display: flex;
}

.biztech-theme-card-wrap > .biztech-theme-card[b-aygl80l72b] {
    flex: 1 1 auto;
    padding-inline-end: 40px;
}

.biztech-theme-card-delete[b-aygl80l72b] {
    position: absolute;
    inset-block-start: 4px;
    inset-inline-end: 4px;
}

/* R6.8: the OS's reduced-motion choice wins over the theme's. */
@media (prefers-reduced-motion: reduce) {
    .biztech-theme-section > summary[b-aygl80l72b]::after {
        transition: none;
    }
}

/* W25-04 · A11. A picture or caption below the tenant: its label and where it is set. The fieldset's own box is
   taken away by app.css's .biztech-choice-group. */
.biztech-theme-tenant-only[b-aygl80l72b] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Ui/UiAlert.razor.rz.scp.css */
/* W0-52 · the inline alert. The glyph is the severity's role, and PaletteContrast requires every status colour
   at 4.5:1 as text against BOTH Background and Surface. So an alert cannot be illegible on either
   surface in either mode on any palette that boots. The body text takes the page's own ink rather
   than the severity's: a whole paragraph in error red is harder to read than one in the ordinary
   colour beside a red glyph, and R12.7's second channel is already spent on the
   glyph. */

/* 🔴 W19-23 · THE OUTLINED BOX IS GONE. A 1px border in the full severity colour around a whole row read as the loudest
   object on every console page - louder than the fields it was about - and W19-11 had already replaced the same shape
   with the composer note for tips. An alert now takes the note's shape: the severity's tint as the ground, the glyph in
   a deeper tint of it, and a hairline of the same hue so the block keeps an edge on a white surface and on dark (R6.6).
   The severity is still carried three ways - the hue, the glyph's shape (R12.7) and, on a failure, role="alert". */
.biztech-alert[b-vx07oufthc] {
    --biztech-alert-tone: var(--biztech-palette-info);

    display: flex;
    align-items: center;
    gap: 12px;

    box-sizing: border-box;
    padding: 12px;
    border: 1px solid color-mix(in srgb, var(--biztech-alert-tone) 24%, transparent);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: color-mix(in srgb, var(--biztech-alert-tone) 8%, var(--biztech-palette-surface));

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
    letter-spacing: var(--biztech-font-body2-letter-spacing);
}

/* R5.7's console density. /i/{key} is comfortable and leaves this off. */
.biztech-alert-dense[b-vx07oufthc] {
    padding: 8px 12px;
    gap: 8px;
}

.biztech-alert-info[b-vx07oufthc] { --biztech-alert-tone: var(--biztech-palette-info); }
.biztech-alert-success[b-vx07oufthc] { --biztech-alert-tone: var(--biztech-palette-success); }
.biztech-alert-warning[b-vx07oufthc] { --biztech-alert-tone: var(--biztech-palette-warning); }
.biztech-alert-error[b-vx07oufthc] { --biztech-alert-tone: var(--biztech-palette-error); }

/* The glyph in its tinted circle, the composer note's 32px mark; 24px at the console's density. */
.biztech-alert-mark[b-vx07oufthc] {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--biztech-alert-tone) 16%, transparent);
    color: var(--biztech-alert-tone);
}

.biztech-alert-dense .biztech-alert-mark[b-vx07oufthc] {
    inline-size: 24px;
    block-size: 24px;
}

.biztech-alert-body[b-vx07oufthc] {
    flex: 1 1 auto;
    min-inline-size: 0;
    color: var(--biztech-palette-text-primary);

    /* R4.6's prose measure. A failure message is prose - R10.4 asks it to say what happened and then
       what to do next - and a sentence that runs the width of a console is one nobody finishes. */
    max-inline-size: 46rem;
}

/* The action at the row's end, as the note's and the filter bar's are: the message stops at its prose measure, and Retry beside
   the last word left it floating mid-row. An auto margin aligns it; it spaces nothing (I18). */
.biztech-alert-action[b-vx07oufthc] {
    flex: none;
    margin-inline-start: auto;
}
/* /Components/Ui/UiButton.razor.rz.scp.css */
/* W0-52 · the button.

   🔴 A <button> ARRIVES WITH USER-AGENT DEFAULTS, and app.css already records what happens when they
   are left alone: T24 round 3 turned the board card into a real <button> and had to undo "centred
   13px Arial and a shrink-to-fit width" - the card rendered as a small grey button rather than a
   card. MudBlazor's `*` reset hides some of that today and W0-53 removes it, so every one of them is
   declared here.

   The colours are the palette's, and the contrast is decided by the palette rather than by this
   file: a FILLED button paints an On* pair (OnPrimary on Primary, tested at 4.5:1), and an OUTLINED
   or TEXT one paints the role as ink on the page or a card, which PaletteContrast also requires at
   4.5:1 against both surfaces. Neither can fail on a palette that boots. */

.biztech-button[b-7pp4wp8xz3] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;

    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-default);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-button-line-height);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    /* D1: sentence case. The token is `none` where MudTheme still says `uppercase`. */
    text-transform: var(--biztech-font-button-transform);

    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    background: transparent;
    color: inherit;

    /* R6.7: 120ms, ease-in-out, and only properties that do not lay out. */
    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out, border-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

.biztech-button-small[b-7pp4wp8xz3] {
    min-block-size: 32px;
    padding: 4px 12px;
}

/* W0-63 · finding 6. The floor reads the token - 40px at :root, 32px under .biztech-shell - so this
   button compacts with the console and keeps its box everywhere else. The DEFINITE size that makes
   declared equal rendered is `.biztech-shell .biztech-button` in app.css; see its note for why a floor
   alone leaves a medium button rendering 42.5.

   .biztech-button-small keeps its literal 32px above: that is already the console's target and already
   on the scale, and outside the console a 32px small button is what /i/{key} was signed off with. */
.biztech-button-medium[b-7pp4wp8xz3] {
    min-block-size: var(--biztech-control-height);
    padding: var(--biztech-control-padding-block, 8px) 16px;
}

/* ── Outlined · the house default (R3.6: the 3:1 lives on the border) ──────────────────────────── */

.biztech-button-outlined[b-7pp4wp8xz3] {
    border-color: currentcolor;
    background: transparent;
}

.biztech-button-outlined:hover:not(:disabled)[b-7pp4wp8xz3] {
    background: color-mix(in srgb, currentcolor 8%, transparent);
}

/* ── Text · the lower-weight action beside a filled one ────────────────────────────────────────── */

.biztech-button-text[b-7pp4wp8xz3] {
    border-color: transparent;
    background: transparent;
}

.biztech-button-text:hover:not(:disabled)[b-7pp4wp8xz3] {
    background: color-mix(in srgb, currentcolor 8%, transparent);
}

/* 🔴 A BUTTON THAT IS ON. `Pressed` writes aria-pressed on this component's <button> branch; this is
   what it looks like, and it lives here because the seam that publishes the parameter owns what the
   parameter draws.

   AFTER .biztech-button-text above, which is what makes it work at all. Both are (0,2,0) once Blazor
   appends the scope attribute, so source order decides - and the first thing tried was app.css, where
   the same selector is also (0,2,0) but the scoped bundle is linked afterwards. `background:
   transparent` won, and the open tab stopped being tinted at all.

   Three surfaces read it: /inquiries' Active/Archived switch, the create panel's Details/Process/
   Delivery strip, and a stage row's Edit. R8.2's count, which is why it is one rule rather than three
   copies.

   🔴 THE TINT AND THE BORDER TOGETHER, AND THE MEASUREMENT IS WHY BOTH. 12% of primary reads 1.5:1
   against the page on light and 1.19:1 on dark - invisible, leaving the ink's colour as the only
   signal, which is the "colour alone" WCAG 1.4.1 rules out. 12% rather than the nav's 8% because those
   carry a 2px inset bar as well and a button has nothing but its own ground to say it is on.

   `border-color` only: .biztech-button-text declares a transparent 1px border already, so a pressed
   control does not change size and nothing beside it moves. */
.biztech-button[aria-pressed="true"][b-7pp4wp8xz3] {
    background: color-mix(in srgb, var(--biztech-palette-primary) 12%, transparent);
    color: var(--biztech-palette-primary);
    border-color: var(--biztech-palette-primary);
}

/* ── Filled · one per surface ──────────────────────────────────────────────────────────────────── */

/* 🔴 THE BASE RULE CARRIES THE FALLBACK, AND IT EXISTS BECAUSE TWO MEMBERS OF UiColor HAD NO RULE AT
   ALL. `Filled` + `Default` and `Filled` + `Inherit` matched none of the seven role rules below, so a
   filled button rendered with NO GROUND and whatever ink it had inherited: on /case-types the SELECTED
   tab was indistinguishable from the unselected ones, and hovering it painted a dark ground under
   near-black ink at 1.24:1 against R3.1's 4.5 floor. Measured in Chrome on 2026-09-07.

   A fallback here rather than two more role rules, so the answer covers every member of the enum -
   including one added later, which is the case that would otherwise repeat this exactly. Primary is the
   fallback because this section's own heading is the reason: ONE FILLED COLOUR PER SURFACE, so a filled
   button that names no role is asking for that one. */
.biztech-button-filled[b-7pp4wp8xz3] {
    background: var(--biztech-button-fill, var(--biztech-palette-primary));
    color: var(--biztech-button-ink, var(--biztech-palette-on-primary));
    border-color: var(--biztech-button-fill, var(--biztech-palette-primary));
}

.biztech-button-filled.biztech-button-primary[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-primary);
    --biztech-button-ink: var(--biztech-palette-on-primary);
}

.biztech-button-filled.biztech-button-secondary[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-secondary);
    --biztech-button-ink: var(--biztech-palette-on-secondary);
}

.biztech-button-filled.biztech-button-tertiary[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-tertiary);
    --biztech-button-ink: var(--biztech-palette-on-tertiary);
}

.biztech-button-filled.biztech-button-success[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-success);
    --biztech-button-ink: var(--biztech-palette-on-success);
}

.biztech-button-filled.biztech-button-warning[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-warning);
    --biztech-button-ink: var(--biztech-palette-on-warning);
}

.biztech-button-filled.biztech-button-error[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-error);
    --biztech-button-ink: var(--biztech-palette-on-error);
}

.biztech-button-filled.biztech-button-info[b-7pp4wp8xz3] {
    --biztech-button-fill: var(--biztech-palette-info);
    --biztech-button-ink: var(--biztech-palette-on-info);
}

/* 🔴 THE MIX READS THE BUTTON'S OWN FILL, NOT THE BRAND. This named --biztech-palette-primary, so
   hovering a filled ERROR button moved it toward blue rather than toward its own red, and hovering the
   unstyled Default one is what made the contrast failure above visible. Every role now sets
   --biztech-button-fill, and the base rule's fallback answers for the ones that do not.

   Darkened toward the page's own ink rather than by an opacity: R3.9 forbids expressing a colour
   as opacity on inherited ink, and mixing keeps the result a real value something could measure. */
.biztech-button-filled:hover:not(:disabled)[b-7pp4wp8xz3] {
    background: color-mix(
        in srgb,
        currentcolor 12%,
        var(--biztech-button-fill, var(--biztech-palette-primary)));
}

/* ── Ink for the unfilled variants ─────────────────────────────────────────────────────────────── */

.biztech-button-outlined.biztech-button-default[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-default[b-7pp4wp8xz3] { color: var(--biztech-palette-text-primary); }
.biztech-button-outlined.biztech-button-inherit[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-inherit[b-7pp4wp8xz3] { color: inherit; }
.biztech-button-outlined.biztech-button-primary[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-primary[b-7pp4wp8xz3] { color: var(--biztech-palette-primary); }
.biztech-button-outlined.biztech-button-secondary[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-secondary[b-7pp4wp8xz3] { color: var(--biztech-palette-secondary); }
.biztech-button-outlined.biztech-button-tertiary[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-tertiary[b-7pp4wp8xz3] { color: var(--biztech-palette-tertiary); }
.biztech-button-outlined.biztech-button-success[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-success[b-7pp4wp8xz3] { color: var(--biztech-palette-success); }
.biztech-button-outlined.biztech-button-warning[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-warning[b-7pp4wp8xz3] { color: var(--biztech-palette-warning); }
.biztech-button-outlined.biztech-button-error[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-error[b-7pp4wp8xz3] { color: var(--biztech-palette-error); }
.biztech-button-outlined.biztech-button-info[b-7pp4wp8xz3],
.biztech-button-text.biztech-button-info[b-7pp4wp8xz3] { color: var(--biztech-palette-info); }

/* ── Disabled ─────────────────────────────────────────────────────────────────────────────────── */

/* TextDisabled is deliberately dim and deliberately exempt from contrast (R3.8): WCAG 1.4.3 exempts
   inactive components, and a "disabled" colour that cleared 4.5:1 would make a disabled control look
   enabled - which is a worse defect than the one it would fix. R9.2 puts the REASON in a caption
   beside the control, where it can actually be read. */
.biztech-button:disabled[b-7pp4wp8xz3] {
    color: var(--biztech-palette-text-disabled);
    border-color: var(--biztech-palette-outline-subtle);
    background: transparent;
    cursor: default;
}

.biztech-button-label[b-7pp4wp8xz3] {
    /* R4.7 prefers wrap over truncation, but a button's label is short by construction and a wrapped
       one changes the control's height mid-row. The label stays on one line; a label long enough to
       need two is a label to rewrite. */
    display: inline-block;
}

@media (prefers-reduced-motion: reduce) {
    .biztech-button[b-7pp4wp8xz3] {
        transition: none;
    }
}
/* /Components/Ui/UiChatComposer.razor.rz.scp.css */
/* W6-44 · the seam's chat composer.

   Tokens and scale steps only (R3.1, R5.4). The box's own look — border, radius, ground, ink, type — is
   `.biztech-input`, global in app.css, which is what stops a hand-shaped control drifting from what
   every other field renders. Nothing here restates any of it.

   🔴 THE TYPE AND COLOUR CLASSES ARE DECLARED HERE RATHER THAN REUSED. Blazor's CSS isolation scopes a
   sheet to its own component's elements, so a class defined in UiText.razor.css matches nothing rendered
   here — it would compile, render, and silently take the inherited value. Every component in this folder
   declares the classes it names; UiIconButton.razor.css records the same. */

/* 🔴 THE ROOT HAS A RULE, AND IT NEEDS ONE FOR TWO REASONS.
   Every `biztech-*` class the markup names must be declared somewhere
   (UtilityClassTests.Every_biztech_class_the_markup_names_is_declared_somewhere), and this is where the
   caption is stacked under the row. It declares no margin and no padding, so a spacing utility the
   caller passes still reaches the element at (0,1,0) with nothing to lose to — R14.1a, and the nine
   inert utilities it was written for. */
.biztech-chat-composer[b-re8ejwh9a4] {
    display: flex;
    flex-direction: column;
}

/* The padding and the hairline are the ROW's, which is where specimen 7 draws them (`.mk-composer`
   carries both). Declared here rather than passed down from the mounting panel: a class a parent hands
   to `Class=` lands on markup this component renders, so the parent's scoped sheet cannot reach it
   without ::deep — the trap CaseProgressStrip.razor.css records. */
.biztech-chat-composer__row[b-re8ejwh9a4] {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* 🔴 CLIPPED, NOT display:none OR visibility:hidden. Both of those remove the element from the
   accessibility tree, which would take the box's accessible NAME with it — and the name is the whole
   reason there is a <label> here rather than a placeholder alone. This is app.css's skip-link idiom
   minus the focus half: a <label> is not focusable, so it never needs to come back.

   The design reference's composer is one row; W0-52's decision D1 puts the seam's labels above their
   fields. The specimen wins on the shape, R12.4 wins on the mechanism, and this rule is where the two
   meet. */
.biztech-chat-composer__label[b-re8ejwh9a4] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* min-inline-size: 0 so a long draft shrinks the box rather than pushing the send control out of the
   rail. A flex item's default minimum is its content, which is the same trap SessionStage's
   minmax(0, 1fr) answers one level up. */
.biztech-chat-composer__box[b-re8ejwh9a4] {
    flex: 1 1 auto;
    min-inline-size: 0;

    /* 🔴 NOT RESIZABLE, AND THIS IS THE ONE PLACE THAT IS RIGHT. `.biztech-input-multiline` — which this
       box deliberately does NOT wear — declares `resize: vertical` and an 80px floor, both correct for a
       form field in a page that scrolls. In a 320px rail beside a fixed 240px log, a reader dragging the
       composer taller is the only way left to make the panel push what is under it, which is the whole
       subject of W6-42 one level in. Two rows, always.

       This is not a box-model zero and it is not a property the utility layer owns (R14.1a). */
    resize: none;
}

/* 🔴 NO `margin: 0` HERE, AND UtilitySpecificityTests CAUGHT THE ATTEMPT. A <p>'s user-agent margin is
   already zeroed once, in BizTechCssVariables' document reset beside h1-h6 and hr — whose own comment
   records why: "THE ELEMENT RESET, DECLARED ONCE INSTEAD OF THIRTEEN TIMES IN THE SEAM", because a
   scoped `.x[b-xxxxxxxxxx]` is (0,2,0) against a utility's (0,1,0) and would silently outrank every
   spacing class a caller passes. This rule would have been the fourteenth restatement. */
.biztech-chat-composer__caption[b-re8ejwh9a4] {
    padding-block-start: 0.5rem;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* 🔴 W19 · THE BOX AND THE SEND, AS ONE ROW OF TWO ROUNDED SHAPES.

   The box takes the console's card corners rather than the field's plain radius, and the send is a
   40px filled square beside it - the primary colour and its own ink - so the one thing to press after
   typing is the strongest mark in the panel. It was a bare primary glyph that read as decoration at
   the end of the box. Disabled, it drops to the quiet outline fill and the disabled ink, so a shut
   composer (a session that has ended) does not offer a coloured button that does nothing.

   Reached through ::deep because the button is UiIconButton's root, a child component of this one
   (I19). Its size class is left alone - the 40px is set here as the box this row needs. The fill pair
   is the primary role and its ink, which PaletteContrast holds at 4.5:1. 10 x 4 (R5.1). */
.biztech-chat-composer__row[b-re8ejwh9a4] {
    align-items: center;
    padding: 0.75rem;
}

.biztech-chat-composer__box[b-re8ejwh9a4] {
    border-radius: calc(var(--biztech-radius-default) * 2);
}

.biztech-chat-composer__row[b-re8ejwh9a4]  .biztech-icon-button {
    flex: 0 0 auto;
    inline-size: 40px;
    block-size: 40px;
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
}

.biztech-chat-composer__row[b-re8ejwh9a4]  .biztech-icon-button:hover:not(:disabled) {
    background: color-mix(in srgb, var(--biztech-palette-on-primary) 12%, var(--biztech-palette-primary));
}

.biztech-chat-composer__row[b-re8ejwh9a4]  .biztech-icon-button:disabled {
    background: var(--biztech-palette-outline-subtle);
    color: var(--biztech-palette-text-disabled);
}

/* W22-08 · the stop control's own span, so it is a different element from the send (biztech-chat.js gates only the send).
   It lays out as the send does: one glyph at the row's end. */
.biztech-chat-composer__stop[b-re8ejwh9a4] {
    display: inline-flex;
}
/* /Components/Ui/UiChip.razor.rz.scp.css */
/* W0-52 · a labelled pill.

   🔴 THE COLOURED VARIANTS ARE SAFE BY CONSTRUCTION, AND THAT IS MEASURED RATHER THAN HOPED.
   PaletteContrast requires every brand and status role at 4.5:1 as TEXT against BOTH Background and
   Surface - "Primary used as text or an icon on the page" and "...on a card", seven roles times two
   surfaces. So an outlined chip that paints its ink and its border in a role cannot fail R3.5 on
   either surface, in either mode, on any palette that boots (an AA-failing one refuses to start).

   🔴 W0-74 REVERSED THE LAST SENTENCE OF THAT PARAGRAPH, WHICH READ: "That is also why the chip is
   outlined rather than filled: a filled one would need its On* partner and a per-role decision about
   which surface it sits on." Both objections are now answered rather than argued with - the On*
   partner is DERIVED alongside the fill and cannot be missing, and the surface is a per-mode fact the
   palette itself holds (Surface in light, Background in dark). ADR 0026 D-H. */

.biztech-chip[b-l77f5whw4r] {
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    padding: 2px 8px;
    border: 1px solid currentcolor;
    border-radius: var(--biztech-radius-pill);

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-caption-weight);
    line-height: var(--biztech-font-caption-line-height);
    letter-spacing: var(--biztech-font-caption-letter-spacing);

    /* R4.7: a chip carries a name or a count read aloud, so it wraps rather than truncating - and
       never shrinks below the 12px floor to fit, which is why the size above is a token. */
    white-space: nowrap;
}

/* `currentcolor` on the border above means an OUTLINED variant sets ONE property and the outline
   follows. A chip whose border and ink could drift apart is two decisions where there is one. */

.biztech-chip-inherit[b-l77f5whw4r] { color: inherit; }
.biztech-chip-default[b-l77f5whw4r] { color: var(--biztech-palette-text-secondary); }
.biztech-chip-secondary[b-l77f5whw4r] { color: var(--biztech-palette-secondary); }
.biztech-chip-tertiary[b-l77f5whw4r] { color: var(--biztech-palette-tertiary); }
.biztech-chip-info[b-l77f5whw4r] { color: var(--biztech-palette-info); }

/* 🔴 W0-74 · ADR 0026 D-H · THE FOUR ROLES WITH A CONTAINER READ AS A SOFT TONAL FILL.

   What makes Material 3 read as Material 3 is not its hues - it is that a status stops being an
   outline and becomes a fill with its own ink. The container roles are DERIVED from the roles above
   (R3.3, BizTechPalette's computed members), so a tenant that overrides Success gets a matching
   container for free and cannot author a failing one.

   THE INK IS SAFE BY CONSTRUCTION, AND THAT IS MEASURED RATHER THAN HOPED. PaletteContrast requires
   every On*Container at 4.5:1 on its own container, in both modes, on the shipped palette AND on
   whatever a deployment or a tenant configured - an AA-failing palette refuses to start. The worst of
   the eight is success at 6.38:1.

   THE BORDER IS THE FILL, NOT currentcolor. currentcolor is now the container's INK, so an inherited
   border would draw a dark ring round a soft pill. Painting the border the fill keeps it one shape,
   and it costs no rule: R3.6 puts 1.4.11's 3:1 on a border that CARRIES MEANING, and a chip is inert
   by design - UiChip declares no OnClick and no OnClose - so what has to be legible here is the label.

   🔴 AND THE SECOND ARGUMENT OF EACH var() IS THE OUTLINE TREATMENT, KEPT. Where no token block has
   been emitted, --biztech-palette-*-container resolves to nothing and each chain falls back to exactly
   what this file declared before this card: transparent ground, currentcolor border, the role as ink.
   PortalStyleSheetTests asserts BOTH halves of every chain, because a dropped fallback looks identical
   in the one context anybody tests.

   NOT secondary, tertiary or info: four roles are what the surfaces use, and R11.4's "add a row rather
   than a synonym" reasoning applies - add the fifth when something needs it. A page may therefore show
   a filled chip beside an outlined one, which is the decision above and not a miss. */

.biztech-chip-primary[b-l77f5whw4r] {
    color: var(--biztech-palette-on-primary-container, var(--biztech-palette-primary));
    background: var(--biztech-palette-primary-container, transparent);
    border-color: var(--biztech-palette-primary-container, currentcolor);
}

.biztech-chip-success[b-l77f5whw4r] {
    color: var(--biztech-palette-on-success-container, var(--biztech-palette-success));
    background: var(--biztech-palette-success-container, transparent);
    border-color: var(--biztech-palette-success-container, currentcolor);
}

.biztech-chip-warning[b-l77f5whw4r] {
    color: var(--biztech-palette-on-warning-container, var(--biztech-palette-warning));
    background: var(--biztech-palette-warning-container, transparent);
    border-color: var(--biztech-palette-warning-container, currentcolor);
}

.biztech-chip-error[b-l77f5whw4r] {
    color: var(--biztech-palette-on-error-container, var(--biztech-palette-error));
    background: var(--biztech-palette-error-container, transparent);
    border-color: var(--biztech-palette-error-container, currentcolor);
}
/* /Components/Ui/UiCodeEditor.razor.rz.scp.css */
/* W20-07 · ADR 0035 · the seam's code editor.

   Tokens only (R3.1). This sheet reaches the host element and the caption, which are this component's own markup
   (I19), and nothing CodeMirror draws inside the host: those elements are created by the module, carry no scope
   attribute, and are themed from JavaScript with the same tokens (biztech-code-editor.js, EditorView.theme).

   The root declares no margin and no padding, so a spacing utility a caller passes in Class still reaches it at
   (0,1,0) with nothing to lose to (R14.1a). */
.biztech-code-editor[b-6rygz4px1v] {
    display: block;
    min-inline-size: 0;

    /* The box before biztech-code-editor.js attaches, and the same 12rem floor that module gives
       `.cm-content` — so the editor does not change height as it mounts. It is a floor and not a
       height: CodeMirror grows the box with the text up to the module's maxHeight, and a declared
       height here would put empty surface under a short document. */
    min-block-size: 12rem;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    overflow: hidden;
}

/* W27-06 · Compact: a formula or an HTML field is a few lines, and a 12rem floor under each of six composer
   fields would bury the form. 6rem is 96px = 24 × 4, about four lines; the module gives `.cm-content` the same
   floor when it is told Compact, so the box still does not change height as it mounts. */
.biztech-code-editor--compact[b-6rygz4px1v] {
    min-block-size: 6rem;
}

/* 🔴 THE FOCUS RING IS THE HOST'S, AND THE BORDER GOES TRANSPARENT UNDER IT.

   The ring used to be CodeMirror's, declared in biztech-code-editor.js on `.cm-editor` at
   `outline-offset: -2px` — inside this element's 1px border. A focused editor therefore drew a 1px
   edge and then a 2px ring just within it: two boxes, which is exactly the defect app.css records
   against `.biztech-input` and answers there the same way. This is that answer, for the one control
   whose border and whose focusable element are different elements.

   `:has()` because the focused element is CodeMirror's and carries no scope attribute, so no scoped
   rule can reach it; the CHILD combinator follows the `.biztech-shell:has(> .biztech-drawer)`
   precedent, since the module mounts the view with `parent: host` and nothing deeper should arm this.

   Thickness and colour are unchanged from the rule this replaces, so R3.11 and WCAG 2.4.11 are
   answered by the same pixels. The border going transparent rather than taking the ring's colour is
   app.css's measurement, not a new one: 1px border plus 2px ring in one colour reads as a 3px edge. */
.biztech-code-editor:has(> .cm-focused)[b-6rygz4px1v] {
    border-color: transparent;
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 0;
}

/* Said beside the editor rather than as a snackbar: it is about this text and stays until the text is smaller. */
.biztech-code-editor__caption[b-6rygz4px1v] {
    margin-block: 0.25rem 0;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-error);
}
/* /Components/Ui/UiContainer.razor.rz.scp.css */
/* W0-52 · R5.3. The page's surface.

   🔴 W0-59 · THE BLOCK PADDING MUDMAINCONTENT USED TO SUPPLY. This file declared `padding: 0` and the
   gutters `padding-inline: 24px`, so the header above recorded only the HORIZONTAL half of the
   measurement it was built from - "24px, matching what Studio's own pages render at". The vertical half
   was never taken, because MudBlazor was still providing it and nothing was missing to measure. Six
   screens shipped flush against the app bar.

   On the container rather than on <main>, so it travels with the surface a page already wraps itself
   in: AnonymousLayout uses no UiContainer, and /i/{key}'s own 2rem panel padding is untouched. 24px
   matches the gutters below, so a page's content is inset the same distance on all four sides.

   🔴 AND THE PER-PAGE MARGINS COME OFF IN THE SAME COMMIT. /inquiries, /board and /case-types each
   carried `biztech-my-6` on their header row, which is where their 24px actually came from - measured
   in a browser, and it is why the plan's predicted gap of 0 was only true on /ui, whose header is a
   UiText and whose utility was inert (S4). Both halves at once would read 48px. Those three now carry
   `biztech-mb-6`, bottom only, and the top belongs to this rule on all four pages. R5.10 states it:
   vertical breathing room comes from the container, never from a per-page margin.

   The `padding: 0` and `margin: 0` that were here are gone rather than moved: a <div> has neither from
   the user agent, and a scoped reset outranks the utility layer (R14.1a). */

.biztech-container[b-9n4b5k6no7] {
    box-sizing: border-box;
    width: 100%;
    /* 🔴 W0-63 · FINDING 6. 16px, was 24. R5.3's drawer clearance holds - content starts at
       240 + 16 = 256 - and §5's R5.10 paragraph is rewritten in this same commit. 4 x 4 on the base
       unit. */
    padding-block: 16px;
}

/* 24px, matching what Studio's own pages render at - the measurement R5.3 was written from. */
.biztech-container-gutters[b-9n4b5k6no7] {
    /* W0-63 · finding 6. 16px, was 24, for the reason above. */
    padding-inline: 16px;
}
/* /Components/Ui/UiDialog.razor.rz.scp.css */
/*
    W14-04 · the general-purpose modal's own geometry.

    🔴 IT DECLARES .biztech-dialog ITSELF RATHER THAN REACHING FOR UiDialogHost'S, AND I19 IS WHY.

    A Blazor scoped rule reaches only the markup of the component it was written in - the stamped
    attribute compound is the selector's LAST one - so a rule in UiDialogHost.razor.css cannot style a
    <dialog> this file renders. Sharing it would mean promoting it to app.css, which puts a component's
    geometry in the global sheet where nothing associates it with its owner.

    The two copies say the same thing on purpose, and they are the same six tokens: PortalStyleSheetTests'
    colour sweep reads both, so neither can drift into a hand-picked value.

    🔴 NO z-index ANYWHERE, WHICH IS THE WHOLE REASON FOR A NATIVE <dialog>. showModal() puts the element
    in the browser's top layer, above every stacking context on the page - so R6.2's "MudBlazor owns
    1100-1600, do not compete" is satisfied by not entering the competition.

    I17: the PANEL inside declares its own padding, as UiPaper's callers do. This element carries none,
    so a caller that forgets one gets a visibly flush dialog rather than a subtly wrong one.
*/

.biztech-dialog-panel[b-q8hqthzfb5] {
    box-sizing: border-box;
    margin: auto;
    padding: 0;
    inline-size: min(34rem, calc(100vw - 32px));
    max-block-size: calc(100vh - 32px);
    overflow-y: auto;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    box-shadow: var(--biztech-shadow-overlay);
}

/* 🔴 Wide. AFTER .biztech-dialog-panel AND THAT IS THE WHOLE MECHANISM: both selectors are
   (0,1,0), so the cascade falls to source order and a rule written above would silently lose.

   46rem is UiDialogHost's measure rather than a new one, so the two overlays in this application have two
   widths between them and not three. The floor is unchanged, so R13.3 holds identically: below sm the
   dialog spans the screen it is on whichever measure it was asked for. */
.biztech-dialog-wide[b-q8hqthzfb5] {
    inline-size: min(46rem, calc(100vw - 32px));
}

.biztech-dialog-panel[b-q8hqthzfb5]::backdrop {
    background: var(--biztech-scrim);
}
/* /Components/Ui/UiDialogHost.razor.rz.scp.css */
/* W0-52 · the dialog.

   🔴 NO z-index ANYWHERE IN THIS FILE. A modal <dialog> renders in the browser's TOP LAYER, above
   every stacking context on the page whatever their z-index - so R6.2's "MudBlazor owns 1100-1600,
   do not compete" is satisfied by not entering the argument at all. This is the one overlay in the
   application that cannot be covered by anything, including MudBlazor's own dialog, and it needed no
   layer to get there.

   ::backdrop is the browser's own scrim for a modal dialog, and it reads a TOKEN rather than a
   literal. A scrim is not a colour anything is read against - PaletteContrast has nothing to say
   about it - but the colour sweep in PortalStyleSheetTests cannot tell a scrim from a hand-picked
   brand colour and should not have to, so the value lives in BizTechCssVariables beside the two
   shadows, which are there for exactly the same reason. */

.biztech-dialog[b-8bopc17jwd] {
    box-sizing: border-box;
    margin: auto;
    padding: 0;
    inline-size: min(46rem, calc(100vw - 32px));
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    box-shadow: var(--biztech-shadow-overlay);
}

.biztech-dialog[b-8bopc17jwd]::backdrop {
    background: var(--biztech-scrim);
}

.biztech-dialog-form[b-8bopc17jwd] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 24px;
    margin: 0;
}

.biztech-dialog-title[b-8bopc17jwd] {
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-h6-size);
    font-weight: var(--biztech-font-h6-weight);
    line-height: var(--biztech-font-h6-line-height);
    letter-spacing: var(--biztech-font-h6-letter-spacing);
}

.biztech-dialog-message[b-8bopc17jwd] {
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-primary);
}

.biztech-dialog-actions[b-8bopc17jwd] {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
}

/* The two buttons are plain <button type="submit"> inside the form rather than UiButton, and that is
   deliberate: `method="dialog"` only closes the dialog when the SUBMITTER is a form control of this
   form, and routing that through a component that renders type="button" would break the whole
   no-JavaScript close path. They are styled to match UiButton rather than reusing it. */
.biztech-dialog-cancel[b-8bopc17jwd],
.biztech-dialog-confirm[b-8bopc17jwd] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-block-size: 40px;
    padding: 8px 16px;
    border: 1px solid currentcolor;
    border-radius: var(--biztech-radius-default);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-button-line-height);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    text-transform: var(--biztech-font-button-transform);
    cursor: pointer;
    background: transparent;
}

/* The safe answer is the filled one. The destructive confirm was filled in error red and the cancel was an
   outline, so the one control that could not be taken back was the loudest on the surface and the easiest
   to press by mistake. Now cancel takes the theme's primary fill, the emphasis every other surface gives
   its main button. */
.biztech-dialog-cancel[b-8bopc17jwd] {
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    border-color: var(--biztech-palette-primary);
}

/* The destructive one. Error rather than Primary, because R9.13's dialog exists only to confirm
   something destructive and the button should look like what it does - in the outline, so it reads as
   the choice that needs a second look rather than the one the surface is offering. */
.biztech-dialog-confirm[b-8bopc17jwd] {
    color: var(--biztech-palette-error);
    border-color: var(--biztech-palette-error);
}

/* W18-09 · a typed confirmation's confirm, until the text is typed. UiButton's own disabled rule
   (UiButton.razor.css), so it looks like every other control that cannot be pressed yet; the field's label
   above is R9.2's reason, readable where the dim colour is not. */
.biztech-dialog-confirm:disabled[b-8bopc17jwd] {
    color: var(--biztech-palette-text-disabled);
    border-color: var(--biztech-palette-outline-subtle);
    background: transparent;
    cursor: default;
}

/* R13.3: below sm the dialog spans the screen it is on, and the actions stack so two verb labels
   are not squeezed onto one 375px row. */
@media (max-width: 599.98px) {
    .biztech-dialog[b-8bopc17jwd] {
        inline-size: calc(100vw - 32px);
    }

    .biztech-dialog-actions[b-8bopc17jwd] {
        flex-direction: column-reverse;
    }

    .biztech-dialog-cancel[b-8bopc17jwd],
    .biztech-dialog-confirm[b-8bopc17jwd] {
        inline-size: 100%;
    }
}
/* /Components/Ui/UiDivider.razor.rz.scp.css */
/* W0-52 · a separator. The user agent gives <hr> a border on all four sides and a block margin.

   🔴 W0-59 · THE BORDER IS STILL DECLARED AWAY HERE; THE MARGIN IS NOT, AND THAT IS THE POINT.
   A scoped `margin: 0` is (0,2,0) once Blazor rewrites it, so it outranked every `biztech-mb-4` the
   gallery passes this component - four dividers on /ui computing `margin: 0px`. The <hr> margin is the
   user agent's, so it is reset once by the document block BizTechCssVariables emits, where a utility
   can still beat it. The border is this component's own look and stays. */

.biztech-divider[b-vo0n8dmj0h] {
    border: 0;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}
/* /Components/Ui/UiEmptyState.razor.rz.scp.css */
/* W19-20 · the empty block on the list card: the quiet edge, twice the theme's radius and the surface ground - the same
   three declarations UiListCard draws, so an empty list and a full one are the same object (§2a C4, C5). */
.biztech-empty-state-card[b-dl37b8mnpt] {
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
}

/* A dense block on its own card. Dense drops the block padding because it was made for a block inside a card that already
   pads it; standing on its own card that left the sentence touching the card's edges - a 24px-high bar. The card keeps a
   step of air above and below, the list card's row height. */
.biztech-empty-state-card.biztech-empty-state-dense[b-dl37b8mnpt] {
    padding-block: 16px;
}
/* /Components/Ui/UiFileField.razor.rz.scp.css */
/* W19-11 · the seam's file field, once a file is held: one row naming it, beside its Remove. Tokens only (R3.1); I18. */

/* The hidden input below is placed against the field, not against the page. */
.biztech-file-field--held[b-7xfiw7arld] {
    position: relative;
}

/* The held row: a quiet box the input's height, the glyph, the name taking what is left, Remove at the end. */
.biztech-file-held[b-7xfiw7arld] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-block-size: var(--biztech-control-height);
    padding-inline: 12px 4px;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
}

.biztech-file-held-glyph[b-7xfiw7arld] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
}

/* The name, on one line and cut with an ellipsis rather than wrapping the row; its title carries the whole of it. A label
   for the input, so pressing it opens the picker - the pointer says so. */
.biztech-file-held-name[b-7xfiw7arld] {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    color: var(--biztech-palette-text-primary);
    cursor: pointer;
}

/* While a file is held the native input says its name a second time, so it is visually hidden - not removed: it stays the
   focusable control the field's label names. Reached through ::deep because InputFile renders it, not this markup (I19). */
.biztech-file-field--held[b-7xfiw7arld]  input[type="file"] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    border: 0;
    white-space: nowrap;
}

/* A keyboard focus on the hidden input is drawn on the row that stands in for it (R3.11). */
.biztech-file-field--held:has(input[type="file"]:focus-visible) .biztech-file-held[b-7xfiw7arld] {
    outline: 2px solid var(--biztech-palette-primary);
    outline-offset: 2px;
}
/* /Components/Ui/UiGrid.razor.rz.scp.css */
/* W0-52 · twelve columns, and a gap rather than a cancelled margin.

   Only the spacing values the application uses are declared. R5.2 makes Spacing="2" the house value
   and every grid in the Portal sets exactly that; 0 and 4 are here because a grid with no gutter and
   a grid with a generous one are the two a caller reaches for next, and both are on the 4px scale.
   A speculative spacing-7 would be the utility layer's mistake in a different file. */

.biztech-grid[b-m2xkei2ahj] {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    box-sizing: border-box;
}

/* 🔴 W0-78 · THE 3 WAS MISSING, AND FIVE CALL SITES HAD BEEN RENDERING WITH NO GAP AT ALL.
   Found in a browser on /users/{id}/roles: the role picker's bottom edge and the button's top edge
   measured at the same y - 482 and 482 - so the two controls were touching inside a padded panel.
   UiGrid emits `biztech-grid-spacing-{Spacing}` unconditionally, and a class nobody defines renders
   exactly like a class nobody wrote: `gap` stayed `normal`, which on a grid is zero.
   It is the same failure mode I19 exists for, one layer down - nothing errors, nothing warns, and the
   markup reads as though it asked for a gap.
   AccessRulesWriters and ActivateUser (both W0-76) carried it too, so this one line closes all three
   pages. 24px because the scale is 8px steps and 3 sits between 2's 16 and 4's 32 - the value the
   callers have been asking for since the day they were written. */
.biztech-grid-spacing-0[b-m2xkei2ahj] { gap: 0; }
.biztech-grid-spacing-1[b-m2xkei2ahj] { gap: 8px; }
.biztech-grid-spacing-2[b-m2xkei2ahj] { gap: 16px; }
.biztech-grid-spacing-3[b-m2xkei2ahj] { gap: 24px; }
.biztech-grid-spacing-4[b-m2xkei2ahj] { gap: 32px; }
/* /Components/Ui/UiGridItem.razor.rz.scp.css */
/* W0-52 · column spans, twelve per breakpoint.

   Thirty-six one-line rules rather than an inline `grid-column: span N`, because R14.2 forbids an
   inline style for layout and R5.4 forbids a magic length - and a span arriving from a FORM
   DEFINITION (the assignee form's @group.ColumnSpan) is exactly the case where a component cannot
   know the value at authoring time. Twelve of anything is what "a twelve-column grid" means, so
   none of these is speculative in the sense the utility layer's test polices.

   min-inline-size: 0 on the base, so a long unbroken string - a 36-character access key - shrinks
   its column instead of overflowing the row. Grid items default to min-content, which is the single
   most common cause of a grid that scrolls sideways on a phone. */

.biztech-col[b-6o4w5ahxby] {
    box-sizing: border-box;
    min-inline-size: 0;
}

/* W3-30 · D13: the UA's [hidden] loses to any author `display`, so the cell restates it (as UiToolbar and MainLayout's drawer do). */
.biztech-col[hidden][b-6o4w5ahxby] {
    display: none;
}

.biztech-col-xs-1[b-6o4w5ahxby] { grid-column: span 1; }
.biztech-col-xs-2[b-6o4w5ahxby] { grid-column: span 2; }
.biztech-col-xs-3[b-6o4w5ahxby] { grid-column: span 3; }
.biztech-col-xs-4[b-6o4w5ahxby] { grid-column: span 4; }
.biztech-col-xs-5[b-6o4w5ahxby] { grid-column: span 5; }
.biztech-col-xs-6[b-6o4w5ahxby] { grid-column: span 6; }
.biztech-col-xs-7[b-6o4w5ahxby] { grid-column: span 7; }
.biztech-col-xs-8[b-6o4w5ahxby] { grid-column: span 8; }
.biztech-col-xs-9[b-6o4w5ahxby] { grid-column: span 9; }
.biztech-col-xs-10[b-6o4w5ahxby] { grid-column: span 10; }
.biztech-col-xs-11[b-6o4w5ahxby] { grid-column: span 11; }
.biztech-col-xs-12[b-6o4w5ahxby] { grid-column: span 12; }

@media (min-width: 600px) {
    .biztech-col-sm-1[b-6o4w5ahxby] { grid-column: span 1; }
    .biztech-col-sm-2[b-6o4w5ahxby] { grid-column: span 2; }
    .biztech-col-sm-3[b-6o4w5ahxby] { grid-column: span 3; }
    .biztech-col-sm-4[b-6o4w5ahxby] { grid-column: span 4; }
    .biztech-col-sm-5[b-6o4w5ahxby] { grid-column: span 5; }
    .biztech-col-sm-6[b-6o4w5ahxby] { grid-column: span 6; }
    .biztech-col-sm-7[b-6o4w5ahxby] { grid-column: span 7; }
    .biztech-col-sm-8[b-6o4w5ahxby] { grid-column: span 8; }
    .biztech-col-sm-9[b-6o4w5ahxby] { grid-column: span 9; }
    .biztech-col-sm-10[b-6o4w5ahxby] { grid-column: span 10; }
    .biztech-col-sm-11[b-6o4w5ahxby] { grid-column: span 11; }
    .biztech-col-sm-12[b-6o4w5ahxby] { grid-column: span 12; }
}

@media (min-width: 960px) {
    .biztech-col-md-1[b-6o4w5ahxby] { grid-column: span 1; }
    .biztech-col-md-2[b-6o4w5ahxby] { grid-column: span 2; }
    .biztech-col-md-3[b-6o4w5ahxby] { grid-column: span 3; }
    .biztech-col-md-4[b-6o4w5ahxby] { grid-column: span 4; }
    .biztech-col-md-5[b-6o4w5ahxby] { grid-column: span 5; }
    .biztech-col-md-6[b-6o4w5ahxby] { grid-column: span 6; }
    .biztech-col-md-7[b-6o4w5ahxby] { grid-column: span 7; }
    .biztech-col-md-8[b-6o4w5ahxby] { grid-column: span 8; }
    .biztech-col-md-9[b-6o4w5ahxby] { grid-column: span 9; }
    .biztech-col-md-10[b-6o4w5ahxby] { grid-column: span 10; }
    .biztech-col-md-11[b-6o4w5ahxby] { grid-column: span 11; }
    .biztech-col-md-12[b-6o4w5ahxby] { grid-column: span 12; }
}
/* /Components/Ui/UiIcon.razor.rz.scp.css */
/* W0-52 · the glyph box.

   Sized in px rather than em, deliberately: R11.3 gives icons two sizes and an em-sized glyph would
   also inherit the type scale, so the same icon would render at four different sizes depending on
   which slot happened to surround it. Both values are on the 4px scale.

   `fill: currentColor` is on the element in markup rather than here, so a glyph is coloured even if
   this sheet fails to load - the one property whose loss would make an icon invisible rather than
   merely misplaced. */

.biztech-icon[b-miov41hmbq] {
    display: inline-block;
    flex: none;
    vertical-align: middle;
    /* The two paths Material ships include a fill="none" spacer sized to the 24-unit viewBox, so the
       glyph is already centred in its own box - nothing here needs to correct for it. */
}

.biztech-icon-small[b-miov41hmbq] {
    inline-size: 20px;
    block-size: 20px;
}

.biztech-icon-medium[b-miov41hmbq] {
    inline-size: 24px;
    block-size: 24px;
}
/* /Components/Ui/UiIconButton.razor.rz.scp.css */
/* W0-52 · an icon-only button.

   Square, so the glyph sits in the middle of a target rather than in the corner of a wide one, and
   round, because a circular hit area is what tells a pointer this is one control rather than part of
   a toolbar strip.

   🔴 THE COLOUR CLASSES ARE DECLARED HERE RATHER THAN REUSED FROM UiText.razor.css. Blazor's CSS
   isolation scopes a sheet to its own component's elements, so `biztech-ink-primary` defined over
   there matches nothing rendered here - it would compile, render, and silently take the inherited
   colour. Every component in this folder declares the classes it names. */

.biztech-icon-button[b-z230jmoezm] {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-pill);
    background: transparent;
    color: inherit;
    cursor: pointer;

    transition: background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

/* 🔴 W6-53 · design §4. THE OUTLINED VARIANT, AND IT IS .mk-btn-icon's THREE DECLARATIONS:

     .mk-btn      { border: 1px solid var(--biztech-palette-outline);
                    border-radius: var(--biztech-radius-default); background: transparent }
     .mk-btn-icon { padding: 0; inline-size: 32px }

   A rounded SQUARE, not a circle - which is the one visible difference from the base rule above, and the
   reason the border is declared here rather than the radius being left alone. The size classes already
   give the box its 32px, so only the border and the corner change.

   Text stays the default and stays a round ghost: every icon button in the application except the
   session toolbar's media pair is one, and §4 draws none of those with a box. */
.biztech-icon-button-outlined[b-z230jmoezm],
.biztech-icon-button-filled[b-z230jmoezm] {
    border-color: var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
}

/* R5.8's 44px touch target is NOT applied here globally, and that is a decision rather than an
   omission: the operator console is exempt by decision (a mouse at a desk), and app.css's
   `@media (pointer: coarse)` block under .biztech-anon is what grows these on /i/{key}, which is
   the surface the rule names. */
.biztech-icon-button-small[b-z230jmoezm] {
    inline-size: 32px;
    block-size: 32px;
    padding: 4px;
}

.biztech-icon-button-medium[b-z230jmoezm] {
    inline-size: 40px;
    block-size: 40px;
    padding: 8px;
}

.biztech-icon-button:hover:not(:disabled)[b-z230jmoezm] {
    background: color-mix(in srgb, currentcolor 12%, transparent);
}

.biztech-icon-button:disabled[b-z230jmoezm] {
    color: var(--biztech-palette-text-disabled);
    cursor: default;
}

/* Inherit is the default: an icon button in the app bar takes the app bar's own ink, which is the
   OnAppbar role its background was tested against. */
.biztech-icon-button-inherit[b-z230jmoezm] { color: inherit; }
.biztech-icon-button-default[b-z230jmoezm] { color: var(--biztech-palette-text-primary); }
.biztech-icon-button-primary[b-z230jmoezm] { color: var(--biztech-palette-primary); }
.biztech-icon-button-secondary[b-z230jmoezm] { color: var(--biztech-palette-secondary); }
.biztech-icon-button-tertiary[b-z230jmoezm] { color: var(--biztech-palette-tertiary); }
.biztech-icon-button-success[b-z230jmoezm] { color: var(--biztech-palette-success); }
.biztech-icon-button-warning[b-z230jmoezm] { color: var(--biztech-palette-warning); }
.biztech-icon-button-error[b-z230jmoezm] { color: var(--biztech-palette-error); }
.biztech-icon-button-info[b-z230jmoezm] { color: var(--biztech-palette-info); }

@media (prefers-reduced-motion: reduce) {
    .biztech-icon-button[b-z230jmoezm] {
        transition: none;
    }
}
/* /Components/Ui/UiLifecycleMap.razor.rz.scp.css */
/*
    W4-22 · F7.2. The lifecycle map's own styles.

    Every colour is a --biztech-palette-* token (R3.1) and every size a --biztech-font-* one. Nothing
    here is a literal: unlike UiQrCode - which is read by a CAMERA and specified by ISO/IEC 18004 -
    this is read by a person, so it takes the tenant's palette like every other surface, and it has to
    survive both modes.
*/

/*
    🔴 R13.7. THE MAP SCROLLS, THE PAGE DOES NOT. A lifecycle is wider than a phone and that is fine;
    what is not fine is the page scrolling sideways, which moves every other control with it.
*/
.biztech-lifecycle-map[b-69ht8nkv2w] {
    overflow-x: auto;
    overflow-y: hidden;
    max-width: 100%;

    /* 🔴 W16-09 · FINDING 3 · A HAIRLINE, BECAUSE THIS BAR SITS INSIDE A PAGE THAT ALSO SCROLLS.

       MainLayout.razor.css states the rule and SessionChat.razor.css is its precedent: a scrollport
       INSIDE a page takes a hairline, so the page's own bar stays the one that reads as the document's.
       `thin` rather than `none` - UiTabs uses `none` where an arrow carries the affordance instead, and
       nothing here would carry it. The map still scrolls by wheel, by drag and, since this card gave it
       a tabindex, by keyboard. */
    scrollbar-width: thin;
}

.biztech-lifecycle-map svg[b-69ht8nkv2w] {
    /* Never shrink below its own geometry - a squeezed map overlaps its own labels rather than
       scrolling, and the scroll above is what makes the width honest. */
    min-width: max-content;
    display: block;
}

/*
    🔴 EVERY BORDER IS SOLID, ON EVERY STATE.

    The first build drew stages not yet reached with `stroke-dasharray` and it was the first thing
    called out on sight: a dashed box reads as an UNFINISHED DRAWING, not as "not yet". State is
    carried by fill and colour here, and by the word in the chip - which is the channel R12.7
    actually asks for.
*/
.biztech-lifecycle-card[b-69ht8nkv2w] {
    fill: var(--biztech-palette-surface);
    stroke: var(--biztech-palette-outline);
    stroke-width: 1;
}

/* A stage the case has left: quiet, but finished. */
.biztech-lifecycle-node--done .biztech-lifecycle-card[b-69ht8nkv2w] {
    stroke: var(--biztech-palette-success);
    stroke-width: 1.5;
}

/* Where the case is NOW. The one thing on the map that should catch the eye first. */
.biztech-lifecycle-node--current .biztech-lifecycle-card[b-69ht8nkv2w] {
    stroke: var(--biztech-palette-primary);
    stroke-width: 2.5;
}

/*
    Not reached yet: a muted plate, solid, with muted ink.

    🔴 W4-24 · R3.6, WCAG 1.4.11. THE STROKE WAS --outline-subtle AND THE BOX WAS NOT THERE. Measured
    on /cases/{caseId} rather than eyeballed: 1.25:1 against the paper behind it in light and 1.24:1 in
    dark, where 3:1 is required for a non-text boundary. The label ink was fine at 7.40:1, so the last
    stages read as floating text rather than as stages, and W4-22's own browser pass missed it because
    the reached states carry a coloured stroke and the eye goes to the lit part of the route.

    --outline measures 3.33:1 light and 3.51:1 dark. LifecycleNodeContrastTests computes both from the
    resolved token values rather than restating a hex, so a palette change cannot quietly undo this.

    🔴 THE FILL DOES NOT MOVE. W4-22's ruling stands - a stage not reached is quieter than one that has
    been - so this changes the BOUNDARY, which is what carries the shape, and not the state.
*/
.biztech-lifecycle-node--ahead .biztech-lifecycle-card[b-69ht8nkv2w] {
    fill: var(--biztech-palette-background);
    stroke: var(--biztech-palette-outline);
}

.biztech-lifecycle-node--ahead .biztech-lifecycle-label[b-69ht8nkv2w] {
    fill: var(--biztech-palette-text-secondary);
}

/* The status badge. */
.biztech-lifecycle-chip[b-69ht8nkv2w] {
    fill: var(--biztech-palette-outline-subtle);
}

.biztech-lifecycle-node--done .biztech-lifecycle-chip[b-69ht8nkv2w] {
    fill: var(--biztech-palette-success);
}

.biztech-lifecycle-node--current .biztech-lifecycle-chip[b-69ht8nkv2w] {
    fill: var(--biztech-palette-primary);
}

.biztech-lifecycle-chip-text[b-69ht8nkv2w] {
    fill: var(--biztech-palette-surface);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-caption-weight);
    letter-spacing: var(--biztech-font-caption-letter-spacing);
}

/* An "ahead" chip sits on a muted plate rather than a coloured one, so its ink stays readable. */
.biztech-lifecycle-node--ahead .biztech-lifecycle-chip-text[b-69ht8nkv2w] {
    fill: var(--biztech-palette-text-secondary);
}

.biztech-lifecycle-label[b-69ht8nkv2w] {
    fill: var(--biztech-palette-text-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
}

.biztech-lifecycle-footnote[b-69ht8nkv2w],
.biztech-lifecycle-sentence[b-69ht8nkv2w] {
    fill: var(--biztech-palette-text-secondary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
}

.biztech-lifecycle-edge[b-69ht8nkv2w] {
    stroke: var(--biztech-palette-outline);
    stroke-width: 1.5;
}

.biztech-lifecycle-arrowhead[b-69ht8nkv2w] {
    fill: var(--biztech-palette-outline);
}

/* The route this case actually took. */
.biztech-lifecycle-edge--taken[b-69ht8nkv2w] {
    stroke: var(--biztech-palette-primary);
    stroke-width: 2.5;
}

.biztech-lifecycle-arrowhead--taken[b-69ht8nkv2w] {
    fill: var(--biztech-palette-primary);
}

/*
    A return - a revoke sending the case back to an earlier stage. Dashed HERE and only here, because
    on a line the dash means "this is not the main flow", which is true. On a node it meant "this
    drawing is unfinished", which was not.
*/
.biztech-lifecycle-edge--return[b-69ht8nkv2w] {
    stroke: var(--biztech-palette-outline-subtle);
    stroke-dasharray: 5 4;
}

/*
    W13-10. An interrupt that can fire from ANY stage - archiving. Dashed for the reason a return is,
    and with a finer dash so the two read as different kinds of "not the main flow" rather than as the
    same one.

    It is anchored at the first stage because a line has to start somewhere and LifecycleLayout draws
    no edge whose ends are not both nodes. The dash and the route list's "from any stage" carry the
    meaning; the anchor is only where the line starts.
*/
.biztech-lifecycle-edge--anystage[b-69ht8nkv2w] {
    stroke: var(--biztech-palette-outline-subtle);
    stroke-dasharray: 2 5;
}

/*
    🔴 R12.2. The route as sentences in document order, for a reader who cannot navigate an SVG of
    boxes and arrows however well each shape is labelled.

    Visually hidden with a scoped class rather than a shared utility, because app.css has none -
    TenantChrome's header states that, and DeckViewer.razor.css carries its own copy for the same
    reason. No colour and no radius token here, so PortalStyleSheetTests' sweep has nothing to find.
*/
.biztech-lifecycle-route[b-69ht8nkv2w] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
/* /Components/Ui/UiListCard.razor.rz.scp.css */
/* W19-20 · the list card. Every colour and radius is a --biztech-* variable, so a tenant's palette and radius reach it in
   both modes. The rows are UiTable's, reached through ::deep from this file's own wrapper (I19). */
@media (min-width: 960px) {
    .biztech-list-card[b-q1ef0d08eh] {
        border: 1px solid var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: var(--biztech-palette-surface);
    }
}

@media (max-width: 959.98px) {
    .biztech-list-card[b-q1ef0d08eh]  .biztech-table-row {
        border-color: var(--biztech-palette-outline-subtle);
        border-radius: calc(var(--biztech-radius-default) * 2);
        background: var(--biztech-palette-surface);
    }
}
/* /Components/Ui/UiMenu.razor.rz.scp.css */
/* W0-52 · the disclosure panel.

   Anchored by ordinary positioning - absolute inside a relative wrapper - rather than by the top
   layer. That is a real trade and worth naming: a top-layer popover would never be clipped by an
   ancestor's overflow, but CSS anchor positioning is not baseline across R13.6's four browsers, so a
   top-layer panel would need JavaScript to follow its trigger. The one menu in this application sits
   in the app bar, which clips nothing.

   The layer is `affordance` from app.css's scale (R6.1: never a raw z-index). Inside the app bar's
   own stacking context that is enough to sit above the bar's content, and it does not enter
   MudBlazor's 1100-1600 band (R6.2). */

.biztech-menu[b-fa8bh3chd0] {
    display: inline-flex;
}

/* W19-11 · the panel's containing block, only while it is open. Positioned at all times, a closed trigger painted over
   anything earlier in the tree that has no layer of its own - a "No problems" message once drew under the composer's More
   button. (Since W27-06 the snackbar host has its own layer, above this; the rule still keeps a closed trigger from
   painting over other unlayered content.) */
.biztech-menu-open[b-fa8bh3chd0] {
    position: relative;
}

.biztech-menu-trigger[b-fa8bh3chd0] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    inline-size: 32px;
    block-size: 32px;
    padding: 4px;
    border: 1px solid transparent;
    border-radius: var(--biztech-radius-pill);
    background: transparent;
    color: inherit;
    cursor: pointer;
}

.biztech-menu-trigger:hover:not(:disabled)[b-fa8bh3chd0] {
    background: color-mix(in srgb, currentcolor 12%, transparent);
}

.biztech-menu-trigger:disabled[b-fa8bh3chd0] {
    color: var(--biztech-palette-text-disabled);
    cursor: default;
}

/* Covers the viewport so a click anywhere else dismisses. Transparent, and BEHIND the panel. */
.biztech-menu-scrim[b-fa8bh3chd0] {
    position: fixed;
    inset: 0;
    z-index: var(--biztech-layer-scrim);
    background: transparent;
}

.biztech-menu-panel[b-fa8bh3chd0] {
    position: absolute;
    inset-block-start: calc(100% + 4px);
    inset-inline-end: 0;
    z-index: var(--biztech-layer-affordance);

    box-sizing: border-box;

    /* 🔴 W14-01 · A FLOOR AND A CEILING, WHERE THERE USED TO BE ONLY A FLOOR.

       12rem is 192px, and photographed on /session/{caseId} on 2026-09-11 that is exactly what the
       "Ask for a document" panel was: a form with a select, a text field and a list of what has been
       asked for, folded into a 190px column over the slide. The floor was right for what this rule was
       written for - a short list of menu items, where a panel narrower than its trigger looks broken -
       and it was the ONLY size instruction, so a panel holding a whole section shrank to fit a column
       sized for words.

       `max-content` sizes to whatever is in it, so a menu of four items is still 12rem and a panel with
       a form in it is as wide as the form. The ceiling then stops that being unbounded: 24rem is the
       widest this may grow on a large screen, and the viewport clamp is what keeps it on a phone, where
       the panel is anchored to the trigger's inline end and would otherwise be cut off by the edge it is
       measured from. */
    inline-size: max-content;
    min-inline-size: 12rem;
    max-inline-size: min(24rem, calc(100vw - 2rem));
    padding: 4px;
    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    box-shadow: var(--biztech-shadow-raised);
}

/* 🔴 W0-73 · THE LABELLED TRIGGER, AS AN ADDITION RATHER THAN AN EDIT.

   Every rule above is untouched, so the three icon-only triggers compute exactly what they computed
   before this card - which is the half UiOverlayRenderTests measures on that branch.

   THE HEIGHT COMES OFF THE TOKEN, unlike the 32px literal above it, and that is deliberate: this
   trigger sits IN a row of controls, so it must be the same box as the buttons beside it - 32px
   inside .biztech-shell where W0-63 narrows --biztech-control-height, and 40px everywhere else.
   The icon-only trigger keeps its literal because it lives in the app bar, which is not such a row.

   A radius of `default` rather than `pill`: a pill around a word reads as a chip, and in this
   application a chip is a filter that has already been applied (§7's specimen draws both, one above
   the other). */
.biztech-menu-trigger-labelled[b-fa8bh3chd0] {
    inline-size: auto;
    block-size: var(--biztech-control-height);
    gap: 8px;
    padding-inline: 12px;
    border-radius: var(--biztech-radius-default);

    /* 🔴 W14-01 · AND AN EDGE, BECAUSE THIS ONE STANDS IN A ROW OF OUTLINED BUTTONS.

       The icon-only trigger above declares `border: 1px solid transparent` and is right to: it lives in
       the app bar, where a visible edge round a glyph would be the only one on the band. A LABELLED
       trigger lives in a toolbar - the comment above says exactly that, and takes its height from the
       control token for it - and there it was the one control with no edge at all. On /session/{caseId}
       "Ask for a document" read as a paperclip and some grey text between five bordered buttons, which
       is not a control anybody presses first. Reported from a screenshot on 2026-09-11.

       Same token as UiButton's outlined variant, so the row is one box repeated rather than two kinds
       of box. The transparent border was already reserving the pixel, so nothing moves. */
    border-color: var(--biztech-palette-outline);
}

/* The word must not break, or a narrow toolbar wraps "More" onto two lines inside its own button. */
.biztech-menu-trigger-label[b-fa8bh3chd0] {
    white-space: nowrap;
}

/* W19-11 · the panel above its trigger, its foot 4px over the trigger's top - the mirror of the rule above. */
.biztech-menu-panel.biztech-menu-panel-up[b-fa8bh3chd0] {
    inset-block-start: auto;
    inset-block-end: calc(100% + 4px);
}

/* The count after a labelled trigger's word: a filled circle in the primary role, so a number reads as a tally
   rather than as part of the label ("Ask for a document · 1"). The ink is the role's own pair. */
.biztech-menu-trigger-count[b-fa8bh3chd0] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 20px;
    block-size: 20px;
    padding-inline: 4px;
    box-sizing: border-box;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    color: var(--biztech-palette-on-primary);
    font-size: var(--biztech-font-caption-size);
    font-weight: 600;
    line-height: 1;
}

/* OpensRight: anchored to the trigger's start edge instead of its end. */
.biztech-menu-panel-right[b-fa8bh3chd0] {
    inset-inline-start: 0;
    inset-inline-end: auto;
}
/* /Components/Ui/UiMenuItem.razor.rz.scp.css */
/* W0-52 · one row of the disclosure panel. Full width, left-packed, and the label and its glyph stay
   together (R5.9: a label and its value stay closer to each other than to the next pair). */

.biztech-menu-item[b-fagn8uwofg] {
    display: flex;
    align-items: center;
    gap: 12px;

    box-sizing: border-box;
    inline-size: 100%;
    min-block-size: 40px;
    padding: 8px 12px;
    border: 0;
    border-radius: var(--biztech-radius-default);
    background: transparent;
    color: inherit;
    cursor: pointer;

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
    letter-spacing: var(--biztech-font-body2-letter-spacing);
    text-align: start;

    /* 🔴 W0b-03 · the anchor form. A user agent underlines a link, and the button form never was -
       so one underlined row among plain ones reads as a defect rather than as a link. Harmless on the
       button, which has no default decoration to remove. */
    text-decoration: none;
}

.biztech-menu-item:hover:not(:disabled)[b-fagn8uwofg] {
    background: color-mix(in srgb, currentcolor 8%, transparent);
}

.biztech-menu-item:disabled[b-fagn8uwofg] {
    color: var(--biztech-palette-text-disabled);
    cursor: default;
}

.biztech-menu-item-label[b-fagn8uwofg] {
    flex: 1 1 auto;
    min-inline-size: 0;
}
/* /Components/Ui/UiPaper.razor.rz.scp.css */
/* W0-52 · the flat surface. Border rather than shadow: R3.6 puts the 3:1 on the border, R6.6 says a
   border does on dark what a shadow does on light, and Outline is the role held to 3:1 against BOTH
   Surface and Background (R3.7). Reaching for a shadow here would be styling against roles nobody
   tested.

   1px per R5.6. The radius is read from the token, never restated (R5.5). */

.biztech-paper[b-5t289n8rsf] {
    box-sizing: border-box;
    background: var(--biztech-palette-surface);
    /* 🔴 W19-23 · §2a C9: an in-flow card's edge is outline-subtle and its corners twice the theme's radius - UiListCard's
       and the settings row's edge, which a dozen page sheets were restating over this one through ::deep. The full
       Outline drew every panel darker than the list beside it. */
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    color: var(--biztech-palette-text-primary);

    /* W19-07 · ADR 0026 D-E's amendment. The border still carries the edge; the shadow is the theme's Depth -
       none unless a theme names soft or strong. */
    box-shadow: var(--biztech-shadow-card);
}
/* /Components/Ui/UiPasswordField.razor.rz.scp.css */
/* W19-18 · the password field's own pieces. The field, label and input wear app.css's global classes, as UiTextField's
   do; these rules name only the elements this file adds (I19).

   The label and its aside on one row: the label at the start, the link at the end, sharing a baseline. */
.biztech-password-label-row[b-suaytbtfgw] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

/* The box and its Show / Hide button: the button sits inside the box's end, and the typed text stops short of it. */
.biztech-password-shell[b-suaytbtfgw] {
    position: relative;
    display: block;
}

.biztech-password-shell > input[b-suaytbtfgw] {
    padding-inline-end: 64px;
}

.biztech-password-reveal[b-suaytbtfgw] {
    position: absolute;
    inset-block: 4px;
    inset-inline-end: 4px;
    padding-inline: 12px;
    border: none;
    border-radius: var(--biztech-radius-default);
    background: transparent;
    color: var(--biztech-palette-primary);
    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    cursor: pointer;
}

.biztech-password-reveal:hover[b-suaytbtfgw] {
    background: var(--biztech-palette-primary-container);
}

.biztech-password-reveal:disabled[b-suaytbtfgw] {
    color: var(--biztech-palette-text-disabled);
    cursor: default;
    background: transparent;
}
/* /Components/Ui/UiProgressLinear.razor.rz.scp.css */
/* W0-52 · an indeterminate bar.

   🔴 R6.7 ALLOWS transform AND NOTHING THAT LAYS OUT, which is why the bar slides with translateX
   rather than animating `left` or `width`. A width animation runs on the main thread and reflows
   sixty times a second behind whatever is loading - on the one frame the operator is waiting on.

   R6.8: guarded in CSS. There is no JS half here to guard - the animation is entirely declarative,
   which is also why it keeps running if the circuit stalls, and that is correct: a bar that froze
   the moment the server stopped answering would look like the page had finished. */

.biztech-progress[b-sswtwrweo2] {
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
    inline-size: 100%;
    block-size: 4px;
    border-radius: var(--biztech-radius-pill);
    background: color-mix(in srgb, var(--biztech-palette-primary) 16%, transparent);
}

.biztech-progress-bar[b-sswtwrweo2] {
    position: absolute;
    inset-block: 0;
    inline-size: 40%;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    animation: biztech-progress-slide-b-sswtwrweo2 1200ms ease-in-out infinite;
}

/* W27-05 · the determinate bar. The fill spans the track and is scaled from the start edge by the value, so
   a change of value moves a transform and lays nothing out (R6.7). The value arrives unitless in
   --progress-value, set on the element by the component. */
.biztech-progress-fill[b-sswtwrweo2] {
    position: absolute;
    inset: 0;
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-primary);
    transform-origin: left center;
    transform: scaleX(calc(var(--progress-value, 0) / 100));
    transition: transform var(--biztech-motion-duration) ease-out;
}

@keyframes biztech-progress-slide-b-sswtwrweo2 {
    from { transform: translateX(-100%); }
    to { transform: translateX(350%); }
}

@media (prefers-reduced-motion: reduce) {
    .biztech-progress-bar[b-sswtwrweo2] {
        /* Still visibly a progress indicator, and still says "waiting" - it simply stops moving.
           WCAG 2.3.3, and the reason this is not `display: none`: removing the only sign that
           something is in flight is a worse answer than removing the motion. */
        animation: none;
        inline-size: 100%;
        opacity: .6;
    }

    .biztech-progress-fill[b-sswtwrweo2] {
        transition: none;
    }
}
/* /Components/Ui/UiQrCode.razor.rz.scp.css */
/* W6-18 · the symbol's box.

   NO COLOUR IN HERE, AND THAT IS THE POINT. The plate and the ink are attributes in the markup, for
   the reason the component's header gives at length: a QR code is read by a camera and has to be
   dark-on-light in both modes. This sheet is swept by PortalStyleSheetTests like every other scoped
   sheet, and it has nothing for that sweep to find.

   9rem is 144px - a whole multiple of the 4px base unit, so R5.4 is satisfied without a named layout
   constant. At the 45-module extent a participant link encodes to, that is 3.2 CSS px per module,
   which scans at arm's length. Below about 2px per module a phone camera starts guessing.

   NO border-radius. Rounded corners would clip the finder patterns, which are the three things a
   scanner locates first - so there is nothing here for R5.5's radius rule to read a variable for. */

.biztech-qr[b-o6bdmbd8c9] {
    display: block;
    inline-size: 9rem;
    /* The viewBox is square, so height follows width and nothing has to restate the ratio (R11.6's
       "constrain ONE dimension - the viewBox carries the ratio", applied to something that is not a
       logo). */
    block-size: auto;
}
/* /Components/Ui/UiSettingsRow.razor.rz.scp.css */
/* W19-20 · a settings row. The head and the body are columns spaced by their own gap (I18); from desktop width they sit
   side by side, the head in the start third and the body - at most 40rem - in the end two thirds. */
.biztech-settings-row[b-911jxsxfnr] {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.biztech-settings-row-head[b-911jxsxfnr] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
}

.biztech-settings-row-body[b-911jxsxfnr] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-inline-size: 0;
}

@media (min-width: 960px) {
    .biztech-settings-row[b-911jxsxfnr] {
        display: grid;
        grid-template-columns: minmax(12rem, 1fr) minmax(0, 2fr);
        column-gap: 32px;
        align-items: start;
    }

    .biztech-settings-row-body[b-911jxsxfnr] {
        max-inline-size: 40rem;
    }
}
/* /Components/Ui/UiSkeleton.razor.rz.scp.css */
/* W0-52 · the placeholder.

   The two heights are the two the application already used - 48px for a row or a field, 120px for a
   card - and they live here rather than at nine call sites, which is R5.4's point. Both are on the
   4px scale, so neither needs a row in the layout-constant registry.

   Still, not shimmering. R12.8 and R6.8 both bear on it, and a shimmer is motion nobody asked for on
   the frame a person is already waiting through; the surface tint alone says "not yet". R3.12 leaves
   skeleton styling to the library, and this is the library now. */

.biztech-skeleton[b-0qqvlms747] {
    box-sizing: border-box;
    inline-size: 100%;
    border-radius: var(--biztech-radius-default);
    background: color-mix(in srgb, var(--biztech-palette-text-primary) 8%, transparent);
}

.biztech-skeleton-row[b-0qqvlms747] {
    block-size: 48px;
}

.biztech-skeleton-block[b-0qqvlms747] {
    block-size: 120px;
}
/* /Components/Ui/UiSnackbarHost.razor.rz.scp.css */
/* W0-52 · where snackbars sit.

   🔴 W27-06 SUPERSEDES W0-68'S FIRST "DO NOT": THE HOST HAS ITS OWN LAYER. It used to declare no
   z-index (R6.2's "MudBlazor owns 1100-1600. Do not compete." while both substrates were linked), so
   it painted in the base stacking context - and a success toast slid UNDER the console's app bar
   (layer 7) and the portal's sticky header (layer 2) as soon as the page scrolled. MudBlazor's band is
   not entered: --biztech-layer-snackbar is 8, one above the app bar and far below 1100. It paints over
   the rail and the overlay drawer too, which is the accepted trade for a message that closes on a
   click (plan D19).

   The dialog is still a native <dialog> in the top layer, above every z-index there is. */

.biztech-snackbar-host[b-v52iwfuido] {
    position: fixed;
    z-index: var(--biztech-layer-snackbar);

    /*
        🔴 TOP TRAILING, UNDER THE APP BAR - AND THIS USED TO BE BOTTOM LEADING. Messages opened at
        the foot of the page; they belong at the top right, below the app bar.

        The block offset is DERIVED, not measured. --biztech-content-block-start is declared on
        .biztech-shell from the same var() that sizes grid row one, so the stack clears the bar because
        it is TOLD the bar's height, not because 16px happens to be too small and 80px happens to be
        enough. The gutter is added to it, so the message sits a gutter below the bar exactly as it
        used to sit a gutter above the viewport's foot.

        🔴 THE SHELL'S PROPERTY AND NOT --biztech-appbar-height, WHICH IS THE WHOLE POINT OF THE
        INDIRECTION. That token is emitted at :root by UiThemeTokens, so it reads 64px on EVERY surface
        - including AnonymousLayout and SignInLayout, which mount this host and render no app bar at
        all (their own headers are a mark plus 12px of padding, and shorter than the console's bar).
        Read directly it would push the message 64px down a page with nothing above it, and no fallback
        could ever fire to say so, because the token is always there. Read from the shell the fallback
        fires exactly where it should: those two layouts declare no shell, so the offset is the gutter
        alone, which is the right answer on a page with nothing above the content.

        🔴 W0-68'S RAIL PROBLEM IS GONE RATHER THAN SOLVED AGAIN, and its reasoning is worth keeping
        because it explains why the old inset existed at all. The host started at the viewport's
        LEADING edge, where the 240px navigation rail sits, so every message lost its first words
        behind it - five stacked messages each reading "e case type configured, so there is nothing to
        open. ...". That was fixed by starting at the shell's INLINE twin of the property above.
        Anchored to the TRAILING edge there is no rail to clear, so that property had no reader left
        and MainLayout.razor.css no longer declares it: a property nothing reads is the W0-59 defect
        this repository has already paid for once.

        🔴 AND THE LEADING EDGE STAYS UNPINNED, which is the same trap W0-68 recorded with the sides
        reversed. With ONE inline inset and `inline-size: auto` the used width is SHRINK-TO-FIT,
        clamped by the max below; with both it becomes `containing block - start - end`, so 46rem
        stops being a ceiling and becomes the width - Add("Saved.") measured about 140px before and
        736px after, on every surface that mounts this host.
    */
    inset-block-start: calc(var(--biztech-content-block-start, 0px) + 16px);
    inset-inline-end: 16px;

    display: flex;
    flex-direction: column;

    /* Each message is its own width, hugging the trailing edge. Stretched, a one-word confirmation
       would be as wide as the longest refusal above it. */
    align-items: flex-end;
    gap: 8px;

    /* The host is always mounted and usually empty, so it must not swallow clicks on what is behind
       it. The messages themselves take pointer events back. */
    pointer-events: none;
    max-inline-size: 46rem;
}

.biztech-snackbar-region[b-v52iwfuido] {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
}

.biztech-snackbar[b-v52iwfuido] {
    display: flex;
    align-items: center;
    gap: 12px;

    box-sizing: border-box;
    padding: 12px 16px;
    border: 1px solid currentcolor;
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-overlay);
    pointer-events: auto;

    /* W27-06 · a click anywhere on a message closes it; the close button is the keyboard's way. */
    cursor: pointer;

    font-family: var(--biztech-font-family);
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
}

.biztech-snackbar-info[b-v52iwfuido] { color: var(--biztech-palette-info); }
.biztech-snackbar-success[b-v52iwfuido] { color: var(--biztech-palette-success); }
.biztech-snackbar-warning[b-v52iwfuido] { color: var(--biztech-palette-warning); }
.biztech-snackbar-error[b-v52iwfuido] { color: var(--biztech-palette-error); }

/* 🔴 W0-68 · what a region says about the messages the cap dropped.

   Secondary ink and no glyph, because it reports on the STACK rather than on an action: a severity
   colour would claim it was an outcome, and §9's four severities are all outcomes. It keeps
   .biztech-snackbar's own box so the report reads as part of the stack it is about rather than as
   floating text beside it. */
.biztech-snackbar-hidden[b-v52iwfuido] {
    color: var(--biztech-palette-text-secondary);

    /* It closes nothing (W27-06, D19). */
    cursor: default;
}

/* 🔴 AND ON THE TEXT ITSELF, BECAUSE THE RULE ABOVE CANNOT REACH IT.

   `.biztech-snackbar-text` below carries a direct `color: var(--biztech-palette-text-primary)` on the
   very <span> that holds the sentence, and a direct declaration beats an inherited one always - so the
   wrapper's colour reached only `currentcolor`, which here is just the border. The notice's words
   rendered in the same ink as the messages it sits above, which is the opposite of the intent. */
.biztech-snackbar-hidden .biztech-snackbar-text[b-v52iwfuido] {
    color: var(--biztech-palette-text-secondary);
}

.biztech-snackbar-text[b-v52iwfuido] {
    flex: 1 1 auto;
    min-inline-size: 0;
    color: var(--biztech-palette-text-primary);
}

/* W21-04 · a message's one action: a text button in primary ink on the message's own row. A plain
   <button> because the seam's button brings a control's height and margins a one-line message cannot
   hold; the shared focus ring reaches it by class. */
.biztech-snackbar-action[b-v52iwfuido] {
    flex: none;
    min-block-size: 32px;
    padding-inline: 8px;
    border: 0;
    border-radius: var(--biztech-radius-default);
    background: transparent;
    color: var(--biztech-palette-primary);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

/* R13.3. On a phone the host spans the width rather than sitting in a corner, because a 46rem
   message box on a 375px screen is a message box off the side of the screen. Both insets here is
   deliberate and is the one place the shrink-to-fit note above does not apply: spanning the width
   IS the intent, and max-inline-size is lifted so nothing clamps it back. */
@media (max-width: 599.98px) {
    .biztech-snackbar-host[b-v52iwfuido] {
        inset-inline: 16px;
        max-inline-size: none;
    }

    /* Full width, so a message hugging the trailing edge would leave a ragged stack. */
    .biztech-snackbar-host[b-v52iwfuido],
    .biztech-snackbar-region[b-v52iwfuido] {
        align-items: stretch;
    }
}
/* /Components/Ui/UiSpacer.razor.rz.scp.css */
/* W0-52 · takes whatever room is left in a flex row. `flex-grow` only: it must never claim a basis
   of its own, or it would push a control off the end of a narrow app bar rather than collapsing. */

.biztech-spacer[b-0g47ty6fwz] {
    flex: 1 1 auto;
    min-inline-size: 0;
}
/* /Components/Ui/UiStatTile.razor.rz.scp.css */
/* W19-23 · one stat tile: the label and its badge, the figure, one line of context. The quiet card of §2a C9 - the subtle
   edge, twice the radius, the surface ground and the theme's card depth. Tokens only (R3.1); every class is this file's (I19). */
.biztech-stat-tile[b-j4vgl57fta] {
    /* The warning role moved towards orange - ComplianceFigureBar.razor.css says why and how it was measured: the ink keeps
       the role's lightness (6.5:1 light, 6.8:1 dark), the tint is the lifted mark over the surface. */
    --biztech-stat-attention-ink: oklch(from var(--biztech-palette-warning) l calc(c * 1.6) calc(h - 12));
    --biztech-stat-attention-tint: color-mix(
        in srgb, oklch(from var(--biztech-palette-warning) max(l, 0.72) calc(c * 1.6) calc(h - 12)) 18%, var(--biztech-palette-surface));

    display: flex;
    flex-direction: column;
    gap: 4px;
    min-inline-size: 0;
    padding: 16px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: calc(var(--biztech-radius-default) * 2);
    background: var(--biztech-palette-surface);
    box-shadow: var(--biztech-shadow-card);
    color: var(--biztech-palette-text-primary);
}

/* A tile that is a way in: the whole card is the anchor, its edge firming on hover. R3.11's focus ring is app.css's. */
.biztech-stat-tile-linked[b-j4vgl57fta] {
    text-decoration: none;
}

.biztech-stat-tile-linked:hover[b-j4vgl57fta] {
    border-color: var(--biztech-palette-outline);
}

.biztech-stat-tile-linked:hover .biztech-stat-tile-label[b-j4vgl57fta] {
    text-decoration: underline;
}

.biztech-stat-tile-head[b-j4vgl57fta] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    min-inline-size: 0;
}

.biztech-stat-tile-label[b-j4vgl57fta] {
    font-size: var(--biztech-font-body2-size);
    line-height: var(--biztech-font-body2-line-height);
    font-weight: 500;
    color: var(--biztech-palette-text-secondary);
}

.biztech-stat-tile-value[b-j4vgl57fta] {
    font-size: var(--biztech-font-h4-size);
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.biztech-stat-tile-caption[b-j4vgl57fta] {
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    color: var(--biztech-palette-text-secondary);
}

/* The tone, in words, on the role's derived container tint with its own ink (ADR 0026 D-H) - a quiet badge where the 4px bar
   was. Quiet has no badge tint: context is not a finding. */
.biztech-stat-tile-badge[b-j4vgl57fta] {
    flex: none;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: var(--biztech-font-caption-size);
    line-height: var(--biztech-font-caption-line-height);
    font-weight: 600;
    white-space: nowrap;
    background: color-mix(in srgb, var(--biztech-palette-text-secondary) 12%, transparent);
    color: var(--biztech-palette-text-secondary);
}

.biztech-stat-tile-badge-good[b-j4vgl57fta] {
    background: var(--biztech-palette-success-container, color-mix(in srgb, var(--biztech-palette-success) 16%, transparent));
    color: var(--biztech-palette-on-success-container, var(--biztech-palette-success));
}

.biztech-stat-tile-badge-look[b-j4vgl57fta] {
    background: var(--biztech-stat-attention-tint);
    color: var(--biztech-stat-attention-ink);
}

.biztech-stat-tile-badge-bad[b-j4vgl57fta] {
    background: var(--biztech-palette-error-container, color-mix(in srgb, var(--biztech-palette-error) 16%, transparent));
    color: var(--biztech-palette-on-error-container, var(--biztech-palette-error));
}

.biztech-stat-tile-glyph[b-j4vgl57fta] {
    display: inline-flex;
    flex: none;
    color: var(--biztech-palette-text-secondary);
}

/* A glyph takes the tone's role - the shape and the label say it too (R12.7). Quiet stays secondary ink. */
.biztech-stat-tile-glyph-good[b-j4vgl57fta] {
    color: var(--biztech-palette-success);
}

.biztech-stat-tile-glyph-look[b-j4vgl57fta] {
    color: var(--biztech-stat-attention-ink);
}

.biztech-stat-tile-glyph-bad[b-j4vgl57fta] {
    color: var(--biztech-palette-error);
}
/* /Components/Ui/UiStatTiles.razor.rz.scp.css */
/* W19-23 · the stat tiles' row: as many across as fit at 10rem - six sit on one row beside the drawer at 1440 - the row
   carrying the gaps (I18). */
.biztech-stat-tiles[b-nnkhfmoslb] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(10rem, 100%), 1fr));
    gap: 16px;
}
/* /Components/Ui/UiTabs.razor.rz.scp.css */
/* W0-73 · the tab row. Design §6 and §7's `.mk-tabs`, with the specimen's colours read as roles.

   🔴 ::deep ON EVERY ENTRY RULE, AND IT IS NOT OPTIONAL.

   UiTab renders a Blazor NavLink, and Blazor stamps its scope attribute only on elements a component
   renders ITSELF. A bare `.biztech-tab` compiles to `.biztech-tab[b-xxxxxxxxxx]` and matches NOTHING
   here - not "matches less", nothing at all, because every entry is two components deep. ::deep
   compiles to `[b-xxxxxxxxxx] .biztech-tab`, a descendant selector rooted at the <nav> this component
   DOES render, which reaches the anchors and still cannot escape this subtree.

   MainNavMenu.razor.css carries the identical fix and records finding it on screen rather than in a
   test: three NavLinks reporting `min-block-size: 0px` and `text-decoration: underline` - default
   browser links - while the one plain <a> beside them was styled correctly.

   🔴 NO PADDING AND NO MARGIN ON THE ROOT, DELIBERATELY.

   The specimen's `padding: 12px 16px 0` is the PAGE's inset around this row, not the row's own box -
   W4-23 and W4-13 supply it with spacing utilities. Declaring it here would silently outrank every
   `biztech-p*` and `biztech-m*` a caller passes, because Blazor's rewrite puts a scoped rule at (0,2,0)
   against a utility class's (0,1,0). That is R14.1a's whole subject and the defect that had nine
   utilities on /ui computing zero. */

.biztech-tabs[b-w0b1sddi9v] {
    display: flex;

    /* flex-end, so a taller trailing control does not drag the entries off the hairline. */
    align-items: flex-end;
    gap: 8px;
    border-block-end: 1px solid var(--biztech-palette-outline-subtle);

    /* 🔴 W0-79 · A FLOOR, SO THE ROW'S HEIGHT DOES NOT DEPEND ON WHETHER ITS TRAILING SLOT IS FILLED.

       align-items: flex-end above means this <nav> takes its TALLEST child. AgentCaseLauncher guards its
       Grid/List switch INSIDE the <Trailing> slot, so the trailing column exists only on a work tab:

       🔴 MEASURED IN CHROMIUM RATHER THAN ADDED UP, AND THE ARITHMETIC WAS OPTIMISTIC. Removing this
       line and reading both gallery specimens at 1440px reports:

         without a trailing control   36px
         with one                     41px

       A five-pixel step, not the eight the component arithmetic suggested (32px button + 2x2 inset +
       2x1 border + 8px padding-block-end against an entry at 8 + line-height + 8 + 2 - 1). Small enough
       to argue about in a screenshot and large enough to move the hairline and every card under it every
       time an operator changes tab.

       So the row grew about 8px the moment an operator moved off Start, the hairline moved with it, and
       every card below moved too. Four other causes were ruled out with evidence before this one - no
       Count is passed to UiTab on that page, PageHeader is identical on all three sections, the tab set
       is decided once per load by permission rather than by section, and the search box is below the bar.

       🔴 THIS IS INSIDE THE "NO PADDING AND NO MARGIN" RULE ABOVE, NOT AN EXCEPTION TO IT. That rule's
       reason is specificity: a scoped rule at (0,2,0) silently outranks every biztech-p* or biztech-m* a
       caller passes, which is R14.1a's subject and the defect that had nine utilities computing zero. A
       BLOCK-SIZE FLOOR OUTRANKS NO UTILITY - there is no biztech-h* scale for it to fight with - so the
       caller's box is still entirely the caller's. PortalStyleSheetTests
       .The_tab_row_declares_a_block_size_floor_and_still_no_box asserts both halves together.

       48px, WHICH CLEARS BOTH AND IS ON THE SCALE. R5's base unit is 4px, and PortalStyleSheetTests
       refuses a raw length that is neither a multiple of it nor a named constant - and it is right to:
       41 or 46 is a number somebody measured once on one build and nobody could check again. 48 is the
       next step up from both, so the row is one height on every tab. */
    min-block-size: 48px;
}

/* The scrolling half.

   `min-inline-size: 0` is what lets a flex item shrink below its content and actually scroll. Without
   it this list grows to fit its entries, the <nav> grows with it, and the LANDMARK overflows instead -
   which is R13.8's measured defect one level down, and invisible because `.biztech-main` clips. */
.biztech-tabs-list[b-w0b1sddi9v] {
    display: flex;
    gap: 4px;
    min-inline-size: 0;
    overflow-x: auto;

    /* Hidden, per the specimen. See UiTabs.razor's header for why R12.2's labelled-region
       prescription has no subject here: every entry is a focusable link, so the keyboard reaches all
       of them, and the row only overflows below sm where the input is a finger. */
    scrollbar-width: none;
}

.biztech-tabs-list[b-w0b1sddi9v]::-webkit-scrollbar {
    display: none;
}

/* Stays put while the entries scroll under it. */
.biztech-tabs-trailing[b-w0b1sddi9v] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-inline-start: auto;
    padding-block-end: 8px;
}

[b-w0b1sddi9v] .biztech-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;

    /* 🔴 SITS ON THE ROW'S HAIRLINE RATHER THAN ABOVE IT, so the current entry's 2px REPLACES the 1px
       instead of stacking into 3px. R5.6 fixes every border at 1px and this is the one place a second
       weight is the signal rather than decoration - which is why the negative margin is a real value
       and not a reset (R14.1a: what is forbidden is ZEROING a box-model property the utility layer
       owns, and no utility sets a negative block-end margin).

       🔴 AND -1px IS NOT ON PortalStyleSheetTests' EXEMPTION LIST - IT IS INVISIBLE TO THE SWEEP.
       That test exempts `0px`, `1px` and `2px` by name, which is what covers the hairline above and the
       2px underline below. This value passes for a different reason: the sweep's pattern requires no
       word character or hyphen before the digits, so a leading minus makes it match nothing at all.
       One device pixel by construction, and it is the negative of the border it cancels - but nothing
       would stop `-13px` here either, so treat this line as unguarded. */
    border-block-end: 2px solid transparent;
    margin-block-end: -1px;

    color: var(--biztech-palette-text-secondary);
    text-decoration: none;

    /* Never wrap. A two-line entry is what the row scrolls in order to avoid. */
    white-space: nowrap;

    /* W19-07 · the underline and the ink ease in at the theme's motion duration, so switching tab is seen as
       a move rather than a jump. Colour only - R6.7 animates nothing that lays out. */
    transition:
        color var(--biztech-motion-duration, 120ms) ease-in-out,
        border-color var(--biztech-motion-duration, 120ms) ease-in-out,
        background-color var(--biztech-motion-duration, 120ms) ease-in-out;
}

[b-w0b1sddi9v] .biztech-tab:hover {
    color: var(--biztech-palette-text-primary);
    background: color-mix(in srgb, currentcolor 8%, transparent);
}

/* 🔴 THE CURRENT ENTRY, KEYED ON aria-current RATHER THAN ON NavLink's OWN `active` CLASS.

   The attribute is the accessibility contract; the class is the framework's implementation detail.
   Keying the underline on the attribute means what a screen reader announces and what an eye sees can
   never disagree - and if NavLink ever renamed its class, this row would still be correct.

   R12.7 - never colour alone - is satisfied twice over: the underline and the weight each read with no
   colour perception at all. */
[b-w0b1sddi9v] .biztech-tab[aria-current="page"] {
    color: var(--biztech-palette-text-primary);
    font-weight: 600;
    border-block-end-color: var(--biztech-palette-primary);
}

/* The token, not a literal, so the count is the same size as every other caption in the application
   and moves with the scale rather than beside it - `.biztech-text-caption` reads the same property. */
[b-w0b1sddi9v] .biztech-tab-count {
    color: var(--biztech-palette-text-secondary);
    font-size: var(--biztech-font-caption-size);
}

/* 🔴 W16-08 · finding 3. THE ROW SAYS THAT IT SCROLLS, WHICH IT DID NOT.

   Measured at 390x844 on 2026-09-14: the case list's row read "Inquiry 1 · Presentati..." with Video
   Conference off-screen entirely, and on a case Record sat behind Form & signatures. The row scrolled
   correctly the whole time - `overflow-x: auto` above, and biztech-tabs.js brings the current entry
   into view - and nothing on screen said so. A tab a user cannot see is a tab they do not know exists.

   THE BOARD'S ANSWER, NOT A SECOND ONE. app.css draws the same two fades and the same two round
   buttons off the same three attributes, and biztech-scroller.js writes them for both surfaces. The
   card: "copy that, do not invent a second answer."

   🔴 THE SCROLLBAR STAYS HIDDEN, AND THAT IS A DECISION RATHER THAN AN OVERSIGHT. `.biztech-tabs-list`
   declares `scrollbar-width: none` per the design specimen, and this card keeps it: above sm the row
   does not overflow at all, so the only widths where a bar would appear are the ones where these fades
   and arrows are already showing. What changes is that there is now an affordance at all.

   🔴 EVERY SELECTOR BELOW NAMES AN ELEMENT THIS COMPONENT RENDERS ITSELF, so none of them needs ::deep
   and I19 is satisfied by construction - unlike the entry rules above, which reach into UiTab's
   NavLink and would match NOTHING without it. */

.biztech-tabs-viewport[b-w0b1sddi9v] {
    position: relative;

    /* The flex item that may shrink, and `min-inline-size: 0` is what lets it: a flex item does not
       shrink below its content without one. The list keeps its own copy rather than this replacing it -
       the minimum applies per box, so removing either lets the list grow to fit its entries, this
       wrapper grow with it, and the LANDMARK overflow instead. That is R13.8's measured defect one
       level down, and invisible because .biztech-main clips. */
    flex: 1 1 auto;
    min-inline-size: 0;
}

/* The fades. Both are suppressed at their own edge and when there is nothing to scroll, which is the
   whole point of the runtime flags. pointer-events: none so neither ever eats a press on an entry. */
.biztech-tabs-viewport[b-w0b1sddi9v]::before,
.biztech-tabs-viewport[b-w0b1sddi9v]::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inline-size: 2rem;
    pointer-events: none;
    z-index: var(--biztech-layer-scrim);
}

.biztech-tabs-viewport[b-w0b1sddi9v]::before {
    inset-inline-start: 0;
    background: linear-gradient(to right, var(--biztech-palette-background), transparent);
}

.biztech-tabs-viewport[b-w0b1sddi9v]::after {
    inset-inline-end: 0;
    background: linear-gradient(to left, var(--biztech-palette-background), transparent);
}

.biztech-tabs-viewport:not([data-scrollable])[b-w0b1sddi9v]::before,
.biztech-tabs-viewport:not([data-scrollable])[b-w0b1sddi9v]::after,
.biztech-tabs-viewport[data-at-start][b-w0b1sddi9v]::before,
.biztech-tabs-viewport[data-at-end][b-w0b1sddi9v]::after {
    display: none;
}

/* The buttons. Hidden until the module says the row scrolls, so a three-entry row on a laptop shows
   nothing at all - and above sm this row does not overflow, so that is every laptop.

   🔴 inset-block-end RATHER THAN A VERTICAL CENTRING, AND THE ROW'S OWN GEOMETRY IS WHY. The entries
   sit ON the hairline and `.biztech-tabs` carries a 48px floor, so the optical centre of the ENTRIES is
   above the centre of the box: `top: 50%` would put these slightly low against the words they scroll.
   8px is the entries' own padding-block-end, so the arrows sit on the same line they do. */
.biztech-tabs-scroll[b-w0b1sddi9v] {
    position: absolute;
    inset-block-end: 8px;
    z-index: var(--biztech-layer-affordance);
    display: none;
}

.biztech-tabs-viewport[data-scrollable] .biztech-tabs-scroll[b-w0b1sddi9v] {
    display: block;
}

.biztech-tabs-viewport[data-at-start] .biztech-tabs-scroll-start[b-w0b1sddi9v],
.biztech-tabs-viewport[data-at-end] .biztech-tabs-scroll-end[b-w0b1sddi9v] {
    display: none;
}

.biztech-tabs-scroll-start[b-w0b1sddi9v] {
    inset-inline-start: 0;
}

.biztech-tabs-scroll-end[b-w0b1sddi9v] {
    inset-inline-end: 0;
}

/* Filled rather than bordered, for the board's recorded reason: this floats above the entries and has
   to read as an affordance rather than as one of them. No focus ring here and none needed - it carries
   tabindex="-1" and cannot be focused. 32px is the seam's small control and is on R5's 4px scale. */
.biztech-tabs-scroll-button[b-w0b1sddi9v] {
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;

    /* 🔴 border-box AND A REAL PADDING, WHERE /board's COPY OF THIS RULE SAYS `padding: 0`, AND THE
       DIFFERENCE IS WHICH STYLESHEET EACH ONE LIVES IN.

       UtilitySpecificityTests forbids a SCOPED sheet from zeroing margin or padding: Blazor rewrites a
       scoped selector as `.x[b-xxxxxxxxxx]`, which is (0,2,0) against a utility class's (0,1,0), so a
       reset here outranks every biztech-pa-* a caller passes - silently, because the class is still in
       the markup and only the computed value disagrees. The board's button is in app.css, where that
       rewrite does not happen and the rule does not apply. This one is not, and copying the line
       verbatim is what the sweep caught.

       So the box is stated positively instead. There is no global `box-sizing: border-box` in this
       application - the only declaration is #blazor-error-ui's own - so without this line the 32px
       would be the CONTENT box and the button would render 42px wide. 4px is on R5's base unit and
       leaves 22px of content for a 16px icon, centred by the flex above.

       An explicit value rather than letting the user agent's button padding stand: Chrome's is
       `1px 6px`, Firefox's is not, and a control this size cannot afford to be two pixels different
       per browser. */
    box-sizing: border-box;
    padding: 4px;

    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-pill);
    background: var(--biztech-palette-surface);
    color: var(--biztech-palette-text-primary);
    box-shadow: var(--biztech-shadow-raised);
    cursor: pointer;
}

/* R6.8: the OS's reduced-motion choice wins over the theme's. */
@media (prefers-reduced-motion: reduce) {
    [b-w0b1sddi9v] .biztech-tab {
        transition: none;
    }
}
/* /Components/Ui/UiText.razor.rz.scp.css */
/* W0-52 · the type scale, spent.

   🔴 W0-59 · THE BOX-MODEL RESET THAT USED TO BE HERE IS GONE, AND ITS ABSENCE IS THE FIX.

   W0-52 wrote: "EVERY BOX-MODEL PROPERTY IS DECLARED, NOT INHERITED. MudBlazor.min.css ships a global
   `*` reset - margin: 0, padding: 0, border-width: 0 - and it is still linked on this document until
   W0-53. A component that leans on it looks correct today and moves the day the <link> goes: a <p>
   would gain the user agent's 1em block margins and an <h5> its own font-size and weight, on every
   screen at once. So this sheet sets what it depends on."

   The DIAGNOSIS was right and the LOCATION was wrong, and W0-59 measured what the location cost.
   Blazor rewrites a scoped selector as `.biztech-text[b-xxxxxxxxxx]`, which is (0,2,0) against a
   utility class's (0,1,0) - so `margin: 0` here outranked every `biztech-mb-*` and `biztech-my-*` a
   page passed this component. Measured on /ui, 2026-08-13: the gallery's own h1 carries
   `biztech-my-6` and computed `margin-top: 0px`, which is why that page's title sat flush against the
   app bar while three console pages (whose header row is a plain <div>) had their 24px.

   A <p>'s and an <h1>'s block margins really are the user agent's, so the reset is still needed - it
   just belongs to the DOCUMENT rather than to this component. BizTechCssVariables emits it once, for
   h1-h6, p, hr and the four form controls, and UtilitySpecificityTests fails the build if it comes
   back here. The font-family below stays: it is this component's own decision, not a reset. */

.biztech-text[b-36huect2gx] {
    font-family: var(--biztech-font-family);
}

/* W31-09 · D16. The six heading slots take the portal's heading face when the theme names one. The variable is declared
   only then, and never in the console (MainLayout paints the theme without it), so everywhere else this resolves to the
   body face above. After .biztech-text, at the same weight, so order decides. */
.biztech-text-h1[b-36huect2gx],
.biztech-text-h2[b-36huect2gx],
.biztech-text-h3[b-36huect2gx],
.biztech-text-h4[b-36huect2gx],
.biztech-text-h5[b-36huect2gx],
.biztech-text-h6[b-36huect2gx] {
    font-family: var(--biztech-font-family-heading, var(--biztech-font-family));
}

/* The slots. Each reads its four facets together, which is R4.3 as CSS: a caller cannot take the
   size from one slot and the line-height from another, because there is nothing here to take. */

.biztech-text-body1[b-36huect2gx] {
    font-size: var(--biztech-font-body1-size);
    font-weight: var(--biztech-font-body1-weight);
    line-height: var(--biztech-font-body1-line-height);
    letter-spacing: var(--biztech-font-body1-letter-spacing);
}

.biztech-text-body2[b-36huect2gx] {
    font-size: var(--biztech-font-body2-size);
    font-weight: var(--biztech-font-body2-weight);
    line-height: var(--biztech-font-body2-line-height);
    letter-spacing: var(--biztech-font-body2-letter-spacing);
}

.biztech-text-h1[b-36huect2gx] {
    font-size: var(--biztech-font-h1-size);
    font-weight: var(--biztech-font-h1-weight);
    line-height: var(--biztech-font-h1-line-height);
    letter-spacing: var(--biztech-font-h1-letter-spacing);
}

.biztech-text-h2[b-36huect2gx] {
    font-size: var(--biztech-font-h2-size);
    font-weight: var(--biztech-font-h2-weight);
    line-height: var(--biztech-font-h2-line-height);
    letter-spacing: var(--biztech-font-h2-letter-spacing);
}

.biztech-text-h3[b-36huect2gx] {
    font-size: var(--biztech-font-h3-size);
    font-weight: var(--biztech-font-h3-weight);
    line-height: var(--biztech-font-h3-line-height);
    letter-spacing: var(--biztech-font-h3-letter-spacing);
}

.biztech-text-h4[b-36huect2gx] {
    font-size: var(--biztech-font-h4-size);
    font-weight: var(--biztech-font-h4-weight);
    line-height: var(--biztech-font-h4-line-height);
    letter-spacing: var(--biztech-font-h4-letter-spacing);
}

.biztech-text-h5[b-36huect2gx] {
    font-size: var(--biztech-font-h5-size);
    font-weight: var(--biztech-font-h5-weight);
    line-height: var(--biztech-font-h5-line-height);
    letter-spacing: var(--biztech-font-h5-letter-spacing);
}

.biztech-text-h6[b-36huect2gx] {
    font-size: var(--biztech-font-h6-size);
    font-weight: var(--biztech-font-h6-weight);
    line-height: var(--biztech-font-h6-line-height);
    letter-spacing: var(--biztech-font-h6-letter-spacing);
}

.biztech-text-subtitle1[b-36huect2gx] {
    font-size: var(--biztech-font-subtitle1-size);
    font-weight: var(--biztech-font-subtitle1-weight);
    line-height: var(--biztech-font-subtitle1-line-height);
    letter-spacing: var(--biztech-font-subtitle1-letter-spacing);
}

.biztech-text-subtitle2[b-36huect2gx] {
    font-size: var(--biztech-font-subtitle2-size);
    font-weight: var(--biztech-font-subtitle2-weight);
    line-height: var(--biztech-font-subtitle2-line-height);
    letter-spacing: var(--biztech-font-subtitle2-letter-spacing);
}

/* The button slot, and the one place W0-52's decision D1 is visible in CSS: the transform token is
   emitted as `none` where MudTheme still says `uppercase`. Read from the token rather than dropped,
   so the divergence lives in one place - BizTechCssVariables - and a test asserts it is the only
   one. */
.biztech-text-button[b-36huect2gx] {
    font-size: var(--biztech-font-button-size);
    font-weight: var(--biztech-font-button-weight);
    line-height: var(--biztech-font-button-line-height);
    letter-spacing: var(--biztech-font-button-letter-spacing);
    text-transform: var(--biztech-font-button-transform);
}

.biztech-text-caption[b-36huect2gx] {
    font-size: var(--biztech-font-caption-size);
    font-weight: var(--biztech-font-caption-weight);
    line-height: var(--biztech-font-caption-line-height);
    letter-spacing: var(--biztech-font-caption-letter-spacing);
}

.biztech-text-overline[b-36huect2gx] {
    font-size: var(--biztech-font-overline-size);
    font-weight: var(--biztech-font-overline-weight);
    line-height: var(--biztech-font-overline-line-height);
    letter-spacing: var(--biztech-font-overline-letter-spacing);
    text-transform: var(--biztech-font-overline-transform);
}

/* The ink. `inherit` declares nothing at all - it is the default and the point is that the caller
   did not choose - and every other role reads a token, so it follows the palette and dark mode
   without this file knowing which mode is on (R7.1). */

.biztech-ink-default[b-36huect2gx] { color: var(--biztech-palette-text-primary); }
.biztech-ink-primary[b-36huect2gx] { color: var(--biztech-palette-primary); }
.biztech-ink-secondary[b-36huect2gx] { color: var(--biztech-palette-secondary); }
.biztech-ink-tertiary[b-36huect2gx] { color: var(--biztech-palette-tertiary); }
.biztech-ink-success[b-36huect2gx] { color: var(--biztech-palette-success); }
.biztech-ink-warning[b-36huect2gx] { color: var(--biztech-palette-warning); }
.biztech-ink-error[b-36huect2gx] { color: var(--biztech-palette-error); }
.biztech-ink-info[b-36huect2gx] { color: var(--biztech-palette-info); }
/* /Components/Ui/UiToolbar.razor.rz.scp.css */
/* W0-73 · the toolbar. Design §7's `.mk-toolbar`, with the specimen's colours read as roles.

   🔴 NOTHING IN THIS FILE SIZES THE ROW IN THE BLOCK AXIS, and UiSeamTests asserts that by name -
   neither spelling appears in a declaration. The children take their box from the control-height
   token, which MainLayout.razor.css narrows for the console and BizTechCssVariables leaves alone
   everywhere else; a second declaration here would fork one decision into two.

   That constraint is also why the separator below uses `align-self: stretch` where design §7's
   `.mk-toolbar-sep` writes a fixed 20px: stretching makes the rule exactly as tall as whatever row it
   is in, at either control height, with no number in this file to keep in step. */

.biztech-toolbar[b-v7m0m5mdiv] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;

    /* Lets the row shrink below its content so `flex-wrap` has something to do. Without it a long row
       grows and `.biztech-main` clips it - R13.8's defect, where the overflow is invisible because the
       clipping is what hides the clipping. */
    min-inline-size: 0;

    padding: 8px;
    border: 1px solid var(--biztech-palette-outline-subtle);
    border-radius: var(--biztech-radius-default);
    background: var(--biztech-palette-surface);

    /* W19-07 · a bar on the page is one of its panels - the case list's filters, the case page's milestone row - so it
       takes the theme's Depth as a card does. Inside a card it is flat (app.css, the one-level rule). */
    box-shadow: var(--biztech-shadow-card);
}

/* 🔴 W14-01 · A ROW WITH NO CONTROL ANYWHERE IN IT DRAWS NOTHING.

   Asked for on 2026-09-11: "if there is nothing to show in the toolbar do not show the toolbar."

   🔴 A NULL SLOT WAS ALREADY HANDLED AND IS NOT THE CASE THAT BITES. `Overflow`/`Secondary` null
   renders no trigger, and has since W0-73. What a caller passes in practice is a fragment FULL OF
   CONDITIONS - AgentSession's Secondary is a gated library picker and a gated panel loop - so the
   fragment is non-null and renders nothing on any composition declaring neither. `live-meeting` is
   exactly that: its expected control list is `[]`, and this row drew an 8px-padded bordered bar with a
   chevron in it.

   🔴 CSS RATHER THAN C#, AND IT IS THE ONLY PLACE THE ANSWER EXISTS. Blazor cannot be asked
   whether a RenderFragment WILL render anything without rendering it. A boolean parameter would be the
   caller re-deriving conditions it has already written once, which is the second-representation argument
   MainLayout's drawer `:has()` makes in this same seam.

   🔴 `:empty`, AND `:has(> *)` WAS THE FIRST SPELLING AND WAS REFUSED. A universal selector in a
   scoped sheet is what ScopedStyleReachTests.No_scoped_rule_targets_a_universal_selector forbids, with
   no exemption list on purpose - "two rules in the application had the `> *` shape and were CORRECT, and
   both were rewritten rather than excused". Mine was correct too (the `*` sits inside `:has()`, so
   Blazor stamps the OUTER compound and the `*` is never scoped) and it is rewritten rather than excused,
   because "this one is fine" is not something a reader can check from the stylesheet.

   `:empty` is exact here rather than a near-miss: Blazor removes insignificant whitespace unless
   `PreserveWhitespace` is set, and this project does not set it - so a wrapper whose fragment rendered
   nothing holds no child nodes at all.

   🔴 IT HIDES ON A NEGATION RATHER THAN SHOWING ON A POSITIVE, WHICH IS THE DIRECTION THAT FAILS
   SAFE. A selector that stops matching leaves every toolbar in the application VISIBLE. The reverse -
   `display: none` by default, revealed by `:has()` - loses every row in the application the day the
   support floor or a wrapper class moves.

   The four clauses are the four places a control can be: the row's own children (excluding the three
   boxes this component renders itself), the inline copy, and the two groups on the second line.

   🔴 W19 · AND A CHILD THAT IS ITSELF EMPTY DOES NOT COUNT. The customer's session pane writes one
   wrapper per toolbar panel - `[data-session-panel]`, kept so the panel's region exists before its
   first request arrives - and a document-request wrapper with nothing outstanding rendered nothing, yet
   held the row open as an 8px-padded strip with no control in it. `:not(:empty)` on the first clause
   is the same exactness the other three already rely on. */
.biztech-toolbar:not(:has(> :not(.biztech-toolbar-inline):not(.biztech-toolbar-more):not(.biztech-toolbar-expander):not(:empty))):not(:has(.biztech-toolbar-inline:not(:empty))):not(:has(.biztech-toolbar-secondary:not(:empty))):not(:has(.biztech-toolbar-narrow:not(:empty)))[b-v7m0m5mdiv] {
    display: none;
}

/* 🔴 THE VERTICAL SEPARATOR - D4, AND NO NEW COMPONENT FOR IT.

   A call site writes <UiDivider />, whose own sheet declares `border-block-start`. This turns that
   rule onto the inline axis instead. ::deep because the <hr> belongs to UiDivider, and Blazor stamps
   this file's scope attribute only on elements THIS component renders - the same rule that gives
   UiTabs its ::deep and MainNavMenu its own.

   🔴 A CHILD SELECTOR, NOT A DESCENDANT ONE, AND THE DIFFERENCE IS A VISIBLE DEFECT.
   `::deep .biztech-divider` compiles to `[b-xxxxxxxxxx] .biztech-divider` and reaches ANY divider
   under any element this component renders - which includes the More menu's panel, because that is
   rendered inside .biztech-toolbar-inline (and its folded twin .biztech-toolbar-narrow). A caller putting a <UiDivider /> between two UiMenuItems
   in the Overflow slot got a 1px vertical sliver hard against the panel's left edge with no top
   border, instead of a horizontal rule between two items. `::deep > ` restricts it to the row's own
   direct children, which is what the sentence above always meant.

   🔴 AND IT WINS OVER UiDivider's OWN RULE ONLY ON SOURCE ORDER, WHICH IS WORTH KNOWING
   BEFORE RENAMING EITHER FILE. `[b-toolbar] > .biztech-divider` and `.biztech-divider[b-divider]` are
   both (0,2,0) - an attribute selector and a class each count once - so the tie is broken by position
   in the generated bundle, and that bundle concatenates the scoped sheets in filename order.
   UiDivider sorts before UiToolbar, so this rule is later and wins. Renaming either sheet so the
   order inverts would silently return the separator to a horizontal rule with no border, with nothing
   failing.

   Zeroing `border-block-start` is not R14.1a's forbidden reset: what that rule forbids is zeroing a
   box-model property THE UTILITY LAYER OWNS - margin and padding - and no utility in app.css sets a
   border.

   🔴 inline-size: 0, NOT 1px. There is no global `box-sizing: border-box` in this
   application - app.css sets it on #blazor-error-ui, on .biztech-input and inside one media block, and
   the seam's components declare it individually - so `inline-size` here is CONTENT width and 1px would
   have produced a 2px element holding a 1px rule, with a dead pixel beside it. Zero content width plus
   the border is the hairline.

   `align-self: stretch` rather than a height is sound only because BizTechCssVariables resets
   `hr { margin: 0 }` in the document block; without that the user agent's `margin-block: 0.5em` would
   inset this rule 8px at each end. */
[b-v7m0m5mdiv] > .biztech-divider {
    align-self: stretch;
    inline-size: 0;
    border-block-start: 0;
    border-inline-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* 🔴 THE COLLAPSE - D2, AND THE WRAPPER EXISTS ONLY TO BE SWITCHED OFF.

   `display: contents` makes the inline wrapper vanish from layout, so the controls inside it stay
   direct flex children of the row and wrap and gap with everything else. A `display: block` wrapper
   would turn them into one unbreakable block that wraps as a unit.

   Both copies are in the DOM and exactly one is displayed. `display: none` removes the other from the
   accessibility tree as well as from the screen, which is what makes rendering the slot twice honest
   rather than a duplicate announcement - app.css's breadcrumb block states the same reason at the same
   breakpoint.

   599.98px, which is how R13.1 says this application writes MudBlazor's `sm`. */
.biztech-toolbar-inline[b-v7m0m5mdiv] {
    display: contents;
}

/* 🔴 W14-01 · THE EXPANDER, AND IT REPLACED A UiMenu TRIGGER.

   "expand new full line not a dropdown" (2026-09-11), so this button unfolds the row's second line in
   flow rather than opening a panel over the page. What that deletes is the whole reachability problem
   the rule here used to solve: UiMenu anchors its panel `inset-inline-end: 0` and `.biztech-main`
   declares `overflow-x: clip`, so a right-anchored 192px panel was safe only while the trigger had
   192px to its left - a measurement this file carried, with a note saying no test covered it. A second
   LINE is clipped by nothing, at any width.

   🔴 AT THE ROW'S END, AND IT TOOK THREE ROUNDS TO GET THE ARITHMETIC RIGHT. Flexbox divides
   free space EQUALLY among every item taking an auto margin. With the session row's own spacer on Swap
   as well, this margin produced TWO holes - ~200px before Swap and ~250px after it, photographed and
   marked on 2026-09-11. Taking it off then left the chevron hard against the controls it unfolds, which
   is not where a control that acts on the ROW belongs.

   One claimant is what makes it work. The session spacer is gone - SessionStage.razor.css records why -
   so this pushes exactly one element to the end and everything before it stays grouped on the left.
   Asked for in those words on 2026-09-11: "right align them ... expand button only".

   🔴 AND IT DECLARES NO HEIGHT, WHICH IS THIS FILE'S OWN ## Do not AND A TEST CAUGHT IT.
   The first version read `block-size: var(--biztech-control-height)` - the token rather than a literal,
   so the number was not forked - and UiSeamTests.The_toolbar_declares_no_height_of_its_own went red on
   both spellings anyway. It is right to: the rule is about this FILE, and "it reads the token" is not
   something a reader can check from a sweep.

   `align-self: stretch` is the answer this sheet already uses, twenty lines up, for the separator:
   "stretching makes the rule exactly as tall as whatever row it is in, at either control height, with
   no number in this file to keep in step." A button is no different. */
.biztech-toolbar-expander[b-v7m0m5mdiv] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    gap: 8px;

    margin-inline-start: auto;
    align-self: stretch;
    padding-inline: 8px;

    border: 1px solid var(--biztech-palette-outline);
    border-radius: var(--biztech-radius-default);
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.biztech-toolbar-expander:hover[b-v7m0m5mdiv] {
    background: color-mix(in srgb, currentcolor 12%, transparent);
}

/* The word, when there is one. /inquiries renames this trigger "Filters" at 375px (design §7) and the
   session row prints nothing at all, so both shapes have to lay out. */
.biztech-toolbar-expander-label[b-v7m0m5mdiv] {
    white-space: nowrap;
}

/* 🔴 W14-01 · AND NO EXPANDER WHEN THERE IS NOTHING BEHIND IT.

   "if there are no items to show expanded mode do not show the expan button" (2026-09-11). Same problem
   as the row above and the same instrument: `Secondary` is a fragment full of conditions, so non-null
   says nothing about whether it drew.

   Above sm the only thing reachable through this button is the Secondary group - Overflow's controls are
   on the first line - so an empty group makes the chevron a promise with nothing behind it.

   🔴 `:not(:has(... :not(:empty)))` RATHER THAN `:has(... :empty)`, AND THE DIFFERENCE IS A ROW
   THAT PASSES NO Secondary AT ALL. The wrapper is only rendered when the slot is non-null, so asking
   whether it is EMPTY asks about an element that is not there - which is false, so the hide never
   applied and /cases/{id} grew a More button with nothing behind it. Photographed on 2026-09-11.

   Asking the opposite - is there a Secondary with something IN it - is true in exactly one case and
   false in both others, which is the question that was meant. */
.biztech-toolbar:not(:has(.biztech-toolbar-secondary:not(:empty))) .biztech-toolbar-expander[b-v7m0m5mdiv] {
    display: none;
}

/* 🔴 AND BELOW sm IT COMES BACK, because that is where Overflow's own copy lives behind it.

   A row whose Secondary is empty still folds its first line at 375px, and an expander hidden there would
   leave every one of those controls unreachable - which is R13.8's defect ("clipped rather than
   scrollable, and its last control unreachable by any means") arriving by a new route.

   AFTER the rule above and at the same specificity, so source order decides and this wins where it
   applies - both selectors are a class plus a `:has()` of one class. */
@media (max-width: 599.98px) {
    .biztech-toolbar:has(.biztech-toolbar-narrow:not(:empty)) .biztech-toolbar-expander[b-v7m0m5mdiv] {
        display: inline-flex;
    }
}

/* 🔴 W14-01 · THE SECOND LINE.

   `flex-basis: 100%` in a wrapping row is what makes a full line rather than another item: the row
   cannot fit it beside anything, so it always starts one. A `display: block` sibling would have done
   the same only until the row happened to have room.

   Its own flex row, because the controls inside are a row: they wrap and gap here exactly as they do on
   the line above, with the same 8px.

   The rule separates it from the line above rather than a margin, because the two lines are one control
   group and a hairline says "still the same row, more of it" where a gap says "a different thing". */
.biztech-toolbar-more[b-v7m0m5mdiv] {
    flex-basis: 100%;

    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;

    padding-block-start: 8px;
    border-block-start: 1px solid var(--biztech-palette-outline-subtle);
}

/* 🔴 AND `hidden` HAS TO BE RESTATED, because the rule above would otherwise win.
   `display: none` is the user agent's default for [hidden] and any `display` declaration beats it.
   MainLayout's `.biztech-drawer[hidden]` carries the same line for the same reason. */
/* 🔴 W8-25's SWEEP ALSO NAMES `.biztech-toolbar`, AND THAT IS A SUBSTRING MATCH RATHER THAN A
   SECOND DEFECT. `PortalStyleSheetTests.IsToggledWithHidden` asks whether any TAG carrying the class
   name also carries `hidden=`, by `Contains` - and the tag below is
   `class="biztech-toolbar-more" hidden="..."`, which contains `biztech-toolbar` as a prefix. Every
   class in this application is prefixed that way, so the same reading will name the parent of any
   component whose child is toggled.

   The rule is written rather than argued away because it is TRUE on its own terms: a row marked
   `hidden` must not stay laid out, and `.biztech-toolbar` declares `display: flex` at the top of this
   file, which outranks the user agent exactly as the sweep says. Nothing toggles it today, so it is
   inert - and it costs one line to be right if anything ever does. */
.biztech-toolbar[hidden][b-v7m0m5mdiv] {
    display: none;
}

.biztech-toolbar-more[hidden][b-v7m0m5mdiv] {
    display: none;
}

/* Lays nothing out: the controls stay direct children of the second line and take its gap and wrap,
   the same argument .biztech-toolbar-inline makes for the first. */
.biztech-toolbar-secondary[b-v7m0m5mdiv] {
    display: contents;
}

/* 🔴 Overflow's SECOND COPY, OFF ABOVE sm.

   Above sm those controls are on the first line and this copy would be the same controls twice - in the
   document and in the accessibility tree, because the second line is in flow rather than in a panel that
   only exists while open. `display: none` is what keeps exactly one of them announced. */
.biztech-toolbar-narrow[b-v7m0m5mdiv] {
    display: none;
}

@media (max-width: 599.98px) {
    .biztech-toolbar-inline[b-v7m0m5mdiv] {
        display: none;
    }

    .biztech-toolbar-narrow[b-v7m0m5mdiv] {
        display: contents;
    }
}
/* /Components/Ui/UiTriStateBox.razor.rz.scp.css */
/* W14-03 · the permission tree's box.

   🔴 I19. EVERY SELECTOR BELOW NAMES A CLASS THIS COMPONENT'S OWN MARKUP WRITES. There is no `> *`
   and nothing reaching into UiIcon's <svg>: Blazor stamps the scope attribute on the LAST compound of
   a selector, so `.biztech-box svg` would be stamped on the svg - which belongs to UiIcon, not to this
   file - and would be inert with no error and no warning. The glyph is sized from this element's own
   font-size instead, which UiIcon's `em`-based sizing already follows.

   🔴 AND THE THREE STATES DIFFER BY MORE THAN COLOUR, which is the component's whole point (R12.7).
   Off has no glyph at all; On and Some carry different shapes. The colours below are the confirmation,
   never the signal. */

.biztech-box[b-cxpvvd13ou] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 20px;
    block-size: 20px;
    flex: 0 0 auto;

    /* The glyph inherits this, so no rule has to reach the child to size it. Read from the
       type scale rather than typed, so the box tracks the caption slot it sits beside. */
    font-size: var(--biztech-font-caption-size);

    border: 1px solid var(--biztech-palette-outline);

    /* 🔴 HALF THE PANEL RADIUS, BECAUSE A 20px CONTROL IS NOT A PANEL. The token is 8px - fine on a
       paper, and 40% of the width here, which rendered a CIRCLE. Beside the native checkboxes on the
       key rows that read as a radio button: "pick one of these" rather than "tick any of these".
       Read from the variable rather than restated, so it still tracks a theme change (R5.5). */
    border-radius: calc(var(--biztech-radius-default) / 2);
    color: var(--biztech-palette-on-primary);
    background-color: transparent;
}

.biztech-box-on[b-cxpvvd13ou],
.biztech-box-some[b-cxpvvd13ou] {
    border-color: var(--biztech-palette-primary);
    background-color: var(--biztech-palette-primary);
}
