/* seifosman.com — intro styles (preloader + shark canvas), split from app.css on 2026-11-01 so the intro is one owned unit.
   Depends on app.css tokens (--bg, --accent, --accent-2, --accent-rgb, --accent2-rgb, --muted, --ok, --on-accent, --glow, --mono, --display, --ease). */

body.loading.has-cursor,body.loading.has-cursor *{cursor:auto} /* keep the real pointer visible during the preloader (custom cursor sits behind it) */
body.loading{overflow:hidden;height:100vh;height:100svh}
  /* Preloader */
  #preloader{position:fixed;inset:0;z-index:10000;background:var(--bg);display:grid;place-items:center;overflow:hidden;transition:transform .8s var(--ease)}
  /* Exit: the curtain lifts (.8s, the site's expo-out) while the text leaves a beat faster and fades — content
     and surface moving at different rates is what makes a wipe read as depth instead of a slide-off. */
  /* 2026-11: the curtain fades in place instead of sliding up, so the sharks on it hand over to the hero's school at the same spots. */
  #preloader.done{opacity:0;pointer-events:none;
    /* Sliding it off-screen does NOT retire it. Without this the preloader stayed
       display:grid, position:fixed inset:0 at z-index:10000 — the topmost composited
       layer on the page, for the whole session — still holding a full-screen background
       image with a CSS filter, an 1800x1008 canvas, and two infinite animations. Every
       frame of every scroll paid for it. visibility is delayed by the length of the
       slide so the exit animation still plays, then the whole subtree stops rendering. */
    visibility:hidden;
    transition:opacity .62s cubic-bezier(.4,0,.2,1) .06s,visibility 0s linear .7s}
  #preloader.done .pre-canvas{opacity:0;transition:opacity .4s linear}
  #preloader.done .pre-inner{transform:translateY(-48px);opacity:0;transition:transform .5s var(--ease),opacity .35s ease-out}
  /* Belt and braces: nothing inside a retired loader should keep running. Paused, not removed — `animation:none`
     reset the mark and the name to their from-frames, so both vanished the instant the curtain started to lift. */
  #preloader.done *,#preloader.done *::before,#preloader.done *::after{animation-play-state:paused!important}
  #preloader::before{content:'';position:absolute;inset:-20%;background:radial-gradient(40% 40% at 50% 38%,rgba(var(--accent2-rgb),.22),transparent 70%);filter:blur(30px)}
  #preloader::after{content:'';position:absolute;inset:0;opacity:.5;background-image:linear-gradient(rgba(255,255,255,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.04) 1px,transparent 1px);background-size:48px 48px;-webkit-mask-image:radial-gradient(circle at 50% 40%,#000,transparent 75%);mask-image:radial-gradient(circle at 50% 40%,#000,transparent 75%)}
  /* Ocean plate: the photograph sits on a deep-water gradient (lit from above, darkest at the floor), so if
     assets/intro/ocean.jpg never arrives the scene still has depth and the text keeps its contrast. */
  .pre-ocean{position:absolute;inset:0;z-index:0;background:url('assets/intro/ocean.jpg') center/cover no-repeat,radial-gradient(110% 80% at 50% 0%,#1a2340 0%,#0b1020 45%,#04060c 100%);opacity:.5;filter:saturate(.72) hue-rotate(-26deg) brightness(.92);-webkit-mask-image:radial-gradient(120% 100% at 50% 30%,#000 55%,transparent 100%);mask-image:radial-gradient(120% 100% at 50% 30%,#000 55%,transparent 100%)}
  .pre-nocanvas .pre-ocean{opacity:.62} /* no 2d canvas → the plate alone carries the scene, so let it show a little more */
  .pre-canvas{position:absolute;inset:0;width:100%;height:100%;z-index:0;opacity:.9}
  .pre-inner{position:relative;z-index:1;text-align:center;width:min(460px,84vw)}
  .pre-mark{width:74px;height:74px;margin:0 auto 26px;border-radius:20px;display:grid;place-items:center;font-family:var(--display);font-weight:800;font-size:1.7rem;color:var(--on-accent);background:linear-gradient(135deg,var(--accent),var(--accent-2));box-shadow:var(--glow);position:relative;animation:preMark .8s var(--ease) both}
  .pre-mark::before{content:'';position:absolute;inset:-11px;border-radius:50%;border:1.5px solid transparent;border-top-color:var(--accent);border-right-color:var(--accent-2);animation:preSpin 1s linear infinite}
  @keyframes preMark{from{opacity:0;transform:scale(.6) rotate(-12deg)}to{opacity:1;transform:none}}
  @keyframes preSpin{to{transform:rotate(360deg)}}
  .pre-name{font-family:var(--display);font-weight:800;font-size:clamp(1.4rem,5vw,2.2rem);letter-spacing:-.02em;line-height:1;background:linear-gradient(180deg,#fff,var(--accent));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;clip-path:inset(0 100% 0 0);animation:preName 1s .15s var(--ease) forwards}
  @keyframes preName{to{clip-path:inset(0 0 0 0)}}
  [dir="rtl"] .pre-name{clip-path:inset(0 0 0 100%)} /* the reveal wipes in reading direction */
  .pre-role{font-family:var(--mono);font-size:.78rem;letter-spacing:.2em;text-transform:uppercase;color:var(--accent);margin-top:14px;opacity:0;animation:preFade .6s .4s forwards}
  @keyframes preFade{to{opacity:1}}
  /* the download counter is the intro's hero — big, glowing, gently pulsing; tabular figures so the digits
     advance in place instead of the whole number jittering sideways on every tick */
  .pre-count{font-family:var(--display);font-weight:800;font-size:clamp(4.6rem,19vw,8.5rem);line-height:.9;margin:22px 0 16px;font-variant-numeric:tabular-nums;background:linear-gradient(120deg,#fff,var(--accent) 55%,var(--accent-2));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;filter:drop-shadow(0 0 30px rgba(var(--accent2-rgb),.55));animation:preCountPulse 2.2s ease-in-out infinite}
  @keyframes preCountPulse{50%{transform:scale(1.035)}}
  .pre-count i{font-style:normal;font-size:.34em;color:var(--muted);-webkit-text-fill-color:var(--muted);margin-inline-start:6px;filter:none}
  /* Caption under the big number — names what the count actually is (890 stores), so the
     intro states a real fact instead of a fake percentage. */
  .pre-unit{font-family:var(--mono);font-size:.75rem;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);margin:-6px 0 18px;opacity:0;animation:preFade .6s .5s forwards}
  .pre-bar{width:100%;height:5px;background:rgba(255,255,255,.07);border-radius:4px;overflow:hidden;box-shadow:0 0 0 1px rgba(var(--accent-rgb),.12)}
  /* The fill glides between the 110ms ticks on the site's own ease instead of stepping linearly. */
  .pre-bar i{display:block;height:100%;width:100%;transform:scaleX(0);transform-origin:0 50%;background:linear-gradient(90deg,var(--accent),var(--accent-2));box-shadow:0 0 18px var(--accent);transition:transform .24s var(--ease)}
  .pre-status{font-family:var(--mono);color:var(--muted);margin-top:14px;font-size:.75rem;letter-spacing:.02em;transition:opacity .16s ease-out}
  /* Skip affordance: the intro is deliberate, but a visitor must always be able to get past it.
     Fades in after 1.2s so it doesn't undercut the opening beat. */
  .pre-skip{font-family:var(--mono);color:var(--muted);margin-top:10px;font-size:.75rem;letter-spacing:.18em;text-transform:uppercase;opacity:0;animation:preSkipIn .5s 1.2s forwards}
  @keyframes preSkipIn{to{opacity:.8}}
  /* Short viewports (a phone held sideways is 390px tall): the stack is ~400px at full size, so the mark was
     clipped at the top and the caption and hint fell off the bottom. Compact the vertical rhythm, not the width. */
  @media (max-height:560px){
    .pre-mark{width:48px;height:48px;margin-bottom:12px;border-radius:14px;font-size:1.1rem}
    .pre-mark::before{inset:-8px}
    .pre-role{margin-top:8px}
    .pre-count{font-size:clamp(3rem,13vh,5.5rem);margin:10px 0 8px}
    .pre-unit{margin:-2px 0 10px}
    .pre-status{margin-top:8px}
    .pre-skip{margin-top:6px}
  }
  #preloader{cursor:pointer}
  #preloader:focus-visible{outline:2px solid var(--accent);outline-offset:-4px}
  @media (prefers-reduced-motion:reduce){.pre-skip{animation:none;opacity:.8}}
  .pre-status::before{content:'● ';color:var(--ok)}
/* With JS off: no-js.js never strips the class, so the loader must not show or lock scroll. */
.no-js #preloader{display:none!important}
.no-js body.loading{overflow:auto;overflow-x:hidden;height:auto}
/* scaleX fills away from its origin: start at the right edge under RTL. */
[dir="rtl"] .pre-bar i{transform-origin:100% 50%}
@media (prefers-reduced-motion:reduce){#preloader{display:none}body.loading{overflow:auto;overflow-x:hidden;height:auto}}
