/* ==========================================================================
   base.css — reset, typography, layout rails, primitives.
   ========================================================================== */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + var(--s-4));
}

body {
  min-height: 100svh;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--ink-900);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

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

img { height: auto; }

button,
input,
select,
textarea { font: inherit; color: inherit; }

button { background: none; border: 0; cursor: pointer; }

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

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

:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

::selection {
  background: rgb(var(--accent-rgb) / 0.34);
  color: var(--text-strong);
}

/* ---- Typography ------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  text-wrap: balance;
}

p { text-wrap: pretty; }

.display {
  font-size: var(--fs-display);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
}

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

.lead {
  font-size: var(--fs-lead);
  line-height: 1.56;
  color: var(--text-muted);
  max-width: 54ch;
}

.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }

.mono {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
}

/* The kicker/eyebrow used to label every section and project chapter */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--accent-2);
}

.eyebrow::before {
  content: "";
  width: 26px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent-2));
}

.eyebrow--plain::before { display: none; }

.grad {
  background: linear-gradient(
    104deg,
    var(--text-strong) 8%,
    var(--accent) 42%,
    var(--accent-2) 72%,
    var(--accent-3) 96%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---- Layout rails ----------------------------------------------------- */
.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--rail);
}

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

.section__head {
  display: grid;
  gap: var(--s-4);
  max-width: 62ch;
  margin-bottom: var(--s-8);
}

/* Rule of thirds: content sits on the upper-third / left-third line */
.thirds {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
  align-items: start;
}

.thirds > * { grid-column: 1 / -1; }

@media (min-width: 900px) {
  .thirds__copy { grid-column: 1 / span 7; }
  .thirds__art { grid-column: 8 / span 5; }
  .thirds__art--wide { grid-column: 7 / span 6; }
  .thirds__copy--narrow { grid-column: 1 / span 5; }
  .thirds__offset { grid-column: 3 / span 8; }
}

.stack { display: grid; gap: var(--s-5); }
.stack--sm { gap: var(--s-3); }
.stack--lg { gap: var(--s-7); }

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4);
}

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

.skip-link {
  position: absolute;
  top: var(--s-3);
  left: var(--s-3);
  z-index: 200;
  padding: var(--s-3) var(--s-5);
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--ink-900);
  font-weight: 600;
  transform: translateY(-160%);
  transition: transform var(--dur-2) var(--ease-out);
}

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

/* ---- Glass material --------------------------------------------------- */
.glass {
  position: relative;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-lg);
  box-shadow: var(--glass-shadow), var(--glass-inner);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
}

/* Specular highlight along the top edge — sells the 3D "pane" read */
.glass::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(
    150deg,
    rgb(255 255 255 / 0.14) 0%,
    rgb(255 255 255 / 0) 34%
  );
  opacity: 0.9;
}

.glass--pad { padding: clamp(var(--s-5), 3vw, var(--s-7)); }
.glass--flat { box-shadow: var(--lift-2), var(--glass-inner); }

/* ---- Chips / tags ----------------------------------------------------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0.34em 0.82em;
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.02em;
  color: rgb(var(--accent-rgb));
  background: rgb(var(--accent-rgb) / 0.1);
  border: 1px solid rgb(var(--accent-rgb) / 0.26);
  transition: transform var(--dur-2) var(--ease-spring),
    background-color var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out);
}

.chip--accent2 { color: var(--accent-2); background: rgb(var(--accent-2-rgb) / 0.1); border-color: rgb(var(--accent-2-rgb) / 0.28); }
.chip--accent3 { color: var(--accent-3); background: rgb(var(--accent-3-rgb) / 0.1); border-color: rgb(var(--accent-3-rgb) / 0.28); }
.chip--quiet { color: var(--text-muted); background: rgb(255 255 255 / 0.05); border-color: var(--glass-border); }

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

/* ---- Buttons ---------------------------------------------------------- */
/* 3D extruded slab. The two pseudo-elements are the bottom and right faces,
   rotated out of the plane; `preserve-3d` on the parent keeps them attached
   while the face tilts. Resting angles are deliberately shallower than a
   full 70deg/30deg so the label stays legible at small sizes. */
.btn {
  --color1: var(--accent);
  --color2: color-mix(in srgb, var(--accent) 72%, #000);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  /* 44px min-height keeps the control a comfortable touch target at every size */
  min-height: 44px;
  padding: 0.82em 1.5em;
  border: none;
  border-radius: var(--r-sm);
  background: linear-gradient(var(--color1), var(--color2));
  color: #fff;
  font-family: var(--font-display);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  text-shadow: 0 2px 6px rgb(0 0 0 / 0.45);
  cursor: pointer;
  perspective: 1000px;
  transform: rotateX(22deg) rotateZ(7deg);
  transform-style: preserve-3d;
  transition: transform var(--dur-3) var(--ease-out),
    box-shadow var(--dur-3) var(--ease-out);
  box-shadow: var(--lift-2);
}

/* Bottom face */
.btn::before {
  content: "";
  position: absolute;
  inset: auto 0 0 auto;
  width: 100%;
  height: 14px;
  background: var(--color2);
  transform: rotateX(90deg);
  transform-origin: bottom;
  border-radius: inherit;
}

/* Right face */
.btn::after {
  content: "";
  position: absolute;
  inset: 0 0 auto auto;
  width: 14px;
  height: 100%;
  background: color-mix(in srgb, var(--color1) 80%, #000);
  transform: rotateY(-90deg);
  transform-origin: right;
  border-radius: inherit;
}

.btn:hover {
  transform: rotateX(8deg) rotateZ(0deg);
  box-shadow: var(--lift-3);
}

.btn:active { transform: rotateX(16deg) rotateZ(3deg) translateY(2px); }

.btn:focus-visible {
  outline: 3px solid var(--accent-2);
  outline-offset: 3px;
}

.btn--primary {
  --color1: var(--accent);
  --color2: color-mix(in srgb, var(--accent) 66%, #000);
}

.btn--ghost {
  --color1: var(--ink-500);
  --color2: var(--ink-700);
  color: var(--text);
}

.btn--sm { padding: 0.6em 1.1em; font-size: var(--fs-micro); }

.btn__icon {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  transition: transform var(--dur-2) var(--ease-spring);
}

.btn:hover .btn__icon { transform: translateY(2px); }
.btn--forward:hover .btn__icon { transform: translateX(3px); }

/* Press + spring feedback shared by every pressable surface */
.pressable {
  transition: transform 160ms var(--ease-spring);
}

.pressable.is-pressed { transform: scale(0.94); }

/* ---- Text shift on hover ---------------------------------------------- */
/* Two stacked copies of the label; the pair slides up on hover. */
.shift {
  position: relative;
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  line-height: 1.24;
}

.shift__a,
.shift__b {
  display: block;
  transition: transform var(--dur-3) var(--ease-out);
}

.shift__b {
  position: absolute;
  inset: 0;
  color: var(--accent-2);
}

.shift:hover .shift__a,
a:hover > .shift .shift__a,
button:hover > .shift .shift__a { transform: translateY(-102%); }

.shift:hover .shift__b,
a:hover > .shift .shift__b,
button:hover > .shift .shift__b { transform: translateY(-102%); }

/* Underline that draws in from the left on hover */
.ulink {
  position: relative;
  display: inline-block;
  color: var(--text);
  transition: color var(--dur-2) var(--ease-out);
}

.ulink::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-out);
}

.ulink:hover { color: var(--accent-2); }
.ulink:hover::after { transform: scaleX(1); }

/* ---- Motion primitives (driven by assets/js/motion.js) ---------------- */
/* Reveal primitives are gated behind `html.js`, which app.js sets as its very
   first statement. If the script never runs — JS disabled, a blocked request,
   a syntax error — nothing is hidden and the page reads normally. */
html.js [data-reveal] {
  opacity: 0;
  transform: translate3d(var(--reveal-x, 0px), 30px, 0);
  transition: opacity var(--dur-4) var(--ease-out),
    transform var(--dur-4) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

html.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* Clip reveal — content unmasked from the bottom edge upward */
html.js [data-clip] {
  clip-path: inset(0 0 100% 0);
  opacity: 0;
  transition: clip-path 900ms var(--ease-out), opacity 500ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

[data-clip].is-in {
  clip-path: inset(0 0 0 0);
  opacity: 1;
}

html.js [data-clip-x] {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 900ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

html.js [data-clip-x].is-in { clip-path: inset(0 0 0 0); }

/* Scrub — driven continuously by scroll progress, no CSS transition */
[data-scrub] {
  transform: translate3d(0, var(--scrub-y, 0px), 0) scale(var(--scrub-s, 1));
  opacity: var(--scrub-o, 1);
  will-change: transform, opacity;
}

/* Stagger children inherit their index-based delay from JS.
   `.is-in` goes on the children themselves: IntersectionObserver does not fire
   for a wrapper whose children are all at opacity 0, so observing the group
   element alone would never reveal anything. */
html.js [data-stagger] > * {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

html.js [data-stagger] > *.is-in { opacity: 1; transform: none; }

@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;
    transition-delay: 0ms !important;
  }

  [data-reveal],
  [data-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
  }
  [data-clip],
  [data-clip-x] { clip-path: none !important; opacity: 1 !important; }

  [data-scrub] { transform: none !important; opacity: 1 !important; }
}
