/* ==========================================================================
   GREEN & GRAVEL
   base.css — tokens, reset, typography, layout primitives, motion primitives

   Colour, type and spacing all resolve from the tokens in :root.
   Change them there and the whole site follows.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Paper and ink -------------------------------------------------------- */
  --paper:       #f4f1e9;   /* warm off-white, the default ground */
  --paper-2:     #eae5d9;   /* sand, for alternating bands */
  --paper-3:     #ded7c6;   /* deeper sand, for insets */
  --ink:         #16180f;   /* charcoal with a green cast */
  --ink-2:       #3a3d33;
  --muted:       #5b5e53;   /* 5.9:1 on paper, 5.3:1 on sand: passes as body text */
  --line:        #d3ccba;
  --line-soft:   #e3ddce;

  /* Naturals ------------------------------------------------------------- */
  --olive:       #3b4630;   /* primary accent */
  --olive-deep:  #29311f;
  --moss:        #6d7b56;
  --stone:       #9a9385;
  --timber:      #976f47;   /* used sparingly, hairlines and details */
  --timber-ink:  #6f5c3c;   /* the same note, dark enough to be read as text */

  /* Dark grounds --------------------------------------------------------- */
  --night:       #12140e;
  --night-2:     #1b1e15;
  --night-line:  rgba(244, 241, 233, 0.16);
  --on-night:    #f4f1e9;
  --on-night-mu: rgba(244, 241, 233, 0.62);

  /* Type -----------------------------------------------------------------
     Two roles, not two moods. Archivo does the structural work: display
     headings, navigation, labels, metadata, buttons. It is a wide grotesque
     with weight in it, so a headline reads as built rather than drawn.
     Instrument Sans does the reading: paragraphs and form copy.

     A high-contrast display serif was tried here first and pulled the brand
     toward fashion editorial. Hairline strokes at 100px read delicate, which
     is the opposite of what this company sells. */
  --display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --sans:    'Instrument Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
             Roboto, Helvetica, Arial, sans-serif;
  --mono:    ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  /* Rhythm --------------------------------------------------------------- */
  --gutter:      clamp(20px, 4vw, 56px);
  --maxw:        1560px;
  --maxw-text:   62ch;
  --nav-h:       76px;

  --sp-section:  clamp(88px, 12vw, 176px);
  --sp-block:    clamp(48px, 6vw, 88px);

  /* Motion ---------------------------------------------------------------
     Firm curves with short tails. The previous set used an expo-out, which
     glides to a stop over a long distance and reads as floaty. These decelerate
     decisively, like a panel sliding into place and stopping. */
  --ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:    cubic-bezier(0.32, 0.06, 0.12, 1);
  --ease-in-out: cubic-bezier(0.62, 0.02, 0.24, 1);
  --dur:         0.4s;
  --dur-slow:    0.7s;

  /* Corners. Deliberately near-square. This is not a SaaS product. -------- */
  --r:           0px;
  --r-input:     2px;

  color-scheme: light;
  accent-color: var(--olive);
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchors clear the fixed masthead */
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

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

/* Class-based display rules outrank the UA style for [hidden], so say it
   once here and hidden always means hidden. */
[hidden] { display: none !important; }

h1, h2, h3, h4, h5 { margin: 0; font-weight: 500; }
p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; }
input, select, textarea, button { font-family: inherit; }

:focus-visible {
  outline: 2px solid var(--olive);
  outline-offset: 3px;
}
.on-dark :focus-visible,
.is-dark :focus-visible { outline-color: var(--on-night); }

::selection { background: var(--olive); color: var(--paper); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 900;
  padding: 12px 20px;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  transform: translateY(-160%);
  transition: transform 0.25s var(--ease-out);
}
.skip-link:focus-visible { transform: none; }

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

/* Display. Sized to be read, not to fill the viewport: the scale tops out
   well below the old one so the headline sits in the layout instead of
   overwhelming it. */
.display {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -0.032em;
  line-height: 1.02;
  text-wrap: balance;
}

.d-1 { font-size: clamp(2.6rem, 5.6vw, 5.4rem); }
.d-2 { font-size: clamp(2.2rem, 4vw, 3.9rem); }
.d-3 { font-size: clamp(1.75rem, 2.8vw, 2.7rem); line-height: 1.08; }

/* Structural headings. Same family, less weight, tighter role. */
.h-1 {
  font-family: var(--display);
  font-size: clamp(1.55rem, 2.2vw, 2.15rem);
  font-weight: 600;
  letter-spacing: -0.028em;
  line-height: 1.14;
}
.h-2 {
  font-family: var(--display);
  font-size: clamp(1.2rem, 1.6vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1.24;
}
.h-3 {
  font-family: var(--display);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.014em;
  line-height: 1.38;
}

/* Small caps labels: navigation, location, category, metadata. Not buttons,
   and not body copy. */
.label {
  display: inline-block;
  font-family: var(--display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.4;
}
.label--rule { display: inline-flex; align-items: center; gap: 14px; }
.label--rule::before {
  content: '';
  width: 34px; height: 1px;
  background: currentColor;
  opacity: 0.5;
}
.on-dark .label,
.is-dark .label { color: var(--on-night-mu); }

.num {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.lede {
  font-size: clamp(1.0625rem, 1.15vw, 1.3rem);
  line-height: 1.5;
  color: var(--ink-2);
  max-width: 48ch;
  text-wrap: pretty;
}

/* Reading copy. Slightly larger and darker than the usual muted grey: this
   site has real information to convey and the text has to hold its own
   against the photography rather than sit under it. */
.body {
  font-size: 1.0625rem;
  line-height: 1.62;
  color: var(--ink-2);
  max-width: var(--maxw-text);
  text-wrap: pretty;
}
.body + .body { margin-top: 1.05em; }
.body--muted { color: var(--muted); }
.body--sm { font-size: 0.9375rem; line-height: 1.6; color: var(--muted); }

.on-dark .lede, .is-dark .lede { color: var(--on-night-mu); }
.on-dark .body, .is-dark .body { color: var(--on-night-mu); }
.on-dark, .is-dark { color: var(--on-night); }

/* Placeholder copy sits at a lower contrast so real copy stands out later. */
.ph { color: color-mix(in srgb, currentColor 62%, transparent); }

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.shell--wide { max-width: none; padding-inline: var(--gutter); }
.shell--tight { max-width: 1120px; }

.section { padding-block: var(--sp-section); }
.section--half { padding-block: calc(var(--sp-section) * 0.6); }
.section--sand { background: var(--paper-2); }
.section--night { background: var(--night); color: var(--on-night); }
/* A dark band on a paper page has to undo the ink colours the same way a whole
   night page does, or the lede lands at 1.7:1 and cannot be read at all. */
.section--night .lede,
.section--night .body,
.section--night .body--sm,
.section--night .label,
.section--night .media-cap { color: var(--on-night-mu); }
.section--night .h-1,
.section--night .h-2,
.section--night .display { color: var(--on-night); }

/* Twelve columns. Sections place content asymmetrically inside it. */
.g12 {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
}

.c1  { grid-column: 1 / 13; }
.c-l { grid-column: 1 / 6; }    /* left editorial column */
.c-r { grid-column: 7 / 13; }   /* right editorial column */
.c-r-in { grid-column: 8 / 13; }
.c-mid { grid-column: 3 / 11; }
.c-wide { grid-column: 2 / 12; }

.stack > * + * { margin-top: var(--flow, 20px); }
.stack--lg { --flow: 32px; }
.stack--sm { --flow: 12px; }

/* Hairline rules are the main structural device on this site. */
.rule {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
  transform-origin: left center;
}
.is-dark .rule, .on-dark .rule { background: var(--night-line); }

/* Animated divider: draws itself when it enters the viewport. */
.rule--draw { transform: scaleX(0); transition: transform 1.1s var(--ease-out); }
.rule--draw.is-in { transform: scaleX(1); }

.section-head { display: grid; gap: 28px; }

/* --------------------------------------------------------------------------
   5. Motion primitives
   Driven by IntersectionObserver in js/lib/reveal.js. Everything animates
   transform and opacity only.
   -------------------------------------------------------------------------- */

[data-reveal] { --d: 0ms; }

/* Simple rise */
[data-reveal='rise'] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity 0.8s var(--ease-out) var(--d),
              transform 0.9s var(--ease-out) var(--d);
}
[data-reveal='rise'].is-in { opacity: 1; transform: none; }

/* Fade only, for large blocks where movement would be noisy */
[data-reveal='fade'] {
  opacity: 0;
  transition: opacity 1s var(--ease-out) var(--d);
}
[data-reveal='fade'].is-in { opacity: 1; }

/* Masked text. js/lib/reveal.js wraps each word in .w > .wi */
[data-reveal='text'] .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
[data-reveal='text'] .wi {
  display: inline-block;
  transform: translate3d(0, 108%, 0);
  transition: transform 0.95s var(--ease-out);
  transition-delay: calc(var(--d) + var(--wd, 0ms));
  will-change: transform;
}
[data-reveal='text'].is-in .wi { transform: none; }

/* Image reveal: the picture unmasks upward and settles back from a slight
   overscale. The mask sits on the children, never on the observed frame:
   a clip-path on the frame itself would stop it ever intersecting, and the
   reveal would never fire. */
[data-reveal='image'] > img,
[data-reveal='image'] > video,
[data-reveal='image'] > .media__fill {
  clip-path: inset(0 0 100% 0);
  transform: scale(1.1);
  transition: clip-path 1.2s var(--ease-out) var(--d),
              transform 1.6s var(--ease-out) var(--d);
}
[data-reveal='image'].is-in > img,
[data-reveal='image'].is-in > video,
[data-reveal='image'].is-in > .media__fill {
  clip-path: inset(0 0 0 0);
  transform: none;
}

/* Line that draws in from the left */
[data-reveal='line'] {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.1s var(--ease-out) var(--d);
}
[data-reveal='line'].is-in { transform: scaleX(1); }

/* Stagger helper: set --i on children of a [data-stagger] container */
[data-stagger] > * { --d: calc(var(--i, 0) * 90ms); }

/* Parallax targets are moved by js/lib/ticker.js via --py (pixels). */
[data-parallax] {
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}

/* --------------------------------------------------------------------------
   6. Reduced motion
   Nothing moves, nothing is hidden, everything stays usable.
   -------------------------------------------------------------------------- */

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

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

  [data-reveal] { opacity: 1 !important; transform: none !important; }
  [data-reveal='text'] .wi { transform: none !important; }
  [data-reveal='image'] > img,
  [data-reveal='image'] > video,
  [data-reveal='image'] > .media__fill { transform: none !important; clip-path: none !important; }
  [data-reveal='line'], .rule--draw { transform: scaleX(1) !important; }
  [data-parallax] { transform: none !important; }
}

/* --------------------------------------------------------------------------
   7. Print
   -------------------------------------------------------------------------- */

@media print {
  .masthead, .drawer, .cursor, .scroll-cue, .progress, video { display: none !important; }
  body { background: #fff; color: #000; }
}

/* --------------------------------------------------------------------------
   8. Seasonal palettes

   The one place on this site where colour leads rather than accents. Each set
   is a ground, an ink, a muted ink, a rule and an accent, so any block can be
   scoped to a season by putting data-season on it and nothing inside has to
   know which season it is in.

   Deliberately held back from primary: painted plaster and dyed cloth rather
   than seasonal clip art. Spring is new growth, summer is deeper foliage,
   autumn is ochre rather than pumpkin, winter is frost.
   -------------------------------------------------------------------------- */

[data-season='spring'] {
  --s-bg:     #d5e0c0;
  --s-ink:    #232e17;
  --s-muted:  #4b583a;
  --s-line:   #bccaa4;
  --s-accent: #5d7a3c;
  /* The stage wash is a duotone over photography, so it is much deeper than
     the flat band ground and carries its own ink. */
  --s-scrim:    rgba(66, 88, 40, 0.74);
  --s-scrim-ink: #f4f1e9;
  --s-scrim-mu:  rgba(244, 241, 233, 0.78);
}

[data-season='summer'] {
  --s-bg:     #a9b782;
  --s-ink:    #1e2711;
  --s-muted:  #313c1f;
  --s-line:   #93a26c;
  --s-accent: #34421d;
  --s-scrim:    rgba(44, 58, 24, 0.76);
  --s-scrim-ink: #f4f1e9;
  --s-scrim-mu:  rgba(244, 241, 233, 0.78);
}

[data-season='autumn'] {
  --s-bg:     #d3a069;
  --s-ink:    #33200e;
  --s-muted:  #472c11;
  --s-line:   #bf8b52;
  --s-accent: #8a4f1c;
  --s-scrim:    rgba(103, 57, 18, 0.76);
  --s-scrim-ink: #f4f1e9;
  --s-scrim-mu:  rgba(244, 241, 233, 0.8);
}

[data-season='winter'] {
  --s-bg:     #ecefef;
  --s-ink:    #1a1e1e;
  --s-muted:  #57605f;
  --s-line:   #d3d9d8;
  --s-accent: #55686a;
  /* Winter is the one that inverts: a frost wash with dark type over it. */
  --s-scrim:    rgba(228, 234, 234, 0.88);
  --s-scrim-ink: #1a1e1e;
  --s-scrim-mu:  #4b5453;
}

/* Christmas keeps the night treatment: it is the one seasonal service that
   only exists after dark. */
[data-season='christmas'] {
  --s-bg:     #12140e;
  --s-ink:    #f4f1e9;
  --s-muted:  rgba(244, 241, 233, 0.62);
  --s-line:   rgba(244, 241, 233, 0.16);
  --s-accent: #c8a06a;
  --s-scrim:    rgba(12, 14, 9, 0.68);
  --s-scrim-ink: #f4f1e9;
  --s-scrim-mu:  rgba(244, 241, 233, 0.7);
}

/* Scope a block to whichever season it carries. Everything inside follows,
   including type that would otherwise take the page's own ink. */
/* The class is doubled throughout so a season always beats whatever the page
   itself is doing. Without it the dark-page rules on the Seasonal page win on
   source order and put white type on a white winter ground. */
.season-scope.season-scope {
  background: var(--s-bg);
  color: var(--s-ink);
  transition: background-color 0.9s var(--ease), color 0.9s var(--ease);
}
.season-scope.season-scope .label,
.season-scope.season-scope .body,
.season-scope.season-scope .lede,
.season-scope.season-scope .media-cap,
.season-scope.season-scope .num,
.season-scope.season-scope .step__d { color: var(--s-muted); }
.season-scope.season-scope .display,
.season-scope.season-scope .h-1,
.season-scope.season-scope .h-2,
.season-scope.season-scope .h-3,
.season-scope.season-scope .arrow-link { color: var(--s-ink); }
.season-scope.season-scope .rule,
.season-scope.season-scope .linelist,
.season-scope.season-scope .linelist li,
.season-scope.season-scope .steps,
.season-scope.season-scope .step { border-color: var(--s-line); }
.season-scope.season-scope .label--rule::before { background: var(--s-accent); opacity: 1; }
.season-scope.season-scope .btn { border-color: var(--s-line); color: var(--s-ink); }
.season-scope.season-scope .btn::before { background: var(--s-ink); }
.season-scope.season-scope .btn:hover { color: var(--s-bg); border-color: var(--s-ink); }
.season-scope.season-scope .btn--fill {
  background: var(--s-accent);
  border-color: var(--s-accent);
  color: var(--s-bg);
}
.season-scope.season-scope .btn--fill::before { background: var(--s-ink); }
.season-scope.season-scope .btn--fill:hover { color: var(--s-bg); }
.season-scope.season-scope :focus-visible { outline-color: var(--s-ink); }

/* Placeholder media tones, so the seasons read seasonally before the
   photography exists. */
.t-spring { --tone: #96ae74; --tone-ink: rgba(20, 28, 12, 0.6); }
.t-summer { --tone: #60743e; --tone-ink: rgba(244, 241, 233, 0.66); }
.t-autumn { --tone: #a0642a; --tone-ink: rgba(244, 241, 233, 0.7); }
.t-winter { --tone: #dee5e5; --tone-ink: rgba(26, 30, 30, 0.5); }
