/* ============================================================
   Saaph — lander intro sequence
   Pairs with js/intro.js. The mark assembles, asks for an email,
   runs the REAL breach check, and shows the result being secured.
   ============================================================ */

/* THEME — note the polarity, it is not the obvious one.
   js/theme.js applies the theme like this:

       if (t === 'light') root.setAttribute('data-theme', 'light');
       else               root.removeAttribute('data-theme');

   so DARK IS THE ABSENCE OF THE ATTRIBUTE. A `:root[data-theme="dark"]` block
   never matches anything — which is exactly what went wrong here: dark mode
   kept the light overlay while the canvas correctly drew WHITE ink onto it, so
   the mark went invisible on reload. Dark tokens therefore live on the bare
   selector and light overrides them, which is also what styles/main.css does. */
#saaphIntro {
  --intro-bg:     #07090E;
  --intro-fg:     #F2F4F8;
  --intro-dim:    rgba(242, 244, 248, .62);
  --intro-faint:  rgba(242, 244, 248, .38);
  --intro-hair:   rgba(242, 244, 248, .22);
  --intro-line:   rgba(255, 255, 255, .20);
  --intro-field:  rgba(255, 255, 255, .05);
  --intro-chip:   rgba(255, 255, 255, .06);
  --intro-bad:    #FF8A5B;
  --intro-ok:     #2FB344;
}
:root[data-theme="light"] #saaphIntro {
  --intro-bg:     #FFFDF8;
  --intro-fg:     #12151B;
  --intro-dim:    rgba(18, 21, 27, .62);
  --intro-faint:  rgba(18, 21, 27, .38);
  --intro-hair:   rgba(18, 21, 27, .22);
  --intro-line:   rgba(18, 21, 27, .18);
  --intro-field:  rgba(18, 21, 27, .04);
  --intro-chip:   rgba(18, 21, 27, .05);
  --intro-bad:    #B23E0B;
  --intro-ok:     #1E7F3C;
}

/* The overlay sits ON TOP of a fully rendered page — it never gates content.
   Crawlers, screen readers and anyone whose JS fails get the ordinary lander
   underneath, and the page's own LCP is unaffected because nothing below waits
   on this. A loading screen that holds the document back costs real search
   traffic and real patience on the second visit. */
#saaphIntro {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--intro-bg);
  color: var(--intro-fg);
  font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  opacity: 1;
  transition: opacity .5s ease;
}
#saaphIntro[hidden] { display: none; }
#saaphIntro.is-leaving { opacity: 0; pointer-events: none; }

html.intro-open, html.intro-open body { overflow: hidden; }

.intro-stage {
  width: min(760px, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.intro-film {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  isolation: isolate;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
.intro-film [data-decor] {
  position: absolute;
  inset: 0;
  -webkit-mask-image: radial-gradient(ellipse 82% 80% at 50% 50%, #000 55%, transparent 100%);
          mask-image: radial-gradient(ellipse 82% 80% at 50% 50%, #000 55%, transparent 100%);
}

/* ---- tagline ------------------------------------------------ */
.intro-tag {
  margin: 2px 0 10px;
  font-family: var(--font-heading, 'Clash Display', system-ui, sans-serif);
  font-size: clamp(20px, 5vw, 28px);
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--intro-fg);
}
.intro-tag em { font-style: normal; color: var(--color-primary, #FF6B00); }
.intro-tag-sub {
  margin: -4px 0 16px;
  font-size: 11.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--intro-faint);
}

/* ---- console ------------------------------------------------ */
.intro-console { width: min(560px, 100%); text-align: center; }

.intro-line {
  margin: 0 0 14px;
  min-height: 1.5em;
  font-size: clamp(14px, 2.4vw, 17px);
  letter-spacing: .01em;
  color: var(--intro-fg);
}
.intro-line b { color: var(--color-primary, #FF6B00); font-weight: 600; }
.intro-caret {
  display: inline-block;
  width: .58em; height: 1.05em;
  margin-left: 2px;
  vertical-align: -.16em;
  background: var(--color-primary, #FF6B00);
  animation: intro-blink 1.05s step-end infinite;
}
@keyframes intro-blink { 50% { opacity: 0; } }

.intro-form { display: flex; gap: 8px; justify-content: center; }
.intro-form[hidden] { display: none; }
.intro-input {
  flex: 1; min-width: 0; max-width: 340px;
  padding: 12px 14px;
  font: inherit; font-size: 16px;   /* 16px or iOS zooms the page on focus */
  color: var(--intro-fg);
  background: var(--intro-field);
  border: 1px solid var(--intro-line);
  border-radius: 8px;
}
.intro-input:focus { outline: none; border-color: var(--color-primary, #FF6B00); }
.intro-input.err { border-color: #F0564B; }
.intro-input::placeholder { color: var(--intro-faint); }

.intro-go {
  padding: 12px 18px;
  font: inherit; font-size: 14px; font-weight: 700;
  color: #fff; cursor: pointer;
  background: var(--color-primary, #FF6B00);
  border: 0; border-radius: 8px;
  white-space: nowrap;
}
.intro-go:disabled { opacity: .55; cursor: default; }

/* ---- scan log ------------------------------------------------ */
.intro-log {
  margin: 16px auto 0;
  max-width: 460px;
  text-align: left;
  font-size: 12.5px;
  line-height: 1.75;
  color: var(--intro-dim);
}
.intro-log:empty { display: none; }
.intro-log div { display: flex; gap: 8px; align-items: baseline; }
.intro-log .dots { flex: 1; overflow: hidden; color: var(--intro-hair); }
.intro-log .bad  { color: var(--intro-bad); font-weight: 600; }
.intro-log .ok   { color: var(--intro-ok);  font-weight: 600; }

.intro-actions {
  margin-top: 20px;
  display: flex; gap: 10px;
  justify-content: center; flex-wrap: wrap;
}
.intro-actions[hidden] { display: none; }
.intro-cta {
  padding: 14px 24px;
  font-family: var(--font-body, system-ui, sans-serif);
  font-size: 15px; font-weight: 700;
  color: #fff; text-decoration: none;
  background: var(--color-primary, #FF6B00);
  border-radius: 999px;
}
.intro-ghost {
  padding: 13px 18px;
  font: inherit; font-size: 13px;
  color: var(--intro-dim);
  background: none; border: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.intro-ghost:hover { color: var(--intro-fg); }

/* Always reachable, always the same place — never a hunt. */
.intro-skip {
  position: fixed;
  top: 18px; right: 18px;
  padding: 8px 14px;
  font: inherit; font-size: 12px;
  color: var(--intro-dim);
  background: var(--intro-chip);
  border: 1px solid var(--intro-line);
  border-radius: 999px;
  cursor: pointer;
}
.intro-skip:hover { color: var(--intro-fg); border-color: var(--intro-hair); }

@media (max-width: 640px) {
  .intro-film { aspect-ratio: 4 / 3; }
  .intro-form { flex-direction: column; }
  .intro-input { max-width: none; }
}

/* ============================================================
   Exit: the mark flies into the header logo slot
   ============================================================ */
.intro-film.is-flying {
  transition: transform .78s cubic-bezier(.66, 0, .18, 1), opacity .78s ease;
  opacity: .12;
}
/* Everything except the film leaves first, so the mark travels alone. */
.intro-console, .intro-skip { transition: opacity .3s ease; }
#saaphIntro.is-flying .intro-console,
#saaphIntro.is-flying .intro-skip { opacity: 0; pointer-events: none; }
#saaphIntro.is-flying { background: transparent; transition: background .7s ease; }

@keyframes intro-land {
  0%   { transform: scale(1.5); filter: brightness(2.2); }
  60%  { transform: scale(.94); }
  100% { transform: scale(1);   filter: brightness(1); }
}
.nav-logo-icon.has-landed { animation: intro-land .5s cubic-bezier(.3, 1.4, .5, 1); }

/* ---- the header mark, always quietly alive -------------------------
   NOT ASCII, deliberately. The mark needs roughly 40 columns to read and a
   48px header slot gives thirteen — a cell-rendered logo there is noise, not a
   logo. The real mark stays and gets a slow sheen crossing it, which reads at
   any size, works on either theme, and costs one compositor layer. */
.nav-logo { position: relative; }
.nav-logo-sheen {
  position: absolute;
  top: 0; left: 0;
  width: 48px; height: 48px;
  border-radius: 9px;
  pointer-events: none;
  overflow: hidden;
}
.nav-logo-sheen::after {
  content: "";
  position: absolute;
  top: -60%; bottom: -60%; left: -140%;
  width: 55%;
  /* The mark's tile is black in both themes, so the sheen is warm-white in
     both. It is lighting the logo, not the page. */
  background: linear-gradient(100deg,
              transparent 0%,
              rgba(255, 255, 255, 0) 30%,
              rgba(255, 186, 120, .34) 50%,
              rgba(255, 255, 255, 0) 70%,
              transparent 100%);
  transform: rotate(8deg);
  animation: nav-sheen 7.5s ease-in-out infinite;
}
@keyframes nav-sheen {
  0%, 68%   { left: -140%; }
  92%, 100% { left: 190%; }
}

/* A visitor who asked their device to stop animating gets the prompt straight
   away, a still mark, and no sheen — the sequence is the part they opted out of. */
@media (prefers-reduced-motion: reduce) {
  #saaphIntro, .intro-caret { transition: none; animation: none; }
  .nav-logo-sheen::after { animation: none; opacity: 0; }
  .nav-logo-icon.has-landed { animation: none; }
  .intro-film.is-flying { transition: opacity .3s ease; }
}


/* ============================================================
   Exit choreography, continued
   ============================================================ */
/* The tagline flies to where the hero headline already is, so the overlay
   resolves INTO the page instead of being swapped for it. */
.intro-tag { transform-origin: 50% 50%; will-change: transform, opacity; }
.intro-tag.is-flying {
  transition: transform .82s cubic-bezier(.62, 0, .16, 1), opacity .82s ease;
  opacity: 0;
}
/* …and it must outlive the console fade, or it would vanish before it moves. */
#saaphIntro.is-flying .intro-console { opacity: 1; }
#saaphIntro.is-flying .intro-line,
#saaphIntro.is-flying .intro-tag-sub,
#saaphIntro.is-flying .intro-log,
#saaphIntro.is-flying .intro-actions,
#saaphIntro.is-flying .intro-form { opacity: 0; transition: opacity .3s ease; }

/* The lander's own background is held at zero while the overlay is up and
   fades up as it lets go. */
#redacted-canvas { transition: opacity 1.2s ease; }
/* transition:none on the way IN. Without it the canvas is briefly visible on
   load and then fades out behind the overlay, which is backwards — it should
   already be gone, and only arrive as the overlay lets go. */
html.intro-open #redacted-canvas { opacity: 0; transition: none; }

/* ---- overlay tools ------------------------------------------ */
.intro-tools {
  position: fixed;
  top: 18px; right: 18px;
  display: flex; gap: 8px; align-items: center;
  z-index: 2;
}
.intro-tools .intro-skip { position: static; }
.intro-theme {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  font: inherit; font-size: 15px; line-height: 1;
  color: var(--intro-dim);
  background: var(--intro-chip);
  border: 1px solid var(--intro-line);
  border-radius: 999px;
  cursor: pointer;
}
.intro-theme:hover { color: var(--intro-fg); border-color: var(--intro-hair); }
#saaphIntro.is-flying .intro-tools { opacity: 0; pointer-events: none; transition: opacity .3s ease; }

@media (prefers-reduced-motion: reduce) {
  .intro-tag.is-flying { transition: opacity .3s ease; }
  #redacted-canvas { transition: none; }
}


/* ---- the header mark, rendered as ASCII ----------------------------
   The <img> underneath is the fallback; this box carries the brand's black
   tile and the oversampled ASCII mark on top of it. The tile is black in both
   themes because that IS the mark — only its edge is themed, so it sits on a
   warm-white header as comfortably as on a navy one. */
.nav-logo-ascii {
  position: absolute;
  top: 0; left: 0;
  /* Sized in JS from the <img> it stands in for — the lander renders that at
     36px and other pages at 44-48px, so any fixed value here is wrong on some
     page. These are only the fallback dimensions before the measure lands. */
  width: 44px; height: 44px;
  overflow: hidden;
  pointer-events: none;
  /* No tile, no border, no shadow. A black square behind the mark makes it a
     BADGE; the ask was for the ASCII itself, sitting on whatever the header is.
     The canvas takes the theme's ink (js/ascii-decor.js -> ink()), so the
     ridges are near-black on the warm-white header and white on the navy one,
     while the stem stays brand orange on both. */
  background: none;
}
.nav-logo-ascii canvas { display: block; }

/* The <img> stays in the DOM for no-JS and for layout, but must not show
   through a now-transparent mark — its black squircle would sit behind the
   ASCII and reinstate exactly the tile we just removed. opacity, not display,
   so it keeps holding the 48px box the canvas is positioned against. */
.nav-logo.has-ascii .nav-logo-icon { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  /* The variant already paints one static frame when motion is reduced; this
     just makes sure nothing else animates the tile. */
  .nav-logo-ascii { transition: none; }
}

/* Breathing room between the mark and the wordmark. "Saaph.in" sat tight
   against it, made worse while the ASCII canvas was overhanging the icon. */
.nav-logo.has-ascii { gap: 13px; }
.nav--lander .nav-logo.has-ascii { gap: 13px; }
@media (max-width: 640px) { .nav-logo.has-ascii { gap: 10px; } }


/* ---- header mark: bigger, and properly spaced --------------------------
   The lander rendered the icon at 36px (main.css .nav--lander .nav-logo-icon),
   which is small for a mark carrying this much detail. Both the <img> and the
   ASCII canvas are sized from this one rule, because the canvas measures the
   image it stands in for. */
.nav--lander .nav-logo-icon { width: 46px; height: 46px; }
@media (max-width: 640px) {
  /* Phones keep the mark at its original 36px. Growing it to 38 with a wider
     gap pushed .nav--lander 3px past the viewport — the nav has no room to
     give at this width, and the mark already reads well here. */
  .nav--lander .nav-logo-icon { width: 36px; height: 36px; }
  /* .nav--lander qualifier is required: the desktop rule below is
     `.nav--lander .nav-logo.has-ascii` (0,3,0) and beats a bare
     `.nav-logo.has-ascii` (0,2,0) even from inside this media query, so the
     mobile gap silently never applied. */
  .nav--lander .nav-logo.has-ascii,
  .nav-logo.has-ascii { gap: 10px; }
}
