/* Forest Fights — ink on night, blood as the only colour. */

@font-face { font-family: "IM Fell English SC"; src: url("fonts/im-fell-english-sc-400.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Bathory"; src: url("fonts/bathory-regular-demo.otf") format("opentype"); font-display: swap; }

:root {
  --night: #070807;
  --bone: #ece6d8;
  --ink: #0e0e0d;
  --blood: #7e0d09;
  --blood-hi: #a5140f;
  --blood-lo: #560705;
  --letter: "IM Fell English SC", Georgia, serif;
  --gothic: "Bathory", "IM Fell English", Georgia, serif;
  --gutter: clamp(20px, 4vw, 56px);
  --ease: cubic-bezier(.2, .7, .1, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
}

*, *::before, *::after { box-sizing: border-box; }
/* every scroll lands on one whole scene, never half of two */
html { background: var(--night); scroll-behavior: smooth; scroll-snap-type: y mandatory; }
html, body { margin: 0; overflow-x: clip; }
body { color: var(--bone); font: 400 16px/1.5 var(--gothic); -webkit-font-smoothing: antialiased; }
/* No pale box over whatever a finger lands on. Phone browsers paint a highlight on every tap - grey in
   Chrome, near-white in Samsung Internet - which on a page this dark arrives as a flash of light. */
* { -webkit-tap-highlight-color: transparent; }
img, video { display: block; max-width: 100%; height: auto; }
h1, h2 { margin: 0; }
button { font: inherit; }
:focus-visible { outline: 2px solid var(--blood-hi); outline-offset: 6px; }
.defs { position: absolute; width: 0; height: 0; }
[hidden] { display: none !important; }

/* ---------- turning the page on a touch screen (main.js, "turning the page") ----------
   The document does not scroll there at all - <main> is moved instead - so nothing snaps, the address bar of
   a phone never collapses mid-swipe, and the scenes never change size under a finger. While a page turns,
   whatever repaints the whole screen on every frame holds still: the grain, the haze, the moon's breathing. */
.pager, .pager body { height: 100%; overflow: hidden; overscroll-behavior: none; }
/* clip, where a browser knows it: a clipped box is not a scroller at all, so not even focus can scroll it
   (WebKit scrolled <body> itself - not the window - to show a focused button in section II: measured) */
.pager body { overflow: clip; }
.pager { scroll-snap-type: none; scroll-behavior: auto; }
.pager main { will-change: transform; }
.turning body::after, .turning .haze, .turning .moonlight,
.turning .slide img, .turning .slide video { animation-play-state: paused; }   /* the photograph's slow drift: a filtered 2048 px picture re-drawn every frame */

/* film grain over everything */
body::after {
  content: ""; position: fixed; inset: -50%; z-index: 100; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 .55 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: .16; mix-blend-mode: overlay;
  animation: grain 1.2s steps(6) infinite;
}
@keyframes grain {
  0% { transform: translate(0, 0); } 20% { transform: translate(-3%, 2%); }
  40% { transform: translate(2%, -3%); } 60% { transform: translate(-2%, -1%); }
  80% { transform: translate(3%, 3%); } 100% { transform: translate(0, 0); }
}

/* the crest is the logo: the drawing as printed */
.mark { position: fixed; top: 16px; left: 20px; z-index: 60; width: clamp(84px, 9vw, 136px); filter: drop-shadow(0 10px 18px rgba(0,0,0,.6)); }
/* It is the first thing to arrive and the first thing to appear: it fades in once its own image has
   decoded (main.js adds .crest-in on <html>), and the forest starts rising a beat later. Only with
   JavaScript - without it the crest is simply there, like the rest of the page. */
.js .mark { opacity: 0; transition: opacity .6s ease; }
.js.crest-in .mark { opacity: 1; }

/* ---------- night scenes ---------- */
.night {
  position: relative; isolation: isolate;
  overflow: hidden; overflow: clip;   /* clip: focus or scrollIntoView can never shift the scene sideways */
  height: 100vh; height: 100dvh;
  scroll-snap-align: start; scroll-snap-stop: always;
  display: flex; flex-direction: column;
  --fire: 1;
}
.embers { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; opacity: 0; }
.is-lit .embers { opacity: 1; }
.embers--back { z-index: -1; }   /* behind the treeline and the undergrowth, in front of the forest behind them */
/* never over any strip of ground: the rows further back show their ground between the
   trunks, so the embers only come into sight once they've risen clear of the floor */
.embers--back { mask-image: linear-gradient(to top, transparent 0, transparent 10%, #000 19%); }
.embers--front { z-index: 4; }   /* in front of the name; only ever drawn up in the sky, never over trees */
.px { will-change: transform; }

/* a forest layer: a low ridge with trees planted along it. The ridge is drawn
   over the trunks, just enough that every tree stands in the ground. */
.forest { position: absolute; left: -4%; right: -4%; bottom: 0; pointer-events: none; color: var(--ink); }
.forest > div, .forest .trees { position: absolute; inset: 0; }
.forest img { position: absolute; height: auto; max-width: none; user-select: none; }
.forest .hill { position: absolute; left: 0; right: 0; bottom: 0; width: 100%; z-index: 1; }
.forest .hill path { fill: currentColor; }

/* ---------- I. the treeline ---------- */
.sky {
  position: absolute; inset: 0; z-index: -12;
  background:
    radial-gradient(70% 50% at 50% 12%, rgba(236, 230, 216, .06), transparent 70%),
    linear-gradient(#040504 0%, #090b09 45%, #151814 100%);
}
.forest--far  { height: 64%; z-index: -9; opacity: .07; filter: blur(1.4px); color: var(--bone); }
.forest--mid  { height: 74%; z-index: -7; opacity: .13; color: var(--bone); }
/* the distance is in the trees, never in the ground: a faded ridge reads as mist,
   and a trunk going into mist looks like it floats */
.forest--back { height: 82%; z-index: 0; }
.forest--back img { opacity: .82; }
.forest--near { height: 100%; z-index: 2; }

/* a pale light low behind the treeline */
.moonlight {
  position: absolute; left: -10%; right: -10%; bottom: -8%; height: 70%; z-index: -4; pointer-events: none;
  background:
    radial-gradient(45% 55% at 50% 100%, rgba(236, 230, 216, .17), rgba(236, 230, 216, .06) 45%, transparent 72%),
    radial-gradient(80% 40% at 50% 100%, rgba(236, 230, 216, .06), transparent 70%);
  opacity: var(--fire);
  animation: breathe 9s ease-in-out infinite;
}
@keyframes breathe { 50% { scale: 1.04 1.08; } }
.haze { position: absolute; left: -30%; right: -30%; bottom: 0; pointer-events: none; }
.haze--far {
  height: 46%; z-index: -8;
  background: radial-gradient(45% 60% at 28% 85%, rgba(236,230,216,.07), transparent 70%),
              radial-gradient(40% 55% at 74% 90%, rgba(236,230,216,.06), transparent 70%);
  animation: drift 46s ease-in-out infinite alternate;
}
.haze--near {
  height: 34%; z-index: -5;
  background: linear-gradient(transparent, rgba(70, 72, 68, .5) 70%, rgba(90, 92, 86, .6));
  mask: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent);
  animation: drift 60s ease-in-out infinite alternate-reverse;
}
@keyframes drift { to { translate: 9% 0; } }

.stage {
  position: relative; z-index: 3; flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: clamp(24px, 6vh, 72px) var(--gutter) clamp(120px, 20vh, 220px);
}
.glow {
  position: absolute; left: 50%; top: 42%; translate: -50% -50%; z-index: -1; pointer-events: none;
  width: min(1100px, 120vw); aspect-ratio: 2 / 1;
  background: radial-gradient(closest-side, rgba(236, 226, 200, .10), transparent);
}
.title { position: relative; width: min(860px, 88vw, 46vh * 2.09); aspect-ratio: 1603 / 766; }
.wordmark { position: absolute; inset: 0; width: 100%; height: 100%; }
.wordmark--img { display: none; }
.no-gl .wordmark--img { display: block; }
.no-gl canvas.wordmark { display: none; }
.cta { margin-top: clamp(8px, 3vh, 36px); }

/* the button: blood on a hand-cut edge */
.btn {
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 18px 60px 20px;
  color: var(--bone);
  font: 400 clamp(30px, 3vw, 40px)/1 var(--letter); letter-spacing: .09em; text-decoration: none; white-space: nowrap;
}
.btn span { display: block; text-shadow: 0 2px 0 rgba(0,0,0,.45); }
.btn__bg {
  position: absolute; inset: 0; z-index: -1; overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.10), transparent 60%),
    linear-gradient(175deg, var(--blood-hi), var(--blood) 55%, var(--blood-lo));
  box-shadow: 0 0 0 2px var(--ink) inset, 0 18px 40px -14px rgba(120, 14, 10, .8);
  filter: url(#rough-soft);
}
.btn__bg::after {
  content: ""; position: absolute; inset: 0; background: var(--ink);
  clip-path: circle(0% at var(--mx, 50%) var(--my, 50%));
  transition: clip-path .7s var(--ease);
}
.btn:hover .btn__bg::after { clip-path: circle(150% at var(--mx, 50%) var(--my, 50%)); }

/* ---------- II. through the trees ---------- */
.through { background: #030303; }
.view { position: absolute; inset: 0; z-index: -1; }
.view__slides { position: absolute; inset: 0; }
.slide { position: absolute; inset: 0; opacity: 0; transition: opacity 1.6s ease; }
.slide img, .slide video {
  width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(1) contrast(1.08) brightness(.9);
  transform: scale(1);
}
.slide.is-on { opacity: 1; }
.slide.is-on img, .slide.is-on video { animation: drift-in 9s var(--ease-out) forwards; }
@keyframes drift-in { from { transform: scale(1.08) translate(1%, 1%); } to { transform: scale(1) translate(0, 0); } }
.slide.is-loud video { filter: none; }
/* the dark closes in from every side, so the picture is seen through an opening */
.view__shade {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(#030303, transparent 22%),
    linear-gradient(transparent 55%, #030303),
    radial-gradient(70% 70% at 50% 50%, transparent 45%, rgba(3,3,3,.85));
}
.view__half { position: absolute; top: 0; bottom: 0; width: 50%; border: 0; background: none; padding: 0; z-index: 2; }
.view__half--prev { left: 0; cursor: w-resize; }
.view__half--next { right: 0; cursor: e-resize; }
.play {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 3;
  width: clamp(72px, 8vw, 110px); aspect-ratio: 1; padding: 0; border: 0; background: none; cursor: pointer; color: var(--bone);
  transition: opacity .6s;
}
.play svg { width: 100%; height: 100%; filter: url(#rough-soft); }
.play circle { fill: rgba(14,14,13,.5); stroke: currentColor; stroke-width: 1.6; }
.play path { fill: var(--blood-hi); transform-origin: 34px 32px; transition: transform .6s var(--ease-out); }
.play:hover path { transform: scale(1.25); }
.play[hidden] { display: none; }
.through .flank { position: absolute; bottom: 0; z-index: 2; height: 118%; width: auto; max-width: none; pointer-events: none; }
.through .flank--l { left: -12%; }
.through .flank--r { right: -8%; scale: -1 1; }
.forest--frame { height: 46%; z-index: 3; }
/* the pictures, small, along the ridge */
.thumbs {
  position: absolute; left: 0; right: 0; bottom: clamp(18px, 3vh, 34px); z-index: 4;
  display: flex; justify-content: center; gap: 10px; padding: 0 var(--gutter);
}
.thumb {
  width: clamp(44px, 5vw, 72px); aspect-ratio: 4 / 3; padding: 0; border: 0; cursor: pointer; overflow: hidden;
  background: #111; box-shadow: 0 0 0 1.5px var(--bone-faint, rgba(236,230,216,.35)); opacity: .5;
  transition: opacity .5s, box-shadow .5s, scale .5s var(--ease-out);
}
.thumb img, .thumb video { width: 100%; height: 100%; object-fit: cover; filter: grayscale(1); }
.thumb.is-on { opacity: 1; box-shadow: 0 0 0 2px var(--blood-hi); scale: 1.08; }
.thumb:hover { opacity: .9; }

/* ---------- entrance ---------- */
.js .hero .sky, .js .hero .moonlight, .js .hero .haze { opacity: 0; transition: opacity 2.8s ease; }
.js .hero .moonlight { transition-delay: 1s; }
/* The fades are short on purpose (Andrej, 18 Sept: "everything must be green" -> "shorter fades"): Chrome
   counts a picture that fades in from opacity 0 only once its fade has FINISHED (measured), so the time the
   trees and the name spend half-transparent is the page's measured speed. The motion - the slow rise, the
   delays between layers, the sweep across the name - is unchanged; only the fades were 1.8 s and 1.2 s. */
.js .rise { opacity: 0; translate: 0 22%; transition: translate 2.6s var(--ease-out), opacity .8s ease; }
.js [data-forest="mid"] { transition-delay: .25s; }
.js [data-forest="deep"] { transition-delay: .32s; }
.js [data-forest="thick"] { transition-delay: .39s; }
.js [data-forest="back"] { transition-delay: .45s; }
.js [data-forest="near"] { transition-delay: .65s; }
.js .title {
  mask-image: linear-gradient(#000 40%, transparent 60%);
  mask-size: 100% 250%; mask-repeat: no-repeat; mask-position: 0 100%;
  opacity: 0; scale: 1.05;
  transition: mask-position 2.8s var(--ease) .9s, opacity .6s ease .9s, scale 3.2s var(--ease-out) .9s;
}
.js .glow { opacity: 0; transition: opacity 3s ease 1.6s; }
.js .cta { opacity: 0; translate: 0 18px; transition: opacity 1.4s ease 2.6s, translate 1.6s var(--ease-out) 2.6s; }
.is-ready .hero .sky, .is-ready .hero .haze, .is-ready .rise, .is-ready .title, .is-ready .glow, .is-ready .cta { opacity: 1; }
.is-ready .hero .moonlight { opacity: var(--fire); }
.is-ready .rise { translate: 0 0; }
.is-ready .title { mask-position: 0 0; scale: 1; }
.is-revealed .title { mask-image: none; }
.is-ready .cta { translate: 0 0; }

/* ---------- into the forest ----------
   One forest, not two scenes. Every layer stands at its own distance; Sign Up
   moves the camera forward into it (see WORLD in main.js): the undergrowth and
   the treeline rush past and are gone, the forest that was behind them in the
   mist comes close and dark, the far forest hardly moves, and the form is
   standing among the trees. Leaving walks the camera back out. */
.btn { border: 0; background: none; cursor: pointer; }
.forest--deep  { height: 68%; z-index: -4; }
/* deeper in, pale light between the trees: without it black trees vanish into the
   black sky above the horizon glow, and so does the walk. Off in the hero; main.js
   raises it with every step in. */
.deeplight { position: absolute; inset: 0; z-index: -11; pointer-events: none; opacity: 0;
  background:
    radial-gradient(60% 55% at 50% 42%, rgba(236, 230, 216, .13), transparent 72%),
    radial-gradient(90% 70% at 50% 60%, rgba(150, 152, 144, .10), transparent 80%); }
.forest--thick { height: 76%; z-index: -2; }

.struck, .struck body, .in-forest, .in-forest body { overflow: hidden; }
/* the blows: blood on the name, and the scene flinches */
.blood { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; transition: opacity .6s ease; }
.in-forest .blood { opacity: 0; scale: 1.25; transition: opacity 1.1s ease .15s, scale 2s var(--ease); }
.hurt { position: absolute; inset: 0; z-index: 11; pointer-events: none; opacity: 0;
  background: radial-gradient(75% 75% at 50% 50%, transparent 50%, rgba(70, 0, 2, .75)); }
.in-forest .title { opacity: 0; scale: 1.25; transition: opacity .8s ease, scale 2s var(--ease); }
.struck .cta { opacity: 0; transition: opacity .35s ease; }
.in-forest .glow { opacity: 0; transition: opacity .5s ease; }
.in-forest .embers { opacity: .55; }
/* fog settles between the trunks, so every tree in the thicket stands apart */
.hero .fog { position: absolute; left: -10%; right: -10%; bottom: 0; height: 62%; z-index: -3; pointer-events: none;
  background: radial-gradient(60% 70% at 50% 100%, rgba(150, 152, 144, .26), rgba(120, 122, 116, .1) 55%, transparent 80%);
  /* it hangs between the trunks but lifts off the ground, so every strip of
     ground stays dark and every trunk is seen going into it */
  mask-image: linear-gradient(to top, transparent 0, transparent 24%, #000 48%);
  opacity: 0; transition: opacity 2.4s ease; }
.in-forest .hero .fog { opacity: 1; transition: opacity 3s ease .8s; }
.embers { transition: opacity 3s ease; }

.enter {
  position: absolute; inset: 0; z-index: 12;
  display: grid; place-items: center; padding: 96px var(--gutter) 48px;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .5s ease, visibility 0s linear .5s;
}
/* a darker pocket among the trees, so the words read */
.enter::before {
  content: ""; position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: -1;
  width: min(720px, 130vw); aspect-ratio: 1; pointer-events: none;
  background: radial-gradient(closest-side, rgba(4, 5, 4, .78) 35%, rgba(4, 5, 4, .35) 70%, transparent);
}
.in-forest .enter { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity 1.4s ease 2.5s, visibility 0s linear 2.5s; }
.enter__form {
  width: min(480px, 100%);
  display: flex; flex-direction: column; gap: clamp(14px, 2.6vh, 26px);
  translate: 0 18px; transition: translate 1.8s var(--ease-out) 2.5s;
}
.in-forest .enter__form { translate: 0 0; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field span { font: 400 clamp(24px, 2.4vw, 30px)/1.1 var(--letter); letter-spacing: .06em; color: var(--bone); }
.field input {
  width: 100%; padding: 8px 2px 10px; border: 0; border-radius: 0;
  border-bottom: 2px solid rgba(236, 230, 216, .45); background: transparent;
  color: var(--bone); font: 400 22px/1.3 Georgia, "Times New Roman", serif; caret-color: var(--blood-hi);
  transition: border-color .4s;
}
.field input:focus { outline: none; border-bottom-color: var(--blood-hi); }
/* A browser filling a field in paints its own pale wash over it (yellow once, white or blue now,
   depending on the browser). The endless transition below was the old guard against it and is not
   enough on its own, because some versions paint it as a background image instead: the inset shadow
   covers the field in the page's own night, whatever the browser tries. */
.field input:-webkit-autofill,
.field input:-webkit-autofill:hover,
.field input:-webkit-autofill:focus,
.field input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--bone);
  -webkit-box-shadow: 0 0 0 40px var(--night) inset;
  caret-color: var(--blood-hi);
  transition: background-color 9999s;
}
.field.is-wrong input { border-bottom-color: var(--blood-hi); }
.field.is-wrong span { color: #d9443c; }
.honey { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.btn--send { align-self: center; margin-top: clamp(6px, 2vh, 18px); }
.btn--send[disabled] { opacity: .5; cursor: progress; }
.enter__said {
  margin: 0; text-align: center;
  /* One row, always (Andrej, 18 Sept: "It must not be two rows ... a single row"). The line is 7.63 em wide
     in Bathory (794 px at 104 px, measured), so 11.2vw is the largest size at which it still fits between
     the 20 px margins of the narrowest phone; nowrap makes it a rule rather than a hope. */
  font: 400 min(clamp(48px, 7vw, 104px), 11.2vw)/.95 var(--gothic); color: var(--bone); white-space: nowrap;
  /* No glow here (it had a 60 px one): the sweep below is a mask, a mask cuts everything at its box, and
     the glow ended in straight-edged bands behind the letters - "the block behind the text" (Andrej,
     18 Sept, measured by brightening a screenshot). Only the hard drop under each letter stays. */
  text-shadow: 0 4px 0 rgba(0,0,0,.5);
}
/* The words themselves. The box is grown past the line box (and pulled back by the same margin) so the
   mask never shaves a letter: Bathory's capitals rise above the line and were cut flat at the top. */
.enter__line { display: block; padding: .3em .2em; margin: -.3em -.2em; }
.enter__said:focus { outline: none; }

/* ---------- signed up ----------
   Andrej, 18 Sept: "make the transition cool ... feel like they accomplished something". The fields drift
   up and dissolve one after another; then the line comes in the way the name does - drawn across like ink,
   out of a blur, its letters settling - and a stroke of blood is drawn under it while the fire flares
   (main.js). Blood red is still the only colour. */
.enter__form.is-leaving .field,
.enter__form.is-leaving .btn--send {
  opacity: 0; translate: 0 -12px; filter: blur(4px);
  transition: opacity .42s ease, translate .5s var(--ease-out), filter .42s ease;
}
.enter__form.is-leaving .field:nth-child(2) { transition-delay: .06s; }
.enter__form.is-leaving .field:nth-child(3) { transition-delay: .12s; }
.enter__form.is-leaving .field:nth-child(4) { transition-delay: .18s; }
.enter__form.is-leaving .btn--send { transition-delay: .24s; }
.enter__said.is-arriving .enter__line {
  mask-image: linear-gradient(90deg, #000 42%, transparent 58%);
  mask-size: 260% 100%; mask-repeat: no-repeat;
  animation: said-in 1.9s var(--ease-out) both;
}
/* Only things that never move the words: the sweep, the blur, the fade and a slight settle. The letters used
   to start spaced out and close up, and spaced out the line was too wide for one row - it wrapped to two and
   snapped back to one (Andrej saw it, 18 Sept). */
@keyframes said-in {
  0%   { mask-position: 100% 0; opacity: 0; filter: blur(9px); scale: 1.05; }
  35%  { opacity: 1; }
  100% { mask-position: 0 0; opacity: 1; filter: blur(0); scale: 1; }
}
/* the dark pocket that keeps the fields readable goes once they have: behind the line, only the forest */
.enter::before { transition: opacity .9s ease; }
.enter.is-done::before { opacity: 0; }
/* The line under it is a cut (Andrej, 18 Sept: "like a cut ... a slash. And then it bleeds out a little
   bit"): a blade-thin wound, sharp at both ends, struck across in a quarter of a second; then it opens,
   a darker seep gathers under it and four runs of blood creep down, slower and slower. The resting state
   is the finished wound, and the animations run backwards from it - so with reduced motion it is simply
   there. It sits outside the words' mask, so nothing of it is ever cut off. */
/* the real cut: the hero's liquid blood on its own strip of canvas, as wide as the line. main.js switches
   it on (.has-gl) when WebGL is there and motion is allowed; otherwise the drawn one below stands in. */
.cut-gl { display: none; width: 100%; height: clamp(96px, 1.7em, 180px); margin: .02em 0 0; pointer-events: none; }
.has-gl .cut-gl { display: block; }
.has-gl .cut { display: none; }
.cut { display: block; width: min(78%, 460px); height: auto; margin: .2em auto 0; overflow: visible; }
.cut__blade, .cut__seep { filter: url(#rough-soft); transform-box: fill-box; }
.cut__blade { fill: var(--blood-hi); transform-origin: 50% 50%; }
.cut__seep { fill: var(--blood-lo); transform-origin: 50% 0; }
.cut__drip { fill: none; stroke: var(--blood); stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
.cut__drip--1 { stroke-width: 3.2; } .cut__drip--2 { stroke-width: 4; }
.cut__drip--3 { stroke-width: 2.6; } .cut__drip--4 { stroke-width: 3.4; }
.is-arriving .cut { animation: cut-slash .24s cubic-bezier(.6, 0, .15, 1) .85s both; }
.is-arriving .cut__blade { animation: cut-open .8s var(--ease-out) 1.05s both; }
.is-arriving .cut__seep { animation: cut-seep 2.4s ease-out 1.1s both; }
.is-arriving .cut__drip { animation: cut-drip 3s cubic-bezier(.2, .6, .25, 1) 1.3s both; }
.is-arriving .cut__drip--2 { animation-duration: 4.2s; animation-delay: 1.15s; }
.is-arriving .cut__drip--3 { animation-duration: 2.2s; animation-delay: 1.75s; }
.is-arriving .cut__drip--4 { animation-duration: 3.4s; animation-delay: 1.45s; }
@keyframes cut-slash { from { clip-path: inset(-30% 105% -30% -5%); } to { clip-path: inset(-30% -5% -30% -5%); } }
@keyframes cut-open { from { transform: scaleY(.3); } }
@keyframes cut-seep { from { opacity: 0; transform: scaleY(.15); } }
@keyframes cut-drip { 0% { stroke-dashoffset: 1; opacity: 0; } 2% { opacity: 1; } 100% { stroke-dashoffset: 0; opacity: 1; } }
.enter__close {
  position: absolute; top: 22px; right: 22px; z-index: 2;
  width: 52px; height: 52px; padding: 10px; border: 0; background: none; cursor: pointer; color: var(--bone);
  opacity: .7; transition: opacity .4s, rotate .6s var(--ease-out);
}
.enter__close:hover { opacity: 1; rotate: 90deg; }
.enter__close svg { width: 100%; height: 100%; overflow: visible; }
.enter__close path { filter: url(#rough-mark); }
.enter__close path { fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; }

/* ---------- small screens ---------- */
@media (max-width: 900px) {
  .mark { top: 12px; left: 14px; }
  .stage { padding-bottom: clamp(100px, 18vh, 160px); }
  /* The name's box is centred, but its ink is not centred in the box: the heavy letters start at the left
     edge and the right ends in thin wisps off the S, so the weight of it sits 3.1 % of its width left of the
     middle (measured two ways on wordmark.png: centre of mass -3.16 %, middle of the body -3.06 %). On a
     phone, where the name nearly fills the screen, that reads as off-centre (Andrej, 18 Sept) - so it is
     moved right by exactly that. */
  .title { width: min(600px, 90vw); left: calc(min(600px, 90vw) * .031); }
  .btn { padding: 14px 44px 16px; font-size: 28px; }
  .forest--far { height: 30%; }
  .forest--mid { height: 36%; }
  .forest--back { height: 40%; }
  .forest--near { height: 46%; }
  .moonlight { height: 45%; }
  .haze--near { height: 24%; }
  .mark { width: 80px; }
  .forest--deep { height: 50%; }
  .forest--thick { height: 60%; }
  .field span { font-size: 24px; }
  .through .flank { height: 70%; }
  .through .flank--l { left: -40%; } .through .flank--r { right: -40%; }
  .forest--frame { height: 30%; }
  .thumbs { gap: 6px; }
  .thumb { width: 40px; }
}

/* ---------- the form on a phone ----------
   Andrej, 18 Sept: smaller, and easy and smooth to type in on any phone. Measured before this: the form
   stood 457-489 px tall, and with the keyboard open the last field was hidden under it on every phone
   tried (iPhone SE/15/15 Pro Max, Galaxy S8, Pixel 8) - the page is held still while the form is open,
   so the browser could not scroll it into view. Now the dialog is its own scroller, exactly as tall as
   what is visible above the keyboard (--vv-height/--vv-top, set by main.js from visualViewport): the
   field being typed in is brought into view there, and the form can also be swiped. The form sits high,
   under the crest, so the first fields are clear of any keyboard. Inputs stay at 17 px - iPhones zoom the
   page into any field under 16 px - and every field and the button are at least 44 px tall to hit. */
@media (pointer: coarse) and (max-width: 600px), (pointer: coarse) and (max-height: 560px) {
  .enter {
    display: flex; flex-direction: column; padding: 0 20px;
    top: var(--vv-top, 0px); bottom: auto; height: var(--vv-height, 100%);
    overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none;
  }
  .enter::-webkit-scrollbar { display: none; }
  /* The dark pocket behind the fields, kept inside the screen's width: as a 130vw circle it stuck 59 px out
     to the right of this scroller, where a browser bringing something into view could shift the whole form
     sideways (measured). Same gradient and size, cut at the screen's edges, which are the screen's anyway. */
  .enter::before {
    left: 0; right: 0; width: auto; height: 130vw; aspect-ratio: auto; translate: 0 -50%;
    background: radial-gradient(circle 65vw at 50% 50%, rgba(4, 5, 4, .78) 35%, rgba(4, 5, 4, .35) 70%, transparent);
  }
  .enter__form { width: min(360px, 100%); margin: 0 auto auto; gap: 10px; padding: clamp(100px, 16svh, 148px) 0 28px; }
  .enter__said { margin: auto; padding: 24px 0; }
  .field { gap: 2px; }
  .field span { font-size: 19px; letter-spacing: .05em; }
  .field input { min-height: 44px; padding: 9px 2px 10px; font-size: 17px; }
  .btn--send { margin-top: 8px; min-height: 46px; padding: 10px 36px 12px; font-size: 22px; }
  /* while typing, the crest steps back: the form may pass under it when it scrolls
     (as specific as .js.crest-in .mark, which would otherwise win) */
  .js.crest-in.typing .mark { opacity: 0; }
}
/* a phone on its side: little height, so the form starts at the top (the crest is well to its left) */
@media (pointer: coarse) and (max-height: 560px) and (min-width: 601px) {
  .enter__form { padding-top: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
  .js .hero .sky, .js .hero .haze, .js .hero .moonlight, .js .rise, .js .title, .js .glow, .js .cta { opacity: 1; translate: none; scale: none; }
  .js .title { mask-image: none; }
  /* still leave the name and the button behind when walking in */
  .js.struck .cta, .js.in-forest .title, .js.in-forest .glow { opacity: 0; }
}
