/*
 * Portal theme layer on top of the UniFi-style UI Kit (unifi-ui.css).
 *
 * Loaded after the kit stylesheet. The kit already re-skins every Bootstrap
 * component (cards, buttons, forms, tables, dropdowns, modals, pagination);
 * this file only carries what the kit does not provide:
 *   1. portal-level RGB token aliases used by app.css,
 *   2. portal utility backfills (fs-*, opacity-*, btn-icon, bg-faded-*),
 *   3. the authentication password-visibility toggle component,
 *   4. shell styling for the portal navbar/footer and page heads, mapped to
 *      the kit's design tokens so light/dark both follow the kit.
 */

/* ---------- Portal RGB token aliases ---------- */
:root,
[data-bs-theme="light"] {
    --uf-primary-rgb: 50, 50, 56;
    --uf-green-rgb: 46, 184, 114;
    --uf-role-admin: #5b21b6;
    --uf-role-admin-soft: #ddd6fe;
    --uf-role-admin-ring: rgba(91, 33, 182, 0.35);
    --uf-role-operator: #134e4a;
    --uf-role-operator-soft: #99f6e4;
    --uf-role-operator-ring: rgba(19, 78, 74, 0.35);
    --uf-role-viewer: #334155;
    --uf-role-viewer-soft: #cbd5e1;
    --uf-role-viewer-ring: rgba(51, 65, 85, 0.35);
}

[data-bs-theme="dark"] {
    --uf-primary-rgb: 148, 148, 148;
    --uf-green-rgb: 55, 192, 124;
    --uf-role-admin: #ddd6fe;
    --uf-role-admin-soft: rgba(196, 181, 253, 0.30);
    --uf-role-admin-ring: rgba(196, 181, 253, 0.55);
    --uf-role-operator: #99f6e4;
    --uf-role-operator-soft: rgba(94, 234, 212, 0.28);
    --uf-role-operator-ring: rgba(94, 234, 212, 0.50);
    --uf-role-viewer: #e2e8f0;
    --uf-role-viewer-soft: rgba(203, 213, 225, 0.26);
    --uf-role-viewer-ring: rgba(203, 213, 225, 0.45);
}

/* ---------- Portal utility backfills ---------- */
/* Kit quiet label (form labels and small section labels on any element). */
.form-label, .uf-label { font-size: 13px; font-weight: 500; color: var(--uf-text-2); margin-bottom: 6px; }
.fs-xs { font-size: 0.75rem !important; }
.fs-sm { font-size: 0.875rem !important; }
.fs-base { font-size: 1rem !important; }
.fs-lg { font-size: 1.125rem !important; }

.opacity-10 { opacity: 0.1 !important; }
.opacity-50 { opacity: 0.5 !important; }
.opacity-60 { opacity: 0.6 !important; }

/* Square icon-only button variant (toolbar actions, drawer headers). */
.btn-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
}

.bg-faded-primary { background-color: var(--uf-primary-soft) !important; }
.bg-faded-dark { background-color: rgba(31, 31, 31, 0.18) !important; }
[data-bs-theme="light"] .bg-faded-dark { background-color: rgba(32, 32, 32, 0.12) !important; }

/* Kit dot extension: neutral theme-accent status dot (busy/processing states). */
.uf-dot.is-blue { background: var(--uf-primary); }

/* Kit soft-pill extension: neutral theme-accent pill (matches uf-val.is-blue). */
.uf-badge.is-blue { color: var(--uf-primary); background: var(--uf-primary-soft); }
/* Kit role-namespace extension (docs/role-badge-namespace-design.md): dedicated
   role colors, reusable at kit level. Roles MUST use is-role-*; status MUST
   NOT use is-role-*. Distinct from green/red/orange/primary/gray status.
   Soft-but-noticeable for identification: saturated pastel fill + inset ring
   (status pills have neither), AA text contrast both themes. */
.uf-badge.is-role-admin { color: var(--uf-role-admin); background: var(--uf-role-admin-soft); box-shadow: inset 0 0 0 1px var(--uf-role-admin-ring); }
.uf-badge.is-role-operator { color: var(--uf-role-operator); background: var(--uf-role-operator-soft); box-shadow: inset 0 0 0 1px var(--uf-role-operator-ring); }
.uf-badge.is-role-viewer { color: var(--uf-role-viewer); background: var(--uf-role-viewer-soft); box-shadow: inset 0 0 0 1px var(--uf-role-viewer-ring); }
/* Status/count pills must stay on one line ("1 Idle", not "1" over "Idle");
   the toolbar wraps the pills as whole units instead. */
.uf-badge { white-space: nowrap; }

/* Group identity glyph on its soft tile: theme accent — monochrome in the
   light mode, neutral gray in dark. Status dots/badges keep colors. */
.group-identity-icon { color: var(--uf-primary); }

/* ---------- Password visibility toggle (authentication surface) ---------- */
.password-toggle { position: relative; }
.password-toggle .form-control { padding-right: 3rem; }
.password-toggle-btn {
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    margin-bottom: 0;
    padding: 0.5rem;
    position: absolute;
    right: 0.625rem;
    top: 50%;
    transform: translateY(-50%);
}
.password-toggle-btn .password-toggle-indicator {
    color: var(--uf-text-3);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.2s ease-in-out;
}
.password-toggle-btn .password-toggle-indicator svg {
    width: 20px;
    height: 20px;
}
.password-toggle-btn .password-toggle-indicator:hover { color: var(--uf-text-1); }
.password-toggle-check { position: absolute; opacity: 0; pointer-events: none; }

/* ---------- Shell: kit top bar + icon rail ---------- */
/* The kit owns .uf-topbar/.uf-rail styling; only the portal's user-dropdown
   trigger and the shell flex column for the footer live here. */
.uf-topbar .nav-link {
    color: var(--uf-text-1);
}
.uf-topbar .nav-link:hover { color: var(--uf-text-2); }
/* Mobile drawer + user-dropdown rows share the reference shell look: plain
   Bootstrap nav-link markup styled via descendant selectors (active pill,
   icon sizing), so the drawer matches the TCIDS reference. */
.offcanvas .nav-link { color: var(--uf-text-1); font-weight: 500; }
.offcanvas .nav-link:hover { color: var(--uf-text-1); background: var(--uf-bg-muted); }
.offcanvas .nav-link.active { color: var(--uf-text-1); background: var(--uf-bg-muted); }
.uf-mobile-nav { --bs-offcanvas-width: 300px; }
.uf-mobile-nav .nav-link {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: var(--uf-radius);
    color: var(--uf-text-1);
    font-size: 14px;
    font-weight: 500;
}
.uf-mobile-nav .nav-link i {
    color: var(--uf-text-2);
    font-size: 18px;
}
/* Lucide SVG sizing: the drawer rows use flex gap, so only set the box. */
.uf-mobile-nav .nav-link .lucide {
    width: 18px;
    height: 18px;
    flex: none;
}
.uf-mobile-nav .offcanvas-header .lucide {
    width: 18px;
    height: 18px;
    margin-right: 10px;
    opacity: 0.6;
}
.uf-mobile-nav .nav-link:hover { background: var(--uf-bg-muted); color: var(--uf-text-1); }
.uf-mobile-nav .nav-link.active {
    background: var(--uf-bg-muted);
    color: var(--uf-text-1);
}
.uf-mobile-nav .nav-link.active i { color: var(--uf-text-1); }
.uf-mobile-nav-divider { border-color: var(--uf-border-light); opacity: 1; }
/* User dropdown items adopt the same row look. */
.dropdown-menu .nav-link.active {
    color: var(--uf-primary);
    background: var(--uf-primary-soft);
}
/* Rows keep the nav-link class (for the active highlight), but read as plain
   menu items — the kit's default nav-link color is primary blue. */
.dropdown-menu .nav-link { color: inherit; }
/* Lucide SVG icons in the account dropdown (menu rows + language/theme rows):
   full strength like the rail (no faded treatment). Sizing stays at the
   drawer tier (18px vs the rail's 21px) for menu density. Spacing follows the
   row type so the icon-to-text gap matches the rail's 10px: menu rows use the
   kit's 9px flex gap (margin zeroed), while the plain d-flex language/theme
   rows keep a 10px margin (they have no flex gap). */
.dropdown-menu .lucide {
    width: 18px;
    height: 18px;
    flex: none;
    margin-right: 10px;
}
.dropdown-menu .dropdown-item .lucide { margin-right: 0; }
.dropdown-menu .dropdown-item-text .lucide { opacity: 0.6; }

/* Initial-letter avatar for the user dropdown trigger (kit uf-avatar size). */
.portal-avatar-initial {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--uf-primary-soft);
    color: var(--uf-primary);
    font-size: 13px;
    font-weight: 600;
    user-select: none;
}
/* Quiet user chip replacing the bare avatar trigger: greeting text + caret +
   avatar, tinted on hover like the kit's app-switcher. The greeting hides
   below the xl breakpoint so the topbar never crowds at lg. */
.uf-user-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 14px;
    border: 0;
    border-radius: 999px;
    background: none;
}
.uf-user-chip:hover { background: var(--uf-bg-muted); }
/* Light-up on hover like the left-rail rows: greeting and caret each step up
   one text tone (the avatar keeps its primary/soft treatment). */
.uf-user-chip:hover .uf-user-greeting { color: var(--uf-text-1); }
.uf-user-chip:hover .uf-user-caret { color: var(--uf-text-2); }
.uf-user-greeting {
    font-size: 13.5px;
    color: var(--uf-text-2);
    max-width: 24ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.uf-user-caret { font-size: 18px; color: var(--uf-text-3); }
/* Icon rail: top-group nav links are styled via descendant selectors so the
   markup keeps the plain Bootstrap `nav-link` / `nav-link active` classes
   (reference shell pattern). */
.uf-rail .nav-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    padding: 0;
    border: 0;
    border-radius: 10px;
    /* Rests at text-2 (kit ships text-3) for readability; hover still lights
       up to text-1 and the active pill stays primary. */
    color: var(--uf-text-2);
    font-size: 0;
    transition: color 0.15s, background-color 0.15s;
}
.uf-rail .nav-link i {
    font-size: 21px;
    line-height: 1;
}
/* Rail nav links render Lucide SVGs (the kit only sizes .uf-rail-item .lucide,
   not the product nav-link markup used in the top group). */
.uf-rail .nav-link .lucide {
    width: 21px;
    height: 21px;
    flex: none;
}
.uf-rail .nav-link:hover {
    color: var(--uf-text-1);
    background: var(--uf-bg-muted);
}
.uf-rail .nav-link.active {
    color: var(--uf-text-1);
    background: var(--uf-bg-muted);
}
[data-bs-theme="light"] .uf-rail .nav-link.active {
    color: var(--uf-on-primary);
    background: var(--uf-primary);
}
/* Bottom-group/toggle rows use the kit's .uf-rail-item class (kit ships
   text-3): same one-step brightening, scoped off :hover/:is-active so the
   text-1 hover light-up and the primary active pill keep working. */
.uf-rail .uf-rail-item:not(.is-active):not(:hover) { color: var(--uf-text-2); }
/* Rail icons are Lucide SVG (kit default): the kit sizes bottom-group icons
   via .uf-rail-item .lucide { width: 21px; height: 21px; } — no portal override. */

/* Lucide spinning indicator (upload submit / picker loading states). */
.lucide-spin { animation: portal-lucide-spin 1s linear infinite; }
@keyframes portal-lucide-spin { to { transform: rotate(360deg); } }

/* Starred job: filled star glyph (survives Lucide re-renders, unlike a
   fill attribute set from JS). */
#job-importance[data-important="true"] svg { fill: currentColor; }

/* ---------- In-page anchor offset (sticky topbar) ---------- */
/* Anchor jumps land the target at the viewport top, where the sticky
   .uf-topbar (--uf-topbar-h) would otherwise cover the section heading. */
html {
    scroll-padding-top: calc(var(--uf-topbar-h) + 16px);
}

/* ---------- Shell: sidebar expanded/minimized states ---------- */
/* The kit only ships the fixed 64px icon rail; the expanded view (icon +
   label rows) and the persisted toggle are portal additions. The state lives
   in <html data-rail-state="...">, set pre-paint by static/js/sidebar.js
   (default: expanded). Minimized restores the kit's original icon-only rail,
   and mobile is unaffected — the kit hides the rail below the desktop
   breakpoint and the offcanvas drawer takes over. */
:root[data-rail-state="expanded"] {
    --uf-rail-w: 224px;
}
/* Shared height for the page footer and the rail's toggle band, so the two
   bottom hairlines sit on the same line (the rail is fixed to the viewport
   bottom exactly like the shell footer). */
:root {
    --uf-footer-h: 54px;
}
.uf-shell .footer {
    height: var(--uf-footer-h);
    padding-top: 0;
    padding-bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
.uf-rail,
.uf-shell {
    transition: width 0.2s ease, margin-left 0.2s ease;
}
@media (prefers-reduced-motion: reduce) {
    .uf-rail,
    .uf-shell { transition: none; }
}

/* Item labels: real text in the expanded view; hidden in the minimized rail
   (the item's title attribute keeps a native tooltip there). */
.uf-rail-label {
    font-size: 13.5px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
:root[data-rail-state="minimized"] .uf-rail-label { display: none; }

/* Expanded rows: full-width, icon leading, label trailing. Applies to both the
   kit's .uf-rail-item and the product nav-link markup used in the top group. */
:root[data-rail-state="expanded"] .uf-rail { padding-inline: 10px; }
:root[data-rail-state="expanded"] .uf-rail-group {
    align-items: stretch;
    width: 100%;
}
:root[data-rail-state="expanded"] .uf-rail .nav-link,
:root[data-rail-state="expanded"] .uf-rail-item {
    width: 100%;
    height: 40px;
    justify-content: flex-start;
    gap: 10px;
    padding: 0 12px;
}
:root[data-rail-state="expanded"] .uf-rail .nav-link {
    font-size: 13.5px;
    font-weight: 500;
}

/* Toggle band pinned to the rail bottom with the same height (and hairline
   position) as the page footer; the kit's rail bottom padding is dropped so
   the band sits flush like the footer does. The rail-bottom admin group just
   above it is a kit feature (see .uf-rail-bottom in vendor/css/unifi-ui.css),
   not a portal override. */
.uf-rail { padding-bottom: 0; }
.uf-rail-group:last-child {
    border-top: 1px solid var(--uf-border-light);
    height: var(--uf-footer-h);
    justify-content: center;
}
.uf-rail-toggle {
    border: 0;
    background: none;
    cursor: pointer;
}
.uf-rail-toggle svg, .uf-rail-toggle .lucide { transition: transform 0.2s ease; }
:root[data-rail-state="minimized"] .uf-rail-toggle svg,
:root[data-rail-state="minimized"] .uf-rail-toggle .lucide { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
    .uf-rail-toggle svg, .uf-rail-toggle .lucide { transition: none; }
}
/* The rail is fixed full-height, so the page area must be the flex sibling
   that grows; the footer stays pinned to the viewport bottom inside it. */
.uf-shell {
    flex: 1 1 auto;
    min-height: 0;
}

/* ---------- Navigation row rhythm (rail + dropdown) ---------- */
/* One density for every navigation surface: 40px rows, 2px between them. The
   kit ships 6px gaps with 40-42px rail / 35px dropdown rows, and deliberately
   ties the rail and dropdown to the same gap value, so they are overridden as
   one set here.
 *
 * This block sits AFTER the rail-state rules on purpose. Those use
 * `:root[data-rail-state="expanded"]` (specificity 0,3,0) against a plain
 * `.uf-rail .nav-link` (0,2,0); placing the overrides earlier would lose to
 * them on the expanded height. Repeating the state selector here keeps
 * specificity equal so load order decides — no !important needed. Same reason
 * for keeping `.dropdown-menu.show` (not a bare `.dropdown-menu`): the kit
 * leans on that exact selector to beat Bootstrap's display:block re-assertion
 * on .show.
 *
 * Covers all three rail groups plus the dropdown. Minimize-sidebar is a
 * `.uf-rail-item` too, so it follows automatically. The mobile drawer
 * (.uf-mobile-nav) is deliberately NOT covered: its spacing is per-row padding
 * in a plain <ul>, not a flex gap, and it is the one surface where rows are
 * finger-sized. */
.uf-rail-group,
.uf-rail-group > ul,
.dropdown-menu.show {
    gap: 2px;
}

/* The rail's top group nests its rows one level deeper (a <ul> inside
   .uf-rail-group), so the group gap above does not reach them — that is why
   this used to carry a `gap-2` utility and read wider than the rest of the
   rail. The utility is gone from the markup; the value lives here with the
   other two so all three groups share one rhythm. */

/* One row height for every rail row, expanded or minimized. 40px is the
   portal's established rail density (the expanded state shipped 40px) and
   keeps a usable pointer target; the minimized icon buttons are square at the
   same 40px so the 10px radius reads identically in both states. The kit ships
   42px squares. */
.uf-rail .nav-link,
.uf-rail-item {
    width: 40px;
    height: 40px;
}

/* Expanded rail: full-width rows at the same height. Width and centering are
   re-stated because the rail-state rule owns them upstream. */
:root[data-rail-state="expanded"] .uf-rail .nav-link,
:root[data-rail-state="expanded"] .uf-rail-item {
    width: 100%;
    height: 40px;
}

/* One type treatment for every rail row. The two groups ship DIFFERENT classes
   (`.nav-link` in the top group, the kit's `.uf-rail-item` below), and only the
   first had portal typography — 13.5px/500 vs the kit's 14px/400 — which is
   the other half of "the top of the nav looks different". 13.5px/500 is the
   portal's stated rail density, so the kit side is brought up to it. Icon size
   (21px) and rest/hover colors already matched and are left alone. */
.uf-rail .nav-link,
.uf-rail-item {
    font-size: 13.5px;
    font-weight: 500;
    line-height: 1.5;
}

/* Dropdown rows. The kit's 7px block padding plus a 21px line box makes a
   35px row, so padding is what has to move; 9.5px lands the row on the same 40px
   as the rail, with min-height as the floor. Padding rather than a fixed height,
   so a wrapped or longer translated label still grows the row instead of
   clipping. */
.dropdown-item {
    min-height: 40px;
    padding-top: 9.5px;
    padding-bottom: 9.5px;
}
/* Language + theme rows: the same 40px. The language row is sized by its
   embedded control (form-select-sm is 37px), which stretch cannot shrink inside
   an auto-height row, so the select is pinned to the 32px content box and the
   row's own 4px padding brings it to 40px. The theme row's switch keeps its
   natural 24px and is centred. */
.dropdown-item-text {
    min-height: 40px;
}
.dropdown-item-text .form-select {
    height: 32px;
    min-height: 0;
    padding-top: 0;
    padding-bottom: 0;
}

/* ---------- Shell: page head ---------- */
/* Kit page heads are compact: 20px/600 title with a 13.5px muted subtitle. */
main h1 {
    font-size: 20px;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.01em;
}
main h1 + p.text-muted { font-size: 13.5px; }

/* ---------- Shell: footer ---------- */
/* Shell chrome shares the surface token with the topbar and rail so the frame
   stays one step above the content canvas. */
.footer { background: var(--uf-surface); }

/* ---------- Neutral secondary button follows the kit's btn-default look ---------- */
.btn-secondary {
    --bs-btn-color: var(--uf-text-1);
    --bs-btn-bg: var(--uf-surface);
    --bs-btn-border-color: var(--uf-border);
    --bs-btn-hover-color: var(--uf-text-1);
    --bs-btn-hover-bg: var(--uf-bg-subtle);
    --bs-btn-hover-border-color: var(--uf-border-strong);
    --bs-btn-active-color: var(--uf-text-1);
    --bs-btn-active-bg: var(--uf-bg-muted);
    --bs-btn-active-border-color: var(--uf-border-strong);
    --bs-btn-disabled-color: var(--uf-text-1);
    --bs-btn-disabled-bg: var(--uf-surface);
    --bs-btn-disabled-border-color: var(--uf-border);
}

/* ---------- Tables: kit re-skin for Bootstrap variants ---------- */
/* Bootstrap's .table-light hard-codes a white header (no dark-mode flip), so
   re-map the variant to the kit's table tokens like unifi-ui.css does for the
   base .table; portal pages must use plain <thead> instead. */
.table-light {
    --bs-table-color: var(--uf-text-1);
    --bs-table-bg: transparent;
    --bs-table-border-color: var(--uf-border-light);
    --bs-table-striped-bg: var(--uf-bg-subtle);
    --bs-table-striped-color: var(--uf-text-1);
    --bs-table-active-bg: var(--uf-bg-muted);
    --bs-table-active-color: var(--uf-text-1);
    --bs-table-hover-bg: var(--uf-bg-subtle);
    --bs-table-hover-color: var(--uf-text-1);
}

/* ---------- Light-theme body/card surfaces use the kit tokens ---------- */
/* The page canvas is a touch lighter than the kit's #f0f0f0 (#ebebeb neutral
   read heavy next to the white cards and darkened the whole shell). Only the
   canvas moves: the footer follows it (same token), and the near-white cards
   keep their separation through their own shadow. Scoped to the light
   attribute, NOT `:root` — the kit sets its dark values on
   `[data-bs-theme="dark"]` at the same specificity, so a `:root` rule here
   would load later and win in dark mode too. */
[data-bs-theme="light"] {
    --uf-bg: #f6f6f7;
}

[data-bs-theme="light"] body {
    background-color: var(--uf-bg);
    color: var(--uf-text-1);
}

[data-bs-theme="light"] .footer {
    background-color: var(--uf-bg);
}

/* Settings-page label column (kit schedules pattern): 14px, primary text. */
.config-label {
    display: inline-block;
    padding-top: 0.35rem;
    font-size: 14px;
    font-weight: 500;
    color: var(--uf-text-1);
}

/* Job detail: source video sits under a normal card header, so drop the
   12px top margin the media-modal bar composition adds. */
#job-video-card .uf-media-view {
    margin-top: 0;
}

/* Job detail: the source placeholder (file unavailable OR format
   unsupported by the HTML5 player) keeps the player's 16:9 box so the
   card never collapses when there is nothing to play — same footprint
   as .uf-media-view, content vertically centered. The global
   `[hidden] { display: none !important }` restore in app.css keeps the
   hidden toggling intact. */
#job-video-card #job-video-unavailable {
    width: 100%;
    aspect-ratio: 16 / 9;
    justify-content: center;
    border-radius: 10px;
    padding: 20px;
}

/* Job detail: still-image sources show the whole frame (contain, not the
   16:9 cover crop the video player uses) so defects are never cropped out. */
#job-video-card #job-image-view {
    object-fit: contain;
}

/* ---------- Pagination: spaced items ---------- */
/* The kit sets `gap: 3px` on `.pagination`, which reads as stuck together
   next to the reference component. Keep the kit's borderless rounded look,
   just give the items breathing room. */
.pagination { gap: 0.5rem; }
/* Labeled Prev/Next links pair a chevron with text; keep them aligned. */
.pagination .page-link { display: inline-flex; align-items: center; gap: 0.25rem; }
.pagination .page-link svg, .pagination .page-link .lucide { width: 1em; height: 1em; }
/* Disabled bounds read as quiet text, never as lit buttons: Bootstrap fills
   disabled page links with its secondary-bg pill, which is too bright against
   the kit surfaces (notably in dark mode). Transparent ground + tertiary text
   + no pointer response instead. */
.pagination .page-item.disabled .page-link {
    color: var(--uf-text-3);
    background-color: transparent;
    border-color: transparent;
    opacity: 0.6;
    pointer-events: none;
}

/* ---------- Pagination: reference full bar ---------- */
/* Full-bar layout from the shared pager (PortalUtils.renderCanonicalPagination
   full mode): info (items-per-page + showing) left, numbered pager middle,
   Go-to right; wraps into a natural stack on narrow screens. */
.portal-pagination {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    width: 100%;
}
.portal-pagination__info {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    margin-right: auto;
}
.portal-pagination__label { margin: 0; font-size: 0.8125rem; color: var(--uf-text-2); }
.portal-pagination__label--short { display: none; }
.portal-pagination__select { width: auto; min-width: 4.5rem; }
.portal-pagination__showing { font-size: 0.8125rem; color: var(--uf-text-2); }
.portal-pagination__goto {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8125rem;
    color: var(--uf-text-2);
}
.portal-pagination__goto label { margin: 0; }
.portal-pagination__input { width: 4.5rem; }
/* Kit `.form-control` (0.45rem 0.8rem) loads after Bootstrap, so it overrides
   `.form-control-sm` (same specificity) and made the Go-to input ~6px taller
   than the sm Go button. Re-assert sm metrics here (higher specificity, later
   layer) so input, page-size select and button share one height:
   1.5em + 0.5rem + 2px border (~31px). */
.portal-pagination__input.form-control-sm {
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
    line-height: 1.5;
    min-height: calc(1.5em + 0.5rem + 2px);
}
.portal-pagination__select.form-select-sm {
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
    padding-left: 0.5rem;
    font-size: 0.875rem;
    line-height: 1.5;
    min-height: calc(1.5em + 0.5rem + 2px);
}
/* Go-to submit is the bar's only true action, so it keeps the visible
   btn-default treatment (surface fill + border + button states) while
   matching the bar's metrics: pagination-sm padding/type and 8px radius, so
   it renders at exactly the boxed input's height (1.5em + 0.5rem + border).
   Page numbers and Prev/Next stay quiet links by design. */
.portal-pagination__go {
    --bs-btn-padding-y: 0.25rem;
    --bs-btn-padding-x: 0.5rem;
    --bs-btn-font-size: 0.875rem;
    --bs-btn-border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    line-height: 1.5;
    min-height: calc(1.5em + 0.5rem + 2px);
    font-weight: 500;
}

/* ---------- Pagination: compact phone bar ---------- */
/* Below sm the pager hides every numbered item (`d-none d-sm-block`) while
   Prev/Next keep chevron + text, so the bar sprawls over four rows with no
   page number in sight. On phones the layout is explicit, not flex-wrapped:
   row 1 is the info line (short page-size label + select + "Showing …"
   status), row 2 is the navigation (pager + quick-go). The full
   "Items per page" label swaps for the short "Per page" variant and the
   "Showing …" status drops its unit word, so row 1 fits the ~280px phone
   column. The chevrons are meaningful on their own, so Prev/Next text is
   visually hidden (spans stay for screen readers, links keep their
   aria-labels) and the numbers come back, tightened so a normal window fits
   its row (huge windows wrap inside the pager instead of pushing the page).
   The "Go to" label is dropped — the input keeps its aria-label — and the
   quick-go input shrinks to ~3 digits. No-op at sm and up. */
@media (max-width: 575.98px) {
    .portal-pagination {
        display: grid;
        grid-template-columns: 1fr auto;
        gap: 0.5rem;
        align-items: center;
    }
    .portal-pagination__info {
        grid-column: 1 / -1;
        margin-right: 0;
        gap: 0.5rem;
    }
    .portal-pagination__info .portal-pagination__showing {
        margin-left: auto;
    }
    .portal-pagination ul.pagination {
        grid-column: 1;
        min-width: 0;
        gap: 0.25rem;
    }
    .portal-pagination__goto {
        grid-column: 2;
    }
    .portal-pagination .pagination > .page-item:first-child .page-link > span,
    .portal-pagination .pagination > .page-item:last-child .page-link > span,
    .portal-pagination__info .portal-pagination__label--full {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }
    .portal-pagination__info .portal-pagination__label--short {
        display: block;
    }
    .portal-pagination .pagination > .page-item.d-none.d-sm-block {
        display: block !important;
    }
    .portal-pagination__goto label {
        display: none;
    }
    .portal-pagination .portal-pagination__select { min-width: 3.5rem; }
    .portal-pagination .portal-pagination__input { width: 2.75rem; }
}

/* White-label brand slot (docs/white-label-design.md §8): fixed 160x32 box
   matching the normalized upload; object-fit fill stretches like the server
   normalization so the preview matches the rendered chrome. */
.brand-logo {
    width: 160px;
    height: 32px;
    object-fit: fill;
    display: block;
}
.uf-brand .brand-logo { margin: 0 auto; }
.redesign-brand .brand-logo { display: inline-block; vertical-align: middle; }

/* Segmented control — unavailable option (kit uf-seg pattern, e.g. a submit
   mode the group's kind policy rejects). The segment stays in the pill so
   the control never breaks shape; it reads muted and cannot be chosen.
   `pointer-events` is restored (Bootstrap kills it on disabled labels) so
   the `title` reason still shows on hover — activating a disabled input is
   a browser no-op, so clicks remain safe. */
.uf-seg .btn-check:disabled + .uf-seg-btn {
  --bs-btn-color: var(--uf-text-3);
  --bs-btn-hover-color: var(--uf-text-3);
  --bs-btn-active-color: var(--uf-text-3);
  color: var(--uf-text-3);
  background: transparent;
  box-shadow: none;
  opacity: 0.6;
  pointer-events: auto;
  cursor: not-allowed;
}
.uf-seg .btn-check:disabled:checked + .uf-seg-btn {
  background: transparent;
  box-shadow: none;
}
