/* ═══════════════════════════════════════════════════════════════════════
   mobile.css — phone / small-tablet layout

   Loaded LAST in index.html so every rule here wins the cascade over the
   feature stylesheets at equal specificity. The desktop build is untouched:
   nothing here applies above 900px, and the only non-media rules elsewhere
   are the two inert base rules in main.css (.nav-toggle / .navbar-menu).

   The app keeps its "shell" model on mobile too — html/body never scroll,
   each route owns an inner scroll container. This file only reflows the
   chrome and the wide fixed-size pieces so nothing clips off-screen.

   Breakpoints:
     900px — tablet: header rows begin to wrap, grids loosen.
     768px — phone: hamburger nav, bottom-sheet drawer, single/2-up grids.
   ═══════════════════════════════════════════════════════════════════════ */

/* ╔══════════════════════════════════════╗
   ║  TABLET  (≤ 900px)                    ║
   ╚══════════════════════════════════════╝ */
@media (max-width: 900px) {
    /* The 2K-monitor down-scale from main.css also fires here — cancel it so
       phones render at their true CSS pixel size. */
    html {
        zoom: 1;
    }

    /* Header rows: stop forcing title and actions onto one line. */
    .page-header,
    .list-header,
    .detail-header,
    .cards-header,
    .inv-detail-title-row,
    .dga-detail-title-row {
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
    }

    .inv-detail-header-right,
    .dga-detail-header-right {
        align-items: stretch;
    }

    /* Prices: drop the 2-column named-area grid to a stacked, scrolling column. */
    .prices-content {
        display: flex;
        flex-direction: column;
        overflow-y: auto;
        gap: 14px;
        grid-template-rows: none;
    }

    .prices-panel {
        min-height: 300px;
    }

    .prices-graph-panel {
        min-height: 260px;
    }

    /* Kill the hover-to-expand-search choreography — no hover on touch, and
       it fights the plain scrolling column above. */
    .prices-content:has(.prices-search-panel:hover),
    .prices-content:has(.prices-search-panel:focus-within),
    .prices-page:has(#watchlist-add-modal:not(.hidden)) .prices-content {
        grid-template-rows: none;
    }

    .prices-content:has(.prices-search-panel:hover) .prices-graph-panel,
    .prices-content:has(.prices-search-panel:focus-within) .prices-graph-panel,
    .prices-page:has(#watchlist-add-modal:not(.hidden)) .prices-content .prices-graph-panel {
        pointer-events: auto;
        opacity: 1;
    }

}

/* ╔══════════════════════════════════════╗
   ║  PHONE  (≤ 768px)                     ║
   ╚══════════════════════════════════════╝ */
@media (max-width: 768px) {

    :root {
        /* Bottom-sheet height for the card drawer; the tab-rail bar anchors
           its bottom edge here so it lands flush on the sheet's top. */
        --drawer-sheet-h: 84dvh;
    }

    /* ── Global padding trim ──
       32px side gutters everywhere → 14px. */
    .topbar,
    .footer {
        padding-left: 14px;
        padding-right: 14px;
    }

    .topbar {
        padding-top: 10px;
        padding-bottom: 10px;
    }

    .page-header,
    .list-header,
    .detail-header,
    .cards-header {
        padding-left: 14px;
        padding-right: 14px;
        padding-top: 14px;
        padding-bottom: 14px;
    }

    /* ── Top bar ── */
    .topbar-brand {
        font-size: 0.78rem;
        letter-spacing: 0.05em;
    }

    .btn-login {
        padding: 7px 14px;
        font-size: 0.8rem;
    }

    /* ══ Hamburger nav ══
       main.css keeps .nav-toggle hidden and .navbar-menu as display:contents;
       flip both here to build a slide-down panel. */
    .navbar {
        position: relative;
        flex-wrap: wrap;
        padding: 0;
    }

    .nav-toggle {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 48px;
        height: 46px;
        padding: 0;
        background: none;
        border: none;
        color: var(--text-muted);
        font-size: 1.2rem;
        cursor: pointer;
        transition: color 0.2s;
    }

    .nav-toggle:hover,
    .nav-toggle.open {
        color: var(--text);
    }

    .navbar-menu {
        display: none;
    }

    .navbar-menu.open {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background: var(--bg);
        border-bottom: 1px solid var(--border);
        box-shadow: var(--shadow-menu);
        z-index: 400;
    }

    /* The right-hand nav group (Admin / My Decks / Inventory) becomes its own
       stacked block. A single brighter rule between it and the left-hand
       links (Home … Prices) marks the divide — no gap. */
    .navbar-menu.open .navbar-right {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        margin-left: 0;
        border-top: 1px solid var(--border-focus);
    }

    .navbar-menu.open a {
        padding: 15px 16px;
        border-bottom: 1px solid var(--border);
        border-left: 3px solid transparent;
        border-bottom-color: var(--border);
    }

    /* The last left link sits directly on the group rule (no doubled line),
       and the final item has no trailing hairline. */
    .navbar-menu.open > a:last-of-type,
    .navbar-menu.open a:last-child {
        border-bottom: none;
    }

    /* Active link: accent moves from the (now-hidden) bottom border to the
       left edge. */
    .navbar-menu.open a.active {
        border-bottom-color: var(--border);
        border-left-color: var(--accent);
        color: var(--text);
    }

    /* Prices and Admin don't work on a phone yet — keep the links visible but
       mark them out. They still route (navigate() shows a "not available"
       stub via mobileBlocked), just dimmed with a trailing tag. */
    .navbar-menu.open a[href="/prices"],
    .navbar-menu.open a[href="/admin"] {
        color: var(--text-muted);
        opacity: 0.6;
    }

    .navbar-menu.open a[href="/prices"]::after,
    .navbar-menu.open a[href="/admin"]::after {
        content: " · desktop only";
        font-size: 0.8em;
        letter-spacing: 0.02em;
        opacity: 0.8;
    }

    /* ══ Page-control caret ══
       Right-aligned on the navbar row, opposite the hamburger. app.js
       unsets [hidden] only on routes that carry a control strip. */
    .page-ctrl-toggle:not([hidden]) {
        display: flex;
        align-items: center;
        justify-content: center;
        margin-left: auto;
        width: 46px;
        height: 46px;
        padding: 0;
        background: none;
        border: none;
        color: var(--text-muted);
        cursor: pointer;
        transition: color 0.2s;
    }

    .page-ctrl-toggle:hover,
    .page-ctrl-toggle.open {
        color: var(--text);
    }

    /* .dropdown-arrow (components.css) points down at rest, flips up on .open. */

    /* Control strip (bin/deck name, counts, search box, filter & sort menus)
       is collapsed by default on mobile — the caret toggles `.page-ctrl-open`
       on <body>. animateHeightWipe drives the open/close transition; this is
       just the resting state for freshly-swapped pages and detail views. */
    body:not(.page-ctrl-open) .cards-header,
    body:not(.page-ctrl-open) .list-header,
    body:not(.page-ctrl-open) .detail-header {
        display: none;
    }

    /* ── Headers ── */
    .detail-header {
        padding: 12px 14px;
    }

    .inv-detail-header-right,
    .dga-detail-header-right {
        align-items: stretch;
        width: 100%;
    }

    .inv-detail-counts-row,
    .dga-detail-counts-row {
        justify-content: flex-start;
    }

    /* Deck Builder is a desktop-only side-by-side panel (opened by right-click,
       which phones don't have) — there's no room to sit it beside the deck view
       here. Force it hidden and keep the page in its normal single column even
       if .dga-builder-open somehow lingers from a desktop session. */
    .dga-builder,
    /* its detail-header toggle button goes too — nothing for it to open here */
    .dga-builder-toggle-btn {
        display: none !important;
    }

    .dga-page.dga-builder-open {
        flex-direction: column;
    }

    /* List-view "+ New Bin / + New Deck" — full-width tap target. */
    .inv-bins-create-btn,
    .dga-create-btn {
        width: 100%;
        text-align: center;
        padding: 12px 16px;
    }

    /* ── Search / filter rows ── */
    .search-wrap,
    .inv-add-search-wrap {
        flex-wrap: wrap;
    }

    .search-wrap input,
    .search-wrap .autocomplete-wrap,
    .inv-add-search-wrap .autocomplete-wrap {
        flex: 1 1 100%;
        width: 100%;
    }

    .btn-search {
        flex: 1 1 100%;
    }

    .cards-header-left,
    .set-dropdown-wrap,
    .cards-filter-wrap {
        width: 100%;
    }

    .set-dropdown-btn,
    .cards-filter-btn {
        width: 100%;
        justify-content: space-between;
    }

    .inv-detail-controls {
        flex-wrap: wrap;
        width: 100%;
    }

    .inv-detail-search,
    .inv-detail-controls input {
        width: 100%;
        flex: 1 1 100%;
        order: -1;
    }

    .inv-filter-dropdown-wrap {
        flex: 1;
    }

    .inv-filter-dropdown-btn {
        width: 100%;
        justify-content: space-between;
    }

    /* Popover menus: keep them anchored to their trigger (position stays
       absolute — the shared .menu default) but cap the width so a wide one
       can't push the page sideways, and cap the height so a long one stays
       on screen. NOTE: do not switch these to position:fixed — .menu sets
       top:calc(100% + 6px), which under fixed resolves against the viewport
       and drops the menu a full screen-height below where it belongs. */
    .menu,
    .set-dropdown-menu,
    .cards-filter-menu,
    .inv-filter-menu,
    .default-bin-menu,
    .topbar-user-dropdown {
        max-width: calc(100vw - 20px);
        max-height: 70vh;
        overflow-y: auto;
    }

    /* The Sets menu anchors left:0 and can be wide — clamp it to the screen. */
    .set-dropdown-menu {
        min-width: 0;
    }

    #set-dropdown-options {
        grid-template-columns: 1fr;
    }

    /* ── Card / tile grids ──
       Trim the outer padding on the list grids (bin list, deck list,
       watchlist) and the card-search grid. */
    .card-grid,
    .inv-bins-grid,
    .dga-deck-grid,
    .prices-watchlist-grid {
        padding: 14px;
        gap: 12px;
    }

    /* Bin / deck LIST tiles (Inventory, My Decks, public Decks & Collection,
       Profile's deck/bin menus) drop from their native ~280px tracks to a
       fluid 2-up so a phone shows at least two per row. 140px keeps two
       columns even in the narrow Profile side panels. Tighter tile padding
       to keep the name + description legible in the smaller box. */
    .inv-bins-grid,
    .dga-deck-grid,
    .admin-user-tile-grid {
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
        gap: 10px;
    }

    .inv-bin-tile,
    .dga-deck-tile {
        padding: 14px 15px;
    }

    /* Give the Profile side panels more room so their tile grid clears the
       140px x 2 threshold. */
    .profile-panel {
        padding: 12px 12px;
    }

    /* Deck-detail and bin-detail card areas must land on the SAME side
       padding as the card-search grid (14px). Decks: the 32px lives on
       .dga-card-grid (wrap has none). Inventory: the 32px lives on
       .inv-card-grid-WRAP, and .inv-card-grid has none — so zero the wrap's
       sides here and put the identical 16px/14px on both inner grids. */
    .dga-card-grid,
    .inv-card-grid {
        padding: 16px 14px;
    }

    .inv-card-grid-wrap {
        padding-left: 0;
        padding-right: 0;
    }

    /* Every card-art grid — search results, bin-detail sections, deck-detail
       sections — uses the identical fluid 2-up tracks, gap and stretch as
       the card search. The dashed "+ Add Card" tile is switched off its
       fixed 355px height to the 5:7 card aspect so it keeps matching the
       now-variable tile height. Card-tile hover overlays are already
       suppressed on touch (see below), so a narrower tile doesn't crowd
       them. */
    #card-results.card-grid,
    .inv-section-grid,
    .dga-section-grid {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        justify-content: stretch;
        gap: 12px;
    }

    .inv-card-add-tile {
        height: auto;
        aspect-ratio: 5 / 7;
    }

    /* Featured-set banners: at least two per row on the narrowest phone,
       more as the viewport widens. */
    #card-results.card-grid--featured,
    .card-grid--featured {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }

    .featured-set-name {
        font-size: 0.92rem;
    }

    .featured-set-prefixes {
        font-size: 0.68rem;
    }

    /* ── Card tiles: no hover on touch ──
       On desktop, hovering a card tile zooms it and reveals a dim layer +
       quick controls (add-to-bin, qty +/-). None of that translates to
       touch, and forcing the controls always-on buried the card art. So on
       mobile the tiles just show clean art — a tap opens the card's drawer
       (Cards / Decks) or its edit modal (Inventory bin), which is where the
       real controls live. Only the hover-zoom transform needs neutralising
       so it can't get stuck after a tap. */
    .tile-hoverable .tile-zoom,
    .tile-hoverable:hover .tile-zoom {
        transform: none !important;
    }

    /* ── Bottom-sheet card drawer ──
       The 820px right-hand slab becomes a sheet that rises from the bottom.
       The tab rail (✕ / info / thema / pricing) docks as its own bar sitting
       flush ON TOP of the sheet — in the scrim gap, NOT overlapping the
       scrollable content — so nothing scrolls under it and the first line of
       content isn't hidden. --drawer-sheet-h is shared by the sheet height
       and the bar's bottom anchor so they always meet. */
    .card-drawer {
        position: fixed;
        top: auto;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        height: 82vh;            /* fallback for no-dvh browsers */
        height: var(--drawer-sheet-h);
        transform: translateY(100%);
        border-radius: 0;
        border: 1px solid var(--border);
        border-bottom: none;
        z-index: 600;
    }

    .card-drawer.open {
        transform: translateY(0);
        box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.5);
    }

    /* Visual scrim behind the sheet (close is via the ✕ in the tab bar). */
    body:has(.card-drawer.open)::before {
        content: '';
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.55);
        z-index: 598;
    }

    /* Tab rail as a bar flush on top of the sheet — its rounded corners give
       the sheet its top edge. */
    .drawer-sidebar {
        position: fixed;
        top: auto;
        left: 0;
        right: 0;
        bottom: calc(82vh - 1px);
        bottom: calc(var(--drawer-sheet-h) - 1px);
        height: 46px;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        gap: 10px;
        width: 100%;
        padding: 0 10px;
        border: 1px solid var(--border);
        border-bottom: 1px solid var(--border);
        border-radius: var(--radius) var(--radius) 0 0;
        background: var(--bg-card);
        box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.4);
        z-index: 601;
    }

    .drawer-sidebar-divider {
        width: 1px;
        height: 20px;
        margin: 0 2px;
    }

    .drawer-inner {
        padding: 18px 16px 32px;
    }

    .drawer-top {
        grid-template-columns: 1fr;
        gap: 16px;
    }

    .drawer-stats {
        grid-template-columns: 1fr 1fr;
    }

    /* ── Modals ── */
    .modal,
    .inv-modal {
        width: calc(100vw - 24px);
        min-width: 0;
        max-width: none;
        max-height: 90vh;
        padding: 18px;
    }

    .inv-modal-wide,
    .inv-modal-wide.inv-modal-foil-step {
        width: calc(100vw - 24px);
        max-width: none;
    }

    /* Side-by-side image + form → stacked. */
    .inv-foil-step-body,
    .inv-add-card-preview {
        flex-direction: column;
        height: auto;
        gap: 14px;
    }

    .inv-foil-step-body .inv-modal-img-large,
    .inv-modal-img-large,
    .inv-modal-img {
        width: 55%;
        max-width: 180px;
        height: auto;
        margin: 0 auto;
    }

    .inv-add-results,
    #add-card-results,
    #inv-banner-results,
    #watchlist-card-results {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
        gap: 8px;
    }

    .inv-import-textarea {
        height: 180px;
    }

    .inv-modal-actions {
        flex-wrap: wrap;
        gap: 8px;
    }

    .inv-modal-actions > * {
        flex: 1 1 auto;
    }

    /* ── Profile ── */
    .profile-body {
        padding: 14px;
    }

    /* ── Home / Login ── */
    .hero {
        padding: 48px 20px;
    }

    .hero-title {
        font-size: 2rem;
    }

    .login-wrap {
        padding: 32px 16px;
    }

    .login-card {
        padding: 26px;
    }
}

/* ── Desktop-only page stub ──
   Rendered into #content by navigate()'s mobileBlocked branch for /prices and
   /admin. Outside the media query since it's only ever inserted on a phone
   anyway; harmless if a viewport-resize leaves it on screen. */
.mobile-unavailable {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 12px;
    padding: 48px 28px;
}

.mobile-unavailable-icon {
    font-size: 2.4rem;
}

.mobile-unavailable-title {
    font-size: 1.15rem;
    font-weight: 600;
    line-height: 1.35;
}

.mobile-unavailable-text {
    color: var(--text-muted);
    font-size: 0.9rem;
    max-width: 320px;
    line-height: 1.5;
}

.mobile-unavailable-home {
    margin-top: 8px;
    padding: 10px 22px;
    font-size: 0.85rem;
    text-decoration: none;
}
