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

:root {
  --bg: #ffffff;
  --ink: #111111;
  --grey: #9C9C9C;
  --text: #111111;   /* = --ink */
  --muted: #9C9C9C;  /* = --grey */
  --border: transparent;   /* hairlines off (was #e5e5e5) — flip back to restore all dividers */
  --f: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --f-serif: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --h-size: clamp(2.25rem, 1.5rem + 3vw, 3.5rem);   /* one size for every section heading on home + About */
  --nav-h: 46px;
  /* Single-column gutter. Only ever applied below 901px — the three-column
     desktop regime keeps its own 2.5rem/1.5rem rhythm untouched. */
  --gutter: clamp(1.15rem, 4vw, 2.5rem);
  --pnav-h: 66px;   /* fixed prev/next bar on project pages */
  --accent: #A87C6E;   /* dusty rose */
  /* Grain field — the grey noise band shared by Selected work (.hz) and the
     contact footer (.ft-field). Defined once here so the two can't drift. */
  /* Gridded field — the light-grey graph paper shared by Services and the
     personal wall. Defined once here so the two can't drift. 44px cells. */
  --grid-bg: #E8E6E2;
  --grid-img:
    repeating-linear-gradient(0deg,  #ffffff 0 1px, transparent 1px 44px),
    repeating-linear-gradient(90deg, #ffffff 0 1px, transparent 1px 44px);
  --grain-bg: #d9d7d3;
  --grain-img: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='0.55'/%3E%3C/svg%3E");
}

html {
  scroll-behavior: smooth;
  /* No page ever scrolls sideways. Clip, not hidden — hidden would make this a
     scroll container and every sticky/pinned section would stop pinning. */
  overflow-x: clip;
}

body {
  font-family: var(--f);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* Headings are set in the serif; everything else stays in Inter. */
h1, h2, h3 { font-family: var(--f-serif); }

/* Cross-fade between pages where supported (Chrome, Edge). Other browsers
   navigate normally. */
@view-transition { navigation: auto; }

a { color: inherit; text-decoration: none; }
img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Keyboard focus — visible for tab users, invisible for mouse users */
:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Respect the OS "reduce motion" setting everywhere */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ══ Motion ══
   Three primitives, used everywhere:
     .rv                reveals on scroll — JS adds .in when it enters the viewport
     .line-mask > span  entrance: a line slides up from behind its own edge
     .fade-in           entrance: a soft fade + lift
   The two entrance types fire once <html> gets .ready (JS, next frame after
   load), staggered by a per-element --d. Everything is gated on html.js so a
   no-JS page renders plainly rather than staying blank. Nothing rotates,
   nothing bounces; the restraint is the point. All of it is switched off by
   the prefers-reduced-motion block above. */

:root {
  --ease: cubic-bezier(0.22, 1, 0.36, 1);   /* fast out, long settle */
  --dur: 0.65s;
  --out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);   /* the work index's reveal curve */
}

/* Read by screen readers and search engines, invisible on screen. For pages
   whose design has no visible <h1> — /work is a bare colour-flood menu. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Everything below is gated on html.js, which a one-line script in <head> sets
   before first paint. Without JS the page renders plainly — never blank. */
html.js .rv {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
html.js .rv.in { opacity: 1; transform: none; }

/* Entrance: a line slides up from behind its own edge */
.line-mask { display: block; overflow: hidden; }
.line-mask > span { display: block; }
html.js .line-mask > span { transform: translateY(105%); }
html.js .fade-in { opacity: 0; }

html.ready .line-mask > span {
  animation: rise 0.85s var(--ease) both;
  animation-delay: var(--d, 0s);
}
html.ready .fade-in {
  animation: fade 0.7s var(--ease) both;
  animation-delay: var(--d, 0s);
}

@keyframes rise { from { transform: translateY(105%); } to { transform: none; } }
@keyframes fade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ── Nav ── */
nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 200;
  height: var(--nav-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 0 1.5rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

.nav-logo { font-size: 1.05rem; font-weight: 700; letter-spacing: -0.01em; display: flex; align-items: center; gap: 0.35rem; }
.nav-logo a { font-style: normal; }

.nav-links { display: flex; align-items: center; font-size: 0.9rem; }
.nav-links a { color: var(--muted); transition: color 0.15s; position: relative; }
.nav-links a:hover { color: var(--text); }
.nav-links a.active { color: var(--text); font-weight: 500; }
.nav-links .sep { color: var(--muted); margin: 0 0.1rem; pointer-events: none; }

/* Underline grows from the left on hover and stays under the active link */
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.28s var(--ease);
}
.nav-links a:hover::after,
.nav-links a.active::after { transform: scaleX(1); }

/* ── Scroll progress (injected by main.js, mostly felt on long pages) ── */
#scroll-progress {
  position: fixed;
  top: var(--nav-h);
  left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--text);
  z-index: 199;
  pointer-events: none;
}

/* ── Images fade in as they decode, instead of popping ── */
html.js img.img-fade { opacity: 0; transition: opacity 0.6s var(--ease); }
html.js img.img-fade.loaded { opacity: 1; }

.nav-right { display: flex; align-items: center; justify-content: flex-end; gap: 1.25rem; }

.nav-cta {
  /* Button reset so the pill styles identically whether it's an <a> or <button> */
  font-family: inherit;
  cursor: pointer;
  font-size: 0.82rem;
  /* Filled black by default; hover inverts to an outline */
  background: var(--text);
  color: var(--bg);
  border: 1px solid var(--text);
  padding: 0.32rem 0.95rem;
  border-radius: 100px;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}
.nav-cta:hover { background: transparent; color: var(--text); border-color: var(--text); }

/* ── Layout ──
   The page itself scrolls. The side columns are sticky, so they sit still while
   the centre column moves — the same look the old fixed-grid + JS wheel handler
   produced, but with real scrolling: momentum, keyboard, scrollbar, and
   scroll-driven animation all work natively. */
.layout {
  display: grid;
  grid-template-columns: 20% 60% 20%;
  align-items: start;
  padding-top: var(--nav-h);
}

/* ── Left column ── */
.col-left {
  position: sticky;
  top: var(--nav-h);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 2rem 1.75rem;
  overflow: hidden;
  height: calc(100dvh - var(--nav-h));
}

.hero-name {
  font-family: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  font-size: clamp(46px, 6.4vw, 70px);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--ink);
}
/* Editorial flourish: the name reads in italic, the greeting stays upright */
.hero-name .name-italic { font-style: italic; }

.hero-name a { color: inherit; }

.left-bottom { display: flex; flex-direction: column; gap: 1.75rem; }

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

.services-list a {
  font-size: 0.85rem;
  color: var(--muted);
  padding: 0.75rem 0;
  border-top: 1px solid var(--border);
  transition: color 0.15s;
}
.services-list a:hover { color: var(--text); }

.social-icons { display: flex; flex-direction: column; gap: 1rem; }
.social-icons a svg { width: 17px; height: 17px; fill: var(--muted); display: block; transition: fill 0.15s; }
.social-icons a:hover svg { fill: var(--text); }

/* ── Center column ── */
.col-center { min-width: 0; }

/* ── Home: bio + work ──
   The bio sticks while the work list scrolls up and over it. These rules used to
   live in a <style> block inside index.html that shadowed this file; they were
   moved here on 2026-07-22 so there is one stylesheet, not two. */
.bio-section {
  position: sticky;
  top: var(--nav-h);
  z-index: 1;
  min-height: calc(100vh - var(--nav-h) - 17rem);
  padding: 2.5rem 2.5rem 3rem;
}

.bio-text {
  font-size: clamp(20px, 2.2vw, 24px);
  font-weight: 400;
  line-height: 1.35;
  color: var(--ink);
  max-width: 46ch;
  letter-spacing: -0.01em;
}
.bio-text .muted { color: var(--grey); }
.bio-text em { color: var(--muted); font-style: normal; }

/* Press feedback — every click on the site gets a little physical */
a, button { -webkit-tap-highlight-color: transparent; }
.nav-cta, .skill-tag, .services-list a, .nav-links a {
  transition: color 0.15s, border-color 0.2s, transform 0.12s var(--ease);
}
.nav-cta:active, .skill-tag:active { transform: scale(0.985); }

/* ── Marquee ── */
.marquee-wrap { background: var(--text); padding: 1.4rem 0; overflow: hidden; margin-top: 1rem; }
.marquee-track {
  display: flex;
  white-space: nowrap;
  width: max-content;
  animation: scroll 14s linear infinite;
  /* JS nudges this while the page is scrolling */
  animation-duration: var(--marquee-dur, 14s);
}
.marquee-wrap:hover .marquee-track { animation-play-state: paused; }
.marquee-track span { font-size: 3rem; font-weight: 700; color: #fff; letter-spacing: -0.02em; padding: 0 0.6rem; }
.marquee-track span.dot { opacity: 0.45; }

@keyframes scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ── Footer ── */
.center-footer {
  padding: 1.25rem 2.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--border);
}
.center-footer span, .center-footer a { font-size: 0.75rem; color: var(--muted); }
.center-footer a { border-bottom: 1px solid var(--border); }

/* ── Right column ── */
.col-right {
  position: sticky;
  top: var(--nav-h);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 1.75rem 1.5rem;
  overflow: hidden;
  height: calc(100dvh - var(--nav-h));
}

.right-top { display: flex; flex-direction: column; gap: 1rem; }

.right-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; }

.availability { font-size: 0.78rem; padding-top: 0.1rem; }

.right-photo { width: 46%; flex-shrink: 0; aspect-ratio: 3 / 4; overflow: hidden; background: #e5e5e5; }

.right-meta { display: flex; flex-direction: column; gap: 0.15rem; text-align: right; }
.right-meta span { font-size: 0.78rem; line-height: 1.55; }
.right-meta .muted { color: var(--muted); }

.right-bottom { display: flex; flex-direction: column; align-items: flex-end; gap: 0.25rem; }
/* Social icons now live here, as a right-aligned row above the email */
.right-bottom .social-icons { flex-direction: row; gap: 0.9rem; margin-bottom: 0.6rem; }
.right-bottom a { font-size: 0.75rem; color: var(--muted); transition: color 0.15s; }
.right-bottom a:hover { color: var(--text); }
.right-copy { font-size: 0.7rem; color: var(--muted); margin-top: 0.25rem; }

/* ── Info page ── */
.info-section { padding: 2.5rem 2.5rem; border-bottom: 1px solid var(--border); }
.info-section:last-child { border-bottom: none; }

.page-label { font-size: 0.7rem; color: var(--muted); letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 1.25rem; }

.info-heading {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin-bottom: 1.5rem;
}

.info-text { font-size: 0.9rem; color: #555; line-height: 1.85; margin-bottom: 1rem; }

/* ── About — random facts ──
   Image on the left, the list on the right; stacks under 900px. Every other
   fact picks up the accent so the column has some rhythm rather than reading
   as a flat block. */
/* Breaks out of the 60% centre column so the band spans the whole screen —
   the same escape the personal wall uses. html has overflow-x: clip, so the
   100vw can't open a horizontal scrollbar. */
.info-section.is-bleed { width: 100vw; margin-left: calc(50% - 50vw); padding-left: 0; padding-right: 0; }

/* Image runs flush to the left edge; only the text side keeps a gutter. */
.rf { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.5rem, 5vw, 4rem); align-items: center; }
.rf-body { padding-right: clamp(1.5rem, 5vw, 4rem); }

.rf-media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: #f4f4f4; }
.rf-media img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Placeholder while the image is pending — deliberately obvious, so it can't
   ship by accident. Delete it along with the div when the image lands. */
.rf-placeholder {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed #cfcfcf;
  color: var(--muted);
  font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase;
}

.rf-list { list-style: none; display: flex; flex-direction: column; gap: 0.8rem; }
.rf-list li { font-size: 0.95rem; line-height: 1.35; }
.rf-list li:nth-child(even) { color: var(--accent); }
.rf-list a { border-bottom: 1px solid currentColor; }

@media (max-width: 900px) {
  /* Stacked: the image still bleeds, the text gets a gutter on both sides */
  .rf { grid-template-columns: 1fr; gap: 1.5rem; }
  .rf-body { padding-left: var(--gutter); padding-right: var(--gutter); }
}

.skills-grid { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.5rem; }
.skill-tag {
  font-size: 0.75rem;
  border: 1px solid var(--border);
  padding: 0.28rem 0.8rem;
  border-radius: 100px;
  color: var(--text);
  transition: border-color 0.2s;
}
.skill-tag:hover { border-color: var(--text); }

/* ── Contact page ── */
.contact-section { padding: 2.5rem 2.5rem; }

.contact-big {
  font-size: var(--h-size);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.0;
  margin-bottom: 3rem;
}

.contact-big a { color: inherit; text-decoration: none; transition: opacity 0.2s; }
.contact-big a:hover { opacity: 0.5; }

.contact-rows { display: flex; flex-direction: column; gap: 0; }

.contact-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.1rem 0;
  border-top: 1px solid var(--border);
}

.contact-row:last-child { border-bottom: 1px solid var(--border); }

.contact-row-label { font-size: 0.72rem; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; }

.contact-row-value { font-size: 0.88rem; }
.contact-row-value a { border-bottom: 1px solid currentColor; padding-bottom: 1px; transition: opacity 0.2s; }
.contact-row-value a:hover { opacity: 0.5; }

/* ── Project detail page ── */
.project-detail-header {
  padding: 2rem 2.5rem 1.5rem;
  border-bottom: 1px solid var(--border);
}

.project-back {
  font-size: 0.75rem;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-bottom: 1.5rem;
  transition: color 0.15s;
}
.project-back:hover { color: var(--text); }

.project-detail-title {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 0.5rem;
}

.project-detail-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: 0.75rem;
}

.project-detail-cat { font-size: 0.8rem; color: var(--muted); }
.project-detail-year { font-size: 0.8rem; color: var(--muted); }

.project-detail-body { padding: 0 2.5rem; }

.project-full-image {
  width: 100%;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: #f2f2f2;
  margin: 1.5rem 0;
}

.project-full-image.tall { aspect-ratio: 4 / 3; }

.project-description {
  padding: 1.5rem 0;
  border-top: 1px solid var(--border);
  font-size: 0.9rem;
  color: #555;
  line-height: 1.85;
}

.project-nav-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.5rem 2.5rem;
  border-top: 1px solid var(--border);
  margin-top: 1rem;
}

.project-nav-link { font-size: 0.8rem; color: var(--muted); transition: color 0.15s; }
.project-nav-link:hover { color: var(--text); }

/* ── Project meta grid ── */
.project-meta-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--border);
  margin-top: 1rem;
}
.project-meta-item { padding: 1rem 1.5rem 1rem 0; }
.project-meta-item + .project-meta-item { padding-left: 1.5rem; border-left: 1px solid var(--border); }
.meta-label { font-size: 0.68rem; color: var(--muted); letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.3rem; }
.meta-value { font-size: 0.85rem; line-height: 1.5; }

/* ── Project sections ── */
.project-section { padding: 1.75rem 0; border-top: 1px solid var(--border); }
.section-label { font-size: 0.68rem; color: var(--muted); letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: 0.75rem; }
.section-text { font-size: 0.88rem; color: #555; line-height: 1.85; }
.section-text + .section-text { margin-top: 0.7rem; }

/* ── Scope row ── */
.scope-row { display: flex; gap: 0; margin-top: 1rem; }
.scope-item { flex: 1; padding: 1rem 0; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 0.3rem; }
.scope-item + .scope-item { border-left: 1px solid var(--border); padding-left: 1.5rem; }
.scope-num { font-size: 0.68rem; color: var(--muted); }
.scope-name { font-size: 0.88rem; }

/* ── Color swatches ── */
.swatch-row { display: flex; gap: 0.5rem; margin-top: 1rem; }
.swatch { flex: 1; }
.swatch-color { height: 56px; border-radius: 3px; }
.swatch-hex { font-size: 0.68rem; color: var(--muted); padding-top: 0.4rem; }
.swatch-name { font-size: 0.72rem; }

/* ── Type specimen ── */
.type-pair { margin-top: 1rem; }
.type-entry { padding: 1rem 0; border-top: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
.type-display-role { font-size: 0.68rem; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 0.25rem; }
.type-display-name { font-size: 0.88rem; }
.type-sample-serif { font-size: 1.8rem; font-weight: 400; line-height: 1; letter-spacing: 0.02em; }
.type-sample-sans { font-size: 1.4rem; font-weight: 400; line-height: 1; }

/* ── Logo grid (brand identity pages) ── */
.logo-variations-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-radius: 3px;
  overflow: hidden;
  margin-top: 1rem;
}
.logo-variation-cell {
  padding: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ── Case study slide images ── */
.slide-image { width: 100%; height: auto; display: block; margin: 1.25rem 0; }
.slide-image:first-child { margin-top: 0; }

/* ── Work detail page (3-column: title/cover/meta · visuals · concept-scope) ── */
.work-detail-title { font-size: 2.6rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1; margin-bottom: 1.5rem; }
.work-cover { width: 100%; aspect-ratio: 16 / 10; overflow: hidden; background: #f2f2f2; }
.work-cover img { width: 100%; height: 100%; object-fit: cover; }
.work-cover-cat { text-align: center; font-size: 0.78rem; color: var(--muted); margin-top: 0.8rem; }

.work-meta-rows { display: flex; flex-direction: column; }
.work-meta-row { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: 0.7rem 0; border-top: 1px solid var(--border); font-size: 0.82rem; }
/* The label holds its width and the value wraps beneath itself — long values
   (a list of tools, several roles) used to wrap back under the label and
   collide with it. */
.work-meta-row .k { color: var(--muted); flex: 0 0 auto; }
.work-meta-row .v { text-align: right; min-width: 0; }

.wd-center { padding: 0 2.5rem; }
.wd-sticky { position: sticky; top: var(--nav-h); z-index: 1; padding-top: 0.5rem; }
.work-lede { font-size: 1.7rem; font-weight: 500; line-height: 1.3; letter-spacing: -0.01em; color: var(--text); padding: 0.25rem 0 1.5rem; }
.work-livelink { display: flex; justify-content: space-between; align-items: baseline; padding: 1rem 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); font-size: 0.8rem; }
.work-livelink .copy { color: var(--muted); }
.work-visuals { position: relative; z-index: 2; background: var(--bg); padding: 1.5rem 0 0; display: flex; flex-direction: column; gap: 1rem; }
.work-visuals .slide-image { margin: 0; }

.work-nav { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; padding-top: 1.5rem; border-top: 1px solid var(--border); }
.work-nav a { display: block; }
.work-nav-label { font-size: 0.72rem; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 0.35rem; }
.work-nav-name { font-size: 0.9rem; color: var(--text); transition: opacity 0.15s; }
.work-nav a:hover .work-nav-name { opacity: 0.55; }
.work-nav-name.muted { color: var(--muted); }

/* ── Fixed prev/next bar, pinned to the bottom of the viewport ──
   Used on the four case-study pages. The page reserves --pnav-h at the bottom
   so nothing hides behind it. */
.project-navbar {
  position: fixed;
  /* top:auto cancels the top:0 the generic `nav` rule sets via `inset` —
     without it this bar renders at the top instead of the bottom. */
  top: auto;
  left: 0; right: 0; bottom: 0;
  z-index: 180;
  height: var(--pnav-h);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0 clamp(1.15rem, 4vw, 2.5rem);
  background: var(--bg);
  border-top: 1px solid var(--border);
  border-bottom: none;
}
.project-navbar a { display: block; min-width: 0; }
.project-navbar .work-nav-label { margin-bottom: 0.15rem; }
/* Keep each name on one line; ellipsis rather than overflow the bar */
.project-navbar .work-nav-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 42vw;
}

body.has-project-nav { padding-bottom: var(--pnav-h); }
/* On the layout (visual-identity) pages the side columns are viewport-height
   and sticky — shrink them so their bottom content clears the bar. */
body.has-project-nav .col-left,
body.has-project-nav .col-right { height: calc(100dvh - var(--nav-h) - var(--pnav-h)); }
@media (max-width: 900px) {
  body.has-project-nav .col-left,
  body.has-project-nav .col-right { height: auto; }
}

/* ── Work listing category filter ── */
.services-list a { cursor: pointer; }
.services-list a.active { color: var(--text); font-weight: 500; }
.work-empty { padding: 1.5rem 2.5rem; color: var(--muted); font-size: 0.85rem; }

/* ══ Responsive ══
   Four targets: 1440+ desktop · 1024 small laptop · 768 tablet · 375 phone.
   The three-column grid holds down to 901px, then stacks. */

/* ── Small laptop: give the centre column even more room ── */
@media (max-width: 1200px) {
  .layout { grid-template-columns: 18% 64% 18%; }
  .col-left { padding: 1.75rem 1.25rem; }
  .col-right { padding: 1.5rem 1.25rem; }
  .bio-section, .center-footer { padding-left: 1.75rem; padding-right: 1.75rem; }
  .wd-center { padding-left: 1.75rem; padding-right: 1.75rem; }
  .marquee-track span { font-size: 2.25rem; }
  .right-photo { width: 52%; }
}

/* ── Tablet / phone: single column ──
   Type below 901px is fluid rather than stepped: every clamp() here reaches
   its desktop value exactly at 900px, so nothing jumps as the columns stack,
   and nothing above 900px is touched. */
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  /* Nothing sticks once the columns stack */
  .col-left, .col-right {
    position: static;
    height: auto;
    border: none;
    border-bottom: 1px solid var(--border);
    padding: 2rem var(--gutter);
  }
  .col-right { border-top: 1px solid var(--border); }

  /* Nav: the CTA (copy-email) stays visible on mobile. The logo and links
     scale down to 375 rather than stepping, and the grid lets the middle
     track shrink so the CTA can never be pushed off the right edge. */
  nav {
    grid-template-columns: auto minmax(0, 1fr) auto;
    padding: 0 clamp(0.85rem, 0.68rem + 0.72vw, 1.5rem);
    column-gap: 0.5rem;
  }
  .nav-logo { font-size: clamp(0.75rem, 8.57px + 0.91vw, 1.05rem); }
  .nav-links {
    font-size: clamp(0.72rem, 9.46px + 0.55vw, 0.9rem);
    justify-content: center;
    min-width: 0;
  }
  .nav-cta {
    font-size: clamp(0.72rem, 0.66rem + 0.25vw, 0.82rem);
    padding: 0.32rem 0.75rem;
    display: inline-flex; align-items: center; min-height: 34px;
  }

  /* Horizontal social row saves vertical space above the work */
  .social-icons { flex-direction: row; gap: 1.5rem; margin: 1.5rem 0; }

  /* 44px minimum tap targets. The nav links and the CTA get theirs from a
     transparent ::before overlay rather than real padding, so the bar stays
     46px, the pill keeps its weight, and the link underline stays on the
     baseline where it belongs. */
  .services-list a { padding: 0.9rem 0; }
  .social-icons a { display: flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }
  .nav-links a::before,
  .nav-cta::before {
    content: "";
    position: absolute;
    top: 50%; left: 0; right: 0;
    height: 44px;
    transform: translateY(-50%);
  }
  .nav-links a::before { left: -0.3rem; right: -0.3rem; }
  .nav-cta { position: relative; }

  .right-photo { width: 60%; }
  .work-detail-title { font-size: clamp(1.6rem, 0.89rem + 3.04vw, 2.6rem); }
  .work-lede { font-size: clamp(1.2rem, 0.84rem + 1.52vw, 1.7rem); }
  .hero-name { font-size: clamp(36px, 20.57px + 4.11vw, 70px); }
  .wd-center { padding: 0 var(--gutter); }
  .wd-sticky { top: var(--nav-h); }
  /* Reaches 2.25rem at 900 — the value the 1200px rule already sets there. */
  .marquee-track span { font-size: clamp(1.5rem, 0.97rem + 2.28vw, 2.25rem); }

  /* Nothing sticks once the columns stack */
  .bio-section { position: static; min-height: 0; padding-bottom: 2.5rem; }
}

/* ── Phone: layout only. Type is already fluid from the block above. ── */
@media (max-width: 560px) {
  .col-left, .col-right { padding: 1.5rem var(--gutter); }
  .bio-section, .center-footer,
  .info-section, .contact-section, .wd-center { padding-left: var(--gutter); padding-right: var(--gutter); }
  .project-meta-grid { grid-template-columns: 1fr; }
  .project-meta-item + .project-meta-item { padding-left: 0; border-left: none; border-top: 1px solid var(--border); }
  .scope-row { flex-direction: column; }
  .scope-item + .scope-item { border-left: none; padding-left: 0; }
  .logo-variations-grid { grid-template-columns: 1fr; }
  .right-meta, .right-bottom { text-align: left; align-items: flex-start; }
}

/* ══ Visual feed ══
   Reuses the existing tokens: --border hairlines, --muted/--text, --ease,
   the .nav-cta pill, the .section-label eyebrow, and the 16px grid gutter. */

.section-label .dia { color: var(--text); }   /* diamond in ink, label stays muted */

.vfeed-heading {
  font-size: var(--h-size);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

/* ── Homepage band (full-width, sits after the 3-column screen) ── */
.vfeed { padding: 96px 0; border-top: 1px solid var(--border); overflow: hidden; }
.vfeed-head { padding: 0 2.5rem; margin-bottom: 40px; }
.vfeed-head-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; }
.vfeed-head .vfeed-heading { max-width: 30ch; }   /* ch is narrow in the serif; ~the old 22ch of Inter */
.vfeed-more { flex-shrink: 0; white-space: nowrap; }

/* Full-bleed strip: a seamless marquee — the boxes scroll left continuously.
   The 5-item set is duplicated in JS so translateX(-50%) loops without a seam.
   Per-item margin (not flex gap) keeps the track periodic so the loop is clean. */
.vfeed-strip {
  display: flex;
  align-items: flex-start;
  width: max-content;
  animation: vfeed-scroll 45s linear infinite;
}
.vfeed-strip .vfeed-item { margin-right: 16px; }
@keyframes vfeed-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  /* No auto-scroll — fall back to a static, trackpad-scrollable strip */
  .vfeed-strip { animation: none; overflow-x: auto; scrollbar-width: none; }
  .vfeed-strip::-webkit-scrollbar { display: none; }
}

.vfeed-item { flex: 0 0 auto; overflow: hidden; background: #f2f2f2; }
.vfeed-item.is-portrait  { height: 440px; aspect-ratio: 3 / 4; }
.vfeed-item.is-landscape { height: 300px; aspect-ratio: 3 / 2; }
.vfeed-item.is-square    { height: 360px; aspect-ratio: 1 / 1; }
.vfeed-item video { display: block; width: 100%; height: 100%; object-fit: cover; }
.vfeed-item img, .vfeed-item video { transition: transform 0.6s var(--ease); }
@media (hover: hover) { .vfeed-item:hover img, .vfeed-item:hover video { transform: scale(1.02); } }

/* Hard-coded staggered vertical offsets, repeating every 5 */
.vfeed-strip .vfeed-item:nth-child(5n+1) { transform: translateY(0); }
.vfeed-strip .vfeed-item:nth-child(5n+2) { transform: translateY(40px); }
.vfeed-strip .vfeed-item:nth-child(5n+3) { transform: translateY(16px); }
.vfeed-strip .vfeed-item:nth-child(5n+4) { transform: translateY(56px); }
.vfeed-strip .vfeed-item:nth-child(5n+5) { transform: translateY(24px); }

@media (max-width: 900px) {
  .vfeed { padding: 64px 0; }
  .vfeed-head { padding: 0 var(--gutter); }
  .vfeed-head-row { flex-direction: column; align-items: flex-start; gap: 1.25rem; }
  .vfeed-item { height: auto; width: 72vw; }   /* ~72vw, first still bleeds left */
}

/* Phone: the strip runs at a fixed height so it stays one even band. */
@media (max-width: 560px) {
  .vfeed { padding: 52px 0; }
  .vfeed-head { margin-bottom: 28px; }
  .vfeed-item { height: 250px; width: auto; }
  .vfeed-strip .vfeed-item:nth-child(5n+2) { transform: translateY(22px); }
  .vfeed-strip .vfeed-item:nth-child(5n+3) { transform: translateY(10px); }
  .vfeed-strip .vfeed-item:nth-child(5n+4) { transform: translateY(30px); }
  .vfeed-strip .vfeed-item:nth-child(5n+5) { transform: translateY(14px); }
}

/* ── /visual-feed page (masonry) ──
   4-column editorial masonry (à la the reference): equal-width columns, items
   keep their natural aspect ratio so heights stagger, captions sit below. */
.vfeed-page { padding: calc(var(--nav-h) + 56px) 2.5rem 96px; }
.vfeed-page-head { margin-bottom: 28px; }
.vfeed-page .vfeed-heading { font-size: clamp(2rem, 4vw, 3.25rem); max-width: 30ch; }
.vfeed-rule { height: 1px; background: var(--border); margin-bottom: 40px; }

/* Balanced masonry: JS deals cells into the shortest column in order, so the
   sequence reads TOP-TO-BOTTOM across the page (CSS columns would fill one
   whole column first, making a sorted order read left-to-right instead). */
.vfeed-masonry { display: flex; gap: 16px; align-items: flex-start; }
.vfeed-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.vfeed-cell { break-inside: avoid; }
.vfeed-cell button { display: block; width: 100%; cursor: zoom-in; background: #f2f2f2; overflow: hidden; border: 0; padding: 0; }
.vfeed-cell img { transition: transform 0.6s var(--ease); }
.vfeed-cell video { display: block; width: 100%; height: auto; background: #f2f2f2; }
@media (hover: hover) { .vfeed-cell button:hover img { transform: scale(1.02); } }

.vfeed-cap { display: flex; gap: 0.5rem; align-items: baseline; padding-top: 0.6rem; font-size: 0.8rem; }
.vfeed-cap .t { color: var(--text); }
.vfeed-cap .d { color: var(--muted); }        /* diamond separator */
.vfeed-cap .y { color: var(--muted); }

/* Reveal: 300ms, small y, no scale (overrides the global .rv timing here) */
.vfeed-masonry .rv { transform: translateY(10px); transition-duration: 0.3s; }
.vfeed-masonry .rv:nth-child(3n+2) { transition-delay: 0.06s; }
.vfeed-masonry .rv:nth-child(3n+3) { transition-delay: 0.12s; }

/* column count is set by JS (layoutVfeed) to match these breakpoints */
@media (max-width: 640px) {
  .vfeed-page { padding: calc(var(--nav-h) + 32px) 1.5rem 64px; }
}

/* ── Lightbox (light, editorial — no dark scrim) ── */
.vfeed-lb {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6vh 6vw;
}
.vfeed-lb[hidden] { display: none; }
.vfeed-lb-img { max-width: 88vw; max-height: 80vh; width: auto; height: auto; object-fit: contain; }
.vfeed-lb-close { position: fixed; top: 1rem; right: 1rem; background: var(--bg); z-index: 1; }
.vfeed-lb-cap { position: fixed; left: 6vw; bottom: 5vh; font-size: 0.85rem; }
.vfeed-lb-cap .y { color: var(--muted); margin-left: 0.4rem; }

/* ══ /work — colour-flood project index ══
   Modelled on the reference work menu (annaparellada.com): a black field of
   oversized names, two to a row, each trailing an em-dash. Hovering a name
   floods the field with that project's colour, turns every name black, drops
   the rest to 10% opacity, and pushes the project's image out sideways from
   behind the name. The reference badges the year in a circle; ours is a
   rectangle carrying the work's disciplines instead.

   The flood is deliberately instant — no colour transition, as in the
   reference. The entrance staggers each name in by 100ms (600ms outQuart,
   rising 25px), matching the menu's open animation. */
.wx-page {
  --wx-bg: #000;
  min-height: 100dvh;
  background: var(--wx-bg);
  color: #fff;
}

/* Nav keeps its own layout; only its colours follow the field, going black
   along with the names while a project is hovered. */
.wx-page nav { background: transparent; border-bottom-color: transparent; }
.wx-page .nav-logo,
.wx-page .nav-logo a,
.wx-page .nav-links a,
.wx-page .nav-links a.active,
.wx-page .nav-links .sep { color: #fff; }
.wx-page .nav-cta { background: transparent; color: #fff; border-color: #fff; }
.wx-page .nav-cta:hover { background: #fff; color: var(--wx-bg); }
.wx-page.flooded .nav-logo,
.wx-page.flooded .nav-logo a,
.wx-page.flooded .nav-links a,
.wx-page.flooded .nav-links a.active,
.wx-page.flooded .nav-links .sep { color: #000; }
.wx-page.flooded .nav-cta { color: #000; border-color: #000; }
.wx-page.flooded .nav-cta:hover { background: #000; color: var(--wx-bg); }

/* The global focus ring is dark ink — invisible on the black field */
.wx-page :focus-visible { outline-color: currentColor; }

/* ── The field ── */
/* Centred both ways. The top padding is the nav's height, so the block
   centres in the space below it rather than under it. */
.wx {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: 100dvh;
  padding: var(--nav-h) 6vw 0;
}
.wx-row { display: flex; align-items: center; justify-content: center; gap: 1.6vw; }

.wx-link {
  position: relative;
  z-index: 1;
  padding: 0.5vw 0;
  color: #fff;
  font-weight: 500;
  transition: opacity 0.25s ease;
}
.wx-name { font-family: var(--f); font-size: 6vw; font-weight: 500; line-height: 1.15; }

/* Hovering one name blackens all of them and drops the rest back. The
   reference lifts the *other* names above the hovered one, so their ghosts
   sit over its image; we lift the hovered one instead, keeping the image
   clear of every other name.
   The dim has to out-rank the .ready entrance rule below, hence html.js. */
.wx.hovering .wx-link { color: #000; }
html.js .wx.hovering .wx-link:not(.is-hover) { opacity: 0.1; }
.wx.hovering .wx-link.is-hover { z-index: 3; }

/* ── Image — pushed clear of the name, right for the first in a row and
   left for the second (the reference's `is-flipped`) ── */
.wx-img {
  position: absolute;
  top: 50%; right: 0;
  z-index: 10;
  width: 28vw; height: 17vw;
  transform: translate(110%, -50%);
  object-fit: cover;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 200ms ease, visibility 0s linear 200ms;
}
.wx-img.is-flipped {
  left: 0; right: auto;
  width: 26vw;
  transform: translate(-110%, -50%);
  object-position: 50% 0%;
}
.wx-link:hover .wx-img,
.wx-link:focus-visible .wx-img {
  opacity: 1;
  visibility: visible;
  transition: opacity 200ms ease, visibility 0s;
}

/* ── The badge — the reference's year circle, squared off and carrying the
   work's disciplines. currentColor means it flips white → black with the
   names, for free. ── */
.wx-badge {
  position: absolute;
  top: -1vw; right: 2vw;
  z-index: 11;
  display: flex;
  gap: 0.4rem;
  opacity: 0;
  transition: opacity 200ms ease;
}
.wx-link:hover .wx-badge,
.wx-link:focus-visible .wx-badge { opacity: 1; }
.wx-tag {
  padding: 6px 12px 4px;           /* the circle's padding, kept as-is */
  border: 1px solid currentColor;
  border-radius: 2px;              /* a rectangle, not a bubble */
  font-size: 14px;
  font-weight: 400;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
}
.wx-tag.is-year { opacity: 0.55; }

/* ── Entrance — names rise and fade in, 100ms apart ──
   .entering owns the animation; JS swaps it for .ready once the last name has
   landed, so the hover dim isn't fighting an animation fill. */
html.js .wx-link { opacity: 0; }
html.js .wx.entering .wx-link {
  animation: wxRise 600ms var(--out-quart) var(--d, 0s) both;
}
html.js .wx.ready .wx-link { opacity: 1; }
@keyframes wxRise {
  from { opacity: 0; transform: translateY(25px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 991px) { .wx-name { font-size: 7.5vw; } }

/* No hover on touch: the image and badge never surface, so the names carry
   the page on their own. */
@media (max-width: 767px) {
  .wx { padding: calc(var(--nav-h) + 8vh) 6vw 8vh; }
  .wx-row { flex-direction: column; align-items: center; gap: 0; }
  .wx-name { font-size: 12vw; }
  .wx-img, .wx-badge { display: none; }
  .wx.hovering .wx-link:not(.is-hover) { opacity: 1; }
}

/* ══ Homepage contact band ══
   The contact page's content, embedded after the Visual feed band so it stays
   reachable now that the nav CTA copies the email instead of linking to it.
   Reuses .contact-big / .contact-rows / .contact-row from the contact page. */
/* Aligned to the hero's centre column (27/46/27), without the grid's border
   lines — the content sits in column 2 and the side columns stay empty. */
/* Same measure as the hero: .layout's centre column, edge to edge. The
   contact block used to run on its own narrower 27/46/27 grid with an extra
   2.5rem gutter, so it sat noticeably inset from the statement above it. */
.home-contact {
  display: grid;
  grid-template-columns: 20% 60% 20%;
  padding: 96px 0;
  border-top: 1px solid var(--border);
}
.home-contact-inner { grid-column: 2; padding: 0; }
.home-contact .section-label { margin-bottom: 1.5rem; }
.home-contact .contact-big { margin-bottom: 2.5rem; }
@media (max-width: 1200px) {
  .home-contact { grid-template-columns: 18% 64% 18%; }   /* tracks .layout */
  .home-contact-inner { padding: 0; }
}
@media (max-width: 900px) {
  .home-contact { grid-template-columns: 1fr; padding: 64px 0; }
  .home-contact-inner { grid-column: 1; padding: 0 1.5rem; }
}
@media (max-width: 560px) {
  .home-contact-inner { padding: 0 1.15rem; }
}

/* ══ Homepage services ══ each discipline set as display type on its own
   rule. Hovering, focusing or tapping a row opens an accent band out from the
   centre line, carrying the same word reversed out of the colour plus that
   service's thumbnail.

   The band is a second copy of the row, clipped to nothing at rest
   (inset(50% 0 50% 0)) and opened to inset(0) — so the reveal reads as colour
   spreading from the rule rather than a plain fade. Modelled on the reference
   at minhpham.design, in the site's own dusty rose.

   The previous image-panel design is kept intact further down, under
   "Homepage services — LEGACY". */
.services {
  padding: 48px 0;
  border-top: 1px solid var(--border);
  /* The personal wall's grey field, but flat — no gridlines here */
  background-color: var(--grid-bg);
}
.services-head { padding: 0 2.5rem; margin-bottom: 20px; }
.services-head .vfeed-heading { max-width: 30ch; }

.svc { list-style: none; padding: 0 2.5rem; }

.svc-row { position: relative; border-top: 1px solid rgba(17, 17, 17, 0.16); }
.svc-row:last-child { border-bottom: 1px solid rgba(17, 17, 17, 0.16); }

/* A button, not a link — there's no services page to navigate to */
.svc-hit {
  display: block; width: 100%; padding: 0;
  background: none; border: 0; font-family: inherit; text-align: left;
  color: inherit; cursor: pointer;
}
.svc-hit:focus-visible { outline: 2px solid var(--ink); outline-offset: -3px; }

/* Two stacked copies of the row. The band is the one in flow, so it sets the
   height; the base sits behind it at inset 0 and can never drift out of line. */
.svc-layer {
  display: flex; align-items: center; justify-content: space-between;
  gap: 2rem; padding: 0.3rem 0;
}
.svc-base { position: absolute; inset: 0; color: var(--ink); }
.svc-band {
  position: relative; z-index: 2;
  background: var(--accent); color: #fff;
  /* Bleeds a little past the text on both sides, so the colour doesn't stop
     hard against the glyphs */
  margin: 0 -1.25rem; padding-left: 1.25rem; padding-right: 1.25rem;
  clip-path: inset(50% 0 50% 0);
  transition: clip-path 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.svc-row.is-open .svc-band {
  clip-path: inset(0);
  transition: clip-path 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
}

.svc-name {
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  font-weight: 500; line-height: 1.1; letter-spacing: -0.02em;
}

/* The thumbnail rides inside the band, so it arrives with the colour */
.svc-thumb {
  flex: none; width: clamp(54px, 4.5vw, 72px); aspect-ratio: 3 / 2;
  overflow: hidden; background: rgba(255, 255, 255, 0.18);
}
.svc-thumb img, .svc-thumb video { display: block; width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 900px) {
  .svc { padding: 0 1.5rem; }
  .svc-layer { gap: 1rem; padding: 0.3rem 0; }
  .svc-band { margin: 0 -0.75rem; padding-left: 0.75rem; padding-right: 0.75rem; }
}
@media (prefers-reduced-motion: reduce) {
  .svc-band, .svc-row.is-open .svc-band { transition: none; }
}

/* ── Homepage services — LEGACY ──
   The previous design: a 4:3 image panel on the left whose media crossfades as
   you hover a plain list on the right. Left in place so the section can be
   reverted by swapping the markup back in index.html — see the comment there.
   Dormant while the .svc markup above is the one in the page. */
.services-body { padding: 0 2.5rem; display: grid; grid-template-columns: 45% 1fr; column-gap: 2.5rem; align-items: start; }

/* Left: fixed 4:3 panel; images stacked + crossfaded so it never resizes or flashes */
.services-panel { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: #f2f2f2; }
.services-panel img, .services-panel video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.35s ease; }
.services-panel img.is-active, .services-panel video.is-active { opacity: 1; }

/* Right: names, hairline above each + below the last */
.services-list { list-style: none; }
.services-item { border-top: 1px solid var(--border); }
.services-list .services-item:last-child { border-bottom: 1px solid var(--border); }
.services-name {
  display: block; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer; font-family: inherit; color: var(--text);
  font-size: 1.75rem; font-weight: 400; line-height: 1.1;
  padding: 1.5rem 0;
  transition: color 0.2s ease;
}
.services-item.is-active .services-name { color: var(--accent); }   /* accent; others stay full contrast */

@media (max-width: 900px) {
  .services-head { padding: 0 1.5rem; }
  .services-body { grid-template-columns: 1fr; row-gap: 2rem; padding: 0 1.5rem; }   /* image on top, list below */
  .services-name { font-size: 1.5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .services-panel img, .services-panel video, .services-name { transition: none; }   /* instant swap */
}

/* ══ Phone: one section, one screen ══
   On a laptop each band of the homepage resolves to about a screen — the
   statement, the wall, the rail, Services, the feed, the contact field. On a
   phone they were landing wherever their content ran out, so the page read as
   one long scroll with sections starting mid-screen. Giving each the height of
   the viewport (minus the fixed nav) and centring its content restores the
   screen-by-screen rhythm the desktop layout has.

   The wall sets its own height from the board's aspect ratio and the contact
   field reserves a zone for the tag pile, so neither is listed here. */
/* Desktop keeps the socials and copyright in the right column, so the contact
   band's copy of them stays out of the way there. */
.home-contact-foot { display: none; }

@media (max-width: 900px) {
  .hz-pin,
  .services,
  .home-contact {
    min-height: calc(100svh - var(--nav-h));
  }
  .services {
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  .home-contact { align-content: center; }

  /* The homepage's right column is footer-only. Stacked, it lands between the
     rail and Services as an orphan block; its links move under Contact. */
  .col-right.is-home-footer { display: none; }
  .home-contact-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 2.5rem;
  }
  .home-contact-foot .social-icons { flex-direction: row; gap: 1.25rem; margin: 0; }
}
