/* ═══════════════════════════════════════════════════════════════════════════
   LOGIN / CREATE — MOBILE STABILITY SHEET                       (2026-08-15)

   Loaded LAST on index.php and create.php, so it wins by source order over
   login-luxe.css, login-fx.css and create.css without needing !important.

   Its single job: the phone. The landing is one fixed screen with a live 3D
   canvas behind it; on a phone the browser's URL bar hides and shows while
   you touch, every one of those changes the viewport height, and anything
   sized in vh/dvh re-lays-out on each one — which reads as flicker and jump.
   Rules that fight that belong HERE, not in the desktop sheets.

   ───────────────────────────────────────────────────────────────────────────
   WHAT ACTUALLY MOVES ON A PHONE, AND WHAT DOES NOT

   `vh` and `@media (max-height:…)` are resolved by every mobile browser
   against the LARGE viewport — the one you get with the URL bar hidden — and
   are therefore CONSTANT while the bar slides. (That is the same rule that
   makes `100vh` famously taller than the visible page on iOS.) They change
   only on a rotation.

   `dvh` and `window.innerHeight` are the two that track the bar live, several
   times a second, and they are the whole bug:
     · login-luxe.css   body.wiz.luxe { height:100dvh }
     · create.css       body.pick-body{ height:100dvh }
       Both bodies are flex columns whose middle child (.lux-air / .pk-air) is
       the spring, so every pixel the shell loses is a pixel the sign-in plate
       and the wizard rail jump by. Measured on an emulated 390x844 phone:
       752px of travel with a 62px single-frame jump over 12 bar movements.
     · login-luxe.css   .lux-auth-card .lux-view { max-height:calc(100dvh …) }
       the REGISTER card's scroll cap.
     · login3d.js:1571  renderer.setSize(innerWidth, innerHeight) — a full
       WebGL drawing-buffer reallocation (a cleared frame) per event.

   So the fix is aimed at `dvh` and `innerHeight`, and nothing else.

   ───────────────────────────────────────────────────────────────────────────
   ⛔ WHY THIS FILE DOES NOT RESTATE OTHER SHEETS' VALUES

   The first version of this file froze ~25 `vh` clamps by restating them as
   calc(var(--vhu) * N). It measured perfectly — and then two things happened
   that killed the approach for good:
     1. Restating `.lux-signin-msg.form-msg:empty{margin-top}` from
        login-luxe.css out-specified a LATER sheet that deliberately re-tunes
        that slot, and moved the whole sign-in plate 3.94px. Because this file
        loads last, ANY value copied out of another sheet silently wins over
        every later override of it.
     2. create.css was rewritten by its owner mid-session — new `--ch`,
        `--pl-*`, .pk-crown, .pk-houses, .pk-hlabel tokens, changed .pk-arch
        and .pk-label values, every line number shifted. The copies here were
        stale within the hour, and a stale copy pins a WRONG size on the phone.

   So: this sheet contains no number that belongs to another sheet. The `dvh`
   freeze is done in login-mobile.js by rewriting the `dvh` lengths in the
   CSSOM in place — whatever the sheets say today, that is what gets frozen.

   ⚠ If you add a rule here, run the mobile layout diff (this sheet enabled vs
   disabled at 390x844 and 844x390, offsetTop/Left/W/H + computed geometry over
   every element on the page) and make sure the ONLY differences are the ones
   you meant to make. That check is what caught (1) above.
   ═══════════════════════════════════════════════════════════════════════ */

@media (hover:none) and (pointer:coarse) {

  /* ═════════════════════ 1. THE PAGE ITSELF ═════════════════════════════
     No rubber-band: the body is already overflow:hidden, but iOS bounces a
     fixed page anyway and drags the whole 3D frame with it. No double-tap
     zoom (touch-action:manipulation keeps pinch-zoom, so this costs no
     accessibility). No text inflation on rotate.                          */
  html.wiz-mlock,
  html.wiz-mlock body {
    overscroll-behavior: none;
    -webkit-text-size-adjust: 100%;
            text-size-adjust: 100%;
  }
  html.wiz-mlock body {
    touch-action: manipulation;
  }

  /* ═════════════════════ 2. THE SHELL ═══════════════════════════════════
     login-mobile.js has already rewritten `height:100dvh` to a frozen px in
     the CSSOM, so this is belt-and-braces: it pins the shell even if a sheet
     ever grows a `min-height`/`max-height` of its own, and it is the one
     place a reader can see what --vh100 is for. --vh100 only ever changes on
     a real rotation.                                                       */
  html.wiz-mlock body.wiz.luxe,
  html.wiz-mlock body.wiz.pick-body {
    height: var(--vh100);
    min-height: var(--vh100);
    max-height: var(--vh100);
  }

  /* ═════════════════════ 3. REPAINT COST ════════════════════════════════
     backdrop-filter over a live WebGL canvas re-reads the whole composited
     backdrop every frame on a phone GPU — the classic mobile flicker source.
     Both of these are full-screen veils that sit directly on top of the 3D
     castle, and neither has anything behind it worth blurring that its own
     gradient cannot carry. Desktop keeps the blur.
     (login-luxe.css .lux-auth-veil, wizloria.css .modal-veil)             */
  html.wiz-mlock .lux-auth-veil,
  html.wiz-mlock .modal-veil {
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
  /* the veils get a little more body to pay for the blur they lost */
  html.wiz-mlock .lux-auth-veil {
    background: radial-gradient(120% 90% at 50% 0%, rgba(11,20,40,.62), rgba(4,9,20,.90));
  }
  html.wiz-mlock .modal-veil { background: rgba(3,2,1,.90) }
}
