/* THE WELCOME PAGE — A DECK WITH A STORY IN IT (Josh, 2026-09-19 late).

   "I like having to scroll in each slide, so each time I tap a slide the new
   slide needs to take up a full page… the hook, then the problem — 'your farm
   data isn't missing, it's disconnected' — with an animation of the tools we
   use scattered all over the place, getting lost… then the solution, a place
   where all this information can live in harmony and never be lost… then how
   we make it all one app, in three simple ways: upload your information, the
   app files it properly, and it presents the information back to you. I want
   all those to be one slide each. And then at the bottom would be the call to
   action."

   Also his: the hook slide carries no body copy and no button (the pitch is
   folded into the three ways), and the invite-only sentence moved off this
   page entirely — it now lives on the log-in screen, which is where someone
   discovers they need it.

   SEVEN SLIDES, each a full page, each snapping into place:
     1 hook · 2 problem · 3 solution + the lead-in · 4 put it in ·
     5 it files it · 6 it gives it back · 7 the ask.

   Colors and faces come from the application's own tokens
   (static/src/styles/tokens.css) so the page and the product read as one. */

:root {
  color-scheme: dark;

  --bg: #0c0c0d;
  --ink: #f5f5f4;
  --ink-soft: rgba(245, 245, 244, 0.74);
  --ink-faint: rgba(245, 245, 244, 0.44);
  --line: rgba(245, 245, 244, 0.14);
  --graphite: #222223;
  --grey-hi: #84888b;
  --leaf: #7fbe58;
  /* the one accent, and it earns its place: it appears only where scattered
     things become connected things (Josh's mock, 2026-09-19) */
  --link: #4ea1ff;

  --serif: "Didot", "Bodoni 72", "Hoefler Text", "Playfair Display", Georgia, "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;

  --shell: min(980px, 86vw);
}

* { box-sizing: border-box; }

/* THE DECK. Mandatory snapping gives the one-slide-at-a-time feel; it is
   switched off where it could trap a reader — a short viewport, or a reader
   who has asked for less motion. */
html {
  scroll-behavior: smooth;
  /* PROXIMITY, not mandatory: the short slides still settle one at a time,
     but the pinned story below runs 320svh and mandatory snapping would
     fight a reader scrubbing through it. */
  scroll-snap-type: y proximity;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
a { color: inherit; }
::selection { background: rgba(245, 245, 244, 0.16); }

.skip {
  position: fixed; left: 16px; top: -80px; z-index: 60;
  padding: 12px 18px; background: var(--ink); color: var(--graphite);
  border-radius: 8px; font-weight: 600; text-decoration: none;
}
.skip:focus { top: 16px; }
:where(a, button):focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; border-radius: 6px; }

.shell { width: var(--shell); margin-inline: auto; position: relative; z-index: 2; }

/* ───────────────────────── the name, always there ───────────────────────── */

.header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 30;
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 26px max(22px, calc((100vw - var(--shell)) / 2));
  pointer-events: none;
}
.header > * { pointer-events: auto; }
.brand {
  font-family: var(--serif); font-size: clamp(25px, 2.8vw, 30px);
  font-weight: 600; letter-spacing: -0.02em; text-decoration: none; line-height: 1;
}
.brand span { color: var(--grey-hi); }
.brand { display: inline-flex; align-items: center; gap: 8px; }
.brand-mark { width: 28px; height: 28px; flex: 0 0 auto; }
.header .enter {
  font-size: 15px; color: var(--ink-soft); text-decoration: none;
  border-bottom: 1px solid transparent; padding-bottom: 2px;
  transition: color .2s, border-color .2s;
}
.header .enter:hover { color: var(--ink); border-bottom-color: var(--line); }

/* ───────────────────────── a slide ───────────────────────── */

.slide {
  position: relative;
  min-height: 100svh;
  scroll-snap-align: start;
  display: grid; place-items: center;
  padding-block: clamp(96px, 14vh, 150px) clamp(88px, 13vh, 130px);
  overflow: hidden;
  text-align: center;
}
.slide canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 0; pointer-events: none;
}
.slide::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(74% 54% at 50% 50%, var(--bg) 26%, rgba(12,12,13,.86) 52%, transparent 88%);
}
/* the close keeps its scrim: the ordered rows behind it are texture, not content */

/* ───────────────────────── THE STORY ─────────────────────────
   One continuous scroll-driven scene, pinned while you scrub through it:
   scattered → wasted → lifted → connected → in order. It replaces what used
   to be two separate slides, because it is one thought.

   Pinning is native `position: sticky` and the scene is a single canvas, so
   there is no third-party animation library and no per-object DOM layout —
   one paint per frame, scroll read only in rAF. */

.story { position: relative; height: 320svh; }
.story-pin {
  position: sticky; top: 0; height: 100svh;
  display: grid; place-items: center; overflow: hidden;
}
.story-pin canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0;
  pointer-events: none;
}
.story-words {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
}
/* the question sits in the middle of the chaos; the answer sits UNDER the
   record it is talking about, so neither is read through the other */
.story-words .words {
  position: absolute; left: 50%; width: var(--shell); text-align: center;
  transform: translate(-50%, -50%);
}
.story-words [data-words="chaos"] { top: 50%; }
/* the answer sits IN FRONT OF the record it is talking about, on the same
   centre line (Josh, 2026-09-19: "in the middle… in front, centered, aligned
   with it. Looks cleaner.") */
.story-words [data-words="order"] { top: 50%; }
.story-words h2 { text-shadow: 0 2px 40px rgba(12, 12, 13, 0.9); }
.story-words .note {
  margin-top: 26px; font-size: 11.5px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-faint); line-height: 1.9;
}
.story-hint {
  position: absolute; left: 50%; bottom: clamp(26px, 4vh, 44px); z-index: 3;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-faint); pointer-events: none;
}
.story-hint i {
  display: block; width: 1px; height: 26px; background: var(--line);
  position: relative; overflow: hidden;
}
.story-hint i::after {
  content: ""; position: absolute; inset: 0; height: 10px; background: var(--ink-faint);
  animation: fall 2.3s cubic-bezier(.65,0,.35,1) infinite;
}

/* Reduced motion gets the end of the story, told plainly: no pin, no scrub,
   both statements stacked, and the scene painted in its ordered state. */
@media (prefers-reduced-motion: reduce) {
  .story { height: auto; }
  .story-pin { position: relative; height: auto; min-height: 100svh; padding-block: 120px; }
  .story-words { position: relative; inset: auto; }
  .story-words .words { position: relative; left: auto; top: auto !important; width: auto; transform: none; opacity: 1 !important; }
  .story-words .words + .words { margin-top: clamp(56px, 9vh, 96px); }
  .story-hint { display: none; }
}

h1, h2 { font-family: var(--serif); font-weight: 600; letter-spacing: -0.022em; text-wrap: balance; margin: 0; }
h1 { font-size: clamp(2.5rem, 7.6vw, 5.1rem); line-height: 1.04; }
h2 { font-size: clamp(2rem, 5.4vw, 3.5rem); line-height: 1.09; }
h1 em, h2 em { font-style: normal; color: var(--grey-hi); display: block; }
p { margin: 0; }
.say {
  margin: 24px auto 0; max-width: 40ch;
  font-size: clamp(1.05rem, 1.9vw, 1.3rem); line-height: 1.5; color: var(--ink-soft);
}
.step {
  display: block; margin-bottom: 20px;
  font-family: var(--serif); font-size: 15px; letter-spacing: 0.06em; color: var(--ink-faint);
}

/* who it is for — slide one only */
.audience { display: flex; gap: 22px; justify-content: center; margin-bottom: 34px; }
.audience a {
  font-size: 14px; color: var(--ink-faint); text-decoration: none;
  padding-bottom: 5px; border-bottom: 1px solid transparent;
  transition: color .2s, border-color .2s;
}
.audience a:hover { color: var(--ink-soft); }
.audience a.on { color: var(--ink); border-bottom-color: var(--ink); }

/* ───────────────────────── advance ───────────────────────── */

.next {
  position: absolute; left: 50%; bottom: clamp(30px, 5vh, 52px); z-index: 4;
  transform: translateX(-50%);
  display: inline-flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 10px 18px; background: none; border: 0; cursor: pointer;
  font-family: var(--sans); font-size: 11.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-faint);
  transition: color .2s;
}
.next:hover { color: var(--ink); }
.next i {
  display: block; width: 1px; height: 30px; background: var(--line); position: relative; overflow: hidden;
}
.next i::after {
  content: ""; position: absolute; inset: 0; height: 11px; background: var(--ink-faint);
  animation: fall 2.3s cubic-bezier(.65,0,.35,1) infinite;
}
@keyframes fall { 0% { transform: translateY(-13px); } 60%, 100% { transform: translateY(32px); } }

/* ───────────────────────── the call to action ───────────────────────── */

.go {
  display: inline-flex; align-items: center; gap: 11px;
  margin-top: 38px; min-height: 54px; padding: 16px 32px;
  background: var(--ink); color: var(--graphite);
  border-radius: 999px; font-size: 16.5px; font-weight: 600; letter-spacing: -0.01em;
  text-decoration: none; transition: transform .22s cubic-bezier(.2,.7,.3,1), background .22s;
}
.go:hover { transform: translateY(-2px); background: #fff; }
.go .arr { transition: transform .22s cubic-bezier(.2,.7,.3,1); }
.go:hover .arr { transform: translateX(4px); }
.signoff {
  display: block; margin-top: 46px;
  font-family: var(--serif); font-size: 15.5px; color: var(--ink-faint);
}
.made { margin-top: 12px; font-size: 13px; color: var(--ink-faint); }

/* ───────────────────────── the drawings ─────────────────────────
   One per way. They loop only while their slide is the one you are on. */

figure.art { margin: clamp(30px, 5vh, 52px) auto 0; width: min(440px, 82vw); }
figure.art svg { display: block; width: 100%; height: auto; overflow: visible; }

/* every piece rests PAINTED; .live starts the loop. A slide that is never
   reached, a full-page capture and a shared link's preview all show the
   finished drawing rather than an empty frame. */
.art .puff, .art .lane-card, .art .recall, .art .wave { will-change: transform, opacity; }

.live .wave { animation: wave 1.25s cubic-bezier(.4,0,.3,1) infinite alternate; transform-origin: center; transform-box: fill-box; }
.live .wave.w2 { animation-delay: .14s; }
.live .wave.w3 { animation-delay: .28s; }
@keyframes wave { from { transform: scaleY(.2); opacity: .45; } to { transform: scaleY(1); opacity: 1; } }

.live .puff { animation: puff 4.4s cubic-bezier(.3,0,.25,1) infinite; }
.live .puff.g2 { animation-delay: 1.45s; }
.live .puff.g3 { animation-delay: 2.9s; }
@keyframes puff {
  0%        { opacity: 0; transform: translateX(0) scale(.86); }
  12%       { opacity: 1; transform: translateX(0) scale(1); }
  62%       { opacity: 1; transform: translateX(150px) scale(1); }
  80%, 100% { opacity: 0; transform: translateX(176px) scale(.94); }
}

.live .lane-card { animation: file 5.4s cubic-bezier(.35,0,.25,1) infinite; }
.live .lane-card.f2 { animation-delay: .62s; }
.live .lane-card.f3 { animation-delay: 1.24s; }
@keyframes file {
  0%        { opacity: 0; transform: translate(0, 0) scale(.88); }
  10%       { opacity: 1; transform: translate(0, 0) scale(1); }
  46%       { opacity: 1; transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(1); }
  58%, 86%  { opacity: .42; transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(.95); }
  96%, 100% { opacity: 0; transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(.95); }
}

.live .recall { animation: recall 4.8s cubic-bezier(.3,0,.25,1) infinite; }
.live .recall.r2 { animation-delay: .3s; }
.live .recall.r3 { animation-delay: .6s; }
.live .recall.r4 { animation-delay: .9s; }
@keyframes recall {
  0%        { opacity: 0; transform: translateY(14px); }
  16%       { opacity: 1; transform: translateY(0); }
  74%       { opacity: 1; transform: translateY(0); }
  90%, 100% { opacity: 0; transform: translateY(-9px); }
}

.live .halo { animation: halo 4.8s ease-out infinite; transform-origin: 180px 176px; transform-box: view-box; }
.live .halo.h2 { animation-delay: .5s; }
.live .halo.h3 { animation-delay: 1s; }
@keyframes halo {
  0%        { opacity: 0; transform: scale(.55); }
  22%       { opacity: .9; }
  70%, 100% { opacity: 0; transform: scale(1.12); }
}

/* ───────────────────────── arrival ─────────────────────────
   The resting state IS the finished state; .seen replays the entrance. */
.rise { opacity: 1; transform: none; }
.rise.seen { animation: rise .9s cubic-bezier(.16, .8, .28, 1) backwards; }
.rise.seen.d2 { animation-delay: .12s; }
.rise.seen.d3 { animation-delay: .24s; }
@keyframes rise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }

/* ───────────────────────── responsive ───────────────────────── */

@media (max-width: 600px) {
  :root { --shell: calc(100vw - 38px); }
  body { font-size: 16px; }
  h1 { font-size: clamp(2.2rem, 10vw, 3.4rem); }
  h2 { font-size: clamp(1.75rem, 8vw, 2.6rem); }
  /* the answer must sit INSIDE the record it is describing, never hang off
     the sides of it (Josh, 2026-09-19) */
  .story-words [data-words="order"] { width: calc(100vw - 64px); }
  .story-words [data-words="order"] h2 { font-size: clamp(1.45rem, 6.6vw, 2.1rem); }
  .story-words [data-words="order"] .note { font-size: 10.5px; letter-spacing: 0.14em; }
  .slide { padding-block: clamp(88px, 13vh, 120px) clamp(84px, 12vh, 110px); }
  figure.art { width: min(320px, 84vw); }
}

/* A viewport too short to hold a slide must never trap the reader. */
@media (max-height: 560px) {
  html { scroll-snap-type: none; }
  .slide { min-height: auto; padding-block: 92px 84px; }
  .next { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; scroll-snap-type: none; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .rise { opacity: 1; transform: none; }
}
