/* phone.css
 *
 * The single source of truth for phone-portrait layout overrides
 * (docs/planning/phone-responsive-layout-plan.md). Linked last, after every other stylesheet, so
 * its rules win by source order alone -- no !important needed anywhere in this file.
 *
 * Scope: exactly one breakpoint, @media (max-width: 640px), and nothing else. This file never
 * redefines a component's base rules; it only adds phone-scoped adjustments inside that one
 * breakpoint. Tablet and desktop are unaffected by definition -- nothing here ever applies above
 * 640px.
 *
 * This replaces the previous scattered, per-file phone/tablet media queries rather than
 * extending them -- see the plan doc for which existing rules are being superseded and why.
 */

@media (max-width: 640px) {
    /* .profile-panel is a fixed 320px (styles.css) regardless of viewport width -- on a
       375-430px phone that leaves 55-110px of the underlying page visible down the left edge,
       and is the exact bug from the original screenshot. Full-width here; the internal field-row
       layout is already flex-based with min-width:0/ellipsis throughout (styles.css), so it
       doesn't need its own phone-specific rules -- it was only ever cramped by the fixed-width
       shell around it. */
    .profile-panel {
        width: 100%;
    }

    /* #profile-mfa-row's action button used to get the blanket @media(max-width:768px)
       .btn:not(.btn-icon){width:100%} treatment from styles.css, which is why an earlier
       version of this rule stacked label/value above the button (to avoid a full-width
       button colliding with the wrapping "Authenticator App MFA" label sharing one row).
       Now that #profile-mfa-action-btn below is restored to a natural width, that collision
       can't happen -- no stacking needed, it shares the row like every other
       .profile-field-row's small icon-button does. */
    /* Same explicit width as .profile-panel-footer .btn-danger below, per explicit request
       -- "Setup"/"Disable" and "Sign Out" have different text lengths and were otherwise
       naturally sized to different widths despite matching padding/font. */
    #profile-mfa-action-btn {
        width: 6.3rem;
        /* Also overriding the same @768px rule's padding (4px 12px 5px 12px) -- that's a
           short ~30px-tall button, not a comfortable tap target once it's not stretched
           full-width to compensate visually. */
        padding: 0.65rem 1.4rem;
        flex-shrink: 0;
        /* Matches .profile-field-label's font-size (styles.css) per explicit request. */
        font-size: 0.72rem;
    }

    /* .profile-panel-footer: same story as #profile-mfa-action-btn above -- Sign Out no
       longer needs its own stacked row now that it's natural-width, not full-width; shares
       the row with the version/build text like the base (non-phone) layout already does.
       Explicit width matches #profile-mfa-action-btn above, per explicit request. */
    .profile-panel-footer .btn-danger {
        width: 6.3rem;
        padding: 0.65rem 1.6rem;
        flex-shrink: 0;
        /* Matches .profile-field-label's font-size (styles.css) per explicit request. */
        font-size: 0.72rem;
    }

    /* Login landing page's Sign In button (#unauth-action-btn): styles.css's
       `.unauth-card .btn { width: auto; min-width: 140px; }` looks like it should already
       protect this button, but it has the exact same specificity (two classes) as the
       later-in-source-order `@media(max-width:768px) .btn:not(.btn-icon){width:100%}` rule
       -- at equal specificity the later rule wins regardless, so this button was silently
       stretched full-width (and squished to ~30px tall) the whole time, same root cause as
       the profile panel buttons above. Restated here (phone.css loads last, so this one
       actually wins) with taller, comfortable padding; .unauth-card's own
       `text-align:center` centers it naturally since it goes back to being inline-block
       content-width, no extra alignment CSS needed. */
    #unauth-action-btn {
        width: auto;
        min-width: 160px;
        padding: 0.65rem 2rem;
    }

    /* Step 6: the nav drawer replaces the tab bar as phone's main navigation entirely (not just
       the 3 tabs the old interim placeholder hid -- that placeholder is removed now that this
       actually ships). The hamburger toggle (core.css, hidden by default) is revealed here. */
    .tabs {
        display: none;
    }

    .mobile-nav-toggle {
        display: flex;
    }

    /* ── Phone nav drawer ─────────────────────────────────────────────
       Same overlay + transform-slide mechanism as .profile-panel/.profile-panel-overlay
       (styles.css), mirrored to slide in from the left instead of the right. */
    .nav-drawer-overlay {
        position: fixed;
        inset: 0;
        z-index: 1100;
        background: transparent;
    }

    .nav-drawer {
        position: fixed;
        top: 0;
        left: 0;
        height: 100dvh;
        width: 280px;
        max-width: 85vw;
        background: var(--card-bg);
        box-shadow: 4px 0 24px rgba(0, 0, 0, 0.18);
        z-index: 1150;
        display: flex;
        flex-direction: column;
        transform: translateX(-100%);
        transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
        border-right: 1px solid var(--border-color);
    }

    .nav-drawer.open {
        transform: translateX(0);
    }

    .nav-drawer-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 1rem 0.75rem 1rem 1.25rem;
        background: linear-gradient(180deg, var(--brand-blue) 0%, var(--blue-green-3) 100%);
        color: var(--white);
        flex-shrink: 0;
    }

    .nav-drawer-title {
        font-size: 1.1rem;
        font-weight: 600;
    }

    .nav-drawer-close {
        color: rgba(255, 255, 255, 0.8) !important;
    }

    .nav-drawer-close:hover {
        color: var(--white) !important;
        background: rgba(255, 255, 255, 0.15) !important;
    }

    .nav-drawer-body {
        flex: 1;
        overflow-y: auto;
        display: flex;
        flex-direction: column;
        padding: 0.5rem 0;
    }

    .nav-drawer-item {
        display: block;
        width: 100%;
        text-align: left;
        border: none;
        background: transparent;
        color: var(--text-primary);
        font-size: 1rem;
        padding: 0.9rem 1.25rem;
        cursor: pointer;
        border-bottom: 1px solid var(--border-color);
    }

    .nav-drawer-item:hover,
    .nav-drawer-item:active {
        background: var(--bg-secondary, #f3f4f6);
    }

    .nav-drawer-item.active {
        font-weight: 600;
        color: var(--brand-blue);
    }

    /* ── Step 7: Dashboard device-detail drill-down ──────────────────────
       Rescoped from dashboard.css's old @media (max-width: 900px) rules, which caught
       tablet portrait (744-820px) too -- tablet keeps the standard side-by-side
       .device-detail-left/.device-detail-right layout with its own internal-pane
       scrolling. On phone, stack into a column and let the overlay itself scroll. */
    #sparkplug-device-detail {
        overflow-y: auto;
        padding: 0.45rem 0.5rem;
    }

    /* .device-detail-header is normally a single flex ROW: back-button | .device-detail-title
       | remove-button. .device-detail-title (flex:1) wraps ALL the inner rows -- name/badges,
       Serial/Type/Model/Last-Seen, and Location -- so every one of those rows inherits the
       SAME narrower "middle column" width that only the name row actually needs to share with
       the back/remove buttons. That's what reads as columns instead of rows: two empty
       full-height gutters, one on each side, matching the back-button's and remove-button's
       width, running down the entire card even though those buttons only occupy row 1.
       Fixed with CSS only (no HTML change) via `display:contents` on .device-detail-title:
       that removes ITS OWN box from layout while promoting its children (name-row, summary
       row, meta, location-row) to be direct grid items of .device-detail-header itself, so
       Serial/Model and Location can be explicitly spanned across the full card width.
       Remove moved into the ⋯ menu on phone (#detail-menu-remove-btn below) -- with it gone,
       row 1 only needs 2 columns, which is also what lets the name row's badges use more of
       the card's width than before.
       Sticky per explicit request: the whole collapsed header (nav row + summary row) stays
       pinned while Key Signals/tabs/everything else scrolls beneath it; the expanded Details
       panel (meta/location, rows 3-4) is part of the same box, so opening Details grows the
       pinned area rather than becoming a second independently-scrolling region -- a deliberate
       simplification, not a structural split into a separate sticky sub-element. */
    .device-detail-header {
        display: grid;
        grid-template-columns: auto 1fr;
        /* "start" top-aligned the back arrow against the taller name+badges row, making it
           sit visibly above the text's vertical center -- only row 1 (back-button vs.
           primary-row) has two competing column items, so "center" only affects that row;
           the other rows are single full-width items with nothing to align against. */
        align-items: center;
        padding: 0.4rem 0.45rem;
        gap: 0.1rem 0.2rem;
        margin-bottom: 0.5rem;
        position: sticky;
        top: 0;
        z-index: 5;
    }

    .device-detail-title {
        display: contents;
    }

    /* Was shrunk below desktop's own 1.4rem (core.css) -- the agreed design shows the back
       arrow noticeably larger/more prominent than that, not smaller. */
    /* Padding trimmed further -- this column's width (icon + its own padding) is what
       pushes column 2 (device name, and everything the expanded Details panel aligns to)
       right of the card's edge, so shrinking it moves that whole alignment point left. */
    .btn-back {
        grid-column: 1;
        grid-row: 1;
        font-size: 1.5rem;
        padding: 0.05rem 0.15rem;
    }

    /* Matches the agreed design's title treatment: smaller than the current 1.1rem/600 but
       bolder (700), not just a straight shrink. */
    .device-detail-name {
        font-size: 0.95rem;
        font-weight: 700;
        /* Same "grow to absorb leftover space" trick .detail-summary-text uses to push
           "Details" flush right -- with the name last-ordered item (⋯, order:3) grown
           against it instead, "⋯"'s right edge lines up with "Details"'s right edge below,
           since both rows share the same column-2-to-grid-end boundary. */
        flex: 1;
        min-width: 0;
    }

    /* Promotes .detail-primary-row and .detail-featured-row (real boxes on phone, see the
       comment on those classes below) to be direct grid items of .device-detail-header --
       the same display:contents technique used on .device-detail-title above, just one
       level deeper, so Warranty/Docs can land in a completely different grid row from the
       name/status/menu without needing an HTML change beyond the wrapper split itself. */
    .device-detail-name-row {
        display: contents;
    }

    /* Remove device now lives in the ⋯ menu (#detail-menu-remove-btn, shown further down) --
       a rare, destructive action doesn't need permanent top-row real estate on phone. */
    #detail-remove-btn {
        display: none;
    }

    .detail-primary-row {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0.35rem;
        grid-column: 2;
        grid-row: 1;
    }

    /* Visual-only reorder (DOM order is untouched -- desktop's current order depends on it
       via display:contents) so the ⋯ menu appears after Online/Alarm on phone, matching the
       agreed design, without affecting desktop at all. Deliberately NOT pushed flush to the
       row's right edge (tried margin-left:auto, reverted) -- .detail-primary-row stretches
       to the full grid column width, so flush-right left a large gap after ONLINE, and it
       moved the menu trigger far enough right that its left-anchored dropdown (still
       left:0 in dashboard.css) opened off-screen. Sits with normal flow spacing instead;
       see .detail-overflow-menu below for the actual off-screen fix. */
    .detail-primary-row #detail-overflow-wrap {
        order: 3;
    }

    /* Plain icon, no button chrome, matching the agreed design -- .btn-ghost.btn-small's
       border/background/shadow are a real button style appropriate for desktop's overflow
       menu trigger, but not what was agreed for phone. box-shadow (.btn's var(--button-
       shadow)) still read as a visible "box" even after border/background were removed. */
    .detail-primary-row #detail-overflow-btn {
        background: none;
        border: none;
        box-shadow: none;
        padding: 0.1rem 0.2rem;
    }

    /* Anchored from the right instead of dashboard.css's default left:0 -- regardless of
       exactly where the trigger sits in the row, a right-anchored menu opens back over the
       card instead of a left-anchored one extending off the right edge of the screen. */
    .detail-overflow-menu {
        left: auto;
        right: 0;
    }

    .detail-summary-row {
        /* Starts at column 2 (not 1) so its left edge lines up with the device name above,
           not the back arrow. The expanded panel below (.detail-featured-row,
           .device-detail-meta, .detail-location-row) deliberately does NOT follow this --
           per explicit request it uses the full card width (column 1) instead, not aligned
           with the summary row. */
        grid-column: 2 / -1;
        grid-row: 2;
        display: flex;
        align-items: baseline;
        gap: 0.5rem;
        margin-top: 0.05rem;
    }

    .detail-summary-text {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        font-size: 0.78rem;
        color: var(--text-secondary);
    }

    .detail-details-toggle {
        flex-shrink: 0;
        display: flex;
        align-items: center;
        gap: 0.2rem;
        background: none;
        border: none;
        padding: 0;
        font-size: 0.72rem;
        font-weight: 700;
        color: var(--brand-blue);
        cursor: pointer;
    }

    .detail-details-toggle-chev {
        font-size: 0.95rem;
        line-height: 1;
        transition: transform 0.15s;
    }

    .device-detail-header.details-expanded .detail-details-toggle-chev {
        transform: rotate(180deg);
    }

    /* Collapsed by default: the summary row above stands in for these. Warranty/Docs
       (.detail-featured-row), Serial/Type/Model/Last-Seen, and Location only render once
       "Details" is tapped -- matches the agreed design exactly: hidden as a pair while
       collapsed, no "unless out-of-warranty" carve-out (that was never actually part of
       what got agreed to). */
    .detail-featured-row,
    .device-detail-meta,
    .detail-location-row {
        display: none;
    }

    /* Warranty/Docs featured row sits between the summary row and the Serial/Type/Model
       grid -- its own grid row, not squeezed back into the top nav row next to ONLINE.
       Online/Offline isn't repeated here since you already saw it before tapping Details.
       Full width (column 1, not aligned with the summary row's column 2) per explicit
       request -- the expanded panel deliberately doesn't line up with the summary line,
       it uses the whole card. */
    .detail-featured-row {
        grid-column: 1 / -1;
        grid-row: 3;
    }

    .device-detail-header.details-expanded .detail-featured-row {
        display: flex;
        gap: 0.5rem;
        margin-top: 0.3rem;
    }

    /* Bigger, icon-led chips instead of the normal small pill -- this is the payoff for
       having tapped in, so it gets more visual weight than status/alarm did up top. */
    .detail-featured-row #detail-warranty-indicator,
    .detail-featured-row #detail-docs-indicator {
        flex: 1;
        height: auto;
        padding: 0.5rem 0.65rem;
        border-radius: 7px;
        font-size: 0.8rem;
        font-weight: 700;
    }

    .detail-featured-row #detail-warranty-indicator::before {
        content: "🛡️ ";
    }

    /* Real 2x2 grid, not the desktop single-row-with-dividers layout, per the agreed
       design: Type+Model on one row, Serial+Last-Seen on the next. DOM order is Serial,
       Type, Model, Last-Seen (unchanged, desktop depends on it) so explicit placement by
       position is needed to get that specific grouping rather than left-to-right document
       order (which would pair Serial+Type, Model+LastSeen instead). */
    .device-detail-header.details-expanded .device-detail-meta {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0.5rem 0.75rem;
    }

    .detail-meta-item:nth-child(1) { grid-column: 1; grid-row: 2; } /* Serial */
    .detail-meta-item:nth-child(2) { grid-column: 1; grid-row: 1; } /* Type */
    .detail-meta-item:nth-child(3) { grid-column: 2; grid-row: 1; } /* Model */
    .detail-meta-item:nth-child(4) { grid-column: 2; grid-row: 2; } /* Last Seen */

    /* Dividers were a desktop single-row artifact -- no borders between cells in the grid. */
    .detail-meta-item + .detail-meta-item {
        border-left: none;
    }

    /* Label on its own line, value+Change together on the line below -- matches the
       agreed design (was previously all three in one row, from before that mockup
       existed). .detail-location-value-row is display:contents on desktop (core.css) so
       desktop is unaffected; here on phone it becomes the real flex row for value+button. */
    .device-detail-header.details-expanded .detail-location-row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 0.3rem;
        margin-top: 0.2rem;
    }

    .detail-location-value-row {
        display: flex;
        align-items: baseline;
        gap: 0.4rem;
        width: 100%;
    }

    .device-detail-meta {
        grid-column: 1 / -1;
        grid-row: 4;
    }

    .detail-location-row {
        grid-column: 1 / -1;
        grid-row: 5;
    }

    .detail-meta-item {
        padding: 0;
    }

    /* .detail-value generally is also used by the Location row's address text, so scope
       this to meta items specifically rather than shrinking every .detail-value. */
    .detail-meta-item .detail-value {
        font-size: 0.85rem;
    }

    /* Last Seen: the full "8/21/2026, 2:04:27 PM CDT" string doesn't fit a half-width grid
       cell. #detail-last-seen-short (fmtTime(), no date/seconds -- e.g. "2:04 PM CDT") is
       the phone-only stand-in, populated in renderDeviceDetail() alongside the full string;
       desktop keeps the full #detail-last-seen unchanged. */
    #detail-last-seen {
        display: none;
    }

    #detail-last-seen-short {
        display: block;
    }

    /* Location + Change back on one row (per explicit request) now that the row has the
       full card width to work with (previously confined to the same narrow middle column
       as back/remove -- see the name-row comment above for the same root cause). The
       address itself is truncated to a single line rather than left to wrap, with the
       ellipsis forced to the START so the END of the path (the most specific part -- room/
       building) stays visible, not the org-level prefix: the standard direction:rtl +
       text-align:left trick flips which edge text-overflow:ellipsis anchors to without
       reversing the actual (LTR) character order of the text itself. */
    .detail-location-row .detail-label {
        flex-shrink: 0;
    }

    .detail-location-path {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        direction: rtl;
        text-align: left;
    }

    .detail-location-btn {
        flex-shrink: 0;
    }

    /* Phone-only Remove menu item (base-hidden in core.css alongside .detail-summary-row). */
    .detail-menu-remove-btn {
        display: block;
    }

    /* Supporting tightening of the same card now that the worst offender is fixed.
       (.device-detail-name-row itself is display:contents now -- these apply to
       .detail-primary-row, the box that actually renders row 1's name+badges.) */
    .detail-primary-row {
        gap: 0.35rem;
        margin-bottom: 0.05rem;
    }

    .device-detail-meta {
        gap: 0.25rem 0;
        margin-top: 0.2rem;
    }

    .device-detail-main {
        flex-direction: column;
        flex: 0 0 auto;
    }

    /* Left col: full-width, only contains Key Signals on phone (schematic moved to tab by JS) */
    .device-detail-left {
        width: 100%;
        border-right: none;
        border-bottom: 1px solid var(--border-color);
        padding-right: 0;
        padding-bottom: 1rem;
        margin-bottom: 0.75rem;
        overflow-y: visible;
        flex: 0 0 auto;
    }

    /* Schematic pane on phone should fill space naturally */
    #device-right-pane-schematic #schematic-section {
        flex: 1;
        min-height: 300px;
    }

    .device-detail-right {
        padding-left: 0;
        flex: 0 0 auto;
        min-height: 500px;
    }

    .device-detail-right-body {
        min-height: 420px;
    }

    /* .btn:not(.btn-icon) is full-width on phone; keep dashboard/detail action controls compact. */
    #dashboard .btn,
    #sparkplug-device-detail .btn {
        width: auto;
    }

    /* ── Step 7: Fleet Locations sub-view ─────────────────────────────────
       Rescoped from fleet.css's old @media (max-width: 768px) rules, which caught
       tablet portrait too -- tablet keeps the standard fixed-260px tree pane +
       flexible detail pane side-by-side. On phone a fixed 260px sidebar would leave
       only ~115-170px for the detail pane, so stack instead. */
    .fleet-contact-cards,
    .fleet-contacts-form {
        grid-template-columns: 1fr;
    }

    .fleet-locations-layout {
        flex-direction: column;
    }

    .fleet-tree-pane {
        width: 100%;
        max-height: 220px;
        border-right: none;
        border-bottom: 1px solid var(--border-color);
    }

    /* ── Step 8: Automation / Reports / Admin ─────────────────────────────
       General class of bug found in the full-app audit: fixed-basis flex children
       inside `flex-wrap: nowrap` rows, sized for desktop, with no phone fallback.
       .form-row is used across many admin/automation forms -- wrapping it is a safe,
       broadly-applicable fix (rows that already fit are unaffected; only rows that
       don't fit start wrapping). The specific fixed-width utility classes then need
       their own override too, since flex-wrap alone just wraps them at their fixed
       220px/190px width, leaving dead space beside them rather than using the row's
       full width once wrapped. */
    .form-row {
        flex-wrap: wrap;
    }

    .admin-field-220,
    .rpt-flex-0-190 {
        flex: 1 1 100%;
        width: 100%;
    }

    /* Automation's Rule Editor condition row is the worst instance of this class of
       bug: flex-wrap:nowrap with ~364px of fixed-width children (60+90+160px plus
       the remove button and gaps) inside a modal with only ~280px of content width
       on phone -- guaranteed overflow, not just a squeeze. Allow wrap, and trim the
       fixed widths down somewhat so the operator+value+remove group has a better
       chance of fitting together on their own wrapped line below the metric select. */
    .rule-cond-row {
        flex-wrap: wrap;
    }

    .rule-cond-logic {
        flex-basis: 50px;
    }

    .rule-cond-metric {
        flex-basis: 100%;
        max-width: 100%;
    }

    .rule-cond-op,
    .rule-cond-text-op,
    .rule-cond-is-label,
    .rule-cond-alarm-state {
        flex-basis: 76px;
    }

    .rule-cond-val {
        flex-basis: 110px;
    }

    /* Reports' sidebar+content layout stacked at the old @max-width:980px (fleet.css),
       which caught tablet portrait too -- same bug class already fixed twice for
       Dashboard/Fleet. Tablet keeps the standard side-by-side layout; on phone, cap
       the stacked nav pane's height (same reasoning as Fleet Locations' tree-pane
       cap above) so the ~11-button report picker doesn't push the actual report
       content below the fold entirely. */
    .reports-layout {
        grid-template-columns: 1fr;
    }

    .reports-nav-pane {
        max-height: 220px;
    }

    /* ── Step 8 continued: wizard/modal density (Rules, Scheduled Reports, Key Signal
       Thresholds) ──────────────────────────────────────────────────────────────
       These three wizards are functional on phone but waste a lot of the already-scarce
       width/height on desktop-tuned spacing: generous modal side padding, a full 1.5rem
       gap between every form field, and a stepper sized for a much wider header. Tightened
       here, not by hiding/removing anything. */

    /* .form-group is used across nearly every form in the app (not just these three
       wizards) -- safe to tighten globally on phone since it only affects spacing, never
       breaks a layout that already fit. */
    .form-group {
        margin-bottom: 0.9rem;
    }

    .form-group label {
        margin-bottom: 0.3rem;
    }

    .form-group small {
        font-size: 0.8rem;
        margin-top: 0.2rem;
    }

    /* .modal-box-rule (Rule Editor AND Key Signal Thresholds -- kst-wizard-modal reuses
       this exact class) had 2.5rem/40px of side padding alone, on a screen that's only
       ~375px wide total -- the single biggest single space-waster on this list. */
    .modal-box-rule {
        padding: 1rem 0.9rem 0;
    }

    /* .modal-box-schedule-editor doesn't override the base .modal-box's own
       1.75rem/2rem padding, so it has the same problem at a smaller magnitude. */
    .modal-box-schedule-editor {
        padding: 1rem 0.9rem 0;
    }

    /* .rule-steps (Rule Editor + KST) and .rpt-steps (Scheduled Reports) are separate,
       parallel implementations of the same numbered-circle stepper (per-feature
       convention, not a shared component) -- same tightening applied to both. */
    .rule-steps,
    .rpt-steps {
        margin-bottom: 0.6rem;
        gap: 0.35rem;
    }

    .rule-step,
    .rpt-step {
        gap: 0.35rem;
    }

    .rule-step-circle,
    .rpt-step-circle {
        width: 1.3rem;
        height: 1.3rem;
        font-size: 0.68rem;
    }

    /* ── Step 8 continued: Admin tab ───────────────────────────────────────
       Admin wasn't covered by the rest of step 8's Automation/Reports audit --
       separate pass, same class of desktop-tuned-width bugs. */

    /* .admin-section .form-group (styles.css) puts label and input side-by-side, which
       assumes far more width than a phone's content column has left once .card's and
       .admin-section's own padding (trimmed below) are accounted for -- longer labels like
       "Failure Alert Webhook URL (optional)" leave almost no room for the input itself.
       Stack back to the app-wide default (label above, full-width input below). */
    .admin-section .form-group {
        display: block;
    }

    .admin-section .form-group label {
        margin-bottom: 0.3rem;
    }

    /* .card's 2rem side padding plus .admin-section's own 1.5rem stack to ~112px lost on a
       375px phone -- same class of fix as .modal-box-rule's padding trim above. */
    #admin > .card {
        padding: 1.25rem 0.9rem;
    }

    .admin-section {
        padding: 1rem 0.9rem;
    }

    /* Outbound Webhooks' create/edit and delivery-log modals are the only two modals in the
       app with a hardcoded min-width (480px/680px, admin.css) instead of scaling with
       .modal-box's own width:90% -- wider than any phone, forcing horizontal overflow. */
    .admin-webhook-modal-box,
    .admin-webhook-delivery-modal-box {
        min-width: 0;
        width: 100%;
    }

    /* Same 100vh-includes-browser-chrome issue already fixed for the Rule/Schedule Report
       wizards -- caught here too since the min-width fix above is what actually makes this
       modal reachable on phone in the first place. */
    .admin-webhook-delivery-modal-box {
        max-height: 80dvh;
    }

    /* .portal-users-headerline (heading + inline action button -- e.g. "Device Certificate
       Access" + "Open Onboarding Station") has no wrap, so a long heading paired with a long
       button label has no room to drop to its own line on phone. */
    .portal-users-headerline {
        flex-wrap: wrap;
    }
}
