/* Inter, self-hosted from wwwroot/fonts/inter. SIL Open Font License 1.1;
   LICENSE.txt sits beside the files. No CDN: a customer reading an agreement on
   the signing or portal pages should not make a third-party request to do it.

   The variable build rather than static weights. The application uses seven
   distinct weights -- 400, 500, 600, 650, 700, 750, 800 -- and static files
   would mean four downloads that still cannot render 650, 750, or 800 without
   the browser synthesising them. One 352 KB file covers the whole 100-900 axis
   genuinely, in a single request, and is smaller than the static set it
   replaces.

   font-display: swap paints fallback text immediately and swaps on arrival,
   rather than blanking text while the font loads. */
@font-face {
    font-family: "Inter";
    src: url("/fonts/inter/InterVariable.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Inter";
    src: url("/fonts/inter/InterVariable-Italic.woff2") format("woff2");
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
}

/* Bootstrap is served from wwwroot/lib/bootstrap and linked by App.razor. It is
   deliberately not imported from a CDN here: the identical 5.3.3 build was being
   fetched twice, once locally and once over the network, and a customer reading
   an agreement on the signing or portal pages should not be making third-party
   requests to do it. An @import also blocks rendering until it resolves. */

/* Mission Telecom Brand Colors */
:root {
    --mt-navy: #0a192f;
    --mt-navy-light: #112240;
    --mt-green: #8bc34a;
    --mt-green-dark: #689f38;
    --mt-white: #ffffff;
    /* Decoration only. At 3.09:1 on white this fails WCAG AA for text, so it is
       kept for the disabled-button fill, where a muted, low-contrast appearance
       is the point, and never used for words. */
    --mt-gray: #8892b0;
    /* The same blue-grey darkened to 4.96:1 on white. Secondary text that a
       Lighthouse audit flagged on the top bar and page-header subtitle reads at
       this value instead. */
    --mt-text-muted: #656f90;

    /* Design tokens. See docs/agent-guidance/RADZEN_UI_STANDARD.md.
       A literal hex or px for any of these is a defect: a value named nowhere
       is a value nobody can check, which is how 62 near-identical greys
       accumulated across 69 stylesheets. */

    /* Surfaces */
    --mt-canvas: #eef3f7;   /* page canvas behind tab panels */
    --mt-surface: #ffffff;  /* panels and cards */

    /* Lines. Two roles, deliberately different weights:
       --mt-border draws a container's own edge (card, table shell, layout
       divider); --mt-rule is the lighter hairline used inside one, including
       the section-heading underline. Collapsing them into one value would
       either wash out card edges or make heading rules shout. */
    --mt-border: #cfd8e0;
    --mt-rule: #e6ebef;

    /* Typeface. The platform UI font -- Segoe UI on Windows, SF on macOS. This is
       what the application has always actually rendered: the previous
       'Helvetica Neue' is not installed on Windows and fell through to Arial, and
       a later Inter declaration had no @font-face so never loaded either. Naming
       it makes the real behaviour deliberate.

       Inter leads because it is now genuinely shipped from wwwroot/fonts/inter.
       Its open apertures and disambiguated 1/l/I and 0/O matter in an
       application dense with ICCIDs, account numbers and invoice identifiers.
       The system stack remains behind it so a failed font load degrades to the
       platform UI font rather than to a serif default.

       Tabular figures do not come from the typeface. They are a CSS opt-in
       (font-variant-numeric: tabular-nums) already applied on money columns. */
    --mt-font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto,
                      "Helvetica Neue", Arial, sans-serif;

    /* Type scale */
    --mt-font-page: 24px;    /* page title, semibold */
    --mt-font-section: 17px; /* section title, semibold */
    --mt-font-body: 13px;    /* body and grid cells, desktop minimum */
    --mt-font-label: 12px;   /* grid headers and field labels */
    --mt-font-eyebrow: 11px; /* eyebrow and secondary metadata */
}

html, body {
    font-family: var(--mt-font-family);
    background-color: #f8f9fa;
}

/* Override Bootstrap primary with Mission Telecom green */
.btn-primary {
    background-color: var(--mt-green);
    border-color: var(--mt-green);
    color: var(--mt-navy);
    font-weight: 600;
}

.btn-primary:hover {
    background-color: var(--mt-green-dark);
    border-color: var(--mt-green-dark);
    color: var(--mt-white);
}

.btn-primary:disabled {
    background-color: var(--mt-gray);
    border-color: var(--mt-gray);
}

.text-primary {
    color: var(--mt-green) !important;
}

.bg-primary {
    background-color: var(--mt-green) !important;
}

a, .btn-link {
    color: var(--mt-green-dark);
}

a:hover {
    color: var(--mt-navy);
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}


/* Card styling */
.card {
    border: none;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(10, 25, 47, 0.1);
}

.card-header {
    border-radius: 8px 8px 0 0 !important;
}

/* Form controls */
.form-control:focus {
    border-color: var(--mt-green);
    box-shadow: 0 0 0 0.2rem rgba(139, 195, 74, 0.25);
}

/* Alerts */
.alert-success {
    background-color: rgba(139, 195, 74, 0.1);
    border-color: var(--mt-green);
    color: var(--mt-green-dark);
}

.alert-danger {
    background-color: rgba(229, 0, 0, 0.1);
    border-color: #e50000;
    color: #c62828;
}

.alert-warning {
    background-color: rgba(255, 152, 0, 0.1);
    border-color: #ff9800;
    color: #e65100;
}
/* ============================================================
   Global: Prevent long unbroken strings (JSON, ICCIDs, etc.)
   from expanding layout width beyond viewport.
   Root cause: Browser treats long strings as minimum content
   width, causing 300k+ px layouts.
   ============================================================ */

/* Flex containers must be allowed to shrink below content size */
.container, .container-fluid, .row, .col, [class^="col-"], [class*=" col-"] {
    min-width: 0;
}

/* Card bodies must not expand beyond viewport */
.card-body {
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
}

/* Tables: fixed layout, cells break long strings */
.table {
    table-layout: fixed;
    width: 100%;
}

.table td, .table th {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Pre/code blocks: wrap long lines */
pre, code, .raw-response-pre {
    max-width: 100%;
    overflow-x: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Table responsive wrapper */
.table-responsive {
    max-width: 100%;
    overflow-x: auto;
}

/* ============================================================
   V3 Candidates: Override global table layout for this page only
   ============================================================ */

.v3-candidates-table {
    table-layout: fixed !important;
    width: 100% !important;
    min-width: 1400px;
}

.v3-candidates-table td,
.v3-candidates-table th {
    overflow: hidden !important;
    text-overflow: ellipsis;
    white-space: nowrap !important;
    max-width: 0;
}

/* V3 Detail Grid */
.v3-detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 0;
    padding: 0;
    background-color: #f8f9fa;
}

.v3-detail-section {
    display: flex;
    flex-direction: column;
    gap: 0;
}

.v3-detail-header {
    font-weight: 600;
    color: #0a192f;
    margin-bottom: 0.25rem;
    padding: 0.75rem 1rem 0.25rem;
    border-bottom: 1px solid #dee2e6;
    background-color: #e9ecef;
}

.v3-detail-row {
    display: flex;
    padding: 0.35rem 1rem;
    border-bottom: 1px solid var(--mt-rule);
    align-items: baseline;
}

.v3-detail-row:last-child {
    border-bottom: none;
}

.v3-detail-label {
    flex: 0 0 160px;
    font-weight: 600;
    color: #495057;
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.025em;
}

.v3-detail-value {
    flex: 1;
    color: #212529;
    font-size: 0.875rem;
    min-width: 0;
    word-break: break-all;
}

@media (max-width: 768px) {
    .v3-detail-grid {
        grid-template-columns: 1fr;
    }
}


/* ============================================================
   App Shell — Fixed top bar + sidebar layout
   ============================================================ */

.app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Fixed Top Bar */
.app-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 56px;
    background: white;
    border-bottom: 1px solid #dee2e6;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 1rem;
    z-index: 1030;
    box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}

.invoice-payment-dialog-wrapper {
    z-index: 1050;
}

/* Commerce dialogs must cover the fixed staff header and navigation. Keep
   this correction scoped to their wrappers, not every Radzen overlay. */
.commerce-dialog-wrapper {
    z-index: 1050;
}

.app-topbar-start {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.app-topbar-end {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.app-logo-link {
    text-decoration: none;
    display: flex;
    align-items: center;
}

.app-logo {
    height: 32px;
    width: auto;
}

/* Mobile hamburger */
.mobile-hamburger {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.25rem;
    color: var(--mt-navy);
    font-size: 1.5rem;
    line-height: 1;
}

.mobile-hamburger:hover {
    color: var(--mt-green);
}

.desktop-nav-width-toggle {
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    color: var(--mt-navy);
    border: 1px solid #d8e1e8;
    border-radius: 4px;
    background: #fff;
}

.desktop-nav-width-toggle:hover,
.desktop-nav-width-toggle:focus-visible {
    color: #126fbd;
    border-color: #9fc5e5;
    background: #eef6fc;
}

/* Sidebar */
.app-sidebar {
    position: fixed;
    top: 56px;
    left: 0;
    bottom: 0;
    width: 260px;
    background: white;
    border-right: 1px solid #dee2e6;
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 1020;
    padding: 0.5rem 0;
}

/* Nav scrollable: no independent scroll, sidebar handles it */
.app-sidebar .nav-scrollable {
    overflow: visible !important;
    max-height: none !important;
}

/* Main content area */
.app-main {
    margin-top: 56px;
    margin-left: 260px;
    flex: 1;
    min-width: 0;
    background-color: #eef3f7;
    min-height: calc(100vh - 56px);
}

@media (min-width: 768px) {
    .app-sidebar,
    .app-main {
        transition: width 0.18s ease, margin-left 0.18s ease;
    }

    .app-shell.nav-compact .app-sidebar {
        width: 68px;
    }

    .app-shell.nav-compact .app-main {
        margin-left: 68px;
    }

    .app-shell.nav-compact .app-sidebar .nav-section-header {
        justify-content: center;
        min-height: 38px;
        padding: 0.45rem 0.5rem;
        gap: 0;
        overflow: hidden;
        font-size: 0;
    }

    .app-shell.nav-compact .app-sidebar .nav-section-header::before {
        display: none;
    }

    .app-shell.nav-compact .app-sidebar .nav-section-header i {
        font-size: 1.05rem;
    }

    .app-shell.nav-compact .app-sidebar .nav-details .nav-item,
    .app-shell.nav-compact .app-sidebar > .nav-scrollable > .nav > .nav-section > .nav-item {
        padding-right: 0.35rem;
        padding-left: 0.35rem;
    }

    .app-shell.nav-compact .app-sidebar .nav-link {
        justify-content: center;
        min-height: 38px;
        padding-right: 0.4rem;
        padding-left: 0.4rem;
    }

    .app-shell.nav-compact .app-sidebar .nav-link span {
        display: none;
    }

    .app-shell.nav-compact .app-sidebar .nav-link i,
    .app-shell.nav-compact .app-sidebar .bi {
        min-width: 18px;
        margin-right: 0;
        font-size: 1.05rem;
    }

    .app-shell.nav-compact .app-sidebar .nav-link.active {
        padding-left: calc(0.4rem - 4px) !important;
    }
}

/* Nav sections */
.nav-section {
    margin-bottom: 0.25rem;
}

.nav-section-header {
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
    color: var(--mt-navy);
    padding: 0.55rem 1rem 0.2rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    list-style: none;
    user-select: none;
}

.nav-section-header::-webkit-details-marker {
    display: none;
}

.nav-section-header::before {
    content: '\25B6';
    display: inline-block;
    font-size: 0.5rem;
    transition: transform 0.2s;
    color: var(--mt-text-muted);
}

.nav-section-header:has(+ .nav-item)::before {
    display: none;
}

details[open] > .nav-section-header::before {
    transform: rotate(90deg);
}

.nav-section-header:hover {
    color: var(--mt-navy);
}

.nav-section-header i {
    font-size: 1rem;
    color: var(--mt-green);
    opacity: 1;
}

/* Nav links */
.app-sidebar .nav-item {
    padding: 0 0.5rem;
}

/* Sub-items inside details get extra indent */
.app-sidebar .nav-details .nav-item {
    padding-left: 1.75rem;
    padding-right: 0.5rem;
}

/* Top-level items (Dashboard, Account) also get indent */
.app-sidebar > .nav-scrollable > .nav > .nav-section > .nav-item {
    padding-left: 1.75rem;
    padding-right: 0.5rem;
}

.app-sidebar .nav-link {
    color: #495057 !important;
    border-radius: 6px;
    padding: 0.45rem 0.625rem;
    margin: 1px 0;
    transition: all 0.15s;
    display: flex !important;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.8125rem;
    text-decoration: none;
}

.app-sidebar .nav-link i {
    font-size: 0.9375rem;
    min-width: 16px;
    text-align: center;
    color: #6b7a90;
    opacity: 0.7;
    flex-shrink: 0;
}

.app-sidebar .nav-link:hover {
    background-color: rgba(139, 195, 74, 0.12) !important;
    color: var(--mt-navy) !important;
}

.app-sidebar .nav-link:hover i {
    color: var(--mt-green-dark);
    opacity: 1;
}

.app-sidebar .nav-link.active {
    background-color: rgba(139, 195, 74, 0.15) !important;
    color: var(--mt-navy) !important;
    font-weight: 600;
    border-left: 4px solid var(--mt-green);
    padding-left: calc(0.625rem - 4px) !important;
}

.app-sidebar .nav-link.active i {
    color: var(--mt-green-dark);
    opacity: 1;
}

/* Nav details (expandable sections) */
.app-sidebar .nav-details {
    padding: 0;
    margin: 0;
}

.app-sidebar .nav-details summary {
    cursor: pointer;
    list-style: none;
}

.app-sidebar .nav-details summary::-webkit-details-marker {
    display: none;
}


/* Page header icon — navy blue square with white icon */
.page-header-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 6px;
    background-color: var(--mt-navy);
    color: var(--mt-white);
    font-size: 1.125rem;
    flex-shrink: 0;
}

.page-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

.page-header-title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--mt-navy);
    line-height: 1.3;
}

.page-header-subtitle {
    margin: 0.125rem 0 0 0;
    font-size: 0.8125rem;
    color: var(--mt-text-muted);
    line-height: 1.3;
}

/* Page header with right-aligned actions */
.page-header-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.page-header-actions {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Execution banner — compact, restrained */
.execution-banner {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0.75rem;
    margin-bottom: 1rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: #8a5a00;
    background-color: #fff8e1;
    border: 1px solid #ffcc02;
    border-radius: 6px;
    line-height: 1.3;
}

.execution-banner i {
    font-size: 0.875rem;
    color: #ff9800;
    flex-shrink: 0;
}

.execution-banner .execution-mode-badge {
    display: inline;
    font-weight: 600;
}

/* Content area */
.content {
    padding-top: 1rem;
    padding-bottom: 2rem;
    min-width: 0;
    max-width: 100%;
}


/* Custom scrollbar — thin, rounded, light gray */
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.15);
    border-radius: 9999px;
}

::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 0, 0, 0.3);
}

/* Firefox scrollbar */
* {
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
}

/* SF Environment Badge */
.sf-env-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.15rem 0.5rem;
    border-radius: 9999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    text-transform: uppercase;
}

.sf-env-sandbox {
    background-color: #e8f4fd;
    color: #0a5a8a;
    border: 1px solid #b8d8f0;
}

.sf-env-production {
    background-color: #fff3cd;
    color: #856404;
    border: 1px solid #ffc107;
}

/* ============================================================
   Mobile Shell
   On mobile (< 768px), sidebar becomes a fixed overlay.
   ============================================================ */

@media (max-width: 767.98px) {
    .app-sidebar {
        transform: translateX(-100%);
        transition: transform 0.25s ease;
        width: 280px;
        background: white;
        box-shadow: none;
        z-index: 1040;
    }

    .app-shell:has(#mobile-nav-toggler:checked) .app-sidebar {
        transform: translateX(0);
        box-shadow: 4px 0 20px rgba(0,0,0,0.2);
    }

    /* Overlay behind sidebar when open */
    .app-shell:has(#mobile-nav-toggler:checked)::after {
        content: '';
        position: fixed;
        top: 56px;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0,0,0,0.4);
        z-index: 1035;
    }

    .app-main {
        margin-left: 0 !important;
        width: 100% !important;
    }

    .content {
        padding-top: 0.5rem !important;
    }
}


/* Allow auto-width columns in ops-table to absorb extra space */
.ops-table col[style*="width:auto"] {
    width: auto !important;
    min-width: 100px;
}


/* ============================================================
   Navigation: Collapsible details sections
   ============================================================ */

.nav-details {
    padding: 0;
    margin: 0;
}

.nav-details summary {
    cursor: pointer;
    padding: 0.5rem 1rem;
    list-style: none;
    display: flex;
    align-items: center;
}

.nav-details summary::-webkit-details-marker {
    display: none;
}

.nav-details summary::before {
    content: '\25B6';
    display: inline-block;
    margin-right: 0.5rem;
    transition: transform 0.2s;
    font-size: 0.6rem;
}

.nav-details[open] summary::before {
    transform: rotate(90deg);
}

.nav-details summary:hover {
    background-color: rgba(139, 195, 74, 0.1);
}

.nav-details-summary {
    cursor: pointer;
    padding: 0.5rem 1rem;
    display: block;
    width: 100%;
}

.nav-details-summary:hover {
    background-color: rgba(139, 195, 74, 0.1);
}
/* ============================================================
   Reusable Responsive Table Pattern
   Standard for operational tables across the app.
   Usage:
     - Wrap table in .mt-table-shell for contained horizontal scroll
     - Use .mt-col-compact, .mt-col-medium, .mt-col-wide for column widths
     - Use .mt-nowrap for fixed-width nowrap+ellipsis columns
     - Use .mt-wrap for wrapping text columns
     - Use .mt-sortable for clickable sort headers
     - Use .mt-summary-tiles for responsive summary card grids
   ============================================================ */

/* Table shell: contained horizontal scroll, never breaks page layout */
.ops-page {
    min-width: 0;
    max-width: 100%;
    overflow-x: hidden;
}

.ops-table-shell {
    display: block;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    border: 1px solid #dee2e6;
    border-radius: 8px;
    background: white;
    box-sizing: border-box;
}

.ops-table {
    table-layout: fixed;
    width: 100%;
    min-width: 1200px;
    max-width: none;
    border-collapse: collapse;
    margin: 0;
}

.ops-table-exceptions {
    width: 2380px;
    min-width: 2380px;
}
.ops-table-candidates {
    width: 1800px;
    min-width: 1800px;
}

.ops-table-attempts {
    width: 1400px;
    min-width: 1400px;
}

.ops-table-write {
    width: 1200px;
    min-width: 1200px;
}

.ops-table-verify {
    width: 1200px;
    min-width: 1200px;
}

.ops-table-salesforce-assets {
    width: max(100%, 2780px);
    min-width: 2780px;
}

.sf-assets-table-shell {
    margin: 0.5rem;
    overflow-x: auto;
    overflow-y: visible;
}

.ops-table-salesforce-assets .sf-col-record-id {
    width: 210px;
}

.ops-table-salesforce-assets .sf-col-readable-id {
    width: 130px;
}

.ops-table-salesforce-assets .sf-col-mission-asset-id {
    width: 260px;
}

.ops-table-salesforce-assets .sf-col-asset-name {
    width: 220px;
}

.ops-table-salesforce-assets .sf-col-status {
    width: 120px;
}

.ops-table-salesforce-assets .sf-col-account-name {
    width: 260px;
}

.ops-table-salesforce-assets .sf-col-account-id {
    width: 190px;
}

.ops-table-salesforce-assets .sf-col-order-id {
    width: 170px;
}

.ops-table-salesforce-assets .sf-col-product-code {
    width: 220px;
}

.ops-table-salesforce-assets .sf-col-logistic-provider {
    width: 180px;
}

.ops-table-salesforce-assets .sf-col-logistic-sku {
    width: 210px;
}

.ops-table-salesforce-assets .sf-col-iccid {
    width: 230px;
}

.ops-table-salesforce-assets .sf-col-imei {
    width: 190px;
}

.ops-table-salesforce-assets .sf-col-msisdn {
    width: 190px;
}


.ops-table thead th {
    white-space: nowrap;
    vertical-align: middle;
    padding: 0.5rem 0.75rem;
    height: 40px;
    border-bottom: 2px solid #0a192f;
    background-color: #0a192f;
    color: white;
    font-size: 0.8125rem;
    position: sticky;
    top: 0;
    z-index: 2;
}

/* ops-table-shell with max-height: constrained viewport */
.ops-table-shell[max-height],
.ops-table-shell[style*="max-height"] {
    overflow-y: auto !important;
    overflow-x: auto !important;
}

/* Ensure tbody cells don't overlap sticky header */
.ops-table tbody td {
    position: relative;
    z-index: 1;
}

.ops-table tbody td {
    vertical-align: middle;
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: clip;
}

/* Visible slim scrollbar for table shells with overflow */
.ops-table-shell::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

.ops-table-shell::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 4px;
}

.ops-table-shell::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 4px;
}

.ops-table-shell::-webkit-scrollbar-thumb:hover {
    background: #a1a1a1;
}

/* Grouped header rows (colspan) also sticky */
.ops-table thead tr th[colspan] {
    position: sticky;
    top: 0;
    z-index: 3;
    text-align: center;
    font-weight: 700;
    border-bottom: 1px solid rgba(255,255,255,0.3);
}

/* Second header row below grouped header */
.ops-table thead tr:not(:first-child) th {
    top: 40px;
    z-index: 2;
}

/* V3 shadow match: grouped header at top, sub-header below */
.v3-shadow-match-table thead tr:first-child th {
    position: sticky;
    top: 0;
    z-index: 3;
    border-bottom: 1px solid var(--mt-green) !important;
}

.v3-shadow-match-table thead tr:last-child th {
    position: sticky;
    top: 40px;
    z-index: 2;
}


.ops-table tbody tr:hover {
    background-color: rgba(10, 25, 47, 0.025);
    color: inherit;
}

.ops-table tbody tr:hover > td {
    background-color: #f8fafc;
    color: inherit;
}

.ops-col-compact {
    width: 90px;
    min-width: 70px;
}

.ops-col-count {
    width: 100px;
    min-width: 80px;
}

.ops-col-date {
    width: 140px;
    min-width: 140px;
}

.ops-col-actions {
    width: 240px;
    min-width: 220px;
}


.ops-col-medium {
    width: 150px;
    min-width: 120px;
}

.ops-col-id {
    width: 200px;
    min-width: 180px;
}

.ops-col-wide {
    width: 640px;
    min-width: 640px;
}

.ops-nowrap {
    white-space: nowrap;
}

.ops-wrap {
    white-space: normal;
    word-break: break-word;
    overflow-wrap: anywhere;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.35;
}

.ops-table tbody td.ops-wrap {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    word-break: break-word;
    overflow-wrap: anywhere;
}

.ops-table tbody td.ops-actions-cell {
    white-space: nowrap;
    overflow: visible;
    text-overflow: clip;
}

.ops-sortable {
    cursor: pointer;
    user-select: none;
    position: relative;
}

.ops-sortable:hover {
    background-color: #13243a;
    color: white;
}

.ops-table thead th.ops-sortable:hover {
    background-color: #112240 !important;
    color: white !important;
}

.ops-sortable .ops-sort-label {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.ops-sort-icon {
    display: inline-block;
    font-size: 0.75rem;
    opacity: 0.5;
    vertical-align: middle;
}

/* Hide empty sort icons (unsorted columns) */
.ops-sort-icon:empty {
    display: none;
}

.ops-sort-active .ops-sort-icon {
    opacity: 1;
    color: var(--mt-green);
}

.ops-summary-text {
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: anywhere;
    line-height: 1.5;
    margin-bottom: 0;
}

.ops-pre-wrap {
    background-color: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 0.25rem;
    padding: 0.75rem;
    font-size: 0.8125rem;
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: anywhere;
    max-height: 300px;
    overflow-y: auto;
    margin-bottom: 0;
}

/* ============================================================
   V3 Shadow Match Table
   Page-specific styles for the current match state table.
   ============================================================ */

.v3-shadow-match-table {
    min-width: 2705px;
    width: 2705px;
}

.v3-shadow-match-table .v3-shadow-group {
    text-align: center;
    border-bottom: 3px solid var(--mt-green);
    background-color: #0a192f;
    color: white;
    font-weight: 700;
}

.v3-shadow-match-table .v3-shadow-group-ahub,
.v3-shadow-match-table .v3-shadow-group-sf {
    border-right: 3px solid var(--mt-green);
}

.v3-shadow-match-table thead tr:last-child th {
    border-bottom: 2px solid #ffffff;
}

.v3-shadow-match-table thead tr:last-child th:nth-child(10),
.v3-shadow-match-table thead tr:last-child th:nth-child(14),
.v3-shadow-match-table tbody td:nth-child(10),
.v3-shadow-match-table tbody td:nth-child(14) {
    border-left: 3px solid var(--mt-green);
}

.v3-shadow-match-table .ops-sort-icon:empty {
    display: none;
}

.v3-shadow-match-table .v3-shadow-col-order {
    width: 115px;
}

.v3-shadow-match-table .v3-shadow-col-ban {
    width: 120px;
}

.v3-shadow-match-table .v3-shadow-col-ban-name {
    width: 240px;
}

.v3-shadow-match-table .v3-shadow-col-msisdn {
    width: 145px;
}

.v3-shadow-match-table .v3-shadow-col-iccid {
    width: 180px;
}

.v3-shadow-match-table .v3-shadow-col-imei {
    width: 160px;
}

.v3-shadow-match-table .v3-shadow-col-activation {
    width: 145px;
}

.v3-shadow-match-table .v3-shadow-col-line-status {
    width: 160px;
}

.v3-shadow-match-table .v3-shadow-col-rate-plan {
    width: 170px;
}

.v3-shadow-match-table .v3-shadow-col-sf-order {
    width: 120px;
}

.v3-shadow-match-table .v3-shadow-col-sf-asset {
    width: 180px;
}

.v3-shadow-match-table .v3-shadow-col-sf-sku {
    width: 120px;
}

.v3-shadow-match-table .v3-shadow-col-assignment {
    width: 200px;
}

.v3-shadow-match-table .v3-shadow-col-status {
    width: 130px;
}

.v3-shadow-match-table .v3-shadow-col-attempts {
    width: 100px;
}

.v3-shadow-match-table .v3-shadow-col-error {
    width: 420px;
}

/* Actions status badges */
.actions-status-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
}
.actions-status-badge.badge-success { background: #e8f5e9; color: #2e7d32; }
.actions-status-badge.badge-warning { background: #fff3e0; color: #e65100; }
.actions-status-badge.badge-danger { background: #ffebee; color: #c62828; }
.actions-status-badge.badge-info { background: #e3f2fd; color: #1565c0; }
.actions-status-badge.badge-secondary { background: #f5f5f5; color: #616161; }

/* Shared Platform page-heading icon. Domain pages supply only the icon glyph. */
.platform-page-heading-icon {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    flex: 0 0 40px;
    margin-top: 2px;
    border-radius: 6px;
    background: #eef3f7;
    color: #0b2238;
    font-size: 20px;
}

/* Quiet destructive action.
 *
 * A filled red button is the highest-contrast thing on a page, so a row of them makes deletion
 * the loudest idea on a screen where nothing is being deleted. These read as an ordinary icon
 * control until pointed at, then commit to red. The colour still arrives before the click, and
 * the accessible name and title are untouched, so nothing about the affordance is hidden. */
/* Three classes deliberately. Radzen's own rule is .rz-button.rz-danger.rz-variant-flat, so a
   two-class selector loses on specificity no matter that app.css is loaded after the theme. */
/* Bordered, not bare. Dropping the fill without adding an outline leaves a floating glyph with
   no hit target a reader can see; the border is what still says "button". Same border tones as
   the status chips, so a row of controls and a row of chips belong to one system. */
.rz-button.rz-variant-flat.platform-quiet-danger,
.rz-button.rz-variant-flat.platform-quiet-positive,
.rz-button.rz-variant-flat.platform-quiet-attention {
    background: transparent;
    border: 1px solid var(--mt-border);
    box-shadow: none;
}

.rz-button.rz-variant-flat.platform-quiet-danger {
    border-color: #e0a9a9;
    color: #b3261e;
}

.rz-button.rz-variant-flat.platform-quiet-positive {
    border-color: #9bcbaa;
    color: #23743b;
}

.rz-button.rz-variant-flat.platform-quiet-attention {
    border-color: #e2c48a;
    color: #8a5a10;
}

.rz-button.rz-variant-flat.platform-quiet-danger:hover:not(:disabled),
.rz-button.rz-variant-flat.platform-quiet-danger:focus-visible:not(:disabled) {
    background: #fbeceb;
    color: #8c1d18;
}

.rz-button.rz-variant-flat.platform-quiet-positive:hover:not(:disabled),
.rz-button.rz-variant-flat.platform-quiet-positive:focus-visible:not(:disabled) {
    background: #e8f5ed;
    color: #1b5c2e;
}

.rz-button.rz-variant-flat.platform-quiet-attention:hover:not(:disabled),
.rz-button.rz-variant-flat.platform-quiet-attention:focus-visible:not(:disabled) {
    background: #fdf4e3;
    color: #6f4708;
}

.rz-button.rz-variant-flat.platform-quiet-danger:disabled,
.rz-button.rz-variant-flat.platform-quiet-positive:disabled,
.rz-button.rz-variant-flat.platform-quiet-attention:disabled {
    background: transparent;
    border-color: #dde4ea;
    color: #9aa7b2;
}

/* Standalone status chips.
 *
 * The grid rule below softened badges inside .platform-data-grid, which left chips that sit on
 * their own -- ESTIMATED, NOT READY, a Draft marker -- still rendering Radzen's saturated
 * brand colours. The result was one page showing a calm "Approved" in a grid and a shouting
 * "ESTIMATED" ten pixels above it. Same palette, same meaning, wherever the chip sits. */
.platform-status-chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border: 1px solid var(--mt-border);
    border-radius: 10px;
    background: #edf1f4;
    color: #34495d;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
}

.platform-status-chip.is-positive {
    border-color: #9bcbaa;
    background: #e8f5ed;
    color: #23743b;
}

.platform-status-chip.is-attention {
    border-color: #e2c48a;
    background: #fdf4e3;
    color: #8a5a10;
}

.platform-status-chip.is-informational {
    border-color: #a8c7e6;
    background: #eaf2fb;
    color: #1a5c98;
}

.platform-status-chip.is-critical {
    border-color: #e0a9a9;
    background: #fbecec;
    color: #a13030;
}

/* Shared Platform status-chip palette for Radzen badges inside a Platform grid.
 *
 * Radzen's stock Success badge is a saturated brand green. On a register where most rows are
 * in the good state -- Posted invoices, Signed contracts, mapped Products -- that colour
 * lands on nearly every row and stops being a signal. These values match the subtler
 * treatment Products already used for Active (#e8f5ed / #23743b), so one page is no longer
 * shouting while its neighbour whispers the same fact.
 *
 * Defined once here rather than per page: every grid that adopts .platform-data-grid should
 * inherit the palette instead of picking its own green. Danger keeps its weight, because a
 * failure is the exception a reader must not miss. */
.platform-data-grid .rz-badge {
    border: 1px solid var(--mt-border);
    background: #edf1f4;
    color: #34495d;
    font-size: 11px;
    font-weight: 600;
}

.platform-data-grid .rz-badge.rz-badge-success {
    border-color: #9bcbaa;
    background: #e8f5ed;
    color: #23743b;
}

.platform-data-grid .rz-badge.rz-badge-info {
    border-color: #a8c7e6;
    background: #eaf2fb;
    color: #1a5c98;
}

.platform-data-grid .rz-badge.rz-badge-warning {
    border-color: #e2c48a;
    background: #fdf4e3;
    color: #8a5a10;
}

.platform-data-grid .rz-badge.rz-badge-light {
    border-color: #d8dfe5;
    background: #f4f7f9;
    color: #607080;
}

/* Shared Platform Radzen grid face. Widths and domain-specific cells stay page-scoped. */
.platform-data-grid .rz-grid-table thead th {
    border-color: #34485c;
    background: #0b2238;
    color: #ffffff;
    font-size: 12px;
    font-weight: 750;
    letter-spacing: 0;
}

.platform-data-grid .rz-grid-table thead th .rz-column-title,
.platform-data-grid .rz-grid-table thead th .rz-column-title-content,
.platform-data-grid .rz-grid-table thead th .rz-sortable-column-icon,
.platform-data-grid .rz-grid-table thead th .rzi {
    color: #ffffff;
    opacity: 1;
}

.platform-data-grid .rz-grid-table thead th .rz-column-title {
    line-height: 1.2;
    white-space: normal;
}

.platform-data-grid .rz-grid-table td {
    color: #1d2f40;
    font-size: 13px;
}

/*
 * Right-aligned columns need an inset on both the header and the cells beneath it.
 *
 * Without it the last character sits flush against the column divider -- the "t" of
 * "Total discount" touching the rule. Header and body get the same value so the numbers
 * stay lined up under their label instead of the header drifting one notch left.
 *
 * Unscoped by design: this applies to every grid using TextAlign.Right, not only the ones
 * that have adopted .platform-data-grid.
 */
.rz-grid-table thead th.rz-text-align-right .rz-column-title,
.rz-grid-table tbody td.rz-text-align-right {
    padding-right: 8px;
}

.platform-data-grid .rz-paginator {
    font-size: 13px;
}

/* Rows with a primary open action use one event-independent affordance. */
.platform-clickable-grid tbody > tr.rz-data-row {
    cursor: pointer !important;
}

.platform-clickable-grid tbody > tr.rz-data-row:hover > td {
    background-color: #eaf4fd !important;
}

/* Shared operational dialog composition. */
.platform-dialog-form {
    display: grid;
    gap: 16px;
    min-width: 0;
}

.platform-dialog-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
}

.platform-dialog-field {
    display: grid;
    align-content: start;
    gap: 5px;
    min-width: 0;
}

.platform-dialog-span {
    grid-column: 1 / -1;
}

.platform-dialog-checkbox {
    display: flex;
    align-items: center;
    align-self: end;
    min-height: 40px;
    gap: 8px;
}

.platform-dialog-field > .rz-label {
    color: #506171;
    font-size: 12px;
    font-weight: 650;
}

.platform-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 4px;
    padding-top: 14px;
    border-top: 1px solid #dce3e8;
}

@media (max-width: 576px) {
    .platform-dialog-grid {
        grid-template-columns: 1fr;
    }

    .platform-dialog-span {
        grid-column: auto;
    }

    .platform-dialog-actions {
        align-items: stretch;
        flex-direction: column-reverse;
    }

    .platform-dialog-actions .rz-button {
        width: 100%;
    }
}

/* Placeholder text remains readable while distinct from entered values. */
.rz-textbox::placeholder,
.rz-inputtext::placeholder,
.rz-autocomplete-input::placeholder,
.rz-datepicker input::placeholder {
    color: #788896;
    opacity: 1;
}

.rz-dropdown-label.rz-placeholder {
    color: #788896;
}

/* Keep transient messages clear of page-level command bars. */
.rz-notification {
    inset-block-start: 4px;
    inset-inline-end: 4px;
    z-index: 1050;
}

/*
    Tab panels are the surface; the page canvas sits behind them.

    Six tabbed pages previously made six independent decisions here -- some white, some
    transparent, some inheriting the theme -- because nothing said what the rule was. The
    panel is white so content inside it is sections rather than cards, which avoids a card
    inside a card and removes any need for elevation on the content.

    Set once, globally. Pages should not override the background; if a page needs different
    padding for its content, override padding alone.
*/
.rz-tabview-panels {
    background: #fff;
}

/* Shared secure-document state. DocumentStatusPoller owns refresh timing;
   this component owns the one visual vocabulary for selected, scanning,
   accepted, and rejected files on staff and customer surfaces. */
.mt-document-upload-status {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--mt-border);
    border-radius: 6px;
    background: var(--mt-surface);
}

.mt-document-upload-status-marker {
    flex: 0 0 14px;
    width: 14px;
    height: 14px;
    border: 2px solid var(--mt-border);
    border-radius: 50%;
}

.mt-document-upload-status.is-selected .mt-document-upload-status-marker {
    border-color: var(--bs-primary);
    background: var(--bs-primary);
}

.mt-document-upload-status.is-pending .mt-document-upload-status-marker {
    border-color: var(--mt-border);
    border-top-color: var(--mt-navy);
    animation: mt-document-status-spin .8s linear infinite;
}

.mt-document-upload-status.is-ready .mt-document-upload-status-marker {
    border-color: var(--mt-green-dark);
    background: var(--mt-green-dark);
}

.mt-document-upload-status.is-failed .mt-document-upload-status-marker {
    border-color: var(--bs-danger);
    background: var(--bs-danger);
}

.mt-document-upload-status-copy {
    display: grid;
    flex: 1 1 auto;
    min-width: 0;
    gap: 2px;
}

.mt-document-upload-status-copy strong {
    overflow-wrap: anywhere;
    font-size: var(--mt-font-body);
    font-weight: 650;
}

.mt-document-upload-status-copy span {
    color: var(--mt-text-muted);
    font-size: var(--mt-font-label);
}

.mt-document-upload-status-actions {
    flex: 0 0 auto;
    margin-left: auto;
}

@keyframes mt-document-status-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .mt-document-upload-status.is-pending .mt-document-upload-status-marker {
        animation: none;
        border-color: var(--mt-navy);
        background: transparent;
    }
}

/*
 * Shared secure upload control (SecureDocumentUpload and its single/multi entry
 * points).
 *
 * These rules live in app.css rather than portal.css because the customer-facing
 * skin is also used by signing, which is not a /portal request and therefore
 * never loads portal.css. Density is the one thing the skin changes: --mt-upload-body
 * is the platform 13px for staff and the documented 15px customer-facing size.
 */
.mt-upload {
    --mt-upload-body: var(--mt-font-body);
    display: grid;
    gap: 8px;
    min-width: 0;
    font-size: var(--mt-upload-body);
}

.mt-upload.is-portal {
    --mt-upload-body: 15px;
}

.mt-upload-label {
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-size: var(--mt-font-label);
    font-weight: 650;
}

.mt-upload.is-portal .mt-upload-label {
    font-size: var(--mt-upload-body);
    font-weight: 600;
}

.mt-upload-optional {
    color: var(--mt-text-muted);
    font-weight: 400;
}

.mt-upload-help {
    margin: 0;
    color: var(--mt-text-muted);
    font-size: var(--mt-font-label);
}

/*
 * Blazor's InputFile renders a bare <input type="file">, so an unstyled
 * "Choose File / No file chosen" sat inside otherwise themed pages. Only the
 * field and its button are restyled; the control keeps its native behavior and
 * keyboard semantics.
 */
.mt-upload-input {
    max-width: 100%;
    padding: .35rem .5rem;
    border: 1px solid var(--mt-border);
    border-radius: 4px;
    background: var(--mt-surface);
    font-size: var(--mt-upload-body);
}

.mt-upload-input::file-selector-button {
    margin-right: .6rem;
    padding: .3rem .7rem;
    border: 1px solid var(--mt-border);
    border-radius: 3px;
    background: #f6f8fa;
    color: inherit;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.mt-upload-input:disabled,
.mt-upload-input:disabled::file-selector-button {
    cursor: not-allowed;
    opacity: .6;
}

/*
 * Customer-facing picker. The native input is laid over a consistent chip so a
 * signer does not meet a different-looking control in each browser. The input
 * stays the focusable, keyboard-operable element; the chip is decorative and is
 * hidden from assistive technology.
 */
.mt-upload-picker {
    position: relative;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
}

.mt-upload-picker-input {
    position: absolute;
    inset: 0;
    z-index: 2;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.mt-upload-picker-input:disabled {
    cursor: not-allowed;
}

.mt-upload-picker-display {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    min-width: 0;
    min-height: 38px;
    overflow: hidden;
    border: 1px solid #aebbc5;
    border-radius: 4px;
    background: var(--mt-surface);
    color: var(--mt-navy);
    font-size: var(--mt-font-label);
}

.mt-upload-picker-input:focus-visible + .mt-upload-picker-display {
    border-color: #006fc9;
    box-shadow: 0 0 0 2px rgba(0, 111, 201, .14);
}

.mt-upload-picker-input:disabled + .mt-upload-picker-display {
    opacity: .6;
}

.mt-upload-picker-button {
    display: inline-flex;
    align-items: center;
    align-self: stretch;
    padding: 0 10px;
    border-right: 1px solid #aebbc5;
    background: #eef2f5;
    font-weight: 650;
    white-space: nowrap;
}

.mt-upload-picker-name {
    min-width: 0;
    padding: 0 10px;
    overflow: hidden;
    color: var(--mt-text-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mt-upload-error {
    margin: 0;
    color: var(--bs-danger);
    font-size: var(--mt-font-label);
}

/*
 * The shared submissions list. Also rendered on its own by surfaces that only
 * display already-submitted documents, so it repeats the density variable
 * rather than depending on a .mt-upload ancestor.
 */
.mt-submission-list {
    --mt-upload-body: var(--mt-font-body);
    display: grid;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.mt-submission-list.is-portal {
    --mt-upload-body: 15px;
}

.mt-submission-list .mt-document-upload-status-copy strong {
    font-size: var(--mt-upload-body);
}

/*
 * The control's own button treatment. Used for the customer skin, where Radzen
 * is unavailable, and for the synchronous Check again command in both skins.
 */
.mt-upload-action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    padding: 4px 12px;
    border: 1px solid var(--mt-border);
    border-radius: 4px;
    background: var(--mt-surface);
    color: inherit;
    font: inherit;
    font-size: var(--mt-font-label);
    line-height: 1.2;
    cursor: pointer;
}

.mt-upload-action:hover:not(:disabled) {
    border-color: var(--mt-navy);
    background: var(--mt-canvas);
}

.mt-upload-action:disabled {
    cursor: not-allowed;
    opacity: .55;
}

.mt-upload-refresh-failure {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    color: var(--mt-text-muted);
    font-size: var(--mt-font-label);
}

/*
 * Preview modal.
 *
 * Fixed position so a scrolling panel, tab body, or table shell cannot clip it.
 * Radzen's DialogService is deliberately not used because App.razor omits Radzen
 * for /portal requests, so a Radzen dialog would never reach a customer.
 */
.mt-upload-preview-overlay {
    position: fixed;
    inset: 0;
    z-index: 1080;
    display: grid;
    place-items: center;
    padding: 24px;
    background: rgba(11, 34, 56, .55);
}

.mt-upload-preview-dialog {
    box-sizing: border-box;
    width: min(1100px, 100%);
    max-height: 100%;
    padding: 16px;
    overflow: auto;
    border-radius: 6px;
    background: var(--mt-surface);
    box-shadow: 0 18px 48px rgba(11, 34, 56, .32);
}

.mt-upload-preview-dialog:focus {
    outline: none;
}

.mt-upload-preview-dialog:focus-visible {
    outline: 2px solid var(--mt-navy);
    outline-offset: 2px;
}

/*
 * PortalDocumentPreview keeps its normal appearance in portal.css. These are the
 * fallbacks that make the same reused primitive legible inside this dialog on a
 * customer-facing route that does not load portal.css.
 */
.mt-upload-preview-dialog .portal-document-preview {
    margin: 0;
    padding: 0;
    border-top: 0;
}

.mt-upload-preview-dialog .portal-document-preview > header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.mt-upload-preview-dialog .portal-document-preview > header > div {
    display: grid;
    min-width: 0;
    gap: 2px;
}

.mt-upload-preview-dialog .portal-document-close {
    display: inline-grid;
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    place-items: center;
    border: 1px solid var(--mt-border);
    border-radius: 4px;
    background: var(--mt-surface);
    cursor: pointer;
}

.mt-upload-preview-dialog .portal-document-frame {
    overflow: hidden;
    height: min(70vh, 760px);
    min-height: 360px;
    border: 1px solid var(--mt-border);
    border-radius: 6px;
    background: var(--mt-canvas);
}

.mt-upload-preview-dialog .portal-document-frame iframe {
    width: 100%;
    height: 100%;
    border: 0;
}

button[data-mission-one-shot-submit].is-submitting,
.portal-one-shot-button.is-submitting {
    cursor: progress;
    opacity: 0.65;
    pointer-events: none;
}

.portal-one-shot-button.is-submitting::before {
    content: "";
    display: inline-block;
    flex: 0 0 .9em;
    width: .9em;
    height: .9em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: mt-portal-command-spin .75s linear infinite;
    vertical-align: -.125em;
}

.portal-one-shot-button.is-submitting > i { display: none; }

@keyframes mt-portal-command-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .portal-one-shot-button.is-submitting::before {
        animation: none;
        border-right-color: currentColor;
    }
}

/*
 * Keeps Tab inside the preview dialog. The sentinels must be focusable, so they
 * cannot be display:none; they are given no size instead.
 */
.mt-upload-preview-sentinel {
    width: 0;
    height: 0;
    overflow: hidden;
    opacity: 0;
}

/*
 * Customer-facing copy reads at the documented 15px. Only genuine labels and
 * metadata stay at the 12px token; help text, failure copy, and the commands a
 * customer has to read and click do not.
 */
.mt-upload.is-portal .mt-upload-help,
.mt-upload.is-portal .mt-upload-error,
.mt-upload.is-portal .mt-upload-picker-display,
.mt-upload.is-portal .mt-upload-action,
.mt-submission-list.is-portal .mt-upload-action,
.mt-upload-refresh-failure.is-portal,
.mt-upload-refresh-failure.is-portal .mt-upload-action {
    font-size: var(--mt-upload-body);
}

.mt-upload.is-portal .mt-upload-action,
.mt-submission-list.is-portal .mt-upload-action,
.mt-upload-refresh-failure.is-portal .mt-upload-action {
    min-height: 36px;
}

/* The scan-status sentence a customer reads ("Security scan in progress...") is
   copy, not metadata, so it takes the customer body size rather than the 12px
   label token the staff density uses. */
.mt-submission-list.is-portal .mt-document-upload-status-copy span,
.mt-upload.is-portal .mt-document-upload-status-copy span {
    font-size: var(--mt-upload-body);
}
