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

@font-face {
  font-family: "Bauhaus95";
  src: url("../assets/fonts/Bauhaus95-Regular.woff2") format("woff2"),
    url("../assets/fonts/Bauhaus95-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Barlow: the resume face (desktop), matching the PDF resume. OFL, see assets/fonts/OFL.txt */
@font-face {
  font-family: "Barlow";
  src: url("../assets/fonts/Barlow-Regular.ttf") format("truetype");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Barlow";
  src: url("../assets/fonts/Barlow-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Barlow";
  src: url("../assets/fonts/Barlow-Bold.ttf") format("truetype");
  font-weight: 700;
  font-display: swap;
}

/* ---------- Tokens ---------- */

:root {
  --ink: #111;
  --paper: #fff;
  --mute: #8c8c8c;
  --faint: #d2d2d2;
  --font: Arial, Helvetica, sans-serif;
  --display: "Bauhaus95", var(--font);
  --gutter: clamp(16px, 3vw, 44px);
  --top: clamp(28px, 4vw, 56px);
  --strip-w: clamp(92px, 8.4vw, 132px);
  --strip-gap: clamp(10px, 1.2vw, 18px);
  --header-h: 0px; /* set by main.js on desktop, where the header is sticky */
}

/* ---------- Base ---------- */

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

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    transition: none !important;
  }
}

/* desktop: text scales gently with screen width, so wide screens (e.g. MacBooks)
   keep the same proportions as a laptop. 16px at 1280px wide, up to 20px. */
@media (min-width: 761px) {
  html {
    font-size: clamp(16px, calc(10px + 0.47vw), 20px);
  }
}

body {
  margin: 0;
  padding-inline: var(--gutter);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 0.9375rem; /* 15px at the default size; grows with the desktop root size above */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
}

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

.eyebrow {
  margin: 0 0 1rem;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--mute);
}

/* project page: the code (A.01) in the project's colour */
.project-code {
  color: var(--tint, inherit);
  font-weight: 700;
}

.text-link {
  border-bottom: 1px solid currentColor;
}

/* ---------- Page transitions ----------
   Between pages the header holds still, the menu glides/resizes into its
   new position, and the rest of the page fades. Browsers without support
   simply navigate as normal. */

@media (min-width: 761px) {
  @view-transition {
    navigation: auto;
  }
}

.site-header {
  view-transition-name: site-header;
}

.menu {
  view-transition-name: menu;
}

::view-transition-group(menu) {
  animation-duration: 0.5s;
  animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
}

::view-transition-old(root) {
  animation: 0.2s ease-out both page-out;
}

::view-transition-new(root) {
  animation: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) 0.1s both page-in;
}

@keyframes page-out {
  to {
    opacity: 0;
  }
}

@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

/* Same effect for browsers without cross-page View Transitions (e.g. Firefox).
   menu-entering: set in <head> before first paint; draws the menu at the previous
   page's size and holds the content back. main.js then swaps to a scale animation. */
html.menu-entering .menu a {
  font-size: var(--menu-enter-size) !important;
}

html.menu-entering .layout > :not(.menu) {
  opacity: 0;
}

.menu.menu-scaling {
  transform-origin: 0 0;
  transition: transform 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
  will-change: transform;
}

.page-enter .layout > :not(.menu) {
  animation: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) 0.1s both page-in;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

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

.site-header {
  padding-block: clamp(11px, 1.5vw, 19px) 16px;
  border-bottom: 1px solid var(--ink);
}

/* desktop, home page: header stays pinned while browsing projects, then slides up
   out of view on the way to the resume, in step with the menu shrinking
   (--header-hide, 0 → 1, set by main.js; trails the menu shrink slightly).
   Project pages: header scrolls away. */
@media (min-width: 761px) {
  body[data-page="index"] .site-header {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--paper);
    transform: translateY(calc(-100% * var(--header-hide, 0)));
  }

  /* menu click: the header slides with the same timing as the menu resize */
  html.is-resizing .site-header {
    transition: transform 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
  }
}

.name {
  display: block;
  margin: 0 0 0.3rem;
  font-family: var(--display);
  font-size: clamp(1.6rem, 3vw, 2.6rem);
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1;
}

/* letter-spacing is set by main.js so the tagline spans the name exactly */
.tagline {
  margin: 0;
  font-size: clamp(0.6rem, 0.78vw, 0.74rem);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}

.tagline span {
  margin-inline: 0.5em;
}

/* ---------- Two-column layout ---------- */

.layout {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 8fr);
  column-gap: clamp(24px, 4vw, 72px);
  padding-top: var(--top);
}

/* box hugs the words, so between pages the menu scales evenly instead of stretching */
.menu {
  position: sticky;
  /* below the pinned header; moves up as the header slides away (home page) */
  top: calc(var(--header-h) * (1 - var(--header-hide, 0)) + var(--top));
  align-self: start;
  justify-self: start;
  width: max-content;
  transform-origin: 0 0; /* the Firefox page-change animation scales from the top-left */
}

.menu ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.menu a {
  display: block; /* height comes from the word alone, so it scales with font-size */
  /* 1.35 × the name, easing down to the name's size as --menu-shrink goes 0 → 1
     (set by main.js on the home page as you scroll toward the resume) */
  font-size: calc(clamp(2.16rem, 4.05vw, 3.51rem) * (1 - (1 - 1 / 1.35) * var(--menu-shrink, 0)));
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 0.92;
  text-transform: uppercase;
  color: var(--faint);
  transition: color 0.25s;
}

.menu a:hover,
.menu a.is-active {
  color: var(--ink);
}

/* menu click on the home page: size change matches the page-transition timing */
.menu.is-resizing a {
  transition: color 0.25s, font-size 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
}

.menu.is-resizing {
  transition: top 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
}

/* desktop project pages: smaller menu in a narrower column, so the project gets the room */
@media (min-width: 761px) {
  body[data-page="project"] .layout {
    grid-template-columns: max-content minmax(0, 1fr);
  }

  body[data-page="project"] .menu a {
    font-size: clamp(1.6rem, 3vw, 2.6rem); /* same as the name */
  }
}

/* ---------- Home: categories + strips ---------- */

.category {
  min-height: 72vh;
  scroll-margin-top: calc(var(--header-h) + var(--top));
  transition: opacity 0.45s;
}

.category.is-dim {
  opacity: 0.16;
}

.category.is-dim:hover {
  opacity: 0.4;
}

.category-head {
  display: flex;
  gap: 1.1em;
  align-items: baseline;
  margin: 0 0 18px;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.category-count {
  color: var(--mute);
}

.strips {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--strip-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* strips stay on one row, narrowing slightly if a category has many projects */
.strips li {
  flex: 0 1 var(--strip-w);
  min-width: 0;
}

.strip {
  display: block;
  width: 100%;
}

.strip-frame {
  position: relative;
  display: block;
  aspect-ratio: 3 / 8;
  overflow: hidden;
  background: #eee;
}

.strip-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 0.35s;
}

/* colour laid over a black-and-white strip; fades out on hover so the grey
   hover state and title read as before */
.strip-frame {
  isolation: isolate; /* blend only with the strip image */
}

/* stripWash: white paper taken down to a light grey under the tint, so a line drawing
   reads as a field of colour like the renders (fades with the tint on hover) */
.strip-wash {
  position: absolute;
  inset: 0;
  background: #c6c6c6;
  mix-blend-mode: multiply;
  pointer-events: none;
  transition: opacity 0.35s;
}

.strip-tint {
  position: absolute;
  inset: 0;
  background: var(--tint);
  mix-blend-mode: overlay;
  pointer-events: none;
  transition: opacity 0.35s;
}

/* stripMask: a flat colour on part of the image only (e.g. a site plan's roads) */
.strip-tint--mask {
  mix-blend-mode: multiply;
  -webkit-mask-size: cover;
  mask-size: cover;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

@media (hover: hover) and (pointer: fine) {
  .strip:hover .strip-tint,
  .strip:hover .strip-wash {
    opacity: 0;
  }
}

.strip:focus-visible .strip-tint,
.strip:focus-visible .strip-wash {
  opacity: 0;
}

.strip-title {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px 0;
  writing-mode: vertical-rl;
  transform: rotate(180deg); /* read bottom-to-top */
  background: rgba(255, 255, 255, 0.6);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-align: center;
  opacity: 0;
  transition: opacity 0.3s;
}

.strip-caption {
  display: none;
}

.strip-code {
  display: block;
  margin-top: 8px;
  font-size: 0.64rem;
  letter-spacing: 0.2em;
  color: var(--mute);
}

@media (hover: hover) and (pointer: fine) {
  .strip:hover img {
    filter: grayscale(1) contrast(0.85) brightness(1.08);
  }
  .strip:hover .strip-title {
    opacity: 1;
  }
}

.strip:focus-visible img {
  filter: grayscale(1) contrast(0.85) brightness(1.08);
}

.strip:focus-visible .strip-title {
  opacity: 1;
}

/* ---------- Project page ---------- */

.project {
  padding-bottom: 64px;
}

.project-head h1 {
  margin: 0;
  padding-bottom: clamp(20px, 2.5vw, 32px);
  border-bottom: 1px solid var(--ink); /* full-width rule above the details */
  font-size: clamp(2rem, 4.2vw, 3.6rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 0.95;
  text-transform: uppercase;
}

.meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 14px 24px;
  margin: 0 0 28px;
  padding-top: 14px;
}

/* desktop: details span exactly the paragraph's width — first item at the left
   edge, last item's right edge on the paragraph's right edge. Same font size and
   ch limit as .lede, so the widths match. */
@media (min-width: 761px) {
  .meta {
    display: flex;
    justify-content: space-between;
    max-width: 75ch;
    font-size: 1.05rem;
  }

  .meta dd {
    font-size: 0.9375rem;
  }
}

.meta dt {
  font-size: 0.64rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--mute);
}

.meta dd {
  margin: 2px 0 0;
  font-weight: 500;
}

.lede {
  max-width: 75ch; /* readable line length */
  margin: 0 0 clamp(32px, 4vw, 56px);
  font-size: 1.05rem;
  line-height: 1.6;
}

.lede p {
  margin: 0;
}

.lede p + p {
  margin-top: 1em;
}

/* desktop: a square site plan crop beside the description (besideText), its right edge
   on the gallery's right edge and its top level with the description's first line;
   the details row above spreads to the same right edge */
.head-beside {
  display: none;
}

@media (min-width: 761px) {
  .project-head.has-beside {
    display: grid;
    /* text column as wide as the description's own 75ch limit; the crop gets the rest */
    grid-template-columns: auto minmax(200px, 1fr);
    column-gap: clamp(24px, 3vw, 48px);
  }

  .project-head.has-beside > .eyebrow,
  .project-head.has-beside > h1,
  .project-head.has-beside > .meta {
    grid-column: 1 / -1;
  }

  /* four or more details (e.g. with collaborators): the last one ends on the site
     plan's right edge; three stay at the description's width */
  .project-head.has-beside > .meta--long {
    max-width: none;
  }

  .project-head.has-beside .lede {
    grid-column: 1;
  }

  .head-beside {
    display: block;
    grid-column: 2;
    grid-row: 4;
    align-self: start;
    justify-self: end;
    width: 100%;
    max-width: 260px;
    /* top level with the first line's capitals (half its leading below the line box) */
    margin: 0.42em 0 clamp(32px, 4vw, 56px);
    font-size: 1.05rem; /* so the em above matches the description's */
  }

  .head-beside img {
    display: block;
    width: 100%;
    height: auto;
  }

  .head-beside figcaption {
    margin-top: 3px;
    line-height: 1.25;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    color: var(--mute);
  }
}

/* mobile: the description collapses to a few lines that fade out (see wireReadMore) */
.lede-more {
  display: block;
  margin: 10px 0 clamp(32px, 4vw, 56px);
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
}

.lede-more[hidden] {
  display: none;
}

.lede.is-collapsed,
.lede.is-open {
  margin-bottom: 0; /* the button keeps the space before the gallery */
}

.lede.is-collapsed {
  position: relative;
  max-height: calc(1.6em * 7); /* seven lines */
  overflow: hidden;
}

.lede.is-collapsed::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 3.2em;
  background: linear-gradient(rgba(255, 255, 255, 0), var(--paper));
}

.gallery figure {
  margin: 0 0 clamp(20px, 2.5vw, 36px);
}

.gallery img {
  display: block;
  width: 100%;
  height: auto;
}

.gallery figcaption {
  margin-top: 3px; /* close to the image, not touching */
  line-height: 1.25;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--mute);
}

/* image groups (see projects.js) */
.gallery-stack .gallery-group,
.gallery-bands .gallery-group {
  display: grid;
  gap: var(--group-gap, 0); /* default no gap: related drawings read as one */
}

/* 3 × 3 study matrices, on mobile too */
.gallery-matrix .gallery-group {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(4px, 0.5vw, 8px);
}

/* side by side at equal heights: each takes width in proportion to its ratio.
   aside: one image on the left, a column of images on the right. */
.gallery-row .gallery-group,
.gallery-aside .gallery-group {
  display: flex;
  align-items: flex-start;
  gap: var(--group-gap, clamp(8px, 1vw, 14px));
}

/* a row can be capped (maxWidth) so a small source isn't blown up */
.gallery-row .gallery-group {
  max-width: var(--group-max, none);
}

/* pan (mobile): an enlarged image to swipe across, matching the slide in view above */
.pan-view {
  display: flex;
  align-items: flex-end; /* drawings sit on the bottom, so the ground line holds still */
  aspect-ratio: calc(var(--pan-ratio, 3) / var(--zoom, 2.5)); /* the tallest image: no height jump between views */
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.gallery .pan-img {
  display: none;
  flex: none;
  width: calc(var(--zoom, 2.5) * 100%);
  max-width: none;
}

.gallery .pan-img.is-active {
  display: block;
}

/* spaceBefore: extra room above a new set of drawings (plans, elevations, details) */
.gallery .is-spaced {
  margin-top: clamp(32px, 4.5vw, 72px);
}

.gallery .is-spaced-half {
  margin-top: clamp(16px, 2.2vw, 36px);
}

.gallery .is-spaced-large {
  margin-top: clamp(56px, 7vw, 112px);
}

/* roomy (desktop): more space between drawings on a long project page */
@media (min-width: 761px) {
  .gallery.is-roomy figure {
    margin-bottom: clamp(36px, 4.5vw, 64px);
  }
}

/* spaceAfter "large": more room below a set (after the roomy rule, so it wins) */
.gallery figure.is-after-large {
  margin-bottom: clamp(92px, 11.5vw, 176px);
}

.gallery figure.is-after-medium {
  margin-bottom: clamp(76px, 9.5vw, 146px);
}

/* side index (desktop): the page's parts listed under the menu */
.project-index {
  position: fixed;
  left: var(--gutter);
  z-index: 14;
}

.project-index ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

.project-index a {
  display: block; /* stacked tight, like the menu and the level selectors */
  font-size: 0.72rem;
  line-height: 1.25;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  transition: color 0.2s;
}

.project-index .is-sub a {
  padding-left: 1.1em;
  font-weight: 400;
}

.project-index a:hover,
.project-index a.is-active {
  color: var(--ink);
}

/* place: images at set offsets and widths, tops aligned */
.gallery-place .gallery-group {
  display: flex;
  align-items: flex-start;
}

.place-item {
  flex: none;
}

.gallery-row .gallery-item,
.gallery-aside .gallery-group > .gallery-item,
.gallery-col {
  flex: var(--r, 1) 1 0;
  min-width: 0;
}

.gallery-col {
  display: grid;
  gap: clamp(12px, 1.5vw, 24px);
}

/* aside: both sides end level; the single image's caption drops to the bottom so it
   lines up with the last caption in the column */
.gallery-aside .gallery-group {
  align-items: var(--group-align, stretch);
}

.gallery-aside .gallery-group > .gallery-item {
  display: flex;
  flex-direction: column;
}

.gallery-aside .gallery-group > .gallery-item > .item-caption {
  margin-top: auto;
  padding-top: 3px;
}

.gallery-aside.is-reverse .gallery-group {
  flex-direction: row-reverse;
}

/* section break with an optional short description under it */
.gallery-section {
  margin: clamp(40px, 6vw, 88px) 0 clamp(44px, 6.5vw, 96px);
}

.gallery-section .gallery-divider {
  margin: 0;
}

.divider-note {
  max-width: 75ch; /* same measure and alignment as the project description */
  margin: clamp(18px, 2vw, 28px) 0 0;
  font-size: 1.05rem;
  line-height: 1.6;
}

/* section break inside a project: a subheading between two full-width rules */
.gallery-divider {
  margin: clamp(40px, 6vw, 88px) 0 clamp(44px, 6.5vw, 96px);
  padding-block: clamp(16px, 2vw, 24px);
  border-block: 1px solid var(--ink);
  text-align: center;
}

.gallery-divider span {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

/* carousel: one plan at a time between two small arrows; slides share one spot and
   cross-fade. Its level selector (.level-select) sits in the left sidebar. */
.carousel-body {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 2.5vw, 40px);
}

.carousel-stage {
  display: grid;
  flex: 0 1 var(--stage-w, 68%);
  cursor: pointer;
}

/* arrowsOut: the image takes the full column and the arrows sit in the margins,
   centred in the page gutter */
.gallery-carousel.is-arrows-out .carousel-body {
  position: relative;
}

.gallery-carousel.is-arrows-out .carousel-stage {
  flex-basis: var(--stage-w, 100%); /* width: shrinks it, centred */
}

.gallery-carousel.is-arrows-out .carousel-arrow {
  position: absolute;
  top: 50%;
  padding: 8px;
  transform: translateY(-50%);
}

.gallery-carousel.is-arrows-out .carousel-arrow[data-step="-1"] {
  left: calc(-1 * (var(--gutter) / 2 + 20.5px));
}

.gallery-carousel.is-arrows-out .carousel-arrow[data-step="1"] {
  right: calc(-1 * (var(--gutter) / 2 + 20.5px));
}

.carousel-slide {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s, visibility 0.35s;
}

/* mobileSrc: the picture wrapper adds no box of its own */
picture {
  display: contents;
}

@media (max-width: 760px) {
  picture[style] img {
    aspect-ratio: var(--m-ratio) !important; /* the mobile file's shape, not the desktop one */
  }
}

.carousel-slide.is-active {
  opacity: 1;
  visibility: visible;
}

/* alignBottom: shorter slides sit on the bottom edge, so a drawing doesn't jump up */
.gallery-carousel.is-bottom .carousel-slide {
  align-self: end;
}

/* plans that open their level in a carousel (desktop) */
@media (min-width: 761px) {
  .opens-level img {
    cursor: pointer;
  }
}

.carousel-note {
  max-width: 60ch;
  margin: 2px 0 0;
  font-size: 0.66rem;
  letter-spacing: 0.02em;
  line-height: 1.45;
}

.carousel-dots {
  display: none; /* mobile only */
}

.mobile-only {
  display: none;
}

@media (max-width: 760px) {
  .mobile-only {
    display: block;
  }
}

.carousel-arrow {
  padding: 14px; /* generous click area */
  border: 0;
  background: none;
  color: var(--faint);
  cursor: pointer;
  transition: color 0.2s;
}

.carousel-arrow:hover,
.carousel-arrow:focus-visible {
  color: var(--ink);
}

.carousel-arrow svg {
  display: block;
  width: 25px;
  height: 30px;
  fill: currentColor;
}

.level-select {
  position: fixed;
  left: var(--gutter);
  z-index: 15;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s, visibility 0.3s;
}

.level-select.is-visible {
  opacity: 1;
  visibility: visible;
}

.level-select button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: clamp(0.8rem, 1.5vw, 1.3rem); /* half the project-page menu size */
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.05;
  text-transform: uppercase;
  color: var(--faint);
  cursor: pointer;
  transition: color 0.2s;
}

.level-select button:hover,
.level-select button.is-active {
  color: var(--ink);
}

/* an image shown no larger than its source, so a low-res render stays crisp */
.gallery figure.is-native img {
  max-width: var(--native-w);
}

/* a short description under a caption */
.caption-note {
  display: block;
  max-width: 60ch;
  margin-top: 2px;
  font-size: 0.92em;
  letter-spacing: 0.02em;
  line-height: 1.45;
  color: var(--ink);
}

.gallery-bands img {
  aspect-ratio: var(--band-ratio);
  object-fit: cover;
  object-position: var(--band-focus);
}

.gallery-grid .gallery-group {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(8px, 1vw, 14px);
}

.gallery-item {
  position: relative;
}

/* white labels set on a drawing's dark background */
.img-label {
  position: absolute;
  transform: translateY(-50%);
  color: #fff;
  font-size: clamp(0.5rem, 0.72vw, 0.68rem);
  font-family: Arial, Helvetica, sans-serif;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}

.img-label--center {
  transform: translate(-50%, -50%);
}

.img-label--dark {
  color: var(--ink); /* for labels on white drawings */
}

.item-caption {
  margin: 3px 0 0;
  line-height: 1.25;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--mute);
}

.label-list {
  display: none;
}

@media (max-width: 760px) {
  .gallery-grid .gallery-group {
    grid-template-columns: minmax(0, 1fr);
  }

  .gallery-row .gallery-group,
  .gallery-aside .gallery-group {
    flex-direction: column;
  }

  .gallery-aside.is-reverse .gallery-group {
    flex-direction: column-reverse; /* the column comes first, as on desktop */
  }

  .gallery-row .gallery-item,
  .gallery-aside .gallery-group > .gallery-item,
  .gallery-col {
    flex: none;
    width: 100%;
  }

  /* mobileRow: stays side by side on phones, small but together */
  .gallery-row.is-mobile-row .gallery-group {
    flex-direction: row;
  }

  .gallery-row.is-mobile-row .gallery-item {
    flex: var(--r, 1) 1 0;
    width: auto;
  }

  .gallery-row.is-mobile-row .gallery-item img {
    width: 100%;
    max-height: none;
  }

  .hide-mobile {
    display: none;
  }

  .gallery .is-spaced {
    margin-top: 16px;
  }

  .gallery .is-spaced-half {
    margin-top: 8px;
  }

  .gallery .is-spaced-large {
    margin-top: 28px;
  }

  .gallery figure.is-after-large {
    margin-bottom: 44px;
  }

  .gallery figure.is-after-medium {
    margin-bottom: 36px;
  }

  .project-index {
    display: none;
  }

  /* swipe carousels: slides side by side, the next one peeking in so it reads as
     scrollable, with dots underneath */
  .gallery-carousel.is-swipe .carousel-stage {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
  }

  .gallery-carousel.is-swipe .carousel-stage::-webkit-scrollbar {
    display: none;
  }

  .gallery-carousel.is-swipe .carousel-slide {
    flex: 0 0 var(--slide-w, 86%); /* mobileSlide sets a smaller share */
    scroll-snap-align: start;
  }

  .carousel-dots {
    display: flex;
    gap: 7px;
    margin-top: 10px;
  }

  .carousel-dots span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--faint);
    transition: background 0.2s;
  }

  .carousel-dots span.is-active {
    background: var(--ink);
  }

  /* carousel: everything stacked with its caption; no tabs */
  .carousel-stage {
    gap: clamp(20px, 5vw, 32px);
    cursor: auto;
  }

  .carousel-slide {
    grid-area: auto;
    opacity: 1;
    visibility: visible;
  }

  .carousel-slide .item-caption {
    display: block;
  }

  .carousel-body {
    display: block;
  }

  .carousel-arrow,
  .level-select {
    display: none;
  }

  .gallery figure.is-native img {
    max-width: 100%; /* full width on phones */
  }

  /* tall drawings (e.g. a wall section) shouldn't run several screens long */
  .gallery-row .gallery-item img {
    width: auto;
    max-width: 100%;
    max-height: 80vh;
  }

  .img-label {
    display: none; /* listed under the group instead */
  }

  .img-label.img-label--keep {
    display: block; /* short map labels stay on the image */
    font-size: 0.55rem;
  }

  .label-list {
    display: block;
    margin: 4px 0 0;
    line-height: 1.35;
    padding: 0;
    list-style: none;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    color: var(--ink);
  }

  .label-list li + li {
    margin-top: 2px;
  }
}

.pager {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 16px;
  align-items: end;
  margin-top: 48px;
  padding-top: 14px;
  border-top: 1px solid var(--ink);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.pager a span {
  display: block;
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  color: var(--mute);
}

.pager a:last-child {
  text-align: right;
}

.pager a:hover {
  color: var(--mute);
}

.pager-index {
  letter-spacing: 0.22em;
}

/* ---------- Resume ---------- */

/* extra space above keeps the resume mostly off screen while browsing projects */
.resume {
  margin-left: calc(-1 * var(--resume-pull, 0px)); /* widen leftward; set by main.js */
  margin-top: 22vh;
  padding-bottom: 64px;
  min-height: calc(100vh - 2 * var(--top));
  scroll-margin-top: var(--top); /* the header has slid away by the time the resume is active */
}

.resume-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
}

.resume-top .eyebrow {
  margin: 0;
}

/* desktop: the header uses the resume rows' two columns, so the email starts on the
   Education column's left edge and Download PDF ends on its right edge */
@media (min-width: 761px) {
  .resume-top {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    column-gap: clamp(32px, 4vw, 64px);
  }
}

/* email left, Download PDF right; the address stays lower case */
.resume-links {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 0.9em;
}

.resume-email {
  text-transform: none;
  letter-spacing: 0.06em;
  font-size: 0.78rem;
  border-bottom: 1px solid transparent;
}

.resume-email:hover,
.resume-email:focus-visible {
  border-bottom-color: currentColor;
}

/* mobile: "03 Resume" on its own line, then email left / Download PDF right */
@media (max-width: 760px) {
  .resume-top {
    flex-direction: column;
    align-items: stretch;
    gap: 0.9rem;
    padding-bottom: 14px; /* room between the Download PDF underline and the first rule */
  }

}

/* two columns, like the PDF: wide main column + narrow side column,
   in rows so each dividing rule runs under both */
.resume-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  column-gap: clamp(32px, 4vw, 64px);
  border-top: 1px solid var(--ink);
}


/* desktop: skills/software span both rows on the right, so Previous Experience
   sits right under Experience (no rule) however long the side column is */
@media (min-width: 761px) {
  .resume-row--split {
    grid-template-areas:
      "exp  side"
      "prev side";
    grid-template-rows: auto 1fr;
  }
  .resume-exp {
    grid-area: exp;
  }
  .resume-side {
    grid-area: side;
  }
  .resume-row--split .resume-prev {
    grid-area: prev;
    padding-top: 0; /* outranks .resume-block below */
  }
}

.resume-block {
  padding-block: 18px 26px;
}

.resume-block h3 {
  margin: 0 0 12px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.resume-block p {
  margin: 0;
  max-width: 68ch;
}

.resume-block .resume-subhead {
  margin-top: 28px;
}

.resume-profile {
  font-size: 1.05rem;
  line-height: 1.55;
}

.plain-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.plain-list li + li {
  margin-top: 2px;
}

/* Education first line — desktop: school above "B.Arch 2023" */
.edu-school {
  display: flex;
  flex-wrap: wrap;
  column-gap: 0.3em;
}

.edu-school strong {
  flex-basis: 100%;
}

/* logo and "|" show on mobile only */
.edu-logo,
.edu-sep {
  display: none;
}

.entry + .entry {
  margin-top: 16px;
}


.entry h4 {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
}

.entry-title {
  font-weight: 400;
}

.entry-role {
  margin: 0 0 6px;
  color: var(--mute);
}

.entry-role .sep {
  margin-inline: 0.4em;
}

.entry ul {
  margin: 0;
  padding-left: 1.1em;
}

.entry li + li {
  margin-top: 3px;
}

/* Desktop: motifs from the PDF resume. Barlow; each block's head is a small colored
   two-digit number (the site's "01 Academic" style, PDF section colors) and the title on a
   rule (these rules replace the row rules); meta right-aligned on the entry line; dash
   bullets; skills subheads. */
@media (min-width: 761px) {
  .resume {
    font-family: "Barlow", var(--font);
  }
  .resume-row {
    border-top: 0;
  }
  .resume-block .rhead {
    display: flex;
    gap: 1.1em;
    align-items: baseline;
    padding-bottom: 7px;
    border-bottom: 1px solid var(--ink);
  }
  .rnum {
    color: var(--c);
  }
  .resume-block .skill-sub {
    margin: 0 0 4px;
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
  }
  .resume-block .resume-subhead.skill-sub {
    margin-top: 18px;
  }
  .edu-sep {
    display: inline;
  }
  .entry-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
  }
  .entry-head .entry-role {
    margin: 0 0 4px;
    white-space: nowrap;
  }
  .entry ul {
    padding-left: 1.1em;
    list-style: none;
  }
  .entry ul li::before {
    content: "–";
    display: inline-block;
    width: 1.1em;
    margin-left: -1.1em;
  }
}

/* ---------- Mobile ---------- */

@media (max-width: 760px) {
  /* rule runs edge to edge, like the menu bar below it */
  .site-header {
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    padding-top: clamp(22px, 3vw, 38px);
  }

  .layout {
    grid-template-columns: minmax(0, 1fr); /* keep the scrolling strip row from widening the page */
    padding-top: 0;
  }

  /* menu becomes a sticky bar under the header */
  .menu {
    top: 0;
    z-index: 10;
    justify-self: stretch;
    width: auto;
    margin-inline: calc(-1 * var(--gutter));
    padding: 12px var(--gutter) 10px;
    background: var(--paper);
    border-bottom: 1px solid var(--ink);
  }

  .menu ul {
    display: flex;
    justify-content: space-between;
  }

  .menu a {
    font-size: clamp(1rem, 5.4vw, 1.9rem);
  }

  .category {
    min-height: 0;
    padding-block: 28px 4px;
    scroll-margin-top: 56px;
  }

  .category.is-dim {
    opacity: 0.4;
  }

  .resume {
    min-height: 0;
    margin-top: 12vh;
  }

  /* strips scroll sideways */
  .strips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin-inline: calc(-1 * var(--gutter));
    padding: 0 var(--gutter) 6px;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
  }

  .strips::-webkit-scrollbar {
    display: none;
  }

  .strips li {
    flex: 0 0 auto;
    scroll-snap-align: start;
  }

  .strip {
    width: 34vw;
  }

  .strip-title {
    display: none;
  }

  .strip-caption {
    display: block;
    margin-top: 8px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.25;
    text-transform: uppercase;
  }

  .strip-code {
    margin-top: 3px;
  }

  .project {
    padding-top: 28px;
  }

  .resume-row {
    grid-template-columns: minmax(0, 1fr);
  }

  /* stacked: the side block gets its own rule */
  .resume-block + .resume-block {
    border-top: 1px solid var(--ink);
  }

  /* coloured numbers on mobile too, like the desktop heads; the Skills block gets its
     "04 Skills" head, with Core Skills / Software as sentence-case subheads under it */
  .rhead {
    display: flex;
    gap: 1.1em;
    align-items: baseline;
  }
  .rnum {
    color: var(--c);
  }
  .resume-block .skill-sub {
    margin: 0 0 4px;
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
  }
  .resume-block .resume-subhead.skill-sub {
    margin-top: 18px;
  }

  /* skills + software run on as one line, separated by dots, wrapping when full */
  .flow-list li {
    display: inline;
    white-space: nowrap; /* never split a skill across lines */
  }

  .flow-list li:not(:last-child)::after {
    content: "·";
    margin-left: 0.3em; /* matches the word space after it, which comes from the HTML */
  }

  /* Education: logo on the left, a rule, then the details */
  .edu-list {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 14px;
  }

  .edu-list li + li {
    margin-top: 0; /* rows touch so the rule is continuous */
  }

  .edu-school {
    display: contents; /* let its pieces sit directly in the grid */
  }

  /* spans the 4 text lines: top of "University" to the bottom of the "g" in
     "Program" (Arial at line-height 1.5; allows for the PNG's transparent edge) */
  .edu-logo {
    display: block;
    grid-column: 1;
    grid-row: 1 / span 4;
    height: 5.83em;
    width: auto;
    margin-top: 0.17em;
    filter: grayscale(1);
  }

  .edu-school strong,
  .edu-line,
  .edu-list > li:not(.edu-school) {
    grid-column: 2;
    padding-left: 14px;
    border-left: 1px solid var(--ink);
  }

  .edu-sep {
    display: inline;
  }

  .edu-sep,
  .edu-year,
  .edu-list > li:not(.edu-school) {
    color: var(--mute);
  }
}
