/*
 * All styles other than the design tokens. Uses only the custom properties from tokens.css for
 * colour, spacing and radius — no hex values anywhere in this file. (Before base/01.3, the
 * monogram avatars' braces were one documented exception; real team photos replaced them, so
 * that exception no longer applies.)
 */

/* ---------- Fonts ---------- */

@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-variable.woff2") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* ---------- Reset & base ---------- */

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

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

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

body,
h1,
h2,
h3,
p,
ul,
ol,
figure {
  margin: 0;
}

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

img {
  max-width: 100%;
  display: block;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-family-mono);
  font-size: var(--font-body-size);
  line-height: var(--font-body-line-height);
  font-weight: var(--font-body-weight);
}

a {
  color: var(--link);
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ---------- Layout helpers ---------- */

.container {
  max-width: 1152px;
  margin-inline: auto;
  padding-inline: var(--space-4);
}

@media (min-width: 768px) {
  .container {
    padding-inline: var(--space-6);
  }
}

/* "Sections are 64px apart on desktop, 48px on mobile" (space-16 / space-12) is the gap between
   one section's content and the next's, not each section's own padding. Splitting the token in
   half on each side, top and bottom, makes two adjoining sections sum to the full token value. */
.section,
.hero {
  padding-block: var(--space-6);
  /* Nav links jump straight to these ids; without this, the sticky 72px header covers the
     section label the visitor just clicked through to. */
  scroll-margin-top: 88px;
}

@media (min-width: 768px) {
  .section,
  .hero {
    padding-block: var(--space-8);
  }
}

/* The full-bleed colour bands are a visual break in their own right, so they get a more
   generous padding of their own rather than the halved inter-section gap above. */
.how-it-works,
.learn-band,
.site-footer {
  padding-block: var(--space-12);
}

@media (min-width: 768px) {
  .how-it-works,
  .learn-band,
  .site-footer {
    padding-block: var(--space-16);
  }
}

.section-label {
  font-family: var(--font-family-mono);
  font-size: var(--font-label-size);
  line-height: var(--font-label-line-height);
  font-weight: var(--font-label-weight);
  letter-spacing: var(--font-label-letter-spacing);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: var(--space-6);
}

/* ---------- Buttons ---------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-0);
  border: 1px solid transparent;
  font-family: var(--font-family-mono);
  font-size: var(--font-button-size);
  line-height: var(--font-button-line-height);
  font-weight: var(--font-button-weight);
  letter-spacing: var(--font-button-letter-spacing);
  text-decoration: none;
  cursor: pointer;
}

.button-primary {
  background: var(--cyanotype);
  border-color: var(--cyanotype);
  color: var(--on-cyanotype);
}

.button-primary:hover {
  background: var(--cyanotype-deep);
  border-color: var(--cyanotype-deep);
}

.button-secondary {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}

.button-secondary:hover {
  background: var(--paper-raised);
}

/* ---------- Motion: reveal on scroll + hover lift (base/01.4, D53) ---------- */

/* The hidden/offset state only exists once reveal.js has confirmed motion is allowed (it adds
   reveal-ready to <html>). Without it — JS off, or prefers-reduced-motion — every [data-reveal]
   element is simply visible, exactly as it is without this feature at all.
   --reveal-delay (base/01.5): reveal.js sets this per element for the stagger, instead of the
   `transition-delay` property directly — that property has a single value that applies to every
   transitioned property, which delayed the hover response along with the reveal (D54). Scoping
   the delay to a variable used only in the reveal entries below fixes that: hover keeps its own
   explicit 0ms delay wherever it appears. The `, 0ms` fallback covers any [data-reveal] element
   reveal.js never touched (no data-reveal-group; it only sets this per group member). */
.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(var(--reveal-offset));
  transition: opacity var(--motion-reveal) var(--motion-ease-out) var(--reveal-delay, 0ms),
              transform var(--motion-reveal) var(--motion-ease-out) var(--reveal-delay, 0ms);
}

.reveal-ready [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* Problem cards, service rows, steps and team cards also lift on hover (see each section below).
   Their transition needs to cover background-color/translate too. A `transition` declaration
   fully replaces any other `transition` on the same element rather than merging with it, so this
   can't be split across two separate rules without one clobbering the other — the more specific
   rule right after this one folds both concerns into one list for exactly these elements.
   --hover-duration (base/01.5, D54): asymmetric timing — 80ms reacting to hover, 200ms easing
   back out on leave. A transition runs with whichever duration is in effect *after* the change,
   so the fast value only needs setting on :hover (per section below); this is the "at rest"/leave
   value. .team-photo's own transition (Team section) reads this same variable by inheritance. */
.problem-card,
.service-row,
.step,
.team-card {
  --hover-duration: var(--motion-hover-out);
  transition: background-color var(--hover-duration) var(--motion-ease-out) 0ms,
              translate var(--hover-duration) var(--motion-ease-out) 0ms;
}

.reveal-ready [data-reveal].problem-card,
.reveal-ready [data-reveal].service-row,
.reveal-ready [data-reveal].step,
.reveal-ready [data-reveal].team-card {
  transition: opacity var(--motion-reveal) var(--motion-ease-out) var(--reveal-delay, 0ms),
              transform var(--motion-reveal) var(--motion-ease-out) var(--reveal-delay, 0ms),
              background-color var(--hover-duration) var(--motion-ease-out) 0ms,
              translate var(--hover-duration) var(--motion-ease-out) 0ms;
}

@media (prefers-reduced-motion: reduce) {
  .problem-card,
  .service-row,
  .step,
  .team-card {
    translate: none;
  }
}

/* ---------- Header ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--paper);
  border-bottom: 1px solid var(--grid);
}

/* min-height, not height: at 768px+ the row of content is always exactly 72px tall, giving the
   sticky bar its spec'd height, but below 768px this same element also holds the opened mobile
   nav panel (it wraps onto a second row there, see the max-width query below), which needs the
   header to grow instead of clipping it. */
.header-inner {
  min-height: 72px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.logo-link {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

.logo {
  width: 216px;
  height: auto;
}

@media (min-width: 768px) {
  .logo {
    width: 298px;
  }
}

.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-0);
  cursor: pointer;
  flex-shrink: 0;
}

.nav-toggle-icon {
  width: 20px;
  height: 20px;
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linecap: square;
  fill: none;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nav-list {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nav-list a {
  font-size: var(--font-meta-size);
  line-height: var(--font-meta-line-height);
  font-weight: var(--font-meta-weight);
  letter-spacing: var(--font-meta-letter-spacing);
  color: var(--ink-muted);
  text-decoration: none;
  white-space: nowrap;
}

.nav-list li {
  flex-shrink: 0;
}

.nav-list a:hover {
  color: var(--cyanotype);
}

/* The 4 nav links + CTA button are tight against the 720px content width right at the 768px
   breakpoint (where the logo also jumps to its full 298px). A smaller horizontal padding on the
   header's own "Book a call" button, only here, keeps it on one line at that width. */
@media (min-width: 768px) {
  .nav-cta {
    padding-inline: var(--space-3);
    white-space: nowrap;
    flex-shrink: 0;
  }
}

@media (max-width: 767.98px) {
  .header-inner {
    flex-wrap: wrap;
  }

  /* Below 768px, the nav-toggle button and the collapsed state only exist once menu.js has run
     (see the .js-enabled rules below). Without it, .site-nav keeps its default flex layout, just
     wrapped onto its own row: stacked and always visible, per the prompt's no-JS requirement. */
  .site-nav {
    order: 3;
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-4);
    padding-block: var(--space-4);
  }

  .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }

  .nav-cta {
    width: 100%;
  }

  .js-enabled .nav-toggle {
    display: inline-flex;
  }

  .js-enabled .site-nav {
    display: none;
  }

  .js-enabled .site-nav.is-open {
    display: flex;
  }
}

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

.hero {
  position: relative;
  overflow: hidden;
}

/* Faint plus-mark drawing grid, hero only, 24px pitch, in the --grid token colour. url() can't
   reference a CSS variable, so the value is inlined here, percent-encoded, inside the data URI. */
.hero::before,
.hero::after {
  content: "";
  position: absolute;
  /* 24px bigger on every side than the hero itself, so the drift animation below never exposes
     an empty edge as it shifts the pattern around. .hero's own overflow: hidden clips it back. */
  inset: -24px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M12 8v8M8 12h8' stroke='%23d5dde7' stroke-width='1' fill='none'/%3E%3C/svg%3E");
  background-repeat: repeat;
  pointer-events: none;
  z-index: 0;
  will-change: transform, opacity;
}

/* The second layer, offset by half a pitch, so its crosses sit between the first layer's. */
.hero::after {
  background-position: 12px 12px;
}

@media (prefers-reduced-motion: no-preference) {
  .hero::before,
  .hero::after {
    animation: hero-grid-shimmer 6s ease-in-out infinite alternate,
               hero-grid-drift 20s ease-in-out infinite alternate;
  }

  /* A negative delay of half the shimmer's duration starts this layer already mid-cycle, so the
     two layers shimmer in opposite phase — a twinkle, not a unison pulse. The drift stays in
     sync between the two (no delay on the second animation), so the crosses move together. */
  .hero::after {
    animation-delay: -3s, 0s;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Static grid only: .hero::before at its default full opacity (no animation ever touches it
     here), .hero::after hidden entirely rather than shown as a second motionless layer. */
  .hero::after {
    display: none;
  }
}

@keyframes hero-grid-shimmer {
  from {
    opacity: 0.35;
  }
  to {
    opacity: 1;
  }
}

@keyframes hero-grid-drift {
  from {
    transform: translate(0, 0);
  }
  to {
    transform: translate(12px, 8px);
  }
}

.hero .container {
  position: relative;
  z-index: 1;
}

.hero-title {
  font-family: var(--font-family-display);
  font-size: var(--font-h1-size-mobile);
  line-height: var(--font-h1-line-height);
  font-weight: var(--font-h1-weight);
  letter-spacing: var(--font-h1-letter-spacing);
  max-width: 800px;
  margin-bottom: var(--space-4);
}

@media (min-width: 768px) {
  .hero-title {
    font-size: var(--font-h1-size);
  }
}

.hero-subheadline {
  font-size: var(--font-hero-subheadline-size);
  line-height: var(--font-hero-subheadline-line-height);
  font-weight: var(--font-hero-subheadline-weight);
  color: var(--ink-muted);
  max-width: 640px;
  margin-bottom: var(--space-8);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

/* ---------- Problems we solve ---------- */

.problems-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
  align-items: stretch;
}

@media (min-width: 640px) {
  .problems-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .problems-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.problem-card {
  background: var(--paper-raised);
  border-left: 2px solid var(--redline);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.problem-card h3 {
  font-family: var(--font-family-display);
  font-size: var(--font-card-title-size);
  line-height: var(--font-card-title-line-height);
  font-weight: var(--font-card-title-weight);
}

.problem-card p {
  font-size: var(--font-body-size);
  line-height: var(--font-body-line-height);
  color: var(--ink-muted);
}

@media (hover: hover) and (pointer: fine) {
  .problem-card:hover {
    background: var(--cyanotype-tint);
    translate: 0 var(--hover-lift);
    --hover-duration: var(--motion-hover-in);
  }
}

/* ---------- Services ---------- */

.services-list {
  display: flex;
  flex-direction: column;
}

.service-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  padding-block: var(--space-8);
  /* The hover fill (below) shouldn't hug the text: this pushes the content in by space-4, then
     pulls the row's own box back out by the same amount, so the text sits exactly where it did
     before, while the row's background/border box now extends 16px beyond it on each side. At
     375px the container's own side padding is also 16px, so the two exactly cancel and the fill
     reaches the viewport edge without overflowing it. */
  padding-inline: var(--space-4);
  margin-inline: calc(-1 * var(--space-4));
}

.service-row + .service-row {
  border-top: 1px solid var(--grid);
}

@media (hover: hover) and (pointer: fine) {
  .service-row:hover {
    background: var(--paper-raised);
    translate: 0 var(--hover-lift);
    --hover-duration: var(--motion-hover-in);
  }
}

@media (min-width: 1024px) {
  .service-row {
    grid-template-columns: 28fr 40fr 32fr;
    gap: var(--space-8);
    align-items: start;
  }
}

.service-title {
  font-family: var(--font-family-display);
  font-size: var(--font-h3-size);
  line-height: var(--font-h3-line-height);
  font-weight: var(--font-h3-weight);
  margin-bottom: var(--space-2);
}

.service-format {
  font-size: var(--font-format-size);
  line-height: var(--font-format-line-height);
  font-weight: var(--font-format-weight);
  letter-spacing: var(--font-format-letter-spacing);
  color: var(--ink-muted);
}

.service-text {
  font-size: var(--font-body-size);
  line-height: var(--font-body-line-height);
  color: var(--ink-muted);
}

.service-includes {
  font-size: var(--font-you-get-size);
  line-height: var(--font-you-get-line-height);
  font-weight: var(--font-you-get-weight);
  color: var(--ink-muted);
}

.you-get-label {
  font-weight: var(--font-you-get-label-weight);
  color: var(--ink);
}

/* ---------- How it works ---------- */

.how-it-works {
  background: var(--cyanotype-deep);
  color: var(--on-deep);
  /* The band's step dividers have no token in design-tokens.json. Proposed default: on-deep at
     25% opacity (see REPORT.md), derived from the token rather than a hard-coded colour. */
  --step-divider: color-mix(in srgb, var(--on-deep) 25%, transparent);
}

.how-it-works .section-label {
  color: var(--on-deep);
}

.steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
}

.step {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

@media (hover: hover) and (pointer: fine) {
  .how-it-works .step:hover {
    background: color-mix(in srgb, var(--on-deep) 6%, transparent);
    translate: 0 var(--hover-lift);
    --hover-duration: var(--motion-hover-in);
  }
}

@media (max-width: 767.98px) {
  .step + .step {
    border-top: 1px solid var(--step-divider);
    padding-top: var(--space-6);
  }
}

@media (min-width: 768px) {
  .steps {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-8);
  }

  .step + .step {
    border-left: 1px solid var(--step-divider);
    padding-left: var(--space-8);
  }
}

.step-number {
  font-family: var(--font-family-mono);
  font-size: var(--font-display-size);
  line-height: var(--font-display-line-height);
  font-weight: 400;
}

.step-title {
  font-family: var(--font-family-display);
  font-size: var(--font-h3-size);
  line-height: var(--font-h3-line-height);
  font-weight: var(--font-h3-weight);
}

.step-text {
  font-size: var(--font-body-size);
  line-height: var(--font-body-line-height);
}

/* ---------- Team ---------- */

.team-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
}

@media (min-width: 768px) {
  .team-grid {
    grid-template-columns: repeat(2, 1fr);
    align-items: stretch;
  }
}

.team-card {
  background: var(--paper-raised);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.team-photo {
  width: 96px;
  height: 96px;
  border-radius: var(--radius-full);
  object-fit: cover;
  display: block;
  /* --hover-duration isn't set here: it inherits whatever value is currently in effect on the
     ancestor .team-card (200ms at rest, 80ms on hover), so the photo's own zoom speeds up and
     slows down in step with the card's lift, without needing its own :hover rule for the timing. */
  transition: transform var(--hover-duration) var(--motion-ease-out) 0ms;
}

@media (hover: hover) and (pointer: fine) {
  /* No background change on team cards (unlike the other hoverable blocks): the lift plus the
     photo zoom below are their hover response. Hovering anywhere on the card triggers the zoom,
     not just the photo itself. */
  .team-card:hover {
    translate: 0 var(--hover-lift);
    --hover-duration: var(--motion-hover-in);
  }

  .team-card:hover .team-photo {
    /* 96px × 1.2 ≈ 115px: about 10px of growth per side, staying inside the card's 24px padding. */
    transform: scale(1.2);
  }
}

@media (prefers-reduced-motion: reduce) {
  .team-photo {
    transform: none;
  }
}

.team-name {
  font-family: var(--font-family-display);
  font-size: var(--font-team-name-size);
  line-height: var(--font-team-name-line-height);
  font-weight: var(--font-team-name-weight);
}

.team-title {
  font-size: var(--font-meta-size);
  line-height: var(--font-meta-line-height);
  font-weight: var(--font-meta-weight);
  letter-spacing: var(--font-meta-letter-spacing);
  color: var(--cyanotype);
}

.team-bio {
  font-size: var(--font-body-size);
  line-height: var(--font-body-line-height);
  color: var(--ink-muted);
}

.team-link {
  font-size: var(--font-meta-size);
  line-height: var(--font-meta-line-height);
  font-weight: 500;
  letter-spacing: var(--font-meta-letter-spacing);
  margin-top: auto;
  align-self: flex-start;
}

/* ---------- Learn with us ---------- */

.learn-band {
  background: var(--cyanotype-tint);
}

.learn-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}

.learn-content p {
  font-size: var(--font-learn-text-size);
  line-height: var(--font-learn-text-line-height);
  font-weight: var(--font-learn-text-weight);
  color: var(--ink-muted);
}

.tag {
  display: inline-block;
  font-family: var(--font-family-mono);
  font-size: var(--font-tag-size);
  line-height: var(--font-tag-line-height);
  font-weight: var(--font-tag-weight);
  letter-spacing: var(--font-tag-letter-spacing);
  text-transform: uppercase;
  color: var(--ink-muted);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 6px var(--space-3);
}

/* ---------- Contact ---------- */

.contact-text {
  font-size: var(--font-contact-text-size);
  line-height: var(--font-contact-text-line-height);
  font-weight: var(--font-contact-text-weight);
  color: var(--ink-muted);
  max-width: 640px;
}

.contact-heading {
  font-family: var(--font-family-display);
  font-size: var(--font-contact-heading-size-mobile);
  line-height: var(--font-contact-heading-line-height);
  font-weight: var(--font-contact-heading-weight);
  margin-bottom: var(--space-4);
}

@media (min-width: 768px) {
  .contact-heading {
    font-size: var(--font-contact-heading-size);
  }
}

.contact-email {
  margin-top: var(--space-8);
}

/* Unused until contact-form/02 brings the form back (D48). */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 640px;
  margin-top: var(--space-8);
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.form-field label {
  font-size: var(--font-form-label-size);
  line-height: var(--font-form-label-line-height);
  font-weight: var(--font-form-label-weight);
  letter-spacing: var(--font-form-label-letter-spacing);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.form-field input,
.form-field textarea {
  font-size: var(--font-input-size);
  line-height: var(--font-input-line-height);
  font-weight: var(--font-input-weight);
  color: var(--ink);
  background: var(--paper-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
}

.form-field textarea {
  min-height: 160px;
  resize: vertical;
}

.contact-form .button {
  align-self: flex-start;
}

.contact-alt {
  font-size: var(--font-contact-alt-size);
  line-height: var(--font-contact-alt-line-height);
  font-weight: var(--font-contact-alt-weight);
  color: var(--ink-muted);
  margin-top: var(--space-4);
}

/* ---------- Footer ---------- */

.site-footer {
  background: var(--cyanotype-deep);
  color: var(--on-deep);
  font-size: var(--font-meta-size);
  line-height: var(--font-meta-line-height);
  font-weight: var(--font-meta-weight);
  letter-spacing: var(--font-meta-letter-spacing);
}

.site-footer a {
  color: var(--on-deep);
}

.footer-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

@media (min-width: 768px) {
  .footer-inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.footer-right {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}
