/* The welcome intro: one tap, then fifteen seconds of flight that end on the page
   itself. The client's own full stop becomes the zero point of a journey, and a
   camera chases its light up the page's lattice (drawn on a canvas by intro.js)
   while four short lines land on the piano's notes: "Every journey starts at
   zero." "Yours starts today." "Step by step. Side by side." "From zero, to
   agent.", which folds into the company name as the light plugs into
   the page's circuit. Then "Welcome to the family, [name]." lands exactly where
   the page's headline sits, and the page takes over. It names no product, so it
   fits every client. intro.js decides whether it shows and runs the timeline;
   this file holds the looks. Without JavaScript or with reduced motion it never
   shows. */

/* --- The page while the intro plays ------------------------------------------ */

/* Keep the scrollbar's space so nothing shifts sideways when the page takes over, and
   jump (not glide) to the top when the film starts. */
html.intro-on { overflow: hidden; scrollbar-gutter: stable; scroll-behavior: auto; }
/* styles.css hides [hidden] with !important, so the early cover needs it too. */
html.intro-on .intro[hidden] { display: grid !important; }
html.intro-on .stage .brand,
html.intro-on .hero-copy h1,
html.intro-on .lede,
html.intro-on .film,
html.intro-on .circuit-traces path,
html.intro-on .circuit-nodes .node,
html.intro-on .circuit-pulse,
html.intro-on .play-pill { animation-play-state: paused; }

/* Held: the headline, brand and circuit sit in their final places (so the film can
   measure them and land on them), hidden until the film arrives there. */
html.intro-held .stage .brand,
html.intro-held #greeting { animation: none; opacity: 0; }
html.intro-held .circuit-traces path,
html.intro-held .circuit-nodes .node,
html.intro-landed .circuit-traces path,
html.intro-landed .circuit-nodes .node,
html.intro-crossed .circuit-traces path,
html.intro-crossed .circuit-nodes .node { animation: none; }
/* Landed: the film became the headline, so it doesn't arrive a second time.
   Crossed: the headlines didn't line up, so intro.js cross-fades them in place instead. */
html.intro-landed .stage .brand,
html.intro-landed #greeting,
html.intro-crossed .stage .brand,
html.intro-crossed #greeting { animation: none; }

/* After the film, the rest of the hero arrives just behind the headline, and the
   film's light resolves into Kensho's card. */
html.intro-played .lede { animation-delay: 960ms; }
html.intro-played .film { animation-delay: 900ms; }
html.intro-played .circuit-pulse { animation-delay: 2.4s; }
html.intro-played .film-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background: radial-gradient(closest-side, rgb(246 247 248 / 0.9), rgb(233 215 241 / 0.45) 55%, transparent);
  opacity: 0;
  pointer-events: none;
  animation: intro-card-light 1200ms var(--ease-out) 900ms both;
}

/* --- The overlay ------------------------------------------------------------- */

.intro {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  /* clip, not a scroll container: focus or find-in-page can't scroll the film out of place. */
  overflow: hidden;
  overflow: clip;
  color: var(--cloud);
  outline: none;
  overscroll-behavior: none;
  touch-action: pinch-zoom;
  -webkit-tap-highlight-color: transparent;
}
.intro button { touch-action: manipulation; }
.intro.is-clear { pointer-events: none; }

.intro-bg {
  position: absolute;
  inset: 0;
  background: var(--graphite);
  pointer-events: none;
}

/* The lattice, anchored to the page's top-right corner exactly like the stage's,
   so the film and the page share one grid. --gap-r is the page scrollbar's width. */
.intro-lattice {
  position: absolute;
  top: 0;
  right: var(--gap-r, 0px);
  bottom: 0;
  left: 0;
  background-size: 72px 72px;
  background-position: right top;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='72' viewBox='0 0 72 72'%3E%3Cpath d='M36 0.5 71.5 36 36 71.5 0.5 36Z' fill='none' stroke='%23F6F7F8' stroke-opacity='0.1'/%3E%3C/svg%3E");
  opacity: 0.7;
}
/* The flight: intro.js draws the travelling lattice, the journey and its light here, at the
   window's size when the film starts. The canvas sits over the circuit copy, so light blooms
   over its nodes. */
.intro-world {
  position: absolute;
  top: 0;
  left: 0;
}
/* The world jolts around the plug on the hit. */
.intro-bg { transform-origin: var(--plug-x, 100%) var(--plug-y, 0px); }
/* Without a canvas the film keeps the page's own lattice throughout. */
.intro.no-world .intro-lattice { opacity: 0.7 !important; }

/* A copy of the page's circuit, in the same place and with the same masks, so it
   draws on the hit and is already there when the page appears underneath. */
.intro-pcircuit {
  position: absolute;
  top: 0;
  right: var(--gap-r, 0px);
  width: 432px;
  height: 288px;
}
.intro-pcircuit .pc-traces path {
  fill: none;
  stroke: var(--yellow);
  stroke-opacity: 0.3;
  stroke-width: 1.25;
  stroke-linejoin: round;
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1;
}
.intro-pcircuit .pc-nodes path {
  fill: var(--graphite);
  stroke: var(--yellow);
  stroke-width: 1.25;
  stroke-linejoin: miter;
}
.intro-pcircuit .pc-nodes circle { fill: var(--yellow); }
/* The light that runs out along each trace from the plug (intro.js sets its dash). */
.intro-pcircuit .pc-pulse {
  fill: none;
  stroke: #f9fbb4;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}
.intro-pcircuit .node {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
@media (max-width: 440px) {
  .intro-pcircuit .lead-in { display: none; }
}
@media (min-width: 900px) and (max-width: 1439px) {
  .intro-pcircuit {
    -webkit-mask-image: linear-gradient(to bottom, #000 30%, transparent 45%);
    mask-image: linear-gradient(to bottom, #000 30%, transparent 45%);
  }
}
@media (max-width: 899px) {
  .intro-pcircuit {
    -webkit-mask-image: linear-gradient(to bottom, #000 26%, transparent 56%);
    mask-image: linear-gradient(to bottom, #000 26%, transparent 56%);
  }
}

/* --- Controls ------------------------------------------------------------------ */

.intro-controls {
  position: absolute;
  top: max(16px, env(safe-area-inset-top));
  right: max(16px, env(safe-area-inset-right));
  z-index: 3;
  display: flex;
  gap: 8px;
}
.intro-mute,
.intro-skip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--cloud-14);
  border-radius: 999px;
  background: rgb(22 22 27 / 0.92);
  color: var(--cloud-72);
  font: 600 0.875rem/1 var(--body);
  cursor: pointer;
  transition: color 160ms var(--ease), background-color 160ms var(--ease);
}
/* Mute sits in the empty bottom corner, clear of the brand and the circuit's top node. */
.intro-mute {
  position: absolute;
  right: max(16px, env(safe-area-inset-right));
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: 3;
  padding: 0;
}
.intro-mute:hover,
.intro-skip:hover { color: var(--cloud); background: rgb(34 34 41 / 0.95); }
.intro-mute svg,
.intro-skip svg,
.intro-sound svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.intro-mute .icon-off,
.intro-mute[aria-pressed="true"] .icon-on { display: none; }
.intro-mute[aria-pressed="true"] .icon-off { display: inline; }
/* The mute button only makes sense once the music is playing. */
.intro:not(.is-sounding) .intro-mute { visibility: hidden; }
.intro :focus-visible { outline: 3px solid var(--yellow); outline-offset: 3px; }

/* --- The gate: the one tap that starts the music --------------------------------- */

.intro-gate {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: center;
  width: min(100% - 32px, 1040px);
  text-align: center;
}
.intro-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--cloud);
  font: 600 0.9375rem/1 var(--body);
  letter-spacing: 0.01em;
}
.intro-brand svg { width: 28px; height: 28px; }
.intro-title {
  max-width: 12ch;
  margin-top: 28px;
  font: 700 clamp(2.75rem, 1.4rem + 5.6vw, 5.5rem)/1.02 var(--display);
  letter-spacing: -0.035em;
  text-wrap: balance;
  /* Names stay whole (Chinese, Japanese and Korean too, as in the headline); intro.js sizes the
     title so they fit, and a word wider than the whole screen breaks rather than overflow. */
  word-break: keep-all;
  overflow-wrap: anywhere;
}
/* intro.js measures name words in this. */
.intro-probe { white-space: nowrap; }
/* A phone turned sideways with a very long name: keep Begin on screen. */
.intro.is-cramped .intro-sub,
.intro.is-cramped .intro-note { display: none; }
/* fitGate's trial: out of the flow but still animating, so nothing blinks. */
.intro.is-cramped-trial .intro-sub,
.intro.is-cramped-trial .intro-note { position: absolute; visibility: hidden; }
/* The client's own full stop: the only light on screen, and where the film begins. */
.intro-stop {
  position: relative;
  color: var(--yellow);
}
.intro-stop::after {
  content: "";
  position: absolute;
  top: 78%;
  left: 50%;
  width: 0.9em;
  height: 0.9em;
  translate: -50% -50%;
  background: radial-gradient(closest-side, rgb(237 242 10 / 0.35), transparent);
  pointer-events: none;
  animation: intro-breathe 4.8s ease-in-out infinite;
}
.intro-sub {
  max-width: 30ch;
  margin-top: 18px;
  color: var(--cloud-72);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  text-wrap: balance;
}
.intro-begin {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  margin-top: 32px;
  padding: 0 30px 0 22px;
  border: 0;
  border-radius: 999px;
  background: var(--yellow);
  color: var(--graphite);
  font: 700 1.0625rem/1 var(--body);
  cursor: pointer;
  transition: background-color 160ms var(--ease), transform 160ms var(--ease);
}
.intro-begin:hover { background: var(--yellow-hover); }
.intro-begin:active { transform: scale(0.97); }
.intro-begin svg { width: 18px; height: 18px; }
.intro-note {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px 16px;
  margin-top: 16px;
  color: var(--cloud-56);
  font-size: 0.875rem;
}
/* Without the music file this part hides, and the length stays. */
.intro-sound {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* --- The film -------------------------------------------------------------------- */

.intro-film {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.intro-seed {
  position: absolute;
  top: var(--seed-y, 0px);
  left: var(--seed-x, 0px);
  color: var(--yellow);
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--seed-fs, 16px);
  line-height: var(--seed-lh, normal);
  transform-origin: var(--seed-ox, 50%) var(--seed-oy, 50%);
  opacity: 0;
}
.intro-seed.is-placed { opacity: 1; }

/* Posters: big quiet lines on the headline's own left edge. Each word rises
   through its own mask. */
.poster,
.lockup {
  position: absolute;
  top: var(--pt, 40%);
  left: var(--pl, 20px);
  margin: 0;
  font: 700 var(--ps, 3rem)/1.02 var(--display);
  letter-spacing: -0.035em;
  white-space: nowrap;
}
/* Leaving, a line passes the camera, which sits where the light is. */
.poster { transform-origin: var(--pox, 50%) var(--poy, 50%); }
.poster .ln { display: block; }
.pw {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding: 0.06em 0 0.16em;
  margin: -0.06em 0 -0.16em;
}
.pw > span {
  display: inline-block;
  transform: translateY(115%);
}
.poster .punct { display: inline-block; }

/* The last poster is the page's own headline, same width and size, so it wraps the
   same way and can become the headline. */
.poster-welcome {
  top: var(--wt, 40%);
  left: var(--hl, 20px);
  width: var(--hw, auto);
  font-size: var(--hs, 2.5rem);
  letter-spacing: -0.034em;
  white-space: normal;
  text-wrap: balance;
  overflow-wrap: anywhere;
}
.poster-welcome em {
  font-style: normal;
  color: var(--yellow);
  word-break: keep-all;
}
/* One name word and its glow. The glow sits outside the word's mask so its blur isn't clipped. */
.poster-welcome .nw {
  position: relative;
  display: inline-block;
  vertical-align: top;
}
/* The glow is exactly as wide as its word, so a word long enough to wrap wraps its glow too. */
.poster-welcome .glow {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  color: var(--yellow);
  filter: blur(14px);
  opacity: 0;
  pointer-events: none;
}

/* "From zero, to agent." folds into the company name. */
.lockup {
  top: var(--lt, 40%);
  display: flex;
  align-items: center;
  gap: 0.24em;
  padding-left: 1.04em;
  transform-origin: 0 0;
}
.lw {
  opacity: 0;
  white-space: nowrap;
}
/* Only the first letter changes case (z to Z), so the rest of the word never doubles up.
   Both letters end at the same point, so the rest of the word stays put. */
.lw .cap { display: inline-grid; }
.lw .cap > span { grid-area: 1 / 1; justify-self: end; }
.lw .lc + .tc { opacity: 0; }
.lockup-mark {
  position: absolute;
  top: var(--mt, 40%);
  left: var(--pl, 20px);
  width: var(--ms, 40px);
  height: var(--ms, 40px);
  opacity: 0;
  transform-origin: 0 0;
}
/* A replica of the page's brand, exactly where the page's brand sits. */
.brand-seat {
  position: absolute;
  top: var(--by, 20px);
  left: var(--bx, 20px);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--cloud);
  font: 600 0.9375rem/1 var(--body);
  letter-spacing: 0.01em;
  opacity: 0;
}
.brand-seat svg { width: 24px; height: 24px; flex: none; }

/* --- Entering and leaving ------------------------------------------------------------ */

@keyframes intro-gate-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
@keyframes intro-gate-out {
  to { opacity: 0; transform: translateY(-16px); }
}
@keyframes intro-breathe {
  0%, 100% { opacity: 0.35; transform: scale(0.9); }
  50% { opacity: 0.8; transform: scale(1.1); }
}
@keyframes intro-fade-out { to { opacity: 0; } }
@keyframes intro-skip-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: scale(1.04); }
}
@keyframes intro-card-light {
  from { opacity: 1; }
  to { opacity: 0; }
}

.intro-gate > * { animation: intro-gate-in 800ms var(--ease-out) both; }
/* The gate waits until intro.js has put the client's name in and the display font is ready. */
.intro:not(.is-ready) .intro-gate { visibility: hidden; }
.intro:not(.is-ready) .intro-gate > * { animation-play-state: paused; }
.intro-gate > :nth-child(2) { animation-delay: 150ms; }
.intro-gate > :nth-child(3) { animation-delay: 300ms; }
.intro-gate > :nth-child(4) { animation-delay: 450ms; }
.intro-gate > :nth-child(5) { animation-delay: 550ms; }

.intro.is-begun .intro-gate { pointer-events: none; }
.intro.is-begun .intro-gate > * { animation: intro-gate-out 450ms cubic-bezier(0.2, 0, 0.2, 1) forwards; }
.intro.is-begun .intro-gate > :nth-child(2) { animation-delay: 40ms; }
.intro.is-begun .intro-gate > :nth-child(3) { animation-delay: 80ms; }
.intro.is-begun .intro-gate > :nth-child(4) { animation-delay: 120ms; }
.intro.is-begun .intro-gate > :nth-child(5) { animation-delay: 160ms; }
.intro.is-begun .intro-stop { visibility: hidden; }

/* The natural end: the controls go, then the stage dissolves onto the identical page. */
.intro.is-leaving .intro-controls,
.intro.is-leaving .intro-mute { animation: intro-fade-out 300ms var(--ease) forwards; }
.intro.is-leaving .intro-bg { animation: intro-fade-out 700ms linear 150ms forwards; }
/* Skip: a quick fade, and the page makes its usual entrance. */
.intro.is-skipping { animation: intro-skip-out 400ms cubic-bezier(0.2, 0, 0.2, 1) forwards; }
