/* =============================================================================
 * desktop.css — GhosterDex on a pointer and a big screen.
 *
 * Ships inside the mini app bundle. EVERY rule lives inside a min-width query,
 * so below the breakpoint this file contributes nothing and Telegram and the
 * Android app are untouched. That is enforced, not trusted:
 * `check-desktop-css.mjs` in the Ghosterdex Desktop workspace fails the sync if
 * any rule escapes one.
 *
 * There are no .tsx changes anywhere and there should not be. Everything the
 * shell positions is positioned in CSS, and the nav is already `position:
 * fixed`, so a full desktop layout is a restyle rather than a restructure.
 *
 * THREE RULES FOR EDITING THIS FILE
 *
 * 1. Prefix overrides with `body`, or reach the element through
 *    `.shell:has(> nav.bottom-nav)`. styles.css is imported from main.tsx
 *    rather than linked, so Vite emits it AFTER this file — source order is not
 *    ours to rely on and specificity has to do the work. Never @layer:
 *    unlayered styles beat layered ones, so this file would always lose.
 *
 * 2. There are four stylesheets. index.html loads ghost-lens.css,
 *    perps-pro.css and fund-pro.css before the bundle. ghost-lens.css
 *    re-declares the nav as `.bottom-nav.bottom-nav` — (0,2,0) — which beats
 *    `body nav.bottom-nav` (0,1,2), because class count is compared before
 *    element count. If a rule here half-works, suspect specificity before
 *    touching the declarations: the subset of properties the rival does not set
 *    still applies, which looks like a broken layout rather than a lost cascade.
 *
 * 3. `--gl-*` variables are scoped to ghost-lens's `.gl` container, not :root.
 *    An undefined var invalidates the whole declaration at computed-value time
 *    rather than falling back, so give each one a literal fallback.
 *
 * A corollary of (1): a :root block cannot take a `body` prefix, because :root
 * IS <html>. Use `:root:root`.
 * ========================================================================== */

@media (min-width: 1000px) {
  :root:root {
    /* The sidebar, and the content column beside it. */
    --gd-side: 284px;
    --gd-col: 880px;

    /* Sidebar surface. One step up from the page so the app reads as two
       planes rather than one flat field — the thing that most separates a
       desktop app from a phone screen stretched wide. */
    --gd-side-bg: color-mix(in srgb, var(--bg-elev) 82%, var(--bg));
    --gd-side-line: color-mix(in srgb, var(--ink) 9%, transparent);

    /* Upstream reserves --nav-h (84px) at the bottom edge for the floating nav,
       and fourteen rules read it: page and docs padding, the deposit wizard,
       .perps, .gifts/.gram, both gift FABs, .batch-bar, .perp-flash, the dock.
       The nav is a sidebar now, so collapsing the token reclaims that band
       everywhere at once instead of overriding fourteen rules and missing the
       fifteenth upstream adds next. */
    --nav-h: 12px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE SHELL
   *
   * Scoped to `.shell:has(> nav.bottom-nav)` — only when the app proper is on
   * screen. App.tsx drops the nav entirely while the wallet gate is up, and the
   * gate wants a centred screen with no sidebar at all, not a sidebar with one
   * item missing.
   * ══════════════════════════════════════════════════════════════════════ */

  body .shell {
    max-width: none;
    margin: 0;
  }

  body .shell:has(> nav.bottom-nav) {
    padding-left: var(--gd-side);
  }

  /* The sidebar's surface, drawn as one continuous plane behind both the brand
     header and the nav. Those are two separate elements in the DOM — .topbar is
     the shell's first child, the nav is its last — and no CSS can put them in a
     shared box. A fixed pseudo-element behind both is what makes them read as
     one panel, and it costs no markup. */
  body .shell:has(> nav.bottom-nav)::before {
    content: '';
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--gd-side);
    z-index: 29;
    background: var(--gd-side-bg);
    border-right: 1px solid var(--gd-side-line);
    pointer-events: none;
  }

  /* ── brand header ──────────────────────────────────────────────────────── */

  /* Lifted out of the content column into the top of the sidebar, where a
     desktop app's mark belongs. Same fixed treatment as the nav below it, and
     the two share the pseudo-element's surface. */
  body .shell:has(> nav.bottom-nav) > .topbar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 31;
    width: var(--gd-side);
    height: 74px;
    padding: 0 18px;
    border-bottom: 1px solid var(--gd-side-line);
  }

  body .shell:has(> nav.bottom-nav) > .topbar .brand-logo {
    width: 32px;
    height: 32px;
    border-radius: 10px;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .brand-name {
    font-size: 19px;
    letter-spacing: 0.2px;
  }

  /* ── the nav, from floating capsule to sidebar list ────────────────────── */

  /* The capsule's own chrome — glass fill, blur, border, 24px radius, drop
     shadow — all belonged to something floating over content. Sitting on the
     sidebar's surface it has nothing to float above, and keeping the shadow
     would draw a seam down the middle of a flat panel. */
  body .shell:has(> nav.bottom-nav) > nav.bottom-nav {
    top: 74px;
    right: auto;
    bottom: 0;
    left: 0;
    transform: none;
    width: var(--gd-side);
    max-width: none;
    height: auto;
    z-index: 30;
    padding: 14px 12px;
    margin-bottom: 0;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;

    /* One column of content-height rows, not five equal columns dividing a
       fixed 68px. */
    grid-template-columns: 1fr;
    grid-auto-rows: max-content;
    align-content: start;
    gap: 2px;
  }

  /* The sidebar gives the labels their size back: they were squeezed to 10.5px
     to fit five across a phone, and there is no reason to whisper here. */
  body .shell:has(> nav.bottom-nav) .nav-item {
    flex-direction: row;
    justify-content: flex-start;
    gap: 13px;
    height: 46px;
    padding: 0 14px;
    font-size: 14.5px;
    font-weight: 600;
    letter-spacing: 0.1px;
    border-radius: 12px;
    text-align: left;
    color: var(--text-dim);
    transition: background 0.16s, color 0.16s;
  }

  body .shell:has(> nav.bottom-nav) .nav-item svg {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
  }

  body .shell:has(> nav.bottom-nav) .nav-item.on {
    color: var(--text);
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    box-shadow: none;
  }

  /* The active marker was a lit dash under a centred label. Upright it becomes
     a bar down the leading edge — the same signal, read the way a vertical list
     is read. */
  body .shell:has(> nav.bottom-nav) .nav-item::before {
    top: 50%;
    bottom: auto;
    left: 0;
    margin-left: 0;
    width: 3px;
    height: 18px;
    border-radius: 0 3px 3px 0;
    transform: translateY(-50%) scaleY(0);
  }
  body .shell:has(> nav.bottom-nav) .nav-item.on::before {
    transform: translateY(-50%) scaleY(1);
  }

  body .shell:has(> nav.bottom-nav) .nav-item .nav-ic {
    display: inline-flex;
    position: relative;
    flex-shrink: 0;
  }

  /* ── content column ────────────────────────────────────────────────────── */

  /* Named rather than matched with a :not() chain, so a new child upstream
     lands in the flow at full width and is obvious, instead of silently
     inheriting a column width that may be wrong for it. */
  body .shell:has(> nav.bottom-nav) > .page,
  body .shell:has(> nav.bottom-nav) > .docs,
  body .shell:has(> nav.bottom-nav) > .net-alert,
  body .shell:has(> nav.bottom-nav) > .error-note {
    width: min(var(--gd-col), 100%);
    margin-inline: auto;
  }

  body .shell:has(> nav.bottom-nav) > .page {
    padding: 30px 28px 72px;
  }
  body .shell:has(> nav.bottom-nav) > .net-alert {
    margin-top: 22px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * SCREEN CONTENT
   *
   * The column is 880px, up from 480. Rows widen gracefully because they are
   * flex — icon, meta, value — the same shape a desktop wallet's balance list
   * has anyway. What does NOT widen gracefully is anything that was a
   * full-width block only because a phone had no other option.
   * ══════════════════════════════════════════════════════════════════════ */

  /* The balance card is the page's hero and earns the width. */
  body .shell:has(> nav.bottom-nav) .vault-card {
    padding: 30px 32px 32px;
    border-radius: 24px;
  }

  /* Three actions stretched across 880px would be three 280px squares with a
     22px icon adrift in each. They stay tile-sized and sit left, where the eye
     already is after reading the balance above them. */
  body .shell:has(> nav.bottom-nav) .actions-row {
    grid-auto-columns: 152px;
    justify-content: start;
    gap: 12px;
    margin-bottom: 32px;
  }

  body .shell:has(> nav.bottom-nav) .asset-list {
    border-radius: 20px;
    padding: 6px 20px;
  }
  body .shell:has(> nav.bottom-nav) .asset-row {
    padding: 15px 4px;
  }

  /* Prose keeps a reading measure. An 880px line of body copy is not a wider
     paragraph, it is a harder one to read. */
  body .shell:has(> nav.bottom-nav) .docs-hero p,
  body .shell:has(> nav.bottom-nav) .perp-foot,
  body .shell:has(> nav.bottom-nav) .star-hero p {
    max-width: 62ch;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * BOTTOM-FIXED FURNITURE
   *
   * A family of elements pins itself to the bottom edge and centres with
   * `left: 50%` — the gifts batch bar and the perps toast. Centred on the
   * viewport they now sit half a sidebar left of the content they belong to,
   * which reads as a misplaced element rather than a deliberate one.
   * ══════════════════════════════════════════════════════════════════════ */

  body:has(.shell > nav.bottom-nav) .batch-bar,
  body:has(.shell > nav.bottom-nav) .perp-flash {
    left: calc(50% + var(--gd-side) / 2);
  }

  /* The dock is NOT centred with `left: 50%` like those two — it brackets
     itself with `left: 16px; right: 16px; margin: 0 auto`. So it takes edges,
     not a shifted centre. Setting `left` alone would pin its left edge to the
     column's centre and run it off the right of the screen.

     It stays a bottom-centred bar rather than moving to a corner: upstream
     already ships a `body.dock-active` rule that lifts the gift FABs clear of
     it, written for a dock that is centred and bottom-anchored. A corner move
     would land it on .gift-fab and break an existing collision fix instead of
     inheriting it. */
  body:has(.shell > nav.bottom-nav) .dock {
    left: calc(var(--gd-side) + 24px);
    right: 24px;
    max-width: 520px;
    margin-inline: auto;
  }

  /* The gift FABs pin to the viewport's right edge, which on a wide screen
     strands them hundreds of pixels from the column they act on. */
  body:has(.shell > nav.bottom-nav) .gift-fab {
    right: max(24px, calc(50% - var(--gd-col) / 2 + var(--gd-side) / 2 - 62px));
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * SHEETS → CENTRED MODALS
   * ══════════════════════════════════════════════════════════════════════ */

  /* A panel rising from the bottom edge is a thumb-reach affordance. On a
     1440px-tall display it puts the controls most of a metre from the click
     that opened them. */
  body .sheet {
    top: 50%;
    bottom: auto;
    left: 50%;
    transform: translate(-50%, -50%);
    max-width: 540px;
    max-height: 82vh;
    border-radius: 24px;
    border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
    padding: 22px 24px 24px;
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.72);
    animation: gdSheetIn 0.24s cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* Upstream's sheetUp keyframe animates translate(-50%, 42%) → (-50%, 0),
     which assumes the sheet is only centred horizontally. Reusing it would
     fight the vertical centring and drop the panel half off-screen. */
  @keyframes gdSheetIn {
    from { transform: translate(-50%, calc(-50% + 10px)); opacity: 0; }
    to   { transform: translate(-50%, -50%); opacity: 1; }
  }

  /* "Drag me down to dismiss", with nothing to drag and no such gesture. */
  body .sheet-grab {
    display: none;
  }

  /* ghost-lens.css ships a second family of sheets for the perps and lens
     screens — its own section header calls them "sheets, matching the app's
     own". They are: a fixed flex container with `align-items: flex-end` holding
     a card with a top-only radius. Same treatment, or the app centres one kind
     of modal and slides the other up off the floor.

     These centre more simply than .sheet: the container does it with flex, so
     the card needs no transform and its slide-up keyframe (ending at
     translateY(0)) stays correct as written. */
  body .gl-float,
  body .gl-sheet {
    align-items: center;
  }
  body .gl-float-card,
  body .gl-card {
    max-width: 540px;
    border-radius: var(--gl-radius-lg, var(--radius-lg, 24px));
    border: 1px solid var(--gl-edge-soft, var(--stroke-soft, rgba(255, 255, 255, 0.06)));
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.72);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * POINTER AND KEYBOARD
   * ══════════════════════════════════════════════════════════════════════ */

  /* Upstream hides every scrollbar (`::-webkit-scrollbar { width: 0 }`), which
     is right on touch — content moves under your finger and a bar is clutter.
     With a mouse it removes both the only sign that a list continues below the
     fold and the only thing you can drag to get there. */
  body ::-webkit-scrollbar {
    width: 11px;
    height: 11px;
  }
  body ::-webkit-scrollbar-track {
    background: transparent;
  }
  body ::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--ink) 13%, transparent);
    border: 3px solid transparent;
    background-clip: content-box;
    border-radius: 999px;
  }
  body ::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--ink) 26%, transparent);
    background-clip: content-box;
  }
  body {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--ink) 15%, transparent) transparent;
  }

  /* The mini app ships no focus styling, which costs nothing on a touchscreen
     because there is no keyboard focus to show. On desktop, Tab is how a
     screen-reader or motor-impaired user reaches the wallet button and every
     nav row, and with no ring the focus position is invisible. :focus-visible,
     so a mouse click never draws one. */
  body :focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 62%, transparent);
    outline-offset: 2px;
    border-radius: 10px;
  }

  @media (hover: hover) {
    body .shell:has(> nav.bottom-nav) .nav-item:not(.on):hover {
      color: var(--text);
      background: color-mix(in srgb, var(--ink) 5%, transparent);
    }
    body .sheet-close:hover {
      color: var(--text);
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
    }
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * PERPS — a terminal, not a tall phone screen
   *
   * On a phone this screen time-shares one column: a `.pp-modes` toggle swaps
   * between the chart and the order ticket, because both cannot fit. A desktop
   * has room for the chart, the book and the ticket at once, which is the whole
   * reason a trading terminal looks the way it does — you watch the book while
   * you set the order.
   *
   * Specificity note: several rules here carry `.pp-root.pp-root`. Upstream
   * addresses this screen as `.pp-root.pp-mode-chart .pp-body` (0,3,0), so
   * `body .pp-body` (0,1,1) loses in chart mode and the layout would apply in
   * one mode and not the other. The doubled class is the same idiom
   * ghost-lens.css already uses for the nav.
   * ══════════════════════════════════════════════════════════════════════ */

  /* .gl-screen is `position: fixed; inset: 0`, so the terminal covers the
     sidebar and the only way out is its own back button. Inset it by the
     sidebar: the nav stays reachable and the app stays one place. */
  body:has(.shell > nav.bottom-nav) .gl-screen {
    left: var(--gd-side);
  }

  /* ── the instrument bar ────────────────────────────────────────────────── */

  /* The stats sit in a two-column label/value grid pushed to the far right by
     `margin-left: auto`. Across 1400px that leaves the price at one end of the
     bar and three 10.5px numbers at the other, with a metre of nothing between
     — the emptiest thing on the screen.

     Column flow turns the same alternating spans into a row of label-over-value
     pairs beside the price. No markup changes: the spans already alternate
     label, value, label, value, so filling column-first across two rows lands
     each pair in its own column. That is the shape every terminal's instrument
     bar has, and why Bybit can show eight stats without it reading as clutter. */
  body .pp-strip {
    align-items: center;
    gap: 0;
    padding: 0 22px 12px;
  }
  body .pp-stats {
    margin-left: 46px;
    margin-right: auto;
    grid-template-columns: none;
    grid-template-rows: auto auto;
    grid-auto-flow: column;
    gap: 3px 36px;
    font-size: 11px;
  }
  /* Values were right-aligned to sit under a label in a two-column grid. In
     their own column they align left, under their own label. */
  body .pp-stats span:nth-child(even) {
    text-align: left;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--gl-market, var(--text));
  }
  body .pp-last .pp-big {
    font-size: 34px;
  }

  /* The chart/ticket toggle answers a question a desktop does not ask. */
  body .pp-head .pp-modes {
    display: none;
  }

  /* ── the terminal grid ─────────────────────────────────────────────────── */

  /* `.pp-split` holds the ticket and the book as a 57/43 pair. `display:
     contents` dissolves that box so both become items of the body's own grid,
     which is what lets the chart sit beside them as a third column instead of
     stacked above. It is the one thing that makes this layout reachable from
     CSS at all.

     Every cell is named, so the screen's other children — .pp-drawbarstrip,
     .pp-chartpane, .pp-quick, all zero-sized in this mode — auto-place into
     implicit rows below and contribute nothing. */
  body .pp-root.pp-root .pp-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px 344px;
    grid-template-rows: minmax(280px, 1fr) auto auto;
    grid-template-areas:
      'chart book form'
      'tabs  tabs form'
      'pos   pos  form';
    gap: 10px 12px;
    padding: 0 22px 18px;
    overflow: hidden;
  }

  /* The two !important declarations in this file, and the only place they are
     correct: perps-pro.js writes `display` INLINE on both of these elements —
     `display: grid` on the split, `display: none` on the chart, because on a
     phone the mode toggle shows one or the other. An inline style outranks
     every stylesheet rule regardless of specificity, so this is not a cascade
     shortcut, it is the only instrument that reaches them.

     The toggle that would fight back is hidden above, so the JS never
     re-asserts a mode after load. */
  body .pp-root.pp-root .pp-body > .pp-chartwrap {
    grid-area: chart;
    display: block !important;
  }
  body .pp-root.pp-root .pp-body > .pp-split {
    display: contents !important;
  }
  body .pp-root.pp-root .pp-split > .pp-right { grid-area: book; }
  body .pp-root.pp-root .pp-split > .pp-form { grid-area: form; }
  body .pp-root.pp-root .pp-body > .pp-tabs { grid-area: tabs; }
  body .pp-root.pp-root .pp-body > .pp-positions { grid-area: pos; }

  /* Book mode caps the chart at a 190px strip so the price stays in sight
     above the ticket. Side by side there is nothing to make room for, and the
     chart should take the height the grid gives it. */
  body .pp-root.pp-compactchart .pp-chartwrap {
    height: auto;
    min-height: 0;
    flex: initial;
    overflow: hidden;
  }

  /* Three columns of different natural heights, each scrolling on its own
     rather than the page scrolling all of them. */
  body .pp-root.pp-root .pp-split > .pp-form,
  body .pp-root.pp-root .pp-split > .pp-right {
    min-height: 0;
    max-height: none;
    overflow-y: auto;
    overflow-x: hidden;
  }

  /* The positions table is the one place a wide screen pays off for free:
     more rows visible without scrolling. */
  body .pp-root.pp-root .pp-body > .pp-positions {
    min-height: 0;
    overflow-y: auto;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE GATE
   *
   * The one view with no sidebar, so it centres on the viewport. Upstream pins
   * its CTA to the bottom edge because that is where a thumb rests; on desktop
   * that is simply a long way from the sentence it answers.
   * ══════════════════════════════════════════════════════════════════════ */

  body .gate {
    justify-content: center;
    gap: 34px;
    padding-bottom: 60px;
  }
  body .gate-cta {
    max-width: 340px;
    margin: 0 auto;
  }
}

/* Wide desktops. A small step: past this the balance rows start to hollow out,
   a symbol on the far left and a number on the far right with nothing between,
   and width stops being the same thing as density. */
@media (min-width: 1600px) {
  :root:root {
    --gd-col: 960px;
  }
}
