/* Velho landing page.
 *
 * Two families, used for two jobs and never mixed up: Newsreader carries every
 * section heading, so each section opens like a chapter; Geist carries the hero
 * statement and all body copy, at one size, everywhere. Navy is the only text
 * colour — muted greys are reserved for fine print and labels.
 *
 * Self-hosted fonts only (CSP allows font-src 'self'). */

@font-face {
  font-family: "Geist"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/fonts/geist-regular.woff2") format("woff2");
}
@font-face {
  font-family: "Geist"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/fonts/geist-medium.woff2") format("woff2");
}
@font-face {
  font-family: "Geist"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("/fonts/geist-semibold.woff2") format("woff2");
}
@font-face {
  font-family: "Newsreader"; font-style: normal; font-weight: 300 500; font-display: swap;
  src: url("/fonts/newsreader.woff2") format("woff2");
}

:root {
  --sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --serif: "Newsreader", Georgia, "Times New Roman", serif;

  --ink: #0a1b34;
  --paper: #f4f1ea;
  --white: #fbfaf6;
  --light: #fffaf1;
  --muted: #6d746f;
  --green: #717b60;
  --signal: #9b4034;
  --line: rgba(10, 27, 52, 0.14);
  --line-dark: rgba(255, 250, 241, 0.18);

  /* One body size for the whole page; card headings are exactly 1.5x it. */
  --body: 17px;
  --card-title: calc(var(--body) * 1.5);

  --shell-max: 1140px;
  --shell-pad: clamp(22px, 5vw, 56px);
  --header-h: 74px;
  --radius: 3px;
}

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 12px);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--body);
  font-weight: 400;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

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

a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
  border-radius: var(--radius);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 12px 18px;
  background: var(--ink);
  color: var(--light);
  text-decoration: none;
}
.skip:focus { left: 8px; top: 8px; }

/* Every content column on the page — including the header — resolves to this,
   so the logo's left edge lines up with every heading below it. */
.shell {
  width: min(100%, calc(var(--shell-max) + (2 * var(--shell-pad))));
  margin-inline: auto;
  padding-inline: var(--shell-pad);
}

/* ============================== BUTTONS ============================== */

.button {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 11px 26px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 180ms ease, color 180ms ease, transform 180ms ease;
}

.button--small { min-height: 38px; padding: 9px 18px; font-size: 14px; }
.button--primary { background: var(--ink); color: var(--light); }
.button--primary:hover { background: #16305a; }
.button--light { background: var(--light); color: var(--ink); }
.button--light:hover { background: #ffffff; }

/* ============================== HEADER ============================== */

.site-header {
  position: fixed;
  z-index: 100;
  inset: 0 0 auto 0;
  height: var(--header-h);
  transition: background-color 240ms ease, backdrop-filter 240ms ease,
    border-color 240ms ease, transform 220ms ease;
  border-bottom: 1px solid transparent;
}

.site-header.is-scrolled {
  background: rgba(244, 241, 234, 0.86);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}

.site-header__inner {
  height: 100%;
  display: flex;
  align-items: center;
  gap: 32px;
}

.brand { display: block; text-decoration: none; margin-right: auto; }
.brand__logo { width: 118px; height: auto; }

.site-nav {
  display: flex;
  gap: 30px;
}

.site-nav a {
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  color: var(--ink);
  opacity: 0.72;
  transition: opacity 160ms ease;
}

.site-nav a:hover { opacity: 1; }

/* =============================== HERO =============================== */

.hero {
  position: relative;
  isolation: isolate;
  overflow: clip;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-items: center;
  padding-top: var(--header-h);
  background: var(--paper);
}

/* The Bauhaus ribbons. Faintness is baked into the SVG's stroke rather than
   applied here, so the knockouts that make one ribbon pass in front of another
   stay fully opaque against the paper.

   `cover` is load-bearing, not a default: the motif has to overflow the hero on
   both axes so every ribbon runs off the edge of the screen. Sizing it to fit
   would letterbox the artwork and leave each ribbon visibly stopping in mid-air
   where the image ends. */
.hero__motif {
  position: absolute;
  z-index: -1;
  inset: 0;
  background: url("assets/bauhaus/hero.svg?v=8") no-repeat 50% 50%;
  background-size: cover;
  pointer-events: none;
}

.hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding-block: clamp(56px, 9vw, 96px);
}

.hero h1 {
  max-width: 15ch;
  margin: 0;
  font-family: var(--sans);
  font-size: clamp(42px, 7.4vw, 92px);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.02;
  text-wrap: balance;
}

.hero__lede {
  max-width: 58ch;
  margin: clamp(22px, 3vw, 30px) 0 clamp(34px, 4vw, 44px);
  font-size: clamp(17px, 1.5vw, 20px);
  line-height: 1.6;
  color: rgba(10, 27, 52, 0.78);
  text-wrap: pretty;
}

/* ========================= PARALLAX PHOTO BAND ========================= */

/* clip-path makes the band a containing block for its own fixed-position
   photograph, so the photo locks to the viewport and the band acts as a moving
   window onto it. No scroll handler involved. */
.band {
  position: relative;
  height: min(76vh, 640px);
  clip-path: inset(0);
  background: var(--ink);
}

.band picture {
  position: fixed;
  inset: 0;
  display: block;
  width: 100%;
  height: 100vh;
}

.band img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.82) contrast(1.02);
}

/* A portrait source in a wide band: bias the crop up so the faces stay in
   frame rather than the table in front of them. */
.band--tall img { object-position: 50% 42%; }

/* ============================== SECTIONS ============================== */

.section {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(88px, 11vw, 148px);
}

.section__head {
  max-width: 720px;
  margin-bottom: clamp(48px, 6vw, 76px);
}

/* Serif section openers. Light weight and tight leading at this size is what
   makes them read as a chapter title rather than a banner. */
.display {
  max-width: 17ch;
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(38px, 5.4vw, 66px);
  font-weight: 400;
  letter-spacing: -0.018em;
  line-height: 1.08;
  text-wrap: balance;
}

.section__lede {
  max-width: 58ch;
  margin: clamp(20px, 2.4vw, 28px) 0 0;
  font-size: clamp(16.5px, 1.3vw, 18.5px);
  line-height: 1.62;
  color: rgba(10, 27, 52, 0.76);
  text-wrap: pretty;
}

/* The numbered badge in front of each card heading. */
.marker {
  display: block;
  margin-bottom: 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--green);
}

/* Shared card heading size: exactly 1.5x body copy. */
.problem__list h3,
.nutshell__steps h3,
.project h3 {
  margin: 0 0 10px;
  font-family: var(--sans);
  font-size: var(--card-title);
  font-weight: 600;
  letter-spacing: -0.018em;
  line-height: 1.25;
  text-wrap: balance;
}

/* =============================== PROBLEM =============================== */

.problem { background: var(--paper); }

/* Short enough to sit on one line, and it should: the 17ch cap that keeps the
   longer headings from running wide would break this one in half. */
.problem .display { max-width: none; }

.problem__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 40px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.problem__list li {
  padding-top: 26px;
  border-top: 1px solid var(--line);
}

.problem__list p {
  margin: 0;
  color: rgba(10, 27, 52, 0.76);
  line-height: 1.62;
}

.sources {
  margin: clamp(48px, 6vw, 72px) auto 0;
  width: fit-content;
  text-align: center;
  font-size: 12.5px;
  color: var(--muted);
}

.sources__label {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* One source per line — three citations side by side read as a single run-on
   sentence at this size. */
.sources ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 6px;
}

.sources a {
  color: var(--muted);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.sources a:hover { color: var(--ink); }

/* ============================== NUTSHELL ============================== */

/* The one inverted section: this is who Velho is, so it is stated on navy. */
.nutshell {
  background: var(--ink);
  color: var(--light);
}

/* Full-bleed element with the artwork pinned to the right and sized to the
   panel's exact height, so the U's two ends leave through the right of the
   screen and nothing is cut inside the section. No mask. */
.nutshell__motif {
  position: absolute;
  z-index: -1;
  inset: 0;
  background: url("assets/bauhaus/nutshell.svg?v=8") no-repeat 100% 0;
  background-size: auto 100%;
  pointer-events: none;
}

.nutshell__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(48px, 7vw, 104px);
  align-items: start;
}

/* Held in view while the four steps scroll past it. */
.nutshell__aside {
  position: sticky;
  top: calc(var(--header-h) + clamp(28px, 6vw, 72px));
}

.nutshell .display { color: var(--light); }
.nutshell .section__lede { color: rgba(255, 250, 241, 0.72); }
.nutshell .marker { color: #aab696; }

.nutshell__steps {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line-dark);
}

.nutshell__steps li {
  padding-block: clamp(30px, 4vw, 42px);
  border-bottom: 1px solid var(--line-dark);
}

.nutshell__steps h3 { color: var(--light); }

.nutshell__steps p {
  max-width: 54ch;
  margin: 0;
  color: rgba(255, 250, 241, 0.72);
  line-height: 1.62;
}

/* ================================ YEAR ================================ */

.year { background: var(--white); }

/* A twelve-column month grid. Each row is a class of work; each item inside a
   row is one named project, placed with --from/--to. --label-from/--label-to
   give the name a box symmetric around its bar, widened only as far as the
   neighbouring projects allow, so names can never collide. */

.plan {
  --plan-label: clamp(150px, 15vw, 186px);
  --plan-gap: clamp(20px, 2.6vw, 34px);
  --plan-bar: 18px;
  --plan-rule: rgba(10, 27, 52, 0.11);
  --plan-paper: var(--white);
  /* one navy family for Velho's own delivery; it deepens with project size */
  --plan-velho-1: #33547a;
  --plan-velho-2: #1d3757;
  --plan-velho-3: var(--ink);
}

.plan__scroll {
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.plan__grid {
  position: relative;
  min-width: 780px;
  padding-bottom: 26px;
}

/* One continuous month grid behind every row, closed off on the right. */
.plan__grid::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0 0 0 calc(var(--plan-label) + var(--plan-gap));
  border-right: 1px solid var(--plan-rule);
  background-image: repeating-linear-gradient(
    to right,
    var(--plan-rule) 0 1px,
    transparent 1px calc(100% / 12)
  );
  pointer-events: none;
}

.plan__axis,
.plan__row {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: var(--plan-label) minmax(0, 1fr);
  column-gap: var(--plan-gap);
  align-items: end;
  min-width: 0;
}

.plan__track {
  display: grid;
  min-width: 0;
  grid-template-columns: repeat(12, minmax(0, 1fr));
}

.plan__axis {
  padding-bottom: 10px;
  border-bottom: 1px solid var(--ink);
}

.plan__axis-title,
.plan__track--axis span {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.plan__track--axis span {
  grid-column: var(--from);
  box-sizing: border-box;
  min-width: 0;
  padding-left: 6px;
}

.plan__row { padding-block: clamp(14px, 1.6vw, 19px); }

.plan__row-label {
  margin: 0 0 -2px;
  align-self: end;
  font-size: clamp(15px, 1.5vw, 17px);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.012em;
  color: var(--ink);
}

.plan__item { display: contents; }

.plan__item-name {
  position: relative;
  box-sizing: border-box;
  min-width: 0;
  grid-row: 1;
  grid-column: var(--label-from) / var(--label-to);
  align-self: end;
  justify-self: center;
  max-width: 100%;
  margin: 0 0 9px;
  padding: 2px 10px;
  background: var(--plan-paper);
  text-align: center;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* A short tick down from the name to the bar it belongs to — the labels are
   centred over their bars, so this is the only cue tying the two together. */
.plan__item-name::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -9px;
  width: 1px;
  height: 9px;
  background: var(--plan-shade);
  opacity: 0.45;
}

.plan__row { --plan-shade: var(--plan-velho-3); }
.plan__row--continuous { --plan-shade: var(--green); }
.plan__row--quick { --plan-shade: var(--plan-velho-1); }
.plan__row--small { --plan-shade: var(--plan-velho-2); }
.plan__row--large { --plan-shade: var(--plan-velho-3); }
.plan__row--partner { --plan-shade: var(--signal); }

.plan__bar {
  grid-row: 2;
  grid-column: var(--from) / var(--to);
  min-width: 0;
  max-width: 100%;
  height: var(--plan-bar);
  /* an equal inset at both ends also divides two back-to-back projects */
  margin-inline: 2px;
  border-radius: var(--radius);
  background: var(--plan-shade);
}


.plan__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  margin: 0;
  padding-top: 18px;
  border-top: 1px solid var(--ink);
  list-style: none;
}

.plan__legend li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13px;
  color: rgba(10, 27, 52, 0.72);
}

.plan__key { width: 26px; height: 11px; flex: none; border-radius: 3px; }
.plan__key--mapping { background: var(--green); }
.plan__key--partner { background: var(--signal); }

/* the Velho key stands for the whole navy family, so it shows all three */
.plan__key--velho {
  background: linear-gradient(
    to right,
    var(--plan-velho-1) 0 33.34%,
    var(--plan-velho-2) 33.34% 66.67%,
    var(--plan-velho-3) 66.67%
  );
}

.plan__hint {
  display: none;
  margin: 12px 0 18px;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.plan.is-scrollable .plan__hint { display: block; }

/* The chart is a chronology, so it draws left to right across every row at
   once — month 1 of all five lanes, then month 2, and so on — rather than one
   lane at a time. --draw is the month index home.js reads off each bar.

   Keyframes rather than transitions: a transition triggered by a class toggle
   can skip to its end state when the start state was never painted, which is
   easy to hit this far down the page. `both` also holds the start state
   through the delay, so nothing flashes in early. */

@keyframes plan-draw {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}

@keyframes plan-name {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: none; }
}

.plan--animate .plan__bar { clip-path: inset(0 100% 0 0); }
.plan--animate .plan__item-name { opacity: 0; }

.plan--animate.is-revealed .plan__bar {
  animation: plan-draw 420ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
  animation-delay: calc(var(--from) * 90ms);
}

/* the continuous lane spans the year, so it fills for as long as the year does */
.plan--animate.is-revealed .plan__row--continuous .plan__bar {
  animation-duration: 1150ms;
}

.plan--animate.is-revealed .plan__item-name {
  animation: plan-name 320ms ease both;
  animation-delay: calc((var(--from) * 90ms) + 150ms);
}

/* ============================== PROJECTS ============================== */

.projects { background: var(--white); }

.projects__motif {
  position: absolute;
  z-index: -1;
  top: 0;
  right: 0;
  width: min(46%, 560px);
  aspect-ratio: 1;
  /* Square element, square artwork, so `cover` is an exact fit: the ribbon's
     two ends land on the section's top edge and the viewport's right edge
     rather than stopping somewhere inside the artwork. No mask — it would
     dissolve the lines before they got out of the frame. */
  background: url("assets/bauhaus/corner.svg?v=8") no-repeat 100% 0;
  background-size: cover;
  pointer-events: none;
}

.projects__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(28px, 3.4vw, 48px) clamp(20px, 2.6vw, 34px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.project__art {
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  margin-bottom: 22px;
  padding: 26px;
  border-radius: var(--radius);
  overflow: hidden;
}

.project__art--blue { background: linear-gradient(152deg, #eef2f9 0%, #dde6f4 100%); }
.project__art--rose { background: linear-gradient(152deg, #fbefed 0%, #f6dfdb 100%); }
.project__art--sand { background: linear-gradient(152deg, #f7f3e9 0%, #ece4d3 100%); }
.project__art--green { background: linear-gradient(152deg, #eff2ea 0%, #e0e7d8 100%); }

/* Direct child only — the mockups inside .project__art are full of <p>s of
   their own, and they set their own much smaller type. */
.project > p {
  margin: 0;
  max-width: 40ch;
  color: rgba(10, 27, 52, 0.76);
  font-size: 15.5px;
  line-height: 1.6;
}

/* --- the little abstractions inside each project tile ------------------- */

.mock {
  width: 100%;
  max-width: 260px;
  font-size: 11px;
}

.mock__line {
  display: block;
  width: var(--w, 100%);
  height: 6px;
  margin-block: 7px;
  border-radius: 3px;
  background: rgba(10, 27, 52, 0.16);
}

.mock__card,
.mock--message,
.mock__field,
.mock__bubble {
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 6px 20px rgba(10, 27, 52, 0.07);
}

.mock--message { padding: 14px 16px 12px; }

.mock__to {
  margin: 0 0 10px;
  font-size: 10.5px;
  font-weight: 500;
  color: rgba(10, 27, 52, 0.62);
}

.mock__chip {
  margin: 12px 0 0;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--green);
}

.mock--quote {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
}

.mock__card { padding: 12px; }

.mock__arrow {
  width: 18px;
  height: 1px;
  background: rgba(10, 27, 52, 0.3);
  position: relative;
}

.mock__arrow::after {
  content: "";
  position: absolute;
  right: 0;
  top: -2.5px;
  border: 3px solid transparent;
  border-left-color: rgba(10, 27, 52, 0.3);
}

.mock__figure {
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.mock--rows { display: grid; gap: 8px; }

.mock__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.9);
}

.mock__row .mock__line { margin-block: 0; flex: 1; }

.mock__tick,
.mock__flag {
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
}

.mock__tick { background: rgba(113, 123, 96, 0.45); }
.mock__flag { background: rgba(155, 64, 52, 0.5); }
.mock__row.is-flagged { box-shadow: inset 0 0 0 1px rgba(155, 64, 52, 0.28); }

.mock--chat { display: grid; gap: 10px; }

.mock__bubble { padding: 11px 13px; width: 82%; }
.mock__bubble--in { justify-self: start; border-bottom-left-radius: 2px; }
.mock__bubble--out {
  justify-self: end;
  border-bottom-right-radius: 2px;
  background: rgba(10, 27, 52, 0.9);
}
.mock__bubble--out .mock__line { background: rgba(255, 250, 241, 0.42); }

.mock--chart {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  height: 110px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(10, 27, 52, 0.18);
}

.mock__bar {
  flex: 1;
  height: var(--h);
  border-radius: 3px 3px 0 0;
  background: rgba(10, 27, 52, 0.24);
}

.mock__bar--peak { background: var(--ink); }

.mock__field {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 15px;
}

.mock__caret {
  width: 2px;
  height: 13px;
  flex: none;
  background: var(--green);
}

.mock__ask {
  margin: 0;
  font-size: 11.5px;
  color: rgba(10, 27, 52, 0.66);
}

/* =============================== PRICING =============================== */

.pricing { background: var(--paper); }

/* Full-bleed element, artwork sized to the section's exact height and pinned
   right. The hairpin enters and leaves through the top, so both ends run off
   the section boundary; nothing crosses the artwork's left or right edge, which
   would otherwise be a visible cut in the middle of the section. */
.pricing__motif {
  position: absolute;
  z-index: -1;
  inset: 0;
  background: url("assets/bauhaus/loop.svg?v=8") no-repeat 100% 0;
  background-size: auto 100%;
  pointer-events: none;
}

/* Three separate cards rather than columns divided by rules: each plan is its
   own object, every card is opaque (so the motif behind them never shows
   through), and Core is stated in navy — the same "this is the Velho answer"
   move the nutshell panel makes. */
.tiers {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 1.8vw, 24px);
  align-items: stretch;
}

.tier {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(30px, 3.2vw, 40px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
}

.tier--core {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--light);
}

.tier__flag {
  position: absolute;
  top: 0;
  right: clamp(30px, 3.2vw, 40px);
  transform: translateY(-50%);
  padding: 5px 12px;
  border-radius: var(--radius);
  /* Navy on sage, not light-on-olive: the label sits half on the navy card, and
     a light fill is the only way it stays legible against both. */
  background: #aab696;
  color: var(--ink);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.tier h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.tier__price {
  margin: 22px 0 0;
  font-size: clamp(28px, 3vw, 38px);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.05;
}

.tier__price span {
  color: var(--muted);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0;
}

.tier--core .tier__price span { color: rgba(255, 250, 241, 0.6); }

.tier__text {
  margin: 18px 0 30px;
  color: rgba(10, 27, 52, 0.76);
  font-size: 15.5px;
  line-height: 1.58;
}

.tier--core .tier__text { color: rgba(255, 250, 241, 0.78); }

/* The card is the affordance, so the action is a full-width button rather than
   a link tucked in the corner. */
.tier__link {
  margin-top: auto;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 20px;
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  color: var(--ink);
  font-size: 14.5px;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 180ms ease, color 180ms ease;
}

.tier__link:hover { background: var(--ink); color: var(--light); }

.tier--core .tier__link {
  border-color: transparent;
  background: var(--light);
  color: var(--ink);
}

.tier--core .tier__link:hover { background: #ffffff; }

/* =============================== CONTACT =============================== */

.contact { background: var(--white); }

.contact__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(340px, 0.85fr);
  gap: clamp(48px, 7vw, 96px);
  align-items: start;
}

.booking-card {
  margin-top: clamp(32px, 4vw, 44px);
  padding: clamp(26px, 3vw, 34px);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--light);
}

.booking-card h3 {
  margin: 0 0 10px;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.booking-card p {
  margin: 0;
  color: rgba(255, 250, 241, 0.76);
  font-size: 15.5px;
  line-height: 1.58;
}

.booking-card__meta {
  margin: 16px 0 22px !important;
  font-size: 12.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 250, 241, 0.54) !important;
}

.contact__form {
  padding: clamp(28px, 3vw, 38px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
}

.contact__form-head { margin-bottom: 26px; }

.contact__form-head h3 {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.contact__form-head p {
  margin: 0;
  color: rgba(10, 27, 52, 0.72);
  font-size: 15px;
  line-height: 1.55;
}

.contact__form label {
  display: block;
  margin-bottom: 16px;
  font-size: 14px;
  font-weight: 500;
}

.contact__form label > span {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.contact__form label small { color: var(--muted); font-size: 12px; font-weight: 400; }

.contact__form input,
.contact__form textarea {
  width: 100%;
  margin-top: 8px;
  padding: 13px 14px;
  border: 1px solid rgba(10, 27, 52, 0.22);
  border-radius: var(--radius);
  outline: none;
  background: rgba(255, 255, 255, 0.6);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  line-height: 1.4;
}

.contact__form textarea { min-height: 112px; resize: vertical; }

.contact__form input:focus,
.contact__form textarea:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

.contact__form .button { width: 100%; margin-top: 6px; }
.contact__form .button:disabled { cursor: wait; opacity: 0.62; }

.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.form-status {
  margin: 16px 0 0;
  font-size: 14px;
  line-height: 1.5;
  text-align: center;
  color: rgba(10, 27, 52, 0.78);
}

.form-status.is-success { color: #33603a; }

.form-alt { margin: 14px 0 0; text-align: center; font-size: 13px; color: var(--muted); }
.form-alt a { color: var(--ink); text-underline-offset: 3px; }

/* =============================== FOOTER =============================== */

.site-footer { padding-block: 34px; background: var(--paper); }

.site-footer__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 28px;
}

.site-footer img { width: auto; height: 34px; }

.site-footer p {
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--muted);
}

.site-footer > div > a:last-child {
  justify-self: end;
  font-size: 13px;
  text-decoration: none;
  color: var(--ink);
}

.site-footer > div > a:last-child:hover { text-decoration: underline; text-underline-offset: 4px; }

/* ============================ SCROLL REVEAL ============================ */

/* Cards enter as their section comes up. home.js stamps --i for the stagger
   and only adds .reveal-ready when it is going to drive them, so with JS off
   or motion reduced the content is simply already visible. */
.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
}

.reveal-ready [data-reveal].is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 620ms cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: calc(var(--i, 0) * 110ms);
}

/* ============================== RESPONSIVE ============================== */

@media (max-width: 1080px) {
  .projects__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 940px) {
  :root { --header-h: 64px; }

  .site-nav { display: none; }

  .nutshell__grid,
  .contact__grid {
    grid-template-columns: 1fr;
  }

  /* Nothing to stick against once the columns stack. */
  .nutshell__aside { position: static; }

  .display { max-width: 20ch; }

  .problem__list { grid-template-columns: 1fr; gap: 0; }
  .problem__list li { padding-block: 28px; }
  .problem__list li:last-child { border-bottom: 1px solid var(--line); }

  .band { height: min(58vh, 460px); }
}

@media (max-width: 900px) {
  .plan {
    /* fixed, not the vw-based clamp: inside the scroll region the container is
       wider than the viewport, so vw would under-size the label column */
    --plan-label: 140px;
    --plan-gap: 16px;
    --plan-bar: 13px;
  }

  .plan__grid { min-width: 664px; padding-bottom: 18px; }
  .plan__axis { padding-bottom: 8px; }
  .plan__axis-title,
  .plan__track--axis span { font-size: 10px; letter-spacing: 0.08em; }
  .plan__track--axis span { padding-left: 5px; }
  .plan__row { padding-block: 12px; }
  .plan__row-label { font-size: 13px; }
  .plan__item-name { margin-bottom: 8px; padding: 2px 7px; font-size: 12.5px; }
  .plan__row--quick .plan__item-name {
    grid-column: var(--mobile-label-from) / var(--mobile-label-to);
    padding-inline: 4px;
  }
  .plan__bar { border-radius: var(--radius); }
}

@media (max-width: 760px) {
  .site-header { will-change: transform; }
  .site-header.is-scroll-hidden { transform: translateY(calc(-100% - 1px)); }
}

@media (max-width: 700px) {
  :root { --body: 16.5px; }

  .hero { min-height: 88vh; min-height: 88svh; }
  .hero h1 { max-width: 13ch; font-size: clamp(36px, 10vw, 52px); }
  /* Scaled up rather than down on narrow screens: fewer, larger curves in
     frame reads calmer behind the headline than the whole composition does. */
  .hero__motif { background-size: auto 185%; }

  .projects__grid { grid-template-columns: 1fr; }
  .project__art { aspect-ratio: 16 / 10; }

  /* Sections are far taller at this width, so a motif sized to the full height
     spreads into a wall of near-vertical lines. Shrinking it keeps the shape
     readable — safe because none of these ribbons exit through the edge being
     pulled in (nutshell and pricing exit right and top respectively). */
  .nutshell__motif,
  .pricing__motif { background-size: auto 52%; }
  .projects__motif { width: min(72%, 340px); }

  .tiers { grid-template-columns: 1fr; gap: 30px; }

  .band { height: min(52vh, 380px); }

  .site-footer__inner { grid-template-columns: 1fr auto; }
  .site-footer p { display: none; }
}

@media (max-width: 430px) {
  .site-header__inner { gap: 12px; }
  .brand__logo { width: 104px; }
  .button:not(.button--small) { width: 100%; }
  /* At 320px, keep each two-month quick-win label near 120px wide. The chart
     stays inside its own horizontal scroller rather than compressing titles. */
  .plan {
    --plan-label: 112px;
    --plan-gap: 12px;
  }
  .plan__grid { min-width: 840px; }
  .plan__row--quick .plan__item-name {
    inline-size: 100%;
  }
  .site-footer__inner { grid-template-columns: 1fr; }
  .site-footer > div > a:last-child { justify-self: start; }
}

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

  .button { transition: none; }
  .site-header { transition-duration: 0s; }

  /* The photo bands stop tracking the viewport and just sit in place. */
  .band picture { position: absolute; height: 100%; }

  .plan--animate .plan__bar,
  .plan--animate.is-revealed .plan__bar,
  .plan--animate .plan__item-name,
  .plan--animate.is-revealed .plan__item-name {
    clip-path: none;
    opacity: 1;
    transform: none;
    animation: none;
  }

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