/* ============================================================
   FPFX BOOT — "The Print"
   Root-only. No surface mirror exists for this file; it is linked
   from index.php alone.

   The inherited loading screen was the upstream release's: concentric
   rings, HUD corner brackets, a travelling scan line, a three-cell
   status row and a percentage fill rail. Every one of those is gone.
   What replaces it animates the REAL render — assets/images/bull-candlestick.webp
   is sliced into vertical strips and each grows from its own baseline,
   which is precisely how a candle prints from its open. Nothing is
   redrawn in code; every pixel on screen is the artwork.

   Mechanic approved in _design/bull-assemble.html.

   THE INVARIANT THIS FILE IS BUILT AROUND
   The finished state is the DEFAULT state. With no JavaScript, in a
   background tab, under prefers-reduced-motion, or after a thrown
   script, `.fx-boot-print` paints the complete bull straight from CSS.
   The print sequence is an enhancement layered on top by adding
   [data-state] — never the other way round. A loader whose default is
   "empty" is a loader that can strand a visitor on a blank screen.
   ============================================================ */

.fx-boot{
  --fxb-ground:#0A0806;
  --fxb-gold:#EEB762;
  --fxb-gold-hi:#F3DBB2;
  --fxb-gold-dim:#8A6B3A;
  --fxb-text:#F8F8F8;
  --fxb-dim:#948C82;
  --fxb-line:rgba(255,255,255,.06);
  --fxb-glass:rgba(13,11,10,.58);
  --fxb-ease:cubic-bezier(.2,.8,.3,1);
  --fxb-total:1400ms;

  position:fixed;
  inset:0;
  /* Above the sticky header and above every strip and modal on the page,
     but declared once, here, so nothing else has to guess. */
  z-index:10000;
  display:grid;
  grid-template-rows:1fr auto;
  place-items:center;
  gap:clamp(14px,3.4vh,34px);
  padding:clamp(18px,4vh,44px) 18px clamp(22px,5vh,50px);
  background:
    radial-gradient(120% 78% at 50% 34%, rgba(238,183,98,.10), transparent 62%),
    radial-gradient(80% 60% at 50% 100%, rgba(138,107,58,.14), transparent 70%),
    var(--fxb-ground);
  overflow:hidden;
  /* No opacity/visibility transition and no `.done` class. Dismissal is a
     DOM removal. A transition that is paused because the tab is hidden
     never fires transitionend, and the overlay is then permanent — which
     is the failure the previous loader actually shipped. */
}

/* ---- the stage ---------------------------------------------------- */

.fx-boot-stage{
  position:relative;
  width:min(58vh,min(78vw,440px));
  aspect-ratio:1/1;
  display:grid;
  place-items:center;
  /* The artwork carries a solid black ground, so it is screened. Screen
     needs its own compositing group or it blends against whatever is
     behind the overlay instead of against the loader's own ground. */
  isolation:isolate;
}

.fx-boot-bloom{
  position:absolute;
  left:50%;top:34%;
  width:76%;
  aspect-ratio:1/1;
  translate:-50% -50%;
  border-radius:50%;
  background:radial-gradient(circle,
    rgba(238,183,98,.26) 0%, rgba(238,183,98,.11) 40%, rgba(238,183,98,0) 70%);
  filter:blur(16px);
  pointer-events:none;
  z-index:0;
  animation:fxBootBreathe 7s var(--fxb-ease) infinite;
}
@keyframes fxBootBreathe{0%,100%{opacity:.55;scale:1}50%{opacity:1;scale:1.06}}

/* The print group. Two things live here and they must agree pixel for
   pixel: this element's own background (the finished bull) and the rack
   of strips that reconstitutes it. Both are drawn at exactly the box
   size — `100% 100%` here, `--bgw` = rack clientWidth in the strips — so
   swapping one for the other is invisible. `contain` on one side and a
   pixel width on the other is how you get a jump at the swap. */
.fx-boot-print{
  position:relative;
  z-index:1;
  width:100%;
  aspect-ratio:1/1;
  background-image:url("/assets/images/bull-candlestick.webp");
  background-repeat:no-repeat;
  background-size:100% 100%;
  background-position:0 0;
  /* Blended ONCE, as a group. Blending each strip on its own turns every
     strip boundary into a visible seam. */
  
}

.fx-boot-rack{
  position:absolute;
  inset:0;
  display:flex;
}

.fx-boot-strip{
  position:relative;
  height:100%;
  flex:0 0 auto;
  background-image:var(--src);
  background-repeat:no-repeat;
  /* Width and offset are exact integer pixels assigned in JS. Percentage
     widths land on fractional pixels and leave hairline gaps. */
  background-size:var(--bgw) 100%;
  background-position:var(--bgx) 0;
  transform-origin:50% 100%;
}

/* The print head: a bright rule travelling with the build, the way a live
   chart shows its leading edge. */
.fx-boot-tick{
  position:absolute;
  top:0;bottom:0;
  width:2px;
  z-index:3;
  background:linear-gradient(to bottom,
    rgba(243,219,178,0), rgba(243,219,178,.85) 45%, rgba(243,219,178,0));
  box-shadow:0 0 18px 3px rgba(238,183,98,.5);
  opacity:0;
  pointer-events:none;
}

/* ---- states ------------------------------------------------------- */
/* AMENDMENT A1. Without `arming` the sequence on screen is
   complete bull -> empty stage -> candles print in, because the CSS
   background paints immediately while build() cannot run until
   img.decode() resolves. `arming` is set SYNCHRONOUSLY at script start,
   before decode, so the finished frame never paints ahead of the print. */
.fx-boot[data-state="arming"] .fx-boot-print{background-image:none}
.fx-boot[data-state="arming"] .fx-boot-rack{opacity:0}

.fx-boot[data-state="printing"] .fx-boot-print{background-image:none}
.fx-boot[data-state="printing"] .fx-boot-strip{
  animation:fxBootGrow var(--dur,380ms) var(--fxb-ease) both;
  animation-delay:var(--d,0ms);
}
@keyframes fxBootGrow{
  0%  {clip-path:inset(100% 0 0 0);opacity:0;filter:brightness(2.4)}
  35% {opacity:1}
  70% {filter:brightness(1.35)}
  100%{clip-path:inset(0 0 0 0);opacity:1;filter:brightness(1)}
}

.fx-boot[data-state="printing"] .fx-boot-tick{
  animation:fxBootTick var(--fxb-total,1400ms) var(--fxb-ease) forwards;
}
@keyframes fxBootTick{
  0%  {opacity:0;left:0%}
  8%  {opacity:1}
  92% {opacity:1}
  100%{opacity:0;left:100%}
}

/* ---- copy + the phase ladder -------------------------------------- */

.fx-boot-copy{
  position:relative;
  z-index:2;
  width:min(560px,100%);
  display:grid;
  justify-items:center;
  gap:10px;
  text-align:center;
}

.fx-boot-title{
  display:block;
  font:600 clamp(16px,2.4vw,21px)/1.15 "Outfit",system-ui,-apple-system,Segoe UI,sans-serif;
  letter-spacing:-.012em;
  color:var(--fxb-text);
}

.fx-boot-sub{
  display:block;
  font:400 13px/1.55 "DM Sans",system-ui,-apple-system,Segoe UI,sans-serif;
  color:var(--fxb-dim);
  max-width:38ch;
}

/* The ladder replaces BOTH removed readouts — the three-cell status row
   and the percentage fill rail. It says something true about the firm
   instead of inventing a progress number: this is the route a trader
   takes. The rail fills left to right in step with the candles printing
   left to right, so the two halves of the screen tell one story. */
.fx-boot-ladder{
  position:relative;
  list-style:none;
  margin:6px 0 0;
  padding:11px 16px;
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:center;
  gap:clamp(10px,2.6vw,26px);
  border:1px solid var(--fxb-line);
  border-radius:999px;
  background:var(--fxb-glass);
  backdrop-filter:blur(9px);
  -webkit-backdrop-filter:blur(9px);
  overflow:hidden;
}

/* The rail. Full width at rest, so the resting state reads as complete. */
.fx-boot-ladder::after{
  content:"";
  position:absolute;
  left:0;bottom:0;
  height:1px;
  width:100%;
  background:linear-gradient(90deg,var(--fxb-gold-dim),var(--fxb-gold),var(--fxb-gold-hi));
  opacity:.75;
}
.fx-boot[data-state] .fx-boot-ladder::after{
  animation:fxBootRail var(--fxb-total,1400ms) var(--fxb-ease) both;
}
@keyframes fxBootRail{from{width:0}to{width:100%}}

.fx-boot-step{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font:500 10.5px/1 "JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.15em;
  text-transform:uppercase;
  color:var(--fxb-text);
  white-space:nowrap;
}

.fx-boot-step i{
  width:6px;height:6px;
  border-radius:50%;
  background:var(--fxb-gold);
  box-shadow:0 0 9px rgba(238,183,98,.7);
  flex:0 0 auto;
}

.fx-boot[data-state] .fx-boot-step{
  animation:fxBootStep 420ms var(--fxb-ease) backwards;
  animation-delay:var(--sd,0ms);
}
@keyframes fxBootStep{
  from{color:var(--fxb-dim)}
  to  {color:var(--fxb-text)}
}
.fx-boot[data-state] .fx-boot-step i{
  animation:fxBootDot 420ms var(--fxb-ease) backwards;
  animation-delay:var(--sd,0ms);
}
@keyframes fxBootDot{
  from{background:rgba(148,140,130,.35);box-shadow:none;scale:.55}
  to  {background:var(--fxb-gold);box-shadow:0 0 9px rgba(238,183,98,.7);scale:1}
}

/* ---- skip --------------------------------------------------------- */
/* Keyboard operable and reachable by pointer. Escape does the same. The
   loader is short-lived, but "short-lived" is not a reason to trap
   somebody behind it. */
.fx-boot-skip{
  position:absolute;
  right:16px;top:16px;
  z-index:4;
  border:1px solid var(--fxb-line);
  border-radius:999px;
  background:var(--fxb-glass);
  color:var(--fxb-dim);
  padding:8px 15px;
  cursor:pointer;
  font:500 10.5px/1 "JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.14em;
  text-transform:uppercase;
  /* Deliberately NOT white-space:nowrap. This label is operator-editable
     (site.loader/skip), and nowrap on operator copy is how a long string
     pushes the page into horizontal scroll. It wraps and gets taller instead.
     The 44px measured height at =<900px is fpfx.css's global touch-target
     floor (`button{min-height:44px}`) doing its job, not a wrap. */
  max-width:calc(100% - 32px);
  transition:color .25s var(--fxb-ease),border-color .25s var(--fxb-ease);
}
.fx-boot-skip:hover{color:var(--fxb-gold);border-color:var(--fxb-gold-dim)}
.fx-boot-skip:focus-visible{
  outline:2px solid var(--fxb-gold);
  outline-offset:3px;
  color:var(--fxb-gold-hi);
}

/* ---- narrow ------------------------------------------------------- */

@media (max-width:600px){
  .fx-boot{gap:clamp(12px,2.6vh,22px)}
  .fx-boot-stage{width:min(46vh,min(80vw,340px))}
  .fx-boot-ladder{gap:9px 14px;padding:10px 14px;border-radius:20px}
  .fx-boot-step{font-size:9.5px;letter-spacing:.12em}
  .fx-boot-skip{right:10px;top:10px;padding:7px 12px;font-size:9.5px}
}

@media (max-width:380px){
  .fx-boot-stage{width:min(40vh,82vw)}
  .fx-boot-sub{font-size:12px}
}

/* ====================================================================
   AMENDMENT A3 — THIS BLOCK MUST STAY LAST IN THIS FILE.

   `.fx-boot[data-state] .fx-boot-print{background-image:url(...)}` below
   has specificity (0,2,0) — identical to
   `.fx-boot[data-state="printing"] .fx-boot-print{background-image:none}`
   above. It wins ONLY because it comes later in source order. Move it up
   and reduced-motion users get an empty stage instead of the artwork.
   Both [data-state] values are covered: `arming` blanks the background
   too, and reduced-motion must never see either blank.
   ==================================================================== */
@media (prefers-reduced-motion:reduce){
  .fx-boot[data-state] .fx-boot-print{
    background-image:url("/assets/images/bull-candlestick.webp");
  }
  .fx-boot-bloom{animation:none;opacity:.8}
  .fx-boot[data-state] .fx-boot-strip{animation:none}
  .fx-boot[data-state] .fx-boot-rack{opacity:0}
  .fx-boot[data-state] .fx-boot-tick{animation:none;opacity:0}
  .fx-boot[data-state] .fx-boot-ladder::after{animation:none;width:100%}
  .fx-boot[data-state] .fx-boot-step,
  .fx-boot[data-state] .fx-boot-step i{animation:none}
  .fx-boot-skip{transition:none}
}
