/* =========================================================================
   Command Nexus — Component Style Source (single source of truth)
   -------------------------------------------------------------------------
   This is the canonical stylesheet for standardized UI components (buttons,
   icon buttons, dropdowns). Pages should adopt the `.nx-*` classes here
   instead of re-defining their own one-off button/dropdown styles, so the
   look stays consistent and can be edited from one place.

   Pick a variant by class:
     Buttons      .nx-btn  +  --primary | --secondary | --ghost | --danger
     Icon button  .nx-icon-btn  (+ .logout-btn for the destructive hover)
     Dropdown     .nx-select   /   .nx-dropdown

   Colors are driven by CSS custom properties so a page/theme can override
   the accent without touching component rules. Defaults match the existing
   Nexus admin teal/gold palette.
   ========================================================================= */

:root {
    /* Accent + surfaces (override per-theme as needed) */
    --nx-accent:        #00d4aa;
    --nx-accent-strong: #00b894;
    --nx-accent-rgb:    0, 212, 170;
    --nx-gold:          #ffd700;
    --nx-gold-rgb:      255, 215, 0;
    --nx-danger:        #ff5b6e;
    --nx-danger-rgb:    255, 91, 110;
    --nx-success:       #2ecc71;
    --nx-success-rgb:   46, 204, 113;
    --nx-warning:       #f1c40f;
    --nx-warning-rgb:   241, 196, 15;
    --nx-info:          #3b82f6;
    --nx-info-rgb:      59, 130, 246;

    --nx-text:          #ffffff;
    --nx-text-muted:    rgba(255, 255, 255, 0.65);
    --nx-surface:       rgba(255, 255, 255, 0.08);
    --nx-surface-2:     rgba(255, 255, 255, 0.12);
    --nx-border:        rgba(255, 255, 255, 0.20);

    /* Canonical app/admin page background — single source of truth so the
       shared gradient can be re-themed from one place instead of being
       hard-coded on every page. Consume via `background: var(--nx-app-bg);`
       or the `.nx-app-bg` utility class below. */
    --nx-app-bg:        linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);

    /* Shape + motion */
    --nx-radius:        8px;
    --nx-radius-sm:     6px;
    --nx-gap:           0.5rem;
    --nx-transition:    150ms ease;
}

/* ---- Page background ---------------------------------------------------- */
/* Opt-in utility for the canonical app/admin page background. A page can add
   `class="nx-app-bg"` to <body> (or point its own body rule at var(--nx-app-bg))
   so the shared gradient lives in one place. Inert until adopted. */
.nx-app-bg {
    background: var(--nx-app-bg);
    background-attachment: fixed;
    min-height: 100vh;
}

/* ---- Text buttons ------------------------------------------------------- */
.nx-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.55rem 1.1rem;
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    color: var(--nx-text);
    background: var(--nx-surface);
    border: 1px solid var(--nx-border);
    border-radius: var(--nx-radius);
    cursor: pointer;
    text-decoration: none;
    transition: background var(--nx-transition), border-color var(--nx-transition),
                color var(--nx-transition), transform var(--nx-transition);
}
.nx-btn:hover    { background: var(--nx-surface-2); }
.nx-btn:active   { transform: translateY(1px); }
.nx-btn:disabled,
.nx-btn.is-disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }

.nx-btn--primary {
    color: #06231e;
    background: linear-gradient(135deg, var(--nx-accent), var(--nx-accent-strong));
    border-color: transparent;
}
.nx-btn--primary:hover { filter: brightness(1.06); background: linear-gradient(135deg, var(--nx-accent), var(--nx-accent-strong)); }

.nx-btn--secondary {
    color: var(--nx-text);
    background: var(--nx-surface-2);
    border-color: var(--nx-border);
}

.nx-btn--ghost {
    background: transparent;
    border-color: var(--nx-border);
}
.nx-btn--ghost:hover { background: rgba(var(--nx-accent-rgb), 0.12); border-color: var(--nx-accent); color: var(--nx-accent); }

.nx-btn--danger {
    color: #2a0a0e;
    background: var(--nx-danger);
    border-color: transparent;
}
.nx-btn--danger:hover { filter: brightness(1.06); }

.nx-btn--success {
    color: #04220f;
    background: var(--nx-success);
    border-color: transparent;
}
.nx-btn--success:hover { filter: brightness(1.06); }

.nx-btn--warning {
    color: #2a2200;
    background: var(--nx-warning);
    border-color: transparent;
}
.nx-btn--warning:hover { filter: brightness(1.06); }

/* Informational / secondary-action accent (blue). */
.nx-btn--info {
    color: #ffffff;
    background: var(--nx-info);
    border-color: transparent;
}
.nx-btn--info:hover { filter: brightness(1.06); }

/* Platform-admin accent (gold) — for the elevated platform-admin actions. */
.nx-btn--admin {
    color: #2a2200;
    background: linear-gradient(135deg, var(--nx-gold), #e0b400);
    border-color: transparent;
}
.nx-btn--admin:hover { filter: brightness(1.06); }

.nx-btn--sm { padding: 0.35rem 0.7rem; font-size: 0.85rem; }
.nx-btn--lg { padding: 0.75rem 1.5rem; font-size: 1.05rem; }

/* ---- Icon buttons (e.g. top-bar profile / logout) ----------------------- */
.nx-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    color: var(--nx-text);
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid var(--nx-border);
    border-radius: var(--nx-radius-sm);
    text-decoration: none;
    cursor: pointer;
    transition: background var(--nx-transition), color var(--nx-transition), border-color var(--nx-transition);
}
.nx-icon-btn:hover { background: rgba(var(--nx-accent-rgb), 0.20); color: var(--nx-accent); border-color: var(--nx-accent); }
.nx-icon-btn.logout-btn:hover { background: rgba(var(--nx-danger-rgb), 0.20); color: var(--nx-danger); border-color: var(--nx-danger); }

/* ---- Dropdowns / selects ------------------------------------------------ */
.nx-select {
    display: inline-block;
    padding: 0.5rem 2.2rem 0.5rem 0.8rem;
    font: inherit;
    color: var(--nx-text);
    background-color: var(--nx-surface);
    border: 1px solid var(--nx-border);
    border-radius: var(--nx-radius-sm);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    background-repeat: no-repeat;
    background-position: right 0.7rem center;
    background-size: 0.7rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%23ffffff' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E");
    transition: border-color var(--nx-transition), background-color var(--nx-transition);
    max-width: 100%;   /* a long <option> must never widen the control past its container */
}
.nx-select:hover  { background-color: var(--nx-surface-2); }
.nx-select:focus  { outline: none; border-color: var(--nx-accent); }
.nx-select option { color: #111; }

/* A `multiple` select is an inline listbox, not a closed control with a popup:
   its options render INSIDE the dark box, where the `#111` popup guard above
   is near-black on near-black. The chevron and its padding are meaningless
   here too, since there is nothing to drop down. Restore readable options and
   a visible selected row. */
.nx-select[multiple] {
    padding: 0.35rem;
    background-image: none;
    cursor: default;
}
.nx-select[multiple] option {
    color: var(--nx-text);
    padding: 0.25rem 0.4rem;
    border-radius: var(--nx-radius-sm);
}
.nx-select[multiple] option:checked {
    background: linear-gradient(var(--nx-accent), var(--nx-accent));
    color: #04231d;
    font-weight: 600;
}

/* Compact variant for dense rows (list rows, toolbars). Mirrors .nx-btn--sm,
   and exists so a cramped row reaches for THIS instead of hand-skinning a bare
   <select> locally — which re-breaks the option popup. */
.nx-select--sm {
    padding: 0.3rem 1.8rem 0.3rem 0.55rem;
    font-size: 0.85rem;
    background-position: right 0.5rem center;
}

/* ---- Form layout primitives (layout only — never skin the control here) -- */
.nx-form-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem 1.25rem;
    align-items: end;
}
.nx-form-group { min-width: 0; }          /* stop grid items blowing out their track */
.nx-label { display: block; margin-bottom: 0.4rem; font-size: 0.85rem; color: var(--nx-text-muted); }
.nx-form-group > .nx-select,
.nx-form-group > input,
.nx-form-group > textarea { width: 100%; box-sizing: border-box; }

/* ---- Nexus Admin suite page header -------------------------------------- */
/* Shared banner that sits ABOVE the suite tab bar on every Nexus Admin page,
   so all five pages read as one surface instead of five hand-rolled banners.
   Rendered by aasRenderHeader() in includes/aas_nav.php. Token-driven only. */
.aas-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 0 0 0.5rem;
}
.aas-header__brand {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nx-accent);
    background: rgba(var(--nx-accent-rgb), 0.15);
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
}
.aas-header__title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin: 0.5rem 0 0;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--nx-text);
}
.aas-header__title i { color: var(--nx-accent); }
.aas-header__subtitle {
    margin: 0.35rem 0 0;
    color: var(--nx-text-muted);
    font-size: 0.92rem;
}

/* Custom dropdown shell (for JS-driven menus that aren't a native <select>) */
.nx-dropdown { position: relative; display: inline-block; }
.nx-dropdown__menu {
    position: absolute;
    top: calc(100% + 0.4rem);
    left: 0;
    min-width: 180px;
    padding: 0.35rem;
    background: #1a2030;
    border: 1px solid var(--nx-border);
    border-radius: var(--nx-radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    z-index: 50;
}
.nx-dropdown__item {
    display: block;
    padding: 0.5rem 0.7rem;
    color: var(--nx-text);
    text-decoration: none;
    border-radius: var(--nx-radius-sm);
    cursor: pointer;
}
.nx-dropdown__item:hover { background: rgba(var(--nx-accent-rgb), 0.15); color: var(--nx-accent); }

/* =========================================================================
   Help tooltip (.nx-help) — CSS-only popover on a focusable question-mark
   trigger. No JS. Keyboard-accessible: the trigger is a focusable element and
   the bubble shows on both :hover and :focus/:focus-within.

   Markup:
     <span class="nx-help" tabindex="0" role="button" aria-label="What is this?">
       <i class="fas fa-circle-question"></i>
       <span class="nx-help__bubble" role="tooltip">Explanatory copy here.</span>
     </span>
   ========================================================================= */
.nx-help {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: 0.4rem;
    color: var(--nx-text-muted);
    cursor: help;
    font-size: 0.85em;
    vertical-align: middle;
    outline: none;
}
.nx-help:hover,
.nx-help:focus { color: var(--nx-accent); }
.nx-help:focus-visible { outline: 2px solid var(--nx-accent); outline-offset: 2px; border-radius: 50%; }
.nx-help__bubble {
    position: absolute;
    bottom: calc(100% + 0.5rem);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: max-content;
    max-width: 260px;
    padding: 0.55rem 0.7rem;
    background: #1a2030;
    border: 1px solid var(--nx-border);
    border-radius: var(--nx-radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    color: var(--nx-text);
    font-size: 0.8rem;
    font-weight: 400;
    line-height: 1.4;
    text-align: left;
    white-space: normal;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.12s ease, transform 0.12s ease;
    z-index: 60;
    pointer-events: none;
}
.nx-help:hover .nx-help__bubble,
.nx-help:focus .nx-help__bubble,
.nx-help:focus-within .nx-help__bubble {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}
.nx-help__bubble::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-top-color: #1a2030;
}

/* =========================================================================
   Banner stack (.nx-banner-stack) — the one top-of-page notice surface.
   Rendered by includes/banner_stack.php as the first thing inside <body>, in
   NORMAL DOCUMENT FLOW: the rows push the page down and scroll away with it,
   rather than floating fixed over whatever the page has at the top. Any number
   of rows can stack (the PHP side caps how many).
   ========================================================================= */
.nx-banner-stack {
    position: relative;
    z-index: 9000;
    display: flex;
    flex-direction: column;
}

.nx-banner {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.6rem 1rem;
    color: #ffffff;
    font-family: -apple-system, "Segoe UI", Tahoma, sans-serif;
    font-size: 0.92rem;
    line-height: 1.35;
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.nx-banner__icon  { flex: 0 0 auto; margin-top: 0.15rem; font-size: 1.05rem; }
.nx-banner__body  { flex: 1 1 auto; min-width: 0; }
.nx-banner__title { font-weight: 700; margin-bottom: 0.15rem; }
.nx-banner__text  { white-space: pre-wrap; overflow-wrap: anywhere; }

.nx-banner__link {
    display: inline-block;
    margin-top: 0.25rem;
    color: #ffffff;
    font-weight: 600;
    text-decoration: underline;
}

.nx-banner__dismiss {
    flex: 0 0 auto;
    padding: 0.25rem 0.7rem;
    font: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    color: #ffffff;
    background: rgba(255, 255, 255, 0.18);
    border: 1px solid rgba(255, 255, 255, 0.45);
    border-radius: var(--nx-radius-sm);
    cursor: pointer;
    transition: background var(--nx-transition);
}
.nx-banner__dismiss:hover { background: rgba(255, 255, 255, 0.3); }

/* Severity skins. Solid, deliberately high-contrast against white text. */
.nx-banner--info      { background: #0d8585; }
.nx-banner--warning   { background: #a87900; }
.nx-banner--important { background: #b3352f; }
.nx-banner--critical  { background: #8c1c17; }
.nx-banner--promo     { background: linear-gradient(90deg, #dc3545, #e8590c); }

/* =========================================================================
   Toasts (.nx-toast-stack / .nx-toast) — the transient success/error surface.
   -------------------------------------------------------------------------
   Distinct from .nx-banner-stack above: banners are persistent, in normal flow
   and push the page down; toasts FLOAT over the page, auto-dismiss after a few
   seconds, and never move the layout — so an action's confirmation cannot shove
   the content the user is reading.

   Rendered server-side by includes/flash.php (markup escaped there) and driven
   by assets/js/nexus-toast.js, which owns the vertical offset: the stack is
   pinned just under the page's real rendered header when the page is scrolled
   to the top, and floats at a small fixed inset once that header has scrolled
   away. The `top` value is therefore set from JS at runtime; the value here is
   only the pre-measurement fallback.
   ========================================================================= */
.nx-toast-stack {
    position: fixed;
    top: 12px;                 /* replaced at runtime by nexus-toast.js */
    left: 50%;
    transform: translateX(-50%);
    z-index: 9500;             /* above .nx-banner-stack (9000) */
    display: flex;
    flex-direction: column;
    gap: var(--nx-gap);
    align-items: center;
    width: min(560px, calc(100vw - 24px));
    pointer-events: none;      /* clicks pass through the empty stack area */
}
.nx-toast-stack:empty { display: none; }

.nx-toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    width: 100%;
    padding: 0.7rem 0.9rem;
    color: #ffffff;
    font-family: -apple-system, "Segoe UI", Tahoma, sans-serif;
    font-size: 0.92rem;
    line-height: 1.35;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--nx-radius);
    box-shadow: 0 8px 26px rgba(0, 0, 0, 0.45);
    /* Enter/leave state is driven by the .nx-toast--in class so a toast that is
       never picked up by JS (script blocked) still renders fully visible. */
    opacity: 1;
    transform: translateY(0);
    transition: opacity 220ms ease, transform 220ms ease;
}

/* Pre-entry + exit states, only ever applied by nexus-toast.js. */
.nx-toast--enter { opacity: 0; transform: translateY(-8px); }
.nx-toast--leave { opacity: 0; transform: translateY(-8px); }

.nx-toast__icon    { flex: 0 0 auto; margin-top: 0.1rem; font-size: 1.05rem; }
.nx-toast__text    { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }

.nx-toast__dismiss {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font: inherit;
    font-size: 1rem;
    line-height: 1;
    color: #ffffff;
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.38);
    border-radius: var(--nx-radius-sm);
    cursor: pointer;
    transition: background var(--nx-transition);
}
.nx-toast__dismiss:hover { background: rgba(255, 255, 255, 0.32); }
.nx-toast__dismiss:focus-visible { outline: 2px solid #ffffff; outline-offset: 2px; }

/* Severity skins. Solid, deliberately high-contrast against white text. */
.nx-toast--success { background: #1e7a4d; }
.nx-toast--error   { background: #a5302c; }
.nx-toast--info    { background: #0d8585; }
.nx-toast--warning { background: #a87900; }

@media (prefers-reduced-motion: reduce) {
    .nx-toast { transition: none; }
    .nx-toast--enter,
    .nx-toast--leave { opacity: 1; transform: none; }
}

/* =========================================================================
   Responsive utilities
   -------------------------------------------------------------------------
   Opt-in wrappers for the two layout shapes that break hardest on a phone:
   a table wider than the screen, and a row of controls that must become a
   column. Both are inert on desktop.
   ========================================================================= */

/* Wrap a wide table/pre/chart in this so IT scrolls sideways instead of the
   whole page. Pair with a table that keeps `min-width` so columns stay legible.
     <div class="nx-scroll-x"><table>...</table></div>                        */
.nx-scroll-x {
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.nx-scroll-x > table { min-width: 100%; }

/* A row of buttons/controls that should wrap rather than overflow.
   USE THIS instead of letting adjacent buttons sit as bare siblings: `.nx-btn`
   is inline-flex and its internal `gap` only separates icon from label, so two
   buttons side by side are held apart by nothing but collapsed source
   whitespace (~4px), and pages that reset margins globally lose even that.
     <div class="nx-actions nx-actions--gap-bottom"> <a class="nx-btn">…       */
.nx-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--nx-gap);
    align-items: center;
    min-width: 0;
}
.nx-actions--end        { justify-content: flex-end; }
/* Separate the row from the block above/below it. Explicit rather than
   automatic, because many app pages carry a global `* { margin: 0 }` reset that
   would silently drop a default margin here. */
.nx-actions--gap-top    { margin-top: 1rem; }
.nx-actions--gap-bottom { margin-bottom: 1rem; }

/* Member profile picture. Always circular, always the same shape whether the
   member uploaded a picture (an <img>) or not (a <span> with their initials on
   the accent colour), so a roster row lines up either way. Size is set inline by
   renderUserAvatar() — the helper also picks which stored rendition to fetch, so
   never scale a big avatar down with CSS alone. */
.nx-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    border-radius: 50%;
    object-fit: cover;
    overflow: hidden;
    background: rgba(var(--nx-accent-rgb), 0.18);
    border: 1px solid rgba(var(--nx-accent-rgb), 0.35);
    vertical-align: middle;
}
.nx-avatar--default {
    color: var(--nx-accent);
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1;
    text-transform: uppercase;
    user-select: none;
}

/* A form reduced to its control(s), sitting inline with its neighbours — the
   "delete" button next to a "save" button, an action cell in a table row.
   Deliberately `inline-flex`, NOT `inline`: vertical margins are ignored on a
   non-replaced inline box, so the older per-page `display: inline` version made
   every `margin-top` on such a form a silent no-op. */
.nx-inline-form {
    display: inline-flex;
    align-items: center;
    gap: var(--nx-gap);
    vertical-align: middle;
}

/* =========================================================================
   Brand mark
   -------------------------------------------------------------------------
   The Command Nexus product mark: shield + a two-line wordmark, left
   justified, the stacked text sized so the block matches the icon height.
   Emitted only by cnBrandMark() in includes/cn_brand.php — pages should
   never rebuild it, which is what let the admin sidebar and the unit
   headers drift apart in the first place.

   The icon is the FontAwesome shield rather than an image file. If a real
   logo asset lands in assets/img/, swap the <i> in the partial; nothing
   here assumes a glyph.
   ========================================================================= */
.cn-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    text-decoration: none;
    color: inherit;
    /* Wrapper margins are eaten by the global `* { margin: 0 }` reset, so the
       mark carries no outer spacing — the header's own gap positions it. */
    transition: opacity var(--nx-transition);
}
.cn-brand:hover,
.cn-brand:focus-visible { opacity: 0.85; text-decoration: none; }
.cn-brand:focus-visible {
    outline: 2px solid var(--nx-accent);
    outline-offset: 3px;
    border-radius: var(--nx-radius-sm);
}

.cn-brand__icon {
    /* Default mark is the home-page blue; admin surfaces opt into red via
       .cn-brand--admin so the colour states who the page serves. */
    color: var(--cn-brand-mark, #00CED1);
    font-size: 2rem;
    line-height: 1;
    flex: none;
}
.cn-brand--admin .cn-brand__icon { color: var(--nx-danger); }

/* The two wordmark lines stack tightly so the pair reads as one block the
   same height as the shield. */
.cn-brand__text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.02;
}
.cn-brand__line {
    font-weight: 900;
    font-size: 1.05rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--nx-text);
    white-space: nowrap;
}
.cn-brand__sub {
    margin-top: 0.15rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--nx-text-muted);
    text-transform: none;
    white-space: nowrap;
    max-width: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Sidebar form: a little more room, since it sits above a divider. */
.cn-brand--stacked { gap: 0.6rem; }
.cn-brand--stacked .cn-brand__icon { font-size: 1.75rem; }

/* Unit-page headers put the product mark next to the org's own tile. The
   hairline keeps "Command Nexus" from reading as part of the org name. */
.cn-brand--divided {
    padding-right: 0.9rem;
    border-right: 1px solid var(--nx-border);
}

/* =========================================================================
   Mobile layer
   -------------------------------------------------------------------------
   The design system had no breakpoints at all, so every `.nx-*` surface kept
   its desktop shape on a phone: multi-column form rows stayed side by side,
   dropdown menus could sit wider than the viewport, and long words in a
   banner pushed the page sideways. These rules reflow the shared components;
   pages built on them get mobile behaviour without their own media queries.
   ========================================================================= */
@media (max-width: 768px) {
    /* Multi-column form rows collapse to one column. */
    .nx-form-row { grid-template-columns: 1fr; gap: 0.85rem; }

    /* Controls go full-bleed so they're comfortable thumb targets. */
    .nx-form-group > .nx-select,
    .nx-form-group > input,
    .nx-form-group > textarea,
    .nx-select { width: 100%; max-width: 100%; }

    /* A dropdown menu must never be wider than the screen. */
    .nx-dropdown { display: block; }
    .nx-dropdown__menu {
        min-width: 0;
        width: 100%;
        max-width: calc(100vw - 2rem);
    }

    /* Help bubbles are centred on the viewport rather than on a trigger that
       might be at the very edge of the screen. */
    .nx-help__bubble { max-width: min(260px, calc(100vw - 3rem)); }

    /* Banner rows: dismiss drops under the message so neither is squeezed. */
    .nx-banner {
        flex-wrap: wrap;
        padding: 0.55rem 0.85rem;
        font-size: 0.88rem;
    }
    .nx-banner__body { flex: 1 1 100%; }
    .nx-banner__dismiss { margin-left: auto; }

    /* Header banner of the Nexus Admin suite pages. */
    .aas-header { gap: 0.75rem; }
    .aas-header__title { font-size: 1.25rem; }

    /* No element in a shared component should be able to widen the page. */
    .nx-banner__text,
    .nx-dropdown__item,
    .nx-btn { overflow-wrap: anywhere; }
    .nx-btn { max-width: 100%; }

    /* The brand mark shrinks rather than pushing the header nav off-screen. */
    .cn-brand { gap: 0.45rem; }
    .cn-brand__icon { font-size: 1.6rem; }
    .cn-brand__line { font-size: 0.9rem; }
    .cn-brand__sub { max-width: 9rem; }
    .cn-brand--divided { padding-right: 0.6rem; }
}

@media (max-width: 480px) {
    /* iOS zooms the page when a focused control's text is under 16px, which
       leaves the layout scrolled sideways after the keyboard closes. */
    .nx-select,
    .nx-form-group > input,
    .nx-form-group > textarea { font-size: 16px; }

    .nx-btn { padding: 0.5rem 0.85rem; }
    .nx-btn--lg { padding: 0.65rem 1.1rem; font-size: 1rem; }

    /* Action rows stack full-width so nothing gets clipped. */
    .nx-actions > .nx-btn { flex: 1 1 100%; }
}
