/* approved/015 r2 · the loading P · the boot frame — src/styles/boot-splash.css
   Linked from index.html (before the app's code) and imported by BrandSplash, so the boot frame and every later splash
   share one file. It sits on top of 015's p-loader.css (the layers, pl-breathe) and the repo's DW-1 .pl-dot rules.
   Every value is copied from the approved preview (r2/boot.preview.css ← drafts/015-loading-fix/lf.css):
   · the wash, lamp and stars: BrandSplash.tsx:24–48, verbatim (.lf-wash/.lf-lamp/.lf-stars)
   · the lockup: 081 welcome.css:12–15 (.lf-fix .lf-lock gap 8 · .lf-wm 44/48)
   · the quarter start, the held frame and reduced motion: .lf-fix rules, verbatim
   The breath out and the holds are timing, so they live in BootSplash.tsx.txt (§ leave). */

#boot{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;background:linear-gradient(180deg,#1E1638,#2B1F50);color:#F5F1FC;touch-action:none}
.boot-lamp{position:absolute;inset:0;opacity:.15;pointer-events:none;background:radial-gradient(120% 55% at 50% -6%,rgba(157,92,255,.6),transparent 62%)}
/* physics: the stars' 1.2 and 1 px dots are BrandSplash's own, copied as drawn */
.boot-stars{position:absolute;inset:0;opacity:.45;pointer-events:none;background-image:radial-gradient(1.2px 1.2px at 25px 35px,rgba(245,241,252,.5),transparent 55%),radial-gradient(1px 1px at 95px 100px,rgba(201,166,255,.4),transparent 55%),radial-gradient(1px 1px at 55px 130px,rgba(255,45,122,.3),transparent 55%);background-size:190px 170px}

/* the lockup: the welcome's. P 118 (138 tall), wordmark 44/48, 8 apart, centred as one group */
.boot-lock{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px}
.boot-wm{display:inline-flex;align-items:baseline;white-space:nowrap;font-family:'Unbounded',sans-serif;font-weight:600;font-size:44px;line-height:48px;letter-spacing:-.01em;color:#F5F1FC}
/* physics: Wordmark.tsx's drawn period at 44: round(44 × .17) = 7, its gap 7 × .4 = 2.8 */
.boot-wm .pl-dot{width:7px;height:7px;margin-left:2.8px}
/* until Unbounded is ready the P shows alone; the space is kept so nothing moves */
html:not(.is-font) #boot .boot-wm{visibility:hidden}

/* the P: 015's two loading layers at 118, drawn from the FAST WebP (DESIGN-3 JOB 1.2, ② 561 "P: fast first": the lossless
   master at its displayed 354 × 414, quality 95, 42 KB — ① 309: no visible change at phone size; it was the 189 KB
   lossless file). A browser that can't pick an image by type keeps the first line: the PNG, the same pixels. */
#boot .pl-mark{--pl-w:118px}
#boot .pl-mark>div,.boot-q .pl-mark>div{background-image:url('/brand/piing-P.png');background-image:image-set(url('/brand/piing-P-fast.webp') type('image/webp'),url('/brand/piing-P.png') type('image/png'))}

/* the same 2.8 s breath, started a quarter in: frame one is mid-swell, the first peak lands at 0.7 s.
   .boot-q is the same start for BrandSplash's later splashes (board, ceremony, reserve, share, top 8). */
#boot .pl-loading.pl-run,.boot-q .pl-loading.pl-run{animation:pl-breathe 2.8s ease-in-out -.7s infinite}
#boot .pl-run .pl-dot.pl-period-loading,.boot-q .pl-run .pl-dot.pl-period-loading{animation:pl-dot-pulse-drawn 2.8s ease-in-out -.7s infinite}

/* the app's launch screen is this frame, held still, until the web view paints */
#boot.is-held .pl-loading.pl-run,#boot.is-held .pl-run .pl-dot.pl-period-loading{animation-play-state:paused}

@media (prefers-reduced-motion:reduce){#boot .pl-mark,.boot-q .pl-mark{filter:drop-shadow(0 0 calc(var(--pl-g) * 14.7) rgba(157,92,255,.5))!important}}

/* ============================================================================
   APP ADAPTATION (DESIGN-2 JOB 3, 2026-10-24; BOOT-GUARD 2026-10-24) — five things 015 r2's file could not know
   ============================================================================
   Above this line the file is approved/015-p-loader/boot-splash.css as delivered (r2.0–r2.9), with ONE selector
   re-keyed by BOOT-GUARD JOB 3 (② 458 (3)): `#boot:not(.is-font) .boot-wm` → `html:not(.is-font) #boot .boot-wm` — the
   boot script decides in <head>, before #boot is parsed, so the state lives on <html> (the declaration is unchanged).
   Below: r2.11, BOOT-GUARD's two (4 · 5) and the app's own needs, kept HERE so the frame and every later splash still
   share one file (r2.5: never a copy).

   1 · r2.11, "never before the welcome" (founder, 22 Oct): signed OUT, the frame is 081's FIRST FRAME, not the
       loader — the hero where 081 puts it (approved/081-the-welcome/welcome.css:13–14: top 112, centred), the P
       UNLIT (the dark layer alone), the wordmark 44/48 with the period still dim (#55477E, welcome.css:15), nothing
       breathing, no floor. 081's page mounts over it and the frame is removed on the route's first paint. The
       boot script (/boot/boot.js, first in <head>) adds .is-door or .is-app to <html> before the first paint — BOOT-GUARD
       moved the state from #boot to <html> (the script runs before #boot is parsed; the old #boot.is-* selectors retire
       here, and the script mirrors the classes onto #boot for a stale copy of this file). Night in both modes (r2.11). */
html.is-door #boot{align-items:flex-start}
/* DESIGN-3 JOB 2 (081 r2, JOB 1.6): the hero stands where the door's one centred column puts it — the column (the hero
   226.25: the P 138.25 + 8 + the wordmark 48 + 12 + the tagline 20; then 40; the door pane 116: the box 52 + 12 + the
   button 52; and the form's 8 clear below) centred between the device's safe edges. physics: 390.25 = that column; the
   door's own column (.wl-col, welcome-app.css) centres the same box the same way, so the frame's removal moves nothing. */
html.is-door #boot .boot-lock{position:absolute;left:0;right:0;top:calc(env(safe-area-inset-top,0px) + (100dvh - env(safe-area-inset-top,0px) - env(safe-area-inset-bottom,0px) - 390.25px) / 2)}
/* DESIGN-3 JOB 3 (1.6, D6): the frame's pane follows the device mark the boot script read (html.is-face · html.is-faces +
   --pl-rows — the worker's piing_d cookie on the web, Preferences in the app): the remembered face's column is the hero
   226.25 + 40 + the face pane 257 (.wl-me 129 + 12 + sign on 52 + 12 + another account 52) + 8 = 531.25, and the chooser's
   226.25 + 40 + (welcome back 22 + 12 + 60 a row + 12 + another account 52) + 8 = 372.25 + 60 × rows; both centre above
   the foot (081 r2: the foot's 44, 14 above max(the home bar's inset, 34), 12 clear = 70 + the inset; welcome-app.css) */
html.is-door.is-face #boot .boot-lock{top:calc(env(safe-area-inset-top,0px) + (100dvh - env(safe-area-inset-top,0px) - max(env(safe-area-inset-bottom,0px),34px) - 70px - 531.25px) / 2)}
html.is-door.is-faces #boot .boot-lock{top:calc(env(safe-area-inset-top,0px) + (100dvh - env(safe-area-inset-top,0px) - max(env(safe-area-inset-bottom,0px),34px) - 70px - 372.25px - var(--pl-rows,2) * 60px) / 2)}
/* DESIGN-3 JOB 1.3–1.4 (② 536: "the "P" and the piing. word mark is loaded at same time and starts it animation
   immediatley"; ② 539 one scene; 081 §3 "the light starts on frame one"): the door's frame no longer stands unlit — it is
   015's welcome mark (boot.js swaps it in), lit by 081's timings (section 7). The P and the wordmark appear TOGETHER,
   once the picture and the face are both ready, and the light starts that same frame: until then the layers stay
   hidden and nothing runs, so no part of the light-up plays unseen. */
html.is-door:not(.is-font) #boot .pl-mark>div{opacity:0!important}
html.is-door:not(.is-p) #boot .boot-wm{visibility:hidden}
html.is-door:not(.is-p) #boot .pl-mark,html.is-door:not(.is-p) #boot .pl-mark>div,html.is-door:not(.is-p) #boot .pl-dot,html.is-door:not(.is-p) #boot .pl-glow,html.is-door:not(.is-font) #boot .pl-mark,html.is-door:not(.is-font) #boot .pl-mark>div,html.is-door:not(.is-font) #boot .pl-dot,html.is-door:not(.is-font) #boot .pl-glow{animation:none!important}
/* signed in the frame stays 015's two-layer loader: the welcome's other three layers (in the markup for the door) are off */
#boot .pl-loading .pl-lit,#boot .pl-loading .pl-front,#boot .pl-loading .pl-bub{display:none}

/* 2 · r2.11 (b), the breath out for a LATER splash (BrandSplash after signing up or on from the door — one full
       breath, then the breath out into the app): the glow swells to the breath's peak (240 ms) and the period to
       opacity 1 while the splash fades over the app (360 ms), the frame's own recipe (BootSplash.tsx.txt § leave).
       Reduced motion: a plain 200 ms fade, nothing swells. RequireAuth sets .boot-leave for the fade's length. */
.boot-q.boot-leave{animation:boot-out .36s cubic-bezier(.2,.8,.2,1) forwards}
.boot-q.boot-leave .pl-mark{animation:boot-peak .24s cubic-bezier(.2,.8,.2,1) forwards!important}
.boot-q.boot-leave .pl-run .pl-dot.pl-period-loading{animation:boot-dot-peak .24s cubic-bezier(.2,.8,.2,1) forwards!important}
@keyframes boot-out{to{opacity:0}}
@keyframes boot-peak{to{filter:drop-shadow(0 0 calc(var(--pl-g) * 20.2) rgba(157,92,255,.72))}}
@keyframes boot-dot-peak{to{opacity:1;box-shadow:0 0 .325em rgba(77,214,196,.95)}}
@media (prefers-reduced-motion:reduce){.boot-q.boot-leave{animation-duration:.2s}.boot-q.boot-leave .pl-mark,.boot-q.boot-leave .pl-run .pl-dot.pl-period-loading{animation:none!important}}

/* 3 · the lockup that stands on the frame also stands on BrandSplash's later splashes (board · ceremony · reserve ·
       share · top 8): .boot-q is the same quarter start (above, 015's own rule) and the wordmark's drawn period
       sits beside the word exactly as Wordmark.tsx draws it, so nothing moves between the frame and the splash. */

/* 4 · BOOT-GUARD JOB 1 (② 458 (1)) — THE FAIL-SAFE, in CSS alone. When the boot script never runs (blocked, stale under new
   HTML, thrown before its first line) nothing else can remove this frame, so at 12 s it fades, hides and stops taking
   taps by itself. physics: 12 s — past every floor (≤ 3.5 s) and every breath out (0.36 s), inside a visitor's
   patience; a 0 s cut, not motion, so reduced motion needs no variant. The script's FIRST statement adds `boot-js` to
   <html> and the rule below stands the fail-safe down — then the floors govern, exactly as before. The app's own net
   (the mount guard, the 6 s after READY, the 20 s ceiling from mount, the route error's force) is src/lib/boot.ts. */
#boot{animation:boot-failsafe 0s linear 12s forwards}
@keyframes boot-failsafe{to{opacity:0;visibility:hidden;pointer-events:none}}
html.boot-js #boot{animation:none}

/* 5 · BOOT-GUARD JOB 4 (② 458 (4)) — THE P ONLY WHEN WHOLE. The layers are hidden until the script has LOADED the picture
   (`is-p` on <html> — the V32 F1 lesson, the frame's copy of Wordmark.tsx's gate), so a WebP streaming in on a slow
   cell never paints as a bright sliver; the order becomes the wash → the wordmark → the whole P → the door.
   !important on the gate: p-loader.css's reduced-motion block pins .pl-lit2 to opacity 1 with !important, and the
   gate must win until the picture is whole. The 0.2 s is a fade, dropped under reduced motion. */
#boot .pl-mark>div{transition:opacity .2s}
html:not(.is-p) #boot .pl-mark>div{opacity:0!important}
@media (prefers-reduced-motion:reduce){#boot .pl-mark>div{transition:none}}

/* 6 · COLD-OPEN-1 JOB 5 — THE LAST LINE. index.html's static <p class="boot-fail"> under #root: when nothing can run (the
   entry blocked or failed) the page must not end on a blank wash or a frame that never leaves. Hidden at first,
   revealed at 20 s by the fail-safe's own pattern (a 0 s cut, no script — THE INLINE LAW), ABOVE the frame (whose own
   fail-safe stands down once boot.js runs, so a blocked entry alone would leave it standing), and gone for good once
   the app mounts (main.tsx adds app-mounted to <html>). physics: 20 s — DESIGN-3 JOB 1.8 (② 552 → ② 554): at 12 s a
   slow network that was still loading read as failed; the 24 px gutter and the type are the frame's (night ink on the
   night wash). */
/* physics: the frame's own ink (#boot's color) — the line must read when no token stylesheet could load */
.boot-fail{position:fixed;left:24px;right:24px;bottom:calc(env(safe-area-inset-bottom,0px) + 48px);z-index:2147483001;margin:0;text-align:center;font:400 15px/20px system-ui,-apple-system,sans-serif;color:#F5F1FC;opacity:0;visibility:hidden;pointer-events:none;animation:boot-fail-show 0s linear 20s forwards}
/* physics: the lavender of the frame's lamp for the one link, legible on the wash with no token stylesheet loaded */
.boot-fail a{color:#C9A6FF;text-decoration:underline}
@keyframes boot-fail-show{to{opacity:1;visibility:visible;pointer-events:auto}}
html.app-mounted .boot-fail{display:none}

/* 7 · DESIGN-3 JOB 1 (081 §3 · ② 536–539 · ② 561) — ONE HERO, LIT FROM ITS FIRST FRAME: the frame's and the door's alike.
   081's two timings, the values verbatim from approved/081-the-welcome/welcome.css:22–33, unscoped from the preview's
   phone (.wl-ph) so the frame (#boot) and the door's own lockup (Wordmark `door`) share ONE set, never a copy:
   · .is-short: a first visit on this device. The light starts on frame one; the whole sequence is 1.2 s, not 4
   · .is-calm:  back again. Lit from the first frame, breathing only, the period mint already
   ONE CHANGE from 081's lines: the breath (pl-breathe, an animated filter) left the mark for the glow behind it
   (section 8) — the mark keeps its resting glow, still. Nothing here is !important, so p-loader.css's reduced-motion
   block (lit and still, the period mint) still wins. */
.pl-welcome.pl-run.is-short{animation:pl-outline 1.2s linear forwards}
.pl-welcome.pl-run.is-short .pl-lit{animation:pl-wipe .42s linear 0s forwards}
.pl-welcome.pl-run.is-short .pl-lit2{animation:pl-wipe .5s linear .2s forwards}
.pl-welcome.pl-run.is-short .pl-front{animation:pl-front .5s linear .2s forwards}
.pl-welcome.pl-run.is-short .pl-bub{animation:pl-pop .4s cubic-bezier(.22,.9,.3,1) .78s forwards}
.pl-run.is-short .pl-dot.pl-period-welcome{animation-delay:1.2s}
/* calm: the outline's own end at once — the resting glow, held still (the breath is the glow's, section 8) */
.pl-mark.pl-welcome.is-calm{animation:pl-outline 0s linear forwards}
.pl-mark.pl-welcome.is-calm .pl-lit2{opacity:1;-webkit-mask-image:none;mask-image:none;animation:none}
.pl-mark.pl-welcome.is-calm .pl-lit,.pl-mark.pl-welcome.is-calm .pl-front,.pl-mark.pl-welcome.is-calm .pl-bub{animation:none;opacity:0}
/* the period mint at once: p-loader.css's own arrival, run in no time (its end state, no second copy of the colour) */
.pl-run.is-calm .pl-dot.pl-period-welcome{animation:pl-dot-on 0s linear forwards}

/* the door's own lockup (Wordmark `door`, src/pages/auth/WelcomePage.tsx) stands where the frame's stood — top 112, the
   P 118 over the wordmark 44/48, 8 apart (Wordmark sets the gap and the line) — and draws the same fast P, so the
   frame's removal changes no pixel. Its P shows only once its picture RUNS (never the dark mosaic), its wordmark only
   once the face is in (when the boot script is watching the face), and it takes the frame's clock over on mount. */
.pl-door .pl-mark>div{background-image:url('/brand/piing-P.png');background-image:image-set(url('/brand/piing-P-fast.webp') type('image/webp'),url('/brand/piing-P.png') type('image/png'))}
/* DESIGN-3 JOB 1.2: the lossless P, swapped in underneath once Wordmark has decoded it off screen (.pl-hd) — the same box,
   the same clock; the glow behind keeps the fast P (it is blurred anyway) */
.pl-door.pl-hd .pl-mark>div{background-image:url('/brand/piing-P.png');background-image:image-set(url('/brand/piing-P.webp') type('image/webp'),url('/brand/piing-P.png') type('image/png'))}
.pl-door .pl-mark:not(.pl-run)>div{opacity:0}
html.boot-js:not(.is-font) .pl-door>span{visibility:hidden}
/* then the rest of the door fades in under the hero (② 536: "then the email and password form fills fade in and all
   other words on the page") — SLOWLY: the founder on his phone, 2026-10-27, *"the email and password and everything
   comes in really fast … I kind of wanted like a slow fade in"*: 1.2 s, the light-up's own length, easing in and out
   (it was 081's pane curve, .24 s). On a first visit not before the period lights: the delay is the page's own
   (--door-in, from the frame's clock). */
@keyframes door-in{from{opacity:0}}
.door-in{animation:door-in 1.2s ease-in-out var(--door-in,0s) both}
@media (prefers-reduced-motion:reduce){.door-in{animation:none}}

/* 9 · DESIGN-3 JOB 1.7 (② 549 → ② 554 · X-022 · D9) — THE OFFLINE CARD IN THE HERO'S PLACE: its lockup is the only thing
   in flow (centred exactly as #boot centres the frame's, so the hand-over moves nothing — the lockup is 118 × 194: the
   P 138, the 8, the wordmark 48); the words sit out of flow under it, from the lockup's bottom (half of 194 = 97) plus
   24, and fade in over .24 s (081's pane time). physics: 97 + 24 = 121 from the middle. */
.offline-words{position:absolute;left:0;right:0;top:calc(50% + 121px);margin:0 auto;animation:door-in .24s cubic-bezier(.2,.8,.2,1) both}
@media (prefers-reduced-motion:reduce){.offline-words{animation:none}}

/* 8 · DESIGN-3 JOB 1.5 (② 541–542 · X-013) — THE BREATH THAT KEEPS GOING. The founder, 2026-10-26: *"the P keep
   breathing until they the login or sign up and go to the next screen"*; on his iPhone (2026-10-27) the P breathed in
   the browser here and NOT on the phone — 015's breath animates the mark's filter (a drop-shadow), which WebKit on a
   phone stops animating (one pulse, then still; X-013, Low Power Mode). So the breath is a GLOW DRAWN ONCE behind the
   P — the same picture with 015's peak glow (pl-breathe 50%: 20.2 × --pl-g, violet .72), a static filter — and only
   its OPACITY moves, on 015's 2.8 s clock: what the compositor animates by itself. The mark in front keeps the resting
   glow (the outline's end, still), so at rest the P is 015's rest and at the peak it carries the peak glow on top.
   The frame's lockup and the door's (Wordmark `door`) both carry it; it moves only under 081's timing classes, so the
   signed-in loader never shows it; reduced motion keeps it still and unseen (the mark's own lit glow stays). */
.pl-glow{position:absolute;top:0;left:50%;width:var(--pl-w);height:calc(var(--pl-w) * 1.1716);margin-left:calc(var(--pl-w) / -2);--pl-g:calc(var(--pl-w) / 100);background:url('/brand/piing-P.png') 0 0/100% 100% no-repeat;background-image:image-set(url('/brand/piing-P-fast.webp') type('image/webp'),url('/brand/piing-P.png') type('image/png'));filter:drop-shadow(0 0 calc(var(--pl-g) * 20.2) rgba(157,92,255,.72));opacity:0;pointer-events:none}
#boot .pl-glow{--pl-w:118px}
.is-short>.pl-glow{animation:pl-glow 2.8s ease-in-out 1.2s infinite}
.is-calm>.pl-glow{animation:pl-glow 2.8s ease-in-out infinite}
@keyframes pl-glow{50%{opacity:1}}
@media (prefers-reduced-motion:reduce){.is-short>.pl-glow,.is-calm>.pl-glow{animation:none}}
