/* ============================================================
   mobile-perf.css — THE TOUCH-DEVICE RENDERING BUDGET.

   Linked LAST from every layout (after primunity.css / site.css and the other
   standard sheets), and written `html`-prefixed + doubled-class + !important on
   the perf-critical properties for the reason motion-standard.css states: page
   sheets are <link>ed AFTER the layout's own, so source order alone is not
   enough. A silently-lost override here does not look like a bug — it looks like
   a slow phone, which is exactly how this shipped unnoticed.

   ── WHAT WAS MEASURED, AND ON WHAT ────────────────────────────────────────────
   A real tenant business site (t7662 `demo-krvspyt-dymvnh-27`, its published
   home page) rendered at a 390x844 iPhone viewport. Three costs compound, and
   the third is the one that made scrolling stutter rather than merely be slow:

     1. THE AMBIENT BACKGROUND IS NEVER STILL. partials/background.php paints a
        position:fixed .bg-layer holding three .bg-orb (676x676, 540x540, 518x518
        CSS px) at `filter:blur(100px)` plus a .bg-aurora (532x330) at
        `filter:blur(60px)`. MEASURED: 3.62x the viewport's area is under blur on
        a 390px-wide screen. Every one of them also runs an INFINITE
        `pmuAuroraDrift` / `pmuAurora` animation whose keyframes change `scale`
        — and scaling a filtered element invalidates the filter's cached raster,
        so the blur is re-convolved every frame, for ever, on a device with a
        dpr of 3 (~10.7M device px). background.css carried NO reduced-motion
        guard and no mobile guard of any kind.

     2. TWENTY-ONE BACKDROP-FILTER PASSES PER FRAME. `.card,.panel` declares
        `backdrop-filter:saturate(150%) blur(var(--glass-blur))` (components.css
        :74) and the page renders 20 cards; `.nav.scrolled` adds a 22nd at
        blur(20px), pinned on screen for the whole scroll (layout.css:12). A
        backdrop-filter re-samples and re-blurs the region BEHIND the element
        every frame it moves — i.e. every frame of a scroll.

     3. 1 AND 2 MULTIPLY. The backdrop those 20 cards blur IS the animated orb
        layer from 1. Because that backdrop never stops changing, nothing the
        compositor caches stays valid, so no frame can reuse the previous
        frame's work. Fixing either alone leaves the other paying full price;
        this sheet fixes both on the devices that cannot afford them.

   ── WHY THE FALLBACK LOOK IS NOT A NEW DESIGN DECISION ───────────────────────
   components.css:94 already declares what a card looks like with no
   backdrop-filter — `@supports not (backdrop-filter:blur(1px)) { .card,.panel
   {background:var(--surface)} }` — and ships it to every browser lacking the
   property. This sheet reuses THOSE values rather than inventing a mobile skin,
   so a phone gets a look the design system already sanctions. The glass reads as
   glass at desk distance on a large canvas; at 390px over a static background it
   is a texture nobody can see and everybody pays for.

   ── SCOPE: WHO IS AFFECTED ───────────────────────────────────────────────────
   `(hover:none), (pointer:coarse), (max-width:900px)` — phones and tablets, and
   a narrow desktop window. DESKTOP WITH A MOUSE IS DELIBERATELY UNTOUCHED: the
   look there is approved and it is not where the complaint came from. The one
   exception is the reduced-motion block at the bottom, which applies everywhere
   because an infinite background animation with no reduced-motion guard is an
   accessibility defect on any device.
   ============================================================ */

@media (hover: none), (pointer: coarse), (max-width: 900px) {

  /* ---------- 1. THE AMBIENT BACKGROUND STOPS MOVING AND STOPS BLURRING ------
     The orbs keep their colour and their placement; they lose the 100px blur
     convolution and the infinite scale animation. `filter:blur()` on a element
     whose background is ALREADY a radial-gradient falling off to transparent is
     close to a no-op visually — it mostly softens the outer stop — so the stops
     below are widened to reproduce that falloff for free. Net effect on screen:
     the same wash of brand colour. Net effect on the compositor: one static
     gradient layer that is painted once and never invalidated again. */
  html .bg-orb,
  html .bg-aurora {
    filter: none !important;
    -webkit-filter: none !important;
    animation: none !important;
    opacity: 1 !important;      /* pmuOrbIn no longer runs to fade them in */
  }
  html .bg-orb--1 {
    background: radial-gradient(circle,
      rgba(30,80,200,.15) 0%, rgba(30,80,200,.10) 32%,
      rgba(30,80,200,.04) 58%, transparent 78%) !important;
  }
  html .bg-orb--2 {
    background: radial-gradient(circle,
      rgba(22,184,245,.14) 0%, rgba(22,184,245,.09) 32%,
      rgba(22,184,245,.035) 58%, transparent 78%) !important;
  }
  html .bg-orb--3 {
    background: radial-gradient(circle,
      rgba(10,42,122,.11) 0%, rgba(10,42,122,.07) 32%,
      rgba(10,42,122,.03) 58%, transparent 78%) !important;
  }
  html .bg-aurora {
    background: linear-gradient(90deg, transparent,
      rgba(30,80,200,.06) 25%, rgba(22,184,245,.075) 50%,
      rgba(10,42,122,.05) 75%, transparent) !important;
  }
  [data-theme="dark"] .bg-orb--1 {
    background: radial-gradient(circle,
      rgba(30,90,220,.26) 0%, rgba(30,90,220,.17) 32%,
      rgba(30,90,220,.07) 58%, transparent 78%) !important;
  }
  [data-theme="dark"] .bg-orb--2 {
    background: radial-gradient(circle,
      rgba(22,184,245,.19) 0%, rgba(22,184,245,.12) 32%,
      rgba(22,184,245,.05) 58%, transparent 78%) !important;
  }
  [data-theme="dark"] .bg-orb--3 {
    background: radial-gradient(circle,
      rgba(10,42,122,.33) 0%, rgba(10,42,122,.21) 32%,
      rgba(10,42,122,.09) 58%, transparent 78%) !important;
  }

  /* The cursor-following glow cannot be followed by a finger. core/motion.js
     initGlow() ALREADY declines to bind the mousemove listener on
     `(pointer:coarse)` and under reduced motion, so the behaviour half is
     correct and is not changed here. What was still being paid for is the
     ELEMENT: a position:fixed 560x560 radial layer that the compositor keeps
     alive whether or not anything ever moves it. This is the paint half. */
  html .bg-glow { display: none !important; }

  /* ---------- 2. NO DECORATIVE BACKDROP-FILTER ------------------------------
     Blanket-off, then hand every translucent surface an opaque background so
     nothing turns into unreadable washed-out glass. Enumerated per component
     rather than left to the blanket rule, because `backdrop-filter:none` on a
     surface whose fill is rgba(...,.72) leaves text sitting on whatever happens
     to be behind it. */
  html *,
  html *::before,
  html *::after {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }

  /* Cards + panels: the value components.css already uses when the browser has
     no backdrop-filter at all. */
  html .card.card,
  html .panel.panel { background: var(--surface) !important; }

  /* A TENANT SITE'S CARD IS PAINTED BY THE DESIGN LANGUAGE, NOT BY THIS RULE.
     MEASURED DEFECT: the rule above is written `html`-prefixed + doubled-class +
     !important precisely so nothing can beat it, and on a phone it therefore
     forced --surface onto every .card inside .sb-site as well. The design
     language's feature/bento SUBJECT card is a slab of --band carrying --on-band
     ink; the fill reverted to --surface and the ink did not, and the card
     measured 1.14:1 heading / 1.10:1 body at 390px — invisible — while its
     siblings measured 14.70:1.

     A higher-specificity !important rule is the only construct that can take the
     declaration back (0-3-1 beats 0-2-1), and reading a custom property is the
     only way to let each card keep its OWN fill through it. The language declares
     --sb-card-bg on .sb-site and re-points it per card, so this rule is a pipe,
     not a colour. Everything the blanket rule is for still holds: the value it
     resolves to is always an opaque, measured fill. */
  html .sb-site .card.card,
  html .sb-site .panel.panel { background: var(--sb-card-bg, var(--surface)) !important; }

  /* The fixed public top nav, opaque instead of 82%-translucent-plus-blur. */
  html .nav.scrolled,
  html .nav.is-scrolled { background: var(--bg-2) !important; }

  /* The dashboard/admin sticky topbar — the CMS console's equivalent, and the
     one that made the console itself stutter on a phone. */
  html .topbar.topbar { background: var(--bg) !important; }

  /* Glass secondary buttons. */
  html .btn--solid.btn--solid { background: var(--surface-solid) !important; }

  /* Popovers, menus, dropdown panels and the custom dialog/modal chrome: all
     were translucent-over-blur. Opaque keeps them legible over live content. */
  html .menu.menu,
  html .pmu-dropdown__panel.pmu-dropdown__panel,
  html .pmu-tooltip.pmu-tooltip,
  html .tooltip.tooltip,
  html .pmu-dialog__panel.pmu-dialog__panel,
  html .modal__panel.modal__panel,
  html .drawer__panel.drawer__panel { background: var(--surface-solid) !important; }

  /* Overlay backdrops keep their dim, lose their blur. The alpha is raised to
     carry the separation the blur used to provide. */
  html .modal__backdrop.modal__backdrop { background: rgba(11,27,58,.58) !important; }
  html .drawer__backdrop.drawer__backdrop { background: rgba(11,27,58,.54) !important; }
  html .pmu-dialog__backdrop.pmu-dialog__backdrop { background: rgba(12,18,32,.56) !important; }
  html .sb2-dialog__backdrop.sb2-dialog__backdrop { background: rgba(12,18,32,.56) !important; }

  /* ---------- 2b. THE BADGES THAT SIT ON TOP OF MEDIA -----------------------
     AUDITED, NOT ASSUMED. A scan of all 55 backdrop-filter rules in the tree
     splits them in two, and only one half needs anything here:

       · Surfaces over the PAGE BACKGROUND — .fl-card, .biz-card, .set-tabs,
         .btn--ghost, .icon-btn, .lang-switch, .toast, .badge, the glass utility
         (var(--glass-bg) = rgba(255,255,255,.72), var(--glass-strong) = .86).
         A 72-86% fill over a flat background is legible with or without a blur,
         so they are left exactly as they are — blur off, fill untouched.

       · Badges over PHOTOS AND VIDEO — the play chips, drag handles, favourite
         stars, progress rings and thumbnail overlays below. These sit on
         arbitrary user-uploaded imagery at 44-60% fill, and there the blur WAS
         doing legibility work: drop it and white text can land on a bright
         patch of someone's photo. So they keep the perf win and get the
         contrast back the honest way — a more opaque fill.

     The alphas below are the originals raised to ~.72-.78, the same place the
     glass tokens already sit for surfaces that never had a blur to lean on. */
  html .pg-card__play.pg-card__play,
  html .portal-post__play.portal-post__play,
  html .portal-card__play.portal-card__play,
  html .phome-post__play.phome-post__play {
    background: color-mix(in srgb, var(--navy-900) 78%, transparent) !important;
  }
  html .pg-card__handle.pg-card__handle,
  html .pf-fav.pf-fav {
    background: color-mix(in srgb, var(--navy-900) 72%, transparent) !important;
  }
  html .excard__badge.excard__badge { background: rgba(11,27,58,.78) !important; }
  html .exr-technique-preview__badge.exr-technique-preview__badge { background: rgba(15,23,42,.76) !important; }
  html .fl-card__badge.fl-card__badge {
    background: color-mix(in srgb, var(--surface) 92%, transparent) !important;
  }
  html .portal-course__ring.portal-course__ring,
  html .phome-course__ring.phome-course__ring {
    background: color-mix(in srgb, var(--surface) 94%, transparent) !important;
  }

  /* ---------- 3. THE FLOATING-AURORA FAMILY ---------------------------------
     The same defect as the .bg-orb layer, repeated once per hero across the
     app: a 360-420px blob at `filter:blur(60-64px)` running `pmuFloatY`
     (translateY 0 -> -14px) FOR EVER. Translating a filtered element
     invalidates the filter's cached raster exactly as scaling it does, so each
     of these is a large blur re-convolved every frame for as long as the page
     is open — and .portal-hero__aurora / .phome-hero__aurora / .ppost-hero__aurora
     are on the MEMBER PORTAL, which is the surface trainees actually open on a
     phone. Each already carries its own prefers-reduced-motion guard; none had
     a mobile guard. The blob keeps its colour and position; it loses the blur
     pass and the animation. At .10 opacity over a hero card the blur is doing
     very little that the radius and the low alpha are not already doing.

     `.dash-hero__wave` (a 👋 emoji rotating 2.6s) and `.dot` (pmuPulse) are
     deliberately LEFT ALONE: both are tiny, unfiltered, transform/opacity-only
     compositor work, and both carry meaning — one is a greeting, the other is a
     live-status indicator. This sheet is a rendering budget, not a war on
     motion. */
  html .dash-hero__aurora,
  html .portal-hero__aurora,
  html .phome-hero__aurora,
  html .phome-today__aurora,
  html .ppost-hero__aurora,
  html .auth-side__aurora,
  html .auth-side__aurora::before,
  html .auth-side__aurora::after,
  html .error-glow {
    filter: none !important;
    -webkit-filter: none !important;
    animation: none !important;
  }
}

/* ============================================================================
   REDUCED MOTION — EVERY DEVICE, NOT JUST TOUCH.

   background.css declared `pmuAuroraDrift`/`pmuAurora` as `infinite` with no
   reduced-motion guard, so a visitor who had asked the OS to stop animation
   still got three blurred layers scaling under their content for as long as the
   tab was open. 49 other stylesheets in this tree honour the query; this one did
   not, and it is the only one that never stops.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
  html .bg-orb,
  html .bg-aurora,
  html .auth-side__aurora,
  html .auth-side__aurora::before,
  html .auth-side__aurora::after {
    animation: none !important;
    opacity: 1 !important;
  }
  html .bg-glow { display: none !important; }
}
