/* =============================================================================
 * 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, .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);

    /* How tall the sidebar's header is, read by the header itself and by the
       nav that starts under it, so the two can never drift apart. One row for
       the mark alone; two when the wallet switch is on screen, which is the
       only thing that does not fit beside a 21px wordmark in 284px. */
    --gd-head: 64px;
  }
  body .shell:has(> nav.bottom-nav):has(> .topbar .wsw) {
    --gd-head: 128px;
  }

  /* 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: var(--gd-head);
    padding: 0 18px;
    border-bottom: 1px solid var(--gd-side-line);
  }

  /* ── the wallet header ─────────────────────────────────────────────────── */

  /* The mark and the wallet controls were sharing one 284px row with
     `space-between`, so the switch and the wallets button were pressed against
     the sidebar's edge and spilled past it. They are two different jobs
     anyway: the mark says which app this is, the row under it says which
     wallet you are in. Stacking them gives each a full row, and gives the
     switch enough width to say what it is switching between. */
  body .shell:has(> nav.bottom-nav) > .topbar:has(.wsw) {
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: 12px;
    padding: 0 16px;
  }
  body .shell:has(> nav.bottom-nav) > .topbar:has(.wsw) .topbar-actions {
    width: 100%;
    gap: 8px;
  }

  /* Two glyphs are all a phone's topbar can spare; here the switch spans the
     sidebar and each half is named, so the choice reads without being learnt.
     The knob is half the track less its inset, which makes translateX(100%)
     land it exactly on the far edge. */
  body .shell:has(> nav.bottom-nav) > .topbar .wsw {
    display: grid;
    grid-template-columns: 1fr 1fr;
    flex: 1;
    min-width: 0;
    height: 40px;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .wsw-side {
    width: auto;
    height: auto;
    gap: 7px;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .wsw-side i {
    display: inline;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .wsw-knob {
    width: calc(50% - 3px);
    height: calc(100% - 6px);
  }
  body .shell:has(> nav.bottom-nav) > .topbar .wsw.public .wsw-knob {
    transform: translateX(100%);
  }
  body .shell:has(> nav.bottom-nav) > .topbar .icon-btn {
    width: 40px;
    height: 40px;
    flex: none;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .st-dot-btn {
    width: 22px;
    height: 40px;
    flex: none;
  }

  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;
  }

  /* A phone's header names the wallet in this corner (.brand.you in
     styles.css). The sidebar is where the app's own mark belongs, so here the
     corner wears the wordmark again and the wallets button comes back beside
     the switch. */
  body .shell:has(> nav.bottom-nav) > .topbar .brand.you {
    margin: 0;
    padding: 0;
    gap: 11px;
    border-radius: 0;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .brand.you:active {
    transform: none;
    background: none;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .brand.you .brand-name {
    display: inline;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .you-meta,
  body .shell:has(> nav.bottom-nav) > .topbar .you-ring {
    display: none;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .you-face {
    width: auto;
    height: auto;
  }
  body .shell:has(> nav.bottom-nav) > .topbar .icon-btn.wallets {
    display: flex;
  }

  /* ── 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: var(--gd-head);
    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;

    /* Flex column, not the capsule's 5-equal-columns grid: flex is what lets
       `margin-top: auto` below pin the last item to the sidebar's foot, the
       way near.com pins Account. ghost-lens's `.bottom-nav.bottom-nav` grid
       declaration loses to this selector's specificity. */
    display: flex;
    flex-direction: column;
    gap: 2px;
  }

  /* The travelling tile is a five-across idea. Upright, the rows are a list
     and the active one is marked in place, so the light does not travel here. */
  body .shell:has(> nav.bottom-nav) .nav-glide {
    display: none;
  }
  body .shell:has(> nav.bottom-nav) .nav-item.on svg {
    transform: none;
  }

  /* Menu is the sidebar's "account corner": it opens identity, settings and
     docs, which is exactly what lives at the bottom of every desktop app's
     sidebar. Pinning it also stops the five items floating as an island in an
     800px-tall panel — four nav rows read from the top, utilities read from
     the floor. */
  body .shell:has(> nav.bottom-nav) .nav-item:last-child {
    margin-top: auto;
    position: relative;
  }
  body .shell:has(> nav.bottom-nav) .nav-item:last-child::after {
    content: '';
    position: absolute;
    top: -8px;
    left: 2px;
    right: 2px;
    height: 1px;
    background: var(--gd-side-line);
  }

  /* Your Telegram handle, standing in the sidebar where you can set or clear it
     at any time — Gram Zone delivers to it, so it belongs in view rather than
     two taps inside a menu. Hidden on phones (styles.css) where the nav is
     already full, and absent inside Telegram, so the footer pinning has to move
     WITH it: whichever of the two starts the footer cluster carries the auto
     margin and the divider. The :has() test keeps that correct in both cases
     instead of assuming the row is always there. */
  body .shell:has(> nav.bottom-nav) .nav-item.nav-tg {
    display: flex;
    margin-top: auto;
    position: relative;
    overflow: hidden;
  }
  body .shell:has(> nav.bottom-nav) .nav-item.nav-tg::after {
    content: '';
    position: absolute;
    top: -8px;
    left: 2px;
    right: 2px;
    height: 1px;
    background: var(--gd-side-line);
  }
  /* Menu stops being the start of the cluster once the handle row is above it. */
  body .shell:has(> nav.bottom-nav) nav.bottom-nav:has(> .nav-tg) .nav-item:last-child {
    margin-top: 0;
  }
  body .shell:has(> nav.bottom-nav) nav.bottom-nav:has(> .nav-tg) .nav-item:last-child::after {
    display: none;
  }

  /* 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.

     `.trade-page` is on the list because Trade does not put its .page directly
     under the shell — the chain there is `.shell > .trade-page > .page`, the
     wrapper holding the Swap|Perps toggle. Any rule keyed on `> .page` misses
     that whole tab silently, which is why the .page rules below match at any
     depth instead: there is only ever one .page mounted. */
  body .shell:has(> nav.bottom-nav) > .page,
  body .shell:has(> nav.bottom-nav) > .trade-page,
  body .shell:has(> nav.bottom-nav) > .docs,
  body .shell:has(> nav.bottom-nav) > .error-note {
    width: min(var(--gd-col), 100%);
    margin-inline: auto;
  }

  body .shell:has(> nav.bottom-nav) .page {
    width: min(var(--gd-col), 100%);
    margin-inline: auto;
    padding: 30px 28px 72px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * 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.
   * ══════════════════════════════════════════════════════════════════════ */

  /* ── home: hero balance + quick-action rail ────────────────────────────── */

  /* near.com's home puts the balance at the top left and the actions beside
     it, not under it — the two things you came for, on one eye-line. The DOM
     is vault-card THEN actions-row, stacked; a grid on the page re-seats them
     side by side without touching markup.

     The `> * { 1 / -1 }` default is the safety net: any child this rule does
     not name — notices, the external-funds card, whatever upstream adds next —
     spans the full width in source order instead of being scattered by
     auto-placement. */
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 236px;
    gap: 16px 18px;
    align-content: start;
  }
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) > * {
    grid-column: 1 / -1;
  }
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) > .vault-card {
    grid-column: 1;
    grid-row: 1;
    /* all sides: upstream's phone margin-top otherwise sinks the hero 14px
       below the action rail sharing its grid row */
    margin: 0;
    padding: 34px 38px 36px;
    border-radius: 26px;
  }

  /* The phantom watermark was sized for a 440px card; on a 570px hero it was
     a smudge in the corner. Scaled with the card, it is the thing that makes
     the vault read as an object rather than a rectangle with a number in it. */
  body .shell:has(> nav.bottom-nav) .vault-card::after {
    width: 220px;
    height: 220px;
    right: -28px;
    bottom: -44px;
  }
  body .shell:has(> nav.bottom-nav) .vault-sub {
    margin-top: 12px;
  }
  body .shell:has(> nav.bottom-nav) .shield-tag {
    font-size: 13px;
  }

  /* The three tiles become a vertical rail of pills filling the hero's height.
     Row 1 explicitly: auto-placement would land them there anyway, but only
     while vault-card stays the first child, and that is not a fact worth
     leaning on. */
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) > .actions-row {
    grid-column: 2;
    grid-row: 1;
    grid-auto-flow: row;
    grid-auto-columns: initial;
    /* however many tiles there are (four since Earn), sharing the hero's height */
    grid-template-rows: none;
    grid-auto-rows: 1fr;
    gap: 10px;
    margin-bottom: 0;
  }
  /* Scoped to the RAIL, and the scope is the whole point.
     `.actions-row .action-tile` also matches the asset-detail sheet, which
     renders the same markup inline inside .shell (Sheet.tsx does not portal).
     There the tiles sit side by side and wide, so row-direction + flex-start +
     zero vertical padding produced a 233x42 capsule holding a 40px circle with
     ONE pixel of clearance, radius 24px on a 42px box, and ~116px of dead space
     after the label. Measured on production 2026-08-06; reported as
     "this design does not look good".
     The `> .actions-row` child combinator is what excludes the sheet: the rail
     is a direct child of .page, the sheet's row is nested inside .sheet-body. */
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) > .actions-row .action-tile {
    flex-direction: row;
    justify-content: flex-start;
    gap: 13px;
    padding: 0 16px;
    font-size: 14px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) > .actions-row .action-tile .bubble {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
  }

  /* Sheet tiles keep the shape they were designed for — bubble centred above a
     centred label — and only grow into the space a 540px modal gives them. A
     13px label and phone-sized padding read as a screenshot of a phone when the
     dialog is this wide. */
  body .shell:has(> nav.bottom-nav) .sheet .actions-row .action-tile {
    padding: 20px 10px 17px;
    gap: 11px;
    font-size: 14px;
    border-radius: 20px;
  }
  body .shell:has(> nav.bottom-nav) .sheet .actions-row .action-tile .bubble {
    width: 48px;
    height: 48px;
  }

  /* The number is the point of the screen, and 880px of hero can carry more
     than a phone's 46px. */
  body .shell:has(> nav.bottom-nav) .balance-value {
    font-size: 56px;
    letter-spacing: -1.8px;
  }

  /* The asset list is the desktop table it always wanted to be: taller rows,
     larger identity, and the extra width spent on breathing room rather than
     stretching the same 42px of icon across more emptiness. */
  body .shell:has(> nav.bottom-nav) .asset-list {
    border-radius: 20px;
    padding: 8px 22px;
  }
  body .shell:has(> nav.bottom-nav) .asset-row {
    padding: 16px 6px;
    gap: 15px;
  }
  body .shell:has(> nav.bottom-nav) .asset-row .token-icon {
    width: 46px;
    height: 46px;
  }
  body .shell:has(> nav.bottom-nav) .asset-row .sym {
    font-size: 15.5px;
  }
  body .shell:has(> nav.bottom-nav) .asset-row .name {
    font-size: 13px;
  }
  body .shell:has(> nav.bottom-nav) .section-title {
    font-size: 12.5px;
    letter-spacing: 2px;
    margin: 12px 2px 12px;
  }

  /* ── task screens: one column, centred, task-width ─────────────────────────
     near.com renders Swap as a ~500px card in the middle of the screen and it
     is the right call: a swap, a deposit wizard, a withdrawal form are single
     tasks, and spreading their inputs across 880px does not add information,
     it adds mouse travel. Each page is recognised by a class only that screen
     renders. The width override needs the full shell prefix because the
     generic `> .page` rule above sets width at (0,3,2) — one more :has() wins
     the tie. */
  body .shell:has(> nav.bottom-nav) .page:has(.stepper),
  body .shell:has(> nav.bottom-nav) .page.xfer {
    width: min(600px, 100%);
  }


  /* ── gram zone (Explore): the hub's grid ───────────────────────────────────
     The hub is a heading and three .gzc sections, each spanning the grid by
     the safety net below. The two columns are used by the Explore snippet at
     the end of this file, which seats the AI section beside the coming-soon
     one from 1200px. */
  body .shell:has(> nav.bottom-nav) .page.gram {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 14px;
    align-content: start;
  }
  body .shell:has(> nav.bottom-nav) .page.gram > * {
    grid-column: 1 / -1;
  }

  /* The filter strips lose their phone scroller, for the same reason the Stars
     preset chips did: a desktop shows the options, it does not ask you to swipe
     to discover them. Both carry `no-scrollbar`, so what overflows here leaves
     NO trace — no bar, no cue, nothing cut off mid-pill to hint there is more.

     `.gf-active` is the sharp end: those pills are the only per-filter remove
     control (the alternative is "Clear all", which throws away every filter),
     the cap is 200 collections, and one "select all shown" tap can add dozens.
     Measured with active-state labels: at 1440px the 880px column hides a pill
     from 8 filters on, 5 of 12, 8 of 15; at 1000px, 10 of 15 — and the strip
     scrolls only via a wheel gesture nothing on screen suggests exists.
     `.gf-bar` is tighter than it looks too: its seven chips fit while idle, but
     the active labels ("Collections 12", "2.5-150 TON", "#437391") push it
     188px over at 1000px, taking Price and Gift ID off the end.

     Wrapping costs one or two rows of height, which a desktop has, and makes
     every filter clickable again. Verified at 1000px and 1440px: zero chips or
     pills offscreen at 15 active filters. */
  body .shell:has(> nav.bottom-nav) .gf-bar,
  body .shell:has(> nav.bottom-nav) .gf-active {
    flex-wrap: wrap;
    overflow-x: visible;
  }

  /* ── stars & premium ─────────────────────────────────────────────────────
     The checkouts' desktop layout is the Explore snippet's "STARS AND
     PREMIUM, AS A CHECKOUT" at the end of this file; the old rules here were
     written for markup that no longer exists. What stays: the page width the
     purchase-done screen and Agents start from, the recipient field and the
     button and fine print at checkout size. */
  body .shell:has(> nav.bottom-nav) .page.gz-prod {
    width: min(560px, 100%);
  }
  body .shell:has(> nav.bottom-nav) .rc-input input {
    padding: 15px 4px;
    font-size: 15.5px;
  }
  body .shell:has(> nav.bottom-nav) .page.gz-prod .cta {
    padding: 16px;
    font-size: 15.5px;
  }
  body .shell:has(> nav.bottom-nav) .gz-fineprint {
    font-size: 11.5px;
    margin-top: 12px;
  }

  /* 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 {
    max-width: 62ch;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * BOTTOM-FIXED FURNITURE
   *
   * A family of elements pins itself to the bottom edge and centres with
   * `left: 50%` — the gifts cart toast 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) .perp-flash,
  /* The one Gram Zone mounts. Missed on the first pass, so the "cart holds up
     to 200 gifts" toast landed 142px
     (--gd-side/2) left of the column at every width. Only `left` moves, so the
     translateX(-50%) and the cartToastIn keyframe's translate(-50%, 6px) both
     stay correct. */
  body:has(.shell > nav.bottom-nav) .cart-full-toast {
    left: calc(50% + var(--gd-side) / 2);
  }

  /* ── the activity dock lives in the sidebar ────────────────────────────────
   *
   * On a phone it is a floating puck in the thumb corner, because there is
   * nowhere else for it. The desktop sidebar has a column of dead space under
   * Activity — the owner circled it — and a progress card belongs beside the
   * tab it reports on, not hovering over the content in the far corner.
   *
   * Placed by arithmetic rather than reparented, because moving it in the DOM
   * would change nothing about where a `position: fixed` element paints while
   * risking the phone: nav.bottom-nav carries a backdrop-filter at phone width,
   * which makes it a containing block for fixed descendants, and the floating
   * puck would have been trapped inside the 64px bar it is supposed to sit
   * above.
   *
   * The sum is the sidebar's own geometry, each term named so a change to any
   * of them is followed here: nav top (74) + nav padding (14) + four nav rows
   * (46 each) + the gaps between and after them (2 each). Home, Trade, Gram
   * Zone and Activity are the four; the handle row and Menu are pinned to the
   * floor by margin-top:auto and do not enter into it. */
  body:has(.shell > nav.bottom-nav) .dock,
  body:has(.shell > nav.bottom-nav) .dock-puck {
    /* Above the sidebar, not under it.
       The dock ships at z-index 28. The sidebar's background panel
       (.shell::before) is 29 and the nav itself is 30, so moving the dock into
       that column placed it correctly and painted it behind the panel: present
       in the DOM, right size, right offset, invisible. A getBoundingClientRect
       check cannot catch that; only asking what is actually on top can. */
    z-index: 31;
    /* Anchored from the FLOOR, just above the handle row, rather than pinned
       under Activity at the top of the gap.
       Both readings are "under Activity", but the footer is where the eye
       already goes for status and it keeps the card next to the identity it
       belongs to instead of stranded in the middle of an 800px column. Same
       terms as the nav's own geometry, counted upward: nav padding (14) +
       Menu (46) + gap (2) + handle row (46), then 10px of air. */
    top: auto;
    bottom: calc(14px + 46px + 2px + 46px + 10px);
    /* No max-height, and no scroll container.
       Both were defensive and both did harm. ActivityDock renders at most three
       cards (all.slice(0, 3)), about 200px in all. The ceiling could never bind
       on a normal window, while on a short one it squeezed the dock to a ~90px
       stub. Worse, `overflow-y: auto` made it a scroll box: the pending ring
       animates outside the icon's bounds, so the browser found overflow in both
       axes and drew two scrollbars around a clipped circle. A container sized
       by its own content needs neither. */
    left: 12px;
    right: auto;
    width: calc(var(--gd-side) - 24px);
    max-width: none;
    margin: 0;
    transform: none;
  }

  /* Full form, not a circle. The puck is a phone affordance: it shrinks the
     card so it stops covering the screen it is reporting on. In a column that
     has nothing else to show, shrinking hides progress to free space nobody
     wants — so the puck stretches into the same card shape and keeps its
     contents legible. ActivityDock also starts EXPANDED at this width (see its
     collapsed initialiser), so this is the state a reader normally sees. */
  body:has(.shell > nav.bottom-nav) .dock-puck {
    height: auto;
    min-height: 46px;
    border-radius: 12px;
    justify-content: flex-start;
    gap: 10px;
    padding: 0 14px;
  }


  /* ═══════════════════════════════════════════════════════════════════════
   * 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;
  }

  /* Above the perps terminal, not under it. The app's sheets are z 40/41 and
     the .gl-screen overlay is z 3000 — an ordering nothing on a phone could
     ever observe, because the full-screen terminal covered every button that
     opens a sheet. Desktop insets the terminal beside the sidebar, so the
     topbar wallet button stays clickable while it is open — and the sheet it
     opens landed BEHIND the terminal: a modal you could summon and never see.
     ghost-lens's own sheets sit at 3300 for exactly this reason; the app's
     join them there. */
  /* Backdrop and sheet share ONE z-index, deliberately.
     Sheets open from sheets here (Pay with, from the cart) and Sheet.tsx emits
     each as a bare backdrop+panel sibling pair, so the DOM runs
     backdrop1, sheet1, backdrop2, sheet2. Splitting them 3400/3401 put every
     backdrop below every sheet: the second backdrop dimmed nothing and left
     the cart's "Buy N privately" lit and clickable behind an open modal —
     invisible on a phone only because both panels sit on the bottom edge and
     the second physically covers the first, which centring undoes.
     Equal z-index hands the ordering to document order, which IS open order,
     so each pair stacks on the last for ANY depth rather than the two levels a
     sibling-selector chain can reach. Verified by hit-testing a point over
     sheet 1 and outside sheet 2: top element goes sheet1 -> backdrop2. */
  body .sheet-backdrop,
  body .sheet {
    z-index: 3401;
  }

  /* The gift-art viewer has to come up WITH that stack, not stay behind it.
     `.gd-zoom` is deliberately rendered outside the sheet (see styles.css) and
     cleared it on a phone at z 60 against the sheet's 41. Lifting the sheet
     stack to 3400/3401 for the perps terminal left the viewer under BOTH the
     sheet and its full-viewport backdrop: "View full size" opened a lightbox
     that could not be seen, and the click meant to dismiss it landed on the
     backdrop and closed the whole gift instead. One number above the stack.
     `body .gd-zoom` is (0,1,1) so it beats the base (0,1,0) — necessary,
     because Vite emits the bundled styles.css AFTER this file. */
  body .gd-zoom {
    z-index: 3500;
  }

  /* 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;
  }

  /* Focus, two registers — because the app has two kinds of focusable thing.

     Buttons, links, nav rows: a ring. Tab is how a screen-reader or
     motor-impaired user reaches them, and with no ring the position is
     invisible. :focus-visible so a mouse click never draws one. No
     border-radius here: setting it in a focus rule MUTATES the element's own
     radius for the focused moment, which is how every input briefly became a
     stadium-shaped pill.

     Text controls: no ring at all — the FIELD lights up instead. Every input
     in this app is chromeless inside a styled container, and upstream already
     wires the containers: .text-field/.xf-field/.search-box/.pp-field all
     brighten on :focus-within. A ring on the inner <input> double-draws inside
     an already-lit field, hugging the bare control instead of the box that
     visually IS the field. (:focus-visible matches text inputs on click, not
     just on Tab, so exclusion is the only clean way out.) The caret and the
     lit container carry the focus signal. */
  body :focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 62%, transparent);
    outline-offset: 2px;
  }
  body input:focus-visible,
  body textarea:focus-visible,
  body select:focus-visible {
    outline: none;
  }

  /* The container upstream never wired: the Stars and Premium recipient
     field. Same treatment as .text-field:focus-within, character for
     character: one focus language across the whole app. */
  body .rc-input:focus-within {
    border-color: color-mix(in srgb, var(--ink) 45%, transparent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink) 7%, transparent);
    transition: border-color 0.2s, box-shadow 0.2s;
  }

  /* A caret in the brand ink, not browser default — the smallest detail a
     focused field has, and the one you stare at while typing. */
  body input,
  body textarea {
    caret-color: var(--ink);
  }

  @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);
  }

  /* A terminal is not a document.
   *
   * Every label and number carried the text I-beam and was drag-selectable, so
   * a click on empty chrome left a caret sitting in the middle of the ticket
   * and a drag across the ladder painted it blue. Both are document behaviours
   * and neither reference terminal has them: you cannot accidentally select
   * Bybit's order book, because a book is a readout, not prose.
   *
   * Inputs opt straight back in — a price you cannot select is a price you
   * cannot correct — and buttons keep their pointer. Scoped to .pp-root so the
   * wallet screens are untouched, where selecting an address is the point. */
  body .pp-root {
    user-select: none;
    -webkit-user-select: none;
    cursor: default;
  }
  body .pp-root input,
  body .pp-root textarea {
    user-select: text;
    -webkit-user-select: text;
    cursor: text;
  }
  body .pp-root button {
    cursor: pointer;
  }

  /* The book's lean is stated twice — once under the Book/Trades tabs and
     again at the foot of the ladder, the same two numbers in two dressings.
     The foot is where both reference terminals put it, and in a column where
     furniture already claims more than half the height, a duplicate costs
     rows that the ladder needs. */
  body .pp-root .pp-right > .pp-ratio {
    display: none;
  }

  /* ── the ladder fills its column ───────────────────────────────────────────
   * The book must never scroll — that is the whole parity point, and a depth
   * ladder you have to scroll is a list.
   *
   * Doing it by arithmetic failed twice, and instructively. Summing the
   * furniture missed 68px of padding and flex gaps. Taking overhead as the
   * remainder (scrollHeight − rows) fixed that but could not grow back: once
   * the content FITS, scrollHeight equals clientHeight, so the leftover space
   * counts as overhead and the count is pinned at whatever it shrank to. The
   * pane was 264px inside a 439px column with 175px going spare.
   *
   * So: no arithmetic. The pane fills the column, the two ladders split what
   * is left in equal shares, and JS reads the height it was handed. flex-basis
   * 0 is what breaks the circularity — the container's height stops depending
   * on how many rows are in it. */
  body .pp-root .pp-right > .pp-book {
    flex: 1;
    min-height: 0;
  }

  /* ── the column carries BOTH halves ────────────────────────────────────────
   * The book says what people are willing to do; the tape says what they
   * actually did. A phone shows one at a time because it has room for one — a
   * 700px desktop column showing one wastes half of it, and every reference
   * terminal stacks them. So the tabs above stop being a switch here and the
   * lower half appears, carrying the tape and the movers list.
   *
   * 42% is the tape's share: enough for ~12 prints and the movers' chips plus
   * ten rows, while leaving the ladder the majority it needs to stay
   * unscrolled (see the flex-basis note above — the same reasoning applies to
   * this split, which is why it is a percentage of the column rather than a
   * pixel height that would fight the ladder for the remainder). */
  body .pp-root .pp-right > .pp-lower {
    display: flex;
    flex-direction: column;
    flex: 0 0 42%;
    min-height: 0;
    border-top: 1px solid var(--gd-side-line, rgba(255, 255, 255, 0.07));
    margin-top: 6px;
    padding-top: 2px;
  }
  /* The tape is no longer one of two tabs up top — it lives below now, so the
     switch that hid the book to show it would only blank half the column. */
  body .pp-root .pp-righttabs button[data-tab='tape'] {
    display: none;
  }
  body .pp-root .pp-lowertape,
  body .pp-root .pp-movers {
    flex: 1 1 0;
    min-height: 0;
    overflow: hidden;
  }
  body .pp-root .pp-lowertape { overflow-y: auto; }
  body .pp-root .pp-book > .pp-rows {
    flex: 1 1 0;
    min-height: 0;
    align-content: start;
    overflow: hidden;
  }

  /* ── three columns: Price · Size · Total ───────────────────────────────────
   * Both references carry the running total behind each level, and both align
   * the three as a table. Ours were flex/space-between, which lets each row
   * set its own column positions from its own text widths — fine for two
   * cells, visibly ragged with three.
   *
   * One grid, shared by the header and every row, so the columns line up by
   * construction. .pp-depth is absolutely positioned and so is not a grid
   * item — the bar keeps spanning the full row behind the numbers. */
  body .pp-root .pp-book > .pp-bookhead,
  body .pp-root .pp-book .pp-row {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    column-gap: 6px;
  }
  body .pp-root .pp-book > .pp-bookhead > span:nth-child(2),
  body .pp-root .pp-book .pp-row > .pp-sz {
    text-align: right;
  }
  body .pp-root .pp-book > .pp-bookhead > span:nth-child(3),
  body .pp-root .pp-book .pp-row > .pp-tot {
    text-align: right;
    color: var(--gl-market-dim, #8b95a3);
    font-variant-numeric: tabular-nums;
  }

  /* The mid/spread block is 49px of a column the ladder is short of. It states
     one price and one spread; both references give that a single row. */
  body .pp-root .pp-book > .pp-spread {
    padding: 2px;
    line-height: 1.25;
  }
  body .pp-root .pp-book > .pp-spread .pp-mid-px {
    font-size: 14.5px;
  }
  body .pp-root .pp-book > .pp-spread .pp-mid-sub {
    font-size: 10px;
  }

  /* ── the chrome above the body ─────────────────────────────────────────────
   * Every pixel here is a pixel the order book does not get, and the ladder is
   * what the reader came for. Ours spent 244px on five stacked bars where the
   * reference terminals spend roughly 135 — and the difference was showing up
   * as a ladder four levels deep instead of ten.
   *
   * Tightened, not removed: each bar still holds what it held. */
  body .pp-root .gl-head.pp-head {
    min-height: 0;
    padding-top: 6px;
    padding-bottom: 6px;
  }
  /* Folded into the strip by build(), so it is a flex item on the instrument
     bar rather than a row of its own. It keeps the symbol picker and the
     change chip; it loses only the line it used to sit on. */
  body .pp-strip > .pp-pairrow {
    flex: none;
    align-items: center;
    gap: 10px;
    padding: 0 14px 0 0;
    margin-right: 4px;
    border-right: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
  }
  body .pp-root .pp-charttabs {
    padding-top: 4px;
    padding-bottom: 0;
  }
  body .pp-root.pp-root .pp-tfs {
    padding-top: 4px;
    padding-bottom: 6px;
  }
  /* The Book/Trades switch sits above the ladder and is the last of the
     column's own furniture. */
  body .pp-root .pp-righttabs {
    padding-top: 0;
    padding-bottom: 0;
  }

  /* ── 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. */
  /* Grounded with a hairline: margin carries the 22px inset (not padding), so
     the rule stops where the content stops instead of running edge to edge. */
  body .pp-strip {
    align-items: center;
    gap: 0;
    margin: 0 22px 14px;
    padding: 0 0 14px;
    border-bottom: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
  }
  /* Mark and Oracle are columns of their own now, so the text line that
     repeated them under the price is a third copy of the same two numbers
     inside 400px. The node stays and keeps being written, so a window dragged
     below 1000px shows it already correct.

     Scoped through .pp-last on purpose: .pp-mark is ALSO the class on the
     drawn market badge, and `body .pp-mark` would blank every market logo. */
  body .pp-last .pp-mark {
    display: none;
  }

  /* Funding moved to the bar, where both references put it — and the order
     book gets the height back, which is what the ladder was short of. */
  body .pp-book > .pp-fund {
    display: none;
  }

  body .pp-stats {
    margin-left: 10px;
    margin-right: auto;
    grid-template-columns: none;
    grid-template-rows: auto auto;
    grid-auto-flow: column;
    gap: 2px 0;
    font-size: 11px;
    min-width: 0;
  }
  /* Bybit's bar separates each stat with a vertical rule. Label and value are
     two spans stacked in one grid column, so each carries a border-left and
     the pair reads as one divided cell — the 2px row gap nicks the line, which
     at hairline weight reads as intended, not broken.
     CHILD combinator: as a descendant this would also reach any span nested
     inside a label and draw a hairline mid-word. */
  body .pp-stats > span {
    border-left: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    padding: 0 14px;
  }
  /* Under column flow the first column is spans 1 AND 2 — resetting only
     :first-child leaves a stray rule beside the first value. */
  body .pp-stats > span:nth-child(-n + 2) {
    border-left: 0;
    padding-left: 0;
  }
  /* Hyperliquid's labels are dotted because they are hoverable definitions
     (the title comes from STAT_DEF). text-decoration, not border-bottom:
     these spans carry 14px of horizontal padding and a border paints across
     the padding box, so the rule would start 14px left of the first glyph. */
  body .pp-stats > span:nth-child(odd) {
    color: var(--gl-market-faint, #5f6873);
    text-decoration: underline dotted;
    text-decoration-color: var(--gl-edge, rgba(255, 255, 255, 0.14));
    text-underline-offset: 3px;
    text-decoration-skip-ink: none;
    cursor: help;
  }
  /* 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));
  }
  /* .pp-up/.pp-down are (0,1,0) and lose to the rule above, so change and
     funding — the two columns both references colour — would render neutral. */
  body .pp-stats > span:nth-child(even).pp-up {
    color: var(--gl-bid, #34e8a4);
  }
  body .pp-stats > span:nth-child(even).pp-down {
    color: var(--gl-ask, #ff5c7a);
  }
  body .pp-last .pp-big {
    font-size: 34px;
  }

  /* The chart/ticket toggle answers a question a desktop does not ask, in the
     top bar or in the pair row a venue switch moved it to (perps-pro.js
     placeVenues). */
  body .pp-head .pp-modes,
  body .pp-pairrow .pp-modes {
    display: none;
  }

  /* The venue switch spells its venues out, the way the app's own wallet
     switch does in the sidebar: there is room for the words here. */
  body .pp-venue-opt {
    width: auto;
    padding: 0 11px 0 5px;
  }
  body .pp-venue-opt i {
    display: inline;
  }

  /* Aster's account figures: three columns, since the ticket has the width. */
  body .pp-aster-acct {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  body .pp-aster-acct span {
    display: grid;
    gap: 3px;
    justify-items: center;
    text-align: center;
  }

  /* ── 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. */
  /* Chart-dominant, like every terminal that is taken seriously: the book
     needs two numbers and a depth bar, the ticket needs input width, and every
     remaining pixel belongs to the chart. Row gap is 0 because the vertical
     rhythm is done with margins on the chart row instead — that is what lets
     the tabs strip and the positions table below it touch and read as ONE
     stitched panel, the way Bybit's bottom section is one surface with its
     tabs inside. */
  body .pp-root.pp-root .pp-body {
    display: grid;
    grid-template-columns: 46px minmax(0, 1fr) 272px 320px;
    grid-template-rows: minmax(280px, 1fr) auto auto;
    grid-template-areas:
      'rail chart book form'
      'tabs tabs  tabs form'
      'pos  pos   pos  form';
    gap: 0 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. */
  /* No display here any more, and that is load-bearing: the JS owns it. It
     used to carry `display: block !important` to beat book mode's inline
     `none` — right when the phone JS insisted the chart was gone, wrong now
     that setMode shows it on desktop itself (open() clears the phone-only
     chartHidden preference) and renderChartTab needs to HIDE it whenever the
     Overview/Data/Feed pane takes this same grid cell. An !important would
     have pinned the canvas visible under every pane. */
  body .pp-root.pp-root .pp-body > .pp-chartwrap {
    grid-area: chart;
    margin-bottom: 10px;
    /* drawChart measures `parentElement.clientWidth`, which INCLUDES this
       element's 4px side padding, while the canvas renders at 100% of the
       content box under border-box sizing. The bitmap comes out 8px wider than
       its display box, so the plot is squeezed and the crosshair maths drifts
       from the price axis. Pre-existing, and a narrower chart column makes the
       fraction worse — zeroing the padding here removes the discrepancy at
       this width without touching the phone. */
    padding: 0;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-radius: 14px;
    overflow: hidden;
  }

  /* Overview, Data and Feed render here — same cell as the chart, exactly one
     of the two displayed at a time (renderChartTab's contract). Scrolls on its
     own: token details and funding charts are taller than one screen. */
  body .pp-root.pp-root .pp-body > .pp-chartpane {
    grid-area: chart;
    /* Overview/Data/Feed take the rail's gutter too — renderChartTab hides the
       rail alongside the canvas, and without this the pane would sit beside a
       46px hole. The implicit `rail-start`/`chart-end` lines come free from the
       area names above. */
    grid-column: rail-start / chart-end;
    margin-bottom: 10px;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 14px;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-radius: 14px;
  }

  /* ── the drawing rail ──────────────────────────────────────────────────────
   * A permanent column down the chart's left edge, which is where every
   * terminal keeps its tools — not a strip a pencil reveals under the chart.
   *
   * It stays a .pp-body child rather than moving inside .pp-chartwrap. Three
   * things fall out of that for free: this `>` combinator keeps matching;
   * renderChartTab keeps the authority to hide the rail when the Overview pane
   * takes the chart's cell; and the buttons stay outside the chart's
   * capture-phase pointerdown, which starts a 550ms timer to open the
   * order-staging sheet — a slow click on a tool would otherwise stage a trade.
   *
   * `display` is deliberately absent. The JS owns it (it is written inline in
   * four places) and must keep owning it, or the rail would strand itself
   * beside the Overview pane. open() sets S.drawBar and calls renderDrawBar
   * behind the same width gate instead.
   *
   * 46px: .pp-drawtool is 34px square, and 46 − 2(border) − 10(padding) = 34.
   * ────────────────────────────────────────────────────────────────────────── */
  body .pp-root.pp-root .pp-body > .pp-drawbarstrip {
    grid-area: rail;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 10px;
    padding: 8px 5px;
    overflow-x: hidden;
    overflow-y: auto;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-radius: 14px;
  }
  body .pp-root .pp-drawbarstrip .pp-drawtool {
    flex: none;
  }
  /* Utilities to the foot, the way every rail anchors its trash — and the only
     grouping the column needs. */
  body .pp-root .pp-drawbarstrip .pp-drawall {
    margin-top: auto;
    border-style: solid;
  }
  /* A permanently red trash on a permanently visible rail is a standing alarm.
     Grey at rest, red on intent — and it sits a full column away from the
     nearest drawing tool, because Clear wipes every shape with no confirm. */
  body .pp-root .pp-drawbarstrip .pp-drawclear {
    color: var(--gl-market, #9aa4b2);
  }
  body .pp-root .pp-drawbarstrip .pp-drawclear:hover,
  body .pp-root .pp-drawbarstrip .pp-drawclear:focus-visible {
    color: var(--red, #ff5c7a);
  }
  /* :hover before .on — both are (0,4,1) and a tie goes to source order. */
  body .pp-root .pp-drawbarstrip .pp-drawtool:hover {
    background: var(--gl-panel-2);
  }
  /* A solid accent-green square in the left gutter competes with the bids and
     longs on the chart beside it. Tint the ground, accent the glyph. */
  body .pp-root .pp-drawbarstrip .pp-drawtool.on {
    background: var(--gl-panel-2);
    color: var(--gl-accent, #34e8a4);
    border-color: color-mix(in srgb, var(--gl-accent, #34e8a4) 40%, transparent);
  }

  body .pp-root.pp-root .pp-body > .pp-split {
    display: contents !important;
  }

  /* The chart tabs are a .pp-root child above the body, so they span the
     terminal — align their inset with the grid's. */
  body .pp-root .pp-charttabs {
    padding-left: 22px;
    padding-right: 22px;
  }

  /* ── the chart toolbar ─────────────────────────────────────────────────────
   * Target: timeframes far left, icon-only chart controls far right. What was
   * there instead: five intervals, then 472px of nothing, then seven mismatched
   * text-and-icon buttons — including two pairs that did the same job.
   *
   * `.pp-root.pp-root` is not a typo. `.pp-root.pp-compactchart .pp-tfs`
   * (0,3,0) re-asserts overflow-x, and compactchart is the RESTING desktop
   * state: S.mode defaults to 'book', setMode toggles the class from it, and
   * the mode switcher is hidden here — so `body .pp-root .pp-tfs` (0,2,1)
   * would lose every time. The doubled class is the same idiom ghost-lens.css
   * already uses on the nav.
   * ────────────────────────────────────────────────────────────────────────── */
  body .pp-root.pp-root .pp-tfs {
    align-items: center;
    gap: 6px;
    overflow: visible;
    padding: 6px 22px 10px;
  }

  body .pp-root .pp-tfs button {
    padding: 6px 10px;
    color: var(--gl-market, #9aa4b2);
  }
  /* Restated: the rule above is (0,2,2) and would otherwise outrank
     `.pp-tfs button.on` (0,2,1) and kill the selected interval. */
  body .pp-root .pp-tfs button.on {
    background: var(--gl-panel-2);
    color: var(--gl-mine, #eef2f8);
  }

  /* Square icon targets, and the margin reset that makes hiding safe.
     `.pp-tfs .pp-tool` sets `padding: 0 11px` with NO height, so an icon-only
     tool boxes to its 15px glyph — under WCAG 2.5.8's 24px minimum, today, on
     phone as well. It also puts `margin-left: auto` on EVERY tool, with a
     sibling rule walking it back for all but the first; `display: none` does
     not remove an element from sibling matching, so hiding the first tool
     would strand the push on a hidden node and collapse the whole cluster
     leftward. Resetting the margin here is what makes the hides below safe. */
  body .pp-root .pp-tfs .pp-tool {
    margin: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    display: grid;
    place-items: center;
    border-radius: 8px;
    color: var(--gl-market, #9aa4b2);
  }
  /* One push, on the last member of the left group. Must follow the reset —
     equal specificity, and the shorthand above zeroes margin-right. */
  body .pp-root .pp-tfs .pp-more {
    margin-right: auto;
  }
  /* Three icon sets ship at three sizes (15/2.0, 16/1.9, 17/1.7). Presentation
     attributes on <svg> rank below author styles, so they unify from here with
     no JS change. */
  body .pp-root .pp-tfs .pp-tool > svg {
    display: block;
    width: 17px;
    height: 17px;
    stroke-width: 1.7;
  }
  body .pp-root .pp-tfs .pp-tool:hover {
    background: var(--gl-panel-2);
    color: var(--gl-mine, #eef2f8);
  }

  /* The four that go.
     .pp-pencil    gated S.drawBar, which is permanently true here — gates nothing.
     .pp-drawsheet opened the 84-tool sheet; the rail's own all-tools button
                   holds the identical openDrawTools reference.
     .pp-fullbtn / .pp-expand  full screen. Removed rather than restyled: the
                   class it sets, html.pp-fullchart, force-hides seven regions
                   with `display: none !important` and NO media guard, which on
                   this grid half-collapses the terminal (the ticket and book
                   survive on their named areas while everything else vanishes).
                   Its sibling also calls toggleLandscape, which needs a native
                   signer no browser has and toasts "Rotate the phone" on every
                   click. Deleting both controls makes that whole cluster
                   unreachable at this width instead of fighting an !important.
                   The chart already owns ~55% of the viewport; F11 is the
                   browser's own answer.
     display:none, not visibility — these must leave the tab order too.
     .pp-rot needs no rule: it is inline-hidden and the only line that clears
     it runs inside the full-screen path that no longer exists here. */
  body .pp-root .pp-tfs .pp-pencil,
  body .pp-root .pp-tfs .pp-drawsheet,
  body .pp-root .pp-tfs .pp-fullbtn,
  body .pp-root .pp-tfs .pp-expand {
    display: none;
  }

  /* Hide-the-chart is a phone-space affordance (book and ticket, nothing
     else). On desktop the chart owns a column; offering the control would
     offer a hole. open() clears the persisted preference for the same reason. */
  body .pp-root .pp-hidechart {
    display: none;
  }

  /* Each region on its own raised panel. On a phone these share one column and
     separate by whitespace; side by side they need edges, or the screen reads
     as loose furniture on a void instead of a terminal. Same glass language as
     the rest of the app — --gl vars with literal fallbacks, per rule 3. */
  body .pp-root.pp-root .pp-split > .pp-right {
    grid-area: book;
    margin-bottom: 10px;
    padding: 12px;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-radius: 14px;
  }
  body .pp-root.pp-root .pp-split > .pp-form {
    grid-area: form;
    padding: 14px;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-radius: 14px;
  }

  /* The bottom section is ONE panel with the tabs inside it, Bybit-style. Two
     sibling elements cannot share a box, so it is stitched: the tabs strip is
     the panel's top edge (side + top borders, top radius), the table is its
     body (side + bottom borders, bottom radius), zero row-gap lets them touch,
     and the tabs' own border-bottom — which upstream already draws — becomes
     the interior seam under the tab row. */
  body .pp-root.pp-root .pp-body > .pp-tabs {
    grid-area: tabs;
    padding: 8px 16px 0;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-bottom: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-radius: 14px 14px 0 0;
  }
  body .pp-root.pp-root .pp-body > .pp-positions {
    grid-area: pos;
    padding: 8px 16px 12px;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    border-top: 0;
    border-radius: 0 0 14px 14px;
  }

  /* 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;
    max-height: 260px;
    overflow-y: auto;
  }

  /* ── positions: a table, not a stack of tiles ──────────────────────────────
   * The tile was built from a side-by-side with Bybit and is right on a phone,
   * where one position fills the width. Both desktop references show a table:
   * labels once at the top, one line per position, columns you can read down.
   *
   * Every item is placed EXPLICITLY. `display: contents` on the two wrappers
   * promotes their children to grid items, which makes them GRANDCHILDREN of
   * the card — so a `.pp-poscard > *` rule would match the dissolved wrappers
   * (which generate no box) and never the real cells. Sparse auto-placement
   * would then wrap the data onto rows 2 and 3, because document order runs
   * column 1, column 6, column 2 and the cursor only moves forward.
   *
   * One shared 7-column template on the header and the rows, so they align by
   * construction rather than by matching numbers in two places. */
  body .pp-root.pp-root .pp-positions > .pp-poshead-row,
  body .pp-root.pp-root .pp-positions > .pp-poscard {
    display: grid;
    /* The action track is a FIXED width, not auto. The header's last cell is
       empty, so an auto track collapses there to ~0 while the card's fills to
       the buttons — and the two grids then distribute the difference across
       their fr tracks differently, so the columns drift apart by a few pixels
       each. A fixed track makes the header and the rows share one geometry. */
    grid-template-columns:
      minmax(110px, 1.25fr) minmax(64px, 0.9fr) minmax(76px, 1fr)
      minmax(76px, 1fr) minmax(76px, 1fr) minmax(72px, 0.9fr)
      minmax(104px, 1.15fr) 168px;
    align-items: center;
    column-gap: 12px;
  }

  body .pp-root.pp-root .pp-positions > .pp-poshead-row {
    padding: 2px 12px 6px;
    font-size: 11px;
    font-weight: 600;
    color: var(--gl-market-faint, #5f6873);
    border-bottom: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--gl-panel, rgba(255, 255, 255, 0.04));
  }
  /* Numeric headings sit over right-aligned figures. */
  body .pp-root.pp-root .pp-positions > .pp-poshead-row > span:nth-child(n + 2) {
    text-align: right;
  }

  body .pp-root.pp-root .pp-positions > .pp-poscard {
    padding: 6px 12px;
    margin: 0;
    border-radius: 0;
    border-width: 0 0 1px;
  }
  body .pp-root.pp-root .pp-poscard > .pp-poshead,
  body .pp-root.pp-root .pp-poscard > .pp-posgrid {
    display: contents;
  }

  /* The explicit placement the wrappers can no longer provide. */
  body .pp-root.pp-root .pp-poscard .pp-posid { grid-area: 1 / 1; }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell:nth-child(1) { grid-area: 1 / 2; }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell:nth-child(2) { grid-area: 1 / 3; }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell:nth-child(3) { grid-area: 1 / 4; }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell:nth-child(4) { grid-area: 1 / 5; }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell:nth-child(5) { grid-area: 1 / 6; }
  body .pp-root.pp-root .pp-poscard .pp-pospnl { grid-area: 1 / 7; }
  body .pp-root.pp-root .pp-poscard > .pp-posact { grid-area: 1 / 8; }
  /* Margin and value are loose spans rather than labelled cells, so they stay
     one strip under the row instead of pretending to be two more columns. */
  body .pp-root.pp-root .pp-poscard > .pp-posmeta { grid-area: 2 / 1 / auto / -1; }
  /* TP/SL brackets, when present, get their own line under the row. */
  body .pp-root.pp-root .pp-poscard > .pp-poschips { grid-area: 3 / 1 / auto / -1; }

  /* The header states each label once; repeating it in every cell is the tile
     idiom and is what makes a stack of them unreadable as a column. */
  body .pp-root.pp-root .pp-posgrid > .pp-poscell > :not(.gl-num) {
    display: none;
  }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell {
    padding: 0;
    background: none;
    border: 0;
    text-align: right;
  }
  body .pp-root.pp-root .pp-posgrid > .pp-poscell > .gl-num {
    text-align: right;
    font-size: 13px;
  }

  /* P&L keeps its figure but loses the stacked caption — the column is named. */
  body .pp-root.pp-root .pp-poscard .pp-pospnl {
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-end;
    gap: 6px;
    text-align: right;
  }
  body .pp-root.pp-root .pp-poscard .pp-pospnl-k {
    display: none;
  }

  body .pp-root.pp-root .pp-poscard .pp-posid {
    min-width: 0;
  }
  body .pp-root.pp-root .pp-poscard > .pp-posmeta {
    font-size: 11px;
    padding-top: 2px;
  }
  /* Row actions compress to a trailing cluster rather than a full-width bar. */
  body .pp-root.pp-root .pp-poscard > .pp-posact {
    display: flex;
    gap: 6px;
    margin: 0;
  }
  body .pp-root.pp-root .pp-poscard > .pp-posact .pp-posbtn {
    width: auto;
    padding: 5px 10px;
    font-size: 11.5px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * 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;
  }
}

/* =============================================================================
 * The Gram wallet, on the same big screen.
 *
 * The public home is the vault home's twin: the wallet card and the action
 * rail on one eye-line, the tabs and the lists across the full width below.
 * Same grid, same safety net for children this file does not name. The
 * collectibles vitrine becomes a gallery: four across, since two tiles at
 * this width were posters rather than a collection.
 * ========================================================================== */
@media (min-width: 1000px) {
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 236px;
    gap: 16px 18px;
    align-content: start;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > * {
    grid-column: 1 / -1;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-card {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    padding: 34px 38px 36px;
    border-radius: 26px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .actions-row {
    grid-column: 2;
    grid-row: 1;
    grid-auto-flow: row;
    grid-auto-columns: initial;
    grid-template-rows: none;
    grid-auto-rows: 1fr;
    gap: 10px;
    margin-bottom: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .actions-row .action-tile {
    flex-direction: row;
    justify-content: flex-start;
    gap: 13px;
    padding: 0 16px;
    font-size: 14px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(.vault-card) > .actions-row .action-tile .ern-chip,
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .actions-row .action-tile .ern-chip {
    top: 50%;
    left: auto;
    right: 14px;
    transform: translateY(-50%);
    font-size: 11px;
    padding: 3px 8px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .actions-row .action-tile .bubble {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
  }
  body .shell:has(> nav.bottom-nav) .pub-total,
  body .shell:has(> nav.bottom-nav) .pub-total-usd b {
    font-size: 56px;
    letter-spacing: -1.8px;
  }
  body .shell:has(> nav.bottom-nav) .pub-total-usd span {
    font-size: 30px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page .pub-vault.compact {
    margin-top: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page .pub-tabs {
    margin-top: 6px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page .gw-list.asset-list {
    border-radius: 20px;
    padding: 8px 22px;
  }
  body .shell:has(> nav.bottom-nav) .nft-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.afr) {
    display: block;
  }
}
@media (min-width: 1600px) {
  body .shell:has(> nav.bottom-nav) .nft-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

/* ══════════════════════════════════════════════════════════════════════════
 * History, as a table (2026-09-24). renderHistory builds every cell; on a
 * phone most of them hide and their facts ride the row's sub line. Here the
 * sub line hides instead and each fact takes its own column under one
 * header, the positions table's idiom. The summary becomes one strip: the
 * figure, its line, and the four facts in a row.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px) {
  body .pp-root.pp-root .pp-positions > .pp-hx-sum {
    display: grid;
    grid-template-columns: auto minmax(160px, 1fr) auto;
    align-items: center;
    gap: 22px;
    margin: 6px 0 10px;
    padding: 12px 16px;
  }
  body .pp-root.pp-root .pp-hx-sum > .pp-hx-sumhead { display: contents; }
  body .pp-root.pp-root .pp-hx-sum .pp-hx-spark { max-width: none; height: 44px; }
  body .pp-root.pp-root .pp-hx-sum .pp-hx-facts {
    margin: 0;
    grid-template-columns: repeat(4, minmax(92px, auto));
  }
  body .pp-root.pp-root .pp-hx-sum .pp-hx-net { font-size: 26px; }

  body .pp-root.pp-root .pp-positions > .pp-hx-thead,
  body .pp-root.pp-root .pp-positions > .pp-hx-row {
    display: grid;
    grid-template-columns:
      64px minmax(150px, 1.6fr) minmax(110px, 1fr) minmax(84px, 0.8fr)
      minmax(100px, 0.9fr) minmax(84px, 0.8fr) minmax(128px, 1fr);
    align-items: center;
    column-gap: 14px;
  }
  body .pp-root.pp-root .pp-positions > .pp-hx-thead {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 4px 12px 7px;
    font-size: 11px;
    font-weight: 600;
    color: var(--gl-market-faint, #5f6873);
    background: var(--gl-deep, #0d0f13);
    border-bottom: 1px solid var(--gl-edge-soft, rgba(255, 255, 255, 0.06));
  }
  body .pp-root.pp-root .pp-positions > .pp-hx-thead > span:nth-child(n + 4) { text-align: right; }

  body .pp-root.pp-root .pp-positions > .pp-hx-row {
    margin: 0;
    padding: 8px 12px;
    border-radius: 10px;
  }
  body .pp-root.pp-root .pp-positions > .pp-hx-row + .pp-hx-row::before { left: 12px; right: 12px; }
  body .pp-root.pp-root .pp-positions > .pp-hx-row:hover { background: var(--gl-panel-2, rgba(255, 255, 255, 0.07)); }
  body .pp-root.pp-root .pp-positions > .pp-hx-row:hover::before,
  body .pp-root.pp-root .pp-positions > .pp-hx-row:hover + .pp-hx-row::before { opacity: 0; }

  body .pp-root.pp-root .pp-hx-row > .pp-hx-time,
  body .pp-root.pp-root .pp-hx-row > .pp-hx-act,
  body .pp-root.pp-root .pp-hx-row > .pp-hx-size,
  body .pp-root.pp-root .pp-hx-row > .pp-hx-px,
  body .pp-root.pp-root .pp-hx-row > .pp-hx-fee { display: block; }
  body .pp-root.pp-root .pp-hx-row > .pp-hx-time { font-size: 12px; color: var(--gl-market, #9aa4b2); }
  body .pp-root.pp-root .pp-hx-row > .pp-hx-size,
  body .pp-root.pp-root .pp-hx-row > .pp-hx-px,
  body .pp-root.pp-root .pp-hx-row > .pp-hx-fee { text-align: right; font-size: 12.5px; color: var(--gl-mine, #eef2f8); }
  body .pp-root.pp-root .pp-hx-row > .pp-hx-fee { color: var(--gl-market, #9aa4b2); }
  /* the pill lives in its own column here, and the sub line's facts in theirs */
  body .pp-root.pp-root .pp-hx-row .pp-hx-coin > .pp-hx-pill,
  body .pp-root.pp-root .pp-hx-row .pp-hx-sub,
  body .pp-root.pp-root .pp-hx-row .pp-hx-feeline { display: none; }
  body .pp-root.pp-root .pp-hx-row .pp-hx-mkt .pp-logo { width: 26px !important; height: 26px !important; }
  body .pp-root.pp-root .pp-hx-row .pp-hx-coin { font-size: 13.5px; }
  body .pp-root.pp-root .pp-hx-row > .pp-hx-res { align-items: flex-end; }
  body .pp-root.pp-root .pp-hx-row .pp-hx-pnl { font-size: 14px; }
  body .pp-root.pp-root .pp-positions > .pp-hx-day { margin: 12px 12px 4px; }

  /* The history carries a summary above its table: a little more height for
     the panel, still well short of what the chart gives up. */
  body .pp-root.pp-root .pp-body > .pp-positions { max-height: 300px; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * The terminal, v2 (2026-09-24). The owner's brief: "significantly redesign
 * the perps so it will look very good and beat anything in the world".
 *
 * The grid above stays exactly as it is (areas, the JS-owned displays, the
 * ladder that fills its column); this is the skin over it. One panel language
 * for every region: a surface a breath above the page, a hairline edge, a lit
 * top edge and a long soft shadow, so the screen reads as instruments set into
 * a console rather than boxes on a void. The instrument bar becomes a panel of
 * its own. The book gets more of its column, a band at the spread that holds
 * the last price in its colour, and a real buy/sell bar at its foot. Long and
 * Short sit side by side, as on every desktop venue. Timeframes are chips, the
 * chosen one lit silver. The exchange colours stay the only colour on screen.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px) {
  body .gl.pp-root.pp-root {
    --pp-panel: color-mix(in srgb, var(--gl-mine, #eef2f8) 3.2%, var(--gl-void, #050609));
    --pp-panel-hi: color-mix(in srgb, var(--gl-mine, #eef2f8) 5.5%, var(--gl-void, #050609));
    --pp-edge: color-mix(in srgb, var(--gl-mine, #eef2f8) 8.5%, transparent);
    --pp-lit: inset 0 1px 0 color-mix(in srgb, #ffffff 5%, transparent);
    --pp-drop: 0 24px 48px -32px rgba(0, 0, 0, 0.9);
    background:
      radial-gradient(1100px 420px at 18% -160px, color-mix(in srgb, var(--gl-mine) 6%, transparent), transparent 70%),
      radial-gradient(900px 360px at 100% 0%, color-mix(in srgb, var(--tx-up) 4%, transparent), transparent 70%),
      var(--gl-void);
  }
  :root[data-theme='light'] body .gl.pp-root.pp-root {
    --pp-panel: #ffffff;
    --pp-panel-hi: #f7f8fa;
    --pp-edge: color-mix(in srgb, #141920 10%, transparent);
    --pp-drop: 0 20px 40px -30px rgba(20, 25, 32, 0.28);
    background: #f1f3f6;
  }

  /* ── one panel language ─────────────────────────────────────────────── */
  body .pp-root.pp-root .pp-body > .pp-chartwrap,
  body .pp-root.pp-root .pp-body > .pp-chartpane,
  body .pp-root.pp-root .pp-body > .pp-drawbarstrip,
  body .pp-root.pp-root .pp-split > .pp-right,
  body .pp-root.pp-root .pp-split > .pp-form,
  body .pp-root.pp-root .pp-body > .pp-tabs,
  body .pp-root.pp-root .pp-body > .pp-positions {
    background: var(--pp-panel);
    border-color: var(--pp-edge);
    box-shadow: var(--pp-lit), var(--pp-drop);
  }
  body .pp-root.pp-root .pp-body > .pp-chartwrap,
  body .pp-root.pp-root .pp-split > .pp-right,
  body .pp-root.pp-root .pp-split > .pp-form,
  body .pp-root.pp-root .pp-body > .pp-drawbarstrip { border-radius: 18px; }
  body .pp-root.pp-root .pp-body > .pp-tabs { border-radius: 18px 18px 0 0; box-shadow: var(--pp-lit); }
  body .pp-root.pp-root .pp-body > .pp-positions { border-radius: 0 0 18px 18px; }
  body .pp-root.pp-root .pp-body { gap: 0 14px; }
  /* The book runs the full height, beside the account strip as well as the
     chart: a ladder is read top to bottom, and the column the chart row gave
     it held two levels a side. The account strip takes the chart's width,
     which its seven columns fit with room to spare. */
  body .pp-root.pp-root .pp-body {
    grid-template-areas:
      'rail chart book form'
      'tabs tabs  book form'
      'pos  pos   book form';
  }
  body .pp-root.pp-root .pp-split > .pp-right { margin-bottom: 0; }

  /* ── the instrument bar, as a panel ─────────────────────────────────── */
  body .pp-root .pp-strip {
    margin: 2px 22px 12px;
    padding: 10px 18px;
    border: 1px solid var(--pp-edge);
    border-radius: 18px;
    background:
      linear-gradient(90deg, color-mix(in srgb, var(--gl-mine) 4%, transparent), transparent 42%),
      var(--pp-panel);
    box-shadow: var(--pp-lit), var(--pp-drop);
  }
  body .pp-root .pp-strip > .pp-pairrow { padding-right: 18px; margin-right: 6px; border-right-color: var(--pp-edge); }
  body .pp-root .pp-last .pp-big { font-size: 36px; letter-spacing: -0.03em; }
  body .pp-root .pp-stats > span { border-left-color: var(--pp-edge); padding: 0 16px; }
  body .pp-root .pp-stats > span:nth-child(odd) { font-size: 10.5px; letter-spacing: 0.02em; }
  body .pp-root .pp-stats > span:nth-child(even) { font-size: 14px; letter-spacing: -0.01em; }

  /* ── chart tabs and timeframes: chips, the chosen one lit ───────────── */
  body .pp-root .pp-charttabs button.on { color: var(--gl-mine); }
  body .pp-root.pp-root .pp-tfs { gap: 4px; padding-top: 2px; padding-bottom: 10px; }
  body .pp-root .pp-tfs button { border-radius: 9px; font-weight: 700; font-variant-numeric: tabular-nums; }
  body .pp-root .pp-tfs button.on {
    background: var(--gl-mine);
    color: var(--gl-void);
    box-shadow: 0 6px 18px -8px color-mix(in srgb, var(--gl-mine) 60%, transparent);
  }
  body .pp-root .pp-tfs .pp-tool.on { background: var(--gl-panel-2); color: var(--gl-mine); box-shadow: none; }

  /* ── the book: more of its column, a band at the spread, a real bar ─── */
  body .pp-root .pp-right > .pp-lower { flex-basis: 34%; border-top-color: var(--pp-edge); }
  body .pp-root .pp-righttabs button.on {
    background: var(--gl-mine);
    color: var(--gl-void);
  }
  body .pp-root .pp-book .pp-row { border-radius: 4px; }
  body .pp-root .pp-book .pp-row:hover { background: color-mix(in srgb, var(--gl-mine) 6%, transparent); }
  body .pp-root .pp-book > .pp-spread {
    margin: 4px 0;
    padding: 6px 8px;
    border-radius: 10px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--gl-mine) 6%, transparent), transparent);
  }
  body .pp-root .pp-book > .pp-spread .pp-mid-px { font-size: 18px; letter-spacing: -0.02em; }
  body .pp-root .pp-book > .pp-spread .pp-mid-px.pp-up::after { content: ' \2191'; font-size: 13px; }
  body .pp-root .pp-book > .pp-spread .pp-mid-px.pp-down::after { content: ' \2193'; font-size: 13px; }
  body .pp-root .pp-book > .pp-ratio {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    padding: 4px 2px 0;
    font: 800 11px var(--font-display, 'Space Grotesk', Inter, sans-serif);
    font-variant-numeric: tabular-nums;
  }
  body .pp-root .pp-book > .pp-ratio > .pp-up,
  body .pp-root .pp-book > .pp-ratio > .pp-down {
    flex: none;
    padding: 2px 6px;
    border-radius: 6px;
  }
  body .pp-root .pp-book > .pp-ratio > .pp-up { color: var(--tx-up); background: var(--tx-up-wash); }
  body .pp-root .pp-book > .pp-ratio > .pp-down { color: var(--tx-down); background: var(--tx-down-wash); }
  body .pp-root .pp-book > .pp-ratio > .pp-bar {
    flex: 1;
    height: 6px;
    border-radius: 6px;
    overflow: hidden;
    background: var(--tx-down);
  }
  body .pp-root .pp-book > .pp-ratio > .pp-bar > i {
    display: block;
    height: 100%;
    background: var(--tx-up);
    box-shadow: 2px 0 0 var(--pp-panel);
    transition: width 0.5s var(--gl-ease);
  }
  body .pp-root .pp-lowertabs button.on { color: var(--gl-mine); }

  /* ── the ticket ─────────────────────────────────────────────────────── */
  /* Long and Short side by side, the way every desktop venue sets them. */
  body .pp-root .pp-form .pp-sides {
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-top: 6px;
  }
  body .pp-root .pp-form .pp-sides .pp-side {
    padding: 13px 0;
    border-radius: 14px;
    font-size: 15.5px;
  }
  /* The leverage picker shares its class with the market list's "10X" chip,
     and took the chip's colour, tiny capitals, padding and corners. Here it is
     a picker like the two beside it. */
  body .pp-root .pp-form .pp-pick.pp-lev {
    padding: 0 11px;
    border-radius: var(--gl-radius, 16px);
    background: var(--gl-panel);
    border-color: var(--gl-edge-soft);
    color: var(--gl-mine);
    font-size: 13px;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
  }
  body .pp-root .pp-form .pp-field:focus-within {
    border-color: color-mix(in srgb, var(--gl-mine) 42%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--gl-mine) 8%, transparent);
  }

  /* ── the account strip ──────────────────────────────────────────────── */
  body .pp-root .pp-tabs button.on { color: var(--gl-mine); }
  body .pp-root.pp-root .pp-body > .pp-positions { background: var(--pp-panel); }
  body .pp-root.pp-root .pp-positions > .pp-hx-thead { background: var(--pp-panel); }
  body .pp-root.pp-root .pp-hx-sum .pp-hx-spark { width: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * The account card (2026-09-25), paintAcct in perps-pro.js. It closes the
 * ticket column the way desk venues close it: equity large, a bar for how
 * much of it is holding positions up (silver, amber past 40%, red past 70%,
 * the thresholds the Account health strip uses), three figures, and the two
 * doors money uses. margin-top: auto sits it on the panel's floor whenever
 * the ticket above leaves room, and lets it follow the ticket when not.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px) {
  body .pp-root .pp-form > .pp-acctcard {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: none;
    margin-top: auto;
    padding: 14px 14px 12px;
    border-radius: 14px;
    background: linear-gradient(180deg, var(--pp-panel-hi), var(--pp-panel));
    border: 1px solid var(--pp-edge);
    box-shadow: var(--pp-lit);
  }
  body .pp-root .pp-ac-head { display: flex; align-items: center; justify-content: space-between; }
  body .pp-root .pp-ac-k {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--gl-market-faint);
  }
  body .pp-root .pp-ac-tag {
    font-style: normal;
    font-size: 10px;
    font-weight: 800;
    padding: 2px 8px;
    border-radius: 999px;
    color: var(--gl-risk, #f0c46a);
    background: color-mix(in srgb, var(--gl-risk, #f0c46a) 14%, transparent);
  }
  body .pp-root .pp-ac-eq {
    font-family: var(--font-display, 'Space Grotesk', Inter, sans-serif);
    font-size: 25px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.05;
    color: var(--gl-mine);
    font-variant-numeric: tabular-nums;
  }
  body .pp-root .pp-ac-eq.pp-wait { width: 120px; height: 22px; }
  body .pp-root .pp-ac-bar {
    display: block;
    height: 4px;
    border-radius: 4px;
    overflow: hidden;
    background: color-mix(in srgb, var(--gl-mine) 9%, transparent);
  }
  body .pp-root .pp-ac-bar > i {
    display: block;
    width: 0;
    height: 100%;
    border-radius: inherit;
    background: var(--gl-mine);
    transition: width 0.5s var(--gl-ease);
  }
  body .pp-root .pp-ac-bar.warm > i { background: var(--gl-risk, #f0c46a); }
  body .pp-root .pp-ac-bar.hot > i { background: var(--tx-down); }
  body .pp-root .pp-ac-rows { display: grid; gap: 7px; }
  body .pp-root .pp-ac-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: 12px;
    color: var(--gl-market);
  }
  body .pp-root .pp-ac-row > b {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--gl-mine);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  body .pp-root .pp-ac-row > b.pp-win { color: var(--tx-up); }
  body .pp-root .pp-ac-row > b.pp-lose { color: var(--tx-down); }
  body .pp-root .pp-ac-go {
    height: 36px;
    margin-top: 2px;
    border-radius: 10px;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    color: var(--gl-void);
    background: var(--gl-mine);
    border: 0;
    cursor: pointer;
    transition: background 0.15s var(--gl-ease), transform 0.15s var(--gl-ease);
  }
  body .pp-root .pp-ac-go:hover { background: color-mix(in srgb, var(--gl-mine) 86%, transparent); }
  body .pp-root .pp-ac-go:active { transform: scale(0.97); }

  /* Margin mode, leverage and order type on one row: a desktop ticket is wide
     enough for all three words, and the row it gives back is what lets the
     account card sit under the ticket without squeezing it. */
  body .pp-root .pp-form .pp-duo { grid-template-columns: 1.2fr 0.8fr 1fr; }
  body .pp-root .pp-form .pp-duo > .pp-otype { grid-column: auto; }
  /* Nothing in the ticket gives up height to the card; past the panel's
     floor the panel scrolls, as it always has. */
  body .pp-root.pp-root .pp-split > .pp-form > * { flex-shrink: 0; }
  /* On a short screen the card folds to one line: the figure, its bar, and
     the door beside it. The rows go; the Balances tab has them. */
  @media (max-height: 940px) {
    body .pp-root .pp-form > .pp-acctcard {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      align-items: center;
      gap: 3px 12px;
      padding: 10px 12px;
    }
    body .pp-root .pp-form > .pp-acctcard > .pp-ac-head { grid-area: 1 / 1; }
    body .pp-root .pp-form > .pp-acctcard > .pp-ac-eq { grid-area: 2 / 1; font-size: 20px; }
    body .pp-root .pp-form > .pp-acctcard > .pp-ac-bar { grid-area: 3 / 1 / 4 / 3; margin-top: 5px; }
    body .pp-root .pp-form > .pp-acctcard > .pp-ac-go { grid-area: 1 / 2 / 3 / 3; margin: 0; padding: 0 18px; height: 34px; }
    body .pp-root .pp-form > .pp-acctcard > .pp-ac-rows { display: none !important; }
  }
}

/* =============================================================================
 * THE DESKTOP, AS A DESKTOP (owner, 2026-09-28: "i want the desktop website to
 * look like it is desktop view … the mobile style should not be touched")
 *
 * The sidebar made the phone's screens sit beside a nav; this makes them read
 * as one desktop application. A header across the top with search, Deposit,
 * the privacy eye, the theme and who you are (components/DesktopBar). A ⌘K
 * palette that runs anything (components/CommandPalette). Home as a dashboard,
 * with a market and a ledger beside the vault (components/HomeRail) and the
 * coins as a table with columns. Swap with its market beside the ticket
 * (components/SwapMarket). Activity as a ledger.
 *
 * Every element this section styles that a phone does not already have is
 * MOUNTED only at this width (lib/wide's useWide, the same 1000px), so a
 * phone never has it in its tree; the rules for the rest stay behind the
 * breakpoint like everything else in this file.
 * ========================================================================== */
@media (min-width: 1000px) {
  :root:root {
    /* the header's height, shared with the sidebar's own head so the two
       rules underneath them run as one line across the window */
    --gd-bar: 64px;
    --gd-card: color-mix(in srgb, var(--bg-elev) 92%, var(--ink) 2%);
    --gd-card-line: color-mix(in srgb, var(--ink) 9%, transparent);
    --gd-card-lit: inset 0 1px 0 color-mix(in srgb, #ffffff 4%, transparent);
    --gd-hover: color-mix(in srgb, var(--ink) 5.5%, transparent);
    --gd-up: var(--success);
    --gd-down: var(--red);
  }
  :root:root[data-theme='light'] {
    --gd-card: #ffffff;
    --gd-card-line: color-mix(in srgb, #141920 9%, transparent);
    --gd-card-lit: 0 1px 2px rgba(20, 25, 32, 0.04);
    --gd-hover: color-mix(in srgb, #141920 4.5%, transparent);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE HEADER
   * ══════════════════════════════════════════════════════════════════════ */

  body .shell:has(> .gd-bar) {
    padding-top: var(--gd-bar);
  }
  body .shell > .gd-bar {
    position: fixed;
    top: 0;
    left: var(--gd-side);
    right: 0;
    z-index: 32;
    height: var(--gd-bar);
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 0 26px 0 28px;
    background: color-mix(in srgb, var(--bg) 80%, transparent);
    backdrop-filter: saturate(1.5) blur(18px);
    -webkit-backdrop-filter: saturate(1.5) blur(18px);
    border-bottom: 1px solid var(--gd-side-line);
    animation: gdBarIn 0.32s cubic-bezier(0.2, 0, 0, 1) both;
  }
  @keyframes gdBarIn {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: none; }
  }

  /* Search, as a field that is really a button: it opens the palette, where
     the typing happens, so there is one search and not two. */
  body .gd-bar .gd-search {
    flex: 0 1 440px;
    min-width: 220px;
    height: 40px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 8px 0 13px;
    border-radius: 12px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-faint);
    font-size: 13.5px;
    font-weight: 500;
    cursor: text;
    transition: border-color 0.15s, background 0.15s, box-shadow 0.2s;
  }
  body .gd-bar .gd-search:hover {
    border-color: var(--stroke);
    background: var(--glass-2);
  }
  body .gd-bar .gd-search:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--ink) 40%, transparent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink) 8%, transparent);
  }
  body .gd-bar .gd-search-l {
    flex: 1;
    min-width: 0;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body .gd-bar kbd,
  body .gd-pal kbd {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 6px;
    background: var(--bg-elev-2);
    border: 1px solid var(--stroke-soft);
    border-bottom-width: 2px;
    color: var(--text-dim);
    font: 600 11px/1 var(--font);
  }
  body .gd-bar .gd-search kbd + kbd {
    margin-left: -6px;
  }

  body .gd-bar .gd-bar-r {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 8px;
  }

  body .gd-bar .gd-inc {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    padding: 0 12px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--red) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--red) 30%, transparent);
    color: var(--red);
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
  }
  body .gd-bar .gd-inc.maint {
    background: color-mix(in srgb, var(--amber) 12%, transparent);
    border-color: color-mix(in srgb, var(--amber) 30%, transparent);
    color: var(--amber);
  }
  body .gd-bar .gd-inc i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    box-shadow: 0 0 10px currentColor;
    animation: pulse 1.6s infinite;
  }

  body .gd-bar .gd-dep {
    height: 38px;
    padding: 0 18px;
    border-radius: 11px;
    background: var(--grad);
    color: var(--cta-text);
    font-size: 13.5px;
    font-weight: 800;
    letter-spacing: 0.1px;
    box-shadow: 0 10px 24px -14px color-mix(in srgb, var(--ink) 40%, transparent), inset 0 1px 0 color-mix(in srgb, #ffffff 40%, transparent);
    transition: filter 0.15s, transform 0.12s;
  }
  body .gd-bar .gd-dep:hover { filter: brightness(1.06); }
  body .gd-bar .gd-dep:active { transform: scale(0.97); }

  body .gd-bar .gd-ic {
    position: relative;
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border-radius: 11px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
    transition: background 0.15s, color 0.15s, border-color 0.15s;
  }
  body .gd-bar .gd-ic:hover {
    background: var(--glass-2);
    border-color: var(--stroke);
    color: var(--text);
  }
  body .gd-bar .gd-ic.on {
    color: var(--text);
    border-color: color-mix(in srgb, var(--ink) 28%, transparent);
  }
  /* A desktop names an icon on hover. */
  body .gd-bar [data-tip]::after {
    content: attr(data-tip);
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    transform: translate(-50%, -3px);
    padding: 6px 9px;
    border-radius: 8px;
    background: var(--ink);
    color: var(--cta-text);
    font-size: 11.5px;
    font-weight: 700;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.14s 0.25s, transform 0.14s 0.25s;
    z-index: 2;
  }
  body .gd-bar [data-tip]:hover::after {
    opacity: 1;
    transform: translate(-50%, 0);
  }

  body .gd-bar .gd-sep {
    width: 1px;
    height: 24px;
    margin: 0 4px;
    background: var(--gd-side-line);
  }

  /* Who you are, in the corner every desktop keeps for it. The ring is the
     wallet in front: the vault's solid silver, the Gram wallet's blue. */
  body .gd-bar .gd-me {
    height: 44px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 10px 4px 4px;
    border-radius: 14px;
    color: var(--text-dim);
    transition: background 0.15s;
  }
  body .gd-bar .gd-me:hover { background: var(--glass-2); }
  body .gd-bar .gd-me-face {
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    border-radius: 12px;
    overflow: hidden;
    background: var(--bg-elev-2);
    box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--ink) 30%, transparent);
  }
  body .gd-bar .gd-me.public .gd-me-face {
    box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--gram) 70%, transparent);
  }
  body .gd-bar .gd-me-face > img,
  body .gd-bar .gd-me-face > * {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  body .gd-bar .gd-me-m {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.2;
    max-width: 150px;
  }
  body .gd-bar .gd-me-m b {
    font-size: 13.5px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }
  body .gd-bar .gd-me-m i {
    font-style: normal;
    font-size: 11.5px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 5px;
  }
  body .gd-bar .gd-me-m i::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--success);
    box-shadow: 0 0 6px color-mix(in srgb, var(--success) 70%, transparent);
  }
  body .gd-bar .gd-me.public .gd-me-m i::before {
    background: var(--gram);
    box-shadow: 0 0 6px color-mix(in srgb, var(--gram) 70%, transparent);
  }

  /* A narrow desktop (1000px leaves the header 660) keeps every control and
     sheds words: the search its sentence, then the account its name and the
     incident its label, which stays as the pill's tooltip. */
  @media (max-width: 1199px) {
    body .gd-bar .gd-search {
      flex: none;
      min-width: 0;
    }
    body .gd-bar .gd-search-l {
      display: none;
    }
  }
  @media (max-width: 1099px) {
    body .gd-bar .gd-me-m {
      display: none;
    }
    body .gd-bar .gd-inc {
      width: 32px;
      padding: 0;
      justify-content: center;
      gap: 0;
      font-size: 0;
    }
  }

  /* The header carries who you are, so the sidebar's wallets button would be
     the same door twice (owner, 2026-09-26: "so we dont have too many
     duplicates"), and so would the incident pip beside it, which the header
     spells out as a pill. The sidebar keeps the mark and, where offered, the
     switch. */
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar .icon-btn.wallets,
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar .st-dot-btn {
    display: none;
  }

  /* Sticky things that stuck to the window's top now stick under the header. */
  body .shell:has(> .gd-bar) .gifts-topbar {
    top: calc(var(--gd-bar) + 6px);
  }
  body .shell:has(> .gd-bar) > .dev-mirror-badge {
    top: var(--gd-bar);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE PALETTE
   * ══════════════════════════════════════════════════════════════════════ */

  body .gd-pal-back {
    position: fixed;
    inset: 0;
    z-index: 3600;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding-top: 12vh;
    background: var(--backdrop);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    animation: fadeIn 0.14s ease both;
  }
  body .gd-pal {
    width: min(660px, calc(100vw - 48px));
    max-height: min(580px, 76vh);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--sheet-solid);
    border: 1px solid var(--stroke);
    border-radius: 18px;
    box-shadow: 0 40px 90px -24px rgba(0, 0, 0, 0.75), var(--gd-card-lit);
    animation: gdPalIn 0.2s cubic-bezier(0.2, 0, 0, 1) both;
  }
  @keyframes gdPalIn {
    from { opacity: 0; transform: translateY(-10px) scale(0.985); }
    to { opacity: 1; transform: none; }
  }
  body .gd-pal-in {
    display: flex;
    align-items: center;
    gap: 12px;
    height: 62px;
    padding: 0 16px 0 20px;
    border-bottom: 1px solid var(--stroke-soft);
    color: var(--text-dim);
  }
  body .gd-pal-in input {
    flex: 1;
    min-width: 0;
    background: none;
    border: 0;
    outline: 0;
    color: var(--text);
    font: 500 16.5px var(--font);
  }
  body .gd-pal-in input::placeholder { color: var(--text-faint); }
  body .gd-pal-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 6px 8px 8px;
    scrollbar-width: thin;
  }
  body .gd-pal-g {
    padding: 12px 12px 6px;
    color: var(--text-faint);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.4px;
    text-transform: uppercase;
  }
  body .gd-pal-row {
    width: 100%;
    height: 44px;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 12px;
    border-radius: 11px;
    color: var(--text);
    text-align: left;
  }
  body .gd-pal-row.on { background: var(--gd-hover); }
  body .gd-pal-ic {
    flex: none;
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    border-radius: 9px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
  }
  body .gd-pal-ic svg { width: 17px; height: 17px; }
  body .gd-pal-ic .token-icon { width: 22px; height: 22px; box-shadow: none; }
  body .gd-pal-row.on .gd-pal-ic {
    color: var(--text);
    border-color: var(--stroke);
  }
  body .gd-pal-l {
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
  }
  body .gd-pal-h {
    margin-left: auto;
    max-width: 48%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-faint);
    font-size: 12.5px;
  }
  body .gd-pal-go {
    width: 22px;
    text-align: center;
    color: var(--text-dim);
    opacity: 0;
    font-size: 13px;
  }
  body .gd-pal-row.on .gd-pal-go { opacity: 1; }
  body .gd-pal-none {
    padding: 34px 12px;
    text-align: center;
    color: var(--text-faint);
    font-size: 13.5px;
  }
  body .gd-pal-foot {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 16px;
    border-top: 1px solid var(--stroke-soft);
    color: var(--text-faint);
    font-size: 12px;
  }
  body .gd-pal-foot span { display: inline-flex; align-items: center; gap: 4px; }
  body .gd-pal-foot kbd { min-width: 20px; height: 20px; font-size: 10.5px; }
  body .gd-pal-foot b {
    margin-left: auto;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--text-dim);
    letter-spacing: 0.2px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * DESKTOP MANNERS, everywhere in the app
   * ══════════════════════════════════════════════════════════════════════ */

  /* A pointer shows what is clickable; a keyboard shows where it is. */
  body .shell button:not(:disabled),
  body .shell [role='button'] {
    cursor: pointer;
  }
  body .shell :focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 55%, transparent);
    outline-offset: 2px;
  }
  body .shell input:focus-visible,
  body .shell textarea:focus-visible {
    outline: none;
  }
  /* A thin, quiet scrollbar, the desktop's own. */
  html {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--ink) 18%, transparent) transparent;
  }
  ::selection {
    background: color-mix(in srgb, var(--ink) 22%, transparent);
  }
  @media (prefers-reduced-motion: reduce) {
    body .shell > .gd-bar,
    body .gd-pal {
      animation: none;
    }
  }

  /* Rows and tiles answer the pointer. */
  body .shell .asset-row,
  body .shell .tx-row {
    transition: background 0.14s, opacity 0.15s;
  }
  body .shell .action-tile:hover {
    background: var(--glass-2);
    border-color: color-mix(in srgb, var(--ink) 24%, transparent);
  }

  /* The Deposit wizard pins its button to the window's floor so a thumb
     finds it; on a desktop that left a 300px hole between the step and the
     button that confirms it. The button follows its step here. */
  body .shell:has(> nav.bottom-nav) .page.deposit-fit > .cta {
    margin-top: 22px;
  }

  /* The sidebar's rows answer the pointer too. */
  body .shell:has(> nav.bottom-nav) .nav-item:not(.on):hover {
    color: var(--text);
    background: color-mix(in srgb, var(--ink) 4.5%, transparent);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * HOME, AS A DASHBOARD
   *
   * The vault, the verbs under it, the two cards, and the coins as a table on
   * the left; the market and the ledger on the right. The rail is the page's
   * last child in the DOM and is placed here, so the source order a screen
   * reader follows stays vault first.
   *
   * Row gap is zero and each item carries its own margin: the rail spans
   * every row of the left column, and gaps between the implicit empty rows
   * past the last item would each still cost their 16px at the bottom.
   * ══════════════════════════════════════════════════════════════════════ */

  body .shell:has(> nav.bottom-nav) .page:has(> .hr) {
    width: min(1380px, 100%);
    padding-left: 32px;
    padding-right: 32px;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
    column-gap: 24px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > * {
    grid-column: 1;
    margin-bottom: 18px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .vault-card {
    grid-row: auto;
    margin: 0 0 14px;
    min-height: 212px;
  }

  /* The verbs, as a row of four under the balance: the shape Coinbase and
     every desktop wallet gives them, and a width a click finds at once. */
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .actions-row {
    grid-column: 1;
    grid-row: auto;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    grid-auto-rows: auto;
    gap: 12px;
    margin-bottom: 22px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .actions-row .action-tile {
    height: 58px;
    flex-direction: row;
    justify-content: center;
    gap: 11px;
    padding: 0 16px;
    border-radius: 16px;
    font-size: 14px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .actions-row .action-tile .bubble {
    width: 34px;
    height: 34px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .actions-row .action-tile .bubble svg {
    width: 17px;
    height: 17px;
  }

  /* Earn's rate rides the tile's top edge as a badge: beside a centred
     label in a 130px tile it sat on the word itself. */
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .actions-row .action-tile .ern-chip {
    top: -9px;
    left: auto;
    right: 12px;
    transform: none;
    font-size: 10.5px;
    padding: 2px 7px;
  }

  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .section-title {
    margin: 10px 4px 12px;
  }

  /* The rail: under the vault's column while the window is narrow, beside
     it from 1440px, where a 340px column still leaves the vault and its
     five-column table 730. At 1280 beside it, the table's price ran into
     its day. */
  body .shell:has(> nav.bottom-nav) .page > .hr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
    align-items: start;
    margin: 8px 0 0;
  }
  @media (min-width: 1440px) {
    body .shell:has(> nav.bottom-nav) .page:has(> .hr) {
      grid-template-columns: minmax(0, 1fr) 340px;
    }
    body .shell:has(> nav.bottom-nav) .page > .hr {
      grid-column: 2;
      grid-row: 1 / span 40;
      grid-template-columns: minmax(0, 1fr);
      /* its own height, not the forty rows it spans: a stretched item has
         nothing to stick with */
      align-self: start;
      position: sticky;
      top: calc(var(--gd-bar) + 24px);
      margin: 0;
    }
  }
  @media (min-width: 1600px) {
    body .shell:has(> nav.bottom-nav) .page:has(> .hr) {
      grid-template-columns: minmax(0, 1fr) 390px;
    }
  }

  body .hr-card {
    padding: 14px 12px 10px;
    border-radius: 20px;
    background: var(--gd-card);
    border: 1px solid var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
  }
  body .hr-h {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 2px 8px 10px;
  }
  body .hr-h b {
    font-family: var(--font-display);
    font-size: 15.5px;
    font-weight: 700;
    letter-spacing: -0.1px;
    color: var(--text);
  }
  body .hr-h > span {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .hr-all {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 4px 6px 4px 10px;
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text-dim);
    transition: background 0.14s, color 0.14s;
  }
  body .hr-all:hover {
    background: var(--gd-hover);
    color: var(--text);
  }
  body .hr-none {
    padding: 22px 10px 24px;
    text-align: center;
    color: var(--text-faint);
    font-size: 13px;
  }

  body .hr-mkt {
    width: 100%;
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) 72px minmax(88px, auto);
    align-items: center;
    gap: 12px;
    padding: 9px 8px;
    border-radius: 12px;
    text-align: left;
    transition: background 0.14s;
  }
  body .hr-mkt:hover { background: var(--gd-hover); }
  body .hr-mkt .token-icon { width: 32px; height: 32px; }
  body .hr-mkt-m {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
  }
  body .hr-mkt-m b { font-size: 14px; font-weight: 700; color: var(--text); }
  body .hr-mkt-m i {
    font-style: normal;
    font-size: 12px;
    color: var(--text-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body .hr-spark {
    display: block;
    width: 72px;
    height: 26px;
    overflow: visible;
  }
  body .hr-spark.up { color: var(--gd-up); }
  body .hr-spark.down { color: var(--gd-down); }
  body .hr-spark.empty {
    height: 1px;
    align-self: center;
    background: var(--stroke-soft);
  }
  body .hr-mkt-p {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
  }
  body .hr-mkt-p b { font-size: 13.5px; font-weight: 700; color: var(--text); }
  body .hr-mkt-p i { font-style: normal; font-size: 12px; font-weight: 700; }
  body .hr-mkt-p i.up { color: var(--gd-up); }
  body .hr-mkt-p i.down { color: var(--gd-down); }
  body .hr-mkt-p i.flat { color: var(--text-faint); }

  /* The ledger rows as the Activity screen draws them, a size down. */
  body .hr-list .tx-row {
    width: 100%;
    gap: 11px;
    padding: 10px 8px;
    border-radius: 12px;
    border-bottom: 0;
  }
  body .hr-list .tx-row:hover { background: var(--gd-hover); }
  body .hr-list .tx-row .meta .l2 { font-size: 13.5px; }
  body .hr-list .tx-row .right b { font-size: 13.5px; }

  /* ── the coins, as a table ────────────────────────────────────────────── */

  body .shell .asset-list.as-table {
    display: grid;
    grid-template-columns: 54px minmax(140px, 1.7fr) minmax(90px, 1fr) minmax(64px, 0.8fr) minmax(0, 1.1fr) minmax(96px, 1.1fr);
    column-gap: 16px;
    padding: 4px 10px 8px;
    border-radius: 20px;
    background: var(--gd-card);
    border-color: var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
  }
  body .shell .asset-list.as-table > .as-head,
  body .shell .asset-list.as-table > .asset-row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    align-items: center;
  }
  body .shell .asset-list.as-table > .as-head {
    padding: 12px 12px 10px;
    border-bottom: 1px solid var(--stroke-soft);
    color: var(--text-faint);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
  }
  body .shell .asset-list.as-table > .as-head > span:first-child { grid-column: 1 / 3; }
  body .shell .asset-list.as-table > .as-head > span:last-child { text-align: right; }
  body .shell .asset-list.as-table > .asset-row {
    padding: 12px 12px;
    margin: 2px 0 0;
    border-radius: 14px;
    border-bottom: 0;
  }
  body .shell .asset-list.as-table > .asset-row:hover { background: var(--gd-hover); }
  body .shell .asset-list.as-table > .asset-row + .asset-row {
    box-shadow: 0 -1px 0 var(--stroke-soft);
  }
  body .shell .asset-list.as-table > .asset-row:hover,
  body .shell .asset-list.as-table > .asset-row:hover + .asset-row {
    box-shadow: none;
  }
  /* the table has a column for the day, so the chip beside the name goes */
  body .shell .asset-list.as-table .meta .as-ch { display: none; }
  body .shell .asset-list.as-table .as-px,
  body .shell .asset-list.as-table .as-24 {
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
  }
  body .shell .asset-list.as-table .ern-row .as-px { color: var(--success); font-weight: 700; }
  body .shell .asset-list.as-table .as-24 i { font-style: normal; font-weight: 700; }
  body .shell .asset-list.as-table .as-24 .up { color: var(--gd-up); }
  body .shell .asset-list.as-table .as-24 .down { color: var(--gd-down); }
  body .shell .asset-list.as-table .as-24 .flat { color: var(--text-faint); }
  body .shell .as-alloc {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
  }
  body .shell .as-alloc-bar {
    flex: 1;
    max-width: 110px;
    height: 6px;
    border-radius: 99px;
    background: var(--stroke-soft);
    overflow: hidden;
  }
  body .shell .as-alloc-bar > i {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, color-mix(in srgb, var(--ink) 55%, transparent), var(--ink));
  }
  /* Under 1100px the column is 650px: the share goes, and the bar above the
     vault's figure still shows the split. */
  @media (max-width: 1099px) {
    body .shell .asset-list.as-table {
      grid-template-columns: 54px minmax(130px, 1.7fr) minmax(90px, 1fr) minmax(64px, 0.8fr) minmax(96px, 1.1fr);
    }
    body .shell .asset-list.as-table > .as-head > span:nth-child(4),
    body .shell .asset-list.as-table .as-alloc {
      display: none;
    }
  }
  body .shell .as-alloc > b {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
    min-width: 34px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * SWAP, WITH ITS MARKET
   * ══════════════════════════════════════════════════════════════════════ */

  /* One grid for the whole Trade page: the market down the left from the
     very top, and the Swap | Perps switch, the heading and the ticket down
     the right. The switch lives outside the swap's .page (it belongs to the
     Trade page), so the .page steps aside with display: contents and its
     children join this grid; everything it holds that is not the market is
     fixed-position (sheets, the limit screen) or goes down the right. */
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) {
    width: min(1320px, 100%);
    padding: 26px 32px 72px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 440px;
    column-gap: 28px;
    row-gap: 0;
    align-items: start;
  }
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > *,
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .page.xd > * {
    grid-column: 2;
  }
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .page.xd {
    display: contents;
  }
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .page.xd > .swm {
    grid-column: 1;
    grid-row: 1 / span 40;
    align-self: start;
  }
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .trade-seg {
    width: auto;
    max-width: none;
    margin: 0 0 14px;
  }
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .seg-hint {
    margin: -4px 0 8px;
  }
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) .page.xd > .page-h1 {
    margin-top: 6px;
  }

  body .swm {
    display: flex;
    flex-direction: column;
    padding: 20px 22px 18px;
    border-radius: 22px;
    background: var(--gd-card);
    border: 1px solid var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
    position: sticky;
    top: calc(var(--gd-bar) + 24px);
  }
  body .swm-h {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  body .swm-pair {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
  }
  body .swm-icons {
    position: relative;
    width: 46px;
    height: 38px;
    flex: none;
  }
  body .swm-icons > :first-child .token-icon,
  body .swm-icons > .token-icon:first-child { width: 34px; height: 34px; }
  body .swm-icons > :last-child {
    position: absolute;
    right: 0;
    bottom: 0;
  }
  body .swm-icons > :last-child .token-icon,
  body .swm-icons > .token-icon:last-child {
    width: 22px;
    height: 22px;
    box-shadow: 0 0 0 2.5px var(--gd-card);
  }
  body .swm-name {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
  }
  body .swm-name b {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -0.3px;
    color: var(--text);
  }
  body .swm-name b em {
    font-style: normal;
    color: var(--text-faint);
    font-weight: 600;
  }
  body .swm-name i {
    font-style: normal;
    font-size: 12.5px;
    color: var(--text-faint);
  }
  body .swm-spans {
    display: inline-flex;
    padding: 3px;
    gap: 2px;
    border-radius: 11px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
  }
  body .swm-spans button {
    height: 28px;
    padding: 0 12px;
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text-dim);
  }
  body .swm-spans button.on {
    background: var(--ink);
    color: var(--cta-text);
  }
  body .swm-fig {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin: 16px 0 6px;
    font-variant-numeric: tabular-nums;
  }
  body .swm-fig > b {
    font-family: var(--font-display);
    font-size: 36px;
    font-weight: 700;
    letter-spacing: -1px;
    color: var(--text);
  }
  body .swm-fig > span { font-size: 15px; font-weight: 700; color: var(--text-dim); }
  body .swm-fig > em {
    font-style: normal;
    font-size: 13.5px;
    font-weight: 800;
    padding: 3px 8px;
    border-radius: 8px;
  }
  body .swm-fig > em.up { color: var(--gd-up); background: color-mix(in srgb, var(--gd-up) 12%, transparent); }
  body .swm-fig > em.down { color: var(--gd-down); background: color-mix(in srgb, var(--gd-down) 12%, transparent); }
  body .swm-fig > i { font-style: normal; font-size: 12.5px; color: var(--text-faint); }

  body .swm-chart {
    position: relative;
    height: 300px;
    margin: 4px -6px 0 0;
    color: var(--gd-up);
  }
  body .swm-chart.down { color: var(--gd-down); }
  body .swm-chart svg { display: block; overflow: visible; cursor: crosshair; }
  body .swm-chart .swm-grid line { stroke: var(--stroke-soft); stroke-dasharray: 2 4; }
  body .swm-chart text {
    fill: var(--text-faint);
    font: 600 11px var(--font);
    font-variant-numeric: tabular-nums;
  }
  body .swm-chart .swm-now { stroke: currentColor; stroke-opacity: 0.45; stroke-dasharray: 3 4; }
  body .swm-chart .swm-tag rect { fill: currentColor; }
  body .swm-chart .swm-tag text { fill: var(--bg); font-weight: 800; }
  body .swm-chart .swm-hair line { stroke: var(--text-dim); stroke-opacity: 0.5; stroke-dasharray: 3 3; }
  body .swm-chart .swm-hair circle { fill: currentColor; stroke: var(--gd-card); stroke-width: 2.5; }
  body .swm-tip {
    position: absolute;
    top: 6px;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    padding: 6px 10px;
    border-radius: 10px;
    background: var(--sheet-solid);
    border: 1px solid var(--stroke);
    box-shadow: 0 12px 28px -12px rgba(0, 0, 0, 0.6);
    pointer-events: none;
    white-space: nowrap;
  }
  body .swm-tip b { font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums; }
  body .swm-tip span { font-size: 11px; color: var(--text-faint); }
  body .swm-chart.swm-empty {
    display: grid;
    place-items: center;
    color: var(--text-faint);
    font-size: 13.5px;
    border-radius: 14px;
    background: var(--glass);
    /* where the line will stand, so nothing jumps when it arrives */
    margin: 4px 0 0;
  }

  body .swm-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin: 14px 0 0;
    padding: 14px 0 0;
    border-top: 1px solid var(--stroke-soft);
  }
  body .swm-stats > span {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 0 14px;
    min-width: 0;
    border-left: 1px solid var(--stroke-soft);
    font-variant-numeric: tabular-nums;
  }
  body .swm-stats > span:first-child { padding-left: 0; border-left: 0; }
  body .swm-stats i {
    font-style: normal;
    font-size: 11.5px;
    color: var(--text-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body .swm-stats b { font-size: 15px; font-weight: 700; color: var(--text); }
  body .swm-stats u { text-decoration: none; font-size: 11.5px; color: var(--text-dim); }

  body .swm-quick {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 18px 0 0;
  }
  body .swm-quick-l {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-right: 4px;
  }
  body .swm-quick button {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 34px;
    padding: 0 12px 0 8px;
    border-radius: 11px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
    transition: background 0.14s, border-color 0.14s;
  }
  body .swm-quick button .token-icon { width: 18px; height: 18px; box-shadow: none; }
  body .swm-quick button em { font-style: normal; color: var(--text-faint); font-weight: 600; margin-left: -4px; }
  body .swm-quick button:hover { background: var(--glass-2); border-color: var(--stroke); }
  body .swm-quick button.on { border-color: color-mix(in srgb, var(--ink) 45%, transparent); background: var(--glass-2); }
  body .swm-foot {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 16px 0 0;
    color: var(--text-faint);
    font-size: 12px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * ACTIVITY, AS A LEDGER
   * ══════════════════════════════════════════════════════════════════════ */

  /* Not Home: its rail lists ledger rows too, and matching them here
     squeezed the whole dashboard into the ledger's 920px. */
  body .shell:has(> nav.bottom-nav) .page:has(.afr):not(:has(> .hr)),
  body .shell:has(> nav.bottom-nav) .page:has(.tx-row):not(:has(> .hr)) {
    width: min(920px, 100%);
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .asset-list {
    padding: 6px 10px 10px;
    border-radius: 20px;
    background: var(--gd-card);
    border-color: var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row {
    width: 100%;
    gap: 15px;
    padding: 13px 14px;
    border-radius: 14px;
    border-bottom: 0;
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row + .tx-row {
    box-shadow: 0 -1px 0 var(--stroke-soft);
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row:hover,
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row:hover + .tx-row {
    box-shadow: none;
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row:hover { background: var(--gd-hover); }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-day {
    padding: 16px 14px 6px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.3px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-day:first-child { padding-top: 10px; }
  /* the filters stay in reach while the ledger scrolls */
  body .shell:has(> .gd-bar) .page:has(.afr) .afr {
    position: sticky;
    top: var(--gd-bar);
    z-index: 5;
    padding: 10px 0;
    margin-top: -10px;
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * GIFTS, AS A STOREFRONT
   *
   * The vitrine (.page.gifts.gv) had no desktop rules (the old 4-up shelf
   * was written for a .gift-grid that no longer renders), so on a desktop it
   * was still the phone's two cases across 880px: 407px cards for art drawn
   * at 180. Here it is a storefront: as many cases as the width holds.
   *
   * The page's width, its toolbar and its cart, and the cases' hover, are the
   * Explore snippet's at the end of this file (the cart lives in the toolbar
   * on a desktop, so there are no floating buttons to keep a gutter for).
   * ══════════════════════════════════════════════════════════════════════ */
  body .shell:has(> nav.bottom-nav) .page.gv .gv-grid {
    grid-template-columns: repeat(auto-fill, minmax(188px, 1fr));
    gap: 14px;
  }
  body .shell:has(> nav.bottom-nav) .page.gv.gv-tight .gv-grid {
    grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
    gap: 10px;
  }
  body .shell .gv-card {
    transition: translate 0.2s cubic-bezier(0.2, 0, 0, 1), border-color 0.18s, box-shadow 0.25s;
  }
  /* The collections rail stays one row, as a carousel with its scrollbar
     showing: a desktop reads a hidden overflow as the end of the list. The
     fade at the right edge says there is more. */
  body .shell .gv-rail.no-scrollbar {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--ink) 22%, transparent) transparent;
    mask-image: linear-gradient(90deg, #000 calc(100% - 48px), transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 48px), transparent);
    padding-bottom: 14px;
  }
  body .shell .gv-rail.no-scrollbar::-webkit-scrollbar {
    display: block;
    height: 6px;
  }
  body .shell .gv-rail.no-scrollbar::-webkit-scrollbar-thumb {
    border-radius: 99px;
    background: color-mix(in srgb, var(--ink) 22%, transparent);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE GATE, AS A LANDING
   *
   * The first thing a desktop visitor sees before connecting. A phone's gate
   * is a mark, a line and a button at the thumb; here it is a page: the
   * brand across the top, what this is and the button on the left, and the
   * vault as it will look on the right (components/GateShowcase). The words
   * and chips beside the title render at this width only.
   * ══════════════════════════════════════════════════════════════════════ */

  /* the brand, over the gate rather than under it */
  body .shell:has(> .gate) > .topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 33;
    height: 76px;
    padding: 0 40px;
    background: none;
  }
  body .shell:has(> .gate) > .topbar .brand-logo {
    width: 34px;
    height: 34px;
    border-radius: 11px;
  }

  body .gate:has(> .gate-show) {
    display: grid;
    grid-template-columns: minmax(0, 520px) minmax(0, 540px);
    grid-template-rows: auto auto auto;
    justify-content: center;
    align-content: center;
    column-gap: clamp(40px, 6vw, 96px);
    row-gap: 0;
    padding: 96px 48px 64px;
    text-align: left;
    overflow: hidden;
    background:
      radial-gradient(900px 520px at 78% 42%, color-mix(in srgb, var(--ink) 7%, transparent), transparent 70%),
      radial-gradient(700px 480px at 12% 88%, color-mix(in srgb, var(--success) 6%, transparent), transparent 70%),
      var(--bg);
  }
  body .gate:has(> .gate-show) > .gate-body {
    grid-column: 1;
    grid-row: 1;
    flex: none;
    align-items: flex-start;
    justify-content: flex-end;
  }
  body .gate:has(> .gate-show) .gate-mark {
    width: 64px;
    height: 64px;
    margin-bottom: 26px;
    border-radius: 18px;
  }
  body .gate .gate-eyebrow {
    font-style: normal;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 2.2px;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: 14px;
  }
  body .gate:has(> .gate-show) .gate-title {
    font-size: clamp(38px, 3.6vw, 54px);
    line-height: 1.05;
    letter-spacing: -1.4px;
    text-wrap: balance;
  }
  body .gate .gate-sub {
    margin: 18px 0 0;
    max-width: 38ch;
    font-size: 17px;
    line-height: 1.5;
    color: var(--text-dim);
  }
  body .gate .gate-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 22px;
  }
  body .gate .gate-chips > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 12px;
    border-radius: 999px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
    font-size: 12px;
    font-weight: 700;
  }
  body .gate:has(> .gate-show) > .gate-cta {
    grid-column: 1;
    grid-row: 2;
    justify-self: start;
    width: auto;
    max-width: none;
    min-width: 240px;
    margin: 34px 0 0;
    padding: 18px 40px;
  }
  body .gate:has(> .gate-show) > .get-app {
    grid-column: 1;
    grid-row: 3;
    justify-self: start;
    margin: 16px 0 0 4px;
  }

  body .gate > .gate-show {
    grid-column: 2;
    grid-row: 1 / span 3;
    align-self: center;
    position: relative;
    height: 440px;
    display: grid;
    place-items: center;
  }
  body .gate-show .gs-glow {
    position: absolute;
    inset: 12% 8%;
    border-radius: 50%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--ink) 16%, transparent), transparent);
    filter: blur(20px);
  }
  body .gate-show .gs-card {
    position: relative;
    width: min(420px, 100%);
    padding: 26px 28px 24px;
    border-radius: 28px;
    text-align: left;
    background:
      linear-gradient(var(--bg-elev), var(--bg-elev)) padding-box,
      linear-gradient(150deg, color-mix(in srgb, var(--ink) 60%, transparent), color-mix(in srgb, var(--ink) 10%, transparent) 38%, color-mix(in srgb, var(--ink) 5%, transparent) 60%, color-mix(in srgb, var(--ink) 42%, transparent)) border-box;
    border: 1.5px solid transparent;
    box-shadow: 0 50px 90px -40px rgba(0, 0, 0, 0.8);
    transform: perspective(1200px) rotateY(-9deg) rotateX(5deg);
    animation: gsFloat 7s ease-in-out infinite;
  }
  @keyframes gsFloat {
    0%, 100% { translate: 0 0; }
    50% { translate: 0 -10px; }
  }
  body .gate-show .gs-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  body .gate-show .gs-lab {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.8px;
    color: var(--text-faint);
  }
  body .gate-show .gs-eye {
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border-radius: 11px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
  }
  body .gate-show .gs-bal {
    margin: 20px 0 18px;
    font-family: var(--font-display);
    font-size: 54px;
    font-weight: 700;
    letter-spacing: -1px;
    line-height: 1;
    color: var(--text);
  }
  body .gate-show .gs-bal sup {
    font-size: 26px;
    vertical-align: top;
    margin-right: 2px;
    color: var(--text-dim);
  }
  body .gate-show .gs-bal em {
    font-style: normal;
    color: var(--text-faint);
  }
  body .gate-show .gs-bar {
    display: flex;
    gap: 4px;
    height: 6px;
    margin-bottom: 20px;
  }
  body .gate-show .gs-bar i {
    border-radius: 99px;
    background: var(--c);
  }
  body .gate-show .gs-bar i:nth-child(1) { flex: 34; --c: #f7931a; }
  body .gate-show .gs-bar i:nth-child(2) { flex: 28; --c: #2775ca; }
  body .gate-show .gs-bar i:nth-child(3) { flex: 22; --c: var(--success); }
  body .gate-show .gs-bar i:nth-child(4) { flex: 16; --c: color-mix(in srgb, var(--ink) 30%, transparent); }
  body .gate-show .gs-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 12px;
    border-radius: 999px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
    font-size: 12.5px;
    font-weight: 600;
  }
  body .gate-show .gs-chip {
    position: absolute;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 16px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--bg-elev-2) 88%, transparent);
    border: 1px solid var(--stroke);
    color: var(--text);
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
    box-shadow: 0 20px 40px -24px rgba(0, 0, 0, 0.8);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    animation: gsFloat 6s ease-in-out infinite;
  }
  body .gate-show .gs-chip svg { color: var(--text-dim); }
  body .gate-show .gs-c1 { top: 8%; right: 2%; animation-delay: -1.2s; }
  body .gate-show .gs-c2 { bottom: 12%; left: 0; animation-delay: -3s; }
  body .gate-show .gs-c3 { bottom: 2%; right: 10%; animation-delay: -4.6s; }
  :root[data-theme="light"] body .gate-show .gs-card {
    box-shadow: 0 50px 90px -40px rgba(20, 25, 32, 0.35);
  }
  @media (prefers-reduced-motion: reduce) {
    body .gate-show .gs-card,
    body .gate-show .gs-chip {
      animation: none;
    }
  }
  /* Under 1100px the picture goes and the words keep the column. */
  @media (max-width: 1099px) {
    body .gate > .gate-show {
      display: none;
    }
    body .gate:has(> .gate-show) {
      grid-template-columns: minmax(0, 560px);
    }
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE AUDIT PASS (2026-09-28)
   *
   * An audit of every surface at desktop width found what the first pass had
   * left or broken. The rules below answer the ones in the lead's own files:
   * the dashboard, the table, the Trade page, the header's neighbours. The
   * other surfaces' fixes follow this block, each under its own heading.
   * ══════════════════════════════════════════════════════════════════════ */

  /* Sheets do not portal: a sheet opened from Home is a direct child of the
     dashboard's .page, and `> *` gave its fixed, inset-0 backdrop an 18px
     bottom margin, which comes straight off its height: a strip at the foot
     of the window stayed undimmed and clickable. */
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > :is(.sheet-backdrop, .sheet) {
    margin: 0;
  }

  /* A receipt opened from the rail renders inside the rail, and a sticky rail
     is its own stacking context, so the receipt painted under the header and
     the sidebar. While one is open the rail rises above them. */
  body .shell:has(> nav.bottom-nav) .page > .hr:has(> .sheet-backdrop) {
    z-index: 3401;
  }

  /* 1280-1439, the common laptop: the rail beside the vault as well, 320px
     wide and without the sparklines, over a five-column table (the share
     column goes; the vault card's bar still shows the split). It does not
     stick: it is taller than a 768px laptop's window. */
  @media (min-width: 1280px) and (max-width: 1439px) {
    body .shell:has(> nav.bottom-nav) .page:has(> .hr) {
      grid-template-columns: minmax(0, 1fr) 320px;
    }
    body .shell:has(> nav.bottom-nav) .page > .hr {
      grid-column: 2;
      grid-row: 1 / span 40;
      grid-template-columns: minmax(0, 1fr);
      align-self: start;
      margin: 0;
    }
    body .hr-mkt {
      grid-template-columns: 32px minmax(0, 1fr) minmax(88px, auto);
    }
    body .hr-mkt .hr-spark {
      display: none;
    }
    body .shell .asset-list.as-table {
      grid-template-columns: 54px minmax(130px, 1.7fr) minmax(90px, 1fr) minmax(64px, 0.8fr) minmax(96px, 1.1fr);
    }
    body .shell .asset-list.as-table > .as-head > span:nth-child(4),
    body .shell .asset-list.as-table .as-alloc {
      display: none;
    }
  }
  /* A short window: the sticky rail would hide its own foot. It scrolls with
     the page instead. */
  @media (min-width: 1440px) and (max-height: 879px) {
    body .shell:has(> nav.bottom-nav) .page > .hr {
      position: static;
    }
  }

  /* The table's first cell hugs its icon, so a coin's network badge sits on
     the coin's corner again rather than inside its face (the subgrid row's
     padding had squeezed the 46px track to 34). */
  body .shell .asset-list.as-table > .asset-row > :first-child {
    justify-self: start;
  }
  body .shell .asset-list.as-table > .skel-row {
    grid-column: 1 / -1;
    padding: 12px;
  }

  /* The rail's agent faces and gift thumbnails at the rail's icon size. */
  body .hr-list .tx-agent,
  body .hr-list .tx-gift-thumb {
    width: 34px;
    height: 34px;
  }

  /* The trading and Gram tiles: the phone's 10-12px captions under a 26px
     figure read as a phone tile stretched to 450px. Desktop sizes, and the
     row's own spacing instead of the phone's 12px top margin on top of the
     actions' 22px. */
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > :is(.pair-row, .ext-card) {
    margin-top: 0;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row {
    gap: 16px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row > :is(.perps-card, .gx-card) {
    min-height: 136px;
    padding: 18px 20px 16px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row :is(.vault-label, .gx-label) {
    font-size: 11.5px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row .perps-sub {
    font-size: 13px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row .gx-text {
    font-size: 13.5px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row :is(.perps-chip, .perps-go, .gx-go) {
    font-size: 13px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row .pub-pill {
    font-size: 10px;
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .pair-row:not(:has(> .perps-card)) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  body .shell:has(> nav.bottom-nav) .page:has(> .hr) > .ext-card .ext-head span {
    font-size: 13px;
  }

  /* One eye: the header's. The vault card's own would be the same toggle
     twice on one screen. */
  body .shell:has(> .gd-bar) .vault-card .card-eye {
    display: none;
  }

  /* The desktop list's padding reached into sheets (they render inside
     .shell) and indented their lists 22px past their own headings. */
  body .shell:has(> nav.bottom-nav) .sheet .asset-list {
    padding: 0;
    border-radius: 0;
  }
  body .shell:has(> nav.bottom-nav) .sheet .asset-row {
    padding: 12px 8px;
    border-radius: 12px;
  }
  @media (hover: hover) {
    body .shell .sheet .trending-tile:hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 24%, transparent);
    }
    body .lxm-row:hover {
      background: var(--gd-hover);
    }
  }

  /* ── the sidebar head with the wallet switch ────────────────────────────
     With the Gram wallet offered the head is two rows (128px), and its rule
     sat 64px below the header's. The brand keeps a header-height band with
     the rule under it, so the line runs across the window at 64px, and the
     switch sits centred in the band below. */
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar:has(.wsw) {
    justify-content: flex-start;
    gap: 0;
  }
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar:has(.wsw) > .brand {
    flex: none;
    height: var(--gd-bar);
    margin: 0 -16px;
    padding: 0 16px;
    border-bottom: 1px solid var(--gd-side-line);
  }
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar:has(.wsw) > .topbar-actions {
    flex: 1;
    align-items: center;
  }

  /* The sidebar's corner is the app's mark on a desktop, and it goes Home
     (App.tsx); who you are is the header's chip. The face stays in the DOM,
     unseen, because the beta suites find the header by .brand-logo. */
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar .brand.you .you-face {
    position: absolute;
    opacity: 0;
    pointer-events: none;
  }
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar .brand.you::before {
    content: '';
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    border: 1px solid var(--stroke);
    background: url(/ghost.png) center / cover;
  }
  body .shell:has(> .gd-bar):has(> nav.bottom-nav) > .topbar .brand.you:hover .brand-name {
    color: var(--text);
  }

  /* ── Trade ──────────────────────────────────────────────────────────────
     The desktop's three tabs (App.tsx renders .trade-seg.three at this
     width): Swap, Limit and Perps side by side. */
  body .shell .trade-seg.three {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  body .shell .trade-seg.three button:not(.on):hover {
    color: var(--text);
    background: var(--glass);
  }
  body .shell .trade-seg.three button.on {
    color: var(--text);
  }

  /* The swap's page steps aside (display: contents) for the two-pane grid,
     and its entrance went with it; the Trade page fades in instead. */
  body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) {
    animation: fadeIn 0.28s cubic-bezier(0.25, 0.8, 0.3, 1);
  }
  @media (prefers-reduced-motion: reduce) {
    body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) {
      animation: none;
    }
  }
  /* Under 1280px the market column was crushed to 175px beside a 440px
     ticket. The ticket takes the column alone, centred, and the market sits
     under it, full width. */
  @media (max-width: 1279px) {
    body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) {
      width: min(640px, 100%);
      grid-template-columns: minmax(0, 1fr);
    }
    body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > *,
    body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .page.xd > * {
      grid-column: 1;
    }
    body .shell:has(> nav.bottom-nav) > .trade-page:has(.swm) > .page.xd > .swm {
      grid-row: auto;
      order: 1;
      position: static;
      margin-top: 22px;
    }
  }
  body .swm-name b {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body .swm-name {
    min-width: 0;
  }

  /* The ticket answers the pointer, not only the thumb. */
  @media (hover: hover) {
    body .shell .xd-coin:hover {
      background: var(--bg-elev-3);
      border-color: color-mix(in srgb, var(--ink) 28%, transparent);
    }
    body .shell .xd-quick button:hover,
    body .shell .slip-chip:hover,
    body .shell .usd-toggle:hover {
      color: var(--text);
      border-color: var(--stroke);
    }
    body .shell .xd-rotor:hover {
      filter: brightness(1.12);
    }
  }
  body .shell .xd-quick button {
    padding: 5px 10px;
    font-size: 12px;
  }

  /* ── the verify-your-wallet screen ─────────────────────────────────────
     A reading-width card, not the phone's empty state across 880px. */
  body .shell:has(> nav.bottom-nav) > .page.wgate {
    width: min(560px, 100%);
    padding-top: 12vh;
  }

  /* The gate's extras fade in with its title (App.tsx gives them gate-fade):
     the same transition, the same wait. */
  body .gate .gate-eyebrow,
  body .gate .gate-chips,
  body .gate > .gate-show {
    transition: opacity 0.22s ease;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE SIDEBAR NEVER LEAVES FOR A KEYBOARD
   *
   * App.tsx watches for a phone's keyboard by the window's height: a drop of
   * 140px from the tallest it has seen sets body.kb-open, which takes the
   * floating nav and the activity dock off screen so they cannot hang over a
   * field being typed into. A desktop window meets that test whenever it is
   * made shorter, or DevTools is docked along its bottom, and the whole
   * sidebar nav and the dock went with it. Here the nav is a column down the
   * left edge that nothing types under, so it stays.
   * ══════════════════════════════════════════════════════════════════════ */
  body.kb-open .shell:has(> nav.bottom-nav) > nav.bottom-nav {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
  }
  body.kb-open:has(.shell > nav.bottom-nav) .dock,
  body.kb-open:has(.shell > nav.bottom-nav) .dock-puck {
    display: flex;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * PERPS: the price never breaks over two lines
   * ══════════════════════════════════════════════════════════════════════ */
  body .pp-root .pp-last {
    flex: none;
  }
  body .pp-root .pp-last .pp-big {
    white-space: nowrap;
  }
}

/* =============================================================================
 * THE COIN PAGE (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* ═══════════════════════════════════════════════════════════════════════════
 * A COIN, AS A DESKTOP'S COIN PAGE
 *
 * Every row of the coin table opens a coin's own page (VaultAssetSheet for the
 * vault, TokenSheet for the Gram wallet, both built from AssetSheet's parts).
 * On a phone that page is a column: the hero centred, round keys under it, a
 * short chart, the figures, the history, one under another. Put in the
 * desktop's 540px modal it stayed a phone's column, with a 132px chart and
 * keys at the size of a thumb.
 *
 * Here it is a wide modal laid out as a desktop coin page. The hero runs
 * across the top: the face, where the coin lives, the holding and its value
 * on the left, the verbs as a row of buttons on the right. Under it the price
 * sits large on the left with its line at 280px (PriceCard asks PriceChart
 * for that height, and for its pointer readout, only at this width), and the
 * coin's figures and this wallet's history stand on the right. In a window
 * tall enough to hold it, the price card stays in view while the right column
 * scrolls past it.
 *
 * The cards are placed by classes only a desktop renders (tk-pc, tk-info,
 * tk-log), not by their order, so both wallets land the same way. Rows 2 and
 * 3 are auto and 1fr: when the price card is the taller side, the slack goes
 * under the history rather than opening a gap between the two right cards.
 *
 * styles.css is emitted after this file, so every rule here out-ranks its
 * phone counterpart on specificity; none of them needs !important.
 * ════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px) {
  /* ── the modal ─────────────────────────────────────────────────────────── */

  /* (0,3,1) against the generic `body .sheet` (0,1,1): only a sheet whose
     body holds a coin page widens. A receipt opened from its history is a
     sheet of its own and keeps the 540px every other modal has. */
  body .sheet:has(> .sheet-body > .tk) {
    max-width: min(1040px, calc(100vw - 80px));
    max-height: min(88vh, 960px);
    padding: 22px 28px 24px;
  }

  body .sheet-body > .tk {
    display: grid;
    grid-template-columns: minmax(0, 1.45fr) minmax(320px, 1fr);
    grid-template-rows: auto auto 1fr;
    column-gap: 18px;
    row-gap: 16px;
    align-items: start;
    padding-bottom: 2px;
  }

  /* ── the hero, across the top ──────────────────────────────────────────── */

  body .sheet-body > .tk > .tk-hero {
    grid-column: 1 / -1;
    grid-row: 1;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: auto auto auto;
    column-gap: 20px;
    align-items: center;
    justify-items: start;
    text-align: left;
    padding: 2px 2px 20px;
    border-bottom: 1px solid var(--stroke-soft);
  }
  body .sheet-body > .tk > .tk-hero > .tk-face {
    grid-column: 1;
    grid-row: 1 / span 3;
    align-self: center;
  }
  body .sheet-body > .tk > .tk-hero > .tk-zone {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
    font-size: 11px;
  }
  body .sheet-body > .tk > .tk-hero > .tk-amount {
    grid-column: 2;
    grid-row: 2;
    margin-top: 10px;
    justify-content: flex-start;
    gap: 8px;
  }
  body .sheet-body > .tk > .tk-hero > .tk-amount b { font-size: 40px; }
  body .sheet-body > .tk > .tk-hero > .tk-amount span,
  body .sheet-body > .tk > .tk-hero > .tk-amount i { font-size: 26px; }
  body .sheet-body > .tk > .tk-hero > .tk-usd {
    grid-column: 2;
    grid-row: 3;
    margin-top: 5px;
    font-size: 16.5px;
  }

  /* The verbs, as a desktop's buttons: a row of labelled pills, the icon in a
     small plate at the left. Money moving in and out keeps the lit plate the
     phone's keys wear; the rest are plain. */
  body .sheet-body > .tk > .tk-hero > .tk-actions {
    grid-column: 3;
    grid-row: 1 / span 3;
    align-self: center;
    justify-self: end;
    margin-top: 0;
    gap: 8px;
    flex-wrap: nowrap;
  }
  body .sheet-body > .tk > .tk-hero > .tk-actions > button {
    width: auto;
    height: 44px;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 0 16px 0 6px;
    border-radius: 14px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    box-shadow: var(--gd-card-lit);
    color: var(--text);
    font-size: 14px;
    font-weight: 700;
    letter-spacing: -0.1px;
    white-space: nowrap;
    transition: background 0.14s, border-color 0.14s, transform 0.12s;
  }
  body .sheet-body > .tk > .tk-hero > .tk-actions > button:not(:disabled):active {
    transform: scale(0.97);
    background: var(--glass-2);
    border-color: color-mix(in srgb, var(--ink) 30%, transparent);
  }
  body .sheet-body > .tk > .tk-hero > .tk-actions > button:disabled {
    cursor: not-allowed;
  }
  body .sheet-body > .tk > .tk-hero > .tk-actions > button > .tk-act {
    width: 32px;
    height: 32px;
    border-radius: 10px;
    color: var(--text);
    background: color-mix(in srgb, var(--ink) 7%, transparent);
    border: 0;
    box-shadow: none;
  }
  body .sheet-body > .tk > .tk-hero > .tk-actions > button.key-in > .tk-act,
  body .sheet-body > .tk > .tk-hero > .tk-actions > button.key-out > .tk-act {
    color: var(--cta-text);
    background: var(--grad);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 8px 18px -12px var(--accent-glow);
  }
  body .sheet-body > .tk > .tk-hero > .tk-actions > button > .tk-act svg {
    width: 18px;
    height: 18px;
  }

  /* ── the cards ─────────────────────────────────────────────────────────── */

  body .sheet-body > .tk > .tk-card {
    margin-top: 0;
    min-width: 0;
    padding: 16px 18px 18px;
    border-radius: 20px;
    background: var(--glass);
    border-color: var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
  }
  body .sheet-body > .tk > .tk-pc {
    grid-column: 1;
    grid-row: 2 / span 2;
  }
  /* The chart stays in sight while the figures and the history scroll by, but
     only in a window tall enough to show the whole card at once. The card is
     about 480px, 520px when its ranges wrap, and the modal's scrolling area
     is 88vh less about 96px of padding and title; in a shorter window a stuck
     card would keep its High and Low cut off until the very end. */
  @media (min-height: 720px) {
    body .sheet-body > .tk > .tk-pc {
      position: sticky;
      top: 0;
    }
  }
  body .sheet-body > .tk > .tk-info {
    grid-column: 2;
    grid-row: 2;
  }
  body .sheet-body > .tk > .tk-log {
    grid-column: 2;
    grid-row: 3;
  }

  /* each card's name in the desktop's column-header hand */
  body .sheet-body > .tk > .tk-card > .tk-card-head > .tk-k {
    font-size: 11.5px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-faint);
  }

  /* ── the price ─────────────────────────────────────────────────────────── */

  /* The name and the figure on the left, the ranges on the right; when the
     card is too narrow for both (a 1000px window) the ranges drop to a line
     of their own, still at the right, above the chart. */
  body .sheet-body > .tk > .tk-pc {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    column-gap: 16px;
  }
  body .sheet-body > .tk > .tk-pc > .tk-card-head {
    order: 0;
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    flex-wrap: wrap;
    row-gap: 8px;
  }
  body .sheet-body > .tk > .tk-pc > .tk-card-head > .tk-k { flex: 1 0 100%; }
  body .sheet-body > .tk > .tk-pc > .tk-card-head > .tk-price {
    margin-left: 0;
    align-items: center;
    gap: 10px;
  }
  body .sheet-body > .tk > .tk-pc > .tk-card-head > .tk-price b {
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -0.6px;
    line-height: 1.1;
  }
  body .sheet-body > .tk > .tk-pc > .tk-card-head > .tk-price em {
    padding: 3px 8px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
  }
  body .sheet-body > .tk > .tk-pc > .tk-card-head > .tk-price em.up {
    color: var(--gd-up);
    background: color-mix(in srgb, var(--gd-up) 12%, transparent);
  }
  body .sheet-body > .tk > .tk-pc > .tk-card-head > .tk-price em.down {
    color: var(--gd-down);
    background: color-mix(in srgb, var(--gd-down) 12%, transparent);
  }

  /* the ranges as the Swap market's segmented control, compact and at the right */
  body .sheet-body > .tk > .tk-pc > .tk-ranges {
    order: 1;
    flex: none;
    display: inline-flex;
    gap: 2px;
    margin: 8px 0 0 auto;
    padding: 3px;
    border-radius: 11px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
  }
  body .sheet-body > .tk > .tk-pc > .tk-ranges > button {
    flex: none;
    min-width: 34px;
    height: 28px;
    padding: 0 10px;
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text-dim);
  }
  body .sheet-body > .tk > .tk-pc > .tk-ranges > button.on {
    background: var(--ink);
    color: var(--cta-text);
  }
  /* the range's move is said in the strip under the line instead */
  body .sheet-body > .tk > .tk-pc > .tk-ranges > .tk-range-change { display: none; }

  body .sheet-body > .tk > .tk-pc > .pc,
  body .sheet-body > .tk > .tk-pc > .pc-empty {
    order: 2;
    flex: 1 0 100%;
    min-width: 0;
    margin-top: 16px;
  }
  /* The placeholder a range shows while it loads keeps the room of the dates
     line it stands in for (8px over 16px of text, set just below), so the
     card does not jump twice on every range picked. */
  body .sheet-body > .tk > .tk-pc > .pc-empty {
    margin-bottom: 24px;
    border-radius: 14px;
    background: var(--glass);
    font-size: 13.5px;
  }
  body .sheet-body > .tk > .tk-pc > .pc .pc-marks {
    padding: 8px 2px 0;
    font-size: 12px;
    line-height: 16px;
  }

  /* The pointer readout (PriceChart's `readout`): a crosshair over the line,
     a hairline and a dot on the nearest point, the tag with its figures. */
  body .sheet-body > .tk > .tk-pc > .pc.pc-live {
    position: relative;
    border-radius: 10px;
  }
  body .sheet-body > .tk > .tk-pc > .pc.pc-live svg {
    overflow: visible;
    cursor: crosshair;
    touch-action: pan-y;
  }
  body .sheet-body > .tk > .tk-pc > .pc .pc-hair line {
    stroke: var(--text-dim);
    stroke-opacity: 0.55;
    stroke-width: 1;
    stroke-dasharray: 3 3;
  }
  body .sheet-body > .tk > .tk-pc > .pc .pc-hair circle {
    fill: currentColor;
    stroke: var(--sheet-solid);
    stroke-width: 2.5;
  }
  body .sheet-body > .tk > .tk-pc > .pc > .pc-tip {
    position: absolute;
    z-index: 1;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 6px 10px;
    border-radius: 10px;
    background: var(--sheet-solid);
    border: 1px solid var(--stroke);
    box-shadow: 0 12px 28px -12px rgba(0, 0, 0, 0.6);
    white-space: nowrap;
    pointer-events: none;
  }
  body .sheet-body > .tk > .tk-pc > .pc > .pc-tip b {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
  }
  body .sheet-body > .tk > .tk-pc > .pc > .pc-tip span {
    display: flex;
    gap: 7px;
    font-size: 11.5px;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
  }
  body .sheet-body > .tk > .tk-pc > .pc > .pc-tip em {
    font-style: normal;
    font-weight: 800;
  }

  /* the range in figures, the Swap market's stat strip in miniature */
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats {
    order: 3;
    flex: 1 0 100%;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--stroke-soft);
  }
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats > span {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding: 0 14px;
    border-left: 1px solid var(--stroke-soft);
    font-variant-numeric: tabular-nums;
  }
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats > span:first-child {
    padding-left: 0;
    border-left: 0;
  }
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats i {
    font-style: normal;
    font-size: 11.5px;
    color: var(--text-faint);
  }
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats b {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats b.up { color: var(--gd-up); }
  body .sheet-body > .tk > .tk-pc > .tk-pc-stats b.down { color: var(--gd-down); }

  /* ── what the coin is ──────────────────────────────────────────────────── */

  body .sheet-body > .tk > .tk-info > .tk-desc {
    margin: 12px 0 6px;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-dim);
  }
  body .sheet-body > .tk > .tk-info > .tk-desc.dim { color: var(--text-faint); }
  /* More stands under the text here (AssetSheet), so a fold cannot hide it */
  body .sheet-body > .tk > .tk-info > .tk-more {
    display: inline-flex;
    margin: 0 0 4px -8px;
    padding: 4px 8px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 700;
    color: var(--ink-soft);
    transition: background 0.14s;
  }
  body .sheet-body > .tk > .tk-info > .tk-rows { margin-top: 10px; }
  body .sheet-body > .tk > .tk-info .tk-row {
    padding: 10px 0;
    font-size: 14px;
  }
  body .sheet-body > .tk > .tk-info .tk-row b { font-weight: 700; }

  /* ── what this wallet did with it ──────────────────────────────────────── */

  body .sheet-body > .tk > .tk-log > .tk-card-head > .tk-count {
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--glass-2);
    color: var(--text-dim);
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
  }

  /* The rows reach out to the card's edge by the padding they gain, so the
     hover fills a rounded row while the text stays in line with the card's
     name. Lines between rows are shadows, dropped around the one under the
     pointer, the way the coin table and the Activity ledger draw theirs. */
  body .sheet-body > .tk > .tk-log > .tk-ledger {
    margin: 6px -10px 0;
  }
  body .sheet-body > .tk > .tk-log > .tk-ledger > .tx-row {
    gap: 12px;
    padding: 11px 10px;
    border-radius: 12px;
    border-bottom: 0;
  }
  body .sheet-body > .tk > .tk-log > .tk-ledger > .tx-row + .tx-row {
    box-shadow: 0 -1px 0 var(--stroke-soft);
  }

  body .sheet-body > .tk > .tk-log > .ce-list {
    margin: 2px -10px 0;
  }
  body .sheet-body > .tk > .tk-log > .ce-list .ce-day-label {
    margin: 14px 10px 4px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
  }
  body .sheet-body > .tk > .tk-log > .ce-list .ce-row.tap {
    padding: 10px;
    border-radius: 12px;
    border-bottom: 0;
  }
  /* (0,6,1), under the hover's (0,7,1), so the row under the pointer loses its line */
  body .sheet-body > .tk > .tk-log > .ce-list .ce-row + .ce-row {
    box-shadow: 0 -1px 0 var(--stroke-soft);
  }
  body .sheet-body > .tk > .tk-log > .ce-list > .ce-scam {
    margin: 10px 10px 0;
  }

  /* ── the pointer ───────────────────────────────────────────────────────── */

  @media (hover: hover) {
    body .sheet-body > .tk > .tk-hero > .tk-actions > button:not(:disabled):hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 26%, transparent);
    }
    body .sheet-body > .tk > .tk-hero > .tk-actions > button.key-in:not(:disabled):hover > .tk-act,
    body .sheet-body > .tk > .tk-hero > .tk-actions > button.key-out:not(:disabled):hover > .tk-act {
      filter: brightness(1.07);
    }
    body .sheet-body > .tk > .tk-pc > .tk-ranges > button:not(.on):hover {
      background: var(--gd-hover);
      color: var(--text);
    }
    body .sheet-body > .tk > .tk-info > .tk-more:hover {
      background: var(--gd-hover);
    }
    body .sheet-body > .tk > .tk-log > .tk-ledger > .tx-row:hover,
    body .sheet-body > .tk > .tk-log > .ce-list .ce-row.tap:hover {
      background: var(--gd-hover);
    }
    body .sheet-body > .tk > .tk-log > .tk-ledger > .tx-row:hover,
    body .sheet-body > .tk > .tk-log > .tk-ledger > .tx-row:hover + .tx-row,
    body .sheet-body > .tk > .tk-log > .ce-list .ce-row.tap:hover,
    body .sheet-body > .tk > .tk-log > .ce-list .ce-row.tap:hover + .ce-row {
      box-shadow: none;
    }
  }

  /* ── a narrow desktop ──────────────────────────────────────────────────── */

  /* Under 1200px the modal narrows toward 920px and four verbs take most of
     the hero's row, so the holding steps down a size to stay on one line. */
  @media (max-width: 1199px) {
    body .sheet-body > .tk > .tk-hero > .tk-amount b { font-size: 34px; }
    body .sheet-body > .tk > .tk-hero > .tk-amount span,
    body .sheet-body > .tk > .tk-hero > .tk-amount i { font-size: 22px; }
    body .sheet-body > .tk > .tk-hero > .tk-actions > button { padding-right: 14px; gap: 8px; }
  }
}

/* =============================================================================
 * THE GRAM WALLET, AS A DASHBOARD (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* =============================================================================
 * THE GRAM WALLET, AS A DESKTOP (owner, 2026-09-28)
 *
 * The public Home gets the vault Home's dashboard, so the sidebar's
 * Vault | Gram switch changes what the page holds and not its shape: the
 * card, the four verbs as a row under it, the tokens as the vault's table,
 * and the column beside them (components/GramRail, an aside.hr) with the
 * market and this wallet's latest moves. GramRail and the table's extra cells
 * are mounted at this width only (lib/wide), so a phone never has them.
 *
 * The older public rules above (".page.public-page:has(.pub-card)", from
 * (0,5,2) to (0,8,2)) out-rank the vault's ":has(> .hr)" dashboard, so every
 * rule for the page here adds ":has(> .hr)" to theirs and wins by one class.
 * ========================================================================== */
@media (min-width: 1000px) {
  /* ── the page ───────────────────────────────────────────────────────── */

  /* Row gap zero and each item carrying its own margin, as on the vault's
     Home: the rail spans every row, and the empty implicit rows past the last
     item would each still cost a gap at the bottom. */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) {
    width: min(1380px, 100%);
    padding-left: 32px;
    padding-right: 32px;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
    column-gap: 24px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > * {
    grid-column: 1;
    margin-bottom: 18px;
  }
  /* sheets are fixed to the window and take no part in the grid */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > :is(.sheet, .sheet-backdrop) {
    margin: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .pub-card {
    grid-column: 1;
    grid-row: auto;
    margin: 0 0 14px;
    min-height: 212px;
  }

  /* The verbs, as a row of four under the card, the shape the vault's take. */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .actions-row {
    grid-column: 1;
    grid-row: auto;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    grid-template-rows: none;
    grid-auto-rows: auto;
    gap: 12px;
    margin-bottom: 22px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .actions-row .action-tile {
    height: 58px;
    flex-direction: row;
    justify-content: center;
    gap: 11px;
    padding: 0 16px;
    border-radius: 16px;
    font-size: 14px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .actions-row .action-tile .bubble {
    width: 34px;
    height: 34px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .actions-row .action-tile .bubble svg {
    width: 17px;
    height: 17px;
  }
  /* Earn's rate rides the tile's top edge as a badge, as the vault's does. */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .actions-row .action-tile .ern-chip {
    top: -9px;
    left: auto;
    right: 12px;
    transform: none;
    font-size: 10.5px;
    padding: 2px 7px;
  }

  /* ── the column beside the wallet ───────────────────────────────────── */

  /* Under the wallet while the window is narrow: the way into the vault
     across the top, the market and the ledger side by side under it. The row
     is said outright, so no row given the vault's rail by desktop.css can pin
     this one in the wallet's column above everything else. */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .hr {
    grid-column: 1;
    grid-row: auto;
    margin: 8px 0 18px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact {
    grid-column: 1 / -1;
    margin: 0;
    padding: 14px 16px;
    gap: 12px;
    border-radius: 20px;
    background:
      linear-gradient(135deg, color-mix(in srgb, var(--ink) 7%, transparent), transparent 60%),
      var(--gd-card);
    border: 1px solid var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
    transition: border-color 0.15s, background-color 0.15s;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact:not(:disabled):hover {
    border-color: color-mix(in srgb, var(--ink) 28%, transparent);
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact .pub-vault-ic {
    width: 36px;
    height: 36px;
    border-radius: 12px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact .pub-vault-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact .pub-vault-meta b {
    font-size: 14px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact .pub-vault-meta span {
    font-size: 12.5px;
    white-space: normal;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page > .hr > .pub-vault.compact .route-go {
    color: var(--text-faint);
  }

  /* Beside the wallet from 1280px, the same widths as the vault's column.
     1280-1439, the common laptop: 320px, without the sparklines (desktop.css
     takes them out of every rail at this width), and not sticky, since it is
     taller than a 768px window. */
  @media (min-width: 1280px) and (max-width: 1439px) {
    body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) {
      grid-template-columns: minmax(0, 1fr) 320px;
    }
    body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .hr {
      grid-column: 2;
      grid-row: 1 / span 40;
      grid-template-columns: minmax(0, 1fr);
      align-self: start;
      margin: 0;
    }
  }
  /* From 1440px, 340px (390 from 1600) and sticky under the header. */
  @media (min-width: 1440px) {
    body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) {
      grid-template-columns: minmax(0, 1fr) 340px;
    }
    body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .hr {
      grid-column: 2;
      grid-row: 1 / span 40;
      grid-template-columns: minmax(0, 1fr);
      /* its own height, not the forty rows it spans: a stretched item has
         nothing to stick with */
      align-self: start;
      position: sticky;
      top: calc(var(--gd-bar) + 24px);
      margin: 0;
    }
  }
  /* A short window: sticky, the column (the way across, six markets, five
     moves) would keep its own foot out of sight until the page ended. It
     scrolls with the page instead, as the vault's does. */
  @media (min-width: 1440px) and (max-height: 879px) {
    body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) > .hr {
      position: static;
    }
  }
  @media (min-width: 1600px) {
    body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card):has(> .hr) {
      grid-template-columns: minmax(0, 1fr) 390px;
    }
  }

  /* The chain's own rows, as the vault's ledger rows sit in its column. */
  body .hr-list .ce-list {
    margin-top: 0;
  }
  body .hr-list .ce-day-label {
    margin: 10px 8px 2px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .hr-list .ce-day:first-child .ce-day-label {
    margin-top: 0;
  }
  body .hr-list .ce-row {
    width: 100%;
    gap: 11px;
    padding: 9px 8px;
    border-radius: 12px;
    border-bottom: 0;
    transition: background 0.14s;
  }
  body .hr-list .ce-row.tap:hover {
    background: var(--gd-hover);
  }
  body .hr-list .ce-meta b,
  body .hr-list .ce-amt b {
    font-size: 13.5px;
  }
  body .hr-list .ce-scam {
    margin: 6px 8px 4px;
    font-size: 12px;
  }

  /* ── the card: a desktop's type, not a phone's ──────────────────────── */

  /* The same step the vault's card took: the diamond sized for a 440px card
     was a smudge in the corner of this one, and 11px captions sat under a
     56px figure. */
  body .shell:has(> nav.bottom-nav) .pub-card::after {
    width: 220px;
    height: 220px;
    right: -28px;
    bottom: -44px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-change {
    margin-top: 10px;
    padding: 5px 12px;
    font-size: 13.5px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-gram {
    margin-top: 12px;
    font-size: 15.5px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-gram-ic {
    width: 22px;
    height: 22px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-sub {
    margin-top: 14px;
    gap: 8px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-tag {
    padding: 6px 12px;
    font-size: 12.5px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-tag.pub-name {
    padding: 6px 12px 6px 9px;
    font-size: 13px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-tag.pub-name i {
    font-size: 11.5px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card button.pub-tag {
    transition: border-color 0.15s, background-color 0.15s, color 0.15s, filter 0.15s;
  }
  body .shell:has(> nav.bottom-nav) .pub-card button.pub-tag.addr:hover {
    color: var(--text);
    border-color: color-mix(in srgb, var(--gram) 52%, transparent);
    background: color-mix(in srgb, var(--gram) 13%, transparent);
  }
  body .shell:has(> nav.bottom-nav) .pub-card button.pub-tag.pub-name:not(.ghost):hover {
    filter: brightness(1.1);
  }
  body .shell:has(> nav.bottom-nav) .pub-card button.pub-tag.pub-name.ghost:hover {
    background: color-mix(in srgb, var(--gram) 10%, transparent);
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-says {
    margin-top: 12px;
    font-size: 12.5px;
  }
  body .shell:has(> nav.bottom-nav) .pub-card .pub-warn {
    font-size: 13px;
  }

  /* ── Tokens | Collectibles, as a desktop's tabs ─────────────────────── */

  /* The phone's pill stretched across the column was two 450px thumb
     targets holding 12.5px labels. Here: labels on a rule, the open one
     underlined in Gram blue, left-aligned over the list they switch. */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-tabs {
    display: flex;
    gap: 28px;
    margin: 4px 0 16px;
    padding: 0 6px;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--stroke-soft);
    border-radius: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-tabs .pub-tab {
    flex: none;
    margin-bottom: -1px;
    padding: 10px 2px 12px;
    border-radius: 0;
    background: none;
    border-bottom: 2px solid transparent;
    font-size: 14.5px;
    color: var(--text-faint);
    transition: color 0.14s, border-color 0.14s;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-tabs .pub-tab:hover {
    color: var(--text);
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-tabs .pub-tab[aria-selected='true'] {
    background: none;
    color: var(--text);
    border-bottom-color: var(--gram);
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-tabs .pub-tab:focus-visible {
    outline-offset: 3px;
    border-radius: 6px;
  }
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .pub-tabs .pub-tab .n {
    min-width: 22px;
    padding: 1px 7px;
    border-radius: 99px;
    background: var(--glass-2);
    font-size: 11.5px;
    color: var(--text-dim);
  }

  /* ── the tokens, as the vault's table ───────────────────────────────── */

  /* The first column is the face with its day ring round it, 50px where the
     vault's plain icon takes 46. The rest is .as-table's own (desktop.css,
     "the coins, as a table"): the same header, rows, price, day, share and
     value, on the same card. */
  body .shell .asset-list.gw-list.as-table {
    grid-template-columns: 50px minmax(140px, 1.7fr) minmax(90px, 1fr) minmax(64px, 0.8fr) minmax(0, 1.1fr) minmax(96px, 1.1fr);
    margin-top: 0;
  }
  /* Five columns wherever desktop.css takes the share out of the vault's
     table (under 1100px, and 1280-1439 with the column beside it): the rows
     have five cells there, and a sixth track would leave the value short of
     the right edge with an empty strip after it. */
  @media (max-width: 1099px), (min-width: 1280px) and (max-width: 1439px) {
    body .shell .asset-list.gw-list.as-table {
      grid-template-columns: 50px minmax(130px, 1.7fr) minmax(90px, 1fr) minmax(64px, 0.8fr) minmax(96px, 1.1fr);
    }
  }
  /* The older public-page rule (desktop.css, 22px each side for the phone's
     rows) would set this table 12px further in than the vault's. */
  body .shell:has(> nav.bottom-nav) .page.public-page .gw-list.asset-list.as-table {
    padding: 4px 10px 8px;
  }
  /* a note or the dust line is not a row: it spans the table */
  body .shell .asset-list.gw-list.as-table > :not(.as-head):not(.asset-row) {
    grid-column: 1 / -1;
  }
  body .shell .asset-list.gw-list.as-table > .gw-note {
    margin: 14px 4px 8px;
    font-size: 13px;
  }
  body .shell .asset-list.gw-list.as-table > .jet-more {
    margin: 6px 0 2px;
    padding: 11px;
    border-radius: 12px;
    font-size: 13px;
    transition: background 0.14s, color 0.14s;
  }
  body .shell .asset-list.gw-list.as-table > .jet-more:hover {
    background: var(--gd-hover);
    color: var(--text);
  }
  body .shell .asset-list.gw-list.as-table > .asset-row.static:hover,
  body .shell .asset-list.gw-list.as-table > .asset-row.skeleton:hover {
    background: none;
  }

  /* ── Collectibles ───────────────────────────────────────────────────── */

  /* The token table's card, edge and all: the phone's dashed outline round a
     filled card read as a second card language beside the table. */
  body .shell:has(> nav.bottom-nav) .page.public-page:has(.pub-card) > .col-card {
    margin-top: 0;
    padding: 18px 20px 16px;
    border: 1px solid var(--gd-card-line);
    border-radius: 20px;
    background: var(--gd-card);
    box-shadow: var(--gd-card-lit);
  }
  /* The kinds, all at once over the shelf: at most five, so a row of chips
     that wraps rather than a strip that scrolls out of a mouse's reach. */
  body .shell:has(> nav.bottom-nav) .col-card .nft-chips {
    flex-wrap: wrap;
    overflow: visible;
    gap: 8px;
    margin: 0 0 14px;
    padding: 0;
  }
  body .shell:has(> nav.bottom-nav) .col-card .nft-chip {
    max-width: none;
    padding: 7px 13px;
    font-size: 13px;
    transition: color 0.14s, border-color 0.14s, background-color 0.14s;
  }
  body .shell:has(> nav.bottom-nav) .col-card .nft-chip i {
    font-size: 11.5px;
  }
  body .shell:has(> nav.bottom-nav) .col-card .nft-chip:not(.on):hover {
    color: var(--text);
    border-color: var(--stroke);
    background: var(--gd-hover);
  }
  /* Unreviewed plates stay the size they are on a phone: four across a
     900px column made each one a 190px square of nothing. */
  body .shell:has(> nav.bottom-nav) .col-grid.col-grid-tight {
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 10px;
  }
  body .shell:has(> nav.bottom-nav) .col-plate b {
    font-size: 13px;
  }
  body .shell:has(> nav.bottom-nav) .col-plate i {
    font-size: 10.5px;
  }
  body .shell:has(> nav.bottom-nav) .col-guard {
    width: auto;
    padding: 9px 16px;
    font-size: 12.5px;
    transition: color 0.14s, background-color 0.14s, border-color 0.14s;
  }
  body .shell:has(> nav.bottom-nav) .col-guard:hover {
    color: var(--text);
    background: var(--gd-hover);
    border-color: color-mix(in srgb, var(--red) 40%, transparent);
  }
  body .shell:has(> nav.bottom-nav) .col-empty,
  body .shell:has(> nav.bottom-nav) .col-note {
    font-size: 13px;
  }

  /* The address book's shelf in Send is dressed further down, with
     Withdraw's ("The contacts shelf"): one set of rules for both. */

  /* ── the token picker: a keyboard's list ────────────────────────────── */

  body .shell .gw-list.pick .gw-row:not(.static):not(.on):hover,
  body .shell .gw-list.pick .gw-row.kb:not(.on) {
    background: var(--gd-hover);
    border-radius: 12px;
  }
  body .shell .gw-list.pick .gw-row.kb {
    border-radius: 12px;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 20%, transparent);
  }
}

/* =============================================================================
 * GRAM WALLET TRADE, WITH ITS MARKET (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* =============================================================================
 * THE GRAM WALLET'S TRADE, WITH ITS MARKET (components/GramSwapMarket)
 *
 * With the Gram wallet in front, the Trade tab is GramSwap alone: its
 * .page.xd sits straight under the shell, with no .trade-page around it, so
 * none of the vault's "SWAP, WITH ITS MARKET" rules reach it, and the phone's
 * deck was stretched across the whole 824-904px column. Here it gets the same
 * two panes as the vault's Trade: the market down the left, the ticket in a
 * 440px column on the right, and under 1280px the ticket alone in a centred
 * column with the market under it. The market mounts at this width only
 * (lib/wide), so a phone never has it in its tree.
 *
 * The page itself is the grid here (the vault's steps aside for its Trade
 * page's grid, since that one also holds the Swap | Perps switch). Sheets
 * and the limit screen inside it are fixed or portalled, so the grid never
 * places them.
 *
 * Specificity: the generic column rules are
 * `body .shell:has(> nav.bottom-nav) > .page` and `... .page` (0,3,2); these
 * add .xd and a :has(), (0,5,2), and the market's own rules one more class.
 * ========================================================================== */
@media (min-width: 1000px) {
  /* A net, not the layout: a Gram swap page without its market (the market
     mounts at this same width, so it should never be seen) is a task column,
     not the phone's deck across the full column. */
  body .shell:has(> nav.bottom-nav) > .page.xd:not(:has(> .swm)) {
    width: min(560px, 100%);
  }

  /* The two panes, measured to match the vault's Trade exactly. One thing
     the vault's does not need: this is a .page, which the phone's sheet
     stretches to the window's height (flex: 1), and a grid taller than its
     rows shares the spare height out between them, which would spread the
     ticket's parts down the window. align-content keeps the rows packed. */
  body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) {
    width: min(1320px, 100%);
    padding: 26px 32px 72px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 440px;
    column-gap: 28px;
    row-gap: 0;
    align-items: start;
    align-content: start;
  }
  body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) > * {
    grid-column: 2;
  }
  /* Placed by the grid, not by the page's order: GramSwap puts the market
     after the ticket so a keyboard and a screen reader reach the trade
     first, and an item with a row of its own is seated before the rest. */
  body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) > .swm {
    grid-column: 1;
    grid-row: 1 / span 40;
    align-self: start;
  }
  /* The heading's top level with the market's card top. */
  body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) > .page-h1 {
    margin-top: 0;
  }

  /* Under 1280px the market column would be crushed beside a 440px ticket,
     as the vault's was. The ticket takes the column alone, centred, and the
     market sits under it, full width: the vault's own narrow step. */
  @media (max-width: 1279px) {
    body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) {
      width: min(640px, 100%);
      grid-template-columns: minmax(0, 1fr);
    }
    body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) > * {
      grid-column: 1;
    }
    body .shell:has(> nav.bottom-nav) > .page.xd:has(> .swm) > .swm {
      grid-row: auto;
      order: 1;
      position: static;
      margin-top: 22px;
    }
  }

  /* ── the market itself: the vault pane's classes, with the chain's faces ──
     A jetton's face is the chain's own (.gw-face from GramAssets), not the
     catalogue's .token-icon the vault pane's rules are written for, so the
     small face's ring against the card is given here. */
  body .swm.gsm .swm-icons > :last-child .gw-face,
  body .swm.gsm .swm-icons > .gw-face:last-child {
    box-shadow: 0 0 0 2.5px var(--gd-card);
  }
  body .swm.gsm .swm-quick .gw-face {
    box-shadow: none;
  }
  /* The waiting box, and the "no line yet" box, stand exactly where the
     chart will: same height, same top. The vault's sits 6px lower than its
     chart, so the line arriving nudged the stats and the shortcuts up. */
  body .swm.gsm .swm-chart.swm-empty {
    margin-top: 4px;
  }
  /* The wallet's own coins, a second row under the popular pairs: closer to
     it than the stats are, since the two rows are one set of shortcuts. */
  body .swm.gsm .swm-quick.gsm-mine {
    margin-top: 10px;
  }
  body .swm.gsm .swm-quick.gsm-mine button em {
    margin-left: -2px;
  }
  body .swm.gsm .swm-foot svg {
    flex: none;
  }

  /* The way into limit orders, on the title: it answers the pointer as the
     ticket's own controls do. */
  @media (hover: hover) {
    body .shell:has(> nav.bottom-nav) > .page.xd .page-h1 .gsw-limit:hover {
      background: color-mix(in srgb, var(--success) 17%, var(--bg-elev));
      border-color: color-mix(in srgb, var(--success) 62%, transparent);
    }
  }
}

/* =============================================================================
 * MONEY IN AND OUT (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* =============================================================================
 * MONEY IN AND OUT, AS DESKTOP TASK SCREENS
 *
 * Deposit, Withdraw, the Receive and Send doors, Pay with. On a phone each is
 * one column fitted to the glass: the QR sized by the window's height so the
 * address never scrolls, the networks in a two-up box with its own scroll,
 * the contacts a strip a thumb swipes, every control answering a press and
 * nothing else. Here they are task screens: the task itself stays a card
 * about 600px wide, the address ticket puts its QR beside the address, and
 * from 1280px a companion column stands beside the task (Deposit's rules and
 * steps, Withdraw's address book and summary) instead of 300px of bare page
 * on either side of it. Every control answers the pointer.
 *
 * The companion columns (.xs-side) are MOUNTED only at this width (lib/wide),
 * so a phone never has them in its tree.
 * ========================================================================== */
@media (min-width: 1000px) {
  /* ═══════════════════════════════════════════════════════════════════════
   * THE PAGE
   * ══════════════════════════════════════════════════════════════════════ */

  /* Deposit's page is the phone's fit-without-scroll column, and a scroll box
     of its own (overflow: hidden auto) so a short phone can still reach the
     address. A desktop window scrolls; a page that is its own scroll container
     would also hold the side column's sticky to itself instead of the window.
     And the step itself is sized by what it holds: stretched to the window's
     height it pushed everything after it to the floor. */
  body .shell:has(> nav.bottom-nav) .page.deposit-fit {
    overflow: visible;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .dep3 {
    flex: none;
  }

  /* The companion column. Under the task on a narrower window, where there is
     no room beside it; Deposit's carries the rules while the address is up,
     so it is always drawn. Withdraw's is all address book and summary, which
     the phone column already holds at that width (the shelf under the field,
     the chip over the amount), so it waits for the room. */
  body .shell .xs-side {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-top: 26px;
    flex-shrink: 0;
    min-width: 0;
  }
  @media (max-width: 1279px) {
    body .shell .wd-side {
      display: none;
    }
  }

  /* Beside the task from 1280px: the task keeps its ~600px, the column 320.
     The rows are the Home rail's arrangement with one change. The column
     spans every row of the task, and a spanning item that is taller than
     the rows it spans hands the difference to them, which opened gaps
     between the task's own parts whenever the side ran longer. So the grid
     ends in a 1fr row that only the side reaches into: it takes the whole
     difference, and the auto rows above stay the size of what is in them.
     Fourteen rows is room for the longest step (Deposit's coin step has
     eight parts). (0,5,2) beats the task-width rule's (0,4,2). */
  @media (min-width: 1280px) {
    body .shell:has(> nav.bottom-nav) .page.xfer:has(> .xs-side) {
      width: min(1000px, 100%);
      display: grid;
      grid-template-columns: minmax(0, 1fr) 320px;
      grid-template-rows: repeat(14, auto) 1fr;
      column-gap: 32px;
      row-gap: 0;
      align-content: start;
      align-items: start;
    }
    body .shell:has(> nav.bottom-nav) .page.xfer:has(> .xs-side) > * {
      grid-column: 1;
    }
    body .shell:has(> nav.bottom-nav) .page.xfer:has(> .xs-side) > .xs-side {
      grid-column: 2;
      grid-row: 1 / -1;
      margin: 0;
      position: sticky;
      top: calc(var(--gd-bar) + 24px);
      /* a long address book scrolls in its own column rather than running
         off the bottom of a column that is stuck in place */
      max-height: calc(100vh - var(--gd-bar) - 48px);
      overflow-y: auto;
      scrollbar-width: thin;
    }
    /* With the whole book beside the field, the shelf of its first few
       under the field would be the same contacts twice. */
    body .shell:has(> nav.bottom-nav) .page.xfer:has(> .wd-side) .xf-route > .book-shelf {
      display: none;
    }
    /* On a short window (a 1366x768 laptop leaves about 650px) the column
       is taller than the room a stuck column has: Deposit's rules, its steps
       and the open tickets, or a long address book. Stuck, it would be a
       scroll box inside the scrolling page. So there it does not stick; it
       still spans every row beside the task and scrolls with the page. The
       line is the Home rail's own (desktop.css unsticks it under 880px), so
       the two columns stick, or do not, on the same windows. Same
       specificity, later: it wins. */
    @media (max-height: 879px) {
      body .shell:has(> nav.bottom-nav) .page.xfer:has(> .xs-side) > .xs-side {
        position: static;
        max-height: none;
        overflow: visible;
      }
    }
  }

  /* Home › Deposit over the heading: where the page sits, and the way back
     (the header's Deposit button and the palette open these from anywhere,
     and no sidebar row stands for them). */
  body .shell .xs-crumb {
    display: flex;
    align-items: center;
    gap: 4px;
    margin: -8px 0 10px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-faint);
  }
  body .shell .xs-crumb > button {
    margin-left: -7px;
    padding: 4px 7px;
    border-radius: 8px;
    color: var(--text-dim);
    font: inherit;
    transition: background 0.14s, color 0.14s;
  }
  body .shell .xs-crumb > button:hover {
    background: var(--gd-hover);
    color: var(--text);
  }
  body .shell .xs-crumb > span {
    color: var(--text-dim);
  }

  /* ── the companion's cards ────────────────────────────────────────────── */

  body .shell .xs-card {
    padding: 16px 16px 14px;
    border-radius: 20px;
    background: var(--gd-card);
    border: 1px solid var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
  }
  body .shell .xs-h {
    margin: 0 2px 12px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-faint);
  }

  /* the steps, a thread of dots: done ones ticked, the one you are on lit */
  body .shell .xs-steps {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  body .shell .xs-steps > li {
    position: relative;
    display: flex;
    gap: 12px;
    padding: 0 0 16px;
  }
  body .shell .xs-steps > li:last-child {
    padding-bottom: 2px;
  }
  body .shell .xs-steps > li:not(:last-child)::before {
    content: '';
    position: absolute;
    left: 11.25px;
    top: 28px;
    bottom: 4px;
    width: 1.5px;
    border-radius: 1px;
    background: var(--stroke-soft);
  }
  body .shell .xs-steps > li.done:not(:last-child)::before {
    background: color-mix(in srgb, var(--ink) 40%, transparent);
  }
  body .shell .xs-dot {
    flex: none;
    width: 24px;
    height: 24px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--glass);
    border: 1px solid var(--stroke);
    color: var(--text-faint);
    font-size: 11.5px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
  }
  body .shell .xs-steps > li.on .xs-dot {
    background: var(--grad);
    border-color: transparent;
    color: var(--cta-text);
    box-shadow: 0 6px 16px -8px var(--accent-glow);
  }
  body .shell .xs-steps > li.done .xs-dot {
    background: color-mix(in srgb, var(--ink) 12%, transparent);
    border-color: color-mix(in srgb, var(--ink) 35%, transparent);
    color: var(--ink);
  }
  body .shell .xs-step-m {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding-top: 3px;
  }
  body .shell .xs-step-m > b {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text-dim);
  }
  body .shell .xs-step-m > span {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-faint);
  }
  body .shell .xs-steps > li.on .xs-step-m > b {
    color: var(--text);
  }
  body .shell .xs-steps > li.on .xs-step-m > span {
    color: var(--text-dim);
  }
  body .shell .xs-step-m > span b {
    font-weight: 700;
    color: var(--text);
  }

  /* rows that open something: a deposit ticket still waiting */
  body .shell .xs-row {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 8px;
    border-radius: 12px;
    text-align: left;
    color: var(--text-faint);
    transition: background 0.14s, color 0.14s;
  }
  body .shell .xs-row + .xs-row {
    margin-top: 2px;
  }
  body .shell .xs-row-m {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
  }
  body .shell .xs-row-m b,
  body .shell .xs-row-m i {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  body .shell .xs-row-m b {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
  }
  body .shell .xs-row-m i {
    font-style: normal;
    font-size: 12px;
    color: var(--text-faint);
  }

  /* a summary, as label and figure on one line each */
  body .shell .xs-rows {
    margin: 0;
    display: flex;
    flex-direction: column;
  }
  body .shell .xs-rows > div {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 10px 2px;
    border-top: 1px solid var(--stroke-soft);
  }
  body .shell .xs-rows > div:first-child {
    border-top: 0;
    padding-top: 2px;
  }
  body .shell .xs-rows dt {
    flex: none;
    font-size: 13px;
    color: var(--text-dim);
  }
  body .shell .xs-rows dd {
    margin: 0;
    min-width: 0;
    max-width: 66%;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
  }
  body .shell .xs-rows dd.xs-mono {
    font-family: 'Space Grotesk', ui-monospace, monospace;
    font-weight: 600;
    letter-spacing: 0.01em;
  }
  body .shell .xs-rows dd > svg {
    flex: none;
    color: var(--ink);
  }
  body .shell .xs-rows .net-badge,
  body .shell .xs-ic .net-badge {
    border-radius: 50%;
    box-shadow: none;
  }
  body .shell .xs-foot {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 12px 2px 0;
    font-size: 12px;
    color: var(--text-faint);
  }
  body .shell .xs-side kbd {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 6px;
    background: var(--bg-elev-2);
    border: 1px solid var(--stroke-soft);
    border-bottom-width: 2px;
    color: var(--text-dim);
    font: 600 11px/1 var(--font);
  }

  /* facts, each behind a small mark */
  body .shell .xs-facts {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  body .shell .xs-facts > li {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-dim);
  }
  body .shell .xs-ic {
    flex: none;
    width: 26px;
    height: 26px;
    margin-top: -2px;
    display: grid;
    place-items: center;
    border-radius: 9px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
  }
  body .shell .xs-none {
    margin: 2px 2px 4px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-faint);
  }

  /* Withdraw's address book, the Contacts sheet's own rows in the column */
  body .shell .xs-book .xs-h + .book-group {
    margin-top: 0;
  }
  body .shell .xs-book .book-group {
    margin: 12px 6px 4px;
  }
  body .shell .xs-book .book-row {
    border-radius: 12px;
    padding: 6px 6px 6px 4px;
  }
  body .shell .xs-book .empty-state {
    padding: 14px 8px 6px !important; /* over the inline padding the sheet gives it */
  }
  body .shell .xs-book .book-note {
    margin: 10px 4px 0;
    font-size: 12px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * DEPOSIT
   * ══════════════════════════════════════════════════════════════════════ */

  /* ── the coin step: every network laid out, no box in a box ───────────────
     The phone caps the tiles at min(38vh, 300px) with their own scroll so
     Continue stays on screen. Here that made a coin with a dozen networks a
     scroll box inside a scrolling page, with a second thin bar in the
     column; three across and all of them shown is what the room is for.
     (0,5,2) beats the base (0,1,0). */
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-nets {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    max-height: none;
    overflow: visible;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-net {
    padding: 10px 11px;
  }

  /* ── the address ticket: the QR beside the address ────────────────────────
     A phone stacks head, QR, address and the waiting line, with the QR sized
     by the window's height (clamp(118px, 21vh, 184px)) so the whole ticket
     fits without a scroll: 136px on a 650px laptop window. A desktop deposit
     page puts the code beside the address it stands for. The head keeps the
     top row; the QR takes the left, the address, the memo and the waiting
     line the right. The grid's fourth row is 1fr and nobody's: it takes
     whatever height the QR has over the column beside it, so the address and
     the memo stay the size of what they say. */
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto auto 1fr auto;
    column-gap: 22px;
    row-gap: 0;
    padding: 18px 20px 16px;
    flex-shrink: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket > .xf-ticket-head {
    grid-column: 1 / -1;
    grid-row: 1;
    margin-bottom: 16px;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket > .xf-qr {
    grid-column: 1;
    grid-row: 2 / 6;
    align-self: start;
    margin: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-qr-frame svg {
    width: 200px;
  }
  /* Under 1280px the task is the 600px column alone, and the address beside
     the code needs the room more than the code needs the last 16px: at 184px
     it is still the phone's largest QR, and an EVM address breaks into two
     or three lines of chunks rather than four. */
  @media (max-width: 1279px) {
    body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-qr-frame svg {
      width: 184px;
    }
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket > .xf-addr {
    grid-column: 2;
    align-self: start;
    padding: 12px 12px 12px 14px;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket > .xf-addr.memo {
    margin-top: 10px;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket .xf-addr-v {
    font-size: 13.5px;
    line-height: 1.45;
  }
  /* The address breaks between its chunks; the memo is one run of text, and
     the column beside the QR is narrower than a phone's (about 180px at
     1000-1279px), so a long text memo (Stellar's run to 28 characters) would
     push past the copy button and out of the ticket. It breaks anywhere
     instead. (0,7,2) beats styles.css's memo rule (0,3,0). */
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket > .xf-addr.memo .xf-addr-v {
    overflow-wrap: anywhere;
  }
  body .shell:has(> nav.bottom-nav) .page.deposit-fit .xf-ticket > .xf-wait {
    grid-column: 2;
    grid-row: 5;
    align-self: end;
    margin: 14px 0 0;
    padding: 12px 2px 0;
  }

  /* The small print that keeps coins from being lost, at a size one reads:
     9.5px and 10.5px labels were a phone saving a line. */
  body .shell .xf-min > span {
    font-size: 11px;
  }
  body .shell .xf-min > b {
    font-size: 14px;
  }
  body .shell .xf-addr-k {
    font-size: 11.5px;
  }

  /* The rules while the address is up, in the side column under a heading,
     one to a line at reading size rather than 11.6px chips wrapped under the
     card. The EVM sibling-chain block stays the loudest thing there. */
  body .shell .xs-rules .dep-safety {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    margin: 0;
  }
  body .shell .xs-rules .ds-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 5px;
    padding: 10px 12px;
    border-radius: 12px;
    font-size: 13.5px;
    line-height: 1.35;
  }
  body .shell .xs-rules .dep-evm-warn {
    margin-top: 8px;
    padding: 12px 13px;
    font-size: 13px;
    line-height: 1.5;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE ADDRESS FIELDS: Paste, and the address book as a mouse sees it
   * ══════════════════════════════════════════════════════════════════════ */

  /* Paste leads; Scan, where a camera can read at all, is the icon after it.
     The width holds still while the label says Pasted or the keys. */
  body .shell .xf-field .copy-btn.paste {
    min-width: 88px;
    justify-content: center;
    font-variant-numeric: tabular-nums;
  }
  body .shell .xf-field .copy-btn.paste.done {
    color: var(--success);
    background: color-mix(in srgb, var(--success) 12%, transparent);
    border-color: color-mix(in srgb, var(--success) 42%, transparent);
  }
  body .shell .xf-field .copy-btn.qr-only {
    padding: 9px 10px;
  }

  /* The contacts shelf: a phone swipes the strip; a mouse wheel does not
     scroll sideways, the bar was hidden (scrollbar-width: none) and the edge
     faded, so a mouse reached about three pills of eight. They wrap into two
     or three rows instead, every one in reach. Also the Gram wallet's send
     sheet, which carries the same shelf. (0,2,1)/(0,2,2) beat the base. */
  body .shell .book-shelf {
    align-items: flex-start;
  }
  body .shell .book-rail {
    flex-wrap: wrap;
    overflow: visible;
    row-gap: 6px;
    -webkit-mask-image: none;
    mask-image: none;
  }
  body .shell .book-rail::after {
    display: none;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * RECEIVE AND SEND: two doors, side by side
   *
   * A phone stacks the two routes as rows to thumb down. A desktop dialog
   * lays two choices out as two cards beside each other: the mark and the way
   * in along the top, what it is under them, and on the wallet-or-exchange
   * door the fan of coins or networks along the foot. The dialog widens for
   * them, for this sheet alone.
   * ══════════════════════════════════════════════════════════════════════ */
  body .sheet:has(> .sheet-body > .xfc) {
    max-width: 680px;
  }
  body .shell .xfc {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
    margin-top: 4px;
  }
  body .shell .xfc > .xfc-door {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: auto auto 1fr;
    align-items: start;
    row-gap: 16px;
    min-height: 196px;
    padding: 20px 18px 18px 20px;
  }
  body .shell .xfc > .xfc-door > .xfc-glyph {
    grid-column: 1;
    grid-row: 1;
  }
  body .shell .xfc > .xfc-door > .route-go {
    grid-column: 3;
    grid-row: 1;
    transition: transform 0.15s, color 0.15s;
  }
  body .shell .xfc > .xfc-door > .xfc-meta {
    grid-column: 1 / -1;
    grid-row: 2;
  }
  body .shell .xfc > .xfc-door > .xfc-stack {
    grid-column: 1 / -1;
    grid-row: 3;
    align-self: end;
  }
  body .shell .xfc-meta > b {
    font-size: 16.5px;
  }
  body .shell .xfc-meta .route-sub {
    font-size: 13px;
  }

  /* Receive from a GhosterDex user: the code beside the address it carries,
     the way the deposit ticket has it, instead of a 196px square stacked over
     a 64-character address. The dialog widens a little for it, so the
     address reads in three lines of chunks, and Copy and Share sit under it.
     The rule pill and its details keep the full width above. The fifth row
     is 1fr and nobody's, so the column beside the code keeps the size of
     what is in it. (0,4,1)+ beats the base (0,2,0). */
  body .sheet:has(> .sheet-body > .xf-idcard .xf-qr) {
    max-width: 620px;
  }
  body .shell .xf-idcard .route-body:has(> .xf-qr) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto auto auto 1fr;
    column-gap: 20px;
    align-items: start;
  }
  body .shell .xf-idcard .route-body > .only-pill {
    grid-column: 1 / -1;
    grid-row: 1;
    justify-self: start;
  }
  body .shell .xf-idcard .route-body > .pill-details {
    grid-column: 1 / -1;
    grid-row: 2;
  }
  body .shell .xf-idcard .route-body > .xf-qr {
    grid-column: 1;
    grid-row: 3 / 6;
    margin: 12px 0 0 -8px;
  }
  body .shell .xf-idcard .route-body > .xf-idaddr {
    grid-column: 2;
    grid-row: 3;
    margin-top: 20px;
  }
  body .shell .xf-idcard .route-body > .pt-actions {
    grid-column: 2;
    grid-row: 4;
  }
  body .shell .xf-idcard .xf-idaddr .xf-addr-v {
    font-size: 13.5px;
    line-height: 1.5;
  }

  /* The Gram wallet's own amount field lights while it is typed in, as every
     other field here does (.text-field, .xf-to); it was the one left dark. */
  body .shell .gwp-row {
    transition: border-color 0.2s, box-shadow 0.2s;
  }
  body .shell .gwp-row:not(.bad):focus-within {
    border-color: color-mix(in srgb, var(--ink) 45%, transparent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink) 7%, transparent);
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE HEADER EYE, on the money screens too
   *
   * The header's eye (DesktopBar) blanks the vault's figures on Home. App
   * sets .gd-hide on <html> while it is shut, and only at this width, so
   * these screens honour it as well: what a holding holds is blurred, and a
   * pointer resting on one figure brings that one back, for as long as it
   * rests. A warning is never blurred (.pay-bal.over, .pws-held.why), and
   * neither is a figure being typed or a price being paid. The coin picker
   * both screens open (and any sheet listing holdings) blurs what is held
   * but keeps a coin's price in clear (.px-dim): a price is nobody's secret.
   * ══════════════════════════════════════════════════════════════════════ */
  :root.gd-hide body .xf-coin-bal > b,
  :root.gd-hide body .pay-bal:not(.over),
  :root.gd-hide body .pt-asset-bal,
  :root.gd-hide body .gwp-meta > span,
  :root.gd-hide body .pws-psum,
  :root.gd-hide body .pws-held:not(.why),
  :root.gd-hide body .pws-split > span:not(.pws-split-bar),
  :root.gd-hide body .xs-bal,
  :root.gd-hide body .sheet .asset-list .asset-row .amt > :not(.px-dim) {
    filter: blur(6px);
    transition: filter 0.15s, color 0.15s;
  }
  :root.gd-hide body .xf-coin-bal > b:hover,
  :root.gd-hide body .pay-bal:not(.over):hover,
  :root.gd-hide body .pt-asset-bal:hover,
  :root.gd-hide body .gwp-meta > span:hover,
  :root.gd-hide body .pws-psum:hover,
  :root.gd-hide body .pws-held:not(.why):hover,
  :root.gd-hide body .pws-split > span:not(.pws-split-bar):hover,
  :root.gd-hide body .xs-bal:hover,
  :root.gd-hide body .sheet .asset-list .asset-row .amt > :not(.px-dim):hover {
    filter: none;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * POINTER: everything the phone answered with a press alone
   * ══════════════════════════════════════════════════════════════════════ */
  @media (hover: hover) {
    /* Plates whose edge is a gradient drawn in their background: a hover
       that set a background would erase the edge, so they answer with a
       faint ring outside it instead. */
    body .shell .xf-coin,
    body .shell .xfc-door {
      transition: transform 0.12s, border-color 0.15s, background-color 0.15s, box-shadow 0.18s, translate 0.18s;
    }
    body .shell .xf-coin:hover {
      box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 9%, transparent), 0 14px 34px -24px color-mix(in srgb, var(--ink) 30%, transparent);
    }
    body .shell .xf-coin:hover .chev {
      color: var(--text-dim);
    }
    body .shell .xfc-door:hover {
      translate: 0 -2px;
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
      background-color: var(--glass-2);
    }
    body .shell .xfc-door.ghost:hover {
      border-color: transparent;
      box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 10%, transparent), 0 22px 50px -30px color-mix(in srgb, var(--ink) 40%, transparent);
    }
    body .shell .xfc-door:hover .route-go {
      color: var(--text);
      transform: translateX(2px);
    }

    body .shell .xf-net:not(.on):hover {
      background: var(--glass-2);
      border-color: var(--stroke);
    }
    body .shell .xf-addr:hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 34%, transparent);
    }
    body .shell .xf-addr.memo:hover {
      background: color-mix(in srgb, var(--amber) 12%, transparent);
      border-color: color-mix(in srgb, var(--amber) 70%, transparent);
    }
    /* The QR copies when clicked, and says so: the corners stop breathing
       and hold lit. `animation: none`, because the breathing is an opacity
       keyframe, and a running animation outranks a plain opacity. */
    body .shell .xf-qr:hover .xf-qr-corners {
      animation: none;
      opacity: 1;
    }
    body .shell .xf-qr .xf-qr-frame {
      transition: box-shadow 0.18s;
    }
    body .shell .xf-qr:hover .xf-qr-frame {
      box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 16%, transparent), 0 20px 48px -20px color-mix(in srgb, var(--ink) 50%, transparent), 0 10px 26px -14px rgba(0, 0, 0, 0.55);
    }
    body .shell .xf-agree:not(.on):hover {
      border-color: color-mix(in srgb, var(--ink) 32%, transparent);
      color: var(--text);
    }
    body .shell .dep-newaddr:hover {
      color: var(--text);
    }

    body .shell .pay-to:hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
    }
    body .shell .pay-fiat:hover {
      background: var(--bg-elev-3);
    }
    body .shell .pay-memo:not(.editing):hover {
      border-color: color-mix(in srgb, var(--ink) 40%, transparent);
    }
    body .shell .pay-splits button:not(.on):hover {
      color: var(--text);
      border-color: var(--stroke);
      background: var(--glass-2);
    }
    body .shell .pay-cta:not(:disabled):hover {
      filter: brightness(1.06);
    }
    body .shell .copy-btn:hover,
    body .shell .pt-action:hover,
    body .shell .book-all:hover {
      filter: brightness(1.14);
    }
    body .shell .route-back:hover,
    body .shell .only-pill:hover {
      color: var(--text);
      border-color: var(--stroke);
    }

    body .shell .book-pill:not(.on):hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 34%, transparent);
    }
    body .shell .book-row:not(.on):hover {
      background: var(--gd-hover);
    }
    body .shell .book-act:hover {
      color: var(--text);
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
    }
    body .shell .book-act.del:hover {
      color: var(--red);
    }
    body .shell .book-act.star:hover {
      color: var(--amber);
    }
    body .shell .xs-row:hover {
      background: var(--gd-hover);
      color: var(--text-dim);
    }

    body .shell .pt-asset-opt:not(.on):hover {
      background: var(--glass-2);
    }
    body .shell .pws-purse:not(.on):hover {
      color: var(--text);
      border-color: var(--stroke);
    }
    body .shell .pws-coin:not(.on):not(.short):not(.stuck):hover {
      background: var(--gd-hover);
    }
    body .shell .rs-toggle:hover {
      border-color: color-mix(in srgb, var(--ink) 34%, transparent);
    }
    body .shell .pg-details summary:hover {
      color: var(--text);
    }
  }
  @media (prefers-reduced-motion: reduce) {
    body .shell .xfc-door:hover {
      translate: none;
    }
    body .shell .xfc-door:hover .route-go {
      transform: none;
    }
  }
}

/* =============================================================================
 * ACTIVITY, THE LEDGER (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* =============================================================================
 * ACTIVITY, AS A DESKTOP LEDGER (the activity cluster)
 *
 * The vault's Activity was the phone's list in a wider card: two lines a row,
 * the amount pinned left and the dollars pinned right with 600px of nothing
 * between them. Here it is a table. Activity.tsx mounts a row of column heads
 * (.lr-head) at this width only, and LedgerRows adds the one cell a phone never
 * has, the state in words (.lr-st); everything else is the rows' own markup,
 * laid out as columns: .meta and .right step aside (display: contents) so
 * their lines become cells of a grid the whole list shares.
 *
 * The list is the grid and every row a subgrid of it, so a column is as wide
 * as its widest cell in ANY row and the figures line up down the page. The
 * table switches on only when the heads are there (`:has(> .lr-head)`): the
 * skeleton, the empty state and the Gram wallet's list are left as they were.
 *
 * Also here: the filter rail wraps instead of hiding chips behind a fade, the
 * perps block's position sheet is a centred dialog, the minimised dock card is
 * laid out as a card, and the dock gets out of the nav's way on short windows.
 * ========================================================================== */
@media (min-width: 1000px) {
  /* ── the column ───────────────────────────────────────────────────────────
     Never narrower than the rest of the app's pages: at 1600px and up every
     other page takes --gd-col's 960 and a ledger fixed at 920 sat 40px in
     from its neighbours. Same selector as the rule that set 920, and later. */
  body .shell:has(> nav.bottom-nav) .page:has(.afr):not(:has(> .hr)) {
    width: min(max(920px, var(--gd-col)), 100%);
  }

  /* ── the table ─────────────────────────────────────────────────────────── */

  /* icon | transaction | amount | value | status | time

     The first track is the 42px face plus the row's 14px of padding. A
     subgrid's padding is carried by the cells at its edges as extra margin,
     and a fixed track does not grow for it: at 42 the face would sit 14px
     into the gap after it. The max-content track at the far end grows for
     its side on its own. */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) {
    display: grid;
    grid-template-columns: 56px minmax(0, 1.75fr) minmax(0, 1fr) max-content max-content max-content;
    column-gap: 18px;
    padding: 4px 10px 10px;
  }
  /* The perps history under its own tab: icon | trade | details | value | time */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) .pp-actlist:has(> .lr-head) {
    display: grid;
    grid-template-columns: 56px minmax(0, 1.2fr) minmax(0, 1.5fr) max-content max-content;
    column-gap: 18px;
    padding: 4px 10px 10px;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > *,
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) .pp-actlist:has(> .lr-head) > * {
    grid-column: 1 / -1;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > :is(.lr-head, .tx-row),
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) .pp-actlist:has(> .lr-head) > :is(.lr-head, .tx-row) {
    display: grid;
    grid-template-columns: subgrid;
    gap: 0 18px;
    align-items: center;
  }

  /* The heads: the same small capitals as the coins' table on Home. */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .lr-head {
    padding: 12px 14px 10px;
    border-bottom: 1px solid var(--stroke-soft);
    color: var(--text-faint);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    white-space: nowrap;
  }
  /* figures sit right, under figures */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .lr-head > :is(:nth-child(3), :nth-child(4), :nth-child(6)),
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) .pp-actlist:has(> .lr-head) > .lr-head > :is(:nth-child(4), :nth-child(5)) {
    text-align: right;
  }

  /* The row's own lines, placed as cells. Every cell names its row as well as
     its column: the state cell comes after the time in the markup, and a cell
     placed in an earlier column than the one before it would otherwise start a
     second row. */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row > :is(.meta, .right) {
    display: contents;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row > :first-child {
    grid-column: 1;
    grid-row: 1;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row .meta .l1 {
    grid-column: 2;
    grid-row: 1;
    display: block;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
  }
  /* the Status column says it in words; the dot comes back where it does not */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row .meta .l1 > .status-dot {
    display: none;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row .meta .l2 {
    grid-column: 3;
    grid-row: 1;
    min-width: 0;
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* the vault's amount: a figure, right-aligned under its head. (A perps
     row's second line is words, the size and price, and keeps its own look.) */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row .meta .l2 {
    text-align: right;
    color: var(--text);
    font-size: 14px;
    font-weight: 600;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row .right > b {
    grid-column: 4;
    grid-row: 1;
    text-align: right;
    font-size: 14px;
    font-weight: 700;
    white-space: nowrap;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) :is(.asset-list, .pp-actlist):has(> .lr-head) > .tx-row .right > span {
    grid-row: 1;
    text-align: right;
    font-size: 12.5px;
    color: var(--text-faint);
    white-space: nowrap;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row .right > span {
    grid-column: 6;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) .pp-actlist:has(> .lr-head) > .tx-row .right > span {
    grid-column: 5;
  }

  /* The state, in words: quiet when it went through, which is nearly always,
     and coloured when it is still moving or did not. */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row > .lr-st {
    grid-column: 5;
    grid-row: 1;
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 10px 4px 9px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--ink) 5%, transparent);
    color: var(--text-dim);
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row > .lr-st.pending {
    background: color-mix(in srgb, var(--gold) 12%, transparent);
    color: var(--gold);
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row > .lr-st:is(.failed, .refunded) {
    background: color-mix(in srgb, var(--red) 11%, transparent);
    color: var(--red);
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row > .lr-st > .status-dot {
    width: 6px;
    height: 6px;
    box-shadow: none;
  }

  /* Each day, as a section of the table: a quiet band across every column. */
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-day {
    margin: 14px 0 4px;
    padding: 7px 14px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--ink) 3.5%, transparent);
    color: var(--text-dim);
    font-size: 11px;
    letter-spacing: 1.2px;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .lr-head + .tx-day {
    margin-top: 8px;
  }
  body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-day::after {
    display: none;
  }

  /* Under 1200px the column is too narrow for six, and the state goes back to
     being a dot before the words, as it is on a phone. */
  @media (max-width: 1199px) {
    body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) {
      grid-template-columns: 56px minmax(0, 1.75fr) minmax(0, 1fr) max-content max-content;
    }
    body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .lr-head > :nth-child(5),
    body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row > .lr-st {
      display: none;
    }
    body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .lr-head > :nth-child(6),
    body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row .right > span {
      grid-column: 5;
    }
    body .shell:has(> .gd-bar) .page:has(> .afr):not(.public-page) > .asset-list:has(> .lr-head) > .tx-row .meta .l1 > .status-dot {
      display: inline-block;
      margin-right: 8px;
      vertical-align: 1px;
    }
  }

  /* ── loose ends in the ledger skin ─────────────────────────────────────── */

  /* The skeleton sits where the rows will, so nothing shifts when they land. */
  body .shell:has(> .gd-bar) .page:has(.afr) .asset-list > .skel-row {
    padding: 13px 14px;
  }
  /* The day heading's desktop padding already makes its air; the phone's
     margin on top of it doubled the gap above every day. */
  body .shell:has(> .gd-bar) .page:has(.afr) .asset-list > .tx-day {
    margin: 0;
  }
  /* A row Tab brings into view clears the fixed header and the sticky filters
     rather than landing under them. The filters' band is ~56px on one row of
     chips and ~100px once they wrap onto a second (a narrow window, or the
     Gram wallet's seven tabs), so the margin is set for two rows and a little
     air, and holds for one. */
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row {
    scroll-margin-top: calc(var(--gd-bar) + 132px);
    scroll-margin-bottom: 16px;
  }

  /* ── the filter rail: every chip in reach of a mouse ───────────────────────
     On a phone the rail swipes sideways under a fade. A mouse cannot swipe,
     the scrollbar is hidden, and the last chips sat behind the fade on
     windows up to ~1080px. Here the chips wrap onto a second row instead; the
     sticky band just grows. Edit stays on the first row. */
  body .shell:has(> nav.bottom-nav) .afr {
    align-items: flex-start;
  }
  body .shell:has(> nav.bottom-nav) .afr-rail {
    flex-wrap: wrap;
    overflow: visible;
    padding-right: 2px;
    -webkit-mask-image: none;
    mask-image: none;
  }

  /* The chip menu takes a click on its quiet line or its padding itself
     (tabIndex -1, so the focus stays in it and it stays open). The focus
     that lands there is a mouse's, never shown: the lines carry the ring. */
  body .shell .afr-menu:focus {
    outline: none;
  }

  /* ── the perps block, on a desktop ─────────────────────────────────────── */

  /* Open positions side by side rather than as full-width slabs. */
  body .shell:has(> .gd-bar) .page:has(> .afr) .pp-livelane {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px;
  }
  body .shell .pp-live {
    transition: transform 0.15s ease, opacity 0.15s ease, translate 0.18s cubic-bezier(0.2, 0, 0, 1), box-shadow 0.2s;
  }
  /* A closed position's row opens its receipt; the rest are only a record. */
  body .shell .pp-acttap {
    cursor: pointer;
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .pp-actrow:not(.pp-acttap):hover {
    background: none;
  }
  body .shell:has(> .gd-bar) .page:has(.afr) .tx-row + .pp-actrow:not(.pp-acttap):hover,
  body .shell:has(> .gd-bar) .page:has(.afr) .pp-actrow:not(.pp-acttap):hover + .tx-row {
    box-shadow: 0 -1px 0 var(--stroke-soft);
  }

  /* The position sheet: a dialog in the middle of the window, not a band
     across the floor of it. perps-activity.js adds the close button, Escape
     and the focus handling at this width. The sheet is appended to <body>,
     outside .shell, so it carries its own pointer and focus manners. */
  body .pp-possheet {
    justify-content: center;
    align-items: center;
    padding: 24px;
  }
  body .pp-possheet > .pp-posbody {
    width: min(460px, 100%);
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    padding: 20px 22px 22px;
    border: 1px solid var(--stroke);
    border-radius: 22px;
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.72);
    touch-action: auto;
  }
  body .pp-possheet > .pp-posbody:focus {
    outline: none;
  }
  body .pp-possheet .pp-posgrip {
    display: none;
  }
  body .pp-possheet .pp-posbody:has(> .pp-posx) .pp-poshead {
    padding-right: 40px;
  }
  body .pp-possheet .pp-posx {
    position: absolute;
    top: 16px;
    right: 16px;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--stroke-soft);
    background: var(--glass-2);
    color: var(--text-dim);
    transition: color 0.15s, border-color 0.15s, background 0.15s;
  }
  body .pp-possheet button {
    cursor: pointer;
  }
  body .pp-possheet button:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 55%, transparent);
    outline-offset: 2px;
  }

  /* The Ghost receipt a perps row opens is a dialog at this width
     (perps-activity.js marks it role=dialog and gives it the focus, Escape
     and Tab). It hangs outside .shell, so it brings its own pointer. */
  body .pp-receiptwrap[role='dialog'] button {
    cursor: pointer;
  }

  /* ── the dock, minimised ───────────────────────────────────────────────────
     desktop.css stretches the puck into a 260px card, and the puck's insides
     were drawn for a 60px circle: the orbit was an absolute box the size of
     the whole card, so its ring floated in the card's middle away from the
     icon; the stage line hung off the card's left edge, which is off screen;
     and the count sat in the far corner. Here they are a card's contents: the
     ring around the icon, the line beside it, the count and an arrow saying
     "open" at the end.

     Geometry: the icon is 34px at 11px in, so its centre is 28px from the
     card's inner left edge; the orbit is 50px at 3px in, centre 28 too. The
     ring's inner edge is 25.5/60 of 50 = 21.25px from that centre, against
     the icon's 17: a clear 4px between them, as on the phone's puck. */
  body:has(.shell > nav.bottom-nav) .dock-puck {
    min-height: 56px;
    gap: 12px;
    padding: 0 12px 0 11px;
  }
  body:has(.shell > nav.bottom-nav) .dock-puck .dock-ic {
    flex: none;
    width: 34px;
    height: 34px;
  }
  body:has(.shell > nav.bottom-nav) .dock-puck .dock-orbit {
    inset: auto;
    left: 3px;
    top: 50%;
    width: 50px;
    height: 50px;
    transform: translateY(-50%);
  }
  /* The line, in the card rather than floating beside it, and kept rather
     than said once and faded: the card has the room, and it is the only
     words the minimised dock has. Its colour is left alone so a landed or
     failed flight keeps its tint. */
  body:has(.shell > nav.bottom-nav) .dock-puck .dock-puck-say {
    position: static;
    flex: 1;
    min-width: 0;
    max-width: none;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    /* styles.css hides the line outright for reduced motion, since on a
       phone it only ever arrives as an animation. Here it is still, so it
       stays: those windows would otherwise have a card with no words. */
    display: block;
    opacity: 1;
    transform: none;
    animation: none;
    font-size: 13px;
    font-weight: 650;
    text-align: left;
  }
  body:has(.shell > nav.bottom-nav) .dock-puck .dock-puck-count {
    position: static;
    order: 1;
    flex: none;
    margin-left: auto;
  }
  /* The upward caret: this card opens into the full feed. It reuses the
     puck's ::after, which the orbit retired (styles.css hides it), so every
     property the old pulse ring set is put back here. The doubled class
     outranks desktop.css's leftover `.dock-puck.pending::after` radius. */
  body:has(.shell > nav.bottom-nav) .dock-puck.dock-puck::after {
    content: '';
    display: block;
    position: static;
    inset: auto;
    order: 2;
    flex: none;
    width: 7px;
    height: 7px;
    margin: 3px 4px 0 2px;
    border: 0;
    border-top: 2px solid currentColor;
    border-left: 2px solid currentColor;
    border-radius: 1px;
    color: var(--text-faint);
    opacity: 1;
    transform: rotate(45deg);
    animation: none;
    transition: color 0.15s;
  }

  /* ── the dock, on a short window ───────────────────────────────────────────
     The dock stands on the sidebar's floor and grows upward, and the nav's
     rows end 268px down (332px with the wallet switch). Measured: two full
     cards reach the Activity row below ~590px of window (~654px with the
     switch), three below ~680px (~744px), and a 1366x768 laptop gives about
     620-645px. So below 780px the cards drop their bar and explorer link
     (the row's spinner, tick or warning and its line still say where the
     flight is) and stand ~62px tall instead of ~81; below 700px the third
     card waits, and below 620px the second, with the handle saying how many
     are held back.
     The squeeze is the app's own dock's only. gl-dock.js draws the
     terminal's flights as a `.dock.fd-dock` whose cards have another
     anatomy: no bar or link to drop, and the open button and the dismiss
     stacked in the card's column, which a gap of 0 would butt together. The
     holding back of cards applies to both docks, which stand on the same
     floor. */
  @media (max-height: 779px) {
    body:has(.shell > nav.bottom-nav) .dock:not(.fd-dock) .dock-card {
      gap: 0;
      padding: 8px 10px;
    }
    body:has(.shell > nav.bottom-nav) .dock:not(.fd-dock) .dock-card .dock-bar,
    body:has(.shell > nav.bottom-nav) .dock:not(.fd-dock) .dock-card .dock-link {
      display: none;
    }
  }
  @media (max-height: 699px) {
    body:has(.shell > nav.bottom-nav) .dock > .dock-card:nth-of-type(n + 3) {
      display: none;
    }
    body:has(.shell > nav.bottom-nav) .dock:has(> .dock-card:nth-of-type(3)) > .dock-min {
      width: auto;
      min-width: 46px;
      gap: 3px;
      padding: 0 10px;
    }
    body:has(.shell > nav.bottom-nav) .dock:has(> .dock-card:nth-of-type(3)) > .dock-min::after {
      content: '+1';
      font-size: 10.5px;
      font-weight: 800;
      font-variant-numeric: tabular-nums;
    }
  }
  @media (max-height: 619px) {
    body:has(.shell > nav.bottom-nav) .dock > .dock-card:nth-of-type(n + 2) {
      display: none;
    }
    body:has(.shell > nav.bottom-nav) .dock:has(> .dock-card:nth-of-type(2)) > .dock-min {
      width: auto;
      min-width: 46px;
      gap: 3px;
      padding: 0 10px;
    }
    body:has(.shell > nav.bottom-nav) .dock:has(> .dock-card:nth-of-type(2)) > .dock-min::after {
      content: '+1';
      font-size: 10.5px;
      font-weight: 800;
      font-variant-numeric: tabular-nums;
    }
    body:has(.shell > nav.bottom-nav) .dock:has(> .dock-card:nth-of-type(3)) > .dock-min::after {
      content: '+2';
    }
  }

  /* ── the pointer, answered ─────────────────────────────────────────────── */
  @media (hover: hover) {
    body .shell .afr-chip:not(.on):hover,
    body .shell .afr-edit:hover {
      color: var(--text);
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
    }
    body .shell .afr-mi:not(.muted):hover {
      background: var(--glass-2);
    }

    body .shell .pp-live:hover {
      translate: 0 -2px;
      box-shadow: inset 0 1px 0 var(--bump-hi), 0 18px 34px -20px rgba(0, 0, 0, 0.9);
    }
    body .shell .pp-actmore:hover {
      color: var(--text);
    }
    body .pp-possheet .pp-posx:hover {
      color: var(--text);
      background: var(--glass);
      border-color: var(--stroke);
    }
    body .pp-possheet .pp-posact:hover {
      border-color: color-mix(in srgb, var(--ink) 32%, transparent);
    }
    body .pp-possheet .pp-posact.close:hover {
      border-color: var(--red);
      background: color-mix(in srgb, var(--red) 8%, var(--bg-elev-2));
    }
    body .pp-possheet .pp-posact.go:hover {
      opacity: 0.9;
    }
    body .pp-possheet .pp-posmoney:hover {
      color: var(--text);
      border-color: color-mix(in srgb, var(--ink) 32%, transparent);
    }
    body .pp-receiptwrap[role='dialog'] :is(.pp-receipt-close, .pp-receipt-pnl):hover {
      border-color: color-mix(in srgb, var(--ink) 32%, transparent);
    }

    body:has(.shell > nav.bottom-nav) .dock-puck:hover {
      border-color: color-mix(in srgb, var(--ink) 26%, transparent);
    }
    body:has(.shell > nav.bottom-nav) .dock-puck.dock-puck:hover::after {
      color: var(--text);
    }
    /* A resumable deposit's card is a button: its light reaches a little past
       the words, by a spread shadow, so nothing in the card moves. */
    body:has(.shell > nav.bottom-nav) .dock button.dock-open:hover {
      background: var(--gd-hover);
      box-shadow: 0 0 0 6px var(--gd-hover);
    }
    body:has(.shell > nav.bottom-nav) .dock .dock-x:hover,
    body:has(.shell > nav.bottom-nav) .dock .dock-link:hover,
    body:has(.shell > nav.bottom-nav) .dock .dock-min:hover {
      color: var(--text);
    }
  }
}

/* =============================================================================
 * EXPLORE (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* =============================================================================
 * EXPLORE, AS A DESKTOP
 *
 * The hub, Stars and Premium, the Gifts storefront and Agent Wallets. Every
 * element styled here that a phone does not have (.zp-main, .zp-side,
 * .zp-order, .zp-sum-k, .zp-chip-n/-p, .zp-perks, .gv-topacts, .gv-cartbtn,
 * .gv-topbtn, .gv-toolrow, .gv-filterrow, .gv-dl, .gv-dr) is mounted only at
 * this width (lib/wide's useWide, the same 1000px), and everything else stays
 * behind the breakpoint like the rest of this file.
 *
 * Specificity: styles.css, gramzone.css and agents.css are emitted after this
 * file, so every rule that overrides one of theirs outranks it outright
 * (each is annotated where the margin is thin).
 * ========================================================================== */
@media (min-width: 1000px) {
  /* ═══════════════════════════════════════════════════════════════════════
   * THE HUB
   *
   * The page is a two-column grid whose every child spans both columns (the
   * `.page.gram` rules near the top of this file), which since the hub became
   * three sections left the AI door a phone banner 824-904px wide: 200px of
   * words, 400px of empty gradient, then the deck. The door and Coming soon
   * now share a row, each at the width it was drawn for. Without the AI
   * section (config.agents off) nothing matches and Coming soon keeps the
   * full width. Both sections carry the same 24px top margin (.gzc + .gzc),
   * so they line up without help. (0,6,2) and (0,8,2), over the (0,4,2) span.
   *
   * From 1200px only: a half column is ~405px there, a phone's width. Below
   * it the half would be 318-400px, narrower than the 380px at which
   * agents.css already has to step the door's deck down, and the door keeps
   * the whole row.
   * ══════════════════════════════════════════════════════════════════════ */
  @media (min-width: 1200px) {
    body .shell:has(> nav.bottom-nav) .page.gram > .gzc.ai {
      grid-column: 1;
    }
    body .shell:has(> nav.bottom-nav) .page.gram:has(> .gzc.ai) > .gzc.soon {
      grid-column: 2;
    }
  }

  @media (hover: hover) {
    /* :not(:active) so the press still gets agents.css's squeeze */
    body .shell .agt-door:hover:not(:active) {
      transform: translateY(-2px);
    }
  }
  /* gramzone.css lifts a Telegram tile on :hover without asking whether the
     pointer can hover, so a tap on a touch laptop leaves the tile lifted.
     (0,5,4) over its (0,4,3). */
  @media (hover: none) {
    html body .shell:has(> nav.bottom-nav) button.exb-tile:hover:not(:active) {
      transform: none;
    }
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * STARS AND PREMIUM, AS A CHECKOUT
   *
   * Both screens render .page.gz-prod.zp, and on a desktop their markup comes
   * in two halves: .zp-main (the product: the amount and the packages, or the
   * plans and what they bring) and .zp-side (the basket: the order in words,
   * who gets it, what it costs, the button). From 1200px the two sit side by
   * side like a shop's product and basket; below that, one 640px column with
   * the basket as a card under the product. The result screen after a
   * purchase has no .zp and keeps the 560px column.
   * ══════════════════════════════════════════════════════════════════════ */

  /* (0,5,2) over the (0,4,2) 560px column */
  body .shell:has(> nav.bottom-nav) .page.gz-prod.zp {
    width: min(640px, 100%);
  }
  body .shell:has(> nav.bottom-nav) .page.gz-prod.zp > .zp-side {
    margin-top: 28px;
  }
  @media (min-width: 1200px) {
    body .shell:has(> nav.bottom-nav) .page.gz-prod.zp:has(> .zp-side) {
      width: min(1040px, 100%);
      display: grid;
      grid-template-columns: minmax(0, 1fr) 360px;
      column-gap: 32px;
      align-items: start;
    }
    /* Back across the top; the sheets this page renders are fixed, so they
       never take a cell */
    body .shell:has(> nav.bottom-nav) .page.gz-prod.zp:has(> .zp-side) > .docs-back {
      grid-column: 1 / -1;
      justify-self: start;
    }
    body .shell:has(> nav.bottom-nav) .page.gz-prod.zp > .zp-main {
      grid-column: 1;
    }
    /* The basket stays in view while a long product column scrolls. Its own
       height, not the row's, or a stretched item would have nothing to stick
       within. */
    body .shell:has(> nav.bottom-nav) .page.gz-prod.zp > .zp-side {
      grid-column: 2;
      align-self: start;
      margin-top: 6px;
      position: sticky;
      top: calc(var(--gd-bar) + 24px);
    }
  }
  @media (min-width: 1440px) {
    body .shell:has(> nav.bottom-nav) .page.gz-prod.zp:has(> .zp-side) {
      grid-template-columns: minmax(0, 1fr) 380px;
      column-gap: 40px;
    }
  }

  /* ── the product ─────────────────────────────────────────────────────── */

  body .shell:has(> nav.bottom-nav) .zp .zp-top {
    gap: 18px;
    padding: 6px 2px 4px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-top-art {
    width: 72px;
    height: 72px;
    border-radius: 22px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-top-m {
    gap: 6px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-top h1 {
    font-size: 32px;
    letter-spacing: -0.02em;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-top p {
    font-size: 14.5px;
  }
  /* the section captions, in the column headers' voice */
  body .shell:has(> nav.bottom-nav) .zp .zp-lab {
    margin: 28px 2px 12px;
    font-size: 11px;
    letter-spacing: 0.12em;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-lab em {
    font-size: 12.5px;
  }

  body .shell:has(> nav.bottom-nav) .zp .zp-count {
    grid-template-columns: 60px minmax(0, 1fr) 60px;
    gap: 10px;
    margin-bottom: 14px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-step {
    min-height: 62px;
    border-radius: 16px;
    font-size: 24px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-count-mid {
    gap: 10px;
    padding: 0 18px;
    border-radius: 16px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-count-mid input {
    padding: 12px 0;
    font-size: 32px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-count-mid span {
    font-size: 12px;
  }

  /* The packages, as a shelf of tiles: every one in view with what it costs,
     where the phone keeps a strip to swipe. It had also stopped fitting: ten
     chips in a 504px column pushed "100K" off the end, behind a hidden
     scrollbar. Five across, two rows. */
  body .shell:has(> nav.bottom-nav) .zp .zp-chips {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 10px;
    overflow: visible;
    margin: 0;
    padding: 0;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-chip {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    min-width: 0;
    padding: 12px 13px 11px;
    border-radius: 14px;
    font-size: 16px;
    text-align: left;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-chip-n {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-chip-p {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
  }
  /* on the picked tile's gold, the words take the tile's own dark ink */
  body .shell:has(> nav.bottom-nav) .zp .zp-chip.on .zp-chip-n {
    color: #1a1205;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-chip.on .zp-chip-p {
    color: rgba(26, 18, 5, 0.7);
  }
  /* The product column is ~460px at the narrowest two-column width, where
     "100,000" at 16px would crowd its tile and the 100K tile's "1,000 GRAM"
     (~66px) would be cut to "1,000 GR…" in the ~63px left inside it. The
     basket gives up 40px and the gap 8px, which puts the column at ~505px and
     ~73px inside each tile; the 276px left inside the basket still holds the
     recipient toggle (about what a small phone gives it) and the total. The
     grid rule is (0,6,2) like the 1200px one above it, and wins by coming
     later. */
  @media (min-width: 1200px) and (max-width: 1279px) {
    body .shell:has(> nav.bottom-nav) .page.gz-prod.zp:has(> .zp-side) {
      grid-template-columns: minmax(0, 1fr) 320px;
      column-gap: 24px;
    }
    body .shell:has(> nav.bottom-nav) .zp .zp-chip {
      padding: 11px 10px 10px;
      font-size: 14.5px;
    }
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-meter {
    margin: 14px 2px 0;
  }

  /* Premium's plans at a size a pointer reads from arm's length. The "best
     value" line is pinned to 10px of line-height upstream, so it grows with
     its type or the word is clipped. */
  body .shell:has(> nav.bottom-nav) .zp .zp-tickets {
    gap: 12px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-ticket {
    gap: 3px;
    padding: 16px 10px 16px;
    border-radius: 18px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-tk-best {
    height: 14px;
    font-size: 10px;
    line-height: 14px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-tk-months {
    margin-top: 6px;
    font-size: 40px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-tk-unit {
    font-size: 11px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-tk-price {
    margin-top: 10px;
    font-size: 15px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-tk-per {
    font-size: 12px;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-tk-off {
    margin-top: 8px;
    padding: 2px 9px;
    font-size: 11.5px;
  }

  /* what a subscription brings, all eight, as a checklist */
  body .shell:has(> nav.bottom-nav) .zp .zp-perks {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 11px 20px;
    margin: 0;
    padding: 2px 2px 0;
    list-style: none;
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-perks li {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-dim);
  }
  body .shell:has(> nav.bottom-nav) .zp .zp-perks svg {
    flex: none;
    color: #4d8dff;
  }

  /* ── the basket ──────────────────────────────────────────────────────── */

  body .shell:has(> nav.bottom-nav) .zp > .zp-side {
    padding: 20px 22px 18px;
    border-radius: 20px;
    background: var(--gd-card);
    border: 1px solid var(--gd-card-line);
    box-shadow: var(--gd-card-lit);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--stroke-soft);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order-art {
    flex: none;
    width: 46px;
    height: 46px;
    display: grid;
    place-items: center;
    border-radius: 14px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
  }
  /* the same light as the product's own plate above the fold */
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order-art.stars {
    background: radial-gradient(80% 80% at 50% 30%, rgba(255, 190, 70, 0.3), transparent 72%), var(--glass);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order-art.premium {
    background: radial-gradient(80% 80% at 50% 30%, rgba(80, 140, 255, 0.3), transparent 72%), var(--glass);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order-m {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order-m b {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-order-m i {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-style: normal;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-dim);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-lab {
    margin-top: 18px;
  }

  /* The bill: the coin it is paid with as a full-width choice, then what
     leaves the wallet as the card's headline figure. */
  body .shell:has(> nav.bottom-nav) .zp-side .zp-payrow {
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
    margin-top: 18px;
    padding: 16px 0 0;
    border-top: 1px solid var(--stroke-soft);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-pay {
    order: -1;
    width: 100%;
    justify-content: flex-start;
    gap: 9px;
    padding: 11px 14px 11px 12px;
    border-radius: 13px;
    font-size: 13.5px;
  }
  /* (the coin's face is drawn at 20px by Stars.tsx and Premium.tsx on a
     desktop: its size is an inline style no rule here could outrank) */
  body .shell:has(> nav.bottom-nav) .zp-side .zp-pay > svg:last-child {
    margin-left: auto;
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-sum {
    gap: 3px;
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-sum-k {
    font-style: normal;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-sum b {
    font-size: 26px;
    letter-spacing: -0.02em;
  }
  body .shell:has(> nav.bottom-nav) .zp-side .zp-sum i {
    font-size: 13px;
    white-space: normal;
  }
  body .shell:has(> nav.bottom-nav) .zp-side .cta {
    margin-top: 16px;
  }

  @media (hover: hover) {
    body .shell:has(> nav.bottom-nav) .zp .zp-chip:not(.on):not(:disabled):hover,
    body .shell:has(> nav.bottom-nav) .zp .zp-ticket:not(.on):hover,
    body .shell:has(> nav.bottom-nav) .zp .zp-step:not(:disabled):hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 28%, transparent);
    }
    body .shell:has(> nav.bottom-nav) .zp .zp-pay:hover {
      border-color: color-mix(in srgb, var(--ink) 34%, transparent);
    }
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * GIFTS, AS A STOREFRONT (the parts the section of that name above the
   * gate left open)
   *
   * The column. The cart and back-to-top buttons no longer float over the
   * page on a desktop (Gifts.tsx mounts them only on a phone; the cart lives
   * in the bar at the top), so nothing needs the 180px the storefront's
   * --gd-col used to hold back, and holding it back had made the shelf
   * narrower than every other page from 1000 to 1343px: two cases across at
   * 1000-1115px, the phone's vitrine. The storefront takes the width Swap
   * takes. Same (0,5,2) as the rule it replaces, and later in the file.
   * ══════════════════════════════════════════════════════════════════════ */
  body .shell:has(> nav.bottom-nav) .page.gifts.gv {
    --gd-col: 1320px;
  }

  /* The bar that stays. On a phone it is a lone Back pill that floats down
     the grid; here it is a toolbar band under the header, Back on the left
     and the cart on the right, with a backdrop so the cards pass beneath it
     rather than behind floating buttons. Keyed on the header being there,
     like the `top` rule it overrides; (0,6,1) over that rule's (0,3,1). */
  body .shell:has(> .gd-bar) .page.gifts.gv > .gifts-topbar {
    top: var(--gd-bar);
    width: auto;
    justify-content: space-between;
    gap: 12px;
    margin: -10px 0 8px;
    padding: 10px 0;
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv > .gifts-topbar > .docs-back {
    margin: 0;
  }
  body .shell .gv-topacts {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
  }
  body .shell .gv-topbtn {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    padding: 0;
    border-radius: 12px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    color: var(--text-dim);
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    animation: fadeIn 0.18s ease;
  }
  body .shell .gv-cartbtn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 38px;
    padding: 0 14px 0 12px;
    border-radius: 999px;
    background: var(--bg-elev-2);
    border: 1px solid var(--stroke);
    color: var(--text);
    font-size: 13.5px;
    font-weight: 800;
    white-space: nowrap;
    transition: filter 0.15s, border-color 0.15s, background 0.15s;
  }
  /* holding gifts: the theme's contrast fill, as the phone's pill has */
  body .shell .gv-cartbtn.has {
    background: var(--grad);
    border-color: transparent;
    color: var(--bg);
  }
  body .shell .gv-cartbtn em {
    min-width: 20px;
    height: 20px;
    display: inline-grid;
    place-items: center;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--success);
    color: #05221a;
    font-style: normal;
    font-size: 11.5px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
  }
  body .shell .gv-cartbtn b {
    padding-left: 9px;
    border-left: 1px solid color-mix(in srgb, currentColor 28%, transparent);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
  }

  /* The title and the market's three figures on one line, instead of the
     figures stretched into a 1184px ticker of three centred numbers. */
  body .shell:has(> nav.bottom-nav) .page.gifts.gv > .gv-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    margin: 6px 0 16px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv > .gv-head > .gv-h1 {
    margin: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv > .gv-head > .gv-stats {
    flex: 0 1 480px;
    min-width: 0;
    margin: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-stats > span {
    align-items: flex-start;
    padding: 9px 16px 8px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-stats b {
    font-size: 16px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-stats em {
    font-size: 10px;
  }

  /* The controls as a toolbar: the search and the view (Market or Saved,
     density, refresh) on one line, the filters and the sorts on the next,
     and the sorts drop under the filters only when the column cannot hold
     both. The phone's eight stacked rows put the first gifts ~500px down a
     900px window. */
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-toolrow {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 4px 0 12px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-toolrow > .gv-search {
    flex: 1 1 auto;
    min-width: 0;
    height: 44px;
    margin: 0;
    padding: 0 10px 0 14px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-search input {
    font-size: 14.5px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-toolrow > .gv-bar {
    flex: none;
    gap: 10px;
    margin: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-shelf button {
    padding: 8px 15px;
    font-size: 12.5px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gift-refresh {
    width: 38px;
    height: 38px;
    border-radius: 12px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-filterrow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    margin: 0 0 12px;
  }
  /* An auto basis, so the row breaks on the chips' one-line width: the sorts
     go to the next line (to the right, by their auto margin) as soon as the
     chips and the sorts do not both fit, rather than the chips wrapping inside
     the bar beside them. Where the chips alone overflow the row, the bar
     shrinks to it and wraps. */
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-filterrow > .gf-bar {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    padding: 0;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-filterrow > .gv-sorts {
    flex: 0 0 auto;
    margin: 0 0 0 auto;
    padding: 0;
    overflow: visible;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gf-chip {
    padding: 8px 13px;
    font-size: 13px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-sort {
    padding: 7px 12px;
    font-size: 12.5px;
  }
  body .shell:has(> nav.bottom-nav) .page.gifts.gv .gf-active {
    margin-bottom: 4px;
  }

  /* A desktop card's Add to cart and Save are real buttons beside the art
     (Gifts.tsx), so they drop a button's own padding and get a focus ring
     that reads over any gift's colours. (0,3,2) over (0,2,1). */
  body .shell .gv-art > button.gv-pick,
  body .shell .gv-art > button.gv-save {
    padding: 0;
    font: inherit;
  }
  body .shell .gv-art > button:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 2px;
    box-shadow: 0 0 0 5px rgba(6, 8, 14, 0.45);
  }

  /* Tab through the grid upward and the card that takes focus lands under
     the header and the bar above: the window keeps their height clear. */
  :root:root:has(.shell > .gd-bar):has(.page.gifts.gv) {
    scroll-padding-top: calc(var(--gd-bar) + 76px);
  }

  /* The recently viewed strip: up to twelve 64px tiles, 856px, behind a
     hidden scrollbar in a column that is narrower than that below ~1300px,
     so the oldest could not be reached with a mouse. It wraps instead.
     (0,2,1) over .gv-recent-rail and .no-scrollbar at (0,1,0). */
  body .shell .gv-recent-rail {
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: 10px;
  }

  /* ── the open gift, as a dialog ───────────────────────────────────────
     On a phone it is a sheet with the art at 88px, smaller than the card it
     was opened from. Here: the art large on the left with the name, price
     and Save beside it, and the traits and the checkout on the right, the
     left column holding still while the right scrolls. Gifts.tsx gathers
     the two sides into .gv-dl and .gv-dr on a desktop only. */
  body .sheet:has(> .sheet-body > .gv-dl) {
    max-width: 940px;
    max-height: min(88vh, 920px);
  }
  body .sheet-body:has(> .gv-dl) {
    display: grid;
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
    column-gap: 28px;
    align-items: start;
  }
  body .sheet-body > .gv-dl {
    position: sticky;
    top: 0;
  }
  body .sheet-body > .gv-dr {
    min-width: 0;
  }
  body .gv-dl .gv-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'art art' 'meta acts';
    align-items: start;
    gap: 16px 10px;
    padding: 14px 14px 16px;
    border-radius: 24px;
  }
  /* (0,3,1) over .gv-hero-art.gd-thumb (0,2,0) */
  body .gv-dl .gv-hero-art.gd-thumb {
    grid-area: art;
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    border-radius: 18px;
  }
  body .gv-dl .gd-expand {
    right: 10px;
    bottom: 10px;
    width: 28px;
    height: 28px;
    border-radius: 10px;
  }
  body .gv-dl .gv-hero-meta {
    grid-area: meta;
    gap: 8px;
  }
  body .gv-dl .gv-hero-meta > b {
    font-size: 22px;
  }
  body .gv-dl .gv-hero-meta > b em {
    font-size: 16px;
  }
  body .gv-dl .gv-hero-price b {
    font-size: 22px;
  }
  body .gv-dl .gv-hero-price span {
    font-size: 13px;
  }
  body .gv-dl .gv-hero-acts {
    grid-area: acts;
  }
  body .gv-dl .gv-act {
    width: 36px;
    height: 36px;
  }
  body .sheet-body > .gv-dr > .gv-traits:first-child {
    margin-top: 0;
  }

  /* "More like this" wraps instead of scrolling behind a hidden bar: in a
     492px modal "Same symbol" was cut off, out of a mouse's reach.
     (0,2,1) over .gv-similar and .no-scrollbar (0,1,0). */
  body .sheet .gv-similar {
    flex-wrap: wrap;
    overflow-x: visible;
    row-gap: 8px;
  }

  /* The full-size viewer, at a desktop's full size: 430px was barely twice
     a grid card. (0,1,1) over (0,1,0). */
  body .gd-zoom-box {
    width: min(72vh, 640px);
  }
  body .gd-zoom-cap {
    font-size: 19px;
  }

  /* The storefront's hover answers, for a pointer that can hover. These
     replace the three ungated :hover rules in the GIFTS, AS A STOREFRONT
     section above the gate, which lifted cards on a touch laptop after a tap
     and, at (0,3,1), took away what a card or tile was saying: the green ring
     of a card in the cart, the brighter edge of a chosen collection. A
     loading placeholder does not lift at all. */
  @media (hover: hover) {
    body .shell .gv-card:not(.gv-skel):hover {
      translate: 0 -3px;
      border-color: color-mix(in srgb, var(--ink) 24%, transparent);
      box-shadow: 0 24px 46px -26px color-mix(in srgb, var(--tint) 95%, transparent);
    }
    body .shell .gv-card:not(.gv-skel):hover .gv-art img {
      transform: scale(1.05);
    }
    body .shell .gv-rc:hover {
      border-color: color-mix(in srgb, var(--ink) 26%, transparent);
    }
  }
  /* A touch screen this wide keeps :hover on whatever was tapped last, so
     the ungated rules above the gate leave a tapped card lifted until the
     next tap lands elsewhere. Put back what the card had. :not(:active) so a
     press still gets styles.css's squeeze of the art. (0,4,1) and (0,6,2)
     over (0,3,1) and (0,4,2). */
  @media (hover: none) {
    body .shell .gv-card:not(.gv-skel):hover {
      translate: none;
      border-color: var(--stroke);
      box-shadow: 0 16px 34px -24px color-mix(in srgb, var(--tint) 75%, transparent);
    }
    body .shell .gv-card:not(.gv-skel):hover:not(:active) .gv-art img {
      transform: none;
    }
    body .shell .gv-rc:hover {
      border-color: var(--stroke-soft);
    }
  }
  /* Whatever the pointer, the hover never speaks over the state: a card in
     the cart keeps its green ring, a sold one (or a loading placeholder)
     does not lift as though it could be opened, and a chosen collection
     keeps its edge. A class more than the rules they answer; sold before
     picked, so a sold card still in the cart keeps the green. */
  body .shell .gv-card.sold:not(.gv-skel):hover,
  body .shell .gv-card.gv-skel:hover {
    translate: none;
    border-color: var(--stroke);
    box-shadow: 0 16px 34px -24px color-mix(in srgb, var(--tint) 75%, transparent);
  }
  body .shell .gv-card.sold:not(.gv-skel):hover .gv-art img {
    transform: none;
  }
  body .shell .gv-card.picked:not(.gv-skel):hover {
    border-color: var(--success);
    box-shadow: 0 0 0 1px var(--success), 0 24px 46px -26px color-mix(in srgb, var(--tint) 95%, transparent);
  }
  body .shell .gv-rc.on:hover {
    border-color: color-mix(in srgb, var(--ink) 45%, transparent);
  }

  @media (hover: hover) {
    body .shell .gv-art > button.gv-pick:not(.on):hover,
    body .shell .gv-art > button.gv-save:not(.on):hover {
      background: rgba(8, 10, 16, 0.66);
      border-color: #ffffff;
      color: #ffffff;
    }
    body .shell:has(> nav.bottom-nav) .page.gifts.gv .gf-chip:not(.off):hover,
    body .shell:has(> nav.bottom-nav) .page.gifts.gv .gift-refresh:not(:disabled):hover,
    body .shell .gv-topbtn:hover {
      color: var(--text);
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
    }
    body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-sort:not(.on):hover,
    body .shell:has(> nav.bottom-nav) .page.gifts.gv .gv-shelf button:not(.on):hover {
      color: var(--text);
      background: var(--gd-hover);
    }
    body .shell .gv-cartbtn:not(.has):hover {
      border-color: color-mix(in srgb, var(--ink) 34%, transparent);
    }
    body .shell .gv-cartbtn.has:hover {
      filter: brightness(1.06);
    }
    body .sheet .gv-similar button:hover {
      background: var(--glass-2);
      border-color: color-mix(in srgb, var(--ink) 30%, transparent);
    }
    body .shell .gv-recent-rail .gv-rt:hover img {
      outline: 2px solid color-mix(in srgb, var(--ink) 28%, transparent);
      outline-offset: 2px;
    }
    body .shell .gv-recent-rail .gv-rt:hover span {
      color: var(--text);
    }
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * AGENT WALLETS
   *
   * The screen shares .page.gz-prod with the checkouts and so inherited
   * their 560px column: the phone screen with ~290px empty on each side.
   * Here it takes the app's column, the agents become a grid of cards, the
   * first-run steps sit in a row, and the overview's figure is set at a
   * desktop's size. (0,5,2) over the (0,4,2) column. agents.css's own media
   * queries are max-width only, so nothing there competes.
   * ══════════════════════════════════════════════════════════════════════ */
  body .shell:has(> nav.bottom-nav) .page.gz-prod.agt {
    width: min(var(--gd-col), 100%);
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-top {
    padding: 22px 24px 18px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-total {
    font-size: 44px;
    letter-spacing: -1.4px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-sub {
    font-size: 13.5px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-stats {
    margin-top: 18px;
    padding-top: 16px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-stat + .agt-stat {
    padding-left: 22px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-stat em {
    font-size: 11px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-stat b {
    font-size: 20px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-stat b small {
    font-size: 13px;
  }
  /* before the first agent: the pitch at a desktop's size, and its button
     the width of its words rather than the width of the card */
  body .shell:has(> nav.bottom-nav) .page.agt .agt-top[data-empty] {
    padding: 26px 26px 24px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-title {
    font-size: 30px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-top[data-empty] .agt-sub {
    max-width: 46ch;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-top[data-empty] .agt-cta.cta {
    width: auto;
    align-self: flex-start;
    padding: 14px 26px;
    font-size: 15px;
  }

  /* one card each, as many across as the column holds: one at 1000px, two
     from about 1100 */
  body .shell:has(> nav.bottom-nav) .page.agt .agt-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 14px;
    margin-top: 16px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-card {
    padding: 16px 16px 14px;
    border-radius: 20px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-steps {
    flex-direction: row;
    gap: 14px;
    margin-top: 18px;
  }
  body .shell:has(> nav.bottom-nav) .page.agt .agt-steps li {
    flex: 1 1 0;
    min-width: 0;
    padding: 16px 16px 18px;
  }

  /* One agent, in its sheet, and setting one up. Both take a little more
     than the generic 540px modal: the agent's four actions need it to sit
     as a toolbar, and setup's terminal commands wrap less. (0,3,1) over
     `body .sheet` (0,1,1). */
  body .sheet:has(> .sheet-body > .agt-sheet),
  body .sheet:has(> .sheet-body > .agt-setup) {
    max-width: 600px;
  }
  /* The phone's quick-action row, four 52px plates with a caption under
     each, is a thumb's target. Here it is a toolbar: four buttons, each its
     icon beside its word, on a card that answers the pointer. The plate
     keeps its colours (Fund's fill, Pause's amber, Settings' hue and the
     day's spend drawn round its edge, which scales with it). */
  body .sheet .agt-pane.main .agt-keys {
    gap: 8px;
    margin-top: 16px;
  }
  body .sheet .agt-pane.main .agt-key {
    flex-direction: row;
    justify-content: flex-start;
    gap: 9px;
    min-height: 48px;
    padding: 6px 12px 6px 6px;
    border-radius: 15px;
    background: var(--glass);
    border: 1px solid var(--stroke-soft);
    font-size: 13.5px;
    transition: transform 0.12s, opacity 0.15s, background 0.15s, border-color 0.15s;
  }
  body .sheet .agt-pane.main .agt-key-ic {
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: 11px;
  }
  /* setup: the commands a terminal runs, at a size read off a monitor */
  body .sheet .agt-setup .agt-cmd code {
    padding: 6px 14px 13px;
    font-size: 12.5px;
  }

  @media (hover: hover) {
    /* the list answered only :active, because a phone has no hover */
    body .shell:has(> nav.bottom-nav) .page.agt .agt-card:not(.skel):hover {
      border-color: color-mix(in srgb, var(--agt) 40%, var(--stroke-soft));
      background: color-mix(in srgb, var(--agt) 4%, var(--bg-elev));
    }
    body .shell:has(> nav.bottom-nav) .page.agt .agt-add:not(:disabled):hover {
      border-color: color-mix(in srgb, var(--agt) 45%, var(--stroke));
    }
    /* the agent's toolbar, in its sheet */
    body .sheet .agt-pane.main .agt-key:not(:disabled):hover {
      background: var(--gd-hover);
      border-color: color-mix(in srgb, var(--ink) 28%, transparent);
    }
    body .sheet .agt-key.fund:not(:disabled):hover .agt-key-ic {
      filter: brightness(1.08);
    }
    body .sheet .agt-setup .agt-cmd-head button:hover {
      color: var(--text);
      background: var(--gd-hover);
    }
    body .sheet .agt-more-toggle:hover {
      text-decoration: underline;
      text-underline-offset: 3px;
    }
  }
}

/* =============================================================================
 * SHELL MANNERS: ESCAPE, EARN, THE GUIDE, THE SCROLLBAR (desktop audit pass, 2026-09-28; public/desktop.css order:
 * coin page, Gram wallet, Gram trade, money, activity, Explore, shell)
 * ========================================================================== */
/* =============================================================================
 * THE SHELL'S DESKTOP MANNERS
 *
 * What a desktop expects of an app's frame that a phone never asks: a page
 * that does not jump sideways when a modal opens, modals that take the
 * keyboard (Sheet.tsx does the keys; this draws the focus), the self-custody
 * notice in front of everything a first connect opens, Earn as a screen of the
 * app beside the sidebar instead of a layer over all of it, and the guide as a
 * document: a reading column with its contents in a column of their own.
 *
 * Everything here is behind the same 1000px as the rest of this file. The
 * elements it names that a phone does not have (the guide's "Contents" label,
 * Earn's Esc key cap, the notice backdrop's .nc-back) are only rendered at this
 * width (lib/wide).
 * ========================================================================== */
@media (min-width: 1000px) {
  /* ═══════════════════════════════════════════════════════════════════════
   * THE PAGE HOLDS STILL UNDER A MODAL
   *
   * The desktop draws a real scrollbar on the page (the thin one above), and a
   * classic scrollbar takes width. Every sheet locks the page by hiding its
   * overflow (Sheet.tsx), as do Earn, the limit desk and the perps terminal,
   * which took the scrollbar away: the column shifted by half its width and
   * the header's right-hand controls by all of it, and both came back on
   * close. A stable gutter keeps that width whether the bar is drawn or not,
   * which also stops the same jump between a short page and a long one.
   *
   * What it costs: a fixed overlay stops at the gutter, so while a sheet is up
   * the scrollbar's strip down the right edge keeps the page colour instead
   * of the dimming (black on black in the dark theme; a thin light line in the
   * light one), which is how the visible scrollbar looked over a modal anyway.
   * ══════════════════════════════════════════════════════════════════════ */
  :root:root {
    scrollbar-gutter: stable;
  }

  /* A sheet, Earn and the notice take focus when they open, so the keyboard
     starts inside them: a sheet and Earn on the part of them that scrolls, so
     the arrow keys read them, the notice on its checkbox or itself. None of
     those is a control, and a ring around a whole modal or its whole body
     says nothing a ring on its first button would not. The ones that can
     stand inside Earn outrank Earn's own ring below. */
  body .shell .sheet:focus-visible,
  body .ern .sheet:focus-visible,
  body .sheet:focus-visible,
  body .sheet > .sheet-body:focus-visible,
  body .ern:focus-visible,
  body .ern > .ern-scroll:focus-visible,
  body .shell .nc-notice:focus-visible {
    outline: none;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE SELF-CUSTODY NOTICE COMES FIRST
   *
   * A phone stacks the notice (60/61) over the sheets (40/41). This file lifts
   * the sheets to 3401 for the perps terminal, which put the automatic sheets
   * of a first connect (the real-balance ask, an invite from ?ref=) and their
   * dimming over the notice that is meant to be read before either. One step
   * above the sheet stack, and still under the art viewer (3500) and the
   * palette (3600), which does not open while the notice is up.
   * ══════════════════════════════════════════════════════════════════════ */
  body .sheet-backdrop.nc-back {
    z-index: 3402;
  }
  body .nc-notice {
    z-index: 3403;
  }
  /* The keyboard lands on the checkbox; the desktop's text-field rule takes
     the ring off every input, and a checkbox is not a text field. */
  body .shell .nc-notice .nc-check input[type='checkbox']:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 55%, transparent);
    outline-offset: 2px;
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * EARN, BESIDE THE SIDEBAR
   *
   * On a phone Earn covers everything and stops the page under it painting
   * (html.ern-still hides #root). Here it stands where a screen of the app
   * stands, right of the sidebar, like the perps terminal: the sidebar stays
   * in view and a click there leaves Earn first (EarnScreen.tsx). It keeps
   * top: 0, so the header stays covered; Earn's own bar takes its row, 64px
   * with the header's hairline under it.
   *
   * The page under Earn still stops painting. Only the sidebar's four parts
   * (its surface, the brand head, the nav, and the activity dock that stands
   * in it on a desktop) are drawn again: a child can be visible inside a
   * hidden parent, so the rest of #root, the header and everything behind the
   * screen, stays unpainted and out of the Tab order. The dock is there
   * because a stake is exactly the kind of transfer it follows, and it would
   * otherwise vanish for as long as Earn is open. Its controls are safe to
   * leave live: collapsing it changes nothing, and Resume changes the tab,
   * which takes Earn down with the page it was opened from.
   * ══════════════════════════════════════════════════════════════════════ */
  body:has(.shell > nav.bottom-nav) .ern {
    left: var(--gd-side);
  }
  :root.ern-still .shell:has(> nav.bottom-nav)::before,
  :root.ern-still .shell:has(> nav.bottom-nav) > .topbar,
  :root.ern-still .shell:has(> nav.bottom-nav) > nav.bottom-nav,
  :root.ern-still .shell:has(> nav.bottom-nav) > .dock,
  :root.ern-still .shell:has(> nav.bottom-nav) > .dock-puck {
    visibility: visible;
  }

  /* Earn is portalled to <body>, outside .shell, where the app's own focus
     ring (desktop.css, "DESKTOP MANNERS") does not reach, and its controls
     fell back to the page-wide ring drawn a shade stronger. The same ring as
     every other screen; text fields light their box instead, as they do
     everywhere else. */
  body .ern :focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 55%, transparent);
    outline-offset: 2px;
  }
  body .ern input:focus-visible,
  body .ern textarea:focus-visible,
  body .ern select:focus-visible {
    outline: none;
  }

  body:has(.shell > nav.bottom-nav) .ern > .ern-bar {
    min-height: var(--gd-bar, 64px);
    padding-top: 0;
    padding-bottom: 0;
    box-shadow: 0 1px 0 var(--gd-side-line);
  }
  body:has(.shell > nav.bottom-nav) .ern.scrolled > .ern-bar {
    box-shadow: 0 1px 0 var(--gd-side-line), 0 12px 20px -18px rgba(0, 0, 0, 0.65);
  }

  /* Back answers the pointer and says its key. */
  body .ern .ern-back {
    margin-left: -8px;
    padding: 6px 10px 6px 8px;
    border-radius: 10px;
    transition: background 0.15s, opacity 0.12s;
  }
  body .ern .ern-esc {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 20px;
    margin-left: 6px;
    padding: 0 6px;
    border-radius: 6px;
    background: var(--bg-elev-2);
    border: 1px solid var(--stroke-soft);
    border-bottom-width: 2px;
    color: var(--text-faint);
    font: 600 10.5px/1 var(--font);
    letter-spacing: 0.02em;
  }
  @media (hover: hover) {
    body .ern .ern-back:hover {
      background: var(--gd-hover);
    }
  }

  /* Beside the sidebar Earn is 284px narrower than the window, and its
     desktop layout (styles.css, "Earn on a desktop") was sized by the window.
     Its tiers move up by the sidebar's width: the full panorama from 1480px,
     the narrower hero from 1200px, and under that the figure and the clock
     one over the other, with the products two abreast, because a 180px
     figure beside a 356px clock clipped any balance with four digits. */
  @media (min-width: 1200px) and (max-width: 1479px) {
    body:has(.shell > nav.bottom-nav) .ern .ern-hero {
      padding: 38px 34px 46px;
      gap: 26px;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-clock {
      width: 356px;
      margin-right: 18px;
      padding: 18px 20px 20px;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-clock-live .ern-t {
      font-size: 32px;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-clock-row b {
      font-size: 17px;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-clock-offer {
      grid-template-columns: auto 96px minmax(0, 1fr) auto;
      gap: 10px;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-big {
      font-size: 56px;
      letter-spacing: -2px;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-rate {
      font-size: 104px;
      letter-spacing: -4.5px;
    }
  }
  @media (max-width: 1199px) {
    body:has(.shell > nav.bottom-nav) .ern .ern-hero {
      flex-direction: column;
      align-items: flex-start;
      justify-content: flex-start;
      min-height: 0;
      padding: 34px 30px 30px;
      gap: 24px;
    }
    /* left, and short of the far edge, where the filament's lit head is */
    body:has(.shell > nav.bottom-nav) .ern .ern-clock {
      width: min(100%, 440px);
      margin-right: 0;
    }
    body:has(.shell > nav.bottom-nav) .ern .ern-list,
    body:has(.shell > nav.bottom-nav) .ern.ern-pub .ern-list {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  /* ═══════════════════════════════════════════════════════════════════════
   * THE GUIDE, AS A DOCUMENT
   *
   * The phone's guide is one column with its chapters as a strip of chips
   * stuck across the top. Widened, the strip held fourteen chips in one row,
   * half of them off its end where a mouse wheel could not reach, and the
   * prose ran 120 characters to a line. Here it is laid out the way a desktop
   * reads a manual: the masthead across the top, the contents as a column on
   * the left that stays in view, and the chapters in a reading column beside
   * it at a comfortable measure.
   *
   * --docs-top is whatever is fixed across the top of the window: the header
   * in the app, the landing's bar when the guide is read before a wallet is
   * connected (no sidebar, no header), and nothing while the wallet is being
   * verified. Chapters land under it and the contents stick under it.
   * ══════════════════════════════════════════════════════════════════════ */
  body .shell > .docs {
    --docs-top: 0px;
  }
  body .shell:has(> .gd-bar) > .docs {
    --docs-top: var(--gd-bar);
  }
  body .shell:not(:has(> nav.bottom-nav)) > .docs {
    --docs-top: 76px;
  }

  body .shell:has(> nav.bottom-nav) > .docs,
  body .shell:not(:has(> nav.bottom-nav)) > .docs {
    width: min(1180px, 100%);
    margin-inline: auto;
    padding: 28px 40px 80px;
    display: grid;
    grid-template-columns: 216px minmax(0, 720px);
    column-gap: 64px;
    justify-content: center;
    align-content: start;
  }
  body .shell:not(:has(> nav.bottom-nav)) > .docs {
    padding-top: calc(var(--docs-top) + 28px);
  }

  /* The reading column takes every chapter; the Back pill and the masthead
     run across both columns. The contents are placed by row, and the chapters
     flow into the column beside them from the same row down. */
  body .shell > .docs > * {
    grid-column: 2;
    min-width: 0;
  }
  body .shell > .docs > .docs-back,
  body .shell > .docs > .docs-hero {
    grid-column: 1 / -1;
  }

  /* ── the contents ─────────────────────────────────────────────────────── */

  /* A column of its own that sticks under whatever is fixed at the top. It
     scrolls itself when the window is too short for all fourteen (Docs.tsx
     keeps the lit chapter in view by scrolling this column alone), so it
     never needs the page to move. */
  body .shell > .docs > .docs-toc {
    grid-column: 1;
    grid-row: 3 / span 24;
    align-self: start;
    position: sticky;
    top: calc(var(--docs-top) + 28px);
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: calc(100vh - var(--docs-top) - 56px);
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    margin: 28px 0 0;
    padding: 0 6px 0 0;
    background: none;
    border: 0;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    -webkit-mask-image: none;
    mask-image: none;
  }
  body .shell > .docs > .docs-toc .docs-toc-k {
    padding: 0 12px 10px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .shell > .docs > .docs-toc .docs-chip {
    position: relative;
    flex: none;
    width: 100%;
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 8px 12px;
    border: 0;
    border-radius: 10px;
    background: none;
    color: var(--text-dim);
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.35;
    white-space: normal;
    text-align: left;
    transition: background 0.15s, color 0.15s;
  }
  body .shell > .docs > .docs-toc .docs-chip i {
    flex: none;
    width: 18px;
    font-size: 10.5px;
    color: var(--text-faint);
  }
  body .shell > .docs > .docs-toc .docs-chip:active {
    transform: none;
  }
  /* inside the row: the column clips whatever stands outside it */
  body .shell > .docs > .docs-toc .docs-chip:focus-visible {
    outline-offset: -2px;
  }
  /* The chapter being read: lit in place, with the sidebar's own leading bar,
     so the two lists on screen mark "you are here" the same way. */
  body .shell > .docs > .docs-toc .docs-chip.on {
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    color: var(--text);
  }
  body .shell > .docs > .docs-toc .docs-chip.on::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 16px;
    border-radius: 0 3px 3px 0;
    background: var(--ink);
    transform: translateY(-50%);
  }
  body .shell > .docs > .docs-toc .docs-chip.on i {
    color: var(--text-dim);
  }
  @media (hover: hover) {
    body .shell > .docs > .docs-toc .docs-chip:not(.on):hover {
      background: var(--gd-hover);
      color: var(--text);
    }
  }

  /* ── the chapters ─────────────────────────────────────────────────────── */

  /* A jump lands the chapter's top edge on the fixed bar's bottom edge, and
     its 28px of padding is the breathing room above the number. The header
     alone is allowed for: the contents are beside the text now, not over it. */
  body .shell > .docs .docs-sec {
    padding: 28px 0 14px;
    scroll-margin-top: var(--docs-top);
  }
  body .shell > .docs .docs-sec h2 {
    font-size: 32px;
    line-height: 1.12;
    margin-bottom: 16px;
  }
  body .shell > .docs .docs-h3 {
    font-size: 17px;
    margin: 26px 0 10px;
  }
  body .shell > .docs .docs-sec p {
    font-size: 15.5px;
    line-height: 1.72;
    margin-bottom: 14px;
  }
  body .shell > .docs .docs-list li {
    padding-bottom: 10px;
    font-size: 15px;
    line-height: 1.65;
  }
  body .shell > .docs .docs-list li::before {
    top: 10px;
  }
  body .shell > .docs .docs-note {
    font-size: 14px;
  }
  body .shell > .docs .docs-callout {
    padding: 16px 18px;
    font-size: 14.5px;
    line-height: 1.6;
  }
  body .shell > .docs .docs-pill {
    font-size: 13px;
  }
  body .shell > .docs .docs-action li {
    font-size: 14px;
  }
  body .shell > .docs .docs-rule {
    padding: 14px 16px;
    font-size: 14px;
  }
  body .shell > .docs .docs-st-m b {
    font-size: 14.5px;
  }
  body .shell > .docs .docs-st-m span {
    font-size: 13px;
  }
  body .shell > .docs .docs-tr span {
    font-size: 14px;
  }
  body .shell > .docs .docs-tr b {
    font-size: 13.5px;
  }
  body .shell > .docs .docs-diagram {
    max-width: 420px;
    margin: 12px auto 22px;
  }
  body .shell > .docs .docs-faq-q {
    padding: 16px 2px;
    font-size: 15.5px;
  }
  body .shell > .docs .docs-faq-a {
    font-size: 15px;
    line-height: 1.7;
  }
  @media (hover: hover) {
    body .shell > .docs .docs-faq-q:hover .docs-faq-chev {
      color: var(--text);
    }
  }

  /* ── the masthead, the way back, the progress thread ──────────────────── */

  body .shell > .docs > .docs-back {
    justify-self: start;
    margin: 0 0 16px;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
  }
  @media (hover: hover) {
    body .shell > .docs > .docs-back:hover {
      color: var(--text);
      background: var(--glass-2);
      border-color: var(--stroke);
    }
  }
  body .shell > .docs > .docs-hero {
    margin-bottom: 8px;
    padding: 56px 48px 48px;
    border-radius: 28px;
  }
  body .shell > .docs .docs-hero h1 {
    font-size: 50px;
  }
  /* The measure desktop.css gives the masthead inside the app, given here to
     the guide read before a wallet is connected too, so it is one page at one
     measure either way. */
  body .shell > .docs .docs-hero p {
    max-width: 62ch;
    font-size: 16px;
  }
  body .shell > .docs .docs-hero .docs-mist.m1 {
    width: 560px;
    height: 300px;
    left: -120px;
    top: -90px;
  }
  body .shell > .docs .docs-hero .docs-mist.m2 {
    width: 480px;
    height: 280px;
    right: -110px;
    bottom: -110px;
  }
  body .shell > .docs > .docs-footer {
    padding-top: 40px;
  }

  /* The reading thread ran across the very top of the window, over the
     sidebar and along the header's top edge. It runs along the bottom edge
     of whatever is fixed at the top instead, beside the sidebar. */
  body .shell > .docs > .docs-progress {
    top: max(0px, calc(var(--docs-top) - 2.5px));
  }
  body .shell:has(> nav.bottom-nav) > .docs > .docs-progress {
    left: var(--gd-side);
  }

  /* Before a wallet is connected there is no sidebar and no header, and the
     gate that owns the landing's bar is not on screen while the guide is: the
     phone's topbar sat in the flow at the window's far left, and the guide's
     room for a fixed bar left a 150px gap above Back. The guide gets the
     landing's bar, solid enough to read under. */
  body .shell:not(:has(> nav.bottom-nav)):has(> .docs) > .topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 33;
    height: 76px;
    padding: 0 40px;
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    -webkit-backdrop-filter: saturate(1.4) blur(18px);
    backdrop-filter: saturate(1.4) blur(18px);
    border-bottom: 1px solid var(--gd-side-line);
  }
  body .shell:not(:has(> nav.bottom-nav)):has(> .docs) > .topbar .brand-logo {
    width: 34px;
    height: 34px;
    border-radius: 11px;
  }

  /* Where the app's own sidebar stands beside the guide, the window under
     1200px leaves less room: a narrower contents column and a tighter gap
     keep the reading column above 420px, and the masthead scales down. */
  @media (max-width: 1199px) {
    body .shell:has(> nav.bottom-nav) > .docs {
      grid-template-columns: 184px minmax(0, 1fr);
      column-gap: 36px;
      padding-inline: 28px;
    }
    body .shell:has(> nav.bottom-nav) > .docs > .docs-hero {
      padding: 44px 32px 40px;
    }
    body .shell:has(> nav.bottom-nav) > .docs .docs-hero h1 {
      font-size: 42px;
    }
  }
  /* Room for the six doors of the vault two abreast. */
  @media (min-width: 1200px) {
    body .shell > .docs .docs-cards {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 12px;
    }
  }
}

/* =============================================================================
 * LEAD POLISH (desktop audit pass, 2026-09-28)
 * ========================================================================== */
@media (min-width: 1000px) {
  /* Below 1440px the Stars packages' column is about 430px, and five tiles
     across cut their GRAM prices to "0.50352 G…". As many as fit at 104px,
     so every price reads whole. */
  @media (max-width: 1439px) {
    body .shell:has(> nav.bottom-nav) .zp .zp-chips {
      grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
    }
  }
}

/* =============================================================================
 * THE LANDING (2026-10-01)
 *
 * components/GateLanding: ghosterdex.com's front door in a desktop browser,
 * mounted instead of the gate on the plain web (a phone, Telegram and the
 * Android app keep the gate). Owner: "redesign the page to make even more
 * sense and engaging ... that logo is wrong, fix it".
 *
 * It is still the gate: the same fixed layer over the shell (styles.css
 * .gate), so everything that hangs off `.shell:has(> .gate)` still holds. It
 * scrolls inside itself and brings its own nav, so the gate's topbar steps
 * aside while it shows. Every class is lp-*; nothing here reaches the phone
 * gate, the two-column gate a wide Telegram window keeps, or the app.
 * ========================================================================== */
@media (min-width: 1000px) {
  body .shell:has(> .gate.lp) > .topbar {
    display: none;
  }

  body .gate.lp {
    --lp-w: 1180px;
    --lp-pad: clamp(28px, 4vw, 56px);
    --lp-nav: 72px;
    display: block;
    padding: 0;
    gap: 0;
    text-align: left;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--lp-nav) + 12px);
    outline: none;
    background: var(--bg);
    color: var(--text);
  }
  body .lp :focus-visible {
    outline: 2px solid color-mix(in srgb, var(--ink) 70%, transparent);
    outline-offset: 3px;
  }

  /* ── nav ─────────────────────────────────────────────────────────────── */
  body .lp-nav {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 20px;
    height: var(--lp-nav);
    padding: 0 var(--lp-pad);
    border-bottom: 1px solid transparent;
    transition: background-color 0.25s ease, border-color 0.25s ease;
  }
  body .lp-nav.is-solid {
    background: color-mix(in srgb, var(--bg) 76%, transparent);
    -webkit-backdrop-filter: blur(18px) saturate(1.5);
    backdrop-filter: blur(18px) saturate(1.5);
    border-bottom-color: var(--stroke-soft);
  }
  body .lp-brand {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    flex: none;
    border-radius: 12px;
  }
  body .lp-brand-mark {
    width: 34px;
    height: 34px;
    border-radius: 11px;
    border: 1px solid var(--stroke);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--ink) 18%, transparent);
  }
  body .lp-wordmark {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 700;
    letter-spacing: 0.3px;
    color: var(--text);
  }
  body .lp-wordmark em {
    font-style: normal;
    background: linear-gradient(120deg, var(--ink), color-mix(in srgb, var(--ink) 55%, var(--bg)));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  body .lp-links {
    display: flex;
    align-items: center;
    gap: 2px;
    margin: 0 auto;
  }
  body .lp-links > button {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 36px;
    padding: 0 14px;
    border-radius: 999px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-dim);
    white-space: nowrap;
    transition: color 0.15s ease, background-color 0.15s ease;
  }
  body .lp-links > button:hover {
    color: var(--text);
    background: var(--glass);
  }
  body .lp-links > button.on {
    color: var(--text);
    background: var(--glass-2);
  }
  /* GateLanding measured the bar and it cannot hold the links: they leave the
     row but stay laid out, so the next measure still knows their width. */
  body .lp-nav[data-tight] .lp-links {
    position: absolute;
    visibility: hidden;
    pointer-events: none;
  }
  body .lp-nav[data-tight] .lp-nav-end {
    margin-left: auto;
  }
  body .lp-nav-end {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: none;
  }
  body .lp-icon-btn {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 12px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    color: var(--text-dim);
    transition: color 0.15s ease, border-color 0.15s ease;
  }
  body .lp-icon-btn:hover {
    color: var(--text);
    border-color: var(--stroke);
  }
  /* The language, at the top (GateLanding's LangPicker). */
  body .lp-lang {
    position: relative;
  }
  body .lp-lang-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 40px;
    padding: 0 10px 0 12px;
    border-radius: 12px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    color: var(--text-dim);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.5px;
    transition: color 0.15s ease, border-color 0.15s ease;
  }
  body .lp-lang-btn:hover,
  body .lp-lang-btn[aria-expanded='true'] {
    color: var(--text);
    border-color: var(--stroke);
  }
  body .lp-lang-btn > svg:last-child {
    transition: transform 0.2s ease;
  }
  body .lp-lang-btn[aria-expanded='true'] > svg:last-child {
    transform: rotate(180deg);
  }
  body .lp-lang-pop {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 20;
    display: grid;
    min-width: 220px;
    padding: 6px;
    border-radius: 16px;
    border: 1px solid var(--stroke);
    background: var(--sheet-solid);
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.6);
    animation: lpPop 0.18s cubic-bezier(0.2, 0.75, 0.2, 1);
  }
  body .lp-lang-pop button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    height: 38px;
    padding: 0 12px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 600;
    text-align: left;
    color: var(--text-dim);
  }
  body .lp-lang-pop button:hover {
    background: var(--glass-2);
    color: var(--text);
  }
  body .lp-lang-pop button.on {
    color: var(--text);
  }
  body .lp-lang-pop button.on svg {
    color: var(--success);
  }
  :root[data-theme='light'] body .lp-lang-pop {
    box-shadow: 0 24px 60px -20px rgba(20, 25, 32, 0.3);
  }
  @keyframes lpPop {
    from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  }
  @keyframes lpPing {
    0% { box-shadow: 0 0 0 0 color-mix(in srgb, currentColor 55%, transparent); }
    75%, 100% { box-shadow: 0 0 0 8px transparent; }
  }

  /* ── buttons ─────────────────────────────────────────────────────────── */
  body .lp .lp-cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: auto;
    height: 50px;
    margin: 0;
    padding: 0 24px;
    font-size: 15.5px;
    white-space: nowrap;
  }
  body .lp .lp-cta-sm {
    height: 40px;
    padding: 0 14px 0 18px;
    font-size: 14px;
    box-shadow: none;
  }
  body .lp .lp-cta-lg {
    height: 58px;
    padding: 0 28px 0 34px;
    font-size: 17px;
  }
  body .lp .lp-cta:hover:not(:disabled) {
    filter: brightness(1.06);
    transform: translateY(-1px);
  }
  body .lp .lp-cta svg {
    transition: transform 0.2s ease;
  }
  body .lp .lp-cta:hover:not(:disabled) svg {
    transform: translateX(3px);
  }
  /* Busy is not the disabled look: the flow is running (styles.css .gate-cta). */
  body .lp .lp-cta:disabled {
    border: none;
    background: var(--grad);
    color: var(--cta-text);
    cursor: default;
  }
  body .lp-ghost-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 50px;
    padding: 0 20px;
    border-radius: 999px;
    border: 1px solid var(--stroke);
    background: var(--glass);
    color: var(--text);
    font-size: 15px;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.15s ease, border-color 0.15s ease;
  }
  body .lp-ghost-btn:hover {
    background: var(--glass-2);
    border-color: color-mix(in srgb, var(--ink) 26%, transparent);
  }
  body .lp-ghost-btn > svg:last-child {
    color: var(--text-faint);
  }
  body .lp-hero .lp-ghost-btn {
    height: 58px;
    padding: 0 24px;
  }
  body .lp-more {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    text-decoration: none;
    white-space: nowrap;
  }
  body .lp-more:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
  }

  /* ── hero ────────────────────────────────────────────────────────────── */
  body .lp-top {
    position: relative;
    isolation: isolate;
  }
  body .lp-aura {
    position: absolute;
    inset: calc(var(--lp-nav) * -1) 0 -80px;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
  }
  body .lp-aura::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image: radial-gradient(color-mix(in srgb, var(--ink) 13%, transparent) 1px, transparent 1.5px);
    background-size: 28px 28px;
    -webkit-mask-image: radial-gradient(ellipse 56% 62% at 73% 46%, #000 10%, transparent 72%);
    mask-image: radial-gradient(ellipse 56% 62% at 73% 46%, #000 10%, transparent 72%);
    opacity: 0.6;
  }
  body .lp-aura i {
    position: absolute;
    border-radius: 50%;
    filter: blur(90px);
    opacity: 0.5;
    animation: lpAura 22s ease-in-out infinite alternate;
  }
  body .lp-aura i:nth-child(1) {
    left: 50%;
    top: 2%;
    width: 560px;
    height: 560px;
    background: color-mix(in srgb, var(--ink) 13%, transparent);
  }
  body .lp-aura i:nth-child(2) {
    left: -8%;
    top: 40%;
    width: 480px;
    height: 480px;
    background: color-mix(in srgb, var(--success) 24%, transparent);
    animation-delay: -7s;
  }
  body .lp-aura i:nth-child(3) {
    left: 72%;
    top: 50%;
    width: 420px;
    height: 420px;
    background: color-mix(in srgb, var(--gram) 24%, transparent);
    animation-delay: -13s;
  }
  @keyframes lpAura {
    from { transform: translate(0, 0) scale(1); }
    to { transform: translate(48px, -36px) scale(1.14); }
  }
  body .lp-hero {
    display: grid;
    grid-template-columns: minmax(0, 1.04fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(36px, 5vw, 84px);
    max-width: var(--lp-w);
    min-height: max(600px, calc(100vh - var(--lp-nav) - 110px));
    margin: 0 auto;
    padding: 12px var(--lp-pad) 56px;
  }
  body .lp-kicker {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    height: 32px;
    padding: 0 14px 0 12px;
    border-radius: 999px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    color: var(--text-dim);
    font-size: 11.5px;
    font-weight: 800;
    letter-spacing: 1.9px;
    text-transform: uppercase;
  }
  body .lp-kicker i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    color: var(--success);
    background: currentColor;
    animation: lpPing 2.4s ease-out infinite;
  }
  /* The headline leaves no trace: solid at the top, thinning almost to
     nothing by its last line, in any language and at any length. */
  body .lp-title {
    margin: 24px 0 0;
    padding-bottom: 0.08em;
    font-family: var(--font-display);
    font-size: clamp(48px, 5.1vw, 78px);
    font-weight: 700;
    line-height: 1.02;
    letter-spacing: -0.035em;
    text-wrap: balance;
    background: linear-gradient(180deg, var(--text) 0%, var(--text) 48%, color-mix(in srgb, var(--text) 22%, transparent) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  /* English is the shortest of the ten. Every other language (the app sets
     html[lang]) takes a size that keeps the headline to three lines, and the
     buttons' narrower padding, so "Подключить кошелёк" still sits beside
     "Открыть в Telegram". */
  :root:not(:lang(en)) body .lp-title {
    font-size: clamp(40px, 4.3vw, 66px);
  }
  :root:not(:lang(en)) body .lp .lp-hero .lp-cta-lg {
    padding: 0 22px 0 26px;
    font-size: 16px;
  }
  :root:not(:lang(en)) body .lp-hero .lp-ghost-btn {
    padding: 0 18px;
  }
  body .lp-lede {
    max-width: 33em;
    margin: 24px 0 0;
    font-size: 18px;
    line-height: 1.6;
    color: var(--text-dim);
    text-wrap: pretty;
  }
  body .lp-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-top: 36px;
  }
  body .lp-proof {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 20px;
    margin: 30px 0 0;
    padding: 0;
    list-style: none;
  }
  body .lp-proof li,
  body .lp-proof a {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-dim);
  }
  body .lp-proof svg {
    color: var(--success);
  }
  body .lp-proof a {
    text-decoration: underline;
    text-decoration-color: var(--stroke);
    text-underline-offset: 3px;
  }
  body .lp-proof a:hover {
    color: var(--text);
  }
  body .lp-proof a svg {
    color: var(--text-dim);
  }

  /* ── the vault, through a ghost lens ─────────────────────────────────── */
  body .lp-vault {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 26px;
    min-height: 540px;
  }
  body .lp-vault-glow {
    position: absolute;
    inset: 6% 2% 14%;
    border-radius: 50%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--ink) 15%, transparent), transparent);
    filter: blur(26px);
    pointer-events: none;
  }
  /* GateLanding moves the lens by --lx/--ly/--lr; these are only its first
     frame. Both layers sit in one grid cell: the cipher underneath, the
     clear vault on top, cut down to the circle of the lens. */
  body .lp-card {
    --lx: 280px;
    --ly: 150px;
    --lr: 92px;
    position: relative;
    display: grid;
    width: min(440px, 100%);
    overflow: hidden;
    border-radius: 28px;
    border: 1.5px solid transparent;
    background:
      linear-gradient(var(--bg-elev), var(--bg-elev)) padding-box,
      linear-gradient(150deg, color-mix(in srgb, var(--ink) 58%, transparent), color-mix(in srgb, var(--ink) 9%, transparent) 38%, color-mix(in srgb, var(--ink) 4%, transparent) 62%, color-mix(in srgb, var(--ink) 40%, transparent)) border-box;
    box-shadow: 0 60px 100px -50px rgba(0, 0, 0, 0.85);
    animation: lpFloat 8s ease-in-out infinite;
    touch-action: pan-y;
  }
  @keyframes lpFloat {
    0%, 100% { translate: 0 0; }
    50% { translate: 0 -10px; }
  }
  body .lp-layer {
    grid-area: 1 / 1;
    min-width: 0;
    padding: 24px 26px 22px;
  }
  body .lp-clear {
    background: var(--bg-elev);
    -webkit-mask-image: radial-gradient(circle var(--lr) at var(--lx) var(--ly), #000 calc(100% - 1.5px), transparent 100%);
    mask-image: radial-gradient(circle var(--lr) at var(--lx) var(--ly), #000 calc(100% - 1.5px), transparent 100%);
  }
  body .lp-lens {
    position: absolute;
    left: 0;
    top: 0;
    width: calc(var(--lr) * 2);
    height: calc(var(--lr) * 2);
    border-radius: 50%;
    transform: translate(calc(var(--lx) - var(--lr)), calc(var(--ly) - var(--lr)));
    pointer-events: none;
    background: radial-gradient(circle at 32% 26%, color-mix(in srgb, var(--ink) 10%, transparent), transparent 46%);
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--ink) 34%, transparent),
      inset 0 0 0 1px color-mix(in srgb, var(--ink) 8%, transparent),
      inset 0 0 28px color-mix(in srgb, var(--ink) 9%, transparent),
      0 0 46px -8px color-mix(in srgb, var(--success) 45%, transparent);
  }
  body .lp-v-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 34px;
  }
  body .lp-v-lab {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 1.8px;
    color: var(--text-faint);
  }
  body .lp-v-eye {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 11px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    color: var(--text-dim);
  }
  body .lp-v-bal {
    display: flex;
    align-items: center;
    height: 64px;
    margin: 14px 0 12px;
    font-family: var(--font-display);
    font-size: 50px;
    font-weight: 700;
    letter-spacing: -1px;
    white-space: nowrap;
    color: var(--text);
  }
  body .lp-v-bal sup {
    align-self: flex-start;
    margin: 8px 3px 0 0;
    font-size: 24px;
    color: var(--text-dim);
  }
  body .lp-v-bal em {
    font-style: normal;
    color: var(--text-faint);
  }
  body .lp-v-bar {
    display: flex;
    gap: 4px;
    height: 6px;
    margin-bottom: 18px;
  }
  body .lp-v-bar i {
    border-radius: 99px;
  }
  body .lp-v-rows {
    display: grid;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  body .lp-v-rows li {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr) 44px 96px;
    align-items: center;
    gap: 10px;
    height: 32px;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text);
  }
  body .lp-v-sym {
    font-size: 11.5px;
    font-weight: 800;
    color: var(--text-faint);
  }
  body .lp-v-meter {
    height: 6px;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--c) var(--w), color-mix(in srgb, var(--ink) 8%, transparent) var(--w));
  }
  body .lp-v-foot {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    margin-top: 16px;
    padding: 0 12px;
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--success) 26%, transparent);
    background: color-mix(in srgb, var(--success) 10%, transparent);
    color: var(--success);
    font-size: 12px;
    font-weight: 700;
  }
  body .lp-cipher {
    font-family: ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Menlo, Consolas, monospace;
    color: color-mix(in srgb, var(--text) 42%, transparent);
  }
  body .lp-c-lab {
    font-size: 11px;
    letter-spacing: 1px;
  }
  body .lp-cipher .lp-v-eye {
    color: var(--text-faint);
  }
  body .lp-cipher .lp-c-bal {
    font-family: inherit;
    font-size: 30px;
    font-weight: 600;
    letter-spacing: 1px;
    color: color-mix(in srgb, var(--text) 50%, transparent);
  }
  body .lp-c-bar {
    border-radius: 99px;
    background: repeating-linear-gradient(90deg, color-mix(in srgb, var(--text) 18%, transparent) 0 6px, transparent 6px 10px);
  }
  body .lp-cipher .lp-v-rows li {
    font-size: 12.5px;
    font-weight: 500;
    color: inherit;
  }
  body .lp-c-dot {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--text) 10%, transparent);
  }
  body .lp-c-sym {
    font-size: 11px;
  }
  body .lp-c-meter {
    height: 6px;
    border-radius: 99px;
    background: repeating-linear-gradient(90deg, color-mix(in srgb, var(--text) 16%, transparent) 0 4px, transparent 4px 7px);
  }
  body .lp-cipher .lp-c-foot {
    border-color: var(--stroke-soft);
    background: none;
    color: inherit;
    font-weight: 500;
    letter-spacing: 0.5px;
  }
  body .lp-legend {
    position: relative;
    display: flex;
    gap: 20px;
    font-size: 12.5px;
    font-weight: 600;
    white-space: nowrap;
    color: var(--text-faint);
  }
  body .lp-legend span {
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
  body .lp-key-c {
    width: 16px;
    height: 12px;
    border-radius: 3px;
    background: repeating-linear-gradient(90deg, color-mix(in srgb, var(--text) 30%, transparent) 0 3px, transparent 3px 5px);
  }
  body .lp-key-l {
    width: 13px;
    height: 13px;
    border-radius: 50%;
    box-shadow:
      0 0 0 1.5px color-mix(in srgb, var(--ink) 45%, transparent),
      0 0 10px color-mix(in srgb, var(--success) 60%, transparent);
  }
  body .lp-float {
    position: absolute;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 16px;
    border-radius: 14px;
    border: 1px solid var(--stroke);
    background: color-mix(in srgb, var(--bg-elev-2) 86%, transparent);
    color: var(--text);
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
    box-shadow: 0 20px 40px -24px rgba(0, 0, 0, 0.8);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    pointer-events: none;
    animation: lpFloat 6.5s ease-in-out infinite;
  }
  body .lp-float svg {
    color: var(--text-dim);
  }
  body .lp-float.f1 {
    top: 8%;
    right: -2%;
    animation-delay: -1.2s;
  }
  body .lp-float.f2 {
    top: 54%;
    left: -5%;
    animation-delay: -3s;
  }
  body .lp-float.f3 {
    bottom: 14%;
    right: 0;
    animation-delay: -4.6s;
  }

  /* ── coins ───────────────────────────────────────────────────────────── */
  body .lp-coins {
    padding: 30px 0 34px;
    border-block: 1px solid var(--stroke-soft);
    background: color-mix(in srgb, var(--bg-elev) 60%, transparent);
  }
  body .lp-coins-cap {
    max-width: 64ch;
    margin: 0 auto 18px;
    padding: 0 var(--lp-pad);
    text-align: center;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-faint);
  }
  body .lp-marquee {
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
  }
  body .lp-track {
    display: flex;
    width: max-content;
    animation: lpMarquee 52s linear infinite;
  }
  body .lp-marquee:hover .lp-track {
    animation-play-state: paused;
  }
  @keyframes lpMarquee {
    to { transform: translateX(-50%); }
  }
  body .lp-run {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0;
    padding: 0 12px 0 0;
    list-style: none;
  }
  body .lp-run li {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    height: 48px;
    padding: 0 18px 0 11px;
    border-radius: 999px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    font-size: 14px;
    white-space: nowrap;
  }
  body .lp-run li b {
    font-weight: 700;
    color: var(--text);
  }
  body .lp-run li span {
    font-size: 11.5px;
    font-weight: 800;
    color: var(--text-faint);
  }
  body .lp-run li.net {
    padding-left: 17px;
    font-weight: 600;
    color: var(--text-dim);
  }
  body .lp-run li.net i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
  }
  body .lp-coin {
    display: inline-grid;
    place-items: center;
    flex: none;
    border-radius: 50%;
    font-style: normal;
    font-weight: 800;
    line-height: 1;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2), 0 4px 10px -4px rgba(0, 0, 0, 0.5);
  }

  /* ── sections ────────────────────────────────────────────────────────── */
  body .lp-sec {
    max-width: var(--lp-w);
    margin: 0 auto;
    padding: 128px var(--lp-pad) 0;
  }
  body .lp-head {
    max-width: 740px;
    margin: 0 auto 56px;
    text-align: center;
  }
  body .lp-eyebrow {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 2.4px;
    text-transform: uppercase;
    color: var(--success);
  }
  body .lp-head h2 {
    margin: 14px 0 0;
    font-family: var(--font-display);
    font-size: clamp(36px, 3.5vw, 52px);
    font-weight: 700;
    line-height: 1.06;
    letter-spacing: -0.03em;
    color: var(--text);
    text-wrap: balance;
  }
  body .lp-head p {
    max-width: 56ch;
    margin: 18px auto 0;
    font-size: 17px;
    line-height: 1.6;
    color: var(--text-dim);
    text-wrap: pretty;
  }

  /* ── how ─────────────────────────────────────────────────────────────── */
  body .lp-steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 22px;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  body .lp-step-art {
    position: relative;
    display: grid;
    place-items: center;
    height: 200px;
    overflow: hidden;
    border-radius: 24px;
    border: 1px solid var(--stroke-soft);
    background:
      radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--ink) 5%, transparent), transparent 70%),
      var(--bg-elev);
  }
  body .lp-step-n {
    display: block;
    margin-top: 24px;
    font-family: ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Menlo, Consolas, monospace;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 1px;
    color: var(--text-faint);
  }
  body .lp-step h3 {
    margin: 8px 0 0;
    font-family: var(--font-display);
    font-size: 22px;
    letter-spacing: -0.01em;
    color: var(--text);
  }
  body .lp-step p {
    margin: 10px 0 0;
    font-size: 15px;
    line-height: 1.6;
    color: var(--text-dim);
  }
  body .lp-art-key {
    display: flex;
    align-items: center;
  }
  body .lp-mini {
    display: grid;
    justify-items: center;
    gap: 6px;
    width: 116px;
    padding: 16px 10px 14px;
    border-radius: 18px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev-2);
    text-align: center;
  }
  body .lp-mini img,
  body .lp-mini-ic {
    width: 40px;
    height: 40px;
    border-radius: 13px;
  }
  body .lp-mini img {
    border: 1px solid var(--stroke);
  }
  body .lp-mini-ic {
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--success) 13%, transparent);
    color: var(--success);
  }
  body .lp-mini b {
    font-size: 12.5px;
    color: var(--text);
  }
  body .lp-mini .no,
  body .lp-mini .ok {
    font-size: 11px;
    font-weight: 800;
  }
  body .lp-mini .no {
    color: var(--red);
  }
  body .lp-mini .ok {
    color: var(--success);
  }
  body .lp-mini.on {
    border-color: color-mix(in srgb, var(--success) 36%, transparent);
    box-shadow: 0 0 36px -12px color-mix(in srgb, var(--success) 60%, transparent);
  }
  body .lp-wire {
    position: relative;
    width: 60px;
    height: 2px;
    background: repeating-linear-gradient(90deg, var(--stroke) 0 5px, transparent 5px 9px);
  }
  /* What travels is a signature, from the wallet to GhosterDex; never a key. */
  body .lp-wire i {
    position: absolute;
    top: -3px;
    right: 0;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--success);
    box-shadow: 0 0 10px var(--success);
    animation: lpWire 2.4s ease-in-out infinite;
  }
  @keyframes lpWire {
    0% { transform: translateX(0); opacity: 0; }
    15%, 85% { opacity: 1; }
    100% { transform: translateX(-52px); opacity: 0; }
  }
  body .lp-art-dep {
    display: flex;
    align-items: center;
    gap: 20px;
  }
  body .lp-dep-coins {
    display: grid;
    grid-template-columns: repeat(2, 32px);
    gap: 10px;
  }
  body .lp-dep-coins span {
    display: grid;
    animation: lpBob 3.2s ease-in-out infinite;
    animation-delay: calc(var(--i) * -0.8s);
  }
  @keyframes lpBob {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-5px); }
  }
  body .lp-dep-flow {
    display: flex;
    gap: 7px;
  }
  body .lp-dep-flow i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--text-faint);
    animation: lpFlow 1.6s ease-in-out infinite;
    animation-delay: calc(var(--i) * 0.18s);
  }
  @keyframes lpFlow {
    0%, 100% { opacity: 0.25; }
    50% { opacity: 1; background: var(--success); }
  }
  body .lp-dep-vault {
    display: grid;
    place-items: center;
    width: 68px;
    height: 68px;
    border-radius: 22px;
    border: 1px solid color-mix(in srgb, var(--success) 32%, transparent);
    background: color-mix(in srgb, var(--success) 12%, var(--bg-elev-2));
    color: var(--success);
    box-shadow: 0 0 44px -12px color-mix(in srgb, var(--success) 60%, transparent);
  }
  body .lp-sign {
    display: grid;
    gap: 9px;
    width: 210px;
    padding: 16px;
    border-radius: 18px;
    border: 1px solid var(--stroke);
    background: var(--bg-elev-2);
    box-shadow: 0 26px 44px -26px rgba(0, 0, 0, 0.75);
    transform: rotate(-2.5deg);
  }
  body .lp-sign-h {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13.5px;
    font-weight: 800;
    color: var(--text);
  }
  body .lp-sign-l {
    height: 7px;
    border-radius: 99px;
    background: color-mix(in srgb, var(--text) 11%, transparent);
  }
  body .lp-sign-l.s {
    width: 64%;
  }
  body .lp-sign-b {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-top: 4px;
  }
  body .lp-sign-b i,
  body .lp-sign-b b {
    display: grid;
    place-items: center;
    height: 32px;
    border-radius: 10px;
    font-size: 12px;
    font-style: normal;
    font-weight: 700;
  }
  body .lp-sign-b i {
    background: var(--glass-2);
    color: var(--text-dim);
  }
  body .lp-sign-b b {
    background: var(--grad);
    color: var(--cta-text);
    animation: lpPress 3.4s ease-in-out infinite;
  }
  @keyframes lpPress {
    0%, 72%, 100% { transform: scale(1); }
    78% { transform: scale(0.92); }
    86% { transform: scale(1); }
  }

  /* ── privacy ─────────────────────────────────────────────────────────── */
  /* Amber is the app's "anyone can see this" (--public) and mint its
     shielded; the table speaks in the same two colours as the wallet. */
  body .lp-cmp {
    overflow: hidden;
    border-radius: 26px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev);
  }
  body .lp-cmp-row {
    display: grid;
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr) minmax(0, 1.18fr);
    border-top: 1px solid var(--stroke-soft);
  }
  body .lp-cmp-row:first-child {
    border-top: 0;
  }
  body .lp-cmp-row > span {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 74px;
    padding: 16px 26px;
    font-size: 15px;
    line-height: 1.45;
  }
  body .lp-cmp-row > [role='rowheader'] {
    font-weight: 700;
    color: var(--text);
  }
  body .lp-cmp-row > .pub {
    color: var(--text-dim);
  }
  body .lp-cmp-row > .pub svg {
    flex: none;
    color: var(--public);
  }
  body .lp-cmp-row > .gho {
    border-left: 1px solid color-mix(in srgb, var(--success) 22%, transparent);
    background: color-mix(in srgb, var(--success) 6%, transparent);
    font-weight: 600;
    color: var(--text);
  }
  body .lp-cmp-row > .gho svg {
    flex: none;
    color: var(--success);
  }
  body .lp-cmp-hd > span {
    min-height: 60px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 1.6px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .lp-cmp-hd > .pub {
    color: var(--public);
  }
  body .lp-cmp-hd > .gho {
    color: var(--success);
  }
  body .lp-cmp-hd > .gho img {
    width: 24px;
    height: 24px;
    border-radius: 8px;
    border: 1px solid var(--stroke);
  }
  body .lp-note {
    max-width: 68ch;
    margin: 20px auto 0;
    text-align: center;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--text-faint);
  }

  /* ── features ────────────────────────────────────────────────────────── */
  body .lp-bento {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-auto-rows: minmax(220px, auto);
    grid-template-areas:
      'swap swap send send'
      'swap swap dep wd'
      'exp exp perps agent'
      'limit stock gram gram';
    gap: 16px;
  }
  body .lp-tile.t-swap { grid-area: swap; }
  body .lp-tile.t-send { grid-area: send; }
  body .lp-tile.t-dep { grid-area: dep; }
  body .lp-tile.t-wd { grid-area: wd; }
  body .lp-tile.t-exp { grid-area: exp; }
  body .lp-tile.t-perps { grid-area: perps; }
  body .lp-tile.t-agent { grid-area: agent; }
  body .lp-tile.t-limit { grid-area: limit; }
  body .lp-tile.t-stock { grid-area: stock; }
  body .lp-tile.t-gram { grid-area: gram; }
  body .lp-tile {
    position: relative;
    isolation: isolate;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 24px;
    border-radius: 24px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev);
  }
  body .lp-tile::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    opacity: 0;
    background: radial-gradient(440px circle at var(--mx, 50%) var(--my, 0%), color-mix(in srgb, var(--ink) 8%, transparent), transparent 62%);
    transition: opacity 0.3s ease;
  }
  body .lp-tile:hover {
    border-color: var(--stroke);
  }
  body .lp-tile:hover::before {
    opacity: 1;
  }
  body .lp-tile-ic {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: 13px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass-2);
    color: var(--text);
  }
  body .lp-tile h3 {
    margin: 18px 0 0;
    font-family: var(--font-display);
    font-size: 20px;
    letter-spacing: -0.01em;
    color: var(--text);
  }
  body .lp-tile p {
    max-width: 44ch;
    margin: 8px 0 0;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--text-dim);
  }
  body .lp-ticket {
    display: grid;
    margin-top: auto;
    padding-top: 26px;
  }
  body .lp-tk-row {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 8px 12px;
    padding: 16px 18px;
    border-radius: 18px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev-2);
  }
  body .lp-tk-k {
    grid-column: 1 / -1;
    font-size: 12px;
    font-weight: 700;
    color: var(--text-faint);
  }
  body .lp-tk-c {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
  }
  body .lp-tk-a {
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 700;
    letter-spacing: 1px;
    color: var(--text-dim);
  }
  body .lp-tk-flip {
    position: relative;
    z-index: 1;
    justify-self: center;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    margin: -11px 0;
    border-radius: 12px;
    border: 1px solid var(--stroke);
    background: var(--bg-elev);
    color: var(--text);
    animation: lpTurn 5s ease-in-out infinite;
  }
  @keyframes lpTurn {
    0%, 78% { transform: rotate(0deg); }
    90%, 100% { transform: rotate(180deg); }
  }
  body .lp-tk-note {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 14px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--success);
  }
  body .lp-send {
    position: relative;
    align-self: center;
    width: 260px;
    height: 108px;
    margin-top: auto;
  }
  body .lp-send-arc {
    position: absolute;
    left: 0;
    top: 0;
    width: 260px;
    height: 92px;
    overflow: visible;
  }
  body .lp-send-arc path {
    fill: none;
    stroke: var(--stroke);
    stroke-width: 1.5;
    stroke-dasharray: 4 6;
  }
  body .lp-send-a,
  body .lp-send-b {
    position: absolute;
    top: 52px;
    width: 44px;
    height: 44px;
    border-radius: 14px;
    border: 1px solid var(--stroke);
  }
  body .lp-send-a {
    left: 2px;
  }
  body .lp-send-b {
    right: 2px;
    transform: scaleX(-1);
  }
  body .lp-send-dot {
    display: none;
  }
  @supports (offset-path: path('M0 0')) {
    body .lp-send-dot {
      position: absolute;
      left: 0;
      top: 0;
      display: block;
      width: 10px;
      height: 10px;
      border-radius: 50%;
      background: var(--success);
      box-shadow: 0 0 12px var(--success);
      offset-path: path('M24 70 C 84 -6, 176 -6, 236 70');
      offset-rotate: 0deg;
      animation: lpSend 2.8s cubic-bezier(0.45, 0, 0.55, 1) infinite;
    }
  }
  @keyframes lpSend {
    0% { offset-distance: 0%; opacity: 0; }
    12%, 88% { opacity: 1; }
    100% { offset-distance: 100%; opacity: 0; }
  }
  body .lp-send-tags {
    position: absolute;
    left: 50%;
    bottom: 0;
    display: flex;
    gap: 6px;
    translate: -50% 0;
  }
  body .lp-send-tags b {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 9px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--success) 10%, transparent);
    color: var(--success);
    font-size: 11px;
    font-weight: 800;
  }
  body .lp-exp {
    display: flex;
    gap: 10px;
    margin-top: auto;
    padding-top: 22px;
  }
  body .lp-exp span {
    flex: 1;
    display: grid;
    justify-items: center;
    gap: 8px;
    padding: 18px 10px 16px;
    border-radius: 18px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev-2);
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
  }
  body .lp-exp span:nth-child(1) svg { color: #ff7ab6; }
  body .lp-exp span:nth-child(2) svg { color: #ffc23d; }
  body .lp-exp span:nth-child(3) svg { color: #a98bff; }
  body .lp-tile.t-perps p {
    margin-bottom: 14px;
  }
  body .lp-candles {
    display: block;
    width: 100%;
    height: 70px;
    margin-top: auto;
    overflow: visible;
  }
  body .lp-candles line {
    stroke-width: 1.5;
  }
  body .lp-candles .up line { stroke: var(--success); }
  body .lp-candles .up rect { fill: var(--success); }
  body .lp-candles .dn line { stroke: var(--red); }
  body .lp-candles .dn rect { fill: var(--red); }
  body .lp-candles .lp-cd-entry {
    stroke: var(--stroke);
    stroke-dasharray: 3 4;
  }
  body .lp-agents {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: auto;
    padding-top: 16px;
  }
  body .lp-agents span {
    display: inline-flex;
    align-items: center;
    height: 28px;
    padding: 0 11px;
    border-radius: 999px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    font-size: 12px;
    font-weight: 700;
    color: var(--text-dim);
  }
  body .lp-agents .lp-agents-face {
    justify-content: center;
    width: 28px;
    padding: 0;
    color: var(--text);
  }
  body .lp-tile.t-limit p {
    margin-bottom: 14px;
  }
  body .lp-limit {
    display: block;
    width: 100%;
    height: 60px;
    margin-top: auto;
    overflow: visible;
  }
  body .lp-lim-line {
    stroke: color-mix(in srgb, var(--text) 32%, transparent);
    stroke-width: 1.2;
    stroke-dasharray: 4 4;
  }
  /* Drawn up to the line, held, then let go; still, it is simply drawn. */
  body .lp-lim-price {
    fill: none;
    stroke: var(--text-dim);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-dasharray: 100;
    stroke-dashoffset: 0;
    animation: lpDraw 4.4s ease-in-out infinite;
  }
  body .lp-lim-hit {
    fill: var(--success);
    filter: drop-shadow(0 0 6px var(--success));
    transform-box: fill-box;
    transform-origin: center;
    animation: lpHit 4.4s ease-in-out infinite;
  }
  @keyframes lpDraw {
    0% { stroke-dashoffset: 100; opacity: 1; }
    55% { stroke-dashoffset: 0; }
    90% { opacity: 1; }
    100% { stroke-dashoffset: 0; opacity: 0; }
  }
  @keyframes lpHit {
    0%, 52% { opacity: 0; transform: scale(0.3); }
    62%, 90% { opacity: 1; transform: scale(1); }
    100% { opacity: 0; transform: scale(1); }
  }
  body .lp-tickers {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: auto;
    padding-top: 16px;
  }
  body .lp-tickers span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 30px;
    padding: 0 12px 0 10px;
    border-radius: 10px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev-2);
    font-family: ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Menlo, Consolas, monospace;
    font-size: 12px;
    font-weight: 700;
    color: var(--text);
  }
  body .lp-tickers i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
  }
  body .lp-switch-art {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    margin-top: auto;
    padding-top: 20px;
  }
  body .lp-switch {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1fr;
    width: 270px;
    padding: 4px;
    border-radius: 999px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev-2);
  }
  body .lp-switch-knob {
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: calc(50% - 4px);
    border-radius: 999px;
    border: 1px solid var(--stroke);
    background: var(--glass-2);
    animation: lpKnob 7s ease-in-out infinite;
  }
  @keyframes lpKnob {
    0%, 42% { transform: translateX(0); }
    50%, 92% { transform: translateX(100%); }
    100% { transform: translateX(0); }
  }
  body .lp-switch > span {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    height: 40px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
  }
  body .lp-switch .v svg { color: var(--success); }
  body .lp-switch .g svg { color: var(--gram); }
  body .lp-switch-tags {
    display: flex;
    gap: 8px;
  }
  /* The vault says PRIVATE, the Gram wallet says PUBLIC (the guide's words),
     in the wallet's colours for each: the brand blue never carries a claim. */
  body .lp-switch-tags b {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 10px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 1.2px;
    text-transform: uppercase;
  }
  body .lp-switch-tags .v {
    background: color-mix(in srgb, var(--success) 11%, transparent);
    color: var(--success);
  }
  body .lp-switch-tags .g {
    background: color-mix(in srgb, var(--public) 12%, transparent);
    color: var(--public);
  }

  /* ── fees ────────────────────────────────────────────────────────────── */
  body .lp-fees {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }
  body .lp-fee {
    display: grid;
    align-content: start;
    gap: 8px;
    padding: 26px 24px;
    border-radius: 22px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev);
  }
  body .lp-fee span {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .lp-fee b {
    font-family: var(--font-display);
    font-size: clamp(30px, 2.8vw, 42px);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--text);
  }
  body .lp-fee.free b {
    color: var(--success);
  }
  /* A figure takes the largest size at which its --n characters (GateLanding
     sets it) fit the card: "0.20%" and "Free" keep the figures' size, a
     long word like "Безкоштовно" comes down to fit. */
  body .lp-fee {
    container-type: inline-size;
  }
  body .lp-fee b:not(.lp-fee-words) {
    font-size: clamp(20px, min(2.8vw, calc(100cqi / (var(--n, 5) * 0.68))), 42px);
  }
  /* a phrase, not a figure: at the figures' size it ran to three lines in
     Spanish and stretched the whole row */
  body .lp-fee b.lp-fee-words {
    padding-top: 6px;
    font-size: clamp(22px, 2vw, 28px);
    line-height: 1.2;
    text-wrap: balance;
  }
  body .lp-fee small {
    font-size: 14px;
    color: var(--text-dim);
  }
  body .lp-invite {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-top: 16px;
    padding: 18px 22px;
    border-radius: 20px;
    border: 1px dashed var(--stroke);
  }
  body .lp-invite-ic {
    display: grid;
    place-items: center;
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: 13px;
    background: color-mix(in srgb, var(--success) 12%, transparent);
    color: var(--success);
  }
  body .lp-invite p {
    flex: 1;
    margin: 0;
    font-size: 15px;
    line-height: 1.5;
    color: var(--text-dim);
  }
  body .lp-invite b {
    color: var(--text);
  }

  /* ── trust ───────────────────────────────────────────────────────────── */
  body .lp-cards {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }
  body .lp-card2 {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 26px 24px;
    border-radius: 22px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev);
  }
  body .lp-card2-ic {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: 13px;
    border: 1px solid color-mix(in srgb, var(--success) 22%, transparent);
    background: color-mix(in srgb, var(--success) 11%, transparent);
    color: var(--success);
  }
  body .lp-card2 h3 {
    margin: 18px 0 0;
    font-family: var(--font-display);
    font-size: 19px;
    color: var(--text);
  }
  body .lp-card2 p {
    margin: 8px 0 0;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--text-dim);
  }
  body .lp-card2 .lp-more {
    margin-top: 14px;
  }
  body .lp-warn {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    max-width: 780px;
    margin: 22px auto 0;
    padding: 16px 20px;
    border-radius: 16px;
    border: 1px solid color-mix(in srgb, var(--amber) 28%, transparent);
    background: color-mix(in srgb, var(--amber) 8%, transparent);
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-dim);
  }
  body .lp-warn svg {
    flex: none;
    margin-top: 2px;
    color: var(--amber);
  }
  body .lp-warn b {
    color: var(--text);
  }

  /* ── where ───────────────────────────────────────────────────────────── */
  body .lp-apps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.35fr);
    gap: 16px;
  }
  body .lp-app {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 26px 24px 24px;
    border-radius: 22px;
    border: 1px solid var(--stroke-soft);
    background: var(--bg-elev);
  }
  body .lp-app-ic {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: 14px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass-2);
    color: var(--text);
  }
  body .lp-app-ic.tg {
    color: #2aabee;
  }
  body .lp-app-ic.an {
    color: #3ddc84;
  }
  body .lp-aa {
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 700;
  }
  body .lp-app h3 {
    margin: 18px 0 0;
    font-family: var(--font-display);
    font-size: 20px;
    color: var(--text);
  }
  body .lp-app p {
    flex: 1;
    margin: 8px 0 20px;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--text-dim);
  }
  body .lp-app .lp-ghost-btn,
  body .lp .lp-app .lp-cta {
    height: 44px;
    padding: 0 18px;
    font-size: 14px;
  }
  body .lp-lang-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 16px;
  }
  body .lp-lang-list button {
    height: 32px;
    padding: 0 12px;
    border-radius: 999px;
    border: 1px solid var(--stroke-soft);
    background: var(--glass);
    font-size: 13px;
    font-weight: 600;
    color: var(--text-dim);
    transition: color 0.15s ease, border-color 0.15s ease;
  }
  body .lp-lang-list button:hover {
    border-color: var(--stroke);
    color: var(--text);
  }
  body .lp-lang-list button.on {
    border-color: transparent;
    background: var(--grad);
    color: var(--cta-text);
  }

  /* ── last word ───────────────────────────────────────────────────────── */
  body .lp-final {
    position: relative;
    isolation: isolate;
    display: grid;
    justify-items: center;
    max-width: var(--lp-w);
    margin: 150px auto 0;
    padding: 80px var(--lp-pad) 90px;
    text-align: center;
  }
  body .lp-final-glow {
    position: absolute;
    inset: -40px 0 0;
    z-index: -1;
    background:
      radial-gradient(560px 280px at 50% 34%, color-mix(in srgb, var(--success) 13%, transparent), transparent 70%),
      radial-gradient(520px 260px at 50% 62%, color-mix(in srgb, var(--ink) 8%, transparent), transparent 70%);
    pointer-events: none;
  }
  body .lp-final-mark {
    width: 92px;
    height: 92px;
    border-radius: 28px;
    border: 1px solid var(--stroke);
    box-shadow: 0 34px 70px -26px color-mix(in srgb, var(--ink) 36%, transparent);
    animation: lpFloat 7s ease-in-out infinite;
  }
  body .lp-final h2 {
    margin: 32px 0 0;
    font-family: var(--font-display);
    font-size: clamp(42px, 4.6vw, 68px);
    font-weight: 700;
    line-height: 1.03;
    letter-spacing: -0.035em;
    color: var(--text);
    text-wrap: balance;
  }
  body .lp-final p {
    margin: 14px 0 32px;
    font-size: 18px;
    color: var(--text-dim);
  }

  /* ── footer ──────────────────────────────────────────────────────────── */
  body .lp-foot {
    border-top: 1px solid var(--stroke-soft);
  }
  body .lp-foot-top {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) repeat(3, minmax(0, 1fr));
    gap: 32px;
    max-width: var(--lp-w);
    margin: 0 auto;
    padding: 56px var(--lp-pad) 40px;
  }
  body .lp-foot-brand p {
    max-width: 30ch;
    margin: 14px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-dim);
  }
  body .lp-foot-col {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 11px;
  }
  body .lp-foot-col b {
    margin-bottom: 3px;
    font-size: 11.5px;
    font-weight: 800;
    letter-spacing: 1.6px;
    text-transform: uppercase;
    color: var(--text-faint);
  }
  body .lp-foot-col a,
  body .lp-foot-col button,
  body .lp-foot-base a,
  body .lp-foot-base button {
    padding: 0;
    font-size: 14px;
    text-align: left;
    text-decoration: none;
    color: var(--text-dim);
  }
  body .lp-foot-col a:hover,
  body .lp-foot-col button:hover,
  body .lp-foot-base a:hover,
  body .lp-foot-base button:hover {
    color: var(--text);
  }
  body .lp-foot-base {
    display: flex;
    align-items: center;
    gap: 24px;
    max-width: var(--lp-w);
    margin: 0 auto;
    padding: 22px var(--lp-pad) 36px;
    border-top: 1px solid var(--stroke-soft);
    font-size: 13px;
    color: var(--text-faint);
  }
  body .lp-foot-base a,
  body .lp-foot-base button {
    font-size: 13px;
  }

  /* ── rising into place (GateLanding sets data-anim, then data-in) ────── */
  body .lp[data-anim] .lp-rise {
    transition:
      opacity 0.8s cubic-bezier(0.2, 0.75, 0.2, 1) var(--d, 0ms),
      transform 0.8s cubic-bezier(0.2, 0.75, 0.2, 1) var(--d, 0ms),
      border-color 0.2s ease;
  }
  body .lp[data-anim] .lp-rise:not([data-in]) {
    opacity: 0;
    transform: translateY(26px);
  }

  /* ── light ───────────────────────────────────────────────────────────── */
  :root[data-theme='light'] body .lp-card {
    box-shadow: 0 60px 100px -50px rgba(20, 25, 32, 0.35);
  }
  :root[data-theme='light'] body .lp-float,
  :root[data-theme='light'] body .lp-sign {
    box-shadow: 0 20px 40px -24px rgba(20, 25, 32, 0.3);
  }
  :root[data-theme='light'] body .lp-aura i {
    opacity: 0.32;
  }
  :root[data-theme='light'] body .lp-coin {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3), 0 3px 8px -4px rgba(20, 25, 32, 0.4);
  }

  /* ── narrower desktops ───────────────────────────────────────────────── */
  @media (max-width: 1199px) {
    body .lp-links > button {
      padding: 0 10px;
      font-size: 13.5px;
    }
    /* a narrower language button keeps English's links in the bar at 1000px */
    body .lp-lang-btn {
      gap: 5px;
      padding: 0 8px 0 10px;
    }
    /* the two hero buttons stay side by side down to 1000px */
    body .lp .lp-hero .lp-cta-lg {
      padding: 0 22px 0 26px;
      font-size: 16px;
    }
    body .lp-hero .lp-ghost-btn {
      padding: 0 18px;
    }
    body .lp-bento {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      grid-template-areas:
        'swap send'
        'swap dep'
        'wd exp'
        'perps agent'
        'limit stock'
        'gram gram';
    }
    body .lp-cards,
    body .lp-apps,
    body .lp-fees {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    body .lp-vault {
      min-height: 500px;
    }
  }
  @media (max-width: 1099px) {
    body .lp-links > button > svg {
      display: none;
    }
    body .lp-float {
      display: none;
    }
  }
  @media (min-width: 1600px) {
    body .gate.lp {
      --lp-w: 1280px;
    }
    /* the vault keeps its proportions to the headline on a big screen
       (GateLanding divides the scale out of the lens's pointer) */
    body .lp-vault {
      scale: 1.12;
    }
  }

  /* ── stillness ───────────────────────────────────────────────────────── */
  @media (prefers-reduced-motion: reduce) {
    body .gate.lp {
      scroll-behavior: auto;
    }
    body .lp *:not(.spinner),
    body .lp *::before,
    body .lp *::after {
      animation: none !important;
    }
    body .lp-send-dot {
      display: none !important;
    }
    body .lp-track,
    body .lp-run {
      flex-wrap: wrap;
      justify-content: center;
    }
    body .lp-track {
      width: auto;
    }
    body .lp-run[aria-hidden] {
      display: none;
    }
  }
}
