/*
 * Clinkee boot splash — pure HTML+CSS, painted on the very first frame.
 *
 * CSP ships `script-src 'self' 'serviceworker'` with no 'unsafe-inline', so
 * this cannot animate via an inline <script>; everything below is CSS only.
 * JS (packages/clinkee-ui/src/boot/bootSplash.js) only ever adds the
 * `is-leaving` class and removes the node once the app is ready — it never
 * drives the animation itself.
 *
 * Colours are hard-coded rather than referencing @clinkee/ui tokens: this
 * file loads and paints before tokens.css (and before theme-init.js's
 * injected custom-palette <style>, for that matter), so it has to be
 * self-contained. Keep these in step with the Android TWA native splash
 * (sand/espresso background, same mark, ~160dp) so the web splash reads as
 * a continuation of it rather than a second, different-looking screen.
 */

#boot-splash {
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  display: grid;
  place-items: center;
  place-content: center;
  gap: clamp(12px, 3vmin, 20px);
  padding-top: env(safe-area-inset-top, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  --bs-bg: #f3ede3; /* ember --sand-50 = --clk-bg (light) */
  --bs-fg: #1c1512;
  background: var(--bs-bg);
  color: var(--bs-fg);
  font-family: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  transition: opacity 250ms ease, transform 250ms ease;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) #boot-splash {
    --bs-bg: #16120f;
    --bs-fg: #f3ede6;
  }
}

/* The stored theme (stamped on <html> by theme-init.js before first paint)
   beats the OS in both directions. */
:root[data-theme='dark'] #boot-splash {
  --bs-bg: #16120f;
  --bs-fg: #f3ede6;
}

:root[data-theme='light'] #boot-splash {
  --bs-bg: #f3ede3;
  --bs-fg: #1c1512;
}

/* ── Mark ──────────────────────────────────────────────────────────────── */

.boot-splash__mark {
  position: relative;
  width: clamp(72px, 18vmin, 140px);
  height: clamp(72px, 18vmin, 140px);
  opacity: 0;
  animation: boot-splash-pop 520ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.boot-splash__mark img {
  position: relative; /* keeps it in the positioned stacking order, above the absolutely-positioned rings that precede it in the DOM */
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform-origin: center;
  animation: boot-splash-wobble 600ms ease-in-out 520ms 1 both;
}

.boot-splash__ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid #e85d3a;
  opacity: 0;
  transform: scale(1);
  animation: boot-splash-ring 1.6s ease-out infinite;
  animation-delay: 520ms;
}

.boot-splash__ring:nth-of-type(2) {
  border-color: #ee7c5c;
  animation-delay: 1320ms;
}

/* ── Theme-matched mark variants ─────────────────────────────────────────
   Business ships a light and a dark mark (its briefcase badge must contrast
   with the splash background). Apps with a single mark use neither class. */

.boot-splash__img--dark {
  display: none !important;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .boot-splash__img--light {
    display: none !important;
  }
  :root:not([data-theme='light']) .boot-splash__img--dark {
    display: block !important;
  }
}

:root[data-theme='dark'] .boot-splash__img--light {
  display: none !important;
}

:root[data-theme='dark'] .boot-splash__img--dark {
  display: block !important;
}

/* ── Stamp variant (Business) ────────────────────────────────────────────
   The symbol and its briefcase badge are separate, stacked layers sharing one
   frame. The symbol pops in without the clink wobble; the briefcase then
   drops onto its corner with a squash-and-settle; the rings centre on the
   symbol rather than the box. Positions come from brand/splash-layout.css,
   generated alongside the layers. */

.boot-splash__mark--stamp {
  opacity: 1;
  animation: none;
}

.boot-splash__mark--stamp img {
  position: absolute;
  inset: 0;
}

.boot-splash__mark--stamp .boot-splash__symbol {
  animation: boot-splash-pop 520ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.boot-splash__mark--stamp .boot-splash__badge {
  transform-origin: var(--stamp-badge-origin, 80% 90%);
  animation: boot-splash-stamp 440ms cubic-bezier(0.3, 0.7, 0.4, 1) 560ms both;
}

.boot-splash__mark--stamp .boot-splash__ring {
  inset: auto;
  left: var(--stamp-ring-left, 0%);
  top: var(--stamp-ring-top, 0%);
  width: var(--stamp-ring-size, 100%);
  height: var(--stamp-ring-size, 100%);
  animation-delay: 800ms;
}

.boot-splash__mark--stamp .boot-splash__ring:nth-of-type(2) {
  animation-delay: 1600ms;
}

@keyframes boot-splash-stamp {
  0% {
    opacity: 0;
    transform: translateY(-18%) scale(0.6);
  }
  55% {
    opacity: 1;
    transform: translateY(0) scale(1.12, 0.9);
  }
  78% {
    transform: translateY(0) scale(0.97, 1.03);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .boot-splash__mark--stamp .boot-splash__symbol,
  .boot-splash__mark--stamp .boot-splash__badge {
    animation: boot-splash-fade-in 300ms ease both;
  }
}

/* ── Name ──────────────────────────────────────────────────────────────── */

.boot-splash__name {
  font-size: clamp(15px, 2.2vmin, 20px);
  font-weight: 700;
  letter-spacing: 0.01em;
  opacity: 0;
  transform: translateY(6px);
  animation: boot-splash-name-in 500ms ease-out 250ms both;
}

/* ── Leaving ───────────────────────────────────────────────────────────── */

#boot-splash.is-leaving {
  opacity: 0;
  transform: scale(1.03);
  pointer-events: none;
}

/* ── Keyframes ─────────────────────────────────────────────────────────── */

@keyframes boot-splash-pop {
  0% {
    transform: scale(0.8);
    opacity: 0;
  }
  60% {
    transform: scale(1.04);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes boot-splash-wobble {
  0% {
    transform: rotate(0deg);
  }
  30% {
    transform: rotate(-6deg);
  }
  70% {
    transform: rotate(4deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

@keyframes boot-splash-ring {
  0% {
    transform: scale(1);
    opacity: 0.35;
  }
  100% {
    transform: scale(1.9);
    opacity: 0;
  }
}

@keyframes boot-splash-name-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes boot-splash-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ── Reduced motion ────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .boot-splash__mark {
    animation: boot-splash-fade-in 300ms ease both;
  }
  .boot-splash__mark img {
    animation: none;
  }
  .boot-splash__ring {
    display: none;
  }
  .boot-splash__name {
    transform: none;
    animation: boot-splash-fade-in 300ms ease 150ms both;
  }
  #boot-splash.is-leaving {
    transform: none;
  }
}

/*
 * Failsafe: if JS never runs at all (so boot-splash.js can't show the failure
 * state), the splash fades itself out of the way after 60s so the UI is never
 * trapped under it. It sits well past boot-splash.js's 15s failure message,
 * which cancels it (.is-failed) so the Retry button is never faded away.
 * Harmless in the normal case — the node is long gone (removed by
 * dismissBootSplash) before this ever has a chance to run.
 */
@keyframes boot-splash-failsafe {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
}

#boot-splash {
  animation: boot-splash-failsafe 400ms 60s forwards;
}

#boot-splash.is-failed {
  animation: none;
}

/* ── Single-org gate (Client) ────────────────────────────────────────────
   The client's badge is Clinkee's bubble, and it is only meaningful on a
   white-label build where the main mark belongs to the customer. A multi-org
   build already shows Clinkee's own mark, so badging it would be redundant.
   `display: none` rather than `opacity: 0`: an invisible layer would still
   take part in the stacking order over the symbol.

   Keyed on the attribute being PRESENT and not 'true'. Business never sets it
   and its briefcase must always show, so a bare :not([data-single-org='true'])
   matched Business too and hid the briefcase entirely. The client always emits
   the attribute, including as an empty string when PUBLIC_SINGLE_ORG is
   unset — which is a multi-org build, so it must hide as well. */
#boot-splash[data-single-org]:not([data-single-org='true']) .boot-splash__badge {
  display: none !important;
}

/* ── Stamp motion polish ─────────────────────────────────────────────────
   The symbol settles, then the badge lands on it, then the badge's landing
   pushes one ring out — cause and effect, rather than three timers that
   happen to overlap. */
.boot-splash__mark--stamp .boot-splash__badge {
  /* Land slightly after the symbol has stopped moving, not during its
     overshoot: overlapping the two reads as a glitch rather than a stamp. */
  animation-delay: 600ms;
}

@keyframes boot-splash-stamp-settle {
  0% {
    opacity: 0;
    transform: translateY(-22%) scale(0.55) rotate(-8deg);
  }
  50% {
    opacity: 1;
    transform: translateY(0) scale(1.14, 0.88) rotate(2deg);
  }
  72% {
    transform: translateY(-4%) scale(0.96, 1.05) rotate(-1deg);
  }
  88% {
    transform: translateY(0) scale(1.02, 0.99);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

.boot-splash__mark--stamp .boot-splash__badge {
  animation-name: boot-splash-stamp-settle;
  animation-duration: 520ms;
  animation-timing-function: cubic-bezier(0.22, 0.9, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  .boot-splash__mark--stamp .boot-splash__symbol,
  .boot-splash__mark--stamp .boot-splash__badge {
    animation: boot-splash-fade-in 300ms ease both !important;
  }
}

/* ── Screen-reader status (#boot-status) ─────────────────────────────────
   Visually hidden but still in the accessibility tree: the splash is
   aria-hidden, this live region is what is announced. */
.boot-splash__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Failure state ───────────────────────────────────────────────────────
   Added by boot-splash.js after 15s. Button and text use the splash's own
   foreground/background pair (>= 14:1 in both themes), 44px minimum target. */
.boot-splash__error {
  display: grid;
  justify-items: center;
  gap: 12px;
  max-width: min(90vw, 320px);
  text-align: center;
}

.boot-splash__error-text {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.5;
}

.boot-splash__retry {
  min-width: 44px;
  min-height: 44px;
  padding: 0 28px;
  border: 2px solid var(--bs-fg);
  border-radius: 12px;
  background: var(--bs-fg);
  color: var(--bs-bg);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
}

.boot-splash__retry:focus-visible {
  outline: 3px solid #e85d3a;
  outline-offset: 3px;
}

/* ── Forced colours (Windows High Contrast) ─────────────────────────────
   System colours only. The decorative rings go; the mark keeps its own
   colours (forced-color-adjust: none) on a Canvas plate so it stays visible
   whatever the user's forced palette is. */
@media (forced-colors: active) {
  #boot-splash {
    --bs-bg: Canvas;
    --bs-fg: CanvasText;
    background: Canvas;
    color: CanvasText;
  }
  .boot-splash__ring {
    display: none;
  }
  .boot-splash__mark img {
    forced-color-adjust: none;
  }
  .boot-splash__mark {
    border-radius: 50%;
    background: Canvas;
    outline: 2px solid CanvasText;
    outline-offset: 6px;
  }
  .boot-splash__name {
    color: CanvasText;
  }
  .boot-splash__retry {
    background: ButtonFace;
    color: ButtonText;
    border-color: ButtonText;
  }
  .boot-splash__retry:focus-visible {
    outline-color: Highlight;
  }
}
