:root {
  --bg: #fbfbfa;
  --fg: #16161a;
  --muted: #6b6b76;
  --accent: #f26a1b;
  --rule: #e4e4e0;
  --sk: rgba(22, 22, 26, 0.08);
  --sk-sheen: rgba(22, 22, 26, 0.05);
  --panel: #ffffff;
  --panel-edge: rgba(22, 22, 26, 0.08);
  --done: #22c55e;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f0f11;
    --fg: #f2f2f0;
    --muted: #9a9aa5;
    --accent: #ff8a3d;
    --rule: #26262b;
    --sk: rgba(255, 255, 255, 0.09);
    --sk-sheen: rgba(255, 255, 255, 0.06);
    --panel: #17171b;
    --panel-edge: rgba(255, 255, 255, 0.07);
    --done: #34d977;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--fg);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  text-rendering: optimizeLegibility;
}

.eyebrow {
  margin: 0 0 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Behind everything — only visible if the boot screen fails to render. */
.fallback {
  position: fixed;
  inset: 0;
  display: grid;
  place-content: center;
  padding: 2rem;
  text-align: center;
}

.fallback h1 {
  margin: 0;
  font-size: 2rem;
  font-weight: 650;
  letter-spacing: -0.02em;
}

/* ============================================================ boot screen */

.boot {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: grid;
  place-items: center;
  padding: 6vmin 1.5rem;
  background: var(--bg);
  transition: opacity 620ms cubic-bezier(0.4, 0, 0.2, 1),
    visibility 620ms;
}

/* Whole stage lifts, blurs and dissolves when loading completes. */
.boot.is-done {
  opacity: 0;
  visibility: hidden;
}

.boot.is-done .boot__stage {
  transform: scale(1.04) translateY(-14px);
  filter: blur(9px);
}

.boot__stage {
  width: 100%;
  max-width: 27rem;
  transition: transform 620ms cubic-bezier(0.4, 0, 0.2, 1),
    filter 620ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ---------------------------------------------------------- logo mark */

.boot__mark {
  display: flex;
  justify-content: center;
  margin-bottom: 2rem;
}

.boot__mark-ring {
  stroke: var(--accent);
  opacity: 0.28;
  transform-origin: center;
  animation: mark-spin 2.6s linear infinite;
  stroke-dasharray: 34 92;
  stroke-linecap: round;
}

.boot__mark-check {
  stroke: var(--accent);
  stroke-dasharray: 34;
  stroke-dashoffset: 34;
  animation: mark-draw 760ms cubic-bezier(0.65, 0, 0.35, 1) 180ms forwards,
    mark-pulse 2.4s ease-in-out 1s infinite;
}

@keyframes mark-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes mark-draw {
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes mark-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}

/* ---------------------------------------------------------- skeleton app */

.boot__app {
  padding: 1rem 1.125rem 0.5rem;
  border: 1px solid var(--panel-edge);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: 0 18px 50px -28px rgba(0, 0, 0, 0.35);
  opacity: 0;
  transform: translateY(10px);
  animation: fade-up 620ms cubic-bezier(0.16, 1, 0.3, 1) 160ms forwards;
}

.boot__topbar {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding-bottom: 0.875rem;
  border-bottom: 1px solid var(--panel-edge);
}

.boot__list {
  margin: 0;
  padding: 0.5rem 0 0;
  list-style: none;
}

.boot__row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  opacity: 0;
  transform: translateY(8px);
  /* Rows land one after another — the app filling in. */
  animation: fade-up 480ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: calc(420ms + var(--i) * 150ms);
}

/* Empty checkbox that ticks green near the end of the sequence. */
.boot__check {
  position: relative;
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  border: 2px solid var(--sk);
  border-radius: 5px;
  transition: border-color 260ms ease, background-color 260ms ease;
}

.boot__check::after {
  content: "";
  position: absolute;
  inset: 0;
  background: no-repeat center / 11px 11px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 L4.6 9 L10 3' fill='none' stroke='%23fff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 200ms ease, transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.boot__row.is-checked .boot__check {
  border-color: var(--done);
  background: var(--done);
}

.boot__row.is-checked .boot__check::after {
  opacity: 1;
  transform: scale(1);
}

.boot__row.is-checked .sk--line {
  opacity: 0.4;
}

/* ---------------------------------------------------------- skeleton bits */

.sk {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 5px;
  background: var(--sk);
}

/* Light sweeping across the placeholders — the "still working" signal. */
.sk::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--sk-sheen) 45%,
    var(--sk-sheen) 55%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: sheen 1.5s ease-in-out infinite;
}

@keyframes sheen {
  to {
    transform: translateX(100%);
  }
}

.sk--avatar {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 50%;
}

.sk--title {
  flex: 1 1 auto;
  height: 11px;
  max-width: 8.5rem;
}

.sk--pill {
  flex: 0 0 auto;
  width: 46px;
  height: 20px;
  border-radius: 999px;
}

.sk--line {
  flex: 1 1 auto;
  width: var(--w, 70%);
  height: 10px;
  transition: opacity 300ms ease;
}

@keyframes fade-up {
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------------------------------------------------------- progress */

.boot__progress {
  height: 3px;
  margin: 1.75rem 0 0.875rem;
  border-radius: 999px;
  background: var(--sk);
  overflow: hidden;
}

.boot__bar {
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent), #ffb03a);
  /* JS steps the width; the easing here smooths each jump. */
  transition: width 520ms cubic-bezier(0.33, 1, 0.68, 1);
}

.boot__status {
  margin: 0;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, "Cascadia Code", Consolas, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  transition: opacity 240ms ease;
}

.boot__status.is-swapping {
  opacity: 0;
}

/* Trailing animated ellipsis, so the text always looks in-progress. */
.boot__status::after {
  content: "";
  animation: dots 1.4s steps(4, end) infinite;
}

@keyframes dots {
  0% {
    content: "";
  }
  25% {
    content: ".";
  }
  50% {
    content: "..";
  }
  75%,
  100% {
    content: "...";
  }
}

/* ============================================================ reveal */

.reveal {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 3vmin;
  background: #0b0b0d;
  opacity: 0;
  visibility: hidden;
  transition: opacity 700ms ease, visibility 700ms;
}

.reveal.is-visible {
  opacity: 1;
  visibility: visible;
}

.reveal__frame {
  display: grid;
  place-items: center;
  opacity: 0;
  transform: scale(0.88);
  filter: blur(14px);
  transition: opacity 1000ms cubic-bezier(0.16, 1, 0.3, 1) 120ms,
    transform 1100ms cubic-bezier(0.16, 1, 0.3, 1) 120ms,
    filter 900ms cubic-bezier(0.16, 1, 0.3, 1) 120ms;
}

.reveal.is-visible .reveal__frame {
  opacity: 1;
  transform: none;
  filter: none;
}

.reveal__img {
  display: block;
  /* Explicit height, because max-height alone would never scale the image UP —
     reveal.png is just 256x456, so it would otherwise render tiny. The 780px
     ceiling holds the upscale near 1.7x; past that it visibly softens. Raise it
     if you swap in a larger source. object-fit guards the aspect ratio in case
     max-width clamps on a very narrow screen. */
  height: min(88vh, 780px);
  width: auto;
  max-width: 92vw;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 50px 130px -30px rgba(0, 0, 0, 0.9);
  /* Very slow scale so the still image doesn't feel frozen. */
  animation: reveal-drift 18s ease-in-out infinite;
}

@keyframes reveal-drift {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.028);
  }
}

/* Stands in for the image only when /reveal.jpg is missing. */
.reveal__missing {
  display: none;
  margin: 0;
  padding: 4.5rem 2.5rem;
  border: 1px dashed rgba(255, 255, 255, 0.28);
  border-radius: 10px;
  color: #f2f2f0;
  font-family: ui-monospace, SFMono-Regular, "Cascadia Code", Consolas, monospace;
  font-size: 0.9375rem;
  text-align: center;
}

.reveal__missing code {
  padding: 0.15em 0.4em;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.14);
  color: #ffb03a;
}

.reveal[data-image="missing"] .reveal__img {
  display: none;
}

.reveal[data-image="missing"] .reveal__missing {
  display: block;
}

/* ============================================================ a11y */

@media (prefers-reduced-motion: reduce) {
  .boot__mark-ring,
  .boot__mark-check,
  .sk::after,
  .boot__status::after,
  .reveal__img {
    animation: none;
  }

  .boot__mark-check {
    stroke-dashoffset: 0;
  }

  .boot__app,
  .boot__row {
    opacity: 1;
    transform: none;
    animation: none;
  }

  .boot__stage,
  .reveal__frame {
    transition-duration: 200ms;
    transform: none;
    filter: none;
  }
}
