/* ==========================================================================
   Base + Components — built only from tokens.css
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  /* Always reserve the scrollbar's space, so locking scroll (sheet) never
     changes the page width — and 100vw stays the same in both states. */
  scrollbar-gutter: stable;
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; } /* in-page links, e.g. menu → #services */
}

/* Lenis smooth scroll (js/smooth-scroll.js) */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
/* While the page glides, elements slide under a resting cursor; without this
   every button / row / link passing by would flash its hover state. */
.lenis.lenis-scrolling body { pointer-events: none; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-tight);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, p, ul, blockquote, figure { margin: 0; }
h1, h2, h3, h4 { font-size: inherit; font-weight: inherit; } /* weight comes from the type classes */
ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; letter-spacing: inherit; }

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

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

/* ---- Type styles --------------------------------------------------------- */
.t-display-xl,
.t-display-l,
.t-display-m {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
}
.t-display-xl { font-size: var(--text-display-xl); }
.t-display-l  { font-size: var(--text-display-l); }
.t-display-m  { font-size: var(--text-display-m); }

.t-lead {
  font-family: var(--font-body);
  font-size: var(--text-lead);
  line-height: var(--leading-lead);
}

.t-body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}

.t-label {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  line-height: var(--leading-mono);
  text-transform: uppercase;
}
/* Section eyebrows: [ABOUT]. Brackets are decoration, hidden from screen readers. */
.t-label--bracket::before { content: "["; content: "[" / ""; }
.t-label--bracket::after  { content: "]"; content: "]" / ""; }

/* ---- Button --------------------------------------------------------------
   Compact rectangle with an accent outline. On hover the accent wipes in
   from the bottom and leaves upwards (::before).
   .button--filled starts filled and drains on hover.                        */
.button {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: calc(30 * var(--px)); /* fixed height, shared with .button--icon */
  padding: 0 calc(14 * var(--px));
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius);
  background: transparent;
  color: var(--color-accent);
  font-family: var(--font-mono);
  font-size: var(--text-base);
  line-height: var(--leading-mono);
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.3s var(--ease-out);
}
.button::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--color-accent);
  transform-origin: top;      /* leaving: shrinks upwards */
  scale: 1 0;
  transition: scale 0.35s var(--ease-out);
}
.button:not(:disabled, [aria-disabled="true"]):hover { color: var(--color-text-inverse); }
.button:not(:disabled, [aria-disabled="true"]):hover::before {
  transform-origin: bottom;   /* entering: grows from the bottom */
  scale: 1 1;
}
.button--filled { color: var(--color-text-inverse); }
.button--filled::before { scale: 1 1; }
.button--filled:not(:disabled, [aria-disabled="true"]):hover { color: var(--color-accent); }
.button--filled:not(:disabled, [aria-disabled="true"]):hover::before {
  transform-origin: top;      /* drains upwards */
  scale: 1 0;
}
.button:disabled,
.button[aria-disabled="true"] { opacity: 0.35; cursor: default; }

@media (prefers-reduced-motion: reduce) {
  .button, .button::before { transition: none; }
}
.button__icon { flex: none; width: calc(32 * var(--px)); height: calc(8 * var(--px)); }
/* Icon button (same height as .button) holding an SVG icon, so the
   glyph sits in the exact optical centre — font arrows sit low and narrow. */
.button--icon {
  width: calc(36 * var(--px));
  height: calc(30 * var(--px));
  padding: 0;
}
.icon {
  display: block;
  flex: none;
  width: calc(14 * var(--px));
  height: calc(14 * var(--px));
}

/* ---- Tag (small rectangle, like a mini button) ---------------------------- */
.tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: calc(2 * var(--px)) var(--space-2);
  border: var(--border-width) solid var(--color-border-accent);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--text-base);
  line-height: var(--leading-mono);
  text-transform: uppercase;
  white-space: nowrap;
}
.tag--outline { color: var(--color-accent); background: transparent; }
.tag--filled  { color: var(--color-text-inverse); background: var(--color-accent); }
.tag--neutral { color: var(--color-text); border-color: var(--color-border); background: transparent; }

/* ---- Testimonial card ---------------------------------------------------- */
.testimonial {
  display: flex;
  flex-direction: column;
  min-height: calc(319 * var(--px));
  padding: var(--space-8) var(--space-6) var(--space-5) var(--space-8);
  background: var(--color-surface);
}
.testimonial__mark {
  display: block;
  height: calc(25 * var(--px));
  color: var(--color-accent);
  font-family: var(--font-body);
  font-size: var(--text-quote-mark);
  line-height: 1;
}
.testimonial__quote { max-width: calc(592 * var(--px)); }
.testimonial__author {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1-5);
  margin-top: auto;
  padding-top: var(--space-6);
  align-self: flex-end;
}

/* ---- Service card -------------------------------------------------------- */
.service-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, calc(340 * var(--px)));
  grid-template-rows: auto 1fr;
  gap: var(--space-12);
  min-height: calc(319 * var(--px));
  padding: var(--space-8);
  background: var(--color-surface);
}
.service-card__meta {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.service-card__title,
.service-card__text { align-self: end; }
.service-card__title { text-wrap: balance; }

@media (max-width: 700px) {
  .service-card {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr auto;
    gap: var(--space-6);
  }
}

/* ---- Process list (native <details name>, one open at a time) ------------
   Full-width rows between hairlines: number pill · centred title · +/× pill. */
.process { border-bottom: var(--border-width) solid rgb(255 255 255 / 0.12); }
.process__item { border-top: var(--border-width) solid rgb(255 255 255 / 0.12); }
.process__summary {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  list-style: none;
  cursor: pointer;
}
.process__summary::-webkit-details-marker { display: none; }
.process__summary .tag { justify-self: start; }
.process .tag { border-color: var(--color-border-accent); } /* numbers and skill/hobby tags */
.process__title { text-align: center; transition: color var(--duration-fast) var(--ease-out); }
.process__summary:hover .process__title { color: var(--color-accent); }

.process__icon {
  justify-self: end;
  display: grid;
  place-items: center;
  width: calc(32 * var(--px));
  height: calc(20 * var(--px));
  border: var(--border-width) solid var(--color-accent);
  border-radius: var(--radius);
  color: var(--color-text); /* white glyph, accent outline — like the buttons */
  transition: background-color 0.3s var(--ease-out), color 0.3s var(--ease-out);
}
/* Behaves like a button: fills with the accent on hover and while open. */
.process__summary:hover .process__icon,
.process__item[open] .process__icon {
  background: var(--color-accent);
  color: var(--color-text-inverse);
}
.process__icon::before,
.process__icon::after {
  content: "";
  grid-area: 1 / 1;
  width: calc(10 * var(--px));
  height: var(--border-width);
  background: currentColor;
  transition: rotate var(--duration-tilt) var(--ease-out);
}
.process__icon::after { rotate: 90deg; }
.process__item[open] .process__icon::before { rotate: 45deg; }
.process__item[open] .process__icon::after { rotate: 135deg; }

/* A row of tags, e.g. skills inside a process panel. */
.tag-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}
.process__panel:has(.tag-list) { max-width: calc(560 * var(--px)); }

.process__panel {
  max-width: calc(440 * var(--px));
  margin-inline: auto;
  padding: var(--space-2) var(--space-4) var(--space-8);
  text-align: center;
}
.process__panel > p + p { margin-top: var(--space-4); }

/* Smooth open/close where the browser supports animating to `auto`. */
@supports (interpolate-size: allow-keywords) {
  .process { interpolate-size: allow-keywords; }
  .process__item::details-content {
    block-size: 0;
    overflow: clip;
    transition:
      block-size var(--duration-tilt) var(--ease-out),
      content-visibility var(--duration-tilt) allow-discrete;
  }
  .process__item[open]::details-content { block-size: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .process__item::details-content,
  .process__icon::before,
  .process__icon::after { transition: none; }
}

/* ---- Slider (js/slider.js) ----------------------------------------------- */
.slider { position: relative; }
.slider__track {
  position: relative;
  display: flex;
  gap: var(--space-5);
  padding-inline: var(--page-gutter);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--page-gutter);
  scrollbar-width: none;
}
.slider__track::-webkit-scrollbar { display: none; }
.slider__track > * { flex: none; scroll-snap-align: start; }
.slider__track:focus-visible { outline-offset: -2px; }
.slider__track.is-dragging { scroll-snap-type: none; cursor: grabbing; user-select: none; }
@media (hover: hover) and (pointer: fine) {
  .slider__track { cursor: grab; }
}
.slider__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.slider__controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.slider__count { margin-right: var(--space-4); }

/* ---- Feature item -------------------------------------------------------- */
.feature {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: calc(216 * var(--px));
}

/* ---- ASCII field (js/ascii-field.js) ------------------------------------- */
.has-ascii-field {
  position: relative;
  isolation: isolate;
}
.ascii-field {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
  font-family: var(--font-mono);
  font-size: var(--text-base);
}

/* ---- Sheet (js/sheet.js) -------------------------------------------------
   3D side sheet: flies in from the right with a slight tilt out of depth,
   leaves with a softer tilt. States: hidden → .is-open → .is-closing → hidden */
html.has-sheet { overflow: hidden; }

.sheet {
  position: fixed;
  inset: 0;
  z-index: 20;
  perspective: calc(1200 * var(--px));
}
.sheet[hidden] { display: none; }
.sheet.is-closing { pointer-events: none; }

.sheet__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.6);
  opacity: 0;
}

.sheet__panel {
  position: absolute;
  top: var(--page-gutter);
  right: var(--page-gutter);
  bottom: var(--page-gutter);
  display: flex;
  flex-direction: column;
  width: min(calc(560 * var(--px)), calc(100% - 2 * var(--page-gutter)));
  padding: var(--space-8);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--color-surface-sunken);
  translate: 120% 0 calc(100 * var(--px));
  rotate: y -35deg;
}
.sheet__panel:focus { outline: none; }

.sheet__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.sheet__body { flex: 1; display: flex; flex-direction: column; justify-content: center; padding-block: var(--space-12); }
.sheet__foot { display: flex; justify-content: space-between; gap: var(--space-4); }

/* Items reveal one after another once the panel has landed (set --i per item). */
.sheet__item { opacity: 0; translate: 0 var(--reveal-distance); }

.sheet.is-open .sheet__backdrop {
  opacity: 1;
  transition: opacity var(--duration-fade) var(--ease-out);
}
.sheet.is-open .sheet__panel {
  translate: 0 0 0;
  rotate: y 0deg;
  transition:
    translate var(--duration-sheet-in) var(--ease-out) 50ms,
    rotate var(--duration-tilt) var(--ease-out) 50ms;
}
.sheet.is-open .sheet__item {
  opacity: 1;
  translate: 0 0;
  transition:
    opacity var(--duration-tilt) var(--ease-out),
    translate var(--duration-tilt) var(--ease-out);
  transition-delay: calc(250ms + var(--i, 0) * var(--stagger-items));
}

.sheet.is-closing .sheet__backdrop {
  opacity: 0;
  transition: opacity var(--duration-fade) var(--ease-out) 200ms;
}
.sheet.is-closing .sheet__panel {
  translate: 120% 0 0;
  rotate: y -10deg;
  transition:
    translate var(--duration-sheet-out) var(--ease-out),
    rotate var(--duration-tilt) var(--ease-out) 100ms;
}
.sheet.is-closing .sheet__item { opacity: 1; translate: 0 0; }

@media (prefers-reduced-motion: reduce) {
  .sheet .sheet__backdrop,
  .sheet .sheet__panel,
  .sheet .sheet__item { transition: none !important; }
}

.sheet__head > :last-child { margin-left: auto; } /* Close sits right, with or without a label */

/* Menu content inside a sheet: links turn accent on hover. */
.menu-links { display: flex; flex-direction: column; gap: var(--space-2); }
.menu-link {
  display: inline-flex;
  align-items: center;
  transition: color 0.3s var(--ease-out);
}
.menu-link:hover { color: var(--color-accent); }

/* Not-yet-live entries: dimmed, not a link, with a small accent "coming soon" note. */
.menu-link--soon { cursor: default; }
.menu-link--soon:hover { color: inherit; }
.menu-link--soon > :not(.tag) { opacity: 0.45; }
.menu-link--soon > .tag { margin-left: var(--space-5); }

/* ---- Intro (js/intro.js) -------------------------------------------------
   html.is-intro      → start poses (set in <head> before first paint)
   html.is-intro-play → everything transitions home, each with --intro-delay
   Both classes are removed when the intro is over.                          */
.intro-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-block: 0.06em;    /* room for accents and the period, */
  margin-block: -0.06em;    /* without changing the line box     */
}
.intro-word__inner { display: inline-block; }

/* One motion language for the whole page (intro, scroll reveals, menu):
   words rise out of a mask, labels scramble, everything else rises by
   --reveal-distance, all over --duration-reveal with --ease-out.
   Only the slider cards deal in sideways, along their scroll direction. */
.is-intro [data-intro="words"]:not(.is-split) { opacity: 0; }
.is-intro [data-intro="scramble"] { opacity: 0; }
.is-intro [data-intro="rise"] { opacity: 0; translate: 0 var(--reveal-distance); }
.is-intro [data-intro="deal"] > * { opacity: 0; translate: calc(4 * var(--reveal-distance)) 0; }
/* Snap points follow transformed children: without this a scroll-snap track
   would scroll along with the shifted start pose and jump back afterwards. */
.is-intro [data-intro="deal"] { scroll-snap-type: none; }
.is-intro .intro-word__inner { translate: 0 110%; }
.is-intro .ascii-field { opacity: 0; }

/* The ASCII field simply fades in, slower than the rest, from the very start. */
.is-intro-play .ascii-field {
  opacity: 1;
  transition: opacity calc(var(--duration-reveal) * 2) var(--ease-out);
}

.is-intro-play [data-intro="rise"],
.is-intro-play [data-intro="deal"] > *,
.is-intro-play .intro-word__inner {
  opacity: 1;
  translate: 0 0;
  transition:
    opacity var(--duration-reveal) var(--ease-out),
    translate var(--duration-reveal) var(--ease-out);
  transition-delay: var(--intro-delay, 0ms);
}

/* ---- Reveal on scroll (js/reveal.js) -------------------------------------
   html.js-reveal → start poses until an element gets .is-revealed.
   .is-revealing only lives while the entrance plays, so the element's own
   transitions (e.g. a button's hover colour) are back afterwards.           */
.js-reveal [data-reveal="scramble"]:not(.is-revealed) { opacity: 0; }
.js-reveal [data-reveal="rise"]:not(.is-revealed) { opacity: 0; translate: 0 var(--reveal-distance); }
.js-reveal [data-reveal="stagger"]:not(.is-revealed) > * { opacity: 0; translate: 0 var(--reveal-distance); }
.js-reveal [data-reveal="words"]:not(.is-split) { opacity: 0; }
.js-reveal [data-reveal="words"]:not(.is-revealed) .intro-word__inner { translate: 0 110%; }
.js-reveal [data-reveal="clip"]:not(.is-revealed) { clip-path: inset(100% 0 0 0); }
.js-reveal [data-reveal="clip"]:not(.is-revealed) img { scale: 1.4; }

[data-reveal="rise"].is-revealing,
[data-reveal="stagger"].is-revealing > *,
[data-reveal="words"].is-revealing .intro-word__inner {
  transition:
    opacity var(--duration-reveal) var(--ease-out),
    translate var(--duration-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal="clip"].is-revealing {
  transition: clip-path calc(var(--duration-reveal) * 1.5) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal="clip"].is-revealing img {
  transition: scale calc(var(--duration-reveal) * 2) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

/* ---- CTA block ----------------------------------------------------------- */
.cta-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  padding: calc(var(--space-8) + var(--space-1)) var(--space-5) calc(var(--space-16) + var(--space-1));
  background: var(--color-surface-sunken);
  text-align: center;
}

/* ---- Accordion (native <details>) --------------------------------------- */
.accordion {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.accordion__summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  list-style: none;
  cursor: pointer;
}
.accordion__summary::-webkit-details-marker { display: none; }
.accordion__summary:hover .accordion__title { text-decoration: underline; text-underline-offset: 4px; }
.accordion__panel { padding: var(--space-12) 0 var(--space-6); }
