:root {
    /* Brand palette - DSL Standard Light (default theme) */
    --color-midnight:    #13223F;
    --color-tangerine:   #EE6123;
    --color-rice:        #FAF6EA;
    --color-sky-blue:    #9FC2D9;
    --color-royal-blue:  #849DE7;
    --color-excel-green: #1E7145;

    /* Semantic aliases */
    --color-primary:    var(--color-midnight);
    --color-secondary:  var(--color-tangerine);
    --color-accent-1:   var(--color-rice);
    --color-accent-2:   var(--color-sky-blue);
    --color-accent-3:   var(--color-royal-blue);

    /* RGB triplets so accent colours can be alpha-blended (borders, hover tints, focus
       glow) without hardcoding a hex per theme everywhere they're used. */
    --ink-rgb:             19, 34, 63;
    --color-secondary-rgb: 238, 97, 35;
    --color-accent-2-rgb:  159, 194, 217;
    --color-danger-rgb:    220, 53, 69;

    /* Surface tokens - these are what actually flips between light/dark themes. --ink-rgb
       doubles as the "readable ink" colour for whatever --color-surface/--color-bg the
       theme picks, so borders/hover tints/muted text all invert correctly for free. */
    --color-bg:      #f5f5f5;
    --color-surface: #ffffff;
    --color-text:    rgb(var(--ink-rgb));

    --nav-toggler-invert: 0;

    /* Filled buttons darken on hover in light themes, lighten in dark ones - a shade of
       their own colour rather than swapping to a different brand colour entirely. */
    --btn-hover-brightness: 0.85;
}

/* ── Theme: Dark Mode ─────────────────────────────────────────── */
[data-theme="dark"] {
    --color-midnight:    #24466F;
    --color-tangerine:   #EE6123;
    --color-rice:        #FAF6EA;
    --color-sky-blue:    #7FB3D3;
    --color-royal-blue:  #93A5EA;
    --color-excel-green: #2FBF71;

    --ink-rgb:             231, 236, 243;
    --color-secondary-rgb: 238, 97, 35;
    --color-accent-2-rgb:  127, 179, 211;
    --color-danger-rgb:    224, 108, 117;

    --color-bg:      #12181F;
    --color-surface: #1C232C;

    --nav-toggler-invert: 1;
    --btn-hover-brightness: 1.2;
}

/* ── Theme: Solar Dark Mode (Solarized Dark inspired) ────────────── */
[data-theme="solar-dark"] {
    /* Solarized's "blue" accent (#268BD2) only gives hardcoded white text (brand row,
       .btn-primary, modal headers - see the "light-on-dark" comments near .ambra-scan-user
       below) a ~3.8:1 contrast ratio, short of the 4.5:1 WCAG AA text minimum those
       elements assume from every other theme's much darker --color-midnight. Darkened here
       to ~5:1 while keeping the same hue. */
    --color-midnight:    #2075B1;
    --color-tangerine:   #CB4B16;
    --color-rice:        #FDF6E3;
    --color-sky-blue:    #2AA198;
    --color-royal-blue:  #6C71C4;
    --color-excel-green: #859900;

    --ink-rgb:             238, 232, 213;
    --color-secondary-rgb: 203, 75, 22;
    --color-accent-2-rgb:  42, 161, 152;
    --color-danger-rgb:    220, 50, 47;

    --color-bg:      #002B36;
    --color-surface: #073642;
    --color-text:    #93A1A1;

    --nav-toggler-invert: 1;
    --btn-hover-brightness: 1.2;
}

/* ── Theme: Solar Light Mode (Solarized Light inspired) ──────────── */
[data-theme="solar-light"] {
    /* Same contrast fix as solar-dark above - the brand row/.btn-primary/modal-header
       white text needs this darker than Solarized's stock "blue" accent regardless of
       how light the rest of this theme's surfaces are. */
    --color-midnight:    #2075B1;
    --color-tangerine:   #CB4B16;
    --color-rice:        #FDF6E3;
    --color-sky-blue:    #2AA198;
    --color-royal-blue:  #6C71C4;
    --color-excel-green: #859900;

    --ink-rgb:             88, 110, 117;
    --color-secondary-rgb: 203, 75, 22;
    --color-accent-2-rgb:  42, 161, 152;
    --color-danger-rgb:    220, 50, 47;

    --color-bg:      #FDF6E3;
    --color-surface: #ffffff;
    --color-text:    #586E75;

    --nav-toggler-invert: 0;
    --btn-hover-brightness: 0.85;
}

body {
    background-color: var(--color-bg);
    color: var(--color-text);
}

/* ── Generic Bootstrap component theming ─────────────────────────
   Bootstrap's own component colours (card, form-control, alert) are baked in at
   compile time and don't follow our custom properties, so they need explicit
   overrides here to track the active theme. */
.card {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-color: rgba(var(--ink-rgb), 0.1);
}

.form-control,
.form-select {
    background-color: var(--color-surface);
    color: var(--color-text);
    border: 1px solid rgba(var(--ink-rgb), 0.25);
}

/* Bootstrap hardcodes this select's caret as a fixed-grey background-image (it only
   reacts to its own [data-bs-theme] attribute, which this site never sets - themes here
   switch via [data-theme] instead), so the arrow stayed stuck on Bootstrap's default
   colour. Re-drawn with stroke="currentColor" so it follows the select's own `color`
   (set to --color-text above) and repaints with every theme. Overriding the property
   directly rather than a Bootstrap CSS variable, since Bootstrap doesn't route this
   particular background-image through one. */
.form-select {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
}

.form-control:focus,
.form-select:focus {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-secondary);
    box-shadow: 0 0 0 0.2rem rgba(var(--color-secondary-rgb), 0.15);
}

/* Bootstrap's disabled/readonly form-control background is a hardcoded light grey
   (--bs-secondary-bg) that never tracks [data-theme] - combined with our --color-text
   override above (light ink in dark/solar-dark), that left disabled fields showing
   near-white text on a near-white background. Themed the same way as the muted
   .ambra-nav-select:disabled treatment above. */
.form-control:disabled,
.form-control[readonly],
.form-select:disabled {
    background-color: rgba(var(--ink-rgb), 0.06);
    color: var(--color-text);
    opacity: 0.7;
}

/* Bootstrap's placeholder colour (--bs-secondary-color) is a fixed dark grey that only
   reacts to Bootstrap's own [data-bs-theme], which this site never sets - so every
   search box's placeholder (Admin/*.aspx txtSearch, default.aspx, Login.aspx) stayed
   that fixed dark grey regardless of theme, going near-invisible against the dark/
   solar-dark surfaces. Same muted-ink convention as .ambra-admin-hint/.ambra-login-subtitle. */
.form-control::placeholder {
    color: rgba(var(--ink-rgb), 0.55);
    opacity: 1;
}

/* Bootstrap's own --bs-body-color (a fixed dark grey, never themed) is what
   .form-control-plaintext uses for its text colour - it happened to still read fine in
   the light theme's white surfaces, but goes dark-on-dark in dark/solar-dark's surfaces
   (e.g. the read-only Created/Modified labels used all over the admin pages, and
   default.aspx's Job Details modal). */
.form-control-plaintext {
    color: var(--color-text);
}

/* default.aspx's Job Details modal (#jobDetailModal) otherwise stayed Bootstrap's
   default white/dark-text regardless of the active theme, clashing with the
   already-themed .ambra-admin-card content rendered inside it. */
.modal-content {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-color: rgba(var(--ink-rgb), 0.1);
}

.modal-header,
.modal-footer {
    border-color: rgba(var(--ink-rgb), 0.1);
}

/* Every modal footer in this app already lists its Cancel/No button first, then its
   Save/Yes/other action button(s) - Bootstrap's own .modal-footer is flex with
   justify-content:flex-end by default though, which just clusters all of them together on
   the right rather than putting Cancel on the opposite side. This pushes the first button
   to the left edge instead, but only when there's actually something else in the footer to
   separate it from - a modal with just one button (e.g. a plain "Close") stays right-aligned,
   since :not(:only-child) excludes it. */
.modal-footer > .btn:first-child:not(:only-child) {
    margin-right: auto;
}

/* Bootstrap's close button is a hardcoded dark SVG (via background-image, not a
   currentColor stroke) that only reacts to Bootstrap's own [data-bs-theme], which this
   site never sets - themes switch via [data-theme] instead - so without this it stays
   dark and nearly invisible against a dark modal header. Same fix as the navbar
   toggler icon below. */
.btn-close {
    filter: invert(var(--nav-toggler-invert, 0));
}

.alert-info {
    background-color: rgba(var(--color-accent-2-rgb), 0.15);
    border-color: rgba(var(--color-accent-2-rgb), 0.3);
    color: var(--color-text);
}

.alert-warning {
    background-color: rgba(var(--color-secondary-rgb), 0.15);
    border-color: rgba(var(--color-secondary-rgb), 0.3);
    color: var(--color-text);
}

.alert-danger {
    background-color: rgba(var(--color-danger-rgb), 0.15);
    border-color: rgba(var(--color-danger-rgb), 0.3);
    color: var(--color-text);
}

.dropdown-menu {
    background-color: var(--color-surface);
    color: var(--color-text);
    border: 1px solid rgba(var(--ink-rgb), 0.08);
    border-radius: 0.5rem;
    box-shadow: 0 0.75rem 1.5rem rgba(0, 0, 0, 0.15);
    padding: 0.4rem;
    margin-top: 0.5rem;
}

.dropdown-item {
    color: var(--color-text);
    font-size: 0.85rem;
    padding: 0.5rem 1rem;
    border-radius: 0.35rem;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.dropdown-item:hover,
.dropdown-item:focus {
    background-color: rgba(var(--color-secondary-rgb), 0.12);
    color: var(--color-secondary);
}

.ambra-body {
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    padding-bottom: env(safe-area-inset-bottom);
    overflow-x: hidden;
}

/* ── Login page ───────────────────────────────────────────────── */
.ambra-login-body {
    min-height: 100vh;
    background-color: var(--color-bg);
}

.ambra-login-card {
    margin-top: 3rem;
    background-color: var(--color-surface);
    color: var(--color-text);
    border: 1px solid rgba(var(--ink-rgb), 0.1);
    border-top: 3px solid var(--color-secondary);
    border-radius: 0.5rem;
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.1);
}

.ambra-login-title {
    color: var(--color-text);
    font-weight: 700;
}

.ambra-login-subtitle {
    color: rgba(var(--ink-rgb), 0.6);
    font-size: 0.875rem;
}

.ambra-login-input:focus {
    border-color: var(--color-secondary);
    box-shadow: 0 0 0 0.2rem rgba(var(--color-secondary-rgb), 0.15);
}

/* MFA code entry (Login.aspx's ambraSetupOtpInput) - one box per digit rather than a
   single free-text field. */
.ambra-otp-group {
    display: flex;
    gap: 0.5rem;
    justify-content: center;
}

/* flex-basis 3rem/max-width 3rem keep this at its original fixed size whenever the card is
   wide enough to fit all 6 boxes plus gaps (desktop/tablet) - flex-shrink (the default,
   unset here) only kicks in once the row's natural width would exceed .ambra-otp-group's
   own, at which point every box shrinks together rather than the row overflowing outside
   the card. min-width is the floor that stops them shrinking past a legible/tappable size
   on the narrowest phones. */
.ambra-otp-digit {
    flex: 1 1 3rem;
    min-width: 2rem;
    max-width: 3rem;
    height: 3.25rem;
    padding: 0;
    text-align: center;
    font-size: 1.5rem;
    font-weight: 600;
}

.btn-secondary {
    background-color: var(--color-secondary);
    border-color: var(--color-secondary);
    color: #fff;
    font-weight: 600;
    padding: 0.6rem 0;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.btn-secondary:hover,
.btn-secondary:focus {
    filter: brightness(var(--btn-hover-brightness));
    background-color: var(--color-secondary);
    border-color: var(--color-secondary);
    color: #fff;
}

/* ── Admin CRUD pages ─────────────────────────────────────────── */
.ambra-admin-card {
    background-color: var(--color-surface);
    color: var(--color-text);
    border: 1px solid rgba(var(--ink-rgb), 0.1);
    border-left: 3px solid var(--color-secondary);
    border-radius: 0.5rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.08);
    font-size: 0.875rem;
}

/* The left-hand commands column (Add/search/filters) - stays put while the grid scrolls */
.ambra-commands-card {
    background-color: rgba(var(--ink-rgb), 0.06);
}

/* Tablets/small laptops (col-lg-4 commands + col-lg-8 grid) get the side-by-side
   layout too, rather than staying fully stacked all the way up to xl - only large
   desktops need the extra-narrow sidebar carved out below. */
@media (min-width: 992px) {
    .ambra-commands-card {
        position: sticky;
        top: 1rem;
    }
}

@media (min-width: 992px) {
    /* Fixed width rather than a percentage (col-lg-4/col-xl-3's 33%/25% were both too
       wide) - the column shouldn't keep growing as the viewport widens, it should just
       stay a constant, comfortable size from this breakpoint up. */
    .ambra-commands-col {
        flex: 0 0 auto;
        width: 250px;
    }

    /* The content column's own col-lg-8/col-xl-9 computed its width as a fraction of the
       row, entirely independent of .ambra-commands-col's fixed 250px next to it - the
       two didn't add up, so the content column would either leave the sidebar's freed-up
       space sitting unused, or (worse) visibly snap narrower right at the lg/xl
       breakpoints even though the sidebar's own width hadn't changed at all. flex:1
       instead makes it claim exactly whatever's left beside the sidebar, growing/
       shrinking continuously with the viewport with no jumps. min-width:0 overrides a
       flex item's default (content's own min-content width, i.e. never smaller than its
       widest un-wrappable child) - without it a wide grid inside would push this column
       wider than the space actually available instead of leaving that overflow to its
       own .table-responsive's horizontal scroll. */
    .ambra-content-col {
        flex: 1 1 0;
        min-width: 0;
    }
}

.ambra-admin-card .card-title {
    font-size: 1rem;
}

.ambra-admin-card .form-label {
    font-size: 0.8rem;
    font-weight: 500;
    margin-bottom: 0.25rem;
    color: var(--color-text);
}

/* Compact inputs - the 44px touch target elsewhere in the app is overkill for a dense
   admin form used mostly on desktop, so scale these back down. The extra ".card"
   qualifier (every .ambra-admin-card is also a .card) bumps this to 3 classes' worth of
   specificity - .ambra-page-main .form-control (2 classes, declared later in this file)
   would otherwise win the tie on source order alone and put min-height/font-size right
   back to the 44px touch-target values this is trying to override. */
.ambra-admin-card.card .form-control,
.ambra-admin-card.card .form-select {
    min-height: 0;
    font-size: 0.8rem;
}

.ambra-admin-card .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    font-size: 0.85rem;
    padding: 0.4rem 0.9rem;
}

/* Self-drawn checkbox: reset native/Bootstrap rendering entirely so there's no chance of
   a native box showing through underneath the styled one ("ghost checkbox"). */
.ambra-admin-card .form-check {
    min-height: 0;
    display: flex;
    align-items: center;
}

/* padding-left is scoped away from .form-switch specifically - it has higher specificity
   than Bootstrap's own ".form-switch { padding-left: 2.5em; }" (two classes vs one) and
   would otherwise override it, misaligning the switch's slider track. */
.ambra-admin-card .form-check:not(.form-switch) {
    padding-left: 1.5rem;
}

/* Every non-grid checkbox in the app is now a switch (see .ambra-switch-lg below) - this
   just themes Bootstrap's own slider/track colour to the app's accent instead of its
   default blue, rather than replacing the shape/track the way the old square-checkbox
   look (.ambra-checkbox-input, removed) used to. */
.ambra-admin-card .form-switch .form-check-input:checked {
    background-color: var(--color-secondary);
    border-color: var(--color-secondary);
}

/* Bootstrap sizes a switch entirely in em (width: 2em, height: 1em, etc.), all relative to
   its own font-size - bumping that here scales the whole slider proportionally, rather than
   overriding each dimension by hand. Explicit opt-in class for any switch outside an
   .ambra-admin-card (e.g. Preferences.aspx's .ambra-login-card) - switches inside an
   .ambra-admin-card already get the same size from the rule below regardless of whether
   this class is also present, but every switch across the app carries it either way, for
   one consistent, explicit "this is a large switch" marker in the markup. */
.ambra-switch-lg {
    font-size: 1.5rem;
}

/* Bootstrap sizes a switch's track/thumb/padding entirely in em units relative to the
   .form-switch element's own font-size, so bumping it here scales the whole switch
   together rather than fiddling with width/height/border-radius individually. The label
   below keeps its own explicit font-size, which wins over this inherited value, so only
   the switch itself grows - not its text. */
.ambra-admin-card .form-switch {
    font-size: 1.5rem;
}

.ambra-admin-card .form-check-label {
    font-size: 0.85rem;
    margin-left: 0.4rem;
}

.ambra-admin-hint {
    font-size: 0.8rem;
    color: rgba(var(--ink-rgb), 0.55);
}

/* Scan.aspx's PickRunNote column - the "more"/"less" toggle (see the inline script in
   Scan.aspx) reads as a small secondary action, not a full-weight link. */
.ambra-note-more-link {
    font-size: 0.8rem;
    white-space: nowrap;
}

/* Rounds and clips the table to match the card it sits in, since a plain <table>
   inside a card body otherwise looks like it's just been dropped in unstyled. */
.ambra-admin-card .table-responsive {
    border-radius: 0.5rem;
    overflow: hidden;
}

/* Grid and form cards should hug their content's natural width rather than stretching
   to fill the whole column - Bootstrap's .card/.table default to width: 100%, so both
   need overriding here, with the card-body padding left alone. */
.ambra-fit-card {
    display: inline-block;
    width: auto;
    max-width: 100%;
}

.ambra-fit-card .table {
    width: auto;
}

/* Add/Edit form rows - col-12 fields + Bootstrap's width:100% form-control mean the row
   has no natural "fit" width of its own, so without this it stretches to fill the whole
   card instead of just being as wide as a form field actually needs to be. */
.ambra-fit-card .row.g-3 {
    max-width: 420px;
}

/* Process/Job.aspx's Job Details/Address/Job Packages/Job Documents cards - fixed width
   so they sit compactly side by side rather than growing to fill the row like Job
   Lines/Api Logs below. */
.ambra-job-info-card {
    width: 320px;
    max-width: 100%;
}

/* Process/Job.aspx's Api Logs card - unlike the fixed-width cards above, this is a data
   grid where a row or two of data has no meaningful natural width, so instead it grows
   to fill whatever's left in the row (350px minimum, same flex-wrap row as the cards
   above) rather than sitting at a fixed size. */
.ambra-grid-card {
    flex: 1 1 350px;
}

/* Admin/ProductivityReport.aspx's chart cards - each holds one Chart.js <canvas>, sized
   consistently so several charts wrap into a tidy grid instead of each fighting for its
   own arbitrary width. The canvas height cap keeps Chart.js's own responsive resizing
   from growing a chart taller than its card looks good at. */
.ambra-chart-card {
    flex: 1 1 420px;
    max-width: 100%;
}
.ambra-chart-card canvas {
    max-height: 320px;
}

/* Admin/ProductivityReport.aspx's own banner - deliberately loud (hazard-yellow, dashed
   border, pulsing glow) rather than a normal muted Bootstrap alert, so it can't be missed
   or mistaken for a routine notice while this report is still being built. */
.ambra-under-construction-banner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 0.9rem 1.25rem;
    font-size: 1.1rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    text-align: center;
    color: #212529;
    background-color: #ffc107;
    border: 3px dashed #212529;
    border-radius: 0.5rem;
    animation: ambra-under-construction-pulse 1.6s ease-in-out infinite;
}

.ambra-under-construction-banner i {
    font-size: 1.4rem;
    flex-shrink: 0;
}

@keyframes ambra-under-construction-pulse {
    0%, 100% {
        box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.6);
    }
    50% {
        box-shadow: 0 0 0 10px rgba(255, 193, 7, 0);
    }
}

/* Pick Run Performance's own stat card (Duration/Items per Hour/etc.) - sits in
   .ambra-content-col (which doesn't shrink-to-fit, unlike ScanProcess.aspx's
   .ambra-fit-card), so without a cap it stretches to the column's full width. */
.ambra-pickrun-measurement-card {
    max-width: 700px;
}

.ambra-grid-table {
    /* Bootstrap's table variables default to its own --bs-body-bg/--bs-emphasis-color,
       not our theme tokens - reset them here so nothing slips through un-themed even
       where we don't set an explicit background-color/color below. */
    --bs-table-bg: var(--color-surface);
    --bs-table-color: var(--color-text);
    --bs-table-accent-bg: transparent;
    --bs-table-striped-bg: rgba(var(--color-accent-2-rgb), 0.08);
    --bs-table-striped-color: var(--color-text);
    --bs-table-hover-bg: rgba(var(--color-secondary-rgb), 0.08);
    --bs-table-hover-color: var(--color-text);
    --bs-table-active-bg: rgba(var(--color-secondary-rgb), 0.14);
    --bs-table-active-color: var(--color-text);
    --bs-table-border-color: rgba(var(--ink-rgb), 0.08);
    font-size: 0.85rem;
    margin-bottom: 0;
    border-collapse: separate;
    border-spacing: 0;
}

/* Targets bare "th" rather than "thead th" - GridView doesn't reliably wrap its header
   row in an actual <thead> element, but header cells are always <th> (data cells are
   always <td>), so this matches regardless of the exact markup GridView emits. */
.ambra-grid-table th {
    background-color: rgba(var(--ink-rgb), 0.06) !important;
    color: var(--color-text);
    border: none;
    border-bottom: 2px solid var(--color-accent-3);
    border-right: 1px solid rgba(var(--ink-rgb), 0.1);
    font-weight: 700;
    font-size: 0.8rem;
    white-space: nowrap;
    padding: 0.5rem 0.9rem;
    vertical-align: top;
}

.ambra-grid-table th:last-child {
    border-right: none;
}

.ambra-grid-table tbody td {
    background-color: var(--color-surface);
    vertical-align: top;
    padding: 0.35rem 0.9rem;
    border-top: none;
    border-bottom: 1px solid rgba(var(--ink-rgb), 0.08);
    border-right: 1px solid rgba(var(--ink-rgb), 0.08);
    color: rgba(var(--ink-rgb), 0.85);
}

.ambra-grid-table tbody td:last-child {
    border-right: none;
}

.ambra-grid-table tbody tr:last-child td {
    border-bottom: none;
}

/* Zebra striping and hover, tuned to the palette instead of Bootstrap's grey default */
.ambra-grid-table tbody tr:nth-of-type(even) td {
    background-color: rgba(var(--color-accent-2-rgb), 0.08);
}

.ambra-grid-table.table-hover tbody tr:hover td {
    background-color: rgba(var(--color-secondary-rgb), 0.08);
}

/* Rows selected via the checkbox column (click, shift-click range, or select-all) */
.ambra-grid-table tbody tr.grid-row-highlight td {
    background-color: rgba(var(--color-secondary-rgb), 0.14) !important;
}

/* Related Jobs grid's Status cell when that job is in Error - reuses the same
   accent-as-danger-colour convention as .ambra-row-icon-danger elsewhere, rather than
   introducing an unthemed red that wouldn't track the light/dark/solarized switches.
   !important for the same reason as grid-row-highlight above - it must win over the
   table's own hover background. */
.ambra-status-error-cell {
    background-color: rgba(var(--color-secondary-rgb), 0.18) !important;
    color: var(--color-secondary);
    font-weight: 600;
}

/* Sortable column headers (AllowSorting renders each header as a LinkButton) */
.ambra-grid-table th a {
    color: inherit;
    text-decoration: none;
    display: inline-block;
}

.ambra-grid-table th a:hover {
    color: var(--color-secondary);
    text-decoration: underline;
}

/* Ascending/descending indicator appended to the currently-sorted column's header link */
.ambra-sort-icon {
    margin-left: 0.3rem;
    color: var(--color-secondary);
    font-size: 0.7rem;
    vertical-align: 1px;
}

/* First data column rendered as a link (same content, now clickable) - opens the same
   edit view as the row's Edit icon action. */
.ambra-row-link {
    color: var(--color-text);
    font-weight: 600;
    text-decoration: none;
}

.ambra-row-link:hover,
.ambra-row-link:focus {
    color: var(--color-secondary);
    text-decoration: underline;
}

/* Selection checkbox column - same self-drawn checkbox treatment used in forms/grids
   elsewhere, so there's no native/ghost checkbox mismatch. Not scoped to .ambra-grid-table
   specifically - the mobile card view (.ambra-grid-mobile-card-select below) reuses this
   same look for its own selection checkbox, rather than a native browser checkbox. */
.grid-checkbox {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    width: 1rem;
    height: 1rem;
    margin: 0;
    border: 1px solid rgba(var(--ink-rgb), 0.35);
    border-radius: 0.25rem;
    background-color: var(--color-surface);
    background-repeat: no-repeat;
    background-position: center;
    background-size: 0.7rem;
    vertical-align: middle;
    cursor: pointer;
}

.grid-checkbox:checked {
    background-color: var(--color-secondary);
    border-color: var(--color-secondary);
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M13.64 3.64 6 11.28 2.36 7.64 3.64 6.36 6 8.72l6.36-6.36 1.28 1.28Z'/%3e%3c/svg%3e");
}

/* Row actions (Edit/Delete/Revoke) - bare icons, no button chrome, so rows stay short.
   The icon's tooltip/aria-label carries the label that used to be visible button text. */
.ambra-row-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 0.35rem;
    color: var(--color-text);
    opacity: 0.65;
    text-decoration: none;
    transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

.ambra-row-icon .bi {
    font-size: 0.9rem;
}

.ambra-row-icon:hover,
.ambra-row-icon:focus {
    opacity: 1;
    color: var(--color-primary);
    background-color: rgba(var(--ink-rgb), 0.08);
}

.ambra-row-icon.ambra-row-icon-danger:hover,
.ambra-row-icon.ambra-row-icon-danger:focus {
    color: var(--color-secondary);
    background-color: rgba(var(--color-secondary-rgb), 0.12);
}

/* asp:LinkButton with Enabled=false doesn't render a disabled attribute the way
   asp:Button does - it just drops the href and prints plain text, with no built-in
   visual cue. This class is toggled in code-behind alongside Enabled wherever an
   .ambra-row-icon LinkButton can become non-interactive (e.g. jobDetailModal's
   Previous/Next), mirroring .ambra-pager-arrow.disabled below. */
.ambra-row-icon.disabled {
    opacity: 0.3;
    pointer-events: none;
}

/* asp:CheckBoxField in a GridView renders a bare, completely unstyled native
   <input type="checkbox" disabled>, with no .form-check-input class to hook into -
   this is what was actually showing as an unstyled "ghost" checkbox in the grid. */
.ambra-grid-table input[type="checkbox"] {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    width: 1rem;
    height: 1rem;
    margin: 0;
    border: 1px solid rgba(var(--ink-rgb), 0.35);
    border-radius: 0.25rem;
    background-color: var(--color-surface);
    background-repeat: no-repeat;
    background-position: center;
    background-size: 0.7rem;
    vertical-align: middle;
}

.ambra-grid-table input[type="checkbox"]:checked {
    background-color: var(--color-secondary);
    border-color: var(--color-secondary);
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M13.64 3.64 6 11.28 2.36 7.64 3.64 6.36 6 8.72l6.36-6.36 1.28 1.28Z'/%3e%3c/svg%3e");
}

.ambra-grid-table input[type="checkbox"]:disabled {
    opacity: 0.85;
    cursor: default;
}

/* ── Brand row ────────────────────────────────────────────────── */
/* Mobile: single row, brand left / account right (space-between) */
.ambra-brand-row-inner {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    padding-top: calc(0.5rem + env(safe-area-inset-top));
    position: relative;
}

/* Replaces the old "Ambra" brand link/spacer pair - a link to Preferences.aspx showing the
   current Organisation and Print Profile (each with the same icon used for it on
   Preferences.aspx's own dropdowns), rather than a static logo. */
.ambra-org-printagent-link {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 1rem;
    color: var(--color-accent-1);
    text-decoration: none;
    flex: 1 1 auto;
    min-width: 0;
}

.ambra-org-printagent-link:hover {
    color: var(--color-accent-1);
    text-decoration: underline;
}

.ambra-org-printagent-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.9rem;
    font-weight: 600;
    white-space: nowrap;
}

.ambra-org-printagent-item .bi {
    opacity: 0.75;
}

.ambra-brand {
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--color-accent-1);
    flex: 0 0 auto;
    text-decoration: none;
}

.ambra-brand:hover {
    color: var(--color-accent-1);
    text-decoration: none;
}

/* Non-Production flag (Site.Master.cs's EnvironmentName / Login.aspx.cs's own copy) -
   deliberately a plain caution yellow/black rather than any of the site's own theme
   colours, so it reads as "this isn't the real thing" at a glance regardless of theme. */
.ambra-env-badge {
    background-color: #ffc107;
    color: #000;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 0.3rem 0.6rem;
    border-radius: 999px;
    flex: 0 0 auto;
}

.ambra-brand-account {
    flex-wrap: nowrap;
    justify-content: flex-end;
}

@media (min-width: 992px) {
    .ambra-brand-row-inner {
        flex-direction: row;
        justify-content: space-between;
    }

    .ambra-brand-account {
        flex: 1 1 0;
        justify-content: flex-end;
    }

    /* Centered independently of the flow - lnkOrgPrintAgent/the account controls on
       either side aren't the same width, so a plain flex/space-between order would
       leave this off-center. Scoped to the brand row specifically - .ambra-brand is
       also reused (unpositioned) by Login.aspx's own top bar, which must keep its
       normal in-flow layout. */
    .ambra-brand-row-inner .ambra-brand {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }
}

/* ── Navigation row ───────────────────────────────────────────── */
.ambra-nav {
    background-color: var(--color-surface);
    border-top: 2px solid var(--color-secondary);
    border-bottom: 1px solid rgba(var(--ink-rgb), 0.1);
}

/* Bootstrap's navbar-light toggler icon is a hardcoded dark SVG - invert it for dark
   themes so it stays visible against a dark nav background. */
.ambra-nav .navbar-toggler-icon {
    filter: invert(var(--nav-toggler-invert, 0));
}

/* Every tap target in the nav meets the 44px minimum touch size, for handheld/tablet use */
.ambra-nav .nav-link,
.ambra-nav .btn {
    min-height: 44px;
    display: flex;
    align-items: center;
}

/* Bootstrap already hides .navbar-toggler at the navbar-expand-lg breakpoint and up -
   only set sizing here, never touch display, or it'll show at every width. */
.ambra-nav .navbar-toggler {
    min-height: 44px;
    padding: 0.5rem 0.65rem;
}

.ambra-nav .nav-link {
    color: var(--color-text);
    font-size: 0.875rem;
    font-weight: 500;
    padding: 0.5rem 0.85rem;
    transition: color 0.15s ease;
}

.ambra-nav .nav-link:hover,
.ambra-nav .nav-link.active,
.ambra-nav .nav-link.show {
    color: var(--color-secondary);
}

.ambra-nav .dropdown-toggle::after {
    opacity: 0.6;
}

/* Mobile: dropdown is inline within the collapsed menu, not a floating popup - style it
   as a flat, indented sub-list rather than a boxed card that doesn't fit that context. */
@media (max-width: 991.98px) {
    .ambra-nav .dropdown-menu {
        position: static;
        border: none;
        box-shadow: none;
        background: transparent;
        padding: 0.25rem 0 0.25rem 1rem;
        margin: 0;
        border-left: 2px solid rgba(var(--ink-rgb), 0.1);
    }

    .ambra-nav .dropdown-item {
        padding: 0.6rem 0.75rem;
    }
}

.ambra-nav-account {
    border-top: 1px solid rgba(var(--ink-rgb), 0.08);
    padding-top: 0.75rem;
}

/* Icon + <select> pair - a bare <select> can't host an icon itself, so the icon sits
   beside it and the group (not the select) owns the width/responsive behaviour. */
.ambra-nav-select-group {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
}

.ambra-nav-select-group .bi {
    flex-shrink: 0;
    font-size: 0.9rem;
    color: var(--color-text);
    opacity: 0.6;
}

.ambra-nav-select-group .ambra-nav-select-label {
    flex-shrink: 0;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--color-text);
    opacity: 0.7;
    white-space: nowrap;
}

.ambra-nav-select {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--color-text);
    background-color: rgba(var(--ink-rgb), 0.06);
    border: 1px solid transparent;
    min-height: 36px;
}

.ambra-nav-select:focus {
    border-color: var(--color-secondary);
    box-shadow: 0 0 0 0.2rem rgba(var(--color-secondary-rgb), 0.15);
}

.ambra-nav-select:disabled {
    opacity: 0.7;
    background-color: rgba(var(--ink-rgb), 0.04);
}

/* Page-size selects live inside .ambra-admin-card, whose compact input padding above
   leaves no room for the native <select> caret - restore it here so the value doesn't
   render underneath the arrow. */
.ambra-admin-card .ambra-nav-select {
    padding-right: 1.75rem;
}

.ambra-total-count {
    font-size: 0.85rem;
    color: var(--color-text);
    opacity: 0.65;
}

/* Custom numeric pager with prev/next arrows - GridView's built-in PagerSettings.Mode
   can render numeric links or next/previous arrows, but never both together. */
.ambra-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.25rem;
    padding: 0.5rem 0 0;
}

.ambra-pager-arrow,
.ambra-pager-page {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    padding: 0 0.5rem;
    border-radius: 6px;
    color: var(--color-text);
    text-decoration: none;
    font-size: 0.85rem;
}

.ambra-pager-arrow:hover,
.ambra-pager-page:hover {
    background-color: rgba(var(--ink-rgb), 0.08);
    text-decoration: none;
}

.ambra-pager-page.active {
    background-color: var(--color-secondary);
    color: #fff;
    font-weight: 600;
}

.ambra-pager-arrow.disabled {
    opacity: 0.3;
    pointer-events: none;
}

/* The pager row is still a plain <tr> in the same <table class="table-hover">, so
   Bootstrap's row-hover tint would otherwise wash over the pager buttons too. Rather than
   relying on GridView's PagerStyle CssClass actually landing on the <tr> for a templated
   pager (unconfirmed, and the previous class-based attempts at this had no visible effect),
   this targets the row structurally via :has() against the .ambra-pager div that's always
   present in the PagerTemplate markup itself - so it doesn't depend on that class at all.
   Covers every way Bootstrap 5.3 might paint the tint (background, background-image, and
   the inset box-shadow it actually uses) since which one applies wasn't the real problem. */
.ambra-grid-table tr:has(.ambra-pager) {
    background-color: transparent !important;
}

.ambra-grid-table tr:has(.ambra-pager) > * {
    background-color: transparent !important;
    background-image: none !important;
    box-shadow: none !important;
    color: inherit !important;
}

/* Stacked "mobile card" alternative to a wide grid table on narrow viewports.
   Opt-in per page: only takes effect when the page's own markup includes the
   sibling .ambra-grid-mobile-cards block immediately after .table-responsive -
   pages that don't add one are completely unaffected (the :has() below never matches). */
.ambra-grid-mobile-cards {
    display: none;
}

.ambra-grid-mobile-card {
    border: 1px solid rgba(var(--ink-rgb), 0.15);
    border-radius: 0.5rem;
    padding: 0.75rem 0.9rem;
    margin-bottom: 0.6rem;
    background-color: var(--color-surface);
}

.ambra-grid-mobile-card:last-child {
    margin-bottom: 0;
}

.ambra-grid-mobile-card-row {
    display: flex;
    gap: 0.5rem;
    padding: 0.15rem 0;
}

.ambra-grid-mobile-card-label {
    flex: 0 0 auto;
    min-width: 100px;
    font-weight: 600;
    font-size: 0.8rem;
    color: rgba(var(--ink-rgb), 0.65);
}

.ambra-grid-mobile-card-value {
    flex: 1 1 auto;
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

/* Row actions (Edit/View/Delete etc.) render as real buttons on their own full-width row,
   rather than another label/value pair - there's no label for an actions row. */
.ambra-grid-mobile-card-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid rgba(var(--ink-rgb), 0.1);
}

/* Selection checkbox at the top of a card (see rptErrorLogsCards) - the same self-drawn
   .grid-checkbox look used in every grid's selection column, just sized up a touch for an
   easier tap target on a phone. Switches (.ambra-switch-lg) are reserved for the commands
   panel/search filters elsewhere - grid row selection is always a checkbox, table or card. */
.ambra-grid-mobile-card-select {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
}

.ambra-grid-mobile-card-select .grid-checkbox {
    width: 1.25rem;
    height: 1.25rem;
}

/* Selecting a card highlights the whole thing (mirrors .grid-row-highlight's desktop
   table-row tint) - much easier to see at a glance on a phone than a small checked box. */
.ambra-grid-mobile-card.grid-row-highlight {
    background-color: rgba(var(--color-secondary-rgb), 0.14);
    border-color: var(--color-secondary);
}

@media (max-width: 575.98px) {
    /* A paged grid's First/Prev/page-numbers/Next/Last controls (.ambra-pager) render as
       just another <tr> inside the SAME <table> as the data (PagerTemplate, PagerSettings-
       Position="Top") - simply hiding the whole table would take the pager down with it,
       leaving mobile with no way to reach page 2+. So: if the table has no pager at all,
       hide the whole thing as before (same as always); if it does have one, keep the
       wrapper and hide every row except the one containing .ambra-pager, so paging still
       works from the cards below - the header row is deliberately included in "every row"
       here rather than singled out, since GridView doesn't reliably wrap it in an actual
       <thead> element (see the .ambra-grid-table th comment below), so there's no single
       reliable selector for "just the header" to exclude. */
    .table-responsive:has(+ .ambra-grid-mobile-cards):not(:has(.ambra-pager)) {
        display: none;
    }

    .table-responsive:has(+ .ambra-grid-mobile-cards):has(.ambra-pager) .ambra-grid-table tr:not(:has(.ambra-pager)) {
        display: none;
    }

    .ambra-grid-mobile-cards {
        display: block;
    }

    /* .ambra-fit-card normally shrinks to the table's own width (see .ambra-fit-card
       above) - once the table is hidden in favour of the mobile cards, that shrink-to-fit
       sizing just leaves the card (and the cards inside it) narrower than the viewport, so
       a grid's fit-card specifically (identified by containing .ambra-grid-mobile-cards,
       not every .ambra-fit-card - e.g. Add/Edit form cards elsewhere keep their own sizing)
       goes full width instead. */
    .ambra-fit-card:has(.ambra-grid-mobile-cards) {
        display: block;
        width: 100%;
    }
}

@media (min-width: 992px) {
    .ambra-nav-select-group {
        width: auto;
        max-width: 220px;
    }

    .ambra-nav-account {
        border-top: none;
        padding-top: 0;
    }

    .ambra-nav .nav-link,
    .ambra-nav .btn {
        min-height: 0;
    }
}

/* ── Background utilities ─────────────────────────────────────── */
.bg-primary     { background-color: var(--color-primary)    !important; }
.bg-secondary   { background-color: var(--color-secondary)  !important; }
.bg-accent-1    { background-color: var(--color-accent-1)   !important; }
.bg-accent-2    { background-color: var(--color-accent-2)   !important; }
.bg-accent-3    { background-color: var(--color-accent-3)   !important; }

/* ── Text utilities ───────────────────────────────────────────── */
.text-primary   { color: var(--color-primary)    !important; }
.text-secondary { color: var(--color-secondary)  !important; }
.text-accent-1  { color: var(--color-accent-1)   !important; }
.text-accent-2  { color: var(--color-accent-2)   !important; }
.text-accent-3  { color: var(--color-accent-3)   !important; }

/* ── Border utilities ─────────────────────────────────────────── */
.border-primary   { border-color: var(--color-primary)    !important; }
.border-secondary { border-color: var(--color-secondary)  !important; }
.border-accent-1  { border-color: var(--color-accent-1)   !important; }
.border-accent-2  { border-color: var(--color-accent-2)   !important; }
.border-accent-3  { border-color: var(--color-accent-3)   !important; }

/* ── Fill utilities (SVG / icons) ─────────────────────────────── */
.fill-primary   { fill: var(--color-primary)    !important; }
.fill-secondary { fill: var(--color-secondary)  !important; }
.fill-accent-1  { fill: var(--color-accent-1)   !important; }
.fill-accent-2  { fill: var(--color-accent-2)   !important; }
.fill-accent-3  { fill: var(--color-accent-3)   !important; }

/* ── Outline button variants ──────────────────────────────────── */
.btn-outline-primary {
    color: var(--color-text);
    border: 1px solid var(--color-text);
    background-color: transparent;
}
.btn-outline-primary:hover {
    background-color: var(--color-primary);
    color: var(--color-accent-1);
}

.btn-outline-secondary {
    color: var(--color-secondary);
    border: 1px solid var(--color-secondary);
    background-color: transparent;
}
.btn-outline-secondary:hover {
    background-color: var(--color-secondary);
    color: #fff;
}

.btn-outline-export {
    color: var(--color-excel-green);
    border: 1px solid var(--color-excel-green);
    background-color: transparent;
}
.btn-outline-export:hover {
    background-color: var(--color-excel-green);
    color: #fff;
}

/* ── Filled button variants ───────────────────────────────────── */
.btn-primary {
    background-color: var(--color-primary);
    border: 1px solid var(--color-primary);
    color: #fff;
}
.btn-primary:hover,
.btn-primary:focus {
    filter: brightness(var(--btn-hover-brightness));
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

.btn-export {
    background-color: var(--color-excel-green);
    border: 1px solid var(--color-excel-green);
    color: #fff;
}
.btn-export:hover,
.btn-export:focus {
    filter: brightness(var(--btn-hover-brightness));
    background-color: var(--color-excel-green);
    border-color: var(--color-excel-green);
    color: #fff;
}

/* ── Brand row account chip (user + logout, light-on-dark) ────── */
/* These stay hardcoded white/light overlays rather than themed tokens - the brand row
   background is always a mid-to-dark, saturated --color-primary in every theme, so a
   white chip/border reads correctly regardless of which theme is active. */
.ambra-scan-user {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
    font-weight: 500;
    color: #fff;
    text-decoration: none;
    background-color: rgba(255, 255, 255, 0.12);
    border-radius: 999px;
    padding: 0.35rem 0.8rem;
    min-height: 36px;
}

/* Now a link to Preferences.aspx - same hover treatment as .ambra-org-printagent-link. */
.ambra-scan-user:hover {
    color: #fff;
    text-decoration: underline;
    background-color: rgba(255, 255, 255, 0.18);
}

.ambra-scan-user-icon {
    flex-shrink: 0;
    opacity: 0.75;
}

.ambra-scan-logout {
    font-size: 0.78rem;
    font-weight: 500;
    color: #fff;
    background-color: transparent;
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 999px;
    padding: 0.35rem 1rem;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.ambra-scan-logout:hover {
    background-color: var(--color-secondary);
    border-color: var(--color-secondary);
    color: #fff;
}

.ambra-scan-logout-icon {
    flex-shrink: 0;
}

/* Below the nav's collapse breakpoint: drop the username entirely and shrink the logout
   button to a wordless icon-only button, to keep the brand row compact on phones. The
   alerts badge (.ambra-scan-user-alerts) is exempted - unlike the username, it's actual
   information a scanner user on a small screen still needs to see. */
@media (max-width: 991.98px) {
    .ambra-scan-user:not(.ambra-scan-user-alerts) {
        display: none;
    }

    .ambra-scan-logout {
        width: 36px;
        height: 36px;
        padding: 0;
        border-radius: 50%;
    }

    .ambra-scan-logout-text {
        display: none;
    }
}

/* ── Bootstrap modal headers (brand-row colour) ───────────────── */
/* Same background as Site.Master's brand row (.bg-primary/.ambra-brand-row) - a single
   global rule so every current and future modal picks it up with no per-modal markup
   changes. Title/close-button/icon colours are hardcoded white/light overlays rather
   than themed tokens, same reasoning as .ambra-scan-user above: this background is
   always a mid-to-dark, saturated --color-primary in every theme. */
.modal-header {
    background-color: var(--color-primary);
    border-bottom-color: rgba(255, 255, 255, 0.15);
}

.modal-header .modal-title {
    color: #fff;
}

.modal-header .btn-close {
    filter: brightness(0) invert(1);
}

/* .ambra-row-icon buttons can live in a modal-header (see default.aspx's
   jobDetailModal) - their default colour/hover assume a light surface, so both need a
   light-on-dark override here too. */
.modal-header .ambra-row-icon {
    color: #fff;
    opacity: 0.75;
}

.modal-header .ambra-row-icon:hover,
.modal-header .ambra-row-icon:focus {
    color: #fff;
    opacity: 1;
    background-color: rgba(255, 255, 255, 0.15);
}

/* ── Page content: mobile-first, built for handheld scanners/tablets ── */
.ambra-page-main {
    padding-top: 0.75rem;
    padding-bottom: 1.5rem;
    /* fluid horizontal padding: tight on phones, roomier on desktop */
    padding-left: clamp(0.5rem, 3vw, 2rem);
    padding-right: clamp(0.5rem, 3vw, 2rem);
}

/* Fluid type scale so headings/labels never overflow narrow screens */
.ambra-page-main h1 { font-size: clamp(1.3rem, 4vw, 2rem); }
.ambra-page-main h2 { font-size: clamp(1.15rem, 3.5vw, 1.6rem); }
.ambra-page-main h3 { font-size: clamp(1rem, 3vw, 1.3rem); }

/* Buttons/inputs at comfortable tap size on touch devices, tightened up on desktop */
.ambra-page-main .btn {
    min-height: 44px;
    padding-left: 1rem;
    padding-right: 1rem;
}

.ambra-page-main .form-control,
.ambra-page-main .form-select {
    min-height: 44px;
    font-size: 1rem;
}

/* ScanProcess.aspx's barcode input - the single primary control on a scan-heavy handheld
   workflow (Honeywell scanners etc.), so it gets noticeably larger than the site's normal
   44px/1rem touch-target baseline above rather than just inheriting it. Needs 4 classes'
   worth of specificity to actually win: it sits inside pnlContent (.card.ambra-admin-card),
   so without the extra qualifiers here, .ambra-admin-card.card .form-control (3 classes,
   see above - the compact-admin-form override) would keep taking precedence over a plain
   single-class .ambra-scan-input selector and silently shrink this back down to 0.8rem. */
.ambra-admin-card.card .form-control.ambra-scan-input {
    min-height: 100px;
    font-size: 3rem;
}

/* ScanProcess.aspx's textboxes (barcode/location/package-type scan fields, manual
   dimensions) - a visible background change while focused, not just Bootstrap's default
   border/box-shadow glow, so it's obvious at a glance from across a warehouse floor which
   field a handheld scanner's input is about to land in. Reverts on its own once focus
   moves elsewhere - no JS needed, :focus stops matching and the rule stops applying. */
.ambra-scan-process .form-control:focus {
    background-color: rgba(var(--color-secondary-rgb), 0.18);
}

/* ScanProcess.aspx's LOCATION summary - a stat-card layout (caption above value, no
   gridlines) rather than a table, since the data isn't naturally tabular: one hero value
   (Location) plus two distinct groups (this Job's totals, this scanned item's own
   quantities) that a table forced into confusing merged cells and repeated headers. */
.ambra-scan-summary-card {
    border: 1px solid rgba(var(--ink-rgb), 0.15);
}

/* pnlLabellingProgress's own summary card (Job/Packages/Qty Shipped while booking with
   the carrier) - wider than the other .ambra-scan-summary-card instances on this page
   (Location/Package Type scan), since .ambra-fit-card's shrink-to-fit width would
   otherwise leave this one narrower than is comfortable to read while it's polling. 350px
   still wasn't enough room for all three stat columns (Job/Packages/Qty Shipped) side by
   side without their captions/values overlapping, hence the further bump here. */
.ambra-labelling-summary-card {
    width: 440px;
    max-width: 100%;
}

/* pnlPickRunCompleted - just a short heading/icon and a w-100 button, with nothing else
   to give .ambra-fit-card's shrink-to-fit width something to work with, so without this
   it renders noticeably narrower than every other state on this page. */
.ambra-pickrun-completed-panel {
    width: 350px;
    max-width: 100%;
}

.ambra-scan-summary-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: rgba(var(--ink-rgb), 0.6);
}

.ambra-scan-summary-group-label {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

.ambra-scan-summary-value {
    font-size: 1.5rem;
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* The Location value is the one staff need to read at a glance from a distance (e.g.
   while walking a tote to a shelf), so it's sized well above every other value here. */
.ambra-scan-summary-location {
    font-size: 3.75rem;
    font-weight: 600;
}

/* Cards reflow instead of forcing horizontal scroll on narrow screens */
.ambra-page-main .card {
    overflow-wrap: anywhere;
}

/* ...except tables, which already have their own overflow handling via
   .table-responsive's horizontal scroll (see below). Left un-scoped, the rule above lets
   the browser break a cell's text anywhere it likes, which both defeats an explicit
   white-space:nowrap on a column (e.g. default.aspx's Status columns) and tricks
   .ambra-fit-card's shrink-to-fit width calculation into computing a far narrower
   "natural" table width than it actually needs, since a single breakable character now
   counts as the minimum content width of a cell. */
.ambra-page-main .card table {
    overflow-wrap: normal;
}

.ambra-page-main .table-responsive {
    -webkit-overflow-scrolling: touch;
}

@media (max-width: 575.98px) {
    .ambra-page-main .card-body {
        padding: 0.85rem;
    }

    .ambra-page-main pre {
        white-space: pre-wrap;
        word-break: break-word;
    }

    /* Stack button groups full-width on phones for easy thumb reach */
    .ambra-page-main .btn-group-responsive {
        display: flex;
        flex-direction: column;
    }

    .ambra-page-main .btn-group-responsive > .btn {
        width: 100%;
        margin-bottom: 0.5rem;
    }
}

/* The Logs/Organisation menus list every entity in their group - caps height and scrolls
   once a list grows past a reasonable dropdown size, rather than spilling off the bottom
   of the viewport. */
.ambra-scroll-menu {
    max-height: 70vh;
    overflow-y: auto;
}

/* For read-only display of a large free-text field (e.g. Admin/ErrorLogs.aspx's
   ErrorLogDescription, an nvarchar(max) that can hold a full stack trace) - preserves
   whatever line breaks/spacing the stored text already has and wraps long lines instead
   of overflowing horizontally, scrolling once it grows past a reasonable card height. */
.ambra-scroll-text {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 300px;
    overflow-y: auto;
}

/* Bootstrap 5 has no built-in nested/flyout dropdown, so the Admin menu's "Lookup Types"
   submenu (see Site.Master) is a plain CSS hover flyout: the nested .dropdown-menu is
   positioned absolutely off the trigger <li>'s top-right corner and only shown on hover,
   rather than relying on Bootstrap's JS (which only toggles top-level .dropdown-menus). */
.dropdown-submenu {
    position: relative;
}

.dropdown-submenu > .dropdown-menu {
    top: 0;
    left: 100%;
    margin-top: 0;
}

.dropdown-submenu:hover > .dropdown-menu {
    display: block;
}

.dropdown-submenu > a.dropdown-toggle::after {
    transform: rotate(-90deg);
}

/* Fixed-width label for label+value pairs shown side by side on one line (e.g. the Job
   Details modal) rather than stacked, so every value in a column lines up regardless of
   its label's length. */
.ambra-modal-field-label {
    min-width: 160px;
    flex-shrink: 0;
}

/* Delivery address box on the Job Details modal - a plain <address> renders italic by
   default, which reads oddly for a structured postal address, so that's reset here. */
.ambra-address-card {
    background-color: rgba(var(--ink-rgb), 0.03);
    border-left: 3px solid var(--color-secondary);
}

.ambra-address-card address {
    font-style: normal;
}

/* Consistent minimum button width across the whole app (Save/Cancel, modal Previous/Next/Close,
   Actions dropdowns, grid-row buttons, etc.) so buttons don't visibly differ in size based on
   their label length. Applies to every Bootstrap .btn, including .btn-sm, since even the small
   row-action buttons (e.g. Admin/Users.aspx's Reset Password/Reset MFA) should line up. .ambra-btn-min
   is now redundant with this blanket rule but is left on existing markup rather than stripped out. */
.btn {
    min-width: 120px;
}

/* Page heading + Actions/Save/Cancel button row (Process/Job.aspx's <h2>, default.aspx's
   pnlForm heading) - heading stays left, buttons align right via justify-content-between,
   capped at this width so the row doesn't stretch edge-to-edge on wide screens. */
.ambra-page-header {
    max-width: 800px;
}

/* Process/Job.aspx's header Status badge - bigger than a stock Bootstrap badge so it
   reads as the page's headline state at a glance, not a minor annotation like the
   "International" badge next to it. Colour itself comes from StatusID.GetBadgeCssClass
   (a text-bg-* utility class) - only size/weight are overridden here. */
.ambra-status-badge {
    font-size: 0.9rem;
    padding: 0.4em 0.7em;
}

/* StatusID.Labelling's badge colour. Bootstrap's white-text variants (primary/secondary/
   success/danger/dark) are already spoken for by the other statuses, and its previous
   text-bg-info defaults to black text - so this defines its own colour (Bootstrap's
   $indigo) with white text directly, same convention StatusID.GetBadgeCssClass documents
   for the rest. */
.text-bg-labelling {
    background-color: #6610f2;
    color: #fff;
}

/* Logs/Alerts.aspx's Edit Alert card - fixed width so it sits at a sensible size next to
   .ambra-alert-body-card instead of stretching to fill the row (see .ambra-fit-card above). */
.ambra-alert-card {
    width: 350px;
    max-width: 100%;
}

/* Logs/Alerts.aspx's Alert Body card - grows to take the remaining space next to the
   fixed-width .ambra-alert-card; min-width: 0 stops a long unbroken JSON/HTML line from
   pushing the flex item (and so the whole row) wider than the viewport. */
.ambra-alert-body-card {
    flex: 1 1 400px;
    min-width: 0;
}

/* Alert Body rendered as HTML (see BindAlertBody) - always a white background regardless
   of app theme, since the markup being rendered is someone else's raw HTML (typically
   assuming a light/email-style background) rather than themed content of our own. */
.ambra-alert-body-frame {
    width: 100%;
    height: 400px;
    border: 1px solid rgba(var(--ink-rgb), 0.1);
    border-radius: 0.375rem;
    background-color: #fff;
}

.ambra-alert-body-json {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    margin: 0;
}

/* Logs/Apilogs.aspx's Api Log card - same fixed-width pattern as .ambra-alert-card, so
   it sits at a sensible size next to the three detail cards instead of stretching to
   fill the row (see .ambra-fit-card above). */
.ambra-apilog-card {
    width: 300px;
    max-width: 100%;
}

/* Logs/Apilogs.aspx's Request Detail/Response Detail/Response Additional Detail cards -
   share the remaining space next to the fixed-width .ambra-apilog-card, and with each
   other; min-width: 0 stops a long unbroken JSON/HTML/XML line from pushing the flex
   item (and so the whole row) wider than the viewport. */
.ambra-apilog-detail-card {
    flex: 1 1 320px;
    min-width: 0;
}

/* Process/Job.aspx's own Api Log detail view (pnlApilogDetail) - unlike Apilogs.aspx
   above, here all 4 cards (basic info + Request/Response/Response Additional Detail)
   should read as one even row: same width via a shared flex-basis, and same height via
   stretch (the default cross-axis alignment - ambra-apilog-detail-row just avoids the
   align-items-start that would otherwise size each card to its own content). */
.ambra-apilog-detail-row {
    align-items: stretch;
}

.ambra-apilog-equal-card {
    flex: 1 1 280px;
    min-width: 0;
}

/* Logs/CarrierApiLogs.aspx's own info card - same fixed-width pattern as
   .ambra-apilog-card, so it sits at a sensible size next to the Request/Response cards
   instead of stretching to fill the row. */
.ambra-carrierapilog-card {
    width: 300px;
    max-width: 100%;
}

/* Logs/CarrierApiLogs.aspx's Request/Response cards - same sharing pattern as
   .ambra-apilog-detail-card. */
.ambra-carrierapilog-detail-card {
    flex: 1 1 320px;
    min-width: 0;
}

/* Logs/MaintenanceRunLogs.aspx's own info card - same fixed-width pattern as
   .ambra-apilog-card, so it sits at a sensible size next to the Message card instead of
   stretching to fill the row. */
.ambra-maintenancerunlog-card {
    width: 300px;
    max-width: 100%;
}

/* Logs/MaintenanceRunLogs.aspx's Message card - same sharing pattern as
   .ambra-apilog-detail-card. */
.ambra-maintenancerunlog-detail-card {
    flex: 1 1 320px;
    min-width: 0;
}

/* Logs/EdifileIns.aspx's Edifile In card - same fixed-width pattern as .ambra-apilog-card. */
.ambra-edifilein-card {
    width: 300px;
    max-width: 100%;
}

/* Logs/EdifileIns.aspx's Data/Errors/References cards - same sharing pattern as
   .ambra-apilog-detail-card. */
.ambra-edifilein-detail-card {
    flex: 1 1 320px;
    min-width: 0;
}

/* Logs/Emails.aspx's Email card - same fixed-width pattern as .ambra-alert-card, so it
   sits at a sensible size next to its Body/Error Message/Documents cards instead of
   stretching to fill the row (see .ambra-fit-card above). */
.ambra-email-card {
    width: 350px;
    max-width: 100%;
}

/* Logs/Emails.aspx's Body/Error Message/Documents cards - same sharing pattern as
   .ambra-edifilein-detail-card. */
.ambra-email-detail-card {
    flex: 1 1 320px;
    min-width: 0;
}

/* Tenant/Products.aspx's Edit Product card - same fixed-width pattern as .ambra-alert-card,
   so it sits at a sensible size next to the Barcodes card instead of stretching to fill the
   row. The Barcodes card itself just uses .ambra-fit-card - it should size to its own
   content (the barcode table), not stretch to fill the remaining row width. */
.ambra-product-card {
    width: 350px;
    max-width: 100%;
}

/* Tenant/ZPLSettings.aspx's single settings card - wider than the usual narrow Add/Edit
   form (see .ambra-fit-card) since its fields sit two-per-row rather than stacked. */
.ambra-zpl-settings-card {
    max-width: 700px;
}

/* Logs/Emails.aspx's Email card header block (From/To/Cc/Bcc/Sent) - a shaded,
   letterhead-style panel so the read-only view reads like an actual email rather than a
   plain label/value form. rgba(var(--ink-rgb), ...) rather than a raw grey keeps it
   themed across light/dark/solarized (see the surface tokens comment near :root above). */
.ambra-email-headers {
    background-color: rgba(var(--ink-rgb), 0.04);
    border: 1px solid rgba(var(--ink-rgb), 0.08);
    border-radius: 0.375rem;
    padding: 0.5rem 0.75rem;
}

.ambra-email-header-row {
    display: flex;
    gap: 0.5rem;
    padding: 0.15rem 0;
}

.ambra-email-header-label {
    flex: 0 0 3rem;
    font-weight: 600;
    color: rgba(var(--ink-rgb), 0.6);
}

.ambra-email-header-value {
    flex: 1 1 auto;
    word-break: break-word;
}

/* A slightly longer, eased fade for the Job Details modal's initial open/close. */
#jobDetailModal.fade .modal-dialog {
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}

#jobDetailModal.fade {
    transition: opacity 0.3s ease;
}

/* Thin bar along the bottom of a toast (see Site.Master / BasePage.ShowToast, and
   Login.aspx's own toast) that shrinks over its autohide delay - Scripts/ambra-toast.js
   listens for this animation ending and explicitly hides the toast at that point, rather
   than solely trusting Bootstrap's own autohide timer (which pauses on mouse-over, so isn't
   guaranteed to line up with a fixed-duration CSS animation). Not used by the error toast
   (BasePage.ShowErrorToast) - that one has no autohide/countdown at all. */
.ambra-toast-countdown {
    height: 3px;
    background-color: rgba(255, 255, 255, 0.6);
    width: 100%;
}

.toast.show .ambra-toast-countdown {
    animation: ambra-toast-countdown-shrink 10s linear forwards;
}

/* Pauses the countdown (and so the eventual forced-hide) while the toast is being hovered,
   so it can't disappear out from under someone still reading it. */
.toast:hover .ambra-toast-countdown {
    animation-play-state: paused;
}

@keyframes ambra-toast-countdown-shrink {
    from { width: 100%; }
    to { width: 0%; }
}
