/* The fonts are linked from index.html, not @import-ed here: an @import is only
   discovered once this file has been parsed, which puts the font request a full
   round trip further down the critical path, and first paint waits on it. */

/* ============================================================
   Tokens
   ============================================================ */

:root {
  /* Surfaces — true black, with a neutral grey for anything that has to lift off
     it. No blue or indigo bias anywhere: the planets carry the colour. */
  --ink: #000000;
  --ink-raised: #101010;
  --ink-line: rgb(236 234 245 / 0.10);

  /* Text */
  --paper: #eceaf5;
  --muted: #8b88a6;
  --faint: rgb(236 234 245 / 0.16);

  /* Accent — periwinkle violet. Sits opposite the warm planets, so they read as
     the focal points rather than competing with the chrome. */
  --accent: #a78bfa;
  --accent-dim: rgb(167 139 250 / 0.28);
  --warning: #fb7185;

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 180ms;
  --dur-mid: 320ms;
  --dur-slow: 900ms;

  /* Spacing rhythm */
  --gutter: clamp(1.5rem, 6vw, 9rem);

  /* Scene (written by app.js) */
  --scene-progress: 0;
  --scene-focus: 0;
  --parallax-x: 0px;
  --parallax-y: 0px;
}

* {
  box-sizing: border-box;
}

html {
  background: var(--ink);
  color: var(--paper);
  scroll-behavior: smooth;
}

body {
  min-width: 320px;
  margin: 0;
  overflow-x: clip;
  background: var(--ink);
  color: var(--paper);
  font-family: 'DM Sans', system-ui, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

button,
input {
  font: inherit;
}

button {
  color: inherit;
}

img {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
p,
figure,
dl,
dd {
  margin: 0;
}

h1,
h2 {
  font-family: 'Bodoni Moda', Georgia, serif;
  font-weight: 400;
  letter-spacing: -0.055em;
}

::selection {
  background: var(--accent);
  color: var(--ink);
}

:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 6px;
  border-radius: 2px;
}

.skip-link {
  position: fixed;
  top: 1rem;
  left: 1rem;
  z-index: 100;
  padding: 0.7rem 1.1rem;
  border: 1px solid var(--accent);
  background: var(--ink);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: translateY(-200%);
  transition: transform var(--dur-mid) var(--ease-out);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* ============================================================
   Entry veil — the first thing the eye sees
   ============================================================ */

.page-veil {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--ink);
  pointer-events: none;
  animation: veil-lift 1200ms var(--ease-out) 120ms forwards;
}

@keyframes veil-lift {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

/* ============================================================
   Reveal system — driven by IntersectionObserver in app.js
   ============================================================ */

[data-reveal] {
  --reveal-delay: calc(var(--reveal-step, 0) * 85ms);
}

[data-reveal]:not([data-reveal='line']):not([data-reveal='portrait']):not([data-reveal='book']) {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 800ms var(--ease-out) var(--reveal-delay),
    transform 800ms var(--ease-out) var(--reveal-delay);
}

/* Masked line reveal for display type.
   The wrapper is observed, not the inner span: the inner starts clipped
   entirely outside the mask, so it would never report as intersecting. */
.line {
  display: block;
  overflow: hidden;
  /* Descenders (g, y) would otherwise be shaved off by the mask */
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}

.line__inner {
  display: block;
  transform: translateY(105%);
  transition: transform 1050ms var(--ease-out) var(--reveal-delay);
  will-change: transform;
}

[data-reveal='line'].is-revealed .line__inner {
  transform: none;
}

[data-reveal='portrait'] .intro__portrait {
  transform: scale(1.16);
  transition: transform 1600ms var(--ease-out) 100ms, filter 1600ms var(--ease-out) 100ms;
}

[data-reveal='book'] .book__art {
  opacity: 0;
  transform: perspective(1400px) rotateY(-22deg) rotateX(6deg) translateY(40px);
  transition:
    opacity 1100ms var(--ease-out),
    transform 1400ms var(--ease-out);
}

/* Revealed state */
[data-reveal].is-revealed:not([data-reveal='line']):not([data-reveal='portrait']):not([data-reveal='book']) {
  opacity: 1;
  transform: none;
}

[data-reveal='portrait'].is-revealed .intro__portrait {
  transform: scale(1);
}

[data-reveal='book'].is-revealed .book__art {
  opacity: 1;
  transform: perspective(1400px) rotateY(-13deg) rotateX(4deg) translateY(0);
}

/* ============================================================
   Nav
   ============================================================ */

.site-nav {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 60;
  display: flex;
  padding: 1.5rem var(--gutter);
  align-items: center;
  justify-content: space-between;
  mix-blend-mode: difference;
  opacity: 0;
  animation: nav-in 1000ms var(--ease-out) 900ms forwards;
  pointer-events: none;
}

.site-nav > * {
  pointer-events: auto;
}

@keyframes nav-in {
  from {
    opacity: 0;
    transform: translateY(-14px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.site-nav__mark {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
}

.site-nav__glyph {
  color: var(--accent);
  font-size: 0.85rem;
  animation: twinkle 4.5s var(--ease-in-out) infinite;
}

@keyframes twinkle {
  0%, 100% { opacity: 0.55; transform: rotate(0deg); }
  50% { opacity: 1; transform: rotate(90deg); }
}

.site-nav__links {
  display: flex;
  gap: clamp(1.2rem, 3vw, 2.6rem);
}

.site-nav__links a {
  position: relative;
  padding-bottom: 0.25rem;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.6;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.site-nav__links a::after {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  content: '';
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-mid) var(--ease-out);
}

.site-nav__links a:hover {
  opacity: 1;
}

.site-nav__links a:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* ============================================================
   Shared bits
   ============================================================ */

.eyebrow {
  color: var(--muted);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  line-height: 1.4;
  text-transform: uppercase;
}

/* ============================================================
   Intro
   ============================================================ */

.intro {
  position: relative;
  display: grid;
  grid-template-columns: minmax(310px, 42vw) minmax(0, 1fr);
  min-height: 100svh;
  /* Top-align so the portrait column can pin (sticky) while the bio scrolls past */
  align-items: start;
  /* Contains the oversized zodiac wheel so it never bleeds into neighbouring sections */
  overflow: clip;
}

/* Fades the whole bottom edge of the bio into pure black, so scrolling on into the
   black orbit scene reads as one continuous space rather than two stacked pages. */
.intro::after {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  height: clamp(90px, 16vh, 200px);
  background: linear-gradient(to bottom, transparent, var(--ink));
  content: '';
  pointer-events: none;
}

/* Rotating zodiac wheel — a slow, constant background motion in the bio, echoing
   the spinning wheel on the reference site. Sits behind the copy and portrait. */
.intro__zodiac {
  position: absolute;
  /* Anchored to the first screen (viewport units) so it stays behind the hero
     even though the section is now tall enough to scroll */
  top: 46svh;
  left: 42vw;
  z-index: 0;
  width: min(80vw, 840px);
  aspect-ratio: 1;
  color: var(--accent);
  opacity: 0.1;
  transform: translate(-42%, -50%);
  pointer-events: none;
}

.intro__zodiac-wheel {
  width: 100%;
  height: 100%;
  transform-origin: 50% 50%;
  animation: zodiac-spin 150s linear infinite;
}

.intro__zodiac-glyphs text {
  /* Counter-nothing: glyphs ride the wheel so they orbit with it */
  opacity: 0.85;
}

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

/* Copy and portrait must sit above the wheel */
.intro__copy,
.intro__portrait-wrap {
  position: relative;
  z-index: 1;
}

.intro__portrait-wrap {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100svh;
  overflow: hidden;
  background: #101010;
}

.intro__portrait {
  width: 100%;
  height: 100%;
  min-height: 100svh;
  object-fit: cover;
  /* Frames the face/torso of the studio portrait rather than the river-selfie crop */
  object-position: center 34%;
  /* Kept in colour (like the reference bio), with a touch of contrast so the warm
     studio tones sit calmly against the black theme rather than glaring off it. */
  filter: saturate(1.02) contrast(1.04) brightness(0.94);
  will-change: transform;
}

/* Vignette + warm floor so the portrait sits in the dark rather than on it */
.intro__portrait-veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 80% at 50% 40%, transparent 40%, rgb(0 0 0 / 0.55) 100%),
    linear-gradient(to right, transparent 60%, rgb(0 0 0 / 0.9) 100%),
    linear-gradient(to top, rgb(0 0 0 / 1) 2%, rgb(0 0 0 / 0.6) 15%, transparent 46%);
  pointer-events: none;
}

.intro__portrait-wrap::after {
  position: absolute;
  inset: 0;
  border-right: 1px solid var(--ink-line);
  content: '';
  pointer-events: none;
}

.intro__image-note {
  position: absolute;
  right: 1.25rem;
  bottom: 1.1rem;
  color: rgb(236 234 245 / 0.55);
  font-size: 0.61rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
}

.intro__copy {
  display: flex;
  min-width: 0;
  min-height: 100svh;
  padding: clamp(5rem, 10vw, 11rem) var(--gutter) clamp(4rem, 8vw, 9rem);
  flex-direction: column;
  align-items: flex-start;
  /* Top-aligned now that the full bio lives here and the column scrolls */
  justify-content: flex-start;
}

.intro__title {
  max-width: 800px;
  margin-top: clamp(1.4rem, 3vw, 2.6rem);
  font-size: clamp(3.2rem, 6.4vw, 7rem);
  line-height: 0.9;
}

/* Full bio, in the hero copy column */
.intro__bio {
  max-width: 34rem;
  margin-top: clamp(1.6rem, 3vw, 2.6rem);
}

.intro__bio > * + * {
  margin-top: clamp(1.05rem, 1.9vw, 1.5rem);
}

.intro__bio p {
  color: var(--muted);
  font-size: clamp(0.95rem, 1.02vw, 1.04rem);
  line-height: 1.8;
}

.intro__lede {
  margin-top: 0;
  color: var(--paper);
  font-size: clamp(1.05rem, 1.3vw, 1.28rem);
  line-height: 1.7;
}

.intro__facts {
  display: flex;
  margin-top: clamp(2rem, 4vw, 3.4rem);
  flex-wrap: wrap;
  gap: clamp(1.5rem, 3.5vw, 3.5rem);
}

.intro__facts dt {
  color: var(--muted);
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.intro__facts dd {
  margin-top: 0.45rem;
  font-size: 0.86rem;
  letter-spacing: 0.01em;
}

.intro__cue {
  display: flex;
  margin-top: clamp(2.4rem, 5vw, 5rem);
  align-items: center;
  gap: 0.9rem;
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.intro__cue-line {
  width: 3rem;
  height: 1px;
  background: var(--faint);
  transition: width var(--dur-mid) var(--ease-out), background var(--dur-mid) var(--ease-out);
}

.intro__cue:hover .intro__cue-line {
  width: 4.5rem;
  background: var(--accent);
}

.intro__cue-arrow {
  color: var(--accent);
  animation: cue-bob 2.4s var(--ease-in-out) infinite;
}

@keyframes cue-bob {
  0%, 100% { transform: translateY(0); opacity: 0.7; }
  50% { transform: translateY(5px); opacity: 1; }
}

/* ============================================================
   Bio content marks — used inside the hero copy
   ============================================================ */

/* Key phrases lifted out of the muted body copy */
.bio-hl {
  color: var(--paper);
  font-weight: 500;
}

/* The book — the single link in the bio, in accent with an underline that warms
   and an arrow that lifts on hover */
.bio-book {
  color: var(--accent);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: var(--accent-dim);
  text-underline-offset: 4px;
  transition: text-decoration-color var(--dur-mid) var(--ease-out);
}

.bio-book:hover {
  text-decoration-color: var(--accent);
}

.bio-book span {
  display: inline-block;
  margin-left: 0.25em;
  font-size: 0.85em;
  transition: transform var(--dur-mid) var(--ease-out);
}

.bio-book:hover span {
  transform: translate(2px, -2px);
}

/* Pull-quote inside the bio */
.bio-quote {
  margin: clamp(1.8rem, 3.5vw, 2.8rem) 0;
  padding-left: clamp(1rem, 1.8vw, 1.6rem);
  border-left: 2px solid var(--accent);
}

.bio-quote p {
  color: var(--paper);
  font-family: 'Bodoni Moda', Georgia, serif;
  font-size: clamp(1.4rem, 2.4vw, 2rem);
  font-style: italic;
  line-height: 1.3;
  letter-spacing: -0.02em;
}

/* ============================================================
   The orbit — centrepiece
   ============================================================ */

.journey {
  position: relative;
  height: 1000vh;
  background: var(--ink);
}

/* Blend the orbit scene into the sections above and below it. These veils sit at
   the very top and bottom of the (very tall) journey block, so they only appear
   right at the joins: the scene emerges from black as you arrive from the bio,
   and dissolves back to black just before the book. No hard page-like edge. */
.journey::before,
.journey::after {
  position: absolute;
  right: 0;
  left: 0;
  z-index: 8;
  height: 38vh;
  content: '';
  pointer-events: none;
}

.journey::before {
  top: 0;
  background: linear-gradient(to bottom, var(--ink) 8%, transparent);
}

.journey::after {
  bottom: 0;
  background: linear-gradient(to top, var(--ink) 8%, transparent);
}

.journey__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  isolation: isolate;
}

#scene,
.journey__nebula,
.journey__grain {
  position: absolute;
  inset: 0;
}

/* The void behind the system. It is only ever seen if WebGL fails, since the
   canvas above it is opaque — so it is plain black, like everything else. */
.journey__nebula {
  z-index: 0;
  background: var(--ink);
  pointer-events: none;
}

/* The WebGL scene: planets, stars and the portrait all live in here, so depth
   sorting between them is real rather than faked with z-index. */
#scene {
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
}

.journey__grain {
  z-index: 2;
  opacity: 0.18;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 160 160' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.18'/%3E%3C/svg%3E");
  pointer-events: none;
}

/* Scrim so drifting planets never fight the copy for legibility */
.journey__sticky::after {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 5;
  width: min(42rem, 55%);
  background: linear-gradient(to right, rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.5) 45%, transparent 100%);
  content: '';
  pointer-events: none;
}

/* Copy panel */
.planet-copy {
  position: absolute;
  top: 50%;
  left: var(--gutter);
  z-index: 6;
  max-width: min(23rem, 32vw);
  transform: translateY(-50%);
  pointer-events: none;
}

.planet-copy__index {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--accent);
}

.planet-copy__rule {
  width: 2rem;
  height: 1px;
  background: var(--accent-dim);
}

.planet-copy__name {
  margin-top: 0.7rem;
  font-size: clamp(3.4rem, 7vw, 7.5rem);
  line-height: 0.9;
}

.planet-copy__brief {
  max-width: 20rem;
  margin-top: clamp(1.2rem, 2vw, 2rem);
  color: var(--muted);
  font-size: clamp(0.9rem, 1.05vw, 1.02rem);
  line-height: 1.75;
}

/* Swap animation applied by app.js on each planet change */
.planet-copy__name.is-swapping,
.planet-copy__brief.is-swapping,
.planet-copy__index.is-swapping {
  animation: copy-swap 700ms var(--ease-out);
}

@keyframes copy-swap {
  0% { opacity: 0; transform: translateY(16px); filter: blur(5px); }
  100% { opacity: 1; transform: none; filter: blur(0); }
}

/* Progress ticks — one per body */
.journey__ticks {
  position: absolute;
  top: 50%;
  right: var(--gutter);
  z-index: 6;
  display: flex;
  margin: 0;
  padding: 0;
  flex-direction: column;
  gap: 0.85rem;
  list-style: none;
  transform: translateY(-50%);
}

.journey__tick {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.7rem;
  color: var(--muted);
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.35;
  transition: opacity 500ms var(--ease-out), color 500ms var(--ease-out);
}

.journey__tick::after {
  width: 1.1rem;
  height: 1px;
  background: currentColor;
  content: '';
  transition: width 500ms var(--ease-out);
}

.journey__tick.is-active {
  color: var(--accent);
  opacity: 1;
}

.journey__tick.is-active::after {
  width: 2.4rem;
}

.journey__instruction {
  position: absolute;
  bottom: clamp(1.4rem, 3vw, 3rem);
  left: 50%;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: rgb(236 234 245 / 0.45);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transform: translateX(-50%);
  /* Fades out once you've started scrolling the scene */
  opacity: calc(1 - (var(--scene-progress) * 6));
  transition: opacity 400ms var(--ease-out);
}

.journey__instruction-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
  animation: dot-pulse 2s var(--ease-in-out) infinite;
}

@keyframes dot-pulse {
  0%, 100% { opacity: 0.3; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.5); }
}

/* ============================================================
   Book
   ============================================================ */

.book {
  display: grid;
  min-height: 100svh;
  padding: clamp(5rem, 10vw, 11rem) var(--gutter);
  grid-template-columns: minmax(230px, 30vw) minmax(260px, 33rem);
  gap: clamp(3rem, 11vw, 13rem);
  align-items: center;
  justify-content: center;
}

.book__figure {
  width: min(100%, 400px);
  perspective: 1400px;
}

.book__art {
  position: relative;
  width: 100%;
  aspect-ratio: 0.64;
  transform-style: preserve-3d;
  will-change: transform;
}

.book__art-inner {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #121212;
  box-shadow:
    28px 40px 70px rgb(0 0 0 / 0.6),
    0 0 0 1px rgb(236 234 245 / 0.12);
  transform-style: preserve-3d;
}

.book__art img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* The asset is already cropped to the front cover, so it just fills the slab */
  object-fit: cover;
  filter: saturate(0.98) contrast(1.03) brightness(0.97);
}

/* Light sweeping across the cover as it tilts */
.book__sheen {
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.10) 48%, transparent 60%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 600ms var(--ease-out);
}

.book__figure:hover .book__sheen {
  opacity: 1;
}

/* Page-edge illusion on the spine side */
.book__spine {
  position: absolute;
  top: 0;
  left: 0;
  width: 10px;
  height: 100%;
  background: linear-gradient(to right, rgb(0 0 0 / 0.6), rgb(236 234 245 / 0.06));
  pointer-events: none;
}

.book figcaption {
  margin-top: 1.4rem;
  color: var(--muted);
  font-size: 0.61rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.book__title {
  margin-top: 0.8rem;
  font-size: clamp(3.2rem, 5.8vw, 7rem);
  line-height: 0.92;
}

.book__lede {
  max-width: 29rem;
  margin-top: clamp(1.6rem, 3vw, 2.6rem);
  color: var(--muted);
  line-height: 1.8;
}

.text-link {
  position: relative;
  display: inline-flex;
  margin-top: clamp(1.8rem, 3.5vw, 3rem);
  padding-bottom: 0.6rem;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.text-link::after {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--faint);
  content: '';
  transition: background var(--dur-mid) var(--ease-out);
}

.text-link:hover::after {
  background: var(--accent);
}

.text-link span:last-child {
  color: var(--accent);
  transition: transform var(--dur-mid) var(--ease-out);
}

.text-link:hover span:last-child {
  transform: translate(3px, -3px);
}

/* ============================================================
   Consultation
   ============================================================ */

.consultation {
  display: grid;
  min-height: 100svh;
  padding: clamp(5rem, 10vw, 11rem) var(--gutter);
  grid-template-columns: minmax(260px, 1fr) minmax(300px, 1.15fr);
  gap: clamp(3.5rem, 11vw, 12rem);
  align-items: center;
  background: var(--ink);
}

/* Sized to keep each written line on one rendered line — the masked reveal
   only reads correctly when a .line is a single line. */
.consultation__title {
  margin-top: 0.8rem;
  font-size: clamp(2.4rem, 4.3vw, 5rem);
  line-height: 0.98;
}

.consultation__lede {
  max-width: 21rem;
  margin-top: clamp(1.6rem, 3vw, 2.6rem);
  color: var(--muted);
  line-height: 1.8;
}

#consultation-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.4rem clamp(2rem, 4vw, 3.5rem);
}

.form-field {
  position: relative;
  display: block;
  min-width: 0;
}

.form-field__label {
  display: block;
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: color var(--dur-mid) var(--ease-out);
}

.form-field input {
  display: block;
  width: 100%;
  min-width: 0;
  padding: 0.9rem 0 0.8rem;
  border: 0;
  border-bottom: 1px solid rgb(236 234 245 / 0.18);
  border-radius: 0;
  outline: 0;
  background: transparent;
  color: var(--paper);
  color-scheme: dark;
  transition: border-color var(--dur-mid) var(--ease-out);
}

.form-field input::placeholder {
  color: rgb(236 234 245 / 0.22);
}

/* Brass underline that draws in from the left on focus */
.form-field__underline {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 450ms var(--ease-out);
}

.form-field input:focus ~ .form-field__underline {
  transform: scaleX(1);
}

.form-field:focus-within .form-field__label {
  color: var(--accent);
}

.form-field input[aria-invalid='true'] {
  border-bottom-color: var(--warning);
  animation: field-shake 400ms var(--ease-out);
}

@keyframes field-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

/* Sits in the cell beside Birth time, aligned to the field's baseline, so the
   last row reads as a pair instead of leaving half a row empty. */
.submit {
  position: relative;
  display: inline-flex;
  padding: 1rem 1.9rem;
  align-items: center;
  gap: 0.7rem;
  align-self: end;
  justify-self: start;
  overflow: hidden;
  border: 1px solid rgb(167 139 250 / 0.42);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition:
    border-color var(--dur-mid) var(--ease-out),
    color var(--dur-mid) var(--ease-out),
    transform var(--dur-mid) var(--ease-out);
}

.submit__label,
.submit__arrow {
  position: relative;
  z-index: 1;
}

.submit__arrow {
  color: var(--accent);
  transition: transform var(--dur-mid) var(--ease-out), color var(--dur-mid) var(--ease-out);
}

/* Brass fill wipes up from the bottom */
.submit__glow {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: translateY(101%);
  transition: transform 450ms var(--ease-out);
}

.submit:hover {
  border-color: var(--accent);
  color: var(--ink);
  transform: translateY(-2px);
}

.submit:hover .submit__glow {
  transform: translateY(0);
}

.submit:hover .submit__arrow {
  color: var(--ink);
  transform: translate(3px, -3px);
}

.submit:active {
  transform: translateY(0) scale(0.98);
}

#form-status {
  min-height: 1.5rem;
  margin-top: 1.6rem;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.6;
}

#form-status[data-state] {
  animation: copy-swap 600ms var(--ease-out);
}

#form-status[data-state='error'] {
  color: var(--warning);
}

#form-status[data-state='success'] {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--accent);
  font-family: 'Bodoni Moda', Georgia, serif;
  font-size: 1.3rem;
  letter-spacing: -0.02em;
}

/* ============================================================
   Footer
   ============================================================ */

.site-footer {
  display: flex;
  padding: 2.5rem var(--gutter);
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--ink-line);
  color: var(--muted);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.site-footer__note {
  font-family: 'Bodoni Moda', Georgia, serif;
  font-size: 0.9rem;
  font-style: italic;
  letter-spacing: 0;
  text-transform: none;
}

/* ============================================================
   Responsive
   ============================================================ */

@media (max-width: 900px) {
  .intro {
    grid-template-columns: 1fr;
  }

  /* Single-column stack: centre the wheel behind the copy below the portrait */
  .intro__zodiac {
    top: auto;
    bottom: 8vh;
    left: 50%;
    width: min(128vw, 620px);
    opacity: 0.07;
    transform: translate(-50%, 0);
  }

  /* Stacked layout: portrait sits on top, no longer pinned */
  .intro__portrait-wrap {
    position: relative;
    top: auto;
    height: auto;
    min-height: 54svh;
  }

  .intro__portrait {
    min-height: 54svh;
    height: 54svh;
    object-position: center 42%;
  }

  .intro__portrait-wrap::after {
    border-right: 0;
    border-bottom: 1px solid var(--ink-line);
  }

  .intro__portrait-veil {
    background:
      radial-gradient(120% 80% at 50% 40%, transparent 40%, rgb(0 0 0 / 0.5) 100%),
      linear-gradient(to top, rgb(0 0 0 / 0.95), transparent 55%);
  }

  .intro__copy {
    min-height: auto;
    padding: 3.5rem var(--gutter) 4.5rem;
  }

  /* Copy moves below the system, so the scrim rises from the floor instead */
  .journey__sticky::after {
    top: auto;
    right: 0;
    bottom: 0;
    width: auto;
    height: 55%;
    background: linear-gradient(to top, rgb(0 0 0 / 0.9), rgb(0 0 0 / 0.55) 40%, transparent 100%);
  }

  .planet-copy {
    top: auto;
    bottom: clamp(4.5rem, 12vh, 8rem);
    left: var(--gutter);
    max-width: calc(100% - var(--gutter) * 2);
    transform: none;
  }

  .planet-copy__name {
    font-size: clamp(3rem, 13vw, 5rem);
  }

  .planet-copy__brief {
    max-width: 22rem;
    margin-top: 1rem;
    font-size: 0.9rem;
  }

  .journey__ticks {
    display: none;
  }

  .book,
  .consultation {
    grid-template-columns: 1fr;
    gap: 3.5rem;
  }

  /* Bio spans the full column width in the stacked hero */
  .intro__bio {
    max-width: none;
  }

  .book__figure {
    width: min(66vw, 300px);
  }

  .site-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
  }
}

@media (max-width: 560px) {
  /* Keep the brand + all four links on one row instead of overflowing/wrapping */
  .site-nav {
    padding: 1.1rem var(--gutter);
  }

  .site-nav__mark {
    gap: 0.45rem;
    font-size: 0.6rem;
    letter-spacing: 0.1em;
  }

  .site-nav__glyph {
    font-size: 0.72rem;
  }

  .site-nav__links {
    gap: 0.7rem;
  }

  .site-nav__links a {
    padding-bottom: 0.15rem;
    font-size: 0.58rem;
    letter-spacing: 0.05em;
  }

  .intro__title {
    font-size: clamp(3rem, 15vw, 4.6rem);
  }

  .intro__facts {
    gap: 1.2rem 2rem;
  }

  #consultation-form {
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  .submit {
    width: 100%;
    margin-top: 0.6rem;
    justify-content: center;
  }
}

/* Smallest phones: drop the brand name so the four links never clip; the star
   mark stays as a compact logo */
@media (max-width: 360px) {
  .site-nav__mark-name {
    display: none;
  }
}

/* ============================================================
   Reduced motion — the scene still works, it just stops moving
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }

  .page-veil {
    display: none;
  }

  .site-nav {
    opacity: 1;
  }

  /* Everything is simply present */
  [data-reveal],
  [data-reveal] .line__inner,
  [data-reveal] .intro__portrait,
  [data-reveal] .book__art {
    opacity: 1 !important;
    transform: none !important;
  }

  /* The WebGL scene still renders and still follows scroll — orbit-engine.js
     simply stops advancing its clock, so nothing moves on its own. */
  .journey__instruction-dot,
  .intro__cue-arrow,
  .site-nav__glyph {
    animation: none !important;
  }
}
