/* ==========================================================================
   MERIDIAN STUDIO — base.css
   Design tokens, reset, typography, buttons, motion primitives.
   ========================================================================== */

/* --------------------------------------------------------------- tokens -- */
:root {
  /* Palette — warm off-white, anthracite, sand, golden hour */
  --bone:        #F6F2EC;
  --bone-deep:   #EDE7DE;
  --sand:        #E3D9CB;
  --clay:        #C7B7A2;
  --ink:         #14110F;
  --ink-soft:    #201C19;
  --ink-mute:    #6B625A;
  --gold:        #B08D57;   /* on dark grounds  */
  --gold-deep:   #8F6E3C;   /* on light grounds */

  --on-ink:        #F2EDE6;
  --on-ink-mute:   rgba(242, 237, 230, 0.56);
  --on-bone-mute:  rgba(20, 17, 15, 0.62);

  --rule-dark:   rgba(20, 17, 15, 0.14);
  --rule-light:  rgba(242, 237, 230, 0.16);

  /* Type */
  --ff-display: "Instrument Serif", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --ff-sans:    "Archivo", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;

  --fs-eyebrow: 0.6875rem;
  --fs-body:    clamp(1rem, 0.94rem + 0.28vw, 1.125rem);
  --fs-lead:    clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);
  --fs-h2:      clamp(2.75rem, 1.6rem + 5.1vw, 6.75rem);
  --fs-h3:      clamp(1.75rem, 1.1rem + 2.9vw, 3.75rem);
  --fs-hero:    clamp(3rem, 1.3rem + 7.6vw, 8.75rem);
  --fs-huge:    clamp(2.25rem, 0.9rem + 6vw, 6.25rem);

  /* Space & layout */
  --gutter:     clamp(1.25rem, 0.55rem + 3vw, 4.5rem);
  --wrap:       84rem;
  --sec-y:      clamp(6rem, 3rem + 12vw, 16rem);

  /* Motion */
  --ease-out:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft:  cubic-bezier(0.33, 0, 0.16, 1);
  --dur:        1.1s;

  /* Film grain, used as a repeating overlay */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  background: var(--bone);
  color: var(--ink);
  font-family: var(--ff-sans);
  font-size: var(--fs-body);
  line-height: 1.62;
  font-weight: 400;
  letter-spacing: 0.002em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Locks scroll while the mobile menu is open, without layout shift. */
body.is-locked { overflow: hidden; }

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

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

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

ul, ol { list-style: none; padding: 0; }

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

:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 4px;
}

.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 999;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--on-ink);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  transform: translateY(-160%);
  transition: transform 0.3s var(--ease-out);
}
.skip-link:focus-visible { transform: none; }

/* ----------------------------------------------------------- typography -- */
.display {
  font-family: var(--ff-display);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* Two golds. The bright one only ever sits on ink; light grounds get the
   deeper cut so the accent still clears contrast at display sizes. */
.display em {
  font-style: italic;
  color: var(--gold-deep);
}

.section--ink .display em { color: var(--gold); }

.eyebrow {
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--on-bone-mute);
}

.section--ink .eyebrow { color: var(--on-ink-mute); }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.42;
  letter-spacing: -0.011em;
}

/* --------------------------------------------------------------- layout -- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  position: relative;
  padding-block: var(--sec-y);
}

.section--bone { background: var(--bone); color: var(--ink); }
.section--sand { background: var(--bone-deep); color: var(--ink); }
.section--ink  { background: var(--ink); color: var(--on-ink); }

.section__head {
  display: grid;
  gap: clamp(1.5rem, 0.6rem + 3vw, 3rem);
  margin-bottom: clamp(3.5rem, 1.5rem + 7vw, 9rem);
}

.section__title { font-size: var(--fs-h2); }

/* -------------------------------------------------------------- buttons -- */
.btn {
  --btn-fg: var(--ink);
  --btn-bg: transparent;
  --btn-bd: currentColor;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  padding: 1.05em 2.1em;
  border: 1px solid var(--btn-bd);
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  line-height: 1;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.55s var(--ease-out), border-color 0.55s var(--ease-out);
}

/* Wipe fill, no gradients, no glass. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--btn-fill, var(--ink));
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 0.55s var(--ease-out);
}
.btn:hover::before,
.btn:focus-visible::before { transform: scaleY(1); }

.btn--light      { --btn-fg: var(--ink); --btn-bg: var(--on-ink); --btn-bd: var(--on-ink); --btn-fill: var(--bone); }
.btn--light:hover{ color: var(--ink); }

.btn--bare-light { --btn-fg: var(--on-ink); --btn-bd: rgba(242,237,230,0.34); --btn-fill: var(--on-ink); }
.btn--bare-light:hover, .btn--bare-light:focus-visible { color: var(--ink); border-color: var(--on-ink); }

.btn--dark       { --btn-fg: var(--bone); --btn-bg: var(--ink); --btn-bd: var(--ink); --btn-fill: var(--gold); }
.btn--dark:hover { color: var(--ink); border-color: var(--gold); }

.btn--ghost      { --btn-fg: currentColor; --btn-bd: currentColor; --btn-fill: currentColor; padding: 0.85em 1.6em; }
.btn--ghost:hover, .btn--ghost:focus-visible { color: var(--bone); }
.nav.is-solid .btn--ghost:hover { color: var(--bone); }

.btn--lg { padding: 1.35em 3.2em; font-size: 0.875rem; }

/* ------------------------------------------------------ reveal primitives -- */
/* Masked line reveal — the text slides out from behind a clipping edge. */
.line {
  display: block;

  /* The mask has to clip the top and the sides but NOT the bottom.

     These display faces are set at line-heights below 1, so descenders hang
     below the line box — measured at 0.17em on the hero at 130px and 0.14em
     on the manifesto at 100px. `overflow: hidden` clips at the box, so it
     sliced the tails off every g, p and y.

     A negative bottom inset extends the clip region past the box without
     touching the box itself, so unlike padding it needs no margin to
     compensate — and cannot be defeated by an element that sets its own
     margin-bottom, which `.hero__eyebrow` does. Nothing in the layout moves. */
  --descender-room: 0.22em;
  clip-path: inset(0 0 calc(var(--descender-room) * -1) 0);
}
.line > span {
  display: block;
  /* Clears the EXPANDED clip, not just the line box: at 110% alone the tops
     of the letters would sit inside the widened mask and peek out below
     before the line slides in. */
  transform: translateY(calc(110% + var(--descender-room)));
  transition: transform 1.15s var(--ease-out);
  transition-delay: calc(var(--d, 0) * 90ms);
}
.line.is-in > span,
.hero.is-ready .line > span { transform: none; }

/* Same choreography, no clipping — for rows that contain focusable controls
   whose focus ring must not be cut off by the mask. */
.line-soft > span {
  display: block;
  opacity: 0;
  transform: translateY(1.35rem);
  transition:
    opacity 0.9s var(--ease-soft),
    transform 1.15s var(--ease-out);
  transition-delay: calc(var(--d, 0) * 90ms);
}
.hero.is-ready .line-soft > span { opacity: 1; transform: none; }

/* Generic fade + rise for blocks. */
.reveal {
  opacity: 0;
  transform: translateY(2.25rem);
  transition:
    opacity 1s var(--ease-soft),
    transform 1.15s var(--ease-out);
  transition-delay: calc(var(--d, 0) * 110ms);
  will-change: opacity, transform;
}
.reveal.is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Masked lines inside the manifesto keep the overflow clip AND the fade. */
.manifesto .line.reveal { opacity: 1; transform: none; }

/* ------------------------------------------------- reduced motion policy -- */
/* Keyed on the data-motion attribute that site-config.js stamps on <html>,
   deliberately NOT on the media query directly. One decision, made in one
   place, so the stylesheet and the scripts cannot disagree — and so the
   ?motion= override reaches the CSS as well.

   The scripts are what put the video on the page at all, so there is no
   meaningful no-JS path here to fall back to. */
html[data-motion="reduced"] { scroll-behavior: auto; }

html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

html[data-motion="reduced"] .reveal { opacity: 1; transform: none; }
html[data-motion="reduced"] .line > span { transform: none; }
html[data-motion="reduced"] .line-soft > span { opacity: 1; transform: none; }

/* Anchor targets land at the very top of the viewport, so the section runs up
   BEHIND the fixed bar rather than starting beneath it.

   The bar is translucent once solid — 82% bone over a blur — so whatever sits
   behind it colours it. Landing the section under the bar left the previous
   section behind it, which on the jump from the dark manifesto to the light
   contact section meant a dark bar with a hard dark-to-light edge along its
   bottom. Running the target up behind it puts the target's own background
   there instead: the bar reads light on light, and there is no seam.

   Nothing is hidden by this, because these sections carry their own top
   padding — `--sec-y`, a minimum of 6rem — and the bar is at most 90px. The
   copy always clears it with room to spare. That is the assumption to check
   if `--sec-y` is ever reduced: the padding has to stay taller than the bar. */
section[id], #top { scroll-margin-top: 0; }
