/* =====================================================================
   MERIDIAN — RESPONSIVE / MOBILE LAYER
   Loaded AFTER app.css (see index.html) so it wins on source order without
   needing !important for anything except inline styles and MudBlazor's own
   rules. Kept in its own file so the mobile work is reviewable and
   revertable as one unit rather than threaded through 1,885 lines.

   The terminal was built for a desk: a permanent 248px rail, four-across
   KPI grids and eleven-column order books. None of that is wrong on a
   monitor, so NOTHING here changes the desktop rendering — every rule is
   either inside a max-width / pointer query, or a new class whose
   un-queried values reproduce exactly what the inline style it replaced
   produced.

   Breakpoints, and what each one is for:
     <= 1024px  tablet / landscape phone. The rail becomes an off-canvas
                drawer: below this a 248px rail eats a third of the screen,
                and a 56px rail with no labels is worse than no rail.
     <=  900px  three-across grids fold to two; asymmetric splits stack.
     <=  768px  two-column forms fold to one.
     <=  640px  phone. Inputs go to 16px, modals become bottom sheets,
                grids switch to their compact metrics.
     <=  420px  small phone. Anything still two-across folds to one.

   The 16px input rule is not a taste decision. iOS Safari zooms the whole
   viewport when a focused field's text is smaller than 16px, and the only
   way back out is a manual pinch. So every control that can take text gets
   16px on phones. Blocking zoom with maximum-scale=1 would also "fix" it,
   by removing pinch-zoom from users who need it, so we do not do that.
   ===================================================================== */


/* =====================================================================
   1. RESPONSIVE GRID UTILITIES
   These replace hard-coded inline grid-template-columns on the pages. The
   un-queried values match what those inline styles produced, with one
   deliberate difference: every track is minmax(0, 1fr) rather than 1fr.
   Plain 1fr is really minmax(auto, 1fr), so a single unbreakable value — a
   long instrument name, a "+INR 1,71,000.00" — can push the whole grid
   wider than its container. That is invisible on a monitor and is the
   single biggest cause of sideways page scroll on a phone.

   Gaps stay on the element, so pages keep their own spacing.
   ===================================================================== */
/* Single column, but still a grid — so a layout that conditionally drops to one
   panel (the Dashboard without Groups access) keeps the same gap and flow rules
   as its two-column form instead of switching to an inline template. */
.mrd-grid-1 { display: grid; grid-template-columns: minmax(0, 1fr); }
.mrd-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mrd-grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.mrd-grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Card walls: accounts, groups, watchlist symbols, transmission-log fields.
   min(Npx, 100%) is what keeps an auto-fill grid honest — a plain
   minmax(340px, 1fr) track cannot shrink below 340px, so on a 360px phone
   the grid overflowed its padded container by ~30px and took the page with
   it. */
.mrd-grid-auto-150 { display: grid; grid-template-columns: repeat(auto-fit,  minmax(min(150px, 100%), 1fr)); }
.mrd-grid-auto-280 { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }
.mrd-grid-auto-320 { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }
.mrd-grid-auto-340 { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr)); }

/* Named asymmetric splits — one class per site that had its own ratio, so
   each can fold at the width where its own content actually breaks. */
.mrd-split-main   { display: grid; grid-template-columns: minmax(0, 1.6fr)  minmax(0, 1fr);    } /* Dashboard body */
.mrd-split-ticket { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); } /* Order ticket: form + preview */
.mrd-split-script { display: grid; grid-template-columns: minmax(0, 1.7fr)  minmax(0, 0.8fr);  } /* Script search + quantity */

@media (max-width: 1100px) {
    /* Four KPI tiles need ~230px each to hold a 26px numeral and its label.
       Below that they truncate, and two rows of two reads better than four
       squeezed into one. */
    .mrd-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
    .mrd-grid-3      { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mrd-split-main  { grid-template-columns: minmax(0, 1fr); }
    .mrd-split-ticket { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 768px) {
    /* The script search needs the width: its result rows carry a full
       instrument name plus exchange, and the box it drops out of is sized to
       the field. It folds before the plain two-column pairs do. */
    .mrd-split-script { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 560px) {
    /* Held two-up until here deliberately. .mrd-grid-2 covers both form field
       pairs and small stat pairs (Period Open / Volume, circuit limits); at
       ~250px a column both still read, and stacking them earlier would double
       the scroll depth of every modal for no gain. */
    .mrd-grid-2 { grid-template-columns: minmax(0, 1fr); }
}

/* Tiles that hold a full rupee figure rather than a count: the P&L summary
   panel and the account-detail valuation row. Two-across on a 390px phone
   leaves ~128px inside a tile, and "+INR 1,71,000.00" at 22px needs ~168px —
   so without this the figure would be CLIPPED, which on a P&L readout is the
   one failure mode worth writing extra CSS to avoid. Stepping the numerals
   down keeps them whole and keeps the 2x2 shape, which reads far better than
   four full-width tiles stacked down the page.
   Scoped to these two components, so `> div > div:last-child` (the value line
   under its label) is a safe way to reach a font size that is set inline. */
@media (max-width: 560px) {
    .mrd-money-tiles > div > div:last-child { font-size: 17px !important; }
    .mrd-money-tiles > div { padding: 10px 11px !important; }
}

@media (max-width: 400px) {
    .mrd-money-tiles > div > div:last-child { font-size: 15px !important; }
}

@media (max-width: 360px) {
    /* Genuinely narrow (SE-class, 320-359px): two-across leaves ~120px per
       tile, which even a 3-digit count plus its caption starts to crowd.
       Deliberately NOT set at 420px — that folded every 375-414px phone, the
       common case, into eight full-width tiles the dealer had to scroll past
       to reach the position book. */
    .mrd-grid-3,
    .mrd-grid-4 { grid-template-columns: minmax(0, 1fr); }
}


/* =====================================================================
   2. BASE HARDENING
   ===================================================================== */
@media (max-width: 1024px) {
    html {
        /* Safety net: one overflowing child used to make the WHOLE shell
           pannable sideways, which slid the sticky header off screen and left
           the dealer with no navigation. Wide content is expected to scroll
           inside its own container (grids, the dock, the ticker) — never by
           moving the shell.

           Deliberately on `html` and NOT on `body`: overflow-x on the body
           turns it into the scroll container, and position:sticky inside a
           body-as-scroller does not stick — which would have cost us the app
           header, the grid headers and the dock's sticky row all at once. */
        overflow-x: hidden;
    }

    body {
        /* Pull-to-refresh on a WASM app is not a refresh, it is a 3-5 second
           cold boot that loses every filter and open ticket. A dealer scrolling
           a position book upward should not be able to trigger that by
           overshooting. Chaining/rubber-band at the ends goes with it. */
        overscroll-behavior-y: none;
    }

    /* A grey flash on every tap, and long-press selection on things that
       are buttons, both read as "this is a website, not an app". */
    button,
    .sidebar-link,
    .chip,
    .grid-page-btn,
    .app-header-bell {
        -webkit-tap-highlight-color: transparent;
    }

    button,
    .sidebar-link {
        -webkit-user-select: none;
        user-select: none;
    }

    /* Momentum scrolling for every horizontal scroller. */
    .grid-scroll,
    .table-container,
    .mrd-hscroll {
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
    }
}


/* =====================================================================
   3. OFF-CANVAS SIDEBAR  (<= 1024px)
   The rail stops being a column in the layout and becomes a drawer over
   it. Width and transform need !important because MudDrawer writes its
   width inline (SidebarNav sets it so the desktop collapse can animate).
   ===================================================================== */

/* Hidden on desktop — and that is also what keeps the whole mobile-nav
   mechanism inert there. The only way to open the drawer is a button that
   does not exist above 1024px. */
.mrd-nav-toggle    { display: none; }
.mrd-nav-backdrop  { display: none; }

@media (max-width: 1024px) {
    .mrd-nav-toggle {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        flex: none;
        padding: 0;
        border-radius: 11px;
        background: var(--bg-elevated);
        border: 1px solid var(--color-border-strong);
        color: var(--color-text-secondary);
        cursor: pointer;
    }

    .mrd-nav-toggle:active {
        background: var(--accent-primary-subtle);
        color: var(--accent-primary-light);
    }

    .meridian-drawer {
        position: fixed !important;
        top: 0 !important;
        left: 0 !important;
        bottom: 0 !important;
        height: 100% !important;
        width: min(280px, 84vw) !important;
        max-width: 84vw !important;
        z-index: 1300 !important;
        /* -101% rather than -100%: at some zoom levels device-pixel rounding
           left a 1px purple sliver pinned to the screen edge. */
        transform: translateX(-101%);
        transition: transform var(--transition-base);
        border-right: 1px solid var(--color-border) !important;
        box-shadow: none;
        will-change: transform;
    }

    .meridian-drawer.meridian-drawer-open {
        transform: translateX(0);
        box-shadow: 0 0 60px rgba(0, 0, 0, .55);
    }

    /* Reclaim the space the rail used to reserve. MudBlazor's main-content
       margin reads --mud-drawer-width-left, and MainLayout writes that
       variable INLINE on this very element, so both need !important. */
    .mud-main-content {
        --mud-drawer-width-left: 0px !important;
        --mud-drawer-width-right: 0px !important;
        margin-left: 0 !important;
        margin-right: 0 !important;
        padding-left: 0 !important;
    }

    .mrd-nav-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 1290;
        background: rgba(4, 6, 12, .6);
        -webkit-backdrop-filter: blur(2px);
        backdrop-filter: blur(2px);
        /* Swallow the touch rather than let it scroll the page underneath. */
        touch-action: none;
        overscroll-behavior: contain;
        animation: mrd-fade-in 180ms ease;
    }

    /* The drawer is a full-height overlay here, so it has to respect the
       notch and the home indicator itself. */
    .sidebar-inner {
        height: 100% !important;
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    /* 9px of padding on a 13.5px label is a 34px row — under the ~44px a
       thumb actually needs. */
    .sidebar-link {
        padding: 12px 13px;
        font-size: 14.5px;
        gap: 13px;
        margin-bottom: 2px;
    }

    .sidebar-link .mud-icon-root { font-size: 21px; }

    .sidebar-section {
        padding: 18px 10px 7px;
        font-size: 10.5px;
    }

    .sidebar-footer {
        padding: 12px 14px;
        gap: 10px;
    }

    /* Logout is a Size.Small MudIconButton — a 24px box. That is a mouse
       target, and it is the one control in the drawer whose mis-tap ends the
       dealer's session. */
    .sidebar-footer .mud-icon-button {
        min-width: 42px;
        min-height: 42px;
        padding: 9px;
    }

    /* Collapsing to an icon rail is meaningless for a drawer that is either
       fully open or entirely off screen. */
    .sidebar-rail-toggle { display: none !important; }
}

@keyframes mrd-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}


/* =====================================================================
   4. HEADER BAR
   ===================================================================== */
@media (max-width: 1024px) {
    .app-header {
        padding: 0 14px;
        gap: 10px;
        /* In an installed (standalone) app the status bar sits ON the header
           because of viewport-fit=cover. env() is 0 in a normal browser tab,
           so this costs nothing there. */
        padding-top: env(safe-area-inset-top, 0px);
        height: calc(var(--topbar-height) + env(safe-area-inset-top, 0px));
        /* With the rail gone the header is the app's only fixed anchor: it
           must outrank page content, and stay under the drawer + backdrop. */
        z-index: 1200;
    }

    .app-header-title {
        font-size: 16px;
        /* The title block is min-width:0 (set in AppHeader) so it can shrink;
           this is what makes it shrink into an ellipsis rather than clip a
           word off mid-letter. */
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .app-header-sub {
        /* Subtitles are full sentences ("Live overview of all client desks")
           and will not fit beside three buttons. One clipped line. */
        font-size: 11.5px;
        max-width: 46vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .app-header-bell {
        width: 40px;
        height: 40px;
    }
}

@media (max-width: 560px) {
    .app-header {
        padding-left: 10px;
        padding-right: 10px;
        gap: 8px;
    }

    .app-header-title { font-size: 15px; }

    /* Below this the title, back arrow, hamburger and two icon buttons
       already fill the bar. The subtitle is the only thing here that
       carries no information the dealer cannot get elsewhere. */
    .app-header-sub { display: none; }
}


/* =====================================================================
   5. PAGE CHROME
   ===================================================================== */
@media (max-width: 1024px) {
    .page-content { padding: 18px; }
    .card,
    .card-elevated,
    .stat-card { padding: 16px; }
    .stat-card-value { font-size: 26px; }
}

@media (max-width: 640px) {
    .page-content {
        padding: 12px 12px 20px;
        /* Sideways insets matter in landscape on a notched phone. */
        padding-left: max(12px, env(safe-area-inset-left, 0px));
        padding-right: max(12px, env(safe-area-inset-right, 0px));
    }

    .card,
    .card-elevated,
    .stat-card {
        padding: 14px;
        border-radius: var(--radius-md);
    }

    .stat-card-value { font-size: 23px; }

    .page-header {
        /* Page actions were one right-aligned row; on a phone they wrap, and
           a wrapped row should fill the width rather than huddle right. */
        flex-wrap: wrap;
        gap: 8px;
        margin-bottom: 14px;
    }

    /* The action groups inside a page header are their own nested flex rows
       (Refresh + Place Order + Reconnect is ~350px of buttons), so wrapping
       the header alone is not enough — the group has to break too. */
    .page-header > div { flex-wrap: wrap; }

    /* Page toolbars are already flex-wrap with inline gaps, so they wrap.
       What they do not do is stop a control with an inline max-width from
       overshooting a 360px screen. */
    .page-content select,
    .page-content input[type="date"] { max-width: 100% !important; }
}

/* The order ticket's summary column stops being a column below 900px. */
@media (max-width: 900px) {
    .mrd-ticket-summary { position: static !important; }
}

/* Segmented view switchers (Orders: Working / Not Received / Place Order).
   Three flex:1 buttons carrying an icon and a two-word label need ~112px
   each, so at 360px the labels overflowed their own cells. */
@media (max-width: 560px) {
    .mrd-viewtabs > button {
        font-size: 11.5px !important;
        gap: 5px !important;
        padding: 9px 6px !important;
        min-width: 0;
    }
}

@media (max-width: 400px) {
    /* Last resort before the labels break: the label says what the icon says. */
    .mrd-viewtabs > button > svg { display: none; }
}

/* Pages that render their own header row instead of using the top bar (the
   group drill-down) declare this so the row can wrap: back button + title on
   the first line, the account scope and the primary action beneath, rather
   than five controls compressed into one 360px line. */
@media (max-width: 768px) {
    .mrd-page-head {
        flex-wrap: wrap;
        row-gap: 12px;
    }

    /* The flex:1 spacer forces a wrap point on desktop; on a phone it would
       instead eat a whole row of its own. */
    .mrd-page-head > .mrd-page-head-spacer { display: none; }
}


/* =====================================================================
   6. DATA GRIDS
   A trading grid has 8-14 meaningful columns and every one of them is a
   number somebody acts on, so we do NOT hide columns or reflow rows into
   cards — that silently drops information the dealer came for. The table
   keeps its shape and scrolls sideways inside its own container. What
   changes on a phone is the density, and that the scroll is discoverable.
   ===================================================================== */
.grid-scroll { overflow-x: auto; }

@media (max-width: 1024px) {
    .grid-scroll {
        /* Keeps the gesture unambiguous: vertical panning stays with the
           page, horizontal belongs to the grid. */
        touch-action: pan-x pan-y;
    }

    /* A rounded, clipped container hid the fact that the table continued
       past its right edge. The mask fades the last 24px into the surface so
       there is a visible "more this way". The fade is constant rather than
       scroll-driven (not portable yet) — harmless, because a grid narrow
       enough to fit has nothing underneath the fade. */
    .table-container { position: relative; }

    .table-container::after {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        width: 24px;
        pointer-events: none;
        background: linear-gradient(90deg, transparent, var(--bg-surface));
        border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
    }
}

@media (max-width: 640px) {
    .meridian-table { font-size: 12.5px; }

    .meridian-table th {
        padding: 9px 10px;
        font-size: 11px;
    }

    .meridian-table td { padding: 9px 10px; }

    .meridian-table tr.grid-filter-row td { padding: 5px 10px; }

    .grid-filter-input {
        padding: 7px 8px;
        min-width: 84px;
        /* Its font size is set with the rest of the text controls in section
           10, which is keyed to touch rather than to width — see there. */
    }

    .table-pagination {
        /* Rows-per-page and the pager cannot share one line at 360px. */
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
        padding: 10px 12px;
    }

    .table-pagination > div { justify-content: space-between; }

    /* 28px was a mouse target. */
    .grid-page-btn {
        width: 38px;
        height: 38px;
    }

    /* Order History pages on the server and so has its own footer, built from
       inline styles rather than .table-pagination — same treatment. */
    .mrd-pager {
        flex-direction: column;
        align-items: stretch !important;
        gap: 10px;
        padding: 10px 12px !important;
    }

    .mrd-pager > div { justify-content: space-between; }

    .mrd-pager button {
        width: 38px !important;
        height: 38px !important;
    }
}


/* =====================================================================
   7. MODALS -> BOTTOM SHEETS
   A centred 460px card in a 24px gutter is right on a monitor. On a phone
   the same card floats mid-screen with its actions above the thumb-reach
   line, and its max-height is measured against the wrong height while the
   browser's URL bar is showing. Below 640px each modal becomes a sheet
   anchored to the bottom edge and sized in dvh.

   These two classes carry what DesignModal used to declare inline, so its
   desktop appearance is unchanged.
   ===================================================================== */
/* TOP-ALIGNED, NOT CENTRED — from develop, and load-bearing: a centred dialog
   taller than the viewport is clipped at BOTH ends, and the half off the top
   cannot be scrolled back to. Anchoring to the top lets a tall dialog grow
   downward into a scrollable overlay, which always has a way back.
   The top gap is min(4vh, 28px): comfortable on a large display, nearly
   nothing on a short one where height is better spent on the dialog. */
.mrd-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: min(4vh, 28px) 16px 24px;
    overflow-y: auto;
    background: rgba(4, 6, 12, .72);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

.mrd-modal-card {
    width: 100%;
    max-height: calc(100vh - min(8vh, 52px));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--bg-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: 16px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, .6);
    animation: mdpop .26s cubic-bezier(.2, .7, .2, 1);
}

/* dvh tracks the URL bar; vh does not. That difference is exactly why a
   vh-sized dialog on iOS Safari has its confirm button below the fold with no
   way to scroll to it. */
@supports (height: 100dvh) {
    .mrd-modal-card { max-height: calc(100dvh - min(8vh, 52px)); }
}

@media (max-width: 640px) {
    .mrd-modal-overlay {
        padding: 0;
        align-items: flex-end;
    }

    .mrd-modal-card {
        max-width: none !important;
        max-height: 92vh;
        border-radius: 18px 18px 0 0;
        border-right: none;
        border-bottom: none;
        border-left: none;
        /* Clears the home indicator so the primary action is not half under it. */
        padding-bottom: env(safe-area-inset-bottom, 0px);
        animation: mrd-sheet-up .24s cubic-bezier(.2, .7, .2, 1);
    }

    /* Two 50% buttons at 360px are 160px each, and one of them is "Square
       off" or "Decommission". Stacked full width instead.

       column-reverse, so — every .dm-actions in the app is authored as
       [Cancel, Confirm] — the CONFIRM button renders on top and Cancel at the
       bottom. That is the iOS action-sheet convention, and it is the safer of
       the two arrangements here: the thumb's resting position over a bottom
       sheet lands on Cancel, not on the irreversible action. DOM order is
       untouched, so tab order and screen-reader order still read
       Cancel-then-Confirm.

       `flex: none` matters: app.css gives these buttons flex:1 for the
       side-by-side row, and in a COLUMN that would make each one grow to fill
       the sheet's height. */
    .dm-actions {
        flex-direction: column-reverse;
        gap: 8px;
    }

    .dm-btn-cancel,
    .dm-btn-primary,
    .dm-btn-danger {
        flex: none;
        width: 100%;
        padding: 14px;
        font-size: 15px;
    }
}

@supports (height: 100dvh) {
    @media (max-width: 640px) {
        .mrd-modal-card { max-height: 92dvh; }
    }
}

@keyframes mrd-sheet-up {
    from { opacity: 0; transform: translateY(24px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ---------------------------------------------------------------------
   7b. MUDBLAZOR DIALOGS
   Roughly half the modals in the app are MudDialog rather than
   DesignModal (Confirm, Modify Order, Edit Account, Add/Request Static
   IP, Add to Watchlist, the inactivity warning). MudBlazor's default
   paper carries a 32px margin and a vh-based max-height, so on a 360px
   phone a FullWidth "Small" dialog rendered ~296px wide with its actions
   possibly below the fold.
   --------------------------------------------------------------------- */
@media (max-width: 640px) {
    .mud-dialog-container .mud-dialog {
        margin: 12px !important;
        width: calc(100% - 24px) !important;
        max-width: calc(100% - 24px) !important;
        max-height: calc(100vh - 24px);
    }

    /* MudBlazor scopes its own padding as `.mud-dialog .mud-dialog-title`
       (specificity 0,2,0), so a bare `.mud-dialog-title` here loses to it —
       these are deliberately written at matching depth rather than reaching
       for !important. */
    .mud-dialog .mud-dialog-title {
        padding: 16px 16px 8px;
        font-size: 17px;
    }

    .mud-dialog .mud-dialog-content { padding: 0 16px 8px; }

    /* Stacked and full width, and in the SAME order as .dm-actions above:
       column-reverse over MudBlazor's [Cancel, Confirm] markup puts Confirm on
       top and Cancel under the thumb. Getting these two modal systems to agree
       matters — half the app's dialogs are MudDialog and half are DesignModal,
       and a confirm button that swaps ends depending on which one you happened
       to open is how a dealer taps the wrong one. */
    .mud-dialog .mud-dialog-actions {
        flex-direction: column-reverse;
        align-items: stretch;
        gap: 8px;
        padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
    }

    /* flex-basis is the HEIGHT in a column container, so `flex: 1 1 100%`
       here would stretch each button to fill the dialog. Fixed height, full
       width via the stretch above. */
    .mud-dialog .mud-dialog-actions .mud-button-root {
        flex: 0 0 auto;
        width: 100%;
        min-height: 44px;
    }

    /* MudBlazor spaces sibling actions with `> :not(:first-child) {
       margin-left: 8px }`. Once they are stacked that is not spacing, it is
       8px shaved off the width of every button but the first — so the row of
       "full width" buttons came out visibly ragged. The gap above spaces them
       instead. */
    .mud-dialog .mud-dialog-actions > :not(:first-child) {
        margin-left: 0;
        margin-inline-start: 0;
    }
}

@supports (height: 100dvh) {
    @media (max-width: 640px) {
        .mud-dialog-container .mud-dialog { max-height: calc(100dvh - 24px); }
    }
}

/* ---------------------------------------------------------------------
   7c. MUDBLAZOR TABS  (account detail, group detail)
   MudTabs measures its header and shows scroll arrows when the tabs
   overflow, but that measurement runs on render and does not survive an
   orientation change. Letting the toolbar scroll by hand is the fallback
   that always works, and tighter tabs mean five of them fit a phone
   without needing it.
   --------------------------------------------------------------------- */
@media (max-width: 768px) {
    .mud-tabs-toolbar-wrapper {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }

    .mud-tabs-toolbar-wrapper::-webkit-scrollbar { display: none; }

    .mud-tab {
        min-width: auto;
        padding: 0 12px;
        font-size: 12.5px;
    }
}



/* 8. GLOBAL POSITIONS DOCK — removed with the feature. The number is left
   unused rather than renumbering 9-15, which would churn most of this file
   for nothing; this line exists so nobody goes looking for a lost section. */


/* =====================================================================
   9. OVERLAYS PINNED TO AN EDGE
   ===================================================================== */
@media (max-width: 640px) {
    .toast-container {
        /* A 360px-wide toast pinned to the right of a 360px screen has no
           room to be readable, and it landed on top of the header buttons.
           Full width, just under the header, instead. */
        top: calc(var(--topbar-height) + env(safe-area-inset-top, 0px) + 8px);
        left: 10px;
        right: 10px;
        max-width: none;
    }

    .toast { padding: 11px 13px; }

    .connectivity-banner {
        padding: 8px 12px;
        padding-top: calc(8px + env(safe-area-inset-top, 0px));
        font-size: 12px;
        line-height: 1.35;
        text-align: center;
    }

    .notif-panel {
        /* The bell dropdown is absolutely positioned off a button ~10px from
           the right edge, so a fixed-width panel hung off the screen. */
        position: fixed !important;
        top: calc(var(--topbar-height) + env(safe-area-inset-top, 0px) + 6px) !important;
        left: 10px !important;
        right: 10px !important;
        width: auto !important;
        max-width: none !important;
    }
}


/* =====================================================================
   10. FORM CONTROLS ON TOUCH DEVICES
   Everything that takes text goes to 16px so iOS does not zoom the
   viewport on focus, and every control gets a real touch height.

   Keyed to `(hover: none) and (pointer: coarse)` — the standard "touch is
   the primary input" test — and NOT to viewport width, which was the first
   version and was wrong: a phone in LANDSCAPE is 844px wide, sails past any
   max-width:640px gate, and still zooms the viewport the moment a 13px
   field takes focus. Orientation does not change the device.

   `(max-width: 640px)` is kept as the second arm of the OR so a narrow
   desktop window behaves the same, and so this still holds in a mouse-
   driven browser being used to check the layout.

   A touchscreen laptop reports hover:hover / pointer:fine for its PRIMARY
   pointer, so it is deliberately excluded — it does not zoom, and forcing
   44px controls there would coarsen a mouse-driven grid for no reason.
   ===================================================================== */
@media (hover: none) and (pointer: coarse), (max-width: 640px) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
    select,
    textarea,
    .dm-input,
    .dm-select,
    .login-input,
    .grid-filter-input,
    .mud-input-root input,
    .mud-input-slot {
        font-size: 16px !important;
    }

    /* iOS gives a select and a date field their own chrome and ignores
       height; min-height is what actually lands. */
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
    select,
    textarea {
        min-height: 44px;
    }

    .dm-input,
    .dm-select { padding: 12px 13px; }

    /* Stops iOS adding its own inner shadow and corner radius to inputs. */
    input,
    textarea {
        -webkit-appearance: none;
        appearance: none;
        border-radius: 10px;
    }

    /* Android renders a native date field noticeably taller than a text
         input; matching the line box keeps a mixed toolbar row level. */
    input[type="date"] { line-height: 1.2; }
}


/* =====================================================================
   11. LOGIN
   ===================================================================== */
/* Same dvh reasoning as the modals: min-height:100vh on iOS Safari is
   taller than the visible area, so the card sat partly below the fold and
   the page opened already scrolled. */
@supports (height: 100dvh) {
    .auth-shell,
    .login-page { min-height: 100dvh; }
}

@media (max-width: 640px) {
    .login-form-panel {
        align-items: flex-start;
        padding: 28px 18px;
        padding-top: max(28px, env(safe-area-inset-top, 0px));
        padding-bottom: max(28px, env(safe-area-inset-bottom, 0px));
    }

    .login-card       { max-width: none; }
    .login-card-head  { margin-bottom: 18px; }
    .login-card-head h2 { font-size: 21px; }
    .login-submit     { padding: 15px; }
}


/* =====================================================================
   12. SHELL ODDS AND ENDS
   ===================================================================== */
/* On desktop the sidebar is a column in the layout and 100vh is correct;
   dvh is simply the better unit once browser chrome can hide. */
@supports (height: 100dvh) {
    .sidebar-inner { height: 100dvh; }
}

/* Anything the app renders as a wide scrollable strip. */
.mrd-hscroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

@media (max-width: 640px) {
    .indices-bar { height: 34px; }
    .index-chip  { margin-right: 16px; }
    .index-name  { font-size: 10.5px; }
    .index-ltp   { font-size: 11.5px; }

    /* Watchlist symbol cards: four stat columns at ~70px each cannot hold a
       label and a price, so they become 2x2. */
    .mrd-card-stats {
        grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
        gap: 8px 10px !important;
    }

    .mrd-card-name { font-size: 14px; }

    /* A 360px plot inside a 92dvh bottom sheet leaves no room for the price
       header and the range bars underneath it. */
    .mrd-chart-frame { height: 240px !important; }

    /* The order ticket's numeric row (Lots / Qty / Price / Trigger) is built
       from a computed track list, so it is overridden rather than replaced.
       Four across at 360px is ~70px per field — too narrow for a stepper and
       a five-digit price. */
    .mrd-order-fields { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }

    /* Script search results are positioned width:max-content off an input;
       cap the height so the list cannot cover the whole screen. */
    .mrd-search-dropdown { max-height: 52vh; }
}


/* =====================================================================
   13. TOUCH / COARSE POINTER  (any width)
   A stylus or touch tablet at 1200px still cannot hit a 28px button, and
   :hover on touch is not a transient state — the browser latches it after
   a tap and leaves it until you tap elsewhere. So: real hit areas, and no
   behaviour that depends on hover being temporary.
   ===================================================================== */
@media (pointer: coarse) {
    .grid-page-btn   { min-width: 34px; min-height: 34px; }
    .sidebar-link    { min-height: 40px; }
    .app-header-bell { min-width: 38px; min-height: 38px; }

    /* Hover affordances never fire on touch, so make the sort control
       permanently legible rather than reveal it on :hover. */
    .meridian-table th .grid-sort-icon { opacity: 1; }

    /* The lift-on-hover latched after a tap, leaving cards floating 2px up
       with an accent border until the dealer tapped something else. */
    .stat-card:hover,
    .card:hover {
        transform: none;
        border-color: var(--color-border);
        box-shadow: none;
    }

    .dm-btn-primary:hover:not(:disabled),
    .dm-btn-danger:hover:not(:disabled) { transform: none; }

    .sidebar-nav a.sidebar-link:hover .mud-icon-root { transform: none; }
}

/* The ticker pauses on :hover so a dealer can read a value. On touch that
   hover latches, which stopped the tape permanently after one stray tap.
   Restrict the pause to pointers that can actually hover away again. */
@media (hover: none) {
    .indices-bar:hover .indices-track { animation-play-state: running; }
}


/* =====================================================================
   14. REDUCED MOTION
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    .meridian-drawer  { transition: none; }
    .mrd-nav-backdrop { animation: none; }
    .mrd-modal-card   { animation: none; }
}


/* =====================================================================
   15. COMPACT DENSITY FOR SHORT VIEWPORTS
   The whole UI is sized in px against a ~1080p-tall screen. On a 768px
   laptop that same layout is ~300px too tall, which is why it has to be
   read at 85-90% browser zoom.

   These rules key off viewport HEIGHT, not width — the problem is vertical
   budget, and a 1366x768 laptop is wide enough while being 300px short.
   Nothing here fires on a 1080p display, so the desk screens are untouched.

   Two levels:
     <= 900px  compact   (1536x864, 1366x768)  ~ the 90% zoom look
     <= 780px  denser    (1366x768 with chrome, 1280x720) ~ the 85% look

   What this CANNOT reach is the several hundred inline `padding:16px 20px`
   / `font-size:26px` declarations on the KPI tiles and order ticket, since
   an inline style beats any stylesheet rule without !important. The tile
   grids are therefore targeted by their wrapper class below, which is the
   one structural hook they share.
   ===================================================================== */
@media (max-height: 900px) {
    :root { --topbar-height: 54px; }

    .page-content { padding: 16px 18px; }

    .card, .card-elevated, .stat-card { padding: 14px 16px; }
    .stat-card-value { font-size: 24px; }
    .stat-card-label { font-size: 11px; }
    .page-header { margin-bottom: 12px; }

    .app-header-title { font-size: 16px; }
    .app-header-sub   { font-size: 11.5px; }

    /* The single biggest win on a data page: 20 rows x 4px is 80px back. */
    .meridian-table th { padding: 7px 12px; }
    .meridian-table td { padding: 6px 12px; }
    .meridian-table tr.grid-filter-row td { padding: 4px 12px; }
    .table-pagination { padding: 7px 16px; }

    /* KPI / P&L tile rows. The tiles themselves are inline-styled, so the
       wrapper class is the only handle — hence !important, used here and
       nowhere else in this file for exactly that reason. */
    .mrd-grid-3 > div,
    .mrd-grid-4 > div { padding: 11px 14px !important; }
    .mrd-grid-3 > div > div:last-child,
    .mrd-grid-4 > div > div:last-child { font-size: 20px !important; }
    .mrd-money-tiles > div > div:last-child { font-size: 18px !important; }

    /* Sidebar: 11 nav rows at 2px each is another 22px. */
    .sidebar-logo   { padding: 14px 20px 12px; }
    .sidebar-link   { padding: 7px 12px; }
    .sidebar-section { padding: 11px 10px 6px; }
    .sidebar-footer { padding: 10px 14px; }

    /* Dialogs get more of the short screen, and less gutter around it. */
    .mrd-modal-overlay { padding: min(2.5vh, 16px) 16px 16px; }
    .mrd-modal-card    { max-height: calc(100vh - min(5vh, 32px)); }
}

@supports (height: 100dvh) {
    @media (max-height: 900px) {
        .mrd-modal-card { max-height: calc(100dvh - min(5vh, 32px)); }
    }
}

@media (max-height: 780px) {
    :root { --topbar-height: 48px; }

    .page-content { padding: 12px 14px; }

    .card, .card-elevated, .stat-card { padding: 11px 13px; }
    .stat-card-value { font-size: 21px; }
    .page-header { margin-bottom: 10px; }

    .meridian-table { font-size: 12.5px; }
    .meridian-table th { padding: 6px 10px; font-size: 11px; }
    .meridian-table td { padding: 5px 10px; }
    .table-pagination { padding: 6px 12px; }

    .mrd-grid-3 > div,
    .mrd-grid-4 > div { padding: 9px 12px !important; }
    .mrd-grid-3 > div > div:last-child,
    .mrd-grid-4 > div > div:last-child { font-size: 18px !important; }
    .mrd-money-tiles > div > div:last-child { font-size: 16px !important; }

    .sidebar-logo   { padding: 11px 18px 9px; }
    .sidebar-link   { padding: 6px 12px; font-size: 13px; }
    .sidebar-section { padding: 9px 10px 5px; font-size: 9.5px; }
}
