/* ==========================================================================
   SEVOCOMM MTA — Mobile Shell (Phase 2A)
   --------------------------------------------------------------------------
   Bounded responsive shell + navigation + drawer + viewport + spacing /
   touch-target improvements.
   --------------------------------------------------------------------------
   SCOPE GUARANTEES:
   - All rules below are gated by @media (max-width: ...) — desktop styles
     remain untouched at viewports >= 769px.
   - No selector targets queue/table, action-sheet, PKI/cert, cluster, or
     deployment views. Those surfaces are deferred to Phase 2B..2E.
   - This file builds on the existing toggleMobileFolders() scaffolding in
     mail.php; it does NOT introduce new JS state.
   - Phase 2A breakpoints:
       768px — tablet / small-laptop fold (primary mobile entry)
       430px — narrow phone (iPhone 14 Pro and below)
   --------------------------------------------------------------------------
   CAPABILITY CLASSES (added by sevo-ui-env.js — capability-detector phase):
       html.sevo-viewport-mobile     (width <  768px)
       html.sevo-viewport-tablet     (768 <= width < 1024px)
       html.sevo-viewport-desktop    (width >= 1024px)
       html.sevo-touch | html.sevo-no-touch
       html.sevo-pointer-coarse | html.sevo-pointer-fine
       html.sevo-orientation-portrait | html.sevo-orientation-landscape
       html.sevo-reduced-motion      (only when user prefers reduced motion)
       html.sevo-dpr-1 | html.sevo-dpr-2 | html.sevo-dpr-3plus

   Existing @media (max-width: ...) rules below remain AUTHORITATIVE for
   currently-shipping behavior and are not migrated in this pass. NEW rules
   MAY prefer capability-class selectors (e.g. `html.sevo-viewport-mobile
   .foo`) for finer-grained capability gating; mixing forms is permitted.
   Canonical breakpoints are mirrored by the JS detector — keep them in
   sync if changed.
   ========================================================================== */

/* ==========================================================================
   1) Viewport stabilization — applies at all sizes
   --------------------------------------------------------------------------
   These rules are very low-risk and apply globally to prevent the horizontal
   scrollbar / overflow-x oscillation that plagues responsive shells when
   embedded content (search bars, theme blocks) protrudes.
   ========================================================================== */
html, body {
    max-width: 100%;
    overflow-x: hidden;
}

/* Touch-friendly tap behavior on all interactive shell controls */
.mail-header,
.app-launcher,
.folder-pane,
.user-menu,
.auth-card {
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

/* ==========================================================================
   2) TABLET breakpoint — <= 768px
   --------------------------------------------------------------------------
   At this width, the 3-pane mail layout collapses: folder pane becomes a
   drawer (off-canvas, toggled by toggleMobileFolders()), the message list
   and reading pane stack vertically.
   ========================================================================== */
@media (max-width: 768px) {

    /* -- 2.1 Header: keep sticky, restore breathing room ---------------- */
    .mail-header {
        position: sticky;
        top: 0;
        z-index: 100;
        padding-left: 8px;
        padding-right: 8px;
    }

    /* Hide the app brand text (keep the waffle icon) to free width for search */
    .mail-header .app-name {
        display: none;
    }

    /* Header search shrinks but stays usable */
    .mail-header .header-search {
        flex: 1;
        max-width: 100%;
        margin: 0 8px;
    }

    /* Header action icons get a comfortable touch target */
    .mail-header .header-icon,
    .mail-header .user-avatar,
    .mail-header .waffle-btn {
        min-width: 44px;
        min-height: 44px;
    }

    /* -- 2.2 Default layout (non-mail) -------------------------------- */
    .app-content {
        padding: 12px;
    }

    .header-nav {
        gap: 12px !important;
        margin-left: 8px !important;
        overflow-x: auto;
        white-space: nowrap;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .header-nav::-webkit-scrollbar { display: none; }

    .header-nav a {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        padding: 0 8px;
    }

    /* -- 2.3 App rail: thinner but still tappable ------------------- */
    .app-launcher {
        width: 48px;
    }
    .app-launcher .app-icon {
        width: 44px;
        height: 44px;
        font-size: 18px;
    }

    /* -- 2.4 Mail container: stack message-list + reading-pane ------ */
    .mail-container {
        position: relative;
    }

    /* -- 2.5 Folder pane drawer (off-canvas) ------------------------ */
    /*
       Desktop: .folder-pane is an inline flex child sized to var(--folder-pane-width).
       Mobile : we promote it to a position:fixed off-canvas drawer, slide in via .open.
    */
    .folder-pane {
        position: fixed;
        top: 48px;             /* below mail-header */
        bottom: 0;
        left: 0;
        width: 280px;
        max-width: 85vw;
        z-index: 90;
        transform: translateX(-100%);
        transition: transform 0.22s ease-out;
        box-shadow: 2px 0 12px rgba(0, 0, 0, 0.18);
        background: var(--outlook-sidebar-bg, #fafafa);
    }

    .folder-pane.open {
        transform: translateX(0);
    }

    /* Drawer backdrop: rendered via :before so we don't add new HTML */
    .folder-pane.open::before {
        content: '';
        position: fixed;
        top: 48px;
        left: 280px;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.32);
        z-index: -1;
        /* Backdrop is decorative — JS click-to-close on outside is a Phase 2C nice-to-have */
    }

    /* Folder items: larger touch targets */
    .folder-item {
        min-height: 44px;
        padding-top: 10px;
        padding-bottom: 10px;
    }

    /* -- 2.6 Message list + reading pane stacking ------------------- */
    /*
       When viewport collapses to single column, both panes flex to full width.
       The folder-pane is OUT of the flow (position:fixed drawer), so the
       remaining children naturally take 100% via flex:1.
    */
    .message-list-pane,
    .reading-pane,
    .app-content-pane {
        flex: 1 1 100%;
        min-width: 0;
    }

    /* -- 2.7 User menu: align with mobile width ------------------- */
    .user-menu {
        right: 8px !important;
        left: auto;
        width: calc(100vw - 16px);
        max-width: 320px;
    }
    .user-menu-item {
        min-height: 44px;
        padding: 12px 16px;
    }

    /* -- 2.8 Auth page tightening ------------------- */
    .auth-container {
        padding: 16px;
    }
    .auth-card {
        width: 100%;
        max-width: 100%;
        margin: 0;
    }
    .auth-lang-selector {
        top: 8px !important;
        right: 8px !important;
        gap: 4px !important;
    }
    .auth-lang-link {
        min-width: 32px;
        min-height: 32px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* -- 2.9 Generic touch-target baseline for primary buttons / inputs ----
       Scoped narrowly to common form controls inside the shell — does NOT
       cascade into queue tables (those are deferred to Phase 2B).
    */
    .auth-content button,
    .auth-content input[type="submit"],
    .auth-content .btn,
    .new-mail-btn {
        min-height: 44px;
    }
    .auth-content input[type="text"],
    .auth-content input[type="email"],
    .auth-content input[type="password"] {
        min-height: 44px;
        font-size: 16px; /* prevents iOS zoom-on-focus */
    }
}

/* ==========================================================================
   3) NARROW PHONE breakpoint — <= 430px
   --------------------------------------------------------------------------
   At this width, header icons fold further and side padding tightens.
   ========================================================================== */
@media (max-width: 430px) {

    /* Hide the bell + admin icons in the very narrow header to leave room
       for the avatar + settings; users can reach admin via the waffle drawer
       or the avatar menu. Notifications surface is deferred to Phase 2C. */
    .mail-header .header-actions .header-icon[title*="otification" i] {
        display: none;
    }

    /* Tighten header search */
    .mail-header .header-search {
        margin: 0 4px;
    }
    .mail-header .header-search input {
        font-size: 14px;
    }

    /* Folder drawer takes more of the viewport on small phones */
    .folder-pane {
        width: 88vw;
        max-width: 320px;
    }

    /* Folder drawer backdrop offset matches new width */
    .folder-pane.open::before {
        left: 88vw;
    }

    /* Tighten app-content gutter */
    .app-content {
        padding: 8px;
    }

    /* Tighten auth card padding on narrow phones */
    .auth-card {
        padding: 16px !important;
    }
    .auth-header h1 {
        font-size: 1.25rem;
    }
    .auth-header p {
        font-size: 0.875rem;
    }
}

/* ==========================================================================
   4) Accessibility: respect reduced motion preference
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    .folder-pane {
        transition: none;
    }
}

/* ==========================================================================
   END Phase 2A — mobile-shell.css
   ========================================================================== */


/* ==========================================================================
   SEVOCOMM MTA — Mobile Tables (Phase 2B — appended 2026-05-13)
   --------------------------------------------------------------------------
   Scope: mail queue / mail status views only
       admin/queue.php             (.data-table#queue-table)
       admin/mail-flow-audit.php   (.audit-table)
       admin/message-trace.php     (.results-table — JS-generated)

   Strategy:
     1) `.table-responsive` is a NO-OP at desktop widths. The wrapper exists
        purely as a hook for narrow-viewport overflow containment.
     2) At <=768px, the wrapper provides horizontal-scroll containment so
        wide tables (queue: 11 columns; results: 7 columns; audit: 5 cols)
        do NOT push the page wider than the viewport.
     3) At <=430px we tighten cell padding and apply a card-style fallback
        for the .audit-table and .results-table (queue.css already has its
        own row-stack at <=768px so we leave its mechanism intact).
     4) No column-hiding at desktop. Every rule below is gated by @media.
   ========================================================================== */

/* --- Default (>=769px) — no-op wrapper, no visual change ------------------ */
.table-responsive {
    width: 100%;
}

/* --- Tablet and narrower (<=768px) — overflow containment ----------------- */
@media (max-width: 768px) {
    .table-responsive {
        display: block;
        width: 100%;
        max-width: 100%;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        /* Sub-pixel scroll-bar avoidance on iOS Safari */
        scrollbar-width: thin;
    }

    /* Hairline indicator that the table can scroll horizontally */
    .table-responsive {
        border-radius: 4px;
    }

    /* Force tables inside the responsive wrapper to honour their own intrinsic
       width — overflow-x:auto on the wrapper then scrolls past the viewport. */
    .table-responsive > table {
        min-width: 100%;
    }

    /* The audit-table and results-table inherit the wrapper scroll; tighten
       padding so the un-stacked row still fits on a 768px tablet. */
    .audit-table th,
    .audit-table td,
    .results-table th,
    .results-table td {
        padding: 0.5rem 0.625rem;
        font-size: 0.875rem;
    }
}

/* --- Narrow phone (<=430px) — card-stack fallback for audit + results ----- */
/* queue.css already stacks .data-table rows at <=768px (its own breakpoint).
   The two tables below have no equivalent stack rule in their feature CSS,
   so we provide a minimal card-stack here, scoped strictly to <=430px so
   tablets (431..768px) still see the (now-scrollable) table form. */
@media (max-width: 430px) {

    .audit-table,
    .results-table {
        font-size: 0.8125rem;
    }

    /* Hide header row; rely on per-cell labels (where present) or sequence. */
    .audit-table thead,
    .results-table thead {
        display: none;
    }

    .audit-table tr,
    .results-table tr {
        display: block;
        margin-bottom: 0.75rem;
        border: 1px solid rgba(0, 0, 0, 0.12);
        border-radius: 4px;
        padding: 0.625rem 0.75rem;
        background: var(--card-bg, #fff);
    }

    .audit-table td,
    .results-table td {
        display: block;
        text-align: left;
        padding: 0.25rem 0 !important;
        border: none !important;
        word-break: break-word;
    }

    /* If a data-label is present we surface it (matches queue.css convention);
       otherwise the cell simply renders as a labelless block — readable. */
    .audit-table td[data-label]::before,
    .results-table td[data-label]::before {
        content: attr(data-label);
        display: block;
        font-weight: 600;
        font-size: 0.6875rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--text-muted, #666);
        margin-bottom: 0.125rem;
    }

    /* Keep the responsive wrapper from adding its own scroll once the rows
       have stacked vertically — overflow no longer relevant at this point. */
    .table-responsive {
        overflow-x: visible;
    }
}

/* ==========================================================================
   END Phase 2B — mobile tables
   ========================================================================== */

/* ==========================================================================
   Phase 2C — Progressive disclosure ("More" sheet) + bottom-action refinement
   --------------------------------------------------------------------------
   SCOPE GUARANTEES:
   - All new selectors are either:
       (a) initially [hidden] (so they affect nothing without JS activation), or
       (b) gated by @media (max-width: 768px) (so desktop is untouched).
   - The "More" trigger (.more-trigger) is hidden at desktop and revealed only
     at <=768px. At desktop, ALL original action buttons remain visible inline.
   - The "More" sheet (.more-sheet) is a bottom-anchored overlay at <=768px.
     Its [hidden] attribute keeps it out of the accessibility tree by default.
   - .more-sheet [data-action] are CLICK-RELAY buttons only. The real action
     handler (with CSRF / confirm() / form submit) stays on the original
     in-page button. No new fetch() / form action is introduced.
   - Existing action rows (.page-actions, .control-buttons, .action-bar,
     .quarantine-actions, .message-toolbar, .modal-footer) get bottom-oriented
     spacing/touch-target refinement only at <=768px. No HTML restructuring.
   ========================================================================== */

/* The trigger is added inline to existing action rows. Default: hidden.
   Mobile breakpoint un-hides it. This makes desktop a pure no-op. */
.more-trigger {
    display: none;
}

/* The sheet is hidden by default (HTML [hidden] attribute). When opened
   on mobile, it slides up from the bottom. Above 768px, it is permanently
   hidden via [hidden] (no @media override at desktop). */
.more-sheet[hidden] {
    display: none !important;
}

/* Phase 2C — Mobile activations: <= 768px */
@media (max-width: 768px) {

    /* -- Show the "More" trigger -- */
    .more-trigger {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
        padding: 8px 14px;
        font-size: 0.875rem;
        font-weight: 500;
        line-height: 1;
        border: 1px solid var(--border-color, #d0d0d0);
        border-radius: 6px;
        background: #fff;
        color: var(--text-primary, #333);
        cursor: pointer;
        touch-action: manipulation;
    }

    .more-trigger:focus-visible {
        outline: 2px solid #0078d4;
        outline-offset: 2px;
    }

    /* -- Bottom-anchored "More" sheet at <= 768px ------------------------ */
    .more-sheet {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1100;
        background: #fff;
        border-top-left-radius: 12px;
        border-top-right-radius: 12px;
        box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18);
        padding: 12px 12px calc(env(safe-area-inset-bottom, 0px) + 16px);
        max-height: 70vh;
        overflow-y: auto;
        animation: more-sheet-slide-up 180ms ease-out;
    }

    /* Scrim — clicking outside the sheet closes it (JS reads the class).
       Drawn via ::before so we don't need extra DOM. */
    .more-sheet::before {
        content: "";
        position: fixed;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.32);
        z-index: -1;
        animation: more-sheet-scrim-fade 180ms ease-out;
    }

    /* Grab-handle affordance at the top of the sheet */
    .more-sheet::after {
        content: "";
        display: block;
        width: 36px;
        height: 4px;
        background: #d0d0d0;
        border-radius: 2px;
        margin: 4px auto 12px;
    }

    /* Items inside the sheet stack vertically and inherit large touch targets */
    .more-sheet [data-action],
    .more-sheet .more-sheet-item {
        display: flex;
        align-items: center;
        gap: 12px;
        width: 100%;
        min-height: 48px;
        padding: 12px 14px;
        border: none;
        background: transparent;
        text-align: left;
        font: inherit;
        color: var(--text-primary, #222);
        border-radius: 8px;
        cursor: pointer;
        touch-action: manipulation;
    }

    .more-sheet [data-action]:hover,
    .more-sheet [data-action]:focus-visible {
        background: var(--surface-hover, #f3f3f3);
        outline: none;
    }

    .more-sheet [data-action][data-destructive="true"] {
        color: #b00020;
    }

    /* -- Bottom-oriented refinement of existing action rows -- */
    /* These rules apply CSS-only spacing + touch-size to existing action
       button rows. NO HTML or handler changes. */
    .page-actions,
    .quarantine-actions,
    .action-bar,
    .control-buttons,
    .message-toolbar,
    .form-footer {
        gap: 8px;
        flex-wrap: wrap;
    }

    .page-actions .btn,
    .quarantine-actions .btn,
    .action-bar .btn,
    .control-buttons .btn,
    .message-toolbar .btn-icon,
    .form-footer .btn-save,
    .form-footer .btn-cancel {
        min-height: 44px;
        min-width: 44px;
    }

    /* Modal footers (queue.php uses this for retry/hold/delete on a message)
       become a stacked, sticky bottom-action row for thumb reach. */
    .modal-footer {
        gap: 8px;
        flex-wrap: wrap;
    }

    .modal-footer .btn {
        min-height: 44px;
        flex: 1 1 auto;
    }
}

/* Narrow phones — make the sheet items even more spacious */
@media (max-width: 430px) {
    .more-sheet [data-action],
    .more-sheet .more-sheet-item {
        min-height: 52px;
        font-size: 1rem;
    }
}

/* Respect reduced-motion */
@media (prefers-reduced-motion: reduce) {
    .more-sheet,
    .more-sheet::before {
        animation: none !important;
    }
}

@keyframes more-sheet-slide-up {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
}

@keyframes more-sheet-scrim-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ==========================================================================
   END Phase 2C — More sheet + bottom-action refinement
   ========================================================================== */

/* ==========================================================================
   SEVOCOMM MTA — Mobile Admin / Dashboard / Settings (Phase 2D — appended 2026-05-13)
   --------------------------------------------------------------------------
   Scope: admin dashboard, settings, deployment/status, admin forms, cards,
   panels, grids; non-mail operational tables OUTSIDE the Phase 2B trio AND
   OUTSIDE excluded surfaces (cluster/PKI/cert/activation).

   Strategy:
     1) Every rule below is gated by @media (max-width: 768px) or 430px;
        desktop styles remain untouched at viewports >= 769px.
     2) Patterns used:
          - `.page-header` action row stacks below title at narrow widths.
          - `.tabs` (admin-wide tab nav) becomes horizontally scrollable
            instead of wrapping/clipping.
          - `.cert-status-banner` / `.alert-status-banner` collapse the
            metrics row to a 2-col grid then a single column on phones.
          - `.cert-controls` / `.filter-controls` stack their children at
            narrow widths so filter <select>s no longer overflow.
          - `.settings-form` / `.form-row` collapse to single column.
          - Form inputs gain a 16px font-size floor at <=430px to suppress
            iOS zoom-on-focus.
          - `.bulk-actions` / `.bulk-buttons` wrap onto multiple lines.
          - `.wizard-actions` / `.roles-header` wrap and full-width on phones.
          - `.table-responsive` newly wraps the admin non-mail tables added
            in Phase 2D (users-table-container, data-table, history-table,
            health-timeline-table-wrap) — reusing the Phase 2B mechanism.
     3) No selector targets cluster.php, cluster-*.php, certificates.php,
        cert-*.php, pki-*.php, email-auth.php, domain-cert-*.php, or
        activation surfaces. Excluded surfaces remain byte-identical.
     4) No HTML-restructuring rules; everything is CSS-only.
   ========================================================================== */

/* --- Tablet and narrower (<=768px) — admin shell refinements -------------- */
@media (max-width: 768px) {

    /* -- 2D.1 Page-header action row stacks below title at narrow widths --
       The .page-header is a flex row on desktop (title left, actions right).
       At <=768px we let it wrap and align both ends to the start so the
       action buttons no longer overflow on top of the title.
    */
    .admin-main-content .page-header {
        flex-wrap: wrap;
        gap: 8px;
    }
    .admin-main-content .page-header .page-actions {
        flex-wrap: wrap;
        gap: 8px;
    }
    .admin-main-content .page-header .page-actions .btn {
        min-height: 44px;
    }

    /* -- 2D.2 Tabs horizontal scroll (admin-wide pattern) -----------------
       Many admin views (settings, status-sla, updates, users, monitoring,
       notifications, migration) use a `.tabs` row with 5..8 buttons.
       At desktop they wrap; at <=768px the wrap looks broken. Switch to
       horizontal overflow-scroll with hidden scrollbar.
    */
    .admin-main-content .tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .admin-main-content .tabs::-webkit-scrollbar { display: none; }
    .admin-main-content .tabs .tab-btn {
        flex-shrink: 0;
        min-height: 44px;
        white-space: nowrap;
    }

    /* -- 2D.3 Status banners — stack metric row vertically ----------------
       Both .cert-status-banner (status-sla, updates) and .alert-status-banner
       (notifications) lay out as [icon | text | metrics-row]. At <=768px the
       metrics row collapses below text. Inner metrics keep their existing
       per-feature breakpoints (notifications.css already handles 480/360px
       sub-cases; we only enforce the wrap).
    */
    .admin-main-content .cert-status-banner,
    .admin-main-content .alert-status-banner {
        flex-wrap: wrap;
        gap: 12px;
    }
    .admin-main-content .cert-status-banner .status-metrics,
    .admin-main-content .alert-status-banner .status-metrics {
        flex-wrap: wrap;
        gap: 8px 16px;
    }

    /* -- 2D.4 Cert / filter controls — stack at narrow widths -------------
       .cert-controls and .filter-controls are typically flex rows of a
       select + button. At narrow widths we let them wrap and make children
       fill the row.
    */
    .admin-main-content .cert-controls,
    .admin-main-content .filter-controls,
    .admin-main-content .filter-group,
    .admin-main-content .content-header {
        flex-wrap: wrap;
        gap: 8px;
    }
    .admin-main-content .filter-select,
    .admin-main-content .search-input {
        min-height: 44px;
    }

    /* -- 2D.5 Settings forms — labels-above-inputs at narrow widths -------
       .form-row at desktop is typically a two-column grid. Collapse to one
       column at <=768px and let inputs span the full width.
    */
    .admin-main-content .form-row,
    .admin-main-content .mig-form-row {
        display: flex;
        flex-direction: column;
        gap: 12px;
    }
    .admin-main-content .form-row .form-group,
    .admin-main-content .mig-form-row .form-group {
        width: 100%;
        min-width: 0;
    }
    .admin-main-content .form-input,
    .admin-main-content .form-select,
    .admin-main-content .form-textarea {
        width: 100%;
        max-width: 100%;
        box-sizing: border-box;
    }

    /* -- 2D.6 Bulk-actions row wraps on narrow viewports ------------------
       .bulk-actions (users.php) shows count + 3 buttons in a row. Let it
       wrap and let the buttons grow.
    */
    .admin-main-content .bulk-actions {
        flex-wrap: wrap;
        gap: 8px;
    }
    .admin-main-content .bulk-buttons {
        flex-wrap: wrap;
        gap: 6px;
    }
    .admin-main-content .bulk-buttons .btn {
        flex: 1 1 auto;
        min-height: 44px;
    }

    /* -- 2D.7 Wizard / role / section headers — wrap actions --------------
       .wizard-actions, .roles-header, .section-header used across the admin
       wizards (migration, users-roles, settings sections).
    */
    .admin-main-content .wizard-actions,
    .admin-main-content .roles-header,
    .admin-main-content .section-header {
        flex-wrap: wrap;
        gap: 8px;
    }
    .admin-main-content .wizard-actions .btn,
    .admin-main-content .roles-header .btn {
        min-height: 44px;
    }
}

/* --- Narrow phone (<=430px) — admin spacing tightening + iOS zoom guard --- */
@media (max-width: 430px) {

    /* -- 2D.8 Tighten main content gutter on small phones ----------------- */
    .admin-main-content {
        padding-left: 12px !important;
        padding-right: 12px !important;
    }

    /* -- 2D.9 Page-header h1 a touch smaller on narrow phones ------------- */
    .admin-main-content .page-header h1 {
        font-size: 20px;
    }

    /* -- 2D.10 Suppress iOS zoom-on-focus on admin form inputs ------------ */
    .admin-main-content .form-input,
    .admin-main-content .form-select,
    .admin-main-content .form-textarea,
    .admin-main-content .filter-select,
    .admin-main-content .search-input {
        font-size: 16px;
    }

    /* -- 2D.11 Stats grid collapses to single column on phones -----------
       Most admin views use `.stats-grid` (auto-fit / minmax(220px,1fr));
       on small phones the 220px floor forces 1 column anyway, but several
       feature-CSS overrides force `1fr 1fr`. Honor single-column here.
    */
    .admin-main-content .stats-grid {
        grid-template-columns: 1fr !important;
    }
}

/* ==========================================================================
   END Phase 2D — admin / dashboard / settings / deployment / status
   ========================================================================== */


/* ==========================================================================
   Phase 2F — Mobile swipe-reveal pattern (operator-locked, mobile-only)
   --------------------------------------------------------------------------
   2026-05-16 architecture rewrite — LAYERED REVEAL model (Apple-Mail style):
     - .swipe-row is `position: relative; overflow: hidden`.
     - .swipe-actions panel sits ABSOLUTELY inside the row at right:0,
       BEHIND the content (z-index:0). At rest it is fully covered by the
       row's content wrapper (.swipe-row__content, z-index:1).
     - Only the .swipe-row__content layer translates left on swipe; the
       action panel stays put and becomes visually revealed as the content
       slides over it.
     - Row's overflow:hidden ensures actions never spill outside the row.
     - This replaces the prior "panel-positioned-at-right:-150px" exposed
       model which leaked when the parent had overflow-x:visible.

   Safety contract unchanged:
     - Swipe REVEALS the panel; user must TAP a revealed button to invoke.
     - Swipe never executes. Destructive handlers retain their confirm().
     - Mobile-only via @media (max-width: 768px) AND JS mobile gate.
     - Desktop is inert; swipe markup hidden, content rendered normally.
   ========================================================================== */
@media (max-width: 768px) {

    /* Row: overflow-hidden box that hosts the content layer + actions layer. */
    .swipe-row {
        position: relative;
        overflow: hidden;
    }

    /* Content layer — sits ABOVE actions panel, covers it fully at rest.
       Only this layer translates on swipe.

       2026-05-16 v2 correction: wrapper now uses negative-margin trick to
       break out of the .message-item padding box (10px 16px) so it spans
       the FULL row width — necessary to cover the absolutely-positioned
       .swipe-actions panel (which is anchored to row's outer right edge).
       Padding is RE-APPLIED inside the wrapper so message text spacing is
       visually identical. */
    .swipe-row > .swipe-row__content {
        position: relative;
        z-index: 1;
        background: var(--outlook-surface, #ffffff);
        /* Solid opaque background that matches the theme's row surface so
           the panel behind is hidden until swipe. Theme variable falls
           back to white. */
        transition: transform 0.22s ease-out;
        will-change: transform;
        touch-action: pan-y;
        display: block;
        width: 100%;
        box-sizing: border-box;
    }
    .swipe-row.swipe-dragging > .swipe-row__content {
        transition: none;
    }

    /* .message-item-specific: pull wrapper out of the row's padding box
       (10px 16px in outlook365 theme) so it spans the full row width. The
       row's padding is set to 0 at mobile and applied inside the wrapper
       instead, preserving the visual spacing. */
    .swipe-row.message-item {
        padding: 0 !important;
    }
    .swipe-row.message-item > .swipe-row__content {
        padding: 10px 16px;
    }

    /* Unread-row background preservation: .message-item.unread has its own
       background; mirror it onto the wrapper so the unread visual cue is
       preserved when the wrapper covers the row's content area. */
    .swipe-row.message-item.unread > .swipe-row__content {
        background: var(--outlook-surface, #ffffff);
    }
    /* Selected-row background preservation. */
    .swipe-row.message-item.selected > .swipe-row__content {
        background: var(--outlook-selected-bg, #EFF6FC);
    }

    /* <tr> rows: cannot inject a div wrapper without breaking table flow.
       JS detects TR and skips wrapper. Legacy "transform the row" model
       handles these rows; no wrapper styles apply. */

    /* Actions panel — sits BEHIND content, anchored at the right edge of
       the row. z-index:0 keeps it below the content layer. align-items:
       center vertically centers the buttons so they match the visual
       baseline of the row's text content (not stretched to row height). */
    .swipe-row > .swipe-actions {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        z-index: 0;
        display: flex;
        align-items: center;
        gap: 0;
        background: var(--surface-secondary, #f3f3f5);
        pointer-events: auto;
    }

    /* Left-side actions panel — mirror of .swipe-actions but anchored to
       the left edge. Revealed by right-swipe (positive translateX on the
       content layer). Used by mailbox inbox rows for Read/Unread toggle.
       width:auto with display:flex on an absolute element can collapse
       to 0 in WebKit until first paint; set min-width to the per-button
       footprint (64px) so getBoundingClientRect returns a real number
       immediately and the right-swipe gate opens on touchstart. */
    .swipe-row > .swipe-actions-left {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 0;
        display: flex;
        align-items: center;
        gap: 0;
        background: var(--surface-secondary, #f3f3f5);
        pointer-events: auto;
        min-width: 64px;
    }
    @media (max-width: 360px) {
        .swipe-row > .swipe-actions-left {
            min-width: 58px;
        }
    }

    /* Individual action button — Apple-Mail proportions. Fixed height so
       buttons match the message-line visual extent rather than stretching
       to the row's full height (which made them look too tall). */
    .swipe-action {
        flex: 0 0 auto;
        width: 64px;
        height: 100%;
        min-height: 44px;
        border: none;
        background: var(--info, #6c757d);
        color: #ffffff;
        font-size: 11px;
        font-weight: 500;
        cursor: pointer;
        padding: 4px 2px;
        display: inline-flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        line-height: 1.1;
        text-align: center;
    }
    .swipe-action:active {
        filter: brightness(0.92);
    }
    .swipe-action i {
        font-size: 18px;
    }
    .swipe-action.destructive {
        background: var(--danger, #d83b3b);
    }
    .swipe-action.warning {
        background: var(--warning, #e08a00);
    }
    .swipe-action.neutral {
        background: var(--accent, #007AFF);
    }

    /* Edge cases:
       - <tr> rows use overflow:hidden; we already set it above for .swipe-row.
       - On very narrow screens (<360px) we tighten the action width slightly. */
    @media (max-width: 360px) {
        .swipe-action {
            width: 58px;
            font-size: 10px;
        }
        .swipe-action i {
            font-size: 16px;
        }
    }
}

/* Desktop (>=769px) — swipe markup is inert. Hide panel and unwrap content
   visually so rows look exactly as they did pre-Phase-2F. The content
   wrapper still exists in DOM (JS-inserted) but is layout-transparent. */
@media (min-width: 769px) {
    .swipe-row > .swipe-actions,
    .swipe-row > .swipe-actions-left {
        display: none;
    }
    .swipe-row > .swipe-row__content {
        /* Transparent passthrough — no positioning, no transition. */
        position: static;
        transition: none;
        background: transparent;
        will-change: auto;
        touch-action: auto;
    }
    .swipe-row {
        overflow: visible;
    }
}

/* Reduced-motion users — no slide animation. The reveal still works
   (transform is applied to the content layer) but without easing. */
@media (prefers-reduced-motion: reduce) {
    .swipe-row > .swipe-row__content {
        transition: none;
    }
}

/* ==========================================================================
   END Phase 2F — Mobile swipe-reveal pattern
   ========================================================================== */


/* ==========================================================================
   Phase 2G — Admin sidebar mobile drawer (2026-05-15)
   --------------------------------------------------------------------------
   Defect: admin.css @media (max-width: 768px) collapses .admin-sidebar's
   <nav><ul> to display:flex; overflow-x:auto — rendering all section
   groups as a horizontal tab-strip on mobile/tablet, which is unusable.

   Fix: at <= 1023px we override that legacy rule and promote
   .admin-sidebar to an off-canvas drawer matching the .folder-pane pattern
   from Phase 2A. A hamburger button (.admin-nav-toggle) — emitted always in
   the admin-sidebar.php markup but [hidden] until CSS un-hides — toggles
   the .open state. A scrim (.admin-nav-scrim) handles click-outside close.

   Desktop (>= 1024px) is UNCHANGED: the rules below are gated by
   @media (max-width: 1023px). The trigger/scrim elements stay [hidden]
   at desktop via the [hidden] attribute (no override here).
   ========================================================================== */

/* -- Trigger & scrim: hidden at desktop (default), revealed at <= 1023px. */
.admin-nav-toggle[hidden],
.admin-nav-scrim[hidden] {
    display: none;
}

@media (max-width: 1023px) {

    /* -- 2G.1 Hamburger trigger — visible only at mobile/tablet ----------
       Phase 2H (2026-05-15): repositioned from `position: fixed; top:56px`
       to `position: absolute` anchored inside .admin-dashboard. This puts
       the trigger inside the page-chrome of the admin content area instead
       of floating below the mail-header, eliminating the orphaned look. */
    .admin-nav-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 8px;
        left: 8px;
        z-index: 95;
        width: 40px;
        height: 40px;
        padding: 0;
        border: 1px solid var(--outlook-border, #E1DFDD);
        border-radius: 4px;
        background: var(--outlook-card-bg, #ffffff);
        color: var(--outlook-text, #323130);
        font-size: 16px;
        cursor: pointer;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    }

    /* When [hidden] attribute is set initially, the global rule above wins;
       once JS strips [hidden] on viewport-mobile/tablet, the rules here apply. */
    .admin-nav-toggle:hover,
    .admin-nav-toggle:focus-visible {
        background: var(--outlook-sidebar-hover, #F3F2F1);
        outline: none;
    }

    /* -- 2G.2 Override admin.css tab-strip rules ------------------------- */
    /*
       admin.css @ <= 768px makes .admin-dashboard column + .admin-sidebar
       full-width + nav ul flex-row. Earlier Phase 2G attempts used bare
       selectors (.admin-dashboard, .admin-sidebar) which lose the cascade
       to admin.css's later-loaded same-specificity rules (admin.css ships
       AFTER mobile-shell.css in the layout's <link> order — confirmed via
       live HTML head capture 2026-05-16). All structural drawer rules
       below are therefore prefixed with html.sevo-viewport-mobile /
       html.sevo-viewport-tablet so their specificity (0,1,1,0) out-ranks
       admin.css's bare selectors (0,0,1,0) regardless of load order.
    */
    html.sevo-viewport-mobile  .admin-dashboard,
    html.sevo-viewport-tablet  .admin-dashboard {
        flex-direction: row;
        /* Phase 2H: anchor the absolute-positioned .admin-nav-toggle here
           so the trigger sits inside the admin chrome rather than floating
           below the mail-header at fixed top:56. */
        position: relative;
    }

    html.sevo-viewport-mobile  .admin-sidebar,
    html.sevo-viewport-tablet  .admin-sidebar {
        /* Off-canvas drawer */
        position: fixed;
        top: 48px;             /* below admin-header */
        bottom: 0;
        left: 0;
        width: 280px;
        max-width: 85vw;
        padding: 12px 0;
        border-right: 1px solid var(--outlook-border, #E1DFDD);
        border-bottom: none;
        z-index: 90;
        transform: translateX(-100%);
        transition: transform 0.22s ease-out;
        box-shadow: 2px 0 12px rgba(0, 0, 0, 0.18);
        overflow-y: auto;
    }

    html.sevo-viewport-mobile  .admin-sidebar.open,
    html.sevo-viewport-tablet  .admin-sidebar.open {
        transform: translateX(0);
    }

    /* Re-show the sidebar heading inside the drawer (admin.css hides it
       at <=768px because it was a tab-strip; drawers want their label). */
    html.sevo-viewport-mobile  .admin-sidebar h2,
    html.sevo-viewport-tablet  .admin-sidebar h2 {
        display: block;
    }

    /* Reverse the flex tab-strip rule from admin.css. The capability-
       prefixed selectors (specificity 0,1,1,0) out-rank admin.css's
       same-specificity rules regardless of cascade load order. */
    html.sevo-viewport-mobile  .admin-sidebar nav ul,
    html.sevo-viewport-tablet  .admin-sidebar nav ul {
        display: block;
        overflow-x: visible;
        gap: 0;
    }

    /* Group-section rows are top-level <li> inside the outer <ul>; ensure
       they stack vertically and don't pick up nowrap from the tab-strip. */
    html.sevo-viewport-mobile  .admin-sidebar nav > ul > li.admin-nav-group,
    html.sevo-viewport-tablet  .admin-sidebar nav > ul > li.admin-nav-group {
        display: block;
        white-space: normal;
    }

    /* Top-level nav anchors (legacy non-group items, if any): restore
       border-left active indicator + remove tab-strip whitespace tweaks. */
    html.sevo-viewport-mobile  .admin-sidebar nav ul li a,
    html.sevo-viewport-tablet  .admin-sidebar nav ul li a {
        border-left: 3px solid transparent;
        border-bottom: none;
        white-space: normal;
        padding: 10px 16px;
        min-height: 44px;
    }

    html.sevo-viewport-mobile  .admin-sidebar nav ul li.active a,
    html.sevo-viewport-tablet  .admin-sidebar nav ul li.active a {
        border-left-color: var(--outlook-primary, #0078D4);
        border-bottom-color: transparent;
    }

    /* Section group rows (the collapsible <div class="admin-nav-section">):
       larger tap targets for the section header. */
    html.sevo-viewport-mobile  .admin-sidebar .admin-nav-section,
    html.sevo-viewport-tablet  .admin-sidebar .admin-nav-section {
        min-height: 44px;
        padding-top: 12px;
        padding-bottom: 8px;
    }

    /* Section items (sub-nav <li> anchors): touch-friendly height. */
    html.sevo-viewport-mobile  .admin-sidebar .admin-nav-items li a,
    html.sevo-viewport-tablet  .admin-sidebar .admin-nav-items li a {
        min-height: 44px;
        padding-top: 10px;
        padding-bottom: 10px;
    }

    /* -- 2G.3 Scrim ----------------------------------------------------- */
    .admin-nav-scrim {
        position: fixed;
        top: 48px;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.32);
        z-index: 89;            /* just below the drawer (90) */
    }

    /* Hide the trigger when the drawer is open and indicate state via
       aria-expanded — purely visual reinforcement; JS owns the attribute. */
    .admin-nav-toggle[aria-expanded="true"] {
        background: var(--outlook-sidebar-active, #EDEBE9);
    }

    /* -- 2G.4 Main content area --------------------------------------------
       Phase 2H (2026-05-15): the prior `padding-top: 56px` reservation
       stacked on top of admin.css's existing `padding: 16px 20px` (≤768px)
       and produced ~80px of dead vertical space between the mail-header
       and the first piece of page content (the .page-header h1). The
       hamburger is now position:absolute inside .admin-dashboard, so no
       top-padding reservation is needed — admin.css's existing padding is
       sufficient. We only nudge the .page-header content rightward so the
       absolute hamburger (40px wide + 8px left) doesn't overlap the h1. */
    .admin-main-content .page-header,
    .admin-main-content > main > .page-header {
        padding-left: 56px;
        min-height: 40px;
    }

}

/* -- 2H.1 Drawer width — tighter on small phones ----------------------
   Phase 2H (2026-05-15): 280px on a 390px iPhone viewport felt desktop-
   ish. Cap to 260px at ≤430px so the drawer occupies ~67% of the
   viewport with healthy peek of the scrim/content behind. Tablets keep
   the Phase 2G value of 280px. Desktop (≥1024px) unchanged. */
@media (max-width: 430px) {
    html.sevo-viewport-mobile  .admin-sidebar {
        width: 260px;
    }
}

/* -- 2G.5 Reduced motion — skip drawer slide animation ----------------- */
@media (max-width: 1023px) and (prefers-reduced-motion: reduce) {
    html.sevo-viewport-mobile  .admin-sidebar,
    html.sevo-viewport-tablet  .admin-sidebar {
        transition: none;
    }
}

/* ==========================================================================
   END Phase 2G — Admin sidebar mobile drawer
   ========================================================================== */
