/* ==========================================================================
   vaBase Account Portal - dark-first UI foundation (M2.1)
   Semantic tokens per docs/13; --vb-primary is the vaBase brand colour.
   Plain CSS, no frameworks. The full design system (light theme, complete
   palette spec) comes later.
   ========================================================================== */

:root {
    color-scheme: dark;

    /* Backgrounds & surfaces */
    --vb-bg: #0c0d0f;
    --vb-bg-soft: #141519;
    --vb-surface: #17181c;
    --vb-surface-raised: #1d1e23;

    /* Borders */
    --vb-border: #292a30;
    --vb-border-strong: #3c3e46;

    /* Text */
    --vb-text: #eceded;
    --vb-text-muted: #979aa1;

    /* Brand */
    --vb-primary: #5e00ea;
    --vb-primary-hover: #7326ff;
    --vb-primary-soft: rgba(94, 0, 234, 0.16);
    /* Brand tint readable as TEXT on dark backgrounds (buttons/focus use
       --vb-primary itself; #5e00ea lacks contrast as body-text/link colour). */
    --vb-primary-bright: #a883ff;

    /* Semantic status */
    --vb-success: #3ec27d;
    --vb-warning: #d9a13c;
    --vb-danger: #e35d6a;

    /* Shape & depth */
    --vb-radius: 12px;
    --vb-radius-sm: 8px;
    --vb-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);

    /* Type & spacing rhythm */
    --vb-font: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
    --vb-mono: "Cascadia Mono", Consolas, monospace;
    --vb-content-width: 1080px;
}

/* product/58 (the Account Portal beta polish): the M24.1 tokens, copied from the Admin Portal. */
/* ------------------------------------------------------------------ TOKENS */
:root {
    --vb-space-1: 0.25rem;
    --vb-space-2: 0.5rem;
    --vb-space-3: 0.75rem;
    --vb-space-4: 1rem;
    --vb-space-5: 1.5rem;
    --vb-space-6: 2rem;
    --vb-space-7: 3rem;
    --vb-space-8: 4rem;
    --vb-text-xs: 0.75rem;
    --vb-text-sm: 0.85rem;
    --vb-text-base: 0.95rem;
    --vb-text-md: 1.05rem;
    --vb-text-lg: 1.25rem;
    --vb-text-xl: 1.6rem;
    --vb-text-2xl: 2rem;
    --vb-radius-lg: 16px;
    --vb-shadow-2: 0 18px 60px rgba(0, 0, 0, 0.55);
    --vb-success-soft: rgba(62, 194, 125, 0.12);
    --vb-success-line: rgba(62, 194, 125, 0.4);
    --vb-warning-soft: rgba(217, 161, 60, 0.12);
    --vb-warning-line: rgba(217, 161, 60, 0.4);
    --vb-danger-soft: rgba(227, 93, 106, 0.12);
    --vb-danger-line: rgba(227, 93, 106, 0.4);
    --vb-info: #a883ff;
    --vb-primary-brighter: #c3aaff;
    --vb-on-primary: #fff;
    --vb-topbar-height: 56px;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

* { box-sizing: border-box; }

html, body {
    margin: 0;
    min-height: 100vh;
    background: var(--vb-bg);
    color: var(--vb-text);
    font-family: var(--vb-font);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

body {
    /* Subtle brand glow anchoring the top of every page. */
    background:
        radial-gradient(900px 340px at 50% -120px, rgba(94, 0, 234, 0.14), transparent 70%),
        var(--vb-bg);
    display: flex;
    flex-direction: column;
}

a {
    color: var(--vb-primary-bright);
    text-decoration: none;
}
a:hover { color: #c3aaff; }
a:focus-visible, button:focus-visible {
    outline: 2px solid var(--vb-primary);
    outline-offset: 2px;
    border-radius: var(--vb-radius-sm);
}

h1 { font-size: 1.7rem; font-weight: 650; letter-spacing: -0.02em; margin: 0 0 0.4rem; }
h1:focus { outline: none; }
h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 0.5rem; }
h3 { font-size: 0.95rem; font-weight: 600; margin: 0 0 0.4rem; }

.mono { font-family: var(--vb-mono); font-size: 0.9em; }
.muted { color: var(--vb-text-muted); }

/* --------------------------------------------------------------------------
   App shell
   -------------------------------------------------------------------------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.7rem 1.5rem;
    background: color-mix(in srgb, var(--vb-bg) 78%, transparent);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--vb-border);
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--vb-text);
    font-weight: 700;
    font-size: 1.05rem;
}
.brand:hover { color: var(--vb-text); }

.brand-mark {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--vb-primary) 0%, #8b3dff 100%);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 800;
    letter-spacing: 0;
    box-shadow: 0 2px 10px rgba(94, 0, 234, 0.45);
}

.brand-sub {
    color: var(--vb-text-muted);
    font-weight: 400;
    font-size: 0.85rem;
    border-left: 1px solid var(--vb-border-strong);
    padding-left: 0.6rem;
}

.topbar nav {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: wrap;
}

.nav-link {
    color: var(--vb-text-muted);
    padding: 0.35rem 0.75rem;
    border-radius: var(--vb-radius-sm);
    font-size: 0.95rem;
}
.nav-link:hover {
    color: var(--vb-text);
    background: var(--vb-surface-raised);
}

.user-chip {
    color: var(--vb-text-muted);
    background: var(--vb-surface);
    border: 1px solid var(--vb-border);
    border-radius: 999px;
    padding: 0.25rem 0.8rem;
    font-size: 0.85rem;
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.page {
    width: 100%;
    max-width: var(--vb-content-width);
    margin: 0 auto;
    padding: 2.25rem 1.5rem 3rem;
    flex: 1;
}

/* Page header pattern: title + supporting text + optional actions. */
.page-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.75rem;
}
.page-header .lede { margin: 0; }

.lede {
    color: var(--vb-text-muted);
    max-width: 46rem;
    margin: 0 0 1.5rem;
}

.section-title {
    margin: 2.5rem 0 0.25rem;
}
.section-title + .muted { margin-top: 0; }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    border: 1px solid var(--vb-border-strong);
    border-radius: var(--vb-radius-sm);
    background: var(--vb-surface-raised);
    color: var(--vb-text);
    padding: 0.5rem 1.1rem;
    font-size: 0.95rem;
    font-family: inherit;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
.btn:hover { background: var(--vb-border); color: var(--vb-text); }
.btn:active { transform: translateY(1px); }

.btn-primary {
    background: var(--vb-primary);
    border-color: var(--vb-primary);
    color: #fff;
    font-weight: 600;
    box-shadow: 0 2px 12px rgba(94, 0, 234, 0.35);
}
.btn-primary:hover {
    background: var(--vb-primary-hover);
    border-color: var(--vb-primary-hover);
    color: #fff;
}

.btn-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--vb-text-muted);
}
.btn-ghost:hover { color: var(--vb-text); background: var(--vb-surface-raised); }

.inline-form { display: inline; margin: 0; }

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */

.card {
    background: var(--vb-surface);
    border: 1px solid var(--vb-border);
    border-radius: var(--vb-radius);
    padding: 1.4rem;
    box-shadow: var(--vb-shadow);
}

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}

/* Clickable airline/tenant cards on the dashboard. */
.tenant-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}

.tenant-card {
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    background: var(--vb-surface);
    border: 1px solid var(--vb-border);
    border-radius: var(--vb-radius);
    padding: 1.25rem 1.4rem;
    box-shadow: var(--vb-shadow);
    color: var(--vb-text);
    transition: border-color 0.15s ease, transform 0.15s ease;
}
.tenant-card:hover {
    color: var(--vb-text);
    border-color: var(--vb-border-strong);
    transform: translateY(-2px);
}
.tenant-card:hover .tenant-card-cta { color: var(--vb-primary-bright); }

.tenant-card-name { font-size: 1.05rem; font-weight: 650; }

.tenant-card-slug {
    align-self: flex-start;
    font-family: var(--vb-mono);
    font-size: 0.8rem;
    color: var(--vb-text-muted);
    background: var(--vb-bg-soft);
    border: 1px solid var(--vb-border);
    border-radius: 6px;
    padding: 0.1rem 0.5rem;
}

.tenant-card-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.tenant-card-cta {
    margin-top: auto;
    padding-top: 0.35rem;
    font-size: 0.85rem;
    color: var(--vb-text-muted);
}

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.form-card {
    max-width: 27rem;
    margin-top: 0.5rem;
}

/* A form this account may not use (Create airline while the beta is invitation-only): visibly
   unavailable rather than a button that looks pressable and is not. */
.form-card :is(input, .btn):disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Centred narrow column for auth pages. */
.auth-page {
    max-width: 27rem;
    margin: 2.5rem auto 0;
    text-align: center;
}
.auth-page .card { text-align: left; margin-top: 1.5rem; }
.auth-page .lede { margin: 0 auto; }

.field { margin-bottom: 1.1rem; }
.field label {
    display: block;
    color: var(--vb-text);
    font-size: 0.88rem;
    font-weight: 550;
    margin-bottom: 0.35rem;
}

/* Blazor's InputText renders no type attribute by default, so target all inputs
   within a field rather than input[type=...]. */
.field input {
    width: 100%;
    background: var(--vb-bg-soft);
    border: 1px solid var(--vb-border-strong);
    border-radius: var(--vb-radius-sm);
    color: var(--vb-text);
    padding: 0.55rem 0.8rem;
    font-size: 0.95rem;
    font-family: inherit;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input::placeholder { color: var(--vb-text-muted); }
input:focus {
    outline: none;
    border-color: var(--vb-primary);
    box-shadow: 0 0 0 3px var(--vb-primary-soft);
}
/* Keep dark autofill on Chromium. */
input:-webkit-autofill {
    -webkit-box-shadow: 0 0 0 100px var(--vb-bg-soft) inset;
    -webkit-text-fill-color: var(--vb-text);
}

.form-actions { margin-top: 1.35rem; }
.form-actions .btn { width: 100%; }

.hint { color: var(--vb-text-muted); font-size: 0.8rem; margin-top: 0.35rem; }
.hint strong { color: var(--vb-text); }

.form-footer {
    margin: 1.1rem 0 0;
    padding-top: 1rem;
    border-top: 1px solid var(--vb-border);
    color: var(--vb-text-muted);
    font-size: 0.85rem;
}

.invalid { border-color: var(--vb-danger) !important; }
.validation-message {
    display: block;
    color: var(--vb-danger);
    font-size: 0.83rem;
    margin-top: 0.3rem;
}

.alert-error,
.alert-warning,
.alert-success {
    display: flex;
    gap: 0.5rem;
    background: color-mix(in srgb, var(--vb-danger) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--vb-danger) 55%, transparent);
    border-radius: var(--vb-radius-sm);
    color: var(--vb-text);
    padding: 0.65rem 0.9rem;
    margin-bottom: 1.1rem;
    font-size: 0.9rem;
}

/* Same shape as .alert-error, amber (M7.2: the doc 11 Grace payment warning). Only the
   colours differ, so the base rule is shared via the selector list above (the M9.2
   .data-input precedent - never copy the declaration). */
.alert-warning {
    background: color-mix(in srgb, var(--vb-warning) 12%, transparent);
    border-color: color-mix(in srgb, var(--vb-warning) 55%, transparent);
}

/* Green sibling (M7.3: "subscription active"). */
.alert-success {
    background: color-mix(in srgb, var(--vb-success) 12%, transparent);
    border-color: color-mix(in srgb, var(--vb-success) 55%, transparent);
}

/* --------------------------------------------------------------------------
   Data display
   -------------------------------------------------------------------------- */

/* .manage-list is a list of ACTIONS, each carrying the detail that used to be crammed
   into its own button label. It shares table.data's FRAME by sharing its selector
   rather than copying the declarations, so the two cannot drift: it sits directly
   below the status table and has to read as that table's sibling (the .data-input
   precedent, M9.2). */
table.data,
.manage-list {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--vb-surface);
    border: 1px solid var(--vb-border);
    border-radius: var(--vb-radius);
    overflow: hidden;
    box-shadow: var(--vb-shadow);
}

.manage-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    /* The same row metrics as a data cell - matched, not invented. */
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--vb-border);
}
.manage-row:last-child { border-bottom: none; }

.manage-row-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.manage-row-label { font-size: 0.93rem; font-weight: 500; }
.manage-row-detail { font-size: 0.83rem; color: var(--vb-text-muted); }

/* The action column never wraps and never stretches, so three rows of different
   label lengths still line up down the right-hand edge - which is the whole point. */
.manage-row .btn { white-space: nowrap; flex-shrink: 0; }

@media (max-width: 34rem) {
    .manage-row { flex-direction: column; align-items: stretch; }
    .manage-row .btn { width: 100%; }
}
table.data th, table.data td {
    text-align: left;
    padding: 0.65rem 1rem;
    border-bottom: 1px solid var(--vb-border);
    font-size: 0.93rem;
}
table.data th {
    color: var(--vb-text-muted);
    font-weight: 600;
    font-size: 0.83rem;
    background: var(--vb-bg-soft);
    white-space: nowrap;
}
table.data tr:last-child th,
table.data tr:last-child td { border-bottom: none; }

/* Status badges - colour conventions per doc 13; label always present. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    border-radius: 999px;
    padding: 0.14rem 0.7rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--vb-text-muted);
    background: var(--vb-surface-raised);
    border: 1px solid var(--vb-border-strong);
}
.badge::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}
.badge-success { color: var(--vb-success); background: rgba(62, 194, 125, 0.12); border-color: rgba(62, 194, 125, 0.4); }
.badge-warning { color: var(--vb-warning); background: rgba(217, 161, 60, 0.12); border-color: rgba(217, 161, 60, 0.4); }
.badge-danger  { color: var(--vb-danger);  background: rgba(227, 93, 106, 0.12); border-color: rgba(227, 93, 106, 0.4); }
.badge-info    { color: var(--vb-primary-bright); background: var(--vb-primary-soft); border-color: rgba(94, 0, 234, 0.45); }
.badge-muted   { color: var(--vb-text-muted); }

/* --------------------------------------------------------------------------
   Framework chrome & responsive
   -------------------------------------------------------------------------- */

.blazor-error-boundary {
    background: var(--vb-danger);
    padding: 1rem;
    color: #fff;
    border-radius: var(--vb-radius-sm);
}
.blazor-error-boundary::after { content: "An error has occurred."; }

@media (max-width: 640px) {
    .topbar { padding: 0.6rem 1rem; }
    .brand-sub { display: none; }
    .user-chip { display: none; }
    .page { padding: 1.5rem 1rem 2.5rem; }
    .page-header { align-items: stretch; flex-direction: column; }
}

/* --------------------------------------------------------------------------
   Modal dialog
   --------------------------------------------------------------------------
   Matched to the Admin Portal's (same selectors, same metrics) rather than
   invented, so a confirmation looks the same in both portals: dimmed backdrop,
   centred card. Clicking the backdrop cancels; the card stops propagation. */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(6, 7, 8, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    z-index: 100;
}
.modal {
    width: 100%;
    max-width: 30rem;
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.55);
}
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.2rem;
}

/* --------------------------------------------------------------------------
   Staff invitations (M3F.3)
   -------------------------------------------------------------------------- */

/* A row of choices that are not a form submission - .form-actions cannot serve, because
   it deliberately stretches its button to full width for the single-submit forms this
   portal is mostly made of. Matches .hero-actions, left-aligned. */
/* product/54 E1: the operator Delivery card's state line - the badge is spaced from its sentence by the gap, never a typed space (the pill-spacing rule). */
.email-delivery-state {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 0.9rem;
}

.card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.1rem;
}

/* A secondary action inside a table row, where a full-height button would set the row
   height. The Admin Portal has the same class for the same reason; the two stylesheets
   are separate and neither may name a class the other lacks (the M7.7 lesson). */
.btn-small {
    padding: 0.35rem 0.7rem;
    font-size: 0.85rem;
}


/* --------------------------------------------------------------------------
   Selectable option tiles (M3F.6)

   The same shape the Admin Portal uses for its settings choices, so somebody
   picking permissions meets one control wherever they meet it. The two portals
   have separate stylesheets and neither may name a class the other lacks, so
   this is written here rather than shared.
   -------------------------------------------------------------------------- */

.option-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 0.9rem;
    align-items: stretch;
    margin-bottom: 1rem;
}

.option-grid .radio-option { height: 100%; }

/* ⚠️ Qualified `label.radio-option` deliberately, exactly as the Admin Portal is: `.field label`
   above is (0,1,1) with display:block and would beat a bare `.radio-option` (0,1,0) on
   SPECIFICITY however late this appears, laying the tile out as a block instead of a row. The
   class is only ever used on a label. */
label.radio-option {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--vb-border);
    border-radius: var(--vb-radius);
    cursor: pointer;
    /* The block label above a field normally supplies this; an option tile IS the label. */
    margin-bottom: 0;
    font-weight: 400;
}

.radio-option:hover { background: var(--vb-bg-soft); }

.radio-option:has(input:checked) {
    border-color: var(--vb-primary);
    background: color-mix(in srgb, var(--vb-primary) 9%, transparent);
}

.radio-option:has(input:disabled) {
    opacity: 0.55;
    cursor: not-allowed;
}

/* The registration form's trap (product/58 section 2.7c). Hidden from people and from assistive
   technology alike, so only something reading the markup finds it. */
.honeypot { display: none; }

/* The registration agreement: a native checkbox beside its sentence, the sentence wrapping under
   itself rather than under the box, and the whole line a target for the pointer. */
.field label.consent-label { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.88rem; font-weight: 400; color: var(--vb-text); cursor: pointer; margin: 0; }
.consent-label input { width: auto; min-width: 18px; min-height: 18px; background: none; border: 0; padding: 0; box-shadow: none; margin: 0.1rem 0 0; accent-color: var(--vb-primary); flex: 0 0 auto; }
.consent-label a { font-weight: 550; }

/* Resets the .field input text-box styling (full width, background, border, padding): inside a
   tile the input is a native checkbox, not a text field. */
.radio-option input {
    width: auto;
    background: none;
    border: 0;
    padding: 0;
    box-shadow: none;
    margin-top: 0.2rem;
    accent-color: var(--vb-primary);
    flex: 0 0 auto;
}

.radio-option-body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.radio-option-desc {
    color: var(--vb-text-muted);
    font-size: 0.85rem;
    line-height: 1.45;
}

.radio-option-desc em {
    display: block;
    margin-top: 0.25rem;
    font-style: normal;
    color: var(--vb-warning);
}

/* The row above a set of tiles: filter, bulk actions, and how many are chosen. */
.filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.7rem;
    margin-bottom: 1rem;
}

.filter-bar input[type="search"] {
    flex: 1 1 220px;
    max-width: 22rem;
    background: var(--vb-bg-soft);
    border: 1px solid var(--vb-border-strong);
    border-radius: var(--vb-radius-sm);
    color: var(--vb-text);
    padding: 0.5rem 0.8rem;
    font-size: 0.92rem;
    font-family: inherit;
}

/* A short input keeps its natural width inside a wide form card. */
.field-narrow { max-width: 22rem; }

/* A form card that holds a GRID rather than a stack of single fields (M3F.7).

   ⚠️ .form-card is max-width: 27rem, which is right for every other form in this portal -
   they are sign-up-shaped, one field per row, and a wide column of short inputs reads
   badly. It is wrong for a card whose content is a multi-column grid: the tiles collapsed
   into one column and the page became about 1,400px of scrolling, which is what made an
   otherwise finished screen read as unfinished (Myles: "This looks poor"). A modifier
   rather than a change to .form-card, so the narrow default keeps protecting the forms it
   was written for. */
.form-card-wide {
    max-width: none;
}

/* The full-width primary button is a deliberate part of .form-actions: it ends a narrow
   form, where a small button floating left looks lost. Across a wide card it reads as a
   mobile call-to-action, so inside one the button returns to its natural size. */
.form-card-wide .form-actions .btn {
    width: auto;
}

/* The chosen starting point for what an invited person can do. Same tile shape as the
   individual areas below it, so one control language covers both halves of the choice. */
.preset-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0.75rem;
    margin-bottom: 1.1rem;
}

.preset-grid .radio-option { height: 100%; }

/* The heading above one group of option tiles (M3F.8). Quiet on purpose: it orients, it is
   not a section of the page. */
.option-group-title {
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--vb-text-muted);
    margin: 1.3rem 0 0.6rem;
}

.option-group-title:first-of-type { margin-top: 0.4rem; }

/* 🚨 STICKY, so what is chosen and the button that acts on it are never separated by a
   scroll. With the full list open the card is taller than a screen, and a button at the
   bottom of it makes choosing and sending two different journeys.

   ⚠️ It sits INSIDE the card and sticks to the bottom of the viewport, so it stops being
   sticky once the card ends - a bar that hovered over the page after its own form had
   scrolled away would be chrome belonging to nothing. */
.action-bar {
    position: sticky;
    bottom: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 1.4rem -1.4rem -1.4rem;
    padding: 0.9rem 1.4rem;
    border-top: 1px solid var(--vb-border);
    /* Opaque: the tiles scroll UNDER this, and a translucent bar over them is unreadable. */
    background: var(--vb-surface);
    border-radius: 0 0 var(--vb-radius) var(--vb-radius);
}

/* Several small actions in one table cell, without the row growing to button height. */
.row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    justify-content: flex-end;
}

/* 🚨 A <td> WITH display:flex STOPS BEING A TABLE CELL - the M3F.11 defect, which shows as the
   divider under every row stopping short of the right-hand edge because the cell border draws
   only as wide as its own content. The Admin Portal carries the identical companion for the
   identical class; M11I.6 put the first .row-actions cell in THIS portal, and TableCellDisplayTests
   refused it until this rule existed. Matched rather than invented, so the class is safe wherever
   it lands on either portal.

   Cells keep table-cell display and right-align INLINE instead: the buttons are inline-flex, so
   they still sit in a row and still wrap, and the gap becomes a margin because gap belongs to a
   flex or grid container and this is neither any more. */
td.row-actions,
th.row-actions {
    display: table-cell;
    text-align: right;
}
td.row-actions > * + *,
th.row-actions > * + * { margin-left: 0.4rem; }

/* --------------------------------------------------------------------------
   Pending invitations on the dashboard (M3F.9)

   Brand-tinted rather than an .alert-* colour on purpose: an invitation is good
   news, and the alert palette here means danger / warning / done. It is the only
   thing a newly registered staff member has on the page, so it leads.
   -------------------------------------------------------------------------- */

.invite-banner {
    background: linear-gradient(
        135deg,
        color-mix(in srgb, var(--vb-primary) 18%, var(--vb-surface)) 0%,
        var(--vb-surface) 70%);
    border: 1px solid color-mix(in srgb, var(--vb-primary) 45%, var(--vb-border));
    border-radius: var(--vb-radius);
    padding: 1.4rem;
    box-shadow: var(--vb-shadow);
    margin-bottom: 1.6rem;
}

.invite-banner h2 {
    margin-top: 0;
    margin-bottom: 1rem;
}

/* Stacks under the button on narrow screens rather than squeezing the text
   column to nothing. */
.invite-offer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.9rem;
    padding: 0.9rem 0;
    border-top: 1px solid color-mix(in srgb, var(--vb-primary) 22%, var(--vb-border));
}

.invite-offer > div {
    flex: 1 1 18rem;
}

.invite-offer .muted {
    display: block;
    font-size: 0.9rem;
    margin-top: 0.2rem;
}

/* A card whose own contents need spacing, and stacked cards needing space between them.

   ⚠️ Written here rather than borrowed: the Admin Portal has had this exact class since M10.6,
   and the two portals have SEPARATE stylesheets - a class that exists in one is not defined in
   the other, which is the trap StylesheetClassTests caught on the M3F.10 verification page (and
   the fourth time this phase). Same metrics as its Admin Portal namesake on purpose, so the two
   surfaces of one flow do not drift apart visually. `.card` carries no margin by design - most
   live in a grid whose gap does the spacing - so the margin belongs to the stack, not the card. */
.card-stack {
    display: grid;
    gap: 1.25rem;
}

.card-stack + .card-stack {
    margin-top: 1.25rem;
}

/* M11I.6: the operator chat page is this portal's first surface with a picker on it, and this
   stylesheet had no select rule at all - a bare select would have rendered in the browser's own
   chrome on a dark page, which is the silent-CSS failure StylesheetClassTests cannot see (the
   guard checks a class is DEFINED, never that an element is styled). MATCHED to the Admin
   Portal's rule rather than invented, down to the metrics and the data-URI chevron, because the
   two portals are separate deployables of one platform and a picker should look the same in
   both. Chromium pins the native arrow to the border edge and ignores padding-right, so the
   arrow has to be replaced rather than moved. */
.field select {
    width: 100%;
    background: var(--vb-bg-soft);
    border: 1px solid var(--vb-border-strong);
    border-radius: var(--vb-radius-sm);
    color: var(--vb-text);
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23979aa1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.85rem center;
    padding: 0.55rem 2.2rem 0.55rem 0.8rem;
    font-size: 0.95rem;
    font-family: inherit;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field select:focus {
    outline: none;
    border-color: var(--vb-primary);
    box-shadow: 0 0 0 3px var(--vb-primary-soft);
}

/* A reported message, as the moderator reads it. Bounded and wrapped: the copy is somebody
   else's words, it may be 500 characters of one unbroken string, and a cell that stretches the
   table off the page would hide the actions beside it. Same name and same rule as the Admin
   Portal's, because it is the same thing on the other half of one feature. */
.chat-report-body {
    max-width: 28rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* The term list: many short chips rather than a table of one-word rows. */
.term-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.term-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--vb-bg-soft);
    border: 1px solid var(--vb-border-strong);
    border-radius: 999px;
    padding: 0.3rem 0.35rem 0.3rem 0.75rem;
    font-size: 0.88rem;
}

/* The remove control is a glyph inside the chip, so a list of thirty terms stays a list of
   terms rather than a column of buttons. */
.term-chip button {
    background: none;
    border: none;
    color: var(--vb-text-muted);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0.15rem 0.4rem;
    border-radius: 999px;
    font-family: inherit;
}

.term-chip button:hover:not(:disabled) {
    color: var(--vb-text);
    background: var(--vb-border);
}

.term-chip button:disabled { cursor: default; opacity: 0.5; }

/* --------------------------------------------------------------------------
   M11I.6c: the predictive pilot search in /operator/chat's Restrict a pilot box.

   ⚠️ THE ADMIN PORTAL'S PICKER, MATCHED RATHER THAN DESIGNED AGAIN. The two portals have separate
   stylesheets (StylesheetClassTests), and one platform should draw one kind of type-ahead one way.
   The names are that portal's own, airport-* included - its PilotField already draws pilots with
   them - and the values are what its rules come to INSIDE a popout, the only place this page draws
   the list. Only what this page uses is carried over.
   -------------------------------------------------------------------------- */

/* Results OVERLAY the card rather than pushing its other fields down. The wrap holds the INPUT
   alone, so the panel sits just under the box and the hint stays in flow beneath it. */
.suggest-wrap { position: relative; }
.suggest-popout {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 30;
    margin-top: 4px;
    padding: 0.3rem;
    background: var(--vb-surface-raised);
    border: 1px solid var(--vb-border-strong);
    border-radius: var(--vb-radius-sm);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
    max-height: 22rem;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--vb-primary-hover) transparent;
}
.suggest-popout::-webkit-scrollbar { width: 10px; }
.suggest-popout::-webkit-scrollbar-track { background: transparent; }
.suggest-popout::-webkit-scrollbar-thumb {
    background: var(--vb-primary);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: content-box;
}
.suggest-popout::-webkit-scrollbar-thumb:hover {
    background: var(--vb-primary-hover);
    background-clip: content-box;
}

/* The panel scrolls, so the list is a plain flow of rows. Each row owns its padding so its
   highlight reaches the panel's inner edge, and rows separate on the highlight rather than on
   dividers a rounded row would curve short. */
.airport-result-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.airport-result-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.9rem;
    padding: 0.6rem 0.7rem;
    border-radius: var(--vb-radius-sm);
}
/* The brand tint, not a darker step: a highlight darker than the raised panel reads as a hole. */
.airport-result-list li:hover { background: color-mix(in srgb, var(--vb-primary) 9%, transparent); }
.airport-result-info { min-width: 0; }
.airport-result-main {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.airport-result-meta { font-size: 0.8rem; margin-top: 0.2rem; }
.airport-result-list .btn { flex: 0 0 auto; }
.airport-no-results { margin: 0.85rem 0; }

/* The picked pilot, in the tint a chosen option carries. */
.airport-selected {
    background: var(--vb-primary-soft);
    border: 1px solid var(--vb-primary);
    border-radius: var(--vb-radius-sm);
    padding: 0.75rem 0.9rem;
}
.airport-selected-main {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
}
.airport-selected p { margin: 0.35rem 0 0; font-size: 0.85rem; }

/* ==========================================================================
   Account Portal beta polish (product/58): the product CSS the boards demonstrate.
   Written to be merged into src/VaBase.AccountPortal/wwwroot/app.css at phase A2 as it stands.

   Every rule here is one of three things, and says which:
   - TOKENS: the M24.1 additions the Admin Portal already has (its app.css lines 6152-6200), copied
     so both portals read one scale.
   - MATCHED: a primitive copied from the Admin Portal's app.css with the same metrics (the two
     portals keep separate stylesheets by rule; a class must exist in each - StylesheetClassTests).
     The Admin line is named so a later change can be mirrored.
   - NEW: a rule this portal needs that the Admin Portal has no equivalent of (the airline card, the
     auth layout, the footer, the brand mark, the downloads cards, the support panel).
   ========================================================================== */

/* The body's decorative radial glow goes (product/58 section 6): a flat background, the Admin way. */
body { background: var(--vb-bg); }

/* MATCHED (Admin app.css 892): icons are stroke-only and take the colour of what they sit beside. */
.icon { width: 20px; height: 20px; flex: none; }

/* MATCHED (Admin 5697). */
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

/* MATCHED (Admin 5685): a link-styled button. */
.btn-link { border: none; background: none; padding: 0; font: inherit; font-size: 0.88rem; font-weight: 600; color: var(--vb-primary-bright); cursor: pointer; }
.btn-link:hover { text-decoration: underline; }

/* MATCHED (Admin 6627, 7188): icon and small buttons. */
.btn-icon { padding: 0.5rem 0.6rem; }
.btn-icon .icon { width: 18px; height: 18px; }
.btn-sm { padding: 0.35rem 0.8rem; font-size: 0.85rem; }
.btn .icon { width: 16px; height: 16px; }

/* ------------------------------------------------------------------ The shell */

/* NEW: the brand mark is the inverse SVG inline (BrandMark.razor), replacing the "vB" text square.
   28px in the top bar, 44px on the auth pages, 36px on the problem pages. */
.brand-mark { display: inline-flex; width: 28px; height: 28px; border-radius: 7px; background: none; box-shadow: none; }
.brand-mark svg { width: 100%; height: 100%; display: block; }
.brand { gap: 0.55rem; font-weight: 650; }
.brand-sub { font-size: 0.82rem; }

/* The top bar holds its height so the page never jumps when the menu or the chip renders. */
.topbar { min-height: var(--vb-topbar-height); padding-top: 0; padding-bottom: 0; }
.topbar nav { gap: 0.25rem; }
.nav-link { font-size: 0.9rem; font-weight: 500; padding: 0.4rem 0.7rem; }
.nav-link[aria-current="page"] { color: var(--vb-text); background: var(--vb-surface-raised); }

/* MATCHED (Admin 6420-6486): the account menu. Opening and closing is js/account-shell.js's. */
.user-menu { position: relative; }
.user-menu-btn { display: flex; align-items: center; gap: 0.55rem; padding: 0.25rem 0.5rem 0.25rem 0.25rem; border: 1px solid transparent; border-radius: 999px; background: transparent; color: var(--vb-text); font: inherit; font-size: 0.9rem; font-weight: 550; cursor: pointer; }
.user-menu-btn:hover, .user-menu-btn[aria-expanded="true"] { background: var(--vb-surface); border-color: var(--vb-border); }
.user-menu-btn .icon { width: 16px; height: 16px; color: var(--vb-text-muted); }
.avatar-initials { width: 30px; height: 30px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 700; background: var(--vb-surface-raised); border: 1px solid var(--vb-border-strong); color: var(--vb-text); flex: none; }
.user-menu-list { position: absolute; right: 0; top: calc(100% + 0.4rem); z-index: 60; min-width: 15rem; background: var(--vb-surface-raised); border: 1px solid var(--vb-border-strong); border-radius: var(--vb-radius); box-shadow: var(--vb-shadow-2); padding: 0.4rem; }
.user-menu-list[hidden] { display: none; }
.user-menu-head { padding: 0.55rem 0.7rem 0.6rem; border-bottom: 1px solid var(--vb-border); margin-bottom: 0.35rem; }
.user-menu-head strong { display: block; font-size: 0.92rem; }
.user-menu-head span { display: block; font-size: 0.78rem; color: var(--vb-text-muted); overflow: hidden; text-overflow: ellipsis; }
.user-menu-list a, .user-menu-list button { display: flex; align-items: center; gap: 0.6rem; width: 100%; padding: 0.5rem 0.7rem; border: none; border-radius: var(--vb-radius-sm); background: transparent; color: var(--vb-text); font: inherit; font-size: 0.9rem; text-align: left; cursor: pointer; text-decoration: none; }
.user-menu-list a:hover, .user-menu-list button:hover { background: var(--vb-surface); color: var(--vb-text); }
.user-menu-list .icon { width: 16px; height: 16px; color: var(--vb-text-muted); }
.user-menu-list .menu-sep { border-top: 1px solid var(--vb-border); margin: 0.35rem 0; }
.user-menu-list .menu-label { padding: 0.35rem 0.7rem 0.1rem; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--vb-text-muted); }
.user-menu-list .menu-ext { margin-left: auto; color: var(--vb-text-muted); display: inline-flex; }
.user-menu-list .menu-ext .icon { width: 13px; height: 13px; }
.user-menu-list form { margin: 0; }

/* NEW: the footer on every page - the main website, support, the year. Quiet, one line. */
.site-footer { border-top: 1px solid var(--vb-border); padding: 1.1rem 1.5rem; }
.site-footer-inner { max-width: var(--vb-content-width); margin: 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.4rem; font-size: 0.82rem; color: var(--vb-text-muted); }
.site-footer a { color: var(--vb-text-muted); display: inline-flex; align-items: center; gap: 0.3rem; }
.site-footer a:hover { color: var(--vb-text); }
.site-footer a .icon { width: 13px; height: 13px; }
.site-footer-copy { margin-left: auto; }

/* NEW: an external destination says so (the Admin Portal, the website, a receipt). */
.ext { display: inline-flex; align-items: center; gap: 0.35rem; }
.ext .icon { width: 14px; height: 14px; }

/* MATCHED (Admin 6410-6417): breadcrumbs. */
.breadcrumbs { min-width: 0; margin-bottom: 0.6rem; }
.breadcrumbs ol { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: 0.35rem; font-size: 0.9rem; white-space: nowrap; overflow: hidden; }
.breadcrumbs li { display: flex; align-items: center; gap: 0.35rem; min-width: 0; }
.breadcrumbs a { color: var(--vb-text-muted); font-weight: 550; }
.breadcrumbs a:hover { color: var(--vb-text); }
.breadcrumbs li[aria-current="page"] { color: var(--vb-text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.breadcrumbs .crumb-sep { color: var(--vb-border-strong); flex: none; display: inline-flex; }
.breadcrumbs .crumb-sep .icon { width: 14px; height: 14px; }

/* MATCHED (Admin 7154-7162): the page header's title row, with a leading tile (the airline's logo). */
.page-header { margin-bottom: 1.4rem; }
.page-header h1 { margin: 0; font-size: 1.55rem; }
.page-header-title-row { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; }
.page-header .lede { margin-top: 0.3rem; font-size: 0.95rem; }
.page-header-leading { flex: none; display: flex; align-items: center; }
.page-header-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
@media (min-width: 641px) {
    .page-header { align-items: center; }
    .page-header > div:not(.page-header-leading):not(.page-header-actions) { flex: 1 1 24rem; min-width: 0; }
}

/* ------------------------------------------------------------------ Status and facts */

/* MATCHED (Admin 4711, 6633, 7182): the status pill is the one badge family; it never wraps. */
.badge { white-space: nowrap; }
.badge-marked::before { content: none; }
.badge-lg { font-size: 0.85rem; padding: 0.25rem 0.85rem; }

/* MATCHED (Admin 6779-6781): a facts list, in place of a two-column table. */
.facts { display: grid; grid-template-columns: 9rem minmax(0, 1fr); gap: 0.55rem 1rem; margin: 0; font-size: 0.9rem; }
.facts dt { color: var(--vb-text-muted); }
.facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.facts dd .muted { display: block; font-size: 0.82rem; margin-top: 0.15rem; }
@media (max-width: 480px) { .facts { grid-template-columns: minmax(0, 1fr); gap: 0.15rem 0; } .facts dd { margin-bottom: 0.6rem; } }

/* ------------------------------------------------------------------ The airline card (NEW) */

.tenant-grid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1.1rem; }
.tenant-card { padding: 1.2rem 1.3rem 1.1rem; gap: 0.8rem; }
.tenant-card-head { display: flex; align-items: center; gap: 0.8rem; min-width: 0; }
.tenant-card-head .tenant-card-name { font-size: 1.05rem; font-weight: 650; line-height: 1.25; }
.tenant-card-head .tenant-card-slug { align-self: auto; display: inline-block; margin-top: 0.3rem; }
.tenant-card-titles { min-width: 0; display: flex; flex-direction: column; }

/* The airline's tile: its logo or favicon, the initials behind a dead image (the Admin switcher's tile). */
.airline-tile { width: 44px; height: 44px; border-radius: 10px; flex: none; display: inline-flex; align-items: center; justify-content: center; background: var(--vb-surface-raised); border: 1px solid var(--vb-border-strong); color: var(--vb-text); font-weight: 700; font-size: 0.85rem; overflow: hidden; }
.airline-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* PR #274 review: a favicon that will not load is hidden (js/account-shell.js) and the initials take
   the tile - the display rule above would otherwise beat the hidden attribute. */
.airline-tile img[hidden] { display: none; }
.airline-tile-lg { width: 56px; height: 56px; border-radius: 12px; font-size: 1rem; }

.tenant-card-detail { font-size: 0.86rem; color: var(--vb-text-muted); margin: -0.2rem 0 0; }
.tenant-card-role { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; color: var(--vb-text-muted); }
.tenant-card-role .icon { width: 15px; height: 15px; }

/* The card's foot: the primary way in, and the quiet links beside it. The whole card is not a link
   any more (two destinations on one card need their own anchors), so the title links instead. */
.tenant-card-foot { margin-top: auto; padding-top: 0.9rem; border-top: 1px solid var(--vb-border); display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; flex-wrap: wrap; }
.tenant-card-links { display: flex; gap: 0.9rem; font-size: 0.85rem; }
.tenant-card-links a { color: var(--vb-text-muted); }
.tenant-card-links a:hover { color: var(--vb-text); }
.tenant-card:hover { transform: none; border-color: var(--vb-border-strong); }
.tenant-card-name a { color: var(--vb-text); }
.tenant-card-name a:hover { color: var(--vb-primary-bright); }

/* ------------------------------------------------------------------ The airline page (NEW) */

.detail-columns { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 1.1rem; align-items: start; }
@media (max-width: 900px) { .detail-columns { grid-template-columns: minmax(0, 1fr); } }
.card h2 { font-size: 1.02rem; margin-bottom: 0.9rem; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.9rem; }
.card-head h2 { margin: 0; }
.card-foot { margin-top: 1.1rem; display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; }
.subscription-state { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.6rem; }
.subscription-state .muted { font-size: 0.86rem; }

/* The one-time strip after creating an airline: three next steps, then it goes. */
.next-steps { background: linear-gradient(135deg, color-mix(in srgb, var(--vb-primary) 14%, var(--vb-surface)) 0%, var(--vb-surface) 70%); border: 1px solid color-mix(in srgb, var(--vb-primary) 40%, var(--vb-border)); border-radius: var(--vb-radius); padding: 1.1rem 1.3rem; margin-bottom: 1.1rem; }
.next-steps h2 { font-size: 0.98rem; margin: 0 0 0.6rem; }
.next-steps ol { margin: 0; padding-left: 1.2rem; display: grid; gap: 0.3rem; font-size: 0.9rem; }
.next-steps ol .muted { font-size: 0.85rem; }

/* ------------------------------------------------------------------ Downloads (NEW) */

.download-card { display: grid; gap: 0.75rem; }
.download-card-head { display: flex; align-items: center; gap: 0.75rem; }
.download-card-head h2, .download-card-head h3 { margin: 0; }
.download-icon { width: 40px; height: 40px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center; background: var(--vb-primary-soft); border: 1px solid color-mix(in srgb, var(--vb-primary) 45%, var(--vb-border)); color: var(--vb-primary-bright); flex: none; }
.download-icon .icon { width: 20px; height: 20px; }
.download-meta { display: flex; flex-wrap: wrap; gap: 0.3rem 0.9rem; font-size: 0.82rem; color: var(--vb-text-muted); margin: 0; }
.download-meta .mono { font-size: 0.82rem; }
.download-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; margin-top: 0.2rem; }
.download-list { display: grid; gap: 0.6rem; }
.download-row { display: flex; align-items: center; gap: 0.9rem; padding: 0.8rem 1rem; border: 1px solid var(--vb-border); border-radius: var(--vb-radius-sm); background: var(--vb-bg-soft); }
.download-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.download-row-text strong { font-size: 0.95rem; }
.download-row-text .muted { font-size: 0.82rem; }
/* A6: the airline's status pill closes its package line; spaced by the stylesheet, never a typed
   space (Blazor trims one at an element's edge). */
.download-row-text .badge { margin-left: 0.35rem; }
.download-row .btn { flex: none; }
@media (max-width: 560px) { .download-row { flex-wrap: wrap; } .download-row .btn { width: 100%; } }
/* Which template version the airline's site reports (Shared/SiteVersionLine.razor): the pill and
   its words spaced by the gap, never a typed space. */
.site-version { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.55rem; margin: 0.35rem 0 0; font-size: 0.85rem; color: var(--vb-text-muted); }
.site-version .mono { font-size: 0.82rem; color: var(--vb-text); }
.download-row-text .site-version .badge { margin-left: 0; }
.download-row-text .site-version { font-size: 0.82rem; margin-top: 0.2rem; }
.site-version-help { margin: 0.35rem 0 0; font-size: 0.82rem; }
.guide-list { margin: 0.6rem 0 0; padding-left: 1.2rem; font-size: 0.9rem; display: grid; gap: 0.35rem; }
details.whats-inside summary { cursor: pointer; font-size: 0.88rem; color: var(--vb-primary-bright); font-weight: 600; list-style: none; }
details.whats-inside summary::-webkit-details-marker { display: none; }
details.whats-inside ul { margin: 0.5rem 0 0; padding-left: 1.2rem; font-size: 0.88rem; color: var(--vb-text-muted); display: grid; gap: 0.25rem; }

/* ------------------------------------------------------------------ Support (NEW) */

/* Two ways to reach vaBase, side by side (Myles, 2026-11-13): one e-mail, one Discord. They are
   equals, so they share a row and a width; on a phone one sits under the other. */
.support-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 2.25rem; }
.support-pair .support-panel { margin-top: 0; }
/* Discord's mark keeps Discord's colour: a logo recoloured to our accent is not their logo. */
.support-panel .icon.icon-discord { color: #5865f2; }
@media (max-width: 720px) { .support-pair { grid-template-columns: 1fr; gap: 0.75rem; } }
.support-panel { display: flex; align-items: center; gap: 0.8rem; margin-top: 2.25rem; padding: 0.9rem 1.1rem; border: 1px solid var(--vb-border); border-radius: var(--vb-radius); background: var(--vb-bg-soft); font-size: 0.88rem; color: var(--vb-text-muted); }
.support-panel .icon { width: 20px; height: 20px; color: var(--vb-primary-bright); flex: none; }
.support-panel strong { color: var(--vb-text); }

/* ------------------------------------------------------------------ Empty state, problem, skeleton, toast */

/* MATCHED (Admin 837-890). */
.empty-state { text-align: center; padding: 3rem 1.25rem; }
.empty-state-inner { max-width: 22rem; margin: 0 auto; }
.empty-state-bare { padding: 1.5rem 0 0.5rem; }
.empty-state h2 { font-size: 0.95rem; font-weight: 600; margin: 0 0 0.35rem; }
.empty-state p { margin: 0 0 0.5rem; font-size: 0.875rem; line-height: 1.6; }
.empty-state .empty-state-action { margin: 1.25rem 0 0; }
.empty-state-icon { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; margin: 0 auto 1rem; border-radius: 10px; background: var(--vb-primary-soft); border: 1px solid color-mix(in srgb, var(--vb-primary) 45%, var(--vb-border)); color: var(--vb-primary-bright); }
.empty-state-icon-muted { background: color-mix(in srgb, var(--vb-text-muted) 14%, transparent); border-color: var(--vb-border-strong); color: var(--vb-text-muted); }
.empty-state-footnote { margin: 0.9rem 0 0; font-size: 0.78rem; color: var(--vb-text-muted); }

/* MATCHED (Admin 6862-6866), with the brand mark above it on this portal. */
.page-problem { max-width: 28rem; margin: 3.5rem auto 0; text-align: center; }
.page-problem .empty-state-icon { width: 52px; height: 52px; margin-bottom: 1.1rem; }
.page-problem h1 { font-size: 1.35rem; margin: 0 0 0.4rem; }
.page-problem p { color: var(--vb-text-muted); margin: 0 0 1.25rem; }
.page-problem-actions { display: flex; justify-content: center; gap: 0.6rem; }
.page-problem .mono { display: block; margin-top: -0.6rem; margin-bottom: 1.25rem; font-size: 0.8rem; }

/* MATCHED (Admin 6869-6882, 6943-6945, 7033). */
.skeleton { display: block; border-radius: 6px; background: linear-gradient(90deg, var(--vb-surface-raised) 25%, color-mix(in srgb, var(--vb-border) 60%, var(--vb-surface-raised)) 50%, var(--vb-surface-raised) 75%); background-size: 200% 100%; animation: vb-shimmer 1.4s ease-in-out infinite; height: 0.9rem; }
.skeleton-text { width: 60%; }
.skeleton-title { height: 1.3rem; width: 40%; margin-bottom: 0.7rem; }
.skeleton-row { display: flex; gap: 1rem; padding: 0.7rem 0; border-top: 1px solid var(--vb-border); }
.skeleton-row .skeleton { flex: 1; }
.skeleton-tile { height: 4.5rem; border-radius: var(--vb-radius); }
.skeleton-block { display: block; }
.skeleton-short { flex: 0 0 4rem; }
.skeleton-h1 { height: 1.6rem; width: 14rem; }
.skeleton-lede { width: min(34rem, 100%); margin-top: 0.5rem; }
.skeleton-head { margin-bottom: 1.4rem; }
.skeleton-card { padding-top: 0.5rem; }
@keyframes vb-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

/* MATCHED (Admin 6887-6910, 6948). */
.toast-stack { position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 300; display: grid; gap: 0.5rem; }
.toast { display: flex; align-items: center; gap: 0.6rem; min-width: 16rem; max-width: 24rem; padding: 0.7rem 0.9rem; background: var(--vb-surface-raised); border: 1px solid var(--vb-border-strong); border-left: 3px solid var(--vb-success); border-radius: var(--vb-radius-sm); box-shadow: var(--vb-shadow-2); font-size: 0.9rem; }
.toast .icon { width: 18px; height: 18px; color: var(--vb-success); flex: none; }
.toast-text { flex: 1; }
.toast-text .muted { display: block; font-size: 0.8rem; }
.toast-close { margin-left: 0.25rem; }
.toast-close .icon { width: 14px; height: 14px; color: var(--vb-text-muted); }
.toast-error { border-left-color: var(--vb-danger); }
.toast-error .icon { color: var(--vb-danger); }
.toast[hidden] { display: none; }

/* ------------------------------------------------------------------ Auth layout (NEW) */

.auth-shell { min-height: 100vh; display: flex; flex-direction: column; }
.auth-top { display: flex; align-items: center; justify-content: space-between; padding: 0 1.5rem; min-height: var(--vb-topbar-height); }
.auth-top .brand { font-size: 1rem; }
.auth-main { flex: 1; width: 100%; padding: 2rem 1rem 3rem; }
.auth-page { max-width: 26rem; margin: 1.5rem auto 0; }
.auth-page .brand-mark { width: 44px; height: 44px; border-radius: 11px; margin: 0 auto 1rem; }
.auth-page h1 { font-size: 1.45rem; margin-bottom: 0.35rem; }
.auth-page .lede { margin-bottom: 1.25rem; font-size: 0.95rem; }
.auth-page .card { margin-top: 0; padding: 1.5rem; }
.auth-page .card .alert-error, .auth-page .card .alert-success, .auth-page .card .alert-warning { margin-bottom: 1.1rem; }
.auth-page .form-actions { margin-top: 1.2rem; }
.auth-page .form-footer { text-align: center; }
.auth-page .form-footer a { font-weight: 550; }
.auth-page .form-footer + .form-footer { border-top: none; padding-top: 0; margin-top: 0.5rem; }
/* The way back to vaBase 3, under the sign-in card (product/59 section 8). Quiet on purpose: it is
   a sign for the few people who are in the wrong place, not a second thing to do here. */
.auth-alt { margin-top: 1.25rem; padding: 1.1rem 1.25rem; border: 1px solid var(--vb-border); border-radius: var(--vb-radius); background: var(--vb-bg-soft); text-align: left; }
.auth-alt h2 { font-size: 0.95rem; margin: 0 0 0.35rem; }
.auth-alt p { font-size: 0.86rem; color: var(--vb-text-muted); margin: 0 0 0.9rem; }
.auth-alt .btn { width: 100%; min-height: 44px; }
.auth-state-icon { margin: 0 auto 1rem; }
.auth-page .card-actions { margin-top: 0.9rem; }
.auth-page .card-actions .btn { flex: 1 1 auto; }
.auth-page .field:last-of-type { margin-bottom: 0; }
.auth-page .hint { margin-top: 0.4rem; }
.auth-inline-note { display: flex; align-items: center; gap: 0.5rem; justify-content: center; font-size: 0.88rem; color: var(--vb-text-muted); margin: 0 0 1rem; }
.auth-inline-note .icon { width: 16px; height: 16px; color: var(--vb-success); }
/* A3: "Signed in as ... Sign out" - the sign-out is a POST, so a button styled as the link the board
   draws, spaced from its sentence by CSS (Blazor trims a typed space at an element's edge). */
.form-footer .btn-link { margin-left: 0.3rem; }

/* ------------------------------------------------------------------ Create airline (NEW) */

.create-layout { display: grid; grid-template-columns: minmax(0, 32rem) minmax(0, 1fr); gap: 1.25rem; align-items: start; }
@media (max-width: 900px) { .create-layout { grid-template-columns: minmax(0, 1fr); } }
.create-layout .form-card { max-width: none; margin-top: 0; }
.create-layout .form-actions .btn { width: auto; }
.aside-card h2 { font-size: 0.98rem; }
.steps { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.75rem; counter-reset: step; }
.steps li { display: flex; gap: 0.75rem; font-size: 0.9rem; }
.steps li::before { counter-increment: step; content: counter(step); flex: none; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--vb-primary-soft); color: var(--vb-primary-bright); font-size: 0.78rem; font-weight: 700; border: 1px solid color-mix(in srgb, var(--vb-primary) 45%, var(--vb-border)); }
.steps li > div { flex: 1; min-width: 0; }
.steps li .muted { display: block; font-size: 0.84rem; margin-top: 0.1rem; }
.identifier-line { display: flex; align-items: center; gap: 0.4rem; font-size: 0.82rem; margin-top: 0.4rem; color: var(--vb-text-muted); }
.identifier-line .icon { width: 14px; height: 14px; }
.identifier-line.is-ok { color: var(--vb-success); }
.identifier-line.is-bad { color: var(--vb-danger); }
.field-note { margin-top: 0.55rem; font-size: 0.82rem; color: var(--vb-text-muted); padding: 0.55rem 0.7rem; border: 1px solid var(--vb-border); border-radius: var(--vb-radius-sm); background: var(--vb-bg-soft); }
.field-note strong { color: var(--vb-text); }

/* ------------------------------------------------------------------ Dashboard section rows */
.section-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin: 2.25rem 0 0.75rem; }
.section-row h2 { margin: 0; font-size: 1.05rem; }
.section-row a { font-size: 0.88rem; }
.downloads-pointer { display: flex; align-items: center; gap: 0.9rem; padding: 0.9rem 1.1rem; }
.downloads-pointer .download-icon { width: 36px; height: 36px; }
.downloads-pointer-text { flex: 1; min-width: 0; font-size: 0.9rem; }
.downloads-pointer-text strong { display: block; font-size: 0.95rem; }
.downloads-pointer-text .muted { font-size: 0.85rem; }

/* ------------------------------------------------------------------ Phone */
@media (max-width: 640px) {
    .topbar nav .nav-link { display: none; }
    .user-menu-name { display: none; }
    .user-menu-btn { min-height: 44px; }
    .site-footer-inner { gap: 0.4rem 1rem; }
    .site-footer-copy { margin-left: 0; width: 100%; }
    .page-header-actions .btn { flex: 1 1 auto; }
    .tenant-card-foot { flex-direction: column; align-items: stretch; }
    .tenant-card-foot .btn { width: 100%; }
    .tenant-card-links { justify-content: center; }
    .card-foot .btn { width: 100%; }
    .download-actions .btn { width: 100%; }
    .btn { min-height: 44px; }
}

/* The auth column: the mark, heading and lede are centred; the card's contents read left to right. */
.auth-page h1, .auth-page .lede { text-align: center; }
.auth-page .lede { margin-left: auto; margin-right: auto; }

/* ============================================================================
   The signed-out landing page ("/", product/86; the boards in design/account-landing).

   Rules of the block:
     - Everything hangs off one root, .landing, and every class is prefixed landing-. The signed-in
       portal, the sign-in pages and their shared classes (.btn, .card, .topbar) are untouched.
     - Colours are the portal's own --vb-* tokens. The handful of landing-only values below are
       copied from the public site (src/VaBase.MarketingSite/wwwroot/app.css) so the two read as one
       brand; each is marked PUBLIC SITE. The portals share no stylesheet.
     - The portal's base a and a:hover rules out-rank a single class, so every landing link states
       its colour for rest and hover in one selector list.
   ========================================================================== */

/* ------------------------------------------------------------------- fonts
   The public site's Inter and JetBrains Mono, declared by the landing page's own head from
   fingerprinted addresses (Home.razor), so no other page fetches them. These two fallback faces are
   sized to the same metrics, so the text does not move when the files arrive. */
@font-face { font-family: "Inter Fallback"; src: local("Arial"), local("Helvetica"); size-adjust: 107.12%; ascent-override: 90.44%; descent-override: 22.52%; line-gap-override: 0%; }
@font-face { font-family: "JetBrains Mono Fallback"; src: local("Consolas"), local("Courier New"); size-adjust: 109%; ascent-override: 93.58%; descent-override: 27.52%; line-gap-override: 0%; }

/* -------------------------------------------------------------------- root */
.landing {
  /* PUBLIC SITE values the portal has no token for. */
  --landing-text-2: #b4b6bc;
  --landing-night: #07080a;
  --landing-on-brand: #f7f3fd;
  --landing-font: "Inter", "Inter Fallback", "Segoe UI", system-ui, sans-serif;
  --landing-mono: "JetBrains Mono", "JetBrains Mono Fallback", "Cascadia Mono", Consolas, monospace;
  --landing-container: 1200px;
  --landing-wide: 1360px;
  --landing-header: 68px;
  --landing-radius-lg: 18px;
  --landing-shadow-frame: 0 30px 80px rgba(0, 0, 0, 0.55), 0 2px 0 rgba(255, 255, 255, 0.03) inset;
  --landing-shadow-float: 0 28px 70px rgba(0, 0, 0, 0.66), 0 0 0 1px rgba(255, 255, 255, 0.04);
  /* Tighter than the public site's sections: this page is a front door, not a tour. */
  --landing-space: clamp(52px, 5.8vw, 86px);
  --landing-panel: var(--vb-surface);

  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  overflow-x: clip;
  background: var(--vb-bg);
  color: var(--vb-text);
  font-family: var(--landing-font);
  font-size: 17px;
  line-height: 1.6;
  font-feature-settings: "cv11", "ss01";
}
.landing-main { flex: 1 0 auto; }
.landing h1, .landing h2, .landing h3 { margin: 0; font-weight: 600; line-height: 1.1; letter-spacing: -0.022em; color: var(--vb-text); text-wrap: balance; }
.landing h1 { font-size: clamp(2.4rem, 3.9vw, 3.4rem); letter-spacing: -0.035em; line-height: 1.04; }
.landing h2 { font-size: clamp(1.8rem, 3vw, 2.55rem); letter-spacing: -0.03em; }
.landing h3 { font-size: 1.3rem; letter-spacing: -0.015em; }
.landing p { margin: 0; }
.landing ul, .landing ol { margin: 0; padding: 0; list-style: none; }
.landing img, .landing svg { display: block; max-width: 100%; }
.landing :focus-visible { outline: 2px solid var(--vb-primary-bright); outline-offset: 3px; border-radius: 6px; }
/* FocusOnNavigate focuses the h1 on arrival, for screen readers; it is not a control, so it keeps
   the portal's "h1:focus { outline: none }", which the rule above would otherwise out-rank. */
.landing h1:focus { outline: none; }
@media (prefers-reduced-motion: reduce) {
  .landing *, .landing *::before, .landing *::after { transition: none !important; animation: none !important; }
}

/* ------------------------------------------------------------------ layout */
.landing-container { width: min(var(--landing-container), 100% - 48px); margin-inline: auto; }
.landing-wide { width: min(var(--landing-wide), 100% - 48px); margin-inline: auto; }
.landing-section { position: relative; padding-block: var(--landing-space); }
.landing-tone-soft { --landing-panel: #1b1c21; background: var(--vb-bg-soft); border-block: 1px solid var(--vb-border); }
.landing-tone-night { background: var(--landing-night); border-top: 1px solid #1f2026; }
.landing-kicker { display: inline-flex; align-items: center; gap: 10px; font-family: var(--landing-mono); font-feature-settings: normal; font-size: 12.5px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; color: var(--vb-primary-bright); }
.landing-kicker::before { content: ""; width: 22px; height: 1px; background: currentColor; opacity: 0.7; }
.landing-lede { font-size: clamp(1.06rem, 1.4vw, 1.2rem); line-height: 1.55; color: var(--landing-text-2); max-width: 56ch; }
.landing-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.landing-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 16px 32px; margin-bottom: 36px; }
.landing-head-text { display: grid; gap: 14px; max-width: 720px; }

/* ----------------------------------------------------------------- buttons
   PUBLIC SITE metrics, so the same button carries a visitor from one site to the other. */
.landing-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 46px; padding: 0 20px; border: 1px solid transparent; border-radius: 10px; font-weight: 600; font-size: 15.5px; letter-spacing: -0.005em; white-space: nowrap; transition: background-color 0.15s, border-color 0.15s, color 0.15s; }
.landing-btn svg { width: 18px; height: 18px; transition: transform 0.15s; }
.landing-btn:hover svg { transform: translateX(2px); }
.landing-btn-primary, .landing-btn-primary:hover { background: var(--vb-primary); color: var(--landing-on-brand); }
.landing-btn-primary:hover { background: var(--vb-primary-hover); }
.landing-btn-secondary, .landing-btn-secondary:hover { background: transparent; color: var(--vb-text); border-color: var(--vb-border-strong); }
.landing-btn-secondary:hover { border-color: var(--vb-text-muted); background: rgba(127, 127, 140, 0.08); }
.landing-btn-lg { min-height: 54px; padding: 0 26px; border-radius: 12px; font-size: 16.5px; }
.landing-btn-sm { min-height: 38px; padding: 0 14px; font-size: 14px; }
.landing-textlink { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; font-size: 15.5px; color: var(--vb-primary-bright); }
.landing-textlink:hover { color: var(--vb-primary-brighter); }
.landing-textlink svg { width: 15px; height: 15px; transition: transform 0.15s; }
.landing-textlink:hover svg { transform: translate(1px, -1px); }

/* --------------------------------------------------------------- tap areas
   Every link and button answers a tap anywhere in an area at least 44 by 44px. The large buttons
   and the header's Sign in are drawn that size. The compact controls (landing-tap) keep their drawn
   size and carry an empty layer centred on themselves instead, so the target grows and the look
   does not. Rows of compact controls sit 44px apart (the footer links), so neighbouring areas meet
   without overlapping. */
.landing-tap { position: relative; }
.landing-tap::after { content: ""; position: absolute; inset: min(0px, calc(50% - 22px)); }

/* ------------------------------------------------------------------ header
   The public site's bar with the portal's three destinations. Sign in is a text link at every
   width: a returning owner finds it without scrolling or opening a menu. */
.landing-header { position: sticky; top: 0; z-index: 50; background: color-mix(in srgb, var(--vb-bg) 82%, transparent); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); border-bottom: 1px solid var(--vb-border); }
.landing-header-row { display: flex; align-items: center; gap: 20px; height: var(--landing-header); }
.landing-brand, .landing-brand:hover { display: inline-flex; align-items: center; gap: 10px; color: var(--vb-text); font-weight: 650; font-size: 19px; letter-spacing: -0.02em; }
.landing-brand .brand-mark { width: 30px; height: 30px; border-radius: 8px; flex: none; }
.landing-brand-sub { margin-left: 2px; padding-left: 12px; border-left: 1px solid var(--vb-border-strong); color: var(--vb-text-muted); font-weight: 500; font-size: 14px; letter-spacing: 0; line-height: 1.3; }
.landing-header-actions { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.landing-header-link { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 8px 12px; border-radius: 8px; color: var(--landing-text-2); font-weight: 500; font-size: 15px; transition: background-color 0.15s, color 0.15s; }
.landing-header-link:hover { color: var(--vb-text); background: rgba(127, 127, 140, 0.1); }
.landing-header-link svg { width: 14px; height: 14px; opacity: 0.8; }
.landing-header-quiet { color: var(--vb-text-muted); font-size: 14px; }
.landing-header-actions .landing-btn { margin-left: 8px; }

/* ------------------------------------------------------------------ frames
   PUBLIC SITE device frames (DeviceFrame.razor there), copied with matching metrics: a browser, the
   ACARS window and a phone, drawn in CSS around a screenshot. The image fills the frame from its
   top left, so a frame of any shape shows the start of the real screen. */
.landing-frame { position: relative; display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--vb-border-strong); border-radius: var(--vb-radius); background: #0c0d0f; box-shadow: var(--landing-shadow-frame); }
.landing-frame-bar { flex: none; height: 34px; display: flex; align-items: center; gap: 7px; padding: 0 13px; background: #15161a; border-bottom: 1px solid #26272d; }
.landing-frame-bar i { display: block; width: 9px; height: 9px; border-radius: 50%; background: #2c2d34; }
.landing-frame-url { flex: 0 1 300px; min-width: 0; height: 20px; margin-left: 10px; padding: 0 10px; border-radius: 6px; background: #1e1f25; color: #8a8d95; font-family: var(--landing-mono); font-feature-settings: normal; font-size: 11px; line-height: 20px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.landing-frame-titlebar { flex: none; height: 30px; display: flex; align-items: center; gap: 8px; padding: 0 11px; background: #101114; border-bottom: 1px solid #1f2026; color: var(--vb-text-muted); font-size: 12px; line-height: 1; }
.landing-frame-titlebar .brand-mark { width: 15px; height: 15px; border-radius: 4px; flex: none; }
.landing-frame-win { margin-left: auto; display: flex; gap: 14px; opacity: 0.6; }
.landing-frame-win svg { width: 10px; height: 10px; }
.landing-frame-body { position: relative; flex: 1 1 auto; min-height: 0; overflow: hidden; }
.landing-frame-body img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; object-position: top left; }
.landing-frame-phone { border: 7px solid #1c1d22; border-radius: 30px; }
.landing-frame-notch { flex: none; height: 20px; display: grid; place-items: center; background: #0c0d0f; }
.landing-frame-notch i { display: block; width: 58px; height: 5px; border-radius: 3px; background: #26272d; }

/* -------------------------------------------------------------------- hero
   Copy on the left, the product on the right, both inside the first screen at 1440 by 900.

   The stage is one composition of three real screens: the Admin Portal dashboard is the backdrop
   and runs off the right edge of the window (always by the same share of the stage, so it reads as
   a screen that continues, never as a frame that almost fits); the pilot website and the ACARS
   window float over its lower half. A single brand glow sits behind it (the public site's hero
   glow), and the Admin frame darkens toward its foot so the two floating screens lift off it. */
.landing-hero { position: relative; overflow: hidden; padding-block: clamp(40px, 4.6vw, 68px) clamp(52px, 5.6vw, 84px); }
.landing-hero-bg { position: absolute; inset: 0; pointer-events: none; }
.landing-hero-bg svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.landing-hero-grid { position: relative; display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(32px, 4vw, 64px); align-items: center; }
.landing-hero-copy { display: grid; gap: 22px; justify-items: start; }
.landing-hero-copy h1 span { display: block; }
.landing-hero-copy .landing-actions { margin-top: 6px; }
.landing-hero-note { max-width: 46ch; font-size: 14px; line-height: 1.5; color: var(--vb-text-muted); }
.landing-stage { position: relative; height: clamp(440px, 40vw, 580px); margin-right: calc((100vw - min(var(--landing-wide), 100vw - 48px)) / -2); }
.landing-stage .landing-frame-admin { position: absolute; left: 9%; top: 0; width: 112%; height: 86%; }
.landing-stage .landing-frame-admin::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to bottom, transparent 42%, rgba(7, 8, 10, 0.62)); }
.landing-stage .landing-frame-site { position: absolute; left: 0; bottom: 0; width: 50%; aspect-ratio: 16 / 11.2; z-index: 2; box-shadow: var(--landing-shadow-float); }
.landing-stage .landing-frame-acars { position: absolute; right: 5%; bottom: 6%; width: 36%; aspect-ratio: 16 / 11.4; z-index: 3; box-shadow: var(--landing-shadow-float); }
.landing-stage .landing-frame-phone { display: none; }

/* -------------------------------------------------------- platform highlights
   Four panels in an uneven grid (7 and 5, then 5 and 7). Each leads with a real screen that runs
   off the panel's lower right corner; the fourth is a small diagram of what runs where, because
   that is a fact no screenshot shows. */
.landing-bento { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 20px; }
.landing-panel { position: relative; grid-column: span 5; display: flex; flex-direction: column; min-height: 420px; overflow: hidden; border: 1px solid var(--vb-border); border-radius: var(--landing-radius-lg); background: var(--landing-panel); transition: border-color 0.2s; }
.landing-panel:hover { border-color: var(--vb-border-strong); }
.landing-panel-wide { grid-column: span 7; }
.landing-panel-short { min-height: 350px; }
.landing-panel-text { display: grid; gap: 10px; align-content: start; padding: 28px 28px 0; }
.landing-label { font-family: var(--landing-mono); font-feature-settings: normal; font-size: 12px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; color: var(--vb-primary-bright); }
.landing-panel-text p { max-width: 48ch; font-size: 15.5px; line-height: 1.55; color: var(--landing-text-2); }
.landing-caps { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 6px; }
.landing-caps li { display: inline-flex; align-items: center; gap: 8px; font-family: var(--landing-mono); font-feature-settings: normal; font-size: 11.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--vb-text-muted); }
.landing-caps li::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--vb-primary-bright); opacity: 0.8; }
.landing-panel-media { position: relative; flex: 1 1 auto; min-height: 190px; margin: 26px 0 0 28px; }
.landing-panel-media .landing-frame { position: absolute; left: 0; top: 0; right: -1px; bottom: -8px; border-radius: var(--vb-radius) 0 0 0; box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.35); transition: transform 0.25s ease; }
.landing-panel:hover .landing-panel-media .landing-frame { transform: translateY(-5px); }
/* A zoomed screen: the image is laid out at the frame's width, then enlarged from its top left and
   moved, so a small frame shows a legible part of the screen rather than all of it in miniature. */
.landing-zoom img { inset: auto; left: 0; top: 0; width: 100%; height: auto; object-fit: fill; transform-origin: 0 0; }
.landing-shot-pireps img { transform: translateY(-21%); }
/* ACARS, a flight in the climb. The file itself is already cut to the route card, the phase line and
   the instrument tiles; the hero's smaller window enlarges it so the figures stay legible. */
.landing-shot-live-hero img { transform: scale(1.41); }

.landing-panel-split { flex-direction: row; align-items: stretch; }
.landing-panel-split .landing-panel-text { flex: 0 0 47%; padding-bottom: 28px; }
.landing-diagram { flex: 1 1 auto; display: grid; grid-template-columns: 1fr 1fr; gap: 30px 14px; align-content: center; padding: 28px 28px 28px 8px; }
.landing-node { position: relative; display: grid; gap: 3px; padding: 13px 15px; border: 1px solid var(--vb-border-strong); border-radius: 10px; background: var(--vb-bg); }
.landing-node::after { content: ""; position: absolute; left: 50%; top: 100%; height: 31px; border-left: 1px dashed #5a5d68; }
.landing-node-name { font-weight: 600; font-size: 14.5px; letter-spacing: -0.01em; line-height: 1.3; }
.landing-node-meta { font-size: 13px; line-height: 1.35; color: var(--vb-text-muted); }
.landing-node-hub { grid-column: 1 / -1; grid-template-columns: 1fr auto; align-items: center; gap: 3px 14px; border-color: rgba(168, 131, 255, 0.55); background: var(--vb-primary-soft); }
.landing-node-hub::after { display: none; }
.landing-node-hub .landing-node-meta { grid-column: 1; color: var(--landing-text-2); }
/* The airline's own applications sit under the platform: they are not vaBase software, they sign the
   airline's owners and staff in through it. The connector rises from this node to the platform. */
.landing-node-app { grid-column: 1 / -1; grid-template-columns: 1fr auto; align-items: center; gap: 3px 14px; }
.landing-node-app::after { top: auto; bottom: 100%; }
.landing-node-app .landing-node-meta { grid-column: 1; }
.landing-node-tag { grid-column: 2; grid-row: 1 / span 2; font-family: var(--landing-mono); font-feature-settings: normal; font-size: 11.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--vb-text-muted); white-space: nowrap; }
.landing-pill-live { grid-column: 2; grid-row: 1 / span 2; display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px; border: 1px solid var(--vb-border-strong); border-radius: 999px; background: var(--vb-bg); font-size: 13px; color: var(--landing-text-2); white-space: nowrap; }
.landing-pill-live::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--vb-success); box-shadow: 0 0 0 3px rgba(62, 194, 125, 0.18); }

/* --------------------------------------------------------- getting started
   The four steps as one numbered line beside the screen that proves the third: the Downloads page,
   cropped to its two cards, with the package's own config file showing what arrives filled in. */
.landing-start { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: clamp(32px, 5vw, 76px); align-items: center; }
.landing-steps { display: grid; margin-top: 36px; }
.landing-steps li { position: relative; display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 16px; padding-bottom: 22px; }
.landing-steps li:last-child { padding-bottom: 0; }
.landing-steps li::before { content: ""; position: absolute; left: 21.5px; top: 34px; bottom: 0; width: 1px; background: var(--vb-border-strong); }
.landing-steps li:last-child::before { display: none; }
.landing-step-n { display: grid; place-items: center; width: 44px; height: 30px; border: 1px solid var(--vb-border-strong); border-radius: 8px; background: var(--vb-surface); font-family: var(--landing-mono); font-feature-settings: normal; font-size: 12.5px; letter-spacing: 0.08em; color: var(--vb-primary-bright); }
.landing-steps h3 { font-size: 17px; line-height: 30px; }
.landing-steps p { margin-top: 2px; font-size: 15px; line-height: 1.5; color: var(--landing-text-2); max-width: 44ch; }
.landing-start-media { position: relative; padding: 0 0 104px 34px; }
.landing-start-media .landing-frame-body { aspect-ratio: 1032 / 690; flex: none; }
.landing-shot-downloads img { transform: scale(1.2) translate(-7.6%, -21.4%); }
.landing-config { position: absolute; left: 0; bottom: 0; z-index: 2; width: min(372px, 84%); display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; padding: 14px 16px 15px; border: 1px solid var(--vb-border-strong); border-radius: var(--vb-radius); background: #0c0d0f; box-shadow: var(--landing-shadow-float); }
.landing-config-file { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 2px 12px; font-family: var(--landing-mono); font-feature-settings: normal; font-size: 11.5px; letter-spacing: 0.04em; color: var(--vb-text-muted); white-space: nowrap; }
.landing-config-file b { font-weight: 500; color: var(--vb-success); letter-spacing: 0.02em; }
.landing-config pre { margin: 0; font-family: var(--landing-mono); font-feature-settings: normal; font-size: 12.5px; line-height: 1.7; color: #b4b6bc; white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.landing-config .k { color: #a883ff; }
.landing-config .s { color: #3ec27d; }

/* --------------------------------------------------- closing band and footer */
.landing-cta { text-align: center; overflow: hidden; }
.landing-cta-bg { position: absolute; inset: 0; pointer-events: none; }
.landing-cta-bg svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.landing-cta-inner { position: relative; display: grid; gap: 16px; justify-items: center; }
.landing-cta h2 { font-size: clamp(2rem, 3.6vw, 3rem); }
.landing-cta .landing-actions { justify-content: center; margin-top: 12px; }
.landing-cta-support { font-size: 15px; color: var(--vb-text-muted); }
.landing-cta-support a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.landing-footer { padding: 26px 0 30px; border-top: 1px solid var(--vb-border); background: var(--vb-bg); color: var(--vb-text-muted); font-size: 14px; }
.landing-footer-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 24px; }
.landing-footer-brand { display: inline-flex; align-items: center; gap: 10px; }
.landing-footer-brand .brand-mark { width: 22px; height: 22px; border-radius: 6px; }
.landing-footer-links { margin-left: auto; display: flex; flex-wrap: wrap; gap: 12px 22px; }
.landing-footer-links a { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; color: var(--landing-text-2); transition: color 0.15s; }
.landing-footer-links a:hover { color: var(--vb-text); }
.landing-footer-links svg { width: 14px; height: 14px; opacity: 0.8; }
.landing-footer-legal { flex-basis: 100%; font-size: 13px; }

/* -------------------------------------------------------------- responsive
   Three compositions, each drawn for its width rather than scaled from the widest.
     Above 1000: the split hero with the Admin frame running off the window.
     641 to 1000: copy above; the same three screens, contained, as one wide stage.
     640 and below: the Admin frame is enlarged and runs off the right edge so its figures stay
       legible, and the pilot website moves into a phone, because that is where a pilot meets it.
       ACARS is a desktop program and leaves the phone hero; it keeps its own panel below. */
@media (max-width: 1000px) {
  .landing-hero-grid, .landing-start { grid-template-columns: minmax(0, 1fr); }
  .landing-hero-copy { max-width: 640px; }
  .landing-stage { height: clamp(360px, 58vw, 500px); margin-right: 0; margin-top: 8px; }
  .landing-stage .landing-frame-admin { left: 10%; width: 90%; }
  .landing-stage .landing-frame-site { width: 48%; }
  .landing-stage .landing-frame-acars { right: 0; bottom: 7%; width: 37%; }
  .landing-header-quiet { display: none; }
  .landing-panel { grid-column: span 6; }
  .landing-panel-wide { grid-column: 1 / -1; }
  .landing-panel-wide:first-child { min-height: 440px; }
  .landing-start-media { max-width: 640px; }
  .landing-panel-short { min-height: 0; }
  .landing-panel-split { align-items: center; }
}
@media (max-width: 640px) {
  .landing { font-size: 16px; }
  .landing h1 { font-size: 2.3rem; }
  .landing h2 { font-size: 1.7rem; }
  .landing-container, .landing-wide { width: calc(100% - 32px); }
  .landing-header-row { gap: 10px; }
  .landing-header-link { padding-inline: 10px; }
  .landing-header-actions .landing-btn { margin-left: 4px; }
  .landing-hero { padding-top: 32px; padding-bottom: 0; }
  .landing-hero-copy { gap: 18px; }
  .landing-hero-copy .landing-actions { width: 100%; flex-wrap: nowrap; }
  .landing-hero-copy .landing-btn { padding-inline: 18px; }
  .landing-hero-copy .landing-btn-primary { flex: 1 1 auto; }
  .landing-stage { height: 318px; margin: 14px -16px 0 0; }
  .landing-stage .landing-frame-admin { left: 0; width: 150%; height: 100%; border-bottom: 0; border-radius: var(--vb-radius) 0 0 0; }
  .landing-stage .landing-frame-site, .landing-stage .landing-frame-acars { display: none; }
  .landing-stage .landing-frame-phone { display: flex; position: absolute; right: 8%; bottom: -34px; width: 40%; aspect-ratio: 9 / 17.4; z-index: 3; box-shadow: var(--landing-shadow-float); }
  .landing-head { margin-bottom: 26px; }
  .landing-bento { gap: 14px; }
  .landing-panel, .landing-panel-wide { grid-column: 1 / -1; min-height: 0; }
  .landing-panel-wide:first-child { min-height: 0; }
  .landing-panel-text { padding: 22px 20px 0; }
  .landing-panel-media { flex: none; height: 200px; margin: 22px 0 0 20px; }
  .landing-panel-split { flex-direction: column; }
  .landing-panel-split .landing-panel-text { flex: none; padding-bottom: 0; }
  .landing-diagram { padding: 22px 20px 22px; gap: 30px 10px; }
  .landing-node { padding: 11px 12px; }
  .landing-node-hub, .landing-node-app { grid-template-columns: 1fr; }
  .landing-node-tag { grid-column: 1; grid-row: auto; margin-top: 4px; }
  .landing-pill-live { grid-column: 1; grid-row: auto; justify-self: start; margin-top: 6px; }
  .landing-start-media { padding: 0; }
  .landing-start-media .landing-frame-body { aspect-ratio: 358 / 232; }
  .landing-shot-downloads img { transform: scale(1.7) translate(-7.6%, -48.5%); }
  .landing-shot-pireps img { transform: scale(1.75) translateY(-21%); }
  .landing-panel-split { align-items: stretch; }
  .landing-config { position: relative; width: auto; margin: -34px 12px 0; }
  .landing-config-file { column-gap: 8px; }
  .landing-cta { text-align: left; }
  .landing-cta-inner { justify-items: start; }
  .landing-cta .landing-actions { justify-content: flex-start; width: 100%; }
  .landing-cta .landing-btn-primary { flex: 1 1 auto; }
  .landing-footer-links { margin-left: 0; flex-basis: 100%; }
}
/* The header drops parts of the brand as its row narrows, so Sign in and Create account always
   sit on one line at their drawn sizes: "Account Portal" below a 449px row, and the name below 328px
   (the brand is then its mark alone and keeps its name for screen readers). The row itself is
   measured, not the window, because a desktop scrollbar takes width that media queries still
   count; each threshold leaves a few pixels spare for differences in text rendering. */
.landing-header-row { container: landing-header / inline-size; }
@container landing-header (max-width: 448.98px) {
  .landing-brand-sub { display: none; }
}
@container landing-header (max-width: 327.98px) {
  .landing-brand-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
}

/* --------------------------------------------------------------------------
   Connection lost (Components/Shared/ReconnectModal.razor)
   --------------------------------------------------------------------------
   Blazor drives this dialog by putting ONE state class on #components-reconnect-modal; which
   wording shows is decided here and nowhere else, so the dialog is right with no script at all.

   ⚠️ THIS BLOCK IS BYTE-IDENTICAL IN BOTH PORTALS' app.css (PortalReconnectModalTests), with
   the component and js/reconnect-modal.js. Change all three pairs together.

   Hidden until Blazor says otherwise: with no state class the element is not on screen. Above
   every other layer (.modal-backdrop is 100) - a dialog open when the connection drops is as
   unusable as the page under it. */
.reconnect-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1000;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(6, 7, 8, 0.62);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
}
.reconnect-backdrop.components-reconnect-show,
.reconnect-backdrop.components-reconnect-paused,
.reconnect-backdrop.components-reconnect-failed,
.reconnect-backdrop.components-reconnect-rejected,
.reconnect-backdrop.components-reconnect-resume-failed { display: flex; }

.reconnect-card {
    width: 100%;
    max-width: 25rem;
    padding: 1.9rem 1.75rem 1.6rem;
    text-align: center;
    background: var(--vb-surface);
    border: 1px solid var(--vb-border-strong);
    border-radius: var(--vb-radius);
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.55);
    outline: none;
}

/* One state's wording at a time. -retrying is ADDED to -show rather than replacing it, and a
   failed resume needs the same reload a rejected reconnect does. */
.reconnect-state { display: none; }
.components-reconnect-show .reconnect-state-retrying,
.components-reconnect-paused .reconnect-state-paused,
.components-reconnect-failed .reconnect-state-failed,
.components-reconnect-rejected .reconnect-state-rejected,
.components-reconnect-resume-failed .reconnect-state-rejected { display: block; }

.reconnect-title {
    margin: 0 0 0.5rem;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--vb-text);
}
.reconnect-text {
    margin: 0;
    font-size: 0.92rem;
    line-height: 1.55;
    color: var(--vb-text-muted);
}
/* The first attempts are back to back and need no counter; Blazor adds -retrying once it starts
   WAITING between them. The line keeps its space either way so the card does not jump. */
.reconnect-attempt {
    visibility: hidden;
    margin: 1rem 0 0;
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    color: var(--vb-text-muted);
}
.components-reconnect-retrying .reconnect-attempt { visibility: visible; }

.reconnect-actions {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 1.4rem;
}
.reconnect-actions .btn:disabled { opacity: 0.55; cursor: default; }

/* The beacon: a dot calling out, two rings carrying the call. It pulses only while something
   is actually being tried; a settled state holds still and takes that state's colour. */
.reconnect-beacon {
    position: relative;
    width: 3.5rem;
    height: 3.5rem;
    margin: 0 auto 1.15rem;
    color: var(--vb-text-muted);
}
.reconnect-beacon i,
.reconnect-beacon span {
    position: absolute;
    inset: 0;
    margin: auto;
    border-radius: 50%;
}
.reconnect-beacon i {
    width: 0.8rem;
    height: 0.8rem;
    background: currentColor;
    box-shadow: 0 0 0 0.4rem color-mix(in srgb, currentColor 16%, transparent);
}
.reconnect-beacon span {
    border: 2px solid currentColor;
    opacity: 0;
}
/* At rest the first ring stays, drawn in: a lone dot reads as a stray pixel, not a signal. */
.reconnect-beacon span:first-child { opacity: 0.3; transform: scale(0.62); }
.components-reconnect-show .reconnect-beacon,
.reconnect-busy .reconnect-beacon { color: var(--vb-primary-bright); }
.components-reconnect-failed:not(.reconnect-busy) .reconnect-beacon { color: var(--vb-warning); }

@keyframes reconnect-ring {
    0% { transform: scale(0.3); opacity: 0.85; }
    100% { transform: scale(1); opacity: 0; }
}
@keyframes reconnect-arrive {
    from { opacity: 0; }
    to { opacity: 1; }
}
@media (prefers-reduced-motion: no-preference) {
    .components-reconnect-show .reconnect-beacon span,
    .reconnect-busy .reconnect-beacon span { animation: reconnect-ring 2s cubic-bezier(0.2, 0.6, 0.35, 1) infinite; }
    .components-reconnect-show .reconnect-beacon span + span,
    .reconnect-busy .reconnect-beacon span + span { animation-delay: 1s; }

    /* A connection that blinks for a moment is usually back before anyone could read this, so
       the FIRST state waits before fading in. The others are answers to a wait already had. */
    .reconnect-backdrop.components-reconnect-show { animation: reconnect-arrive 0.25s ease-out 0.4s both; }
}
/* end: connection lost */

/* ==== Two-factor sign-in (product/84 sections 5 and 6, the approved design/two-factor boards) ====
   MATCHED rules copy an Admin Portal primitive with the same metrics, because the two portals have
   separate stylesheets. Nothing here restyles a class this portal already shipped. */
/* ---- MATCHED primitives -------------------------------------------------------------------- */
/* MATCHED (Admin .row-sub): the quiet second line in a table cell. */
.row-sub { display: block; font-size: 0.8rem; color: var(--vb-text-muted); }
/* MATCHED (Admin .btn-danger, .btn-danger-solid): a destructive action, outlined or filled. */
.btn-danger { color: var(--vb-danger); border-color: color-mix(in srgb, var(--vb-danger) 50%, transparent); background: transparent; }
.btn-danger:hover { background: var(--vb-danger-soft); color: var(--vb-danger); border-color: var(--vb-danger); }
.btn-danger-solid { background: var(--vb-danger); border-color: var(--vb-danger); color: #fff; font-weight: 600; }
.btn-danger-solid:hover { background: #ee6f7b; border-color: #ee6f7b; color: #fff; }
/* MATCHED (Admin .alert-note): a standing consequence, quieter than a warning. */
.alert-note { background: var(--vb-bg-soft); border: 1px solid var(--vb-border); border-radius: var(--vb-radius-sm); color: var(--vb-text-muted); padding: 0.6rem 0.85rem; margin: 0.75rem 0 0; font-size: 0.9rem; }
.alert-note strong { color: var(--vb-text); }
/* MATCHED (Admin .alert-info): information, neither good nor bad news. */
.alert-info { background: color-mix(in srgb, var(--vb-primary) 12%, transparent); border: 1px solid color-mix(in srgb, var(--vb-primary) 45%, transparent); border-radius: var(--vb-radius-sm); color: var(--vb-text); padding: 0.65rem 0.9rem; margin: 0 0 1.1rem; font-size: 0.9rem; }
/* MATCHED (Admin .input-uppercase): code-like values (references) read in capitals. */
.input-uppercase { text-transform: uppercase; }
/* MATCHED (Admin .modal-wide and the dialog heading). */
.modal-wide { max-width: 42rem; }
.modal h2 { display: flex; align-items: center; gap: 0.5rem; }
/* MATCHED (Admin table.data.data-cards): on a phone a table becomes one card per row. */
@media (max-width: 640px) {
    table.data.data-cards thead { display: none; }
    table.data.data-cards, table.data.data-cards tbody { display: block; }
    table.data.data-cards tr { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.7rem; padding: 0.85rem 1rem; border-top: 1px solid var(--vb-border); }
    table.data.data-cards tr:first-child { border-top: none; }
    table.data.data-cards td { display: block; padding: 0; border: none; background: none; font-size: 0.85rem; color: var(--vb-text-muted); white-space: normal; }
    table.data.data-cards td:first-child { flex: 1 1 60%; min-width: 0; font-size: 0.95rem; color: var(--vb-text); }
}

/* ---- NEW: the two-factor state line ------------------------------------------------------------
   The pill and its sentence side by side; the gap spaces them, never a typed space. */
.tf-state { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.7rem; margin: 0 0 0.9rem; }
.tf-state p { margin: 0; color: var(--vb-text-muted); font-size: 0.9rem; flex: 1 1 18rem; min-width: 0; }
.tf-card .card-actions { margin-top: 1rem; }
.tf-card .facts { margin-top: 0.2rem; }
@media (max-width: 640px) { .tf-card .card-actions .btn { flex: 1 1 100%; justify-content: center; } }
.tf-apps { font-size: 0.82rem; color: var(--vb-text-muted); margin: 0.9rem 0 0; }

/* ---- NEW: set-up, inside the auth column -------------------------------------------------------
   Three steps shown as three short bars, the current one in the brand colour. */
.tf-steps { list-style: none; display: flex; gap: 0.45rem; margin: 0 0 1.15rem; padding: 0; font-size: 0.76rem; color: var(--vb-text-muted); }
.tf-steps li { flex: 1 1 0; display: flex; flex-direction: column; gap: 0.35rem; min-width: 0; }
.tf-steps li::before { content: ""; height: 3px; border-radius: 2px; background: var(--vb-border-strong); }
.tf-steps li.is-done::before { background: color-mix(in srgb, var(--vb-primary-bright) 55%, var(--vb-border-strong)); }
.tf-steps li[aria-current="step"] { color: var(--vb-text); font-weight: 600; }
.tf-steps li[aria-current="step"]::before { background: var(--vb-primary-bright); }
.tf-lead { margin: 0 0 0.9rem; font-size: 0.92rem; }
/* The QR code sits on white, whatever the theme: scanners need the light quiet zone. */
.tf-qr { display: block; width: 184px; height: 184px; margin: 0.2rem auto 1rem; padding: 10px; background: #fff; border-radius: var(--vb-radius-sm); }
.tf-qr svg { display: block; width: 100%; height: 100%; }
details.tf-manual { margin: 0 0 0.2rem; border-top: 1px solid var(--vb-border); padding-top: 0.8rem; }
details.tf-manual summary { cursor: pointer; font-size: 0.88rem; font-weight: 600; color: var(--vb-primary-bright); list-style: none; text-align: center; }
details.tf-manual summary::-webkit-details-marker { display: none; }
details.tf-manual[open] summary { margin-bottom: 0.7rem; }
details.tf-manual p { font-size: 0.85rem; color: var(--vb-text-muted); margin: 0 0 0.6rem; }
/* The key as text: grouped in fours, selectable, with its copy button beside it. */
.tf-key { display: flex; align-items: center; gap: 0.5rem; padding: 0.55rem 0.5rem 0.55rem 0.8rem; background: var(--vb-bg-soft); border: 1px dashed var(--vb-border-strong); border-radius: var(--vb-radius-sm); }
.tf-key .mono { flex: 1; min-width: 0; font-size: 0.95rem; letter-spacing: 0.05em; word-spacing: 0.3em; overflow-wrap: anywhere; color: var(--vb-text); user-select: all; }
.tf-key-facts { margin-top: 0.7rem; }
.tf-key-facts.facts { grid-template-columns: 6.5rem minmax(0, 1fr); font-size: 0.82rem; }
/* The 6-digit code: large, spaced, centred, so a misread digit is easy to see. */
.field input.otp-input { font-family: var(--vb-mono); font-size: 1.55rem; letter-spacing: 0.42em; text-align: center; padding: 0.45rem 0.5rem 0.45rem 0.92rem; }
.field input.recovery-input { font-family: var(--vb-mono); font-size: 1.15rem; letter-spacing: 0.12em; text-align: center; text-transform: uppercase; }
/* A link-styled button standing alone on its own line under a form (switching the code type). */
.tf-switch { text-align: center; margin: 0.9rem 0 0; font-size: 0.88rem; }

/* ---- NEW: the recovery codes, shown once ----------------------------------------------------- */
.tf-codes { list-style: none; counter-reset: tf-code; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.45rem 1rem; margin: 0 0 0.75rem; padding: 0.9rem 1rem; background: var(--vb-bg-soft); border: 1px solid var(--vb-border); border-radius: var(--vb-radius-sm); }
.tf-codes li { counter-increment: tf-code; display: flex; align-items: baseline; gap: 0.55rem; font-family: var(--vb-mono); font-size: 0.98rem; letter-spacing: 0.04em; white-space: nowrap; }
.tf-codes li::before { content: counter(tf-code); width: 1.1rem; text-align: right; font-size: 0.72rem; color: var(--vb-text-muted); }
.tf-codes-actions { display: flex; gap: 0.6rem; margin: 0 0 1rem; }
.tf-codes-actions .btn { flex: 1 1 0; justify-content: center; }
.tf-check { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.9rem; margin: 0; cursor: pointer; }
.tf-check input { margin: 0.2rem 0 0; flex: none; width: 1rem; height: 1rem; accent-color: var(--vb-primary); }
@media (max-width: 360px) { .tf-codes { grid-template-columns: minmax(0, 1fr); } }

/* ---- NEW: Security › Recent sign-ins ----------------------------------------------------------- */
.tf-signins td .badge { margin: 0; }
.tf-result { display: flex; flex-wrap: wrap; align-items: center; gap: 0.2rem 0.55rem; }
.tf-result .row-sub { flex-basis: 100%; }
.tf-where { white-space: nowrap; }

/* ---- NEW: a reset request's progress, for the person and the operator ----------------------- */
.tf-timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.tf-timeline li { position: relative; display: grid; grid-template-columns: 1.6rem minmax(0, 1fr); gap: 0.7rem; padding: 0 0 1rem; font-size: 0.9rem; }
.tf-timeline li:last-child { padding-bottom: 0; }
.tf-timeline li::after { content: ""; position: absolute; left: calc(0.8rem - 1px); top: 1.7rem; bottom: 0.2rem; width: 2px; background: var(--vb-border); }
.tf-timeline li:last-child::after { display: none; }
.tf-dot { width: 1.6rem; height: 1.6rem; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; border: 2px solid var(--vb-border-strong); color: var(--vb-text-muted); background: var(--vb-surface); }
.tf-dot .icon { width: 13px; height: 13px; }
.tf-timeline li.is-done .tf-dot { border-color: var(--vb-success); color: var(--vb-success); }
.tf-timeline li.is-current .tf-dot { border-color: var(--vb-primary-bright); color: var(--vb-primary-bright); }
.tf-timeline strong { display: block; font-weight: 600; }
.tf-timeline .muted { display: block; font-size: 0.84rem; }

/* ---- NEW: Platform › Accounts (the operator's page) ------------------------------------------- */
.ops-columns { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 1.25rem; align-items: start; }
.ops-search { position: relative; margin-bottom: 1.25rem; }
.ops-search .field { margin: 0; }
.ops-verify { border: 1px solid var(--vb-border); border-radius: var(--vb-radius-sm); background: var(--vb-bg-soft); padding: 0.85rem 1rem; margin: 0.9rem 0 0; }
.ops-verify h3 { font-size: 0.9rem; margin: 0 0 0.5rem; }
.ops-verify .facts { grid-template-columns: 7.5rem minmax(0, 1fr); font-size: 0.86rem; }
.ops-missing { display: flex; gap: 0.6rem; align-items: flex-start; font-size: 0.88rem; color: var(--vb-text-muted); }
.ops-missing .icon { width: 16px; height: 16px; flex: none; margin-top: 0.15rem; color: var(--vb-warning); }
@media (max-width: 900px) { .ops-columns { grid-template-columns: minmax(0, 1fr); } }
/* Security page spacing (product/84): the explanation under the state line, the note beside a card heading, the
   note under Recent sign-ins. */
.tf-intro { margin: 0; }
.tf-card .alert-warning { margin: 1rem 0 0; }
.card-head-note { font-size: 0.85rem; }
.tf-signins-note { margin: 0.8rem 0 0; }
/* Account ops: the state pill and its date on one line in a fact; one airline per line. */
.ops-state { margin: 0; }
.ops-airline { display: block; }
/* Account ops: the recovery route, and the checklist (product/84 5.5). */
.ops-route { margin: 0 0 0.8rem; }
.ops-check { display: block; }
.ops-checklist { display: grid; gap: 0.5rem; }
.ops-checklist-head { display: block; font-weight: 600; font-size: 0.88rem; margin-bottom: 0.45rem; }

/* product/82: the operator's free-period tables. The name and its slug pill are spaced by the
   gap, never a typed space, and neither the pill nor the row's actions break mid-word. */
.fp-airline { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; }
.fp-airline .tenant-card-slug { white-space: nowrap; }
td.fp-actions { white-space: nowrap; }
