/* Grain Manager design tokens. See docs/refresh/DESIGN.md.
   Colours come from the brand pack; the panel, wash and easing come from the
   app's sign-in page. Type and stage widths grow with the viewport so the
   site reads on a phone in a cab and on an ultrawide in the farm office. */

/* Variable fonts, subset to Latin and compressed to WOFF2 by tools/subset-fonts.mjs
   from the brief's TrueType files. Regenerate there; never hand-edit these. */
@font-face {
  font-family: Fraunces;
  src: url("/fonts/Fraunces.woff2") format("woff2");
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: Fraunces;
  src: url("/fonts/Fraunces-Italic.woff2") format("woff2");
  font-weight: 300 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: Inter;
  src: url("/fonts/Inter.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Colour */
  --gm-green: #1f6154;
  --gm-green-deep: #123f39;
  --gm-cream: #f7f3eb;
  --gm-ink: #352f27;
  --gm-ink-soft: hsl(35 16% 18% / 0.72);
  --gm-ink-faint: hsl(35 16% 18% / 0.12);
  --gm-wheat: #dee1db;
  --gm-field: hsl(90 28% 80%);
  --gm-straw: #6a5428;
  --gm-night: hsl(215 16% 9%);
  --gm-night-card: hsl(214 15% 12%);
  --gm-night-primary: hsl(162 48% 36%);
  --gm-night-text: hsl(210 16% 92%);
  --gm-night-text-soft: hsl(210 16% 92% / 0.72);

  /* The sign-in panel, as HSL channels so alpha can vary */
  --gm-paper-hsl: 42 30% 96%;
  --gm-night-hsl: 215 16% 9%;

  /* Type. The middle term grows with the viewport; the ends stop it running away. */
  --font-display: Fraunces, Georgia, "Times New Roman", serif;
  --font-sans: Inter, "Segoe UI", system-ui, -apple-system, sans-serif;

  --text-display-1: clamp(2.6rem, 1.5rem + 2.6vw, 5.6rem);
  --text-display-2: clamp(2rem, 1.2rem + 2vw, 4.2rem);
  --text-h3: clamp(1.35rem, 1.1rem + 0.7vw, 2rem);
  --text-lede: clamp(1.1rem, 0.95rem + 0.55vw, 1.6rem);
  --text-body: clamp(1.0625rem, 0.98rem + 0.25vw, 1.3rem);
  --text-small: clamp(0.9rem, 0.84rem + 0.2vw, 1.1rem);
  --text-fine: clamp(0.82rem, 0.78rem + 0.15vw, 0.98rem);
  --text-eyebrow: clamp(0.75rem, 0.7rem + 0.15vw, 0.9rem);

  /* Space and shape. Stages carry imagery and grow wide; reading stays narrow. */
  --wrap: min(1500px, calc(100% - 3rem));
  --wrap-text: min(1160px, calc(100% - 3rem));
  --wrap-narrow: min(720px, var(--wrap));
  --wrap-reading: min(800px, var(--wrap));
  --section-pad: clamp(4rem, 8vw, 9rem);
  --radius-panel: 1.15rem;
  --radius-card: 0.9rem;
  --radius-pill: 999px;
  --shadow-panel: 0 18px 40px -24px hsl(35 30% 16% / 0.4);
  --shadow-frame: 0 30px 60px -30px hsl(35 30% 16% / 0.45);
  --header-h: 4rem;
  --header-gap: 0.6rem; /* space above the header pill */
  --banner-h: 2.25rem; /* BetaBanner height; 0 when the banner is off */

  /* Motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --dur-ui: 220ms;
  --dur-panel: 380ms;
  --dur-reveal: 700ms;
}

@media (min-width: 1920px) {
  :root {
    --header-h: 4.5rem;
    --wrap: min(1800px, calc(100% - 4rem));
    --wrap-text: min(1280px, calc(100% - 4rem));
  }
}
/* Base styles: the field, type, buttons, shared layout primitives. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
  -webkit-text-size-adjust: 100%;
  /* Clip sideways scroll here, not on body. On a phone, overflow clipping
     on body makes position: fixed layers jump as the page scrolls. */
  overflow-x: clip;
}

body {
  margin: 0;
  min-height: 100svh;
  color: var(--gm-ink);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: 1.55;
  background-color: #cbb892;
  timeline-scope: --night;
}

/* The field. A still photograph, fixed, with a cream wash heavier at the top. */
body::before,
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
}
body::before {
  z-index: 0;
  background: url("/media/wheat-field.jpg") center / cover no-repeat;
}
/* The WebP copy (tools/field-webp.mjs) is a third of the bytes. The @supports
   wrapper keeps the JPEG line above as a real fallback; without it the
   minifier folds both into one declaration. */
@supports (background-image: image-set(url("x.webp") type("image/webp"))) {
  body::before {
    background-image: image-set(url("/media/wheat-field.webp") type("image/webp"), url("/media/wheat-field.jpg") type("image/jpeg"));
  }
}
body::after {
  z-index: 1;
  background: linear-gradient(
    180deg,
    hsl(40 36% 97% / 0.42) 0%,
    hsl(38 32% 96% / 0.28) 42%,
    hsl(36 40% 94% / 0.22) 100%
  );
}

/* Dust motes, top half only. Driven by lit-grain-mark.js. */
.field-dust {
  position: fixed;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* The night veil. Opacity is driven by the night chapter (motion.css). */
.night-veil {
  position: fixed;
  inset: 0;
  z-index: 2;
  background: var(--gm-night);
  opacity: 0;
  pointer-events: none;
}

/* On a phone or a tablet the browser bar slides away as you scroll and the
   screen gets taller. A fixed layer sized with inset: 0 grows with it, and
   cover then reframes the photograph, so the field appears to jump and the
   strip at the bottom paints late. The large viewport (100lvh) does not
   change when the bar moves. Any touch screen gets the lock, not just one
   under 900px: an iPad in landscape had the jump too (James, 2 Nov 2026).
   Browsers without lvh keep inset: 0.

   Which edge to hang the layer from depends on where the bar is. The edge
   the bar is on moves as it hides; the other edge stays still. A bar at
   the bottom (Safari on an iPhone) means hang from the top; a bar at the
   top (Chrome on Android, phone or tablet) means hang from the bottom, or
   the field slides up against the text by the bar's height (James, on an
   Android tablet, 2 Nov 2026). CSS cannot see the bar, so: phones default
   to the top edge and wide touch screens (tablets) to the bottom, and the
   inline script in BaseLayout.astro, which can tell the browser apart,
   sets html.bar-top or html.bar-bottom before first paint and overrides
   both. Backdrop.astro follows the same rules.

   This block must stay below the .field-dust and .night-veil rules above:
   they set inset: 0 and height: 100% at the same weight, so whichever
   comes later wins, and when the lock sat above them the dust canvas kept
   stretching with the viewport and its motes jumped as the bar hid
   (James, 2 Nov 2026). */
@media ((max-width: 900px) or (hover: none) or (pointer: coarse)) {
  body::before,
  body::after,
  .field-dust,
  .night-veil {
    top: 0;
    bottom: auto;
    height: 100lvh;
  }
  @media (min-width: 901px) {
    body::before,
    body::after,
    .field-dust,
    .night-veil {
      top: auto;
      bottom: 0;
    }
  }
  html.bar-top body::before,
  html.bar-top body::after,
  html.bar-top .field-dust,
  html.bar-top .night-veil {
    top: auto;
    bottom: 0;
  }
  html.bar-bottom body::before,
  html.bar-bottom body::after,
  html.bar-bottom .field-dust,
  html.bar-bottom .night-veil {
    top: 0;
    bottom: auto;
  }
}

/* Everything readable sits above the field. */
.site-banner,
.site-header,
.site-main,
.site-footer {
  position: relative;
  z-index: 3;
}
.site-header {
  z-index: 6;
}
.site-banner {
  z-index: 7;
}

/* Inside main, chapter photographs sit at 0 and everything else above them,
   so a fading photograph never covers a neighbouring panel. */
.site-main > * {
  position: relative;
  z-index: 1;
}
.site-main > .chapter,
.site-main > .chapters,
.site-main > .season {
  z-index: auto;
}
.chapter {
  position: relative;
}
.chapter-stage {
  position: relative;
  z-index: 1;
}

img,
picture,
svg {
  max-width: 100%;
  height: auto;
  display: block;
}

/* Keep the hidden attribute winning over any display rule of ours. */
[hidden] {
  display: none !important;
}

/* Type */
h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 560;
  color: var(--gm-ink);
  text-wrap: balance;
}
h1 {
  font-size: var(--text-display-1);
  line-height: 0.98;
  letter-spacing: -0.03em;
}
h2 {
  font-size: var(--text-display-2);
  line-height: 1.05;
  letter-spacing: -0.025em;
}
h3 {
  font-size: var(--text-h3);
  line-height: 1.15;
  letter-spacing: -0.015em;
}
h1 em,
h2 em {
  font-style: italic;
  font-weight: 520;
  color: var(--gm-straw);
}
p {
  margin: 0;
}
p + p {
  margin-top: 0.85em;
}
a {
  color: var(--gm-green);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}
a:hover {
  color: var(--gm-green-deep);
}
:focus-visible {
  outline: 2px solid var(--gm-green);
  outline-offset: 3px;
  border-radius: 2px;
}
::selection {
  background: hsl(168 52% 25% / 0.18);
}

.lede {
  font-size: var(--text-lede);
  line-height: 1.5;
  color: var(--gm-ink);
  max-width: 38rem;
  text-wrap: pretty;
}
.small {
  font-size: var(--text-small);
  color: var(--gm-ink-soft);
}
.fine {
  font-size: var(--text-fine);
  line-height: 1.45;
  color: var(--gm-ink-soft);
}
.eyebrow {
  margin: 0;
  font-size: var(--text-eyebrow);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gm-green);
}
.step {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--gm-green);
  letter-spacing: 0.02em;
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.72rem 1.2rem;
  border-radius: var(--radius-pill);
  background: var(--gm-green);
  color: var(--gm-cream);
  font-family: var(--font-sans);
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition:
    background-color var(--dur-ui) var(--ease),
    transform var(--dur-ui) var(--ease),
    box-shadow var(--dur-ui) var(--ease);
}
.btn:hover {
  background: var(--gm-green-deep);
  color: var(--gm-cream);
}
.btn:active {
  transform: translateY(1px);
}
.btn-lg {
  padding: 0.9rem 1.5rem;
  font-size: 1.05rem;
}
.btn-ghost {
  background: hsl(var(--gm-paper-hsl) / 0.55);
  color: var(--gm-ink);
  border-color: hsl(0 0% 100% / 0.6);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.btn-ghost:hover {
  background: hsl(var(--gm-paper-hsl) / 0.8);
  color: var(--gm-ink);
}
.link-quiet {
  color: var(--gm-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.22em;
  text-decoration-color: hsl(35 16% 18% / 0.35);
}
.link-quiet:hover {
  color: var(--gm-green);
  text-decoration-color: currentColor;
}

/* Layout primitives */
.wrap {
  width: var(--wrap);
  margin-inline: auto;
}
.wrap-text {
  width: var(--wrap-text);
  margin-inline: auto;
}
.wrap-narrow {
  width: var(--wrap-narrow);
  margin-inline: auto;
}
.wrap-reading {
  width: var(--wrap-reading);
  margin-inline: auto;
}
.section {
  padding-block: var(--section-pad);
}
.section-tight {
  padding-block: calc(var(--section-pad) * 0.55);
}
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.8rem 1.2rem;
}
.stack > * + * {
  margin-top: var(--stack-gap, 1rem);
}
.center {
  text-align: center;
}
.center .actions {
  justify-content: center;
}
.center .lede {
  margin-inline: auto;
}

.skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 20;
  padding: 0.55rem 0.9rem;
  border-radius: var(--radius-card);
  background: var(--gm-cream);
  color: var(--gm-ink);
  font-weight: 600;
}
.skip:focus {
  top: 0.6rem;
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Lists in copy */
.points {
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}
.points li {
  position: relative;
  padding-left: 1.35rem;
  color: var(--gm-ink);
}
.points li + li {
  margin-top: 0.5rem;
}
.points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 0.55rem;
  height: 1px;
  background: var(--gm-green);
}

/* Night contexts flip the ink */
.is-night,
.is-night h1,
.is-night h2,
.is-night h3,
.is-night .lede,
.is-night .points li {
  color: var(--gm-night-text);
}
.is-night .small,
.is-night .fine {
  color: var(--gm-night-text-soft);
}
.is-night .eyebrow,
.is-night .step {
  color: hsl(162 42% 68%);
}
.is-night .points li::before {
  background: hsl(162 42% 68%);
}
.is-night a {
  color: hsl(162 42% 72%);
}
.is-night .link-quiet {
  color: var(--gm-night-text);
  text-decoration-color: hsl(210 16% 92% / 0.4);
}
.is-night h1 em,
.is-night h2 em {
  color: hsl(40 60% 78%);
}

@media (max-width: 600px) {
  :root {
    --wrap: min(1160px, calc(100% - 1.5rem));
  }
}
/* The frosted panel from the app's sign-in page. One recipe. */

.glass {
  position: relative;
  border-radius: var(--radius-panel);
  background: hsl(var(--gm-paper-hsl) / 0.46);
  border: 1px solid hsl(0 0% 100% / 0.5);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  backdrop-filter: blur(18px) saturate(1.3);
  box-shadow:
    inset 0 1px 0 hsl(0 0% 100% / 0.62),
    var(--shadow-panel);
}

/* Over a photograph: firmer than the sign-in card, still translucent. */
.glass.is-firm {
  background: hsl(var(--gm-paper-hsl) / 0.72);
}

/* For long reading: About, FAQ, legal. Same border, calmer background. */
.glass.is-solid {
  background: hsl(var(--gm-paper-hsl) / 0.86);
}

/* The night chapter. */
.glass.is-night {
  background: hsl(var(--gm-night-hsl) / 0.42);
  border-color: hsl(0 0% 100% / 0.14);
  box-shadow:
    inset 0 1px 0 hsl(0 0% 100% / 0.08),
    0 18px 40px -24px hsl(0 0% 0% / 0.45);
}
.glass.is-night.is-solid {
  background: hsl(var(--gm-night-hsl) / 0.78);
}

/* With no veil darkening the field (reduced motion), the night panel carries
   the contrast on its own. */
@media (prefers-reduced-motion: reduce) {
  .glass.is-night {
    background: hsl(var(--gm-night-hsl) / 0.86);
  }
}

/* Without backdrop blur the fill has to carry the readability on its own. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass {
    background: hsl(var(--gm-paper-hsl) / 0.92);
  }
  .glass.is-night {
    background: hsl(var(--gm-night-hsl) / 0.92);
  }
}

/* Padding steps */
.glass.pad {
  padding: clamp(1.25rem, 3vw, 2.25rem);
}
.glass.pad-lg {
  padding: clamp(1.5rem, 4vw, 3rem);
}
/* Motion. CSS first, scroll-driven where the browser allows it, with a small
   IntersectionObserver fallback in src/scripts/motion.ts.
   Timings: docs/refresh/DESIGN.md. Nothing bounces. */

/* ---------- Reveals -------------------------------------------------------- */

/* Default state: visible. Motion is added only when it is safe and supported.
   That way the content is always there, whatever the browser does. */
.reveal {
  --reveal-y: 24px;
}

@media (prefers-reduced-motion: no-preference) {
  /* Scroll-driven: the element rises as it enters the viewport. */
  @supports (animation-timeline: view()) {
    .reveal {
      animation: reveal-rise var(--dur-reveal) var(--ease) both;
      animation-timeline: view();
      animation-range: entry 0% entry 45%;
    }
  }

  /* Fallback: the script adds .is-in when the element is on screen. */
  @supports not (animation-timeline: view()) {
    .reveal {
      opacity: 0;
      transform: translateY(var(--reveal-y));
      transition:
        opacity var(--dur-reveal) var(--ease),
        transform var(--dur-reveal) var(--ease);
    }
    .reveal.is-in {
      opacity: 1;
      transform: none;
    }
  }
}

@keyframes reveal-rise {
  from {
    opacity: 0;
    transform: translateY(var(--reveal-y));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- Hero -------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  /* The frame rises and settles on load. */
  .hero-frame {
    animation: hero-settle 1100ms var(--ease) both;
    animation-delay: 120ms;
  }
  .hero-copy > * {
    animation: reveal-rise 800ms var(--ease) both;
  }
  .hero-copy > :nth-child(1) { animation-delay: 60ms; }
  .hero-copy > :nth-child(2) { animation-delay: 140ms; }
  .hero-copy > :nth-child(3) { animation-delay: 220ms; }
  .hero-copy > :nth-child(4) { animation-delay: 300ms; }
  .hero-copy > :nth-child(5) { animation-delay: 380ms; }
  .hero-copy > :nth-child(6) { animation-delay: 460ms; }

  /* As the reader scrolls away, the frame hands over to the first chapter. */
  @supports (animation-timeline: view()) {
    .hero {
      view-timeline-name: --hero;
    }
    .hero-frame {
      animation:
        hero-settle 1100ms var(--ease) both,
        hero-leave linear both;
      animation-delay: 120ms, 0ms;
      animation-timeline: auto, --hero;
      animation-range: normal, exit 0% exit 70%;
    }
  }
}

@keyframes hero-settle {
  from {
    opacity: 0;
    transform: translateY(6vh) scale(0.96);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes hero-leave {
  to {
    opacity: 0.35;
    transform: translateY(-4vh) scale(0.9);
  }
}

/* ---------- Pinned chapters -------------------------------------------- */

/* A chapter is a tall wrapper. Its stage sticks for one viewport while the
   frame settles and the copy fades in. Below 900px, on a touch screen of any
   width (hover: none or pointer: coarse, so an iPad in landscape stacks like
   a phone rather than pinning under a thumb; James, 2 Nov 2026), under
   reduced motion, or without scroll-driven animations, chapters are a plain
   stack. The chapter always names its timeline, so the photograph behind it
   can follow it at any width. */

.chapter {
  position: relative;
  view-timeline-name: --chapter;
}
.chapter-stage {
  display: flex;
  align-items: center;
  min-height: 100svh;
  padding-block: 1.25rem;
}

@media (min-width: 901px) and (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    /* The chapter is 200 viewport-heights of scroll. The stage pins for the
       last 100 of them (contain 0% to 100%). Everything has arrived by
       contain 35%, about 35 viewport-heights into the pin, so the chapter
       then holds at full for the remaining 65 before it unpins and slides
       away. (It was 185svh with the copy finishing at contain 60%, which
       left only 34 at full; James found the next chapter arriving before
       the text had fully darkened, 31 Oct 2026. Then 215svh, which he found
       "ever so slightly too long, both up and down", 2 Nov 2026.) */
    .chapter {
      height: 200svh;
    }
    .chapter-stage {
      position: sticky;
      top: 0;
      height: 100svh;
      min-height: 0;
    }
    .chapter-frame {
      animation: chapter-frame linear both;
      animation-timeline: --chapter;
      animation-range: entry 26% contain 19%;
    }
    .chapter-copy > * {
      animation: chapter-copy linear both;
      animation-timeline: --chapter;
      animation-range: entry 37% contain 15%;
    }
    .chapter-copy > :nth-child(2) { animation-range: entry 40% contain 20%; }
    .chapter-copy > :nth-child(3) { animation-range: entry 43% contain 25%; }
    .chapter-copy > :nth-child(4) { animation-range: entry 46% contain 30%; }
    .chapter-copy > :nth-child(5) { animation-range: entry 49% contain 35%; }
  }
}

/* Phones and touch screens: no pinning, but each panel still arrives rather
   than appears. The whole glass panel rises a little and fades in as it
   enters the screen, driven by its own position, so it reads the same at
   any chapter height. */
@media ((max-width: 900px) or (hover: none) or (pointer: coarse)) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .chapter-stage > .stage {
      animation: reveal-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 40%;
    }
  }
}

@keyframes chapter-frame {
  from {
    opacity: 0;
    transform: translateY(8vh) scale(0.92);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes chapter-copy {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- Photographs behind chapters -------------------------------- */

/* The photograph is fixed to the viewport and fades in as the chapter
   arrives, out as it leaves, at every width. Under reduced motion it is a
   still background inside the chapter with softened edges. The state rules
   live in components/Backdrop.astro so they outrank its scoped defaults;
   the keyframes are here. */
@media (prefers-reduced-motion: reduce) {
  .chapter.has-backdrop,
  .season.has-backdrop {
    overflow: clip;
  }
}
@keyframes backdrop-fade {
  0% { opacity: 0; }
  35% { opacity: 1; }
  65% { opacity: 1; }
  100% { opacity: 0; }
}
/* For long sections (the season): a quick fade in, a long hold, a quick fade out. */
@keyframes backdrop-hold {
  0% { opacity: 0; }
  8% { opacity: 1; }
  92% { opacity: 1; }
  100% { opacity: 0; }
}

/* ---------- The night -------------------------------------------------- */

/* The night section names a timeline; the fixed veil listens to it from
   outside, through timeline-scope on body. On the homepage that is the
   offline chapter; on Features it is the offline pillar (James, 2 Nov 2026:
   the veil had only ever run on the homepage, because Pillar.astro turned
   its panel dark but never named the timeline). A pinned pillar also names
   --pillar for its screen, in Pillar.astro, and lists --night with it. */
.is-night-chapter {
  view-timeline-name: --night;
}
.chapter.is-night-chapter {
  view-timeline-name: --night, --chapter;
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .night-veil {
      animation: night-veil linear both;
      animation-timeline: --night;
      animation-range: entry 20% exit 80%;
    }
  }
  @supports not (animation-timeline: view()) {
    .night-veil {
      transition: opacity 900ms var(--ease);
    }
    body.is-night .night-veil {
      opacity: 0.88;
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  /* No veil. The night chapter carries its own dark panel. */
  .night-veil {
    display: none;
  }
}

@keyframes night-veil {
  0% { opacity: 0; }
  30% { opacity: 0.88; }
  70% { opacity: 0.88; }
  100% { opacity: 0; }
}

/* The pinned season on How it works is styled in pages/how-it-works.astro;
   it declares view-timeline-name: --season and uses the backdrop rules above. */

/* ---------- Between pages ---------------------------------------------- */

/* Native cross-document view transitions, CSS only: every page opts in, so
   moving between them crossfades instead of flashing. The sticky header
   keeps its own place; the rest of the old page fades as the new one rises
   into it. A browser without view transitions simply navigates. */
@view-transition {
  navigation: auto;
}
.site-header {
  view-transition-name: site-header;
}
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) {
    animation: page-out 240ms var(--ease) both;
  }
  ::view-transition-new(root) {
    animation: page-in 480ms var(--ease) both;
  }
  ::view-transition-group(site-header) {
    animation-duration: 320ms;
  }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}
@keyframes page-out {
  to {
    opacity: 0;
  }
}
@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}

/* Leaving for the app (Sign up or Login): the field stays, everything on it
   fades, then the browser goes. The app's pages are the same field, so the
   handover reads as one place. motion.ts adds and removes the class. */
@media (prefers-reduced-motion: no-preference) {
  html.is-leaving :is(.site-banner, .site-header, .site-main, .site-footer, .field-dust) {
    transition: opacity 320ms var(--ease);
    opacity: 0;
  }
}

/* ---------- Reduced motion, everywhere ---------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
.site-banner[data-astro-cid-mhu6mgwx] {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  margin: 0;
  min-height: var(--banner-h);
  padding: .3rem 1rem;
  text-align: center;
  font-size: var(--text-fine);
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--gm-cream);
  background: var(--gm-green);
}

.pip[data-astro-cid-mhu6mgwx] {
  flex: none;
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: var(--gm-wheat);
  box-shadow: 0 0 0 3px #dee1db38;
}
.logo[data-astro-cid-f7espo7c] {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: var(--gm-ink);
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1;
}

.logo[data-astro-cid-f7espo7c]:hover {
  color: var(--gm-ink);
}

.logo-tile[data-astro-cid-f7espo7c] {
  flex: none;
  width: 2rem;
  height: 2rem;
}

.logo-header[data-astro-cid-f7espo7c] .logo-word[data-astro-cid-f7espo7c] {
  font-size: 1.15rem;
}

.logo-footer[data-astro-cid-f7espo7c] .logo-tile[data-astro-cid-f7espo7c] {
  width: 1.75rem;
  height: 1.75rem;
}

.logo-footer[data-astro-cid-f7espo7c] .logo-word[data-astro-cid-f7espo7c] {
  font-size: 1.05rem;
}

.is-reversed[data-astro-cid-f7espo7c] {
  color: var(--gm-cream);
}

.is-reversed[data-astro-cid-f7espo7c]:hover {
  color: var(--gm-cream);
}

@media (width <= 560px) {
  .logo-header[data-astro-cid-f7espo7c] .logo-word[data-astro-cid-f7espo7c] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
}
.site-header[data-astro-cid-fzpbxy5g] {
  position: sticky;
  top: 0;
  padding: var(--header-gap) 0 0;
}

.bar[data-astro-cid-fzpbxy5g] {
  width: var(--wrap);
  margin-inline: auto;
  min-height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .4rem .6rem .4rem clamp(1.25rem, 2vw, 2rem);
  border-radius: var(--radius-pill);
  background: hsl(var(--gm-paper-hsl) / .62);
}

.nav[data-astro-cid-fzpbxy5g] {
  margin-left: auto;
}

.nav[data-astro-cid-fzpbxy5g] ul[data-astro-cid-fzpbxy5g] {
  display: flex;
  gap: .2rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav[data-astro-cid-fzpbxy5g] a[data-astro-cid-fzpbxy5g] {
  display: inline-block;
  padding: .5rem .8rem;
  border-radius: var(--radius-pill);
  color: var(--gm-ink);
  font-weight: 500;
  font-size: .96rem;
  text-decoration: none;
  transition: background-color var(--dur-ui) var(--ease),
      color var(--dur-ui) var(--ease);
}

.nav[data-astro-cid-fzpbxy5g] a[data-astro-cid-fzpbxy5g]:hover {
  background: hsl(var(--gm-paper-hsl) / .9);
  color: var(--gm-green-deep);
}

.nav[data-astro-cid-fzpbxy5g] a[data-astro-cid-fzpbxy5g][aria-current="page"] {
  color: var(--gm-green);
  font-weight: 600;
}

.end[data-astro-cid-fzpbxy5g] {
  display: flex;
  align-items: center;
  gap: .5rem;
}

.menu[data-astro-cid-fzpbxy5g] {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  border: 1px solid #fff9;
  border-radius: 50%;
  background: hsl(var(--gm-paper-hsl) / .7);
  cursor: pointer;
}

.menu-line[data-astro-cid-fzpbxy5g] {
  display: block;
  width: 1.05rem;
  height: 1.5px;
  margin: 0 auto;
  background: var(--gm-ink);
  transition: transform var(--dur-ui) var(--ease);
}

.is-open[data-astro-cid-fzpbxy5g] .menu-line[data-astro-cid-fzpbxy5g]:nth-child(2) {
  transform: translateY(3.25px) rotate(45deg);
}

.is-open[data-astro-cid-fzpbxy5g] .menu-line[data-astro-cid-fzpbxy5g]:nth-child(3) {
  transform: translateY(-3.25px) rotate(-45deg);
}

@media (width >= 901px) {
  .bar[data-astro-cid-fzpbxy5g] {
    padding-right: clamp(1.25rem, 2vw, 2rem);
  }
}

@media (width <= 900px) or (hover: none) or (pointer: coarse) {
  .site-header[data-astro-cid-fzpbxy5g] {
    transform: translateY(calc(-1 * var(--tuck, 0px)));
    transition: transform 60ms linear;
    will-change: transform;
  }

  .site-header[data-astro-cid-fzpbxy5g].is-snapping {
    transition: transform .32s var(--ease);
  }
}

@media (width <= 900px) {
  .menu[data-astro-cid-fzpbxy5g] {
    display: flex;
  }

  .end[data-astro-cid-fzpbxy5g] {
    margin-left: auto;
    gap: .4rem;
  }

  .end[data-astro-cid-fzpbxy5g] .btn {
    padding-inline: .9rem;
    font-size: .92rem;
  }

  .nav[data-astro-cid-fzpbxy5g] {
    position: absolute;
    left: 50%;
    top: calc(100% + .5rem);
    width: var(--wrap);
    transform: translateX(-50%) translateY(-6px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-panel) var(--ease),
        transform var(--dur-panel) var(--ease);
  }

  .nav[data-astro-cid-fzpbxy5g] ul[data-astro-cid-fzpbxy5g] {
    flex-direction: column;
    gap: .1rem;
    padding: .6rem;
    border-radius: var(--radius-panel);
    background: hsl(var(--gm-paper-hsl) / .92);
    border: 1px solid #fff9;
    -webkit-backdrop-filter: blur(18px) saturate(1.3);
    backdrop-filter: blur(18px) saturate(1.3);
    box-shadow: inset 0 1px 0 #ffffff9e,
        var(--shadow-panel);
  }

  .nav[data-astro-cid-fzpbxy5g] a[data-astro-cid-fzpbxy5g] {
    display: block;
    padding: .8rem .9rem;
    font-size: 1.05rem;
  }

  .is-open[data-astro-cid-fzpbxy5g] .nav[data-astro-cid-fzpbxy5g] {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
  }
}
.site-footer[data-astro-cid-nns7i3if] {
  margin-top: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(7rem, 14vw, 13rem) 0 clamp(1.5rem, 3vw, 2.5rem);
  color: var(--gm-night-text);
  text-align: center;
}

.site-footer[data-astro-cid-nns7i3if]:before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg,
      hsl(var(--gm-night-hsl) / 0) 0%,
      hsl(var(--gm-night-hsl) / .38) 30%,
      hsl(var(--gm-night-hsl) / .8) 62%,
      hsl(var(--gm-night-hsl) / .94) 100%);
  pointer-events: none;
}

.mark-link[data-astro-cid-nns7i3if] {
  display: block;
  color: var(--gm-night-text);
  text-decoration: none;
}

.mark[data-astro-cid-nns7i3if] {
  height: clamp(3.75rem, 2.75rem + 2vw, 5.5rem);
  width: 100%;
  max-width: clamp(14rem, 10rem + 9vw, 22rem);
  margin: 0 auto;
}

.word[data-astro-cid-nns7i3if] {
  display: block;
  margin-top: .9rem;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1;
  font-size: clamp(1.5rem, 1.15rem + .9vw, 2.2rem);
}

.tagline[data-astro-cid-nns7i3if] {
  margin: .7rem auto 0;
  max-width: 30rem;
  font-size: var(--text-small);
  color: var(--gm-night-text-soft);
}

.links[data-astro-cid-nns7i3if] {
  margin-top: clamp(1.6rem, 3vw, 2.4rem);
}

.links[data-astro-cid-nns7i3if] > ul[data-astro-cid-nns7i3if] {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem .55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.links[data-astro-cid-nns7i3if] > ul[data-astro-cid-nns7i3if] li[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if] {
  display: inline-block;
  padding: .5rem .95rem;
  border-radius: var(--radius-pill);
  border: 1px solid #ffffff24;
  background: #ffffff0d;
  color: var(--gm-night-text);
  font-size: var(--text-small);
  font-weight: 500;
  text-decoration: none;
  transition: background-color var(--dur-ui) var(--ease),
      border-color var(--dur-ui) var(--ease);
}

.links[data-astro-cid-nns7i3if] > ul[data-astro-cid-nns7i3if] li[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if]:hover {
  background: #ffffff1f;
  border-color: #ffffff4d;
}

.contact[data-astro-cid-nns7i3if] {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .9rem;
  margin-top: 1.1rem;
}

.email[data-astro-cid-nns7i3if] {
  margin: 0;
  font-size: var(--text-small);
}

.socials[data-astro-cid-nns7i3if] {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.socials[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if] {
  display: block;
  border-radius: 10px;
  transition: transform var(--dur-ui) var(--ease);
}

.socials[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if]:hover {
  transform: translateY(-2px);
}

.socials[data-astro-cid-nns7i3if] img[data-astro-cid-nns7i3if] {
  display: block;
  width: 40px;
  height: 40px;
}

.email[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if] {
  color: var(--gm-night-text);
  text-decoration: none;
  border-bottom: 1px solid #ffffff47;
  transition: border-color var(--dur-ui) var(--ease);
}

.email[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if]:hover {
  border-color: #ffffffb3;
}

.base[data-astro-cid-nns7i3if] {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  gap: .5rem 1.5rem;
  margin-top: clamp(2.25rem, 4vw, 3.25rem);
  padding-top: 1rem;
  border-top: 1px solid #ffffff1f;
  text-align: left;
}

.base[data-astro-cid-nns7i3if] .fine[data-astro-cid-nns7i3if] {
  margin: 0;
  color: var(--gm-night-text-soft);
}

.base[data-astro-cid-nns7i3if] .small-print[data-astro-cid-nns7i3if] {
  text-align: center;
}

.base[data-astro-cid-nns7i3if] > .fine[data-astro-cid-nns7i3if]:last-child {
  text-align: right;
}

.small-print[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if] {
  color: var(--gm-night-text);
  text-decoration: none;
}

.small-print[data-astro-cid-nns7i3if] a[data-astro-cid-nns7i3if]:hover {
  text-decoration: underline;
}

.dot[data-astro-cid-nns7i3if] {
  margin: 0 .35rem;
  color: var(--gm-night-text-soft);
}

@media (width <= 640px) {
  .base[data-astro-cid-nns7i3if] {
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
    gap: .35rem;
  }

  .base[data-astro-cid-nns7i3if] > .fine[data-astro-cid-nns7i3if]:last-child {
    text-align: center;
  }
}
