/* ============================================================================
   GSO Portal — Mobile App Layer
   ----------------------------------------------------------------------------
   Loaded AFTER gso-ui.css on every page. Everything here is additive and lives
   inside width/pointer media queries, so desktop rendering is untouched.

   What it provides:
     • touch ergonomics      (44px targets, no tap flash, no iOS focus zoom)
     • safe-area awareness   (notch / home-indicator insets)
     • drawer polish         (.gso-drawer-open scroll lock, edge shadow)
     • bottom tab bar        (.gso-tabbar — built by gso-mobile.js)
     • bottom sheets         (modals docked to the thumb on phones)
     • stacked tables        (.gso-stack-sm — rows become record cards)
     • overflow guards       (nothing scrolls the page sideways at 320px)

   Breakpoints match Tailwind: sm 640px, lg 1024px.
   ========================================================================== */

:root {
    --gso-safe-b: env(safe-area-inset-bottom, 0px);
    --gso-safe-t: env(safe-area-inset-top, 0px);
    --gso-safe-l: env(safe-area-inset-left, 0px);
    --gso-safe-r: env(safe-area-inset-right, 0px);
    --gso-tabbar-h: 4.25rem;
}

/* ======================================================= touch ergonomics === */

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

@media (pointer: coarse) {

    a,
    button,
    [role="button"],
    [onclick],
    input,
    select,
    textarea,
    summary {
        -webkit-tap-highlight-color: transparent;
        touch-action: manipulation;
    }

    /* Hover skins latch "stuck" on touch devices — kill the transform half of
       it so a tapped card doesn't stay lifted after the finger leaves. */
    .gso-card-hover:hover {
        transform: none;
    }
}

/* Primary controls become thumb-sized on touch, via padding — never scale. */
@media (pointer: coarse) and (max-width: 1023px) {

    .gso-btn {
        min-height: 2.75rem;
        padding-left: 1rem;
        padding-right: 1rem;
    }

    .gso-btn-sm {
        min-height: 2.375rem;
    }

    /* Square icon-only buttons under 40px keep their look but gain an
       invisible 44px hit area. w-10 (40px) is already close enough to leave
       alone — adding `position: relative` there could re-anchor a badge. */
    .gso-btn.\!p-0,
    button.w-8.h-8,
    button.w-9.h-9 {
        position: relative;
    }

    .gso-btn.\!p-0::after,
    button.w-8.h-8::after,
    button.w-9.h-9::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 44px;
        height: 44px;
        transform: translate(-50%, -50%);
    }

    .sidebar-link {
        padding-top: 0.75rem;
        padding-bottom: 0.75rem;
    }

    .gso-tab {
        min-height: 2.75rem;
    }
}

/* -------------------------------------------------- iOS focus-zoom killer -- */
/* Safari zooms the whole page when a focused field is under 16px. Every input
   in this app is 12–14px, which made every tap on a form yank the layout.
   Selectors carry an attribute so they outrank Tailwind's .text-xs/.text-sm. */
@media (max-width: 640px) {

    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
    select:not([size]),
    textarea:not([data-keep-size]) {
        font-size: 16px;
        line-height: 1.4;
    }

    /* Keep the visual density: taller text needs slightly tighter padding. */
    .gso-input {
        padding: 0.6875rem 0.875rem;
    }

    select.gso-input {
        padding-right: 2.25rem;
    }
}

/* ========================================================= overflow guards === */

@media (max-width: 640px) {

    /* `clip` (not `hidden`) so position:sticky headers keep working. */
    html {
        overflow-x: clip;
    }

    /* Long control numbers, emails and titles must never widen the page. */
    h1, h2, h3, h4,
    .gso-card,
    .glass-panel,
    .glass-card {
        overflow-wrap: anywhere;
    }

    /* Decorative blur orbs are frequently absolutely placed past the edge. */
    .blob,
    [class*="blur-3xl"] {
        pointer-events: none;
    }
}

/* Momentum scrolling everywhere the app owns a scroller. */
main,
.gso-table-wrap,
#sidebar,
[class*="overflow-y-auto"],
[class*="overflow-x-auto"] {
    -webkit-overflow-scrolling: touch;
}

/* Scroll-chaining is only worth blocking on the OUTER scrollers, where it
   otherwise leaks into the page/pull-to-refresh behind them.
   It must NOT go on inner containers: `overflow:auto` makes an element a
   scroll container even when its content fits, and `contain` on such an
   element swallows the gesture entirely — nothing scrolls inside it and
   nothing chains to <main>. That froze the whole page wherever a finger
   landed on a table wrapper (the user directory was unusable). */
main,
#sidebar {
    overscroll-behavior: contain;
}

/* Horizontal scrollers keep the x-axis contained (so a sideways swipe on a
   wide table doesn't trigger the browser's back gesture) while leaving the
   y-axis free to chain up to the page. */
.gso-table-wrap,
[class*="overflow-x-auto"] {
    overscroll-behavior-x: contain;
    overscroll-behavior-y: auto;
}

/* ============================================================ side drawer === */

@media (max-width: 1023px) {

    #sidebar {
        width: min(19rem, 86vw);
        padding-top: calc(1.5rem + var(--gso-safe-t));
        /* No bottom padding: the sticky sign-out footer below owns it, so it
           can pin flush to the drawer's bottom edge with nothing showing
           through beneath it. */
        padding-bottom: 0;
        padding-left: calc(1.25rem + var(--gso-safe-l));
        box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.05), 32px 0 64px -24px rgba(0, 0, 0, 0.85);
        will-change: transform;
    }

    html.light-mode #sidebar {
        box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.06), 32px 0 64px -28px rgba(15, 23, 42, 0.35);
    }

    /* The drawer is a modal surface on phones: opaque, not see-through. */
    #sidebar.bg-slate-950\/90 {
        background-color: rgba(7, 13, 30, 0.97);
    }

    html.light-mode #sidebar {
        background-color: rgba(255, 255, 255, 0.98);
    }

    #mobile-sidebar-overlay {
        transition: opacity 0.28s cubic-bezier(0.16, 1, 0.3, 1);
    }
}

/* Sign out sits last in the drawer, under a nav list that grows with the
   signed-in role and can outrun a short phone screen — and the drawer hides
   its scrollbar, so there is no hint that more is below. Pinning it to the
   bottom of the drawer keeps it findable without scrolling, and gives it a
   real footer treatment instead of looking like one more list item. */
@media (max-width: 1023px) {

    #sidebar button[onclick*="logout"] {
        position: sticky;
        bottom: 0;
        z-index: 2;
        margin-top: 1rem;
        padding-top: 0.875rem;
        padding-bottom: calc(0.875rem + var(--gso-safe-b));
        border-top: 1px solid rgba(255, 255, 255, 0.08);
        background: rgba(7, 13, 30, 0.97);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        /* Full-bleed divider: mirror the drawer's real padding (1.25rem+safe
           on the left from the rule above, 1.5rem on the right from p-6). */
        margin-left: calc(-1.25rem - var(--gso-safe-l));
        margin-right: -1.5rem;
        padding-left: calc(1.25rem + var(--gso-safe-l));
        padding-right: 1.5rem;
        border-radius: 0;
        color: #fb7185;
    }

    html.light-mode #sidebar button[onclick*="logout"] {
        background: rgba(255, 255, 255, 0.98);
        border-top-color: #e5e9f0;
        color: #e11d48;
    }
}

/* Freeze the page behind an open drawer. The drawer's own list keeps its
   scrolling — `touch-action` is deliberately left alone so it can. */
body.gso-drawer-open {
    overflow: hidden !important;
}

/* ========================================================= bottom tab bar === */
/* Built at runtime by gso-mobile.js from whatever sidebar links the signed-in
   role can actually see, so it never offers a destination the user lacks. */

.gso-tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* Under the drawer overlay (z-40) and every modal, over page content. */
    z-index: 35;
    display: none;
    align-items: stretch;
    padding: 0.375rem calc(0.375rem + var(--gso-safe-l)) calc(0.375rem + var(--gso-safe-b)) calc(0.375rem + var(--gso-safe-r));
    background: rgba(7, 13, 30, 0.88);
    backdrop-filter: blur(24px) saturate(160%);
    -webkit-backdrop-filter: blur(24px) saturate(160%);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 -12px 32px -18px rgba(0, 0, 0, 0.9);
}

html.light-mode .gso-tabbar {
    background: rgba(255, 255, 255, 0.9);
    border-top-color: #e5e9f0;
    box-shadow: 0 -12px 32px -20px rgba(15, 23, 42, 0.35);
}

@media (max-width: 1023px) {
    .gso-tabbar {
        display: flex;
    }
}

.gso-tabbar__item {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.1875rem;
    padding: 0.4375rem 0.125rem 0.375rem;
    border-radius: 0.875rem;
    border: none;
    background: transparent;
    color: #7c8ba1;
    font-family: inherit;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: color 0.18s ease, background 0.18s ease;
}

.gso-tabbar__item i {
    font-size: 1.0625rem;
    line-height: 1;
}

.gso-tabbar__label {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gso-tabbar__item:active {
    background: rgba(255, 255, 255, 0.06);
}

html.light-mode .gso-tabbar__item {
    color: #64748b;
}

html.light-mode .gso-tabbar__item:active {
    background: rgba(15, 23, 42, 0.05);
}

.gso-tabbar__item.is-active {
    color: var(--theme-color-main, #4f46e5);
    background: rgba(var(--theme-rgb, 99, 102, 241), 0.12);
}

html.light-mode .gso-tabbar__item.is-active {
    background: rgba(var(--theme-rgb, 99, 102, 241), 0.1);
}

/* Unread/attention dot the pages can flip on: item.dataset.badge = "1" */
.gso-tabbar__item[data-badge]:not([data-badge=""]) i::after {
    content: "";
    position: absolute;
    top: -1px;
    right: -5px;
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: #f43f5e;
    box-shadow: 0 0 0 2px rgba(7, 13, 30, 0.9);
}

.gso-tabbar__item[data-badge]:not([data-badge=""]) i {
    position: relative;
}

/* Content must clear the bar — main is the scroller on every interior page. */
@media (max-width: 1023px) {
    body.gso-has-tabbar main {
        padding-bottom: calc(var(--gso-tabbar-h) + var(--gso-safe-b) + 1rem);
    }
}

@media print {
    .gso-tabbar {
        display: none !important;
    }
}

/* =========================================================== bottom sheets === */
/* gso-mobile.js tags the real panel inside each full-screen modal with
   data-gso-sheet, so backdrops and wrappers are never mistaken for content. */

@media (max-width: 640px) {

    [data-gso-sheet-host] {
        align-items: flex-end !important;
        justify-content: center !important;
        padding: 0 !important;
    }

    [data-gso-sheet] {
        width: 100% !important;
        max-width: 100% !important;
        margin: 0 !important;
        max-height: 92dvh;
        overflow-y: auto;
        overscroll-behavior: contain;
        border-radius: 1.5rem 1.5rem 0 0 !important;
        padding-bottom: var(--gso-safe-b);
        animation: gso-sheet-in 0.32s cubic-bezier(0.16, 1, 0.3, 1);
    }

    /* Grab handle — the affordance that says "this sheet is the front layer".
       It takes its own line above the panel header; `flex: 0 0 auto` and
       `justify-self` keep it centred when the panel is a flex/grid container. */
    [data-gso-sheet]::before {
        content: "";
        position: sticky;
        top: 0;
        z-index: 30;
        display: block;
        flex: 0 0 auto;
        justify-self: center;
        width: 2.25rem;
        height: 0.25rem;
        margin: 0.5rem auto 0.375rem;
        border-radius: 999px;
        background: rgba(255, 255, 255, 0.22);
    }

    html.light-mode [data-gso-sheet]::before {
        background: rgba(15, 23, 42, 0.18);
    }

    /* Sheets that carry a fixed height (iframe hosts) fill the phone instead. */
    [data-gso-sheet][data-gso-sheet-tall] {
        height: 92dvh !important;
    }

    /* Footers inside a sheet: stack, primary on top, full width. */
    [data-gso-sheet] footer.flex,
    [data-gso-sheet] .gso-sheet-actions {
        flex-direction: column-reverse;
        align-items: stretch;
    }

    [data-gso-sheet] footer.flex > .gso-btn,
    [data-gso-sheet] .gso-sheet-actions > .gso-btn {
        width: 100%;
    }
}

@keyframes gso-sheet-in {
    from {
        opacity: 0;
        transform: translateY(24px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ========================================================= stacked tables === */
/* Opt-in per table (class="gso-stack-sm"). Below 640px each row becomes a
   labelled record card — no sideways scrubbing to read a status column.
   Cell labels come from <thead> via gso-mobile.js (data-label). */

@media (max-width: 640px) {

    .gso-table-wrap:has(table.gso-stack-sm) {
        border: none;
        background: transparent;
        box-shadow: none;
        overflow-x: visible;
    }

    table.gso-stack-sm {
        display: block;
        width: 100%;
        min-width: 0;
        border-collapse: separate;
        border-spacing: 0;
    }

    table.gso-stack-sm thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }

    table.gso-stack-sm tbody {
        display: block;
    }

    table.gso-stack-sm tbody tr {
        display: block;
        margin-bottom: 0.625rem;
        padding: 0.25rem 0;
        border: 1px solid var(--gso-border);
        border-radius: var(--gso-radius-lg);
        background: var(--gso-surface-raised);
        box-shadow: var(--gso-shadow-sm);
    }

    html.light-mode table.gso-stack-sm tbody tr {
        background: #ffffff;
    }

    table.gso-stack-sm tbody tr:hover {
        box-shadow: var(--gso-shadow-sm);
    }

    table.gso-stack-sm tbody td {
        display: flex;
        gap: 0.75rem;
        align-items: baseline;
        justify-content: space-between;
        padding: 0.5rem 0.875rem;
        border-bottom: 1px solid rgba(255, 255, 255, 0.045);
        text-align: right;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    html.light-mode table.gso-stack-sm tbody td {
        border-bottom-color: #eef1f6;
    }

    table.gso-stack-sm tbody td::before {
        content: attr(data-label);
        flex: 0 0 6.5rem;
        text-align: left;
        font-size: 9.5px;
        font-weight: 700;
        letter-spacing: 0.09em;
        text-transform: uppercase;
        color: var(--gso-text-muted);
    }

    table.gso-stack-sm tbody td:last-child {
        border-bottom: none;
    }

    /* Empty-state / "no records" rows span everything — let them breathe. */
    table.gso-stack-sm tbody td[colspan] {
        display: block;
        text-align: center;
        border-bottom: none;
    }

    table.gso-stack-sm tbody td[colspan]::before {
        content: none;
    }

    /* An action cell reads better as a full-width button row than a label pair. */
    table.gso-stack-sm tbody td[data-label="Actions"],
    table.gso-stack-sm tbody td[data-label="Action"] {
        justify-content: flex-end;
        flex-wrap: wrap;
        padding-top: 0.625rem;
        padding-bottom: 0.625rem;
    }
}

/* Paper is never 640px wide in the sense this layer means. Printing from a
   phone must still produce a table, not a column of record cards. */
@media print {

    table.gso-stack-sm,
    table.gso-stack-sm thead,
    table.gso-stack-sm tbody,
    table.gso-stack-sm tbody tr,
    table.gso-stack-sm tbody td {
        display: revert;
    }

    table.gso-stack-sm thead {
        position: static;
        width: auto;
        height: auto;
        clip: auto;
        clip-path: none;
    }

    table.gso-stack-sm tbody td::before {
        content: none;
    }
}

/* Tables that stay horizontal get a real scroll affordance instead of a
   silently clipped edge. */
@media (max-width: 640px) {

    .gso-table-wrap:not(:has(table.gso-stack-sm)) {
        background-image:
            linear-gradient(to right, var(--gso-surface-sunken) 30%, rgba(2, 6, 23, 0)),
            linear-gradient(to left, var(--gso-surface-sunken) 30%, rgba(2, 6, 23, 0));
        background-position: left center, right center;
        background-repeat: no-repeat;
        background-size: 24px 100%, 24px 100%;
        background-attachment: local, local;
    }

    .gso-table:not(.gso-stack-sm) thead th {
        padding: 0.625rem 0.75rem;
    }

    .gso-table:not(.gso-stack-sm) tbody td {
        padding: 0.75rem;
    }
}

/* ======================================================= mobile type scale === */
/* Page titles are sized for a 1440px canvas (text-3xl / text-4xl). At 390px
   they cost two lines and push the actual content below the fold, so the
   interior pages step down one rung. Scoped to `.gso-app main` so landing and
   auth pages keep their deliberately oversized hero type. */

@media (max-width: 640px) {

    .gso-app main h1 {
        font-size: 1.5rem;
        line-height: 1.2;
        letter-spacing: -0.02em;
    }

    .gso-app main > header {
        margin-bottom: 1.5rem;
        padding-bottom: 1.25rem;
    }
}

/* ==================================================== header controls === */

/* The drawer toggle is w-9 on some pages and w-10 on others, and sits in a
   flex row that squeezes it (measured 29x36 on the Work Queue). Normalise
   every page to a true 44px target that flex cannot shrink. */
@media (pointer: coarse) and (max-width: 1023px) {

    button[onclick="toggleSidebar()"] {
        width: 2.75rem;
        height: 2.75rem;
        flex: 0 0 auto;
    }

    button[onclick="toggleSidebar()"] i {
        font-size: 1rem;
    }

    /* Header action buttons that predate the design system carry bespoke
       Tailwind padding (reports.html's Print Preview / Export CSV measured
       32-34px tall), so the .gso-btn sizing rule never reaches them. Raise
       only the height — padding and skin are untouched, so nothing about the
       desktop look changes. */
    header button,
    header a.gso-btn {
        min-height: 2.75rem;
    }
}

/* The Work Queue's Print dropdown is anchored `right-0` to a button that sits
   on the LEFT of the header, so on a phone it hung off the left edge with its
   labels cut in half. Below sm it becomes a bottom sheet instead: full width,
   readable labels, thumb-sized rows, clear of the tab bar. */
@media (max-width: 640px) {

    #print-menu {
        position: fixed;
        left: 0.75rem;
        right: 0.75rem;
        top: auto;
        bottom: calc(var(--gso-tabbar-h) + var(--gso-safe-b) + 0.75rem);
        width: auto;
        max-width: none;
        margin: 0;
        max-height: 60dvh;
        overflow-y: auto;
        overscroll-behavior: contain;
        /* Above the tab bar (35) and the drawer overlay (40). */
        z-index: 60;
    }

    #print-menu > button {
        min-height: 2.75rem;
        white-space: normal;
    }
}

/* ============================================================ misc polish === */

@media (max-width: 640px) {

    /* Tab chips scrub sideways instead of wrapping into ragged stacks. */
    .tab-btn,
    .gso-tab {
        flex: 0 0 auto;
        white-space: nowrap;
    }


    /* Toasts pinned to a corner get clipped on narrow screens; span instead. */
    #toast-container,
    [id$="toast-container"] {
        left: 0.75rem !important;
        right: 0.75rem !important;
        top: calc(0.75rem + var(--gso-safe-t)) !important;
        align-items: stretch;
    }

    /* Horizontal tab strips scrub instead of wrapping into ragged rows. */
    [role="tablist"] {
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x proximity;
    }

    [role="tablist"]::-webkit-scrollbar {
        display: none;
    }

    [role="tablist"] > * {
        flex: 0 0 auto;
        scroll-snap-align: start;
        white-space: nowrap;
    }

    /* Dropdown menus anchored right of a button run off-screen at 360px. */
    .gso-modal.absolute {
        max-width: calc(100vw - 1.5rem);
    }
}

/* ------------------------------------------------ print-selection controls --- */
/* The Work Queue's per-record pick box. Small by design on desktop; on touch it
   keeps its look but gains a full 44px hit area so it is not a pixel-hunt. */
.print-pick-box {
    accent-color: var(--theme-color-main, #4f46e5);
}

@media (pointer: coarse) {

    .print-pick {
        position: relative;
        min-width: 1.75rem;
        min-height: 1.75rem;
        justify-content: center;
    }

    .print-pick::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 44px;
        height: 44px;
        transform: translate(-50%, -50%);
    }
}

@media print {

    /* Selection chrome is screen-only. */
    .print-pick,
    #print-select-bar {
        display: none !important;
    }
}

/* ======================================================= full-width phones === */
/* On a 360px phone the page lost 33px a side before any content: 16px of
   <main> padding, then another 16-24px inside every card. Content got ~80% of
   the screen. Below sm the page gutter and the card insets are tightened so
   cards run nearly edge to edge and their contents use the width they have.
   Scoped to the signed-in app (.gso-app main); landing and auth pages keep
   their own spacing. */
@media (max-width: 640px) {

    .gso-app main {
        padding-left: calc(0.5rem + var(--gso-safe-l));
        padding-right: calc(0.5rem + var(--gso-safe-r));
    }

    /* Top-level panels: the outer card is the frame, so a slim inset is
       enough. Nested cards (list rows, stat tiles) get slimmer still. */
    .gso-app main .gso-card,
    .gso-app main .glass-panel,
    .gso-app main .glass-card {
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }

    .gso-app main .gso-card .gso-card,
    .gso-app main .gso-card .glass-card {
        padding-left: 0.625rem;
        padding-right: 0.625rem;
    }

    /* Large rounded corners eat usable width at the edges of a small screen. */
    .gso-app main .gso-card.rounded-3xl,
    .gso-app main .glass-panel.rounded-3xl {
        border-radius: var(--gso-radius-lg);
    }

    /* Tables sit flush inside their card instead of adding a second inset. */
    .gso-app main .gso-card > .gso-table-wrap,
    .gso-app main .gso-card > div > .gso-table-wrap {
        margin-left: -0.25rem;
        margin-right: -0.25rem;
    }
}

@media (max-width: 640px) {

    /* Inner sections of a card (a facility card's photo and body, a chart
       panel, a list strip) carried their own 20-24px inset on top of the
       card's, so their text and buttons sat ~45px from the screen edge. */
    .gso-app main .gso-card .p-5,
    .gso-app main .gso-card .p-6,
    .gso-app main .gso-card .p-8,
    .gso-app main .gso-card .px-5,
    .gso-app main .gso-card .px-6,
    .gso-app main .gso-card .px-8,
    .gso-app main .chart-card,
    .gso-app main .dir-strip {
        padding-left: 0.875rem;
        padding-right: 0.875rem;
    }

    /* The Home calendar's day cells: a tighter gap gives each day more room. */
    .gso-app main #calendar-grid {
        gap: 0.25rem;
    }
}

@media (max-width: 640px) {

    /* Page-level panels built from plain Tailwind (bordered, rounded boxes
       such as the Work Queue filter bar) get the same slim inset as cards. */
    .gso-app main > .rounded-2xl,
    .gso-app main > .rounded-3xl,
    .gso-app main > div > .rounded-2xl:not(.gso-btn),
    .gso-app main > div > .rounded-3xl:not(.gso-btn) {
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }
}

/* ====================================================== visible height === */
/* `h-screen` is 100vh, which on phones includes the space behind the browser's
   address bar / toolbar. The drawer's pinned Sign Out and the bottom of every
   page frame ended up hidden under that toolbar. Size them to what is actually
   visible: --gso-vh (set live by gso-mobile.js), else 100dvh, else 100vh. */
@media (max-width: 1023px) {

    .gso-app .h-screen,
    body.gso-app.h-screen,
    #sidebar {
        height: 100vh;
        height: 100dvh;
        height: var(--gso-vh, 100dvh);
    }

    /* The drawer is pinned top and bottom; never let a height rule push it
       past the visible bottom edge. */
    #sidebar {
        max-height: var(--gso-vh, 100dvh);
    }
}

/* ============================================= Work Queue card actions === */
/* Below lg the action column became ONE row: every status label and button
   squeezed into it, so "CANCELLED" / "CLOSED PIPELINE" wrapped one letter per
   line and the buttons stretched to match. Now it wraps: status labels take a
   full row, buttons sit two per row at a normal height. */
@media (max-width: 1023px) {

    .rec-actions {
        flex-wrap: wrap;
        align-items: stretch;
        justify-content: stretch;
    }

    .gso-app .rec-actions > * {
        flex: 1 1 calc(50% - 0.375rem);
        min-width: 0;
        margin: 0 !important;
        min-height: 2.75rem;
    }

    /* Status labels ("Cancelled", "Closed Pipeline") head the group. */
    .gso-app .rec-actions > div {
        flex-basis: 100%;
        min-height: 0;
        order: -1;
    }

    .gso-app .rec-actions > button {
        white-space: nowrap;
    }
}
