/* Phone mode is selected in the head, before any slide can paint.
   A single slide box avoids a 32,640px composited track on high-DPR phones. */
html.phone #track { display: block; width: 1920px; transform: none !important; }
html.phone #track > .slide:not(.active) { display: none !important; }
html.phone #deck { will-change: auto; }
/* No rubber-band / pull-to-refresh / swipe-history behind the fixed canvas;
   pinch-zoom stays available. */
html.phone, html.phone body { overscroll-behavior: none; }
/* Pinch and pan stay native. The browser's double-tap zoom is off: a slide is
   one full-width block, so iOS's "smart" double-tap had nothing to zoom to and
   only fought taps. */
html.pagefit, html.pagefit body { touch-action: manipulation; }
/* Page-fit: the browser rounds the layout height down to a whole px, while the
   visible area can be a fraction taller -- the leftover sliver was painted in
   the browser's own (white) under-page colour, a hairline along the bottom
   edge. Two px of dark page cover it; panning is locked at the fit, so the
   extra can't be scrolled. */
html.pagefit { height: calc(100% + 2px); }

html.phone *, html.phone *::before, html.phone *::after {
  will-change: auto !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  animation-duration: 0.001ms !important;
  animation-delay: 0s !important;
  animation-iteration-count: 1 !important;
  transition: none !important;
}
html.phone #stage #track .pc-cb-logo { opacity: 1; }
html.phone #stage #track .pc-cb-bg { animation: none !important; transform: none; }
/* The portrait prompt needs no hidden deck surfaces behind it. */
@media (orientation: portrait) {
  html.phone #stage { visibility: hidden; }
}
/* Keep the original overlay stacking, colours, grain scale and opacity.
   Only the turbulence calculation is replaced with its pre-rendered tile. */
html.phone::after, html.phone body::before, html.phone body::after {
  animation: none !important;
  transform: none !important;
  will-change: auto !important;
}
html.phone body::before { opacity: .95; }
html.phone body::after {
  background-image:
    repeating-linear-gradient(0deg, transparent 0 2px, rgba(0,0,0,.18) 2px 3px),
    url("../assets/img/mobile-grain-original.png");
  background-size: 100% 3px, 160px 160px;
}
/* Stop the cover on its designed resting frame, retaining the original grade
   and logo glow. Static shadows are painted only for the visible slide. */
html.phone #stage #track .pc-cb-logo,
html.phone #stage #track .pc-cb-bg img {
  animation: none !important;
  transform: none;
}
/* Keep the large blur surfaces disabled; use their existing gradient ground. */
html.phone .pd-v2tm-grade::before,
html.phone .tm-grade::before {
  filter: none !important;
  mix-blend-mode: normal;
  background: radial-gradient(circle, rgba(64,240,255,.07), transparent 70%);
}
html.phone .pd-cb-qt::before, html.phone .cb-qt::before {
  filter: none !important;
}
@media (orientation: portrait) {
  html.phone::after, html.phone body::before, html.phone body::after {
    display: none !important;
  }
}

/* ---- Filter-free equivalents ----
   CSS filters render through an offscreen buffer at the current raster scale.
   Pinch-zoom multiplies that scale (x5 zoom on a 3x iPhone ~ 4.5 device px per
   stage px), so the cover alone -- a filtered full-bleed photo plus a 60px
   double glow -- ran to hundreds of MB and got the tab killed. Every effect
   below is the same look, pre-rendered or expressed without a filter. */

/* Cover photo: brightness(.5) is exactly a 50% black layer over it
   (saturate .98 / contrast 1.03 are below visibility). */
html.phone #s-cover .pc-cb-bg img { filter: none !important; }
html.phone #s-cover:not(.quotetime) .pc-cb-bg::before {
  content: ""; position: absolute; inset: 0; background: rgba(0,0,0,.5); pointer-events: none;
}
/* Cover logo: its resting double drop-shadow, baked (glow only, rendered by
   the browser from the original filter) and painted in the img's padding. */
html.phone #stage #track .pc-cb-logo {
  filter: none !important;
  box-sizing: content-box;
  padding: 100px;
  margin: -106px auto -100px;
  background: url("../assets/img/logo-glow-phone.webp") center / 100% 100% no-repeat;
}
/* Slide titles: drop-shadow on text is the same shadow as text-shadow. */
html.phone #stage h2.pd-deck-title {
  filter: none !important;
  text-shadow: 0 10px 34px rgba(0,0,0,.85);
}
/* Founding Belief cutout: brightness + 44px shadow baked into a phone copy
   (data-src-phone), 90px of shadow padding around the original box. */
html.phone #stage #track #s-belief > .pd-cb-bg2 {
  filter: none !important;
  left: -244px; top: 169px; bottom: auto;
  width: 706px; height: 1001px;
}
/* Product tiles: brightness(.9) is exactly a 10% black layer
   (saturate 1.05 is below visibility); captions stay above it. */
html.phone #stage :is(.pd-tile, .tile:not(.usp)) :is(img, video) { filter: none !important; }
html.phone #stage :is(.pd-tile, .tile:not(.usp))::after {
  content: ""; position: absolute; inset: 0; z-index: 1; background: rgba(0,0,0,.1);
  pointer-events: none; border-radius: inherit;
}
html.phone #stage :is(.pd-tile, .tile) > :is(figcaption, .pd-flagship-tag) { z-index: 2; }
/* 1-6% saturation/brightness nudges on video: not visible, not worth a pass. */
html.phone #stage :is(.pd-fa, .fa) :is(img, video),
html.phone #stage #s-reach .cc-wall .rc-m video,
html.phone #stage video { filter: none !important; }
/* Vision curve glow: blur(6px) replaced by stacked soft strokes. */
.fx-blur-lite { display: none; }
html.phone .fx-blur { display: none; }
html.phone .fx-blur-lite { display: inline; }

/* ---- Page-fit (see the viewport script in index.html) ----
   Outside the canvas, layout px are 1/--pf screen px, so the few fixed
   decorations sized in px are divided back to their screen size. */
html.pagefit #matteCap, html.pagefit #matteCapV {
  font-size: calc(9px / var(--pf, 1));
  letter-spacing: calc(4px / var(--pf, 1));
}
html.pagefit.phone body::after {
  background-image:
    repeating-linear-gradient(0deg, transparent 0 66.667%, rgba(0,0,0,.18) 66.667% 100%),
    url("../assets/img/mobile-grain-original.png");
  background-size: 100% calc(3px / var(--pf, 1)), calc(160px / var(--pf, 1)) calc(160px / var(--pf, 1));
}
/* Zoomed in: the captions in the side/bottom bars leave the view to the deck. */
html.pagefit.zoomed #matteCap, html.pagefit.zoomed #matteCapV { display: none !important; }

/* ---- Swipe hint (touch devices, landscape; markup + timing in index.html) ----
   Same visual language as the portrait rotate prompt (#rotGate): its dark
   mesh ground, cyan kicker pill, Fauna title with the cyan italic accent and
   dashed gradient strokes. Sizes are stage px (the canvas is 1920 wide), so
   they are the prompt's screen sizes over a landscape fit of ~0.31.
   Transform/opacity only, no filters, and gone after ~4.3s. It re-enables
   animation, which html.phone otherwise flattens to a single frame. */
#swipeHint { display: none; }
html.phone #swipeHint.show {
  display: flex; position: absolute; inset: 0; z-index: 45; pointer-events: none;
  align-items: center; justify-content: center; text-align: center;
  background: rgba(3,2,11,.93);
}
html.phone #swipeHint.show, html.phone #swipeHint.show * {
  animation-duration: var(--d) !important; animation-delay: var(--dl, 0s) !important;
  animation-iteration-count: 1 !important; animation-fill-mode: both !important;
  animation-timing-function: var(--ef, cubic-bezier(.45,0,.25,1)) !important;
}
html.phone #swipeHint.show { --d: .45s; --ef: ease-out; animation-name: sh-in-fade; }
html.phone #swipeHint.bye { opacity: 0; transition: opacity .35s ease !important; }
#swipeHint .sh-mesh { position: absolute; inset: 0; background:
  radial-gradient(58% 42% at 50% 16%, rgba(var(--cyan-rgb),.20), transparent 66%),
  radial-gradient(62% 44% at 50% 92%, rgba(var(--magenta-rgb),.17), transparent 66%),
  radial-gradient(90% 60% at 50% 50%, rgba(var(--violet-rgb),.11), transparent 72%); }
#swipeHint .sh-mesh::after { content: ''; position: absolute; inset: 0;
  background: repeating-linear-gradient(180deg, rgba(255,255,255,.022) 0 3px, transparent 3px 9px); }
#swipeHint .sh-in { position: relative; display: flex; flex-direction: column; align-items: center; }
#swipeHint .sh-pad { position: relative; width: 560px; height: 360px; margin-bottom: 40px; }
#swipeHint .sh-hand {
  position: absolute; left: 50%; top: 50%; width: 200px; height: 258px; margin: -54px 0 0 -62px;
  --d: 2.9s; --dl: .3s; animation-name: sh-hand;
}
#swipeHint .sh-glow { stroke: rgba(var(--cyan-rgb),.22); stroke-width: 9; stroke-linejoin: round; }
#swipeHint .sh-tap { fill: rgba(var(--cyan-rgb),.22); stroke: var(--cyan); stroke-width: 2.2;
  transform-box: fill-box; transform-origin: center; --d: 2.9s; --dl: .3s; animation-name: sh-tap; }
/* Trails run from the swipe's start to the fingertip, brightest at the finger. */
#swipeHint .sh-trail { position: absolute; overflow: visible; --d: 2.9s; --dl: .3s; }
#swipeHint .sh-h { left: calc(50% - 150px); top: calc(50% - 26px); width: 300px; height: 12px;
  transform-origin: 100% 50%; animation-name: sh-trail-h; }
#swipeHint .sh-v { left: calc(50% - 6px); top: calc(50% - 136px); width: 12px; height: 230px;
  transform-origin: 50% 100%; animation-name: sh-trail-v; }
#swipeHint .sh-kick { font-family: var(--font-ui); font-size: 34px; letter-spacing: .3em; text-transform: uppercase;
  color: var(--cyan); padding: 24px 52px; border: 3px solid rgba(var(--cyan-rgb),.32); border-radius: 300px;
  background: rgba(var(--cyan-rgb),.07); margin-bottom: 70px; --d: .5s; --dl: .15s; animation-name: sh-in; }
#swipeHint .sh-t { font-family: var(--font-display); font-weight: 300; font-size: 138px; line-height: 1.06;
  color: #fff; letter-spacing: -.015em; margin-bottom: 44px; --d: .55s; --dl: .22s; animation-name: sh-in; }
#swipeHint .sh-t em { color: var(--cyan); font-style: italic; text-shadow: 0 0 60px rgba(var(--cyan-rgb),.45); }
#swipeHint .sh-s { font-size: 46px; line-height: 1.6; color: var(--fg-3); font-weight: 300; max-width: 1500px;
  --d: .55s; --dl: .3s; animation-name: sh-in; }
@keyframes sh-in-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sh-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
/* 0-44%: swipe left; 52-96%: swipe up. */
@keyframes sh-hand {
  0%   { opacity: 0; transform: translate(150px, 0) rotate(8deg); }
  6%   { opacity: 1; transform: translate(150px, 0) rotate(8deg); }
  34%  { opacity: 1; transform: translate(-150px, 0) rotate(-6deg); }
  44%  { opacity: 0; transform: translate(-168px, 0) rotate(-6deg); }
  52%  { opacity: 0; transform: translate(0, 115px) rotate(0); }
  58%  { opacity: 1; transform: translate(0, 115px) rotate(0); }
  86%  { opacity: 1; transform: translate(0, -115px) rotate(0); }
  96%, 100% { opacity: 0; transform: translate(0, -133px) rotate(0); }
}
@keyframes sh-tap {
  0%, 4% { transform: scale(.4); opacity: 0; } 8%, 34% { transform: scale(1); opacity: 1; } 42%, 54% { transform: scale(.4); opacity: 0; }
  60%, 86% { transform: scale(1); opacity: 1; } 94%, 100% { transform: scale(.4); opacity: 0; }
}
@keyframes sh-trail-h {
  0%, 6% { opacity: 0; transform: scaleX(0); } 8% { opacity: 1; }
  34% { opacity: 1; transform: scaleX(1); } 44%, 100% { opacity: 0; transform: scaleX(1); }
}
@keyframes sh-trail-v {
  0%, 58% { opacity: 0; transform: scaleY(0); } 60% { opacity: 1; }
  86% { opacity: 1; transform: scaleY(1); } 96%, 100% { opacity: 0; transform: scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
  html.phone #swipeHint.show * { animation: none !important; }
}
/* Rotate prompt: its turning-phone animation is the prompt's whole message,
   and with the deck hidden behind it in portrait it costs next to nothing,
   so it is exempt from the phone-wide animation freeze. */
html.phone #rotGate .rg-phone {
  animation-duration: 3.6s !important; animation-iteration-count: infinite !important;
  animation-delay: 0s !important;
}
