/* ==========================================================================
   Basalt · one-page site
   Every colour, size, space and timing comes from tokens.css, which mirrors
   tokens.json in the brand guidelines. Change a token there, not here.

   The three rules from the guidelines:
   1. Void first: at least 40% of every screen stays empty.
   2. One dot: signal orange appears once per view, as a point.
   3. Show the work: real sketches, drawings and factory photos only.
   ========================================================================== */

/* ------------------------------------------------------------------ base -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 80px;
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
p { margin: 0; }
h1, h2, h3, h4 { margin: 0; color: var(--ink); text-wrap: balance; }

::selection { background: var(--navy); color: var(--on-navy); }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  padding: var(--space-3) var(--space-5);
  background: var(--navy); color: var(--on-navy);
}
.skip:focus { left: var(--space-3); top: var(--space-3); }

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

/* ------------------------------------------------------------------ type -- */

.label {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 16px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.display {
  font-size: var(--fs-display);
  line-height: 1.05;
  font-weight: 400;
  letter-spacing: -.035em;
}
.h2 {
  font-size: var(--fs-h2);
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: -.025em;
}
.h3 {
  font-size: var(--fs-h3);
  line-height: 1.23;
  font-weight: 500;
  letter-spacing: -.015em;
}
.h4 {
  font-size: var(--fs-h4);
  line-height: 1.37;
  font-weight: 600;
  letter-spacing: -.01em;
}
.focus-xl {
  font-family: var(--font-serif);
  font-size: var(--fs-focus-xl);
  line-height: 1.17;
  font-weight: 400;
  letter-spacing: -.01em;
  text-wrap: balance;
}
.number {
  font-family: var(--font-serif);
  font-size: var(--fs-number);
  line-height: 1;
  font-weight: 400;
  letter-spacing: -.02em;
}
.lead {
  font-size: var(--fs-lead);
  line-height: 1.57;
  color: var(--ink-soft);
}
.spec {
  font-family: var(--font-mono);
  font-size: var(--fs-spec);
  line-height: 20px;
  color: var(--ink-muted);
}
.fig {
  font-family: var(--font-mono);
  font-size: var(--fs-figure);
  line-height: 16px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* the one orange point per view */
.dot { color: var(--signal); }

/* ---------------------------------------------------------------- layout -- */

.wrap {
  width: 100%;
  max-width: calc(var(--container) + var(--margin) * 2);
  margin-inline: auto;
  padding-inline: var(--margin);
}

.section { padding-block: var(--section); }
.paper   { background: var(--surface-paper); }

/* section opener: label, 24px, headline, 32px, lead, 64px, content */
.head { max-width: 46rem; margin-bottom: var(--space-8); }
.head .label + * { margin-top: var(--space-5); }
.head .lead { margin-top: var(--space-6); max-width: 38rem; }

/* n-others offset: on desktop, text starts at column 5 of 12 */
@media (min-width: 1024px) {
  .offset { margin-left: calc((100% + var(--gutter)) / 12 * 4); }
}

/* --------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 48px;
  padding: 0 var(--space-5);
  border: 1px solid var(--action);
  border-radius: var(--radius-md);
  background: var(--action);
  color: var(--on-action);
  font-size: var(--fs-body-sm);
  font-weight: 500;
  transition: transform var(--dur-base) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
.btn:hover { transform: translateY(-2px); background: var(--navy-700); border-color: var(--navy-700); }
.btn-line { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn-line:hover { background: transparent; border-color: var(--ink); }

.arw { width: 16px; height: 16px; flex: none; transition: transform var(--dur-base) var(--ease-out); }
.btn:hover .arw, .link:hover .arw { transform: translateX(4px); }

/* text link: a 2px signal line draws in from the left */
.link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding-bottom: 4px;
  font-size: var(--fs-body-sm);
  font-weight: 500;
  background: linear-gradient(var(--signal), var(--signal)) 0 100% / 0 2px no-repeat;
  transition: background-size var(--dur-base) var(--ease-out);
}
.link:hover { background-size: 100% 2px; }

/* ---------------------------------------------------------------- header -- */

.top {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
.top.is-stuck {
  background: rgba(255, 255, 255, .92);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom-color: var(--line);
}
.top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  height: 72px;
}

/* logo lockup: wordmark cap height and gap are 40% of the mark height */
.logo {
  --mark: 28px;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--mark) * .4);
}
.logo img {
  width: var(--mark);
  height: var(--mark);
  mix-blend-mode: multiply;   /* the master PNG has a white ground */
}
.logo span {
  font-family: var(--font-logo);
  font-weight: 600;           /* Montserrat SemiBold, wordmark only */
  font-size: calc(var(--mark) * .4 / .7);
  line-height: 1;
  letter-spacing: .08em;
  color: var(--navy);
}

.nav { display: none; align-items: center; gap: var(--space-6); }
@media (min-width: 900px) { .nav { display: flex; } }
.nav a:not(.btn) {
  font-size: var(--fs-body-sm);
  color: var(--ink-soft);
  padding-block: 4px;
  background: linear-gradient(var(--ink), var(--ink)) 0 100% / 0 1px no-repeat;
  transition: color var(--dur-fast) var(--ease-out),
              background-size var(--dur-base) var(--ease-out);
}
.nav a:not(.btn):hover { color: var(--ink); }
.nav a:not(.btn).is-here { color: var(--ink); background-size: 100% 1px; }
.nav .btn { min-height: 40px; padding: 0 var(--space-4); }

.burger {
  display: grid;
  place-content: center;
  gap: 6px;
  width: 44px; height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
@media (min-width: 900px) { .burger { display: none; } }
.burger i {
  display: block;
  width: 22px; height: 1.5px;
  background: var(--ink);
  transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-fast);
}
.burger[aria-expanded="true"] i:first-child { transform: translateY(3.75px) rotate(45deg); }
.burger[aria-expanded="true"] i:last-child  { transform: translateY(-3.75px) rotate(-45deg); }

.menu {
  display: grid;
  grid-template-rows: 0fr;
  background: var(--surface);
  transition: grid-template-rows var(--dur-base) var(--ease-out);
}
.menu.is-open { grid-template-rows: 1fr; border-bottom: 1px solid var(--line); }
.menu > div { overflow: hidden; }
.menu a {
  display: block;
  padding: var(--space-4) var(--margin);
  border-top: 1px solid var(--line);
  font-size: var(--fs-lead);
}
@media (min-width: 900px) { .menu { display: none; } }

/* ------------------------------------------------------------------ hero -- */

.hero { padding-top: calc(72px + var(--space-9)); padding-bottom: var(--space-8); }
.hero .display { margin-top: var(--space-5); max-width: 14ch; }
.hero-foot {
  display: grid;
  gap: var(--space-6);
  margin-top: var(--space-7);
}
.hero-foot .lead { max-width: 30ch; }
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5); }
@media (min-width: 900px) {
  .hero-foot { grid-template-columns: 1fr auto; align-items: end; }
}

/* one picture of the product in context, nothing laid over it */
.duo { margin-top: var(--space-8); }
.duo-main {
  margin: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  aspect-ratio: 16 / 9;
  max-height: 82vh;
  width: 100%;
  background: var(--surface-sunk);
}
.duo-cap { margin-top: var(--space-3); text-align: right; }
.duo-main img, .frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease-out);
}
.duo-main:hover img, .frame:hover img { transform: scale(1.04); }

@media (max-width: 599px) {
  .duo-main { aspect-ratio: 4 / 5; }
  .duo-cap { text-align: left; }
}
@media (min-width: 600px) and (max-width: 899px) and (orientation: portrait) {
  .duo-main { aspect-ratio: 4 / 3; }
}

/* ----------------------------------------------------------------- facts -- */

.facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.fact { padding: var(--space-6) var(--space-5) var(--space-6) 0; }
.fact + .fact { padding-left: var(--space-5); border-left: 1px solid var(--line); }
/* "Worldwide" needs room: it takes a full row until three columns fit */
.fact:nth-child(3) { grid-column: 1 / -1; border-left: 0; padding-left: 0; border-top: 1px solid var(--line); }
.fact .number { font-size: clamp(2.25rem, 5vw, 4rem); }
.fact .label { display: block; margin-top: var(--space-3); }
.fact .label + .label { margin-top: var(--space-1); }
@media (min-width: 1320px) {   /* below this, "Worldwide" does not fit a third */
  .facts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .fact:nth-child(3) { grid-column: auto; border-left: 1px solid var(--line); padding-left: var(--space-5); border-top: 0; }
}

/* ------------------------------------------------------------------ idea -- */

.idea .focus-xl { max-width: 16ch; }
.pair figure { margin: 0; }
.pair {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-8);
  align-items: start;
}
@media (min-width: 700px) {
  .pair { grid-template-columns: 5fr 7fr; gap: var(--gutter); }
  .pair > :last-child { margin-top: var(--space-10); }
}
.frame {
  margin: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-sunk);
}
.frame.r34 { aspect-ratio: 3 / 4; }
.frame.r43 { aspect-ratio: 4 / 3; }
.frame.r11 { aspect-ratio: 1 / 1; }
.frame.r169 { aspect-ratio: 16 / 9; }
.frame.well { background: var(--surface); }
.frame.well img { object-fit: contain; padding: 4%; }
figure .fig, .fig-row { margin-top: var(--space-3); }

/* three short reasons, hairlines not boxes */
.reasons {
  display: grid;
  margin: var(--space-9) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.reasons li {
  display: grid;
  gap: var(--space-2) var(--gutter);
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--line);
}
.reasons p { color: var(--ink-soft); max-width: 44ch; }
@media (min-width: 900px) {
  .reasons li { grid-template-columns: 1fr 5fr 6fr; align-items: baseline; }
}

/* --------------------------------------------------------------- process -- */

/* The label sits above both columns, so the drawing centres on the
   headline-to-paragraph block a reader actually sees. */
.process .story-label { margin-bottom: var(--space-5); }

/* Markup: .story-head (headline, lead) and .story-live (icons, stage
   text, drawing). On desktop .story-live dissolves into the grid so the
   drawing spans both rows and stays centred on all the text. */
@media (min-width: 900px) {
  .process .story-grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: var(--space-8);
    row-gap: 0;
    align-items: start;
  }
  .process .story-live { display: contents; }
  .process .story-head { grid-column: 1; grid-row: 1; }
  .process .story-text { grid-column: 1; grid-row: 2; }
  .process .story-art  { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
}

/* Phones: the headline scrolls away as normal, then the icons, the stage
   text and the drawing pin together and the page scrolls through the
   five stages. Tapping an icon still jumps to that stage. */
@media (max-width: 899px) and (min-height: 640px) {
  .process[data-scroll] { height: 520vh; height: 520svh; padding-bottom: 0; }
  .process[data-scroll] .story-pin,
  .process[data-scroll] .story-pin > .wrap { height: 100%; }
  .process[data-scroll] .story-pin > .wrap { display: flex; flex-direction: column; }
  .process[data-scroll] .story-grid { flex: 1; display: flex; flex-direction: column; gap: var(--space-7); }
  .process[data-scroll] .story-live {
    position: sticky;
    top: 72px;
    min-height: calc(100vh - 72px);
    min-height: calc(100svh - 72px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-5);
    padding-block: var(--space-4);
    background: var(--surface);
  }
  .process[data-scroll] .story-tabs { margin: 0; }
  /* The pinned block is exactly one screen tall. The text and the note
     keep their size; the photo frame gives way if the screen is short,
     so nothing is ever pushed off the bottom. */
  .process[data-scroll] .story-live { height: calc(100vh - 72px); height: calc(100svh - 72px); }
  .process[data-scroll] .story-text { flex: none; }
  .process[data-scroll] .story-art.photos { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
  .process[data-scroll] .frame-well { flex: 0 1 auto; min-height: 0; }
  .process[data-scroll] .shot-cap { flex: none; }
}

/* ---- the photo frame: one photo at a time, never overlapping ----
   Photos sit whole inside a paper well (contain, not crop), so drawings
   and phone shots of any shape read as prints laid on a desk. */
.process .story-art.photos { background: none; border-radius: 0; overflow: visible; }
.process .frame-well {
  position: relative;
  aspect-ratio: 7 / 5;
  border-radius: var(--radius-md);
  background: var(--surface-paper);
  overflow: hidden;
  cursor: pointer;
}
.process .frame-well .shots { display: none; position: absolute; inset: 0; }
.process .frame-well .shots:first-child { display: block; }
.process .shot {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5%;
  opacity: 0;
}
.process .shot:first-child { opacity: 1; }
.process .shot img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  border-radius: var(--radius-md);
}
/* with the script running, only the active set and photo show */
.process.js .frame-well .shots { display: none; }
.process.js .frame-well .shots.on { display: block; }
/* The old photo leaves fast and the new one follows, so two photos are
   never half-visible on top of each other. */
.process.js .shot {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .2s var(--ease-out), transform 0s .2s;
}
.process.js .shot.on {
  opacity: 1;
  transform: none;
  transition: opacity .45s var(--ease-out) .15s, transform .6s var(--ease-out) .15s;
}

.process .shot-cap {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-3);
  min-height: 28px;
}
/* The note is plain body text: it changes with every photo, so it has to
   read at a glance. A short fade, never a wipe that hides half the words. */
.process .shot-note {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 24px;
  font-weight: 500;
  color: var(--ink);
  transition: opacity .3s var(--ease-out), transform .3s var(--ease-out);
}
.process .shot-note.from { opacity: 0; transform: translateY(4px); transition: none; }
.process .shot-count {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--fs-spec);
  letter-spacing: .06em;
  color: var(--ink-muted);
}
/* The narrowest phones: keep every note on one line. */
@media (max-width: 359px) {
  .process .shot-cap { gap: var(--space-2); }
  .process .shot-note { font-size: var(--fs-body-sm); }
}

/* More scroll per stage now that each stage holds up to five photos. */
@media (min-width: 900px) and (min-height: 700px) {
  .process[data-scroll] { height: 600vh; }
}
@media (max-width: 899px) and (min-height: 640px) {
  .process[data-scroll] { height: 600vh; height: 600svh; }
}
/* Shorter phones (an iPhone SE is 667 tall): a flatter frame and tighter
   gaps, so icons, text, photo and note all fit while pinned. */
@media (max-width: 899px) and (min-height: 640px) and (max-height: 760px) {
  .process .frame-well { aspect-ratio: 16 / 10; }
  .process[data-scroll] .story-live { gap: var(--space-4); padding-block: var(--space-2); }
  .process .shot { padding: 3%; }
}

@media (prefers-reduced-motion: reduce) {
  .process.js .shot, .process.js .shot.on { transform: none; transition: none; }
  .process .shot-note { transition: none; }
}

/* The five labels only fit where the icon row is wide enough: tablets
   (600-899) and desktops from 1280. On phones and on 900-1279 laptops,
   where the text column is narrow, they would run into each other
   (measured: 24px over at 900). Keep them for screen readers; the stage
   name is printed under the icons anyway. */
@media (max-width: 599px) { .process .story-tabs { max-width: none; } }
@media (max-width: 599px), (min-width: 900px) and (max-width: 1279px) {
  .process .story-tab span {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap;
  }
}
.process .story-lead { margin-top: var(--space-6); max-width: 34ch; }
.process .story-stage p:last-child { max-width: 38ch; }
@media (min-width: 900px) and (min-height: 700px) {
  .process[data-scroll] { padding: 0; }
  .process[data-scroll] .story-pin { padding-top: 72px; }
}
/* Laptop screens just tall enough to pin: a little less air around the
   icons, so the text column clears the header and the bottom edge. */
@media (min-width: 900px) and (min-height: 700px) and (max-height: 779px) {
  .process .story-tabs { margin-block: var(--space-5); }
}

/* -------------------------------------------------------------- services -- */

.services { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.service {
  display: grid;
  gap: var(--space-3) var(--gutter);
  padding: var(--space-7) 0;
  border-bottom: 1px solid var(--line);
}
.service p { color: var(--ink-soft); max-width: 40ch; }
@media (min-width: 900px) {
  .service { grid-template-columns: 1fr 5fr 6fr; align-items: baseline; }
}
.service .h3 { transition: transform var(--dur-base) var(--ease-out); }
.service:hover .h3 { transform: translateX(8px); }

/* ------------------------------------------------------------------ team -- */

.team {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-7) var(--gutter);
  margin: 0; padding: 0; list-style: none;
}
@media (min-width: 900px) { .team { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.team li { padding-top: var(--space-5); border-top: 1px solid var(--line); }
.team .label { display: block; margin-top: var(--space-2); }
.team p { margin-top: var(--space-4); font-size: var(--fs-body-sm); color: var(--ink-soft); max-width: 24ch; }

/* ------------------------------------------------------------------ work -- */

/* Two pictures side by side, never on top of each other. The small one
   starts lower and drifts faster, so the pair slides past itself as you
   scroll. Odd projects lead with the big picture, even ones mirror it. */
.projects { display: grid; gap: var(--space-10); }
.proj { display: grid; gap: var(--space-7); }

.proj-media { display: grid; gap: var(--space-6); align-items: start; }  /* 32px: more than the 18.4px the stacked pair can drift together */
.proj-media .big   { aspect-ratio: 4 / 3; }
.proj-media .small { aspect-ratio: 4 / 5; width: 58%; justify-self: end; }
@media (min-width: 700px) {
  .proj-media { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--gutter); }
  .proj-media .big   { grid-column: 1 / span 8; }
  .proj-media .small { grid-column: 9 / span 4; width: auto; margin-top: var(--space-9); }
  .proj:nth-child(even) .proj-media .big   { grid-column: 5 / span 8; grid-row: 1; }
  .proj:nth-child(even) .proj-media .small { grid-column: 1 / span 4; grid-row: 1; }
}

/* the title steps across, like n-others */
.proj-title {
  font-size: var(--fs-h1);
  line-height: 1.05;
  font-weight: 400;
  letter-spacing: -.03em;
  margin-top: var(--space-5);
}
.proj-title span { display: block; }
.proj-title span + span { padding-left: 1.4em; }

.proj-body p:not(.spec) { color: var(--ink-soft); max-width: 40ch; }
.proj-body .spec { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--line); max-width: 40ch; }
.proj-body { margin-top: var(--space-6); }
.award {
  display: inline-block;
  margin-top: var(--space-4);
  padding: 4px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--peach);
  color: var(--ember);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* desktop: name on the left four columns, the story from column five */
@media (min-width: 900px) {
  .proj-text { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--gutter); }
  .proj-head { grid-column: 1 / span 4; }
  .proj-body { grid-column: 5 / span 6; margin-top: 0; align-self: end; }  /* level with the foot of the title */
}

/* ----------------------------------------------------------------- motto -- */

/* The motto runs the full width of the screen, page margin to page
   margin, not just the 1280 grid. site.js sizes the type so the line
   fills that width exactly; the vw value below is the no-script fallback. */
.bleed { padding-inline: var(--margin); }

.motto-line {
  margin-top: var(--space-5);
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 4.8vw;            /* measured fit is 4.9vw; slightly under so it never overflows */
  line-height: 1.08;
  letter-spacing: -.02em;
  white-space: nowrap;
  text-wrap: nowrap;
}
.motto-line .fit { display: inline-block; }
.m-br { display: none; }
@media (max-width: 599px) {
  .motto-line { font-size: 8vw; }   /* measured fit is 8.2vw on two lines */
  .m-br { display: inline; }
}

/* the wordmark inside the motto keeps its own face: Montserrat SemiBold */
.wm {
  font-family: var(--font-logo);
  font-weight: 600;
  font-size: .82em;
  letter-spacing: .08em;
  color: var(--navy);
}
.js [data-fill] .wm.fw.lit { color: var(--navy); }

.motto .lead { margin-top: var(--space-7); max-width: 40ch; }

/* --------------------------------------------------------------- contact -- */

.contact { padding-block: var(--section); }
.contact .h2 { color: var(--ink); max-width: 18ch; }
.mail {
  display: inline-block;
  margin-top: var(--space-7);
  font-size: clamp(1.75rem, 5vw, 4rem);
  line-height: 1.1;
  letter-spacing: -.03em;
  color: var(--ink);
  word-break: break-word;
  background: linear-gradient(var(--signal), var(--signal)) 0 100% / 0 3px no-repeat;
  padding-bottom: 6px;
  transition: background-size var(--dur-base) var(--ease-out);
}
.mail:hover { background-size: 100% 3px; }
.contact-meta {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-9);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}
@media (min-width: 700px) { .contact-meta { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.contact-meta p:not(.label) { margin-top: var(--space-2); color: var(--ink-soft); }

/* ---------------------------------------------------------------- footer -- */

.foot { padding-block: var(--space-7); }
.foot-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
}
.foot .spec { color: var(--ink-muted); }

/* ---------------------------------------------------------------- motion -- */

/* Reveal: fade and rise 24px. Content is visible until the script runs. */
.js .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--dur-slow) var(--ease-out) var(--d, 0s),
              transform var(--dur-slow) var(--ease-out) var(--d, 0s);
}
.js .reveal.in { opacity: 1; transform: none; }

/* Drift: images move at their own speed, so pairs slide past each other.
   The script only feeds --drift; amplitude is set per image in the HTML. */
[data-drift] {
  transform: translate3d(0, var(--drift, 0px), 0);
  will-change: transform;
}

/* Focus fill: the statement fills word by word as it is read. */
.js [data-fill] .fw { color: var(--ink-faint); transition: color .35s var(--ease-out); }
.js [data-fill] .fw.lit { color: var(--ink); }


@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js [data-fill] .fw { color: var(--ink); }
  [data-drift] { transform: none; }
  *, *::before, *::after { transition-duration: .001ms !important; animation-duration: .001ms !important; }
}

/* ------------------------------------------------------------- screens -- */

/* Big screens: the text stays on the 1280 grid, but the hero picture
   bleeds wider so it still reads as a panorama, not a column. */
@media (min-width: 1800px) {
  .hero .duo {
    --bleed: min(1760px, calc(100vw - var(--margin) * 4));
    width: var(--bleed);
    margin-left: calc((100% - var(--bleed)) / 2);
  }
}

/* Panoramic screens: keep the hero picture inside the window height and
   let the void do the work. */
@media (min-aspect-ratio: 2 / 1) and (min-width: 1200px) {
  .duo-main { max-height: 70vh; }
  .hero { padding-top: calc(72px + var(--space-8)); }
}

/* Short landscape windows: tighter hero so the picture is reachable. */
@media (max-height: 620px) and (orientation: landscape) {
  .hero { padding-top: calc(72px + var(--space-7)); }
  .duo-main { max-height: 78vh; }
}
