/* ============================================
   NAOMI — SITE STYLES
   Palette + type are placeholders. Swap the
   variables below whenever real colors/fonts are
   ready — nothing else in this file should need
   to change.
   ============================================ */

@font-face {
  font-family: "Naomi Handwriting";
  src: url("../fonts/NaomiHandwritingReal-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Hebrew-only handwriting face. It has no Latin letters, so the
   unicode-range keeps it from being used for anything else, and it sits
   second in --font-hand so Hebrew glyphs fall through to it. */
@font-face {
  font-family: "Naomi Handwriting Hebrew";
  src: url("../fonts/NaomiHandwritingHebrew-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0590-05FF, U+FB1D-FB4F;
}

/* Apertura isn't loaded yet — drop the real font file(s) in /fonts/
   (e.g. Apertura-Regular.woff2, Apertura-Medium.woff2) and uncomment.
@font-face {
  font-family: "Apertura";
  src: url("../fonts/Apertura-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Apertura";
  src: url("../fonts/Apertura-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
*/

:root {
  /* --- Palette (placeholder) ---
     Warm off-white page background, with green kept only as an
     accent for symbols + subtitles. */
  --color-bg: #faf8f5;
  --color-surface: #ffffff;
  --color-ink: #2b2b23;
  --color-ink-soft: #6d6d5f;
  --color-green: #6f7d4c;
  --color-green-dark: #57623c;
  --color-line: rgba(43, 43, 35, 0.14);
  --color-nav-text: #3d1700;
  --color-pink: #f096b6;

  /* --- Type --- */
  --font-body: "Apertura", "Jost", "Segoe UI", sans-serif;
  --font-hand: "Naomi Handwriting", "Naomi Handwriting Hebrew", cursive;
  --font-mono: "Courier New", ui-monospace, SFMono-Regular, Menlo, monospace;

  --container: 1180px;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  overflow-x: hidden;
  font-family: var(--font-body);
  background: var(--color-bg);
  color: var(--color-ink);
  -webkit-font-smoothing: antialiased;
}

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

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

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 32px;
}

.page-shell {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 40px;
}

@media (max-width: 640px) {
  .page-shell {
    padding: 0 18px;
  }
}

/* ============================================
   SITE NAV — logo top-left, symbols right
   ============================================ */

.site-nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  width: 100%;
  padding: 30px 48px 24px;
}

.site-nav__logo {
  font-family: var(--font-hand);
  font-size: 2.2rem;
  color: var(--color-nav-text);
  line-height: 1;
}

.symbol-nav__list {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 32px;
  margin: 0;
  padding: 0;
}

/* Icons are hidden (not deleted) — same markup as before, just not
   shown, so they're easy to bring back later if wanted. Layout below
   matches the homepage's plain-text .landing-hero__nav. */
.symbol-nav__icon-wrap {
  display: none;
}

.symbol-nav__item a {
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-nav-text);
  opacity: 0.75;
  transition: opacity 0.2s ease;
}

.symbol-nav__item a:hover,
.symbol-nav__item.is-active a {
  opacity: 1;
}

@media (max-width: 780px) {
  .site-nav__inner {
    flex-wrap: wrap;
    padding: 24px 28px 20px;
  }
  .symbol-nav__list {
    gap: 20px;
    flex-wrap: wrap;
  }
  .symbol-nav__item a {
    font-size: 0.68rem;
  }
}

/* ============================================
   HOMEPAGE LANDING HERO
   Full-bleed photo, floating sketch, logo + nav
   overlaid on the image, scattered quote.
   Homepage only — other pages keep .site-nav.
   ============================================ */

.landing-hero {
  position: relative;
  width: 100%;
  min-height: 100vh;
  overflow: hidden;
}

.landing-hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.landing-hero__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.landing-hero__topbar {
  position: absolute;
  top: 40px;
  left: 48px;
  right: 48px;
  z-index: 2;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

.landing-hero__logo {
  font-family: var(--font-hand);
  font-size: 2.2rem;
  color: var(--color-surface);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

.landing-hero__nav {
  display: flex;
  gap: 32px;
  padding-top: 10px;
}

.landing-hero__nav a {
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-surface);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  transition: opacity 0.2s ease;
}

.landing-hero__nav a:hover {
  opacity: 0.75;
}

/* Mobile-only hero image, menu button, and menu overlay — all
   default to hidden here so desktop never renders or lays them out;
   the max-width: 768px query below is what actually shows them. */
.landing-hero__bg-img--mobile {
  display: none;
}

#mobile-menu-btn {
  display: none;
}

#mobile-menu {
  display: none;
}

/* ---- Unified center composition ----
   One fixed-size box, centered in the hero, holding the drawing and
   all four quote lines. Because its size is fixed (not 100% of the
   hero), every child's left/top percentage below is relative to THIS
   760x640 box — so the text sits a consistent, small distance from
   the drawing no matter how wide the browser window is, instead of
   scaling out toward the screen edges. */
.hero-composition {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 760px;
  height: 640px;
  z-index: 1;
}

.hero-composition__sketch {
  position: absolute;
  left: 50%;
  top: 42%;
  transform: translate(-50%, -50%);
  width: 350px;
  height: 350px;
  object-fit: contain;
  pointer-events: none;
}

.landing-hero__line {
  position: absolute;
  margin: 0;
  white-space: nowrap;
  font-family: var(--font-hand);
  font-size: 1.55rem;
  line-height: 1.4;
  color: var(--color-surface);
  text-shadow: 0 1px 6px rgba(20, 25, 15, 0.3);
}

.landing-hero__line--attrib {
  opacity: 0.9;
}

/* Positions are hand-tuned against the sketch box above: centered at
   50%/42% of the wrapper, 320px square, so it spans roughly
   29%-71% horizontally and 17%-67% vertically. */
.landing-hero__line--1 {
  left: calc(-3% - 45px);
  top: 31%;
  text-align: right;
}

.landing-hero__line--2 {
  left: 65%;
  top: 41%;
}

.landing-hero__line--3 {
  left: 20%;
  top: 68%;
}

.landing-hero__line--attrib {
  left: 65%;
  top: 78%;
}

@media (max-width: 700px) {
  .landing-hero__topbar {
    top: 24px;
    left: 24px;
    right: 24px;
    flex-direction: column;
    gap: 16px;
  }
  .landing-hero__nav {
    gap: 18px;
    flex-wrap: wrap;
    padding-top: 0;
  }
  .hero-composition {
    width: 320px;
    height: 460px;
  }
  .hero-composition__sketch {
    width: 320px;
    height: 320px;
  }
  .landing-hero__line {
    font-size: 0.95rem;
    white-space: normal;
    max-width: 150px;
  }
  .landing-hero__line--1 {
    left: -4%;
    top: 20%;
    text-align: right;
  }
  .landing-hero__line--2 {
    left: 68%;
    top: 68%;
  }
  .landing-hero__line--3 {
    left: 6%;
    top: 74%;
    max-width: 170px;
  }
  .landing-hero__line--attrib {
    left: 56%;
    top: 88%;
  }
}

/* ---- Mobile hero: swapped image, hidden desktop nav, + menu ----
   This is its own breakpoint (768px) rather than folded into the
   700px block above, per request — the two do overlap for viewports
   701-768px wide, where both apply; nothing here conflicts with the
   700px rules since they touch different properties/elements. */
@media (max-width: 768px) {
  .landing-hero {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
  }

  .landing-hero__bg-img--desktop {
    display: none;
  }

  .landing-hero__bg-img--mobile {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Desktop text nav is replaced by the + button/overlay below. */
  .landing-hero__nav {
    display: none;
  }

  /* The mobile hero image already has the sketch/watercolor and
     quote text baked into the photo itself, so the separate overlay
     elements (sketch image + all 4 quote lines, both nested inside
     this one wrapper) would just duplicate what's already in the
     image. Only the logo and the + menu button should remain. */
  .hero-composition {
    display: none;
  }

  #mobile-menu-btn {
    display: block;
    position: fixed;
    top: 24px;
    right: 24px;
    z-index: 20;
    background: none;
    border: none;
    padding: 0;
    font-family: var(--font-body);
    font-size: 2rem;
    line-height: 1;
    /* Brown by default (the other 8 pages, sitting on the plain
       cream background) — index.html overrides this back to white
       further down, since its button sits on top of a photo. */
    color: var(--color-nav-text);
    cursor: pointer;
    transition: transform 0.3s ease;
  }

  #mobile-menu-btn.is-active {
    transform: rotate(45deg);
  }

  #mobile-menu {
    display: flex;
    position: fixed;
    inset: 0;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 28px;
    width: 100%;
    height: 100vh;
    background: rgba(20, 20, 16, 0.92);
    z-index: 15;
    transform: translateY(-100%);
    transition: transform 0.4s ease;
  }

  #mobile-menu.is-open {
    transform: translateY(0);
  }

  #mobile-menu a {
    font-family: var(--font-body);
    font-size: 1.1rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-surface);
  }
}

/* ============================================
   IMAGE PLACEHOLDER
   ============================================ */

.img-placeholder {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 220px;
  background: linear-gradient(135deg, #f1efe6, #e4e2d4 140%);
  border: 1.5px dashed var(--color-ink-soft);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 20px;
}

.img-placeholder__label {
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--color-ink);
  background: rgba(255, 255, 255, 0.85);
  padding: 8px 14px;
  border-radius: 6px;
  max-width: 220px;
}

/* ============================================
   ZIGZAG NARRATIVE SECTION (post-hero scroll block)
   ============================================ */

.eyebrow {
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-green);
  margin-bottom: 18px;
  display: inline-block;
}

.zigzag {
  margin-top: 100px;
}

/* Plain intro text block (mazor.html) — credit line + overview
   paragraphs, no image, sitting between the hero carousel and the
   first zigzag row. */
.mazor-intro {
  max-width: 640px;
  margin-top: 80px;
}

.mazor-intro .project-meta__credit {
  margin-bottom: 20px;
}

.zigzag__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: start;
  margin-bottom: 120px;
}

.zigzag__row--intro {
  grid-template-columns: 0.9fr 1.1fr;
}

.zigzag__row--sketch {
  grid-template-columns: 0.6fr 1.4fr;
}

/* When one column runs noticeably taller than the other (e.g. a
   two-paragraph text block next to a single image), center the
   shorter column within the row instead of pinning it to the top. */
.zigzag__row--center-media {
  align-items: center;
}

/* Wide diagram (kempton.html's mind map), stretched past its own
   grid column's edge to eat the row's 64px gap too — calc(100% +
   64px) lands its right edge exactly on the text column's left
   edge (touching, never overlapping) instead of stopping 64px short
   of it. align-self: end pins its bottom to the row's bottom edge
   (so the bottom stays put), and the negative margin-top pulls it
   up to bleed into the section above — a negative margin makes the
   grid track's own sizing "see" a shorter box, so this doesn't
   stretch the row despite the image visually overflowing above it. */
.zigzag__media--mindmap {
  width: calc(100% + 64px);
  align-self: end;
  margin-top: -140px;
  margin-left: -70px;
}

.zigzag__media--mindmap img {
  display: block;
  width: 100%;
  height: auto;
}

.zigzag__row--sketch .zigzag__media {
  order: -1;
}

/* Generic reverse utility (media first/left) for plain .zigzag__row
   instances not using the --intro/--sketch column ratios. */
.zigzag__row--reverse .zigzag__media {
  order: -1;
}

.zigzag__text {
  padding-top: 8px;
}

.zigzag__body {
  font-size: 0.98rem;
  line-height: 1.8;
  color: var(--color-ink-soft);
  margin: 0 0 20px;
}

.zigzag__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Placeholder boxes in a zigzag row always get sharp corners. Also
   zero out the base .img-placeholder's min-height:220px here — with
   justify-self:start (below) the box no longer stretches to fill its
   grid column, and that min-height was overriding aspect-ratio's
   computed height, distorting the intended landscape/portrait shape. */
.zigzag__media .img-placeholder {
  border-radius: 0;
  min-height: 0;
}

.zigzag__row--intro .zigzag__media {
  aspect-ratio: 3 / 4;
}

/* Aspect-ratio modifiers, independent of row type, for mixed
   orientation placeholders within one zigzag section. Capped
   max-width + justify-self keep them editorial-sized (not stretched
   to fill the whole grid column) and inset toward the text gutter. */
.zigzag__media--landscape {
  aspect-ratio: 3 / 2;
  max-width: 380px;
  justify-self: start;
}

.zigzag__media--portrait {
  aspect-ratio: 3 / 4;
  max-width: 280px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media--landscape,
.zigzag__row--reverse .zigzag__media--portrait {
  justify-self: end;
}

/* Plain gray placeholder box standing in for a not-yet-final image
   (e.g. nantes.html) — sized via the .zigzag__media--landscape it's
   paired with, so it matches the footprint of a real zigzag image. */
.zigzag__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  background: #d9d9d9;
  text-align: center;
  padding: 20px;
  box-sizing: border-box;
}

.zigzag__placeholder-label {
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--color-ink-soft);
}

/* Two images stacked vertically in one zigzag column (e.g.
   mazor.html). Each image keeps its own natural aspect ratio — no
   forced equal heights — sharp corners by default (no border-radius
   set anywhere on plain <img> here). */
.zigzag__media-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 380px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-stack {
  justify-self: end;
}

/* Single image beside a two-image vertical stack (early-projects.html
   row 2) — the single image is vertically centered against the full
   height of the stack next to it. */
.zigzag__media-composite {
  display: flex;
  align-items: center;
  gap: 16px;
  max-width: 537px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-composite {
  justify-self: end;
}

/* Single image is 40% larger than the stack beside it, so the two
   sides use fixed flex-basis ratios (304:217) instead of an equal
   1:1 split. */
.zigzag__media-composite-single {
  flex: 0 0 304px;
  min-width: 0;
}

.zigzag__media-composite-stack {
  flex: 0 0 217px;
  min-width: 0;
}

.zigzag__media-composite-single img {
  display: block;
  width: 100%;
  height: auto;
}

.zigzag__media-composite-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.zigzag__media-composite-stack img {
  display: block;
  width: 100%;
  height: auto;
}

.zigzag__media-stack img {
  display: block;
  width: 100%;
  height: auto;
}

/* Two-column row where the media side holds a pair of images (a
   larger "hero" image plus a smaller one) that read as one grouped
   visual, not a separate grid column. align-items:center on the flex
   pair vertically centers the small image against the taller one
   rather than top-aligning it. Wider media column than a standard
   .zigzag__row since it's carrying two images side by side. */
.zigzag__row--pair-right {
  grid-template-columns: 0.8fr 1.2fr;
}

.zigzag__media-pair {
  display: flex;
  align-items: center;
  gap: 16px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-pair {
  justify-self: end;
}

.zigzag__media-hero {
  max-width: 413px;
}

.zigzag__media-hero img {
  display: block;
  width: 100%;
  height: auto;
}

.zigzag__media-small {
  max-width: 160px;
  flex-shrink: 0;
}

.zigzag__media-small img {
  display: block;
  width: 100%;
  height: auto;
}

/* Single medium-sized image alongside text (not stacked, not the
   large "hero" size) — used for standalone concept/colorful sketches. */
.zigzag__media-solo {
  max-width: 420px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-solo {
  justify-self: end;
}

.zigzag__media-solo--lg {
  max-width: 520px;
}

.zigzag__media-solo img {
  display: block;
  width: 100%;
  height: auto;
}

/* Compact 2x2 grid of same-ratio images, sized like the other
   editorial media classes above (nantes.html Row 2's hand-drawn
   sections) — inset toward the text gutter via max-width +
   justify-self, not stretched across the whole column. */
.zigzag__media-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  max-width: 380px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-grid {
  justify-self: end;
}

.zigzag__media-grid img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0;
}

/* Three same-ratio images side by side, capped to the same editorial
   width as the other media classes (nantes.html Row 3) rather than
   stretching across the full column. */
.zigzag__media-trio {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-trio {
  justify-self: end;
}

/* Vertically center the three images against each other instead of
   the default top-alignment (early-projects.html row 1 only). */
.zigzag__media-trio--center-imgs {
  align-items: center;
}

.zigzag__media-trio img {
  display: block;
  flex: 1 1 0;
  min-width: 0;
  width: 100%;
  height: auto;
}

/* Two portrait images side by side, each sized like a single
   .zigzag__media--portrait image (kempton.html's photo size) rather
   than a pair squeezed into one editorial-width box — pair with
   .zigzag__row--pair-right for the extra column room this needs. */
.zigzag__media-duo {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  justify-self: start;
}

.zigzag__row--reverse .zigzag__media-duo {
  justify-self: end;
}

.zigzag__media-duo img {
  display: block;
  flex: 0 1 280px;
  min-width: 0;
  max-width: 280px;
  width: 100%;
  height: auto;
}

.zigzag__row--sketch .zigzag__media {
  aspect-ratio: 4 / 3;
}

/* Centered large-format headline rows */
.zigzag__headline {
  max-width: 760px;
  margin: 0 auto 120px;
  text-align: center;
}

.zigzag__headline p {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  line-height: 2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-green-dark);
  margin: 0;
}

/* Scattered photo collage row — staggered, airy, not gridded */
.zigzag__collage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  margin-bottom: 40px;
}

.zigzag__collage .img-placeholder {
  position: absolute;
  min-height: 0;
  border-radius: 0;
}

.zigzag__collage .img-placeholder:nth-child(1) {
  left: 6%;
  top: 8%;
  width: 30%;
  height: 30%;
}

.zigzag__collage .img-placeholder:nth-child(2) {
  left: 54%;
  top: 24%;
  width: 30%;
  height: 32%;
}

.zigzag__collage .img-placeholder:nth-child(3) {
  left: 14%;
  top: 64%;
  width: 30%;
  height: 30%;
}

@media (max-width: 860px) {
  .zigzag {
    margin-top: 64px;
  }
  .zigzag__row,
  .zigzag__row--intro,
  .zigzag__row--sketch {
    grid-template-columns: 1fr;
    gap: 28px;
    margin-bottom: 72px;
  }
  .zigzag__row--sketch .zigzag__media,
  .zigzag__row--reverse .zigzag__media {
    order: 0;
  }
  .zigzag__media--landscape,
  .zigzag__media--portrait,
  .zigzag__media-stack,
  .zigzag__media-solo,
  .zigzag__media-solo--lg,
  .zigzag__media-pair {
    justify-self: center;
    max-width: 320px;
  }
  .zigzag__media-pair {
    flex-direction: column;
    align-items: center;
  }
  .zigzag__media-hero,
  .zigzag__media-small {
    max-width: 100%;
  }
  .zigzag__media-grid,
  .zigzag__media-trio,
  .zigzag__media-duo {
    justify-self: center;
    max-width: 320px;
  }
  .zigzag__media-trio,
  .zigzag__media-duo {
    flex-direction: column;
  }
  .zigzag__media-composite {
    justify-self: center;
    max-width: 320px;
    flex-direction: column;
  }
  .zigzag__media-composite-stack {
    flex-direction: row;
  }
  .zigzag__headline {
    margin-bottom: 72px;
  }
  .zigzag__collage {
    position: static;
    aspect-ratio: auto;
    display: flex;
    flex-direction: column;
    gap: 20px;
  }
  .zigzag__collage .img-placeholder {
    position: static;
    width: 100%;
    height: auto;
    min-height: 220px;
  }
}

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

.footer {
  margin-top: 100px;
  padding: 56px 0 40px;
  border-top: 1px solid var(--color-line);
  text-align: center;
  color: var(--color-ink);
}

/* Minimal homepage-only footer: just the contact icons, no badge/nav/
   meta text, right below the full-viewport hero. */
.mini-footer {
  padding: 22px 0;
  text-align: center;
}

.mini-footer .footer__social {
  margin: 0;
}

.footer__badge {
  width: 122px;
  height: 122px;
  margin: 0 auto 26px;
  color: var(--color-green);
}

.footer__nav {
  display: flex;
  justify-content: center;
  gap: 28px;
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

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

.footer__social {
  display: flex;
  justify-content: center;
  gap: 14px;
  margin: 0 0 24px;
}

.footer__social a {
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-line);
  border-radius: 50%;
  transition: border-color 0.2s ease;
}

.footer__social a:hover {
  border-color: var(--color-green);
}

.footer__social svg {
  width: 17px;
  height: 17px;
  stroke: var(--color-green);
  fill: none;
  stroke-width: 1.4;
}

.footer__meta {
  font-size: 0.7rem;
  color: var(--color-ink-soft);
  letter-spacing: 0.04em;
}

/* ============================================
   SIMPLE PAGE (stub pages)
   ============================================ */

.stub-main {
  margin-top: 40px;
  min-height: 46vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 60px 32px;
}

.stub-main h1 {
  font-size: 2.2rem;
  margin-bottom: 12px;
}

.stub-main p {
  color: var(--color-ink-soft);
  max-width: 480px;
  margin: 0 auto;
}

/* ============================================
   PROJECT GRID (landscape.html)
   ============================================ */

.project-grid-main {
  margin-top: 56px;
  padding-bottom: 40px;
}

.project-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 48px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.project-card a {
  display: block;
}

.project-card__image {
  width: 100%;
  aspect-ratio: 800 / 950;
  object-fit: cover;
  transition: opacity 0.2s ease;
}

.project-card a:hover .project-card__image {
  opacity: 0.85;
}

.project-card__title {
  display: block;
  margin-top: 20px;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink);
  text-align: center;
}

.project-card__location {
  display: block;
  margin-top: 4px;
  font-size: 0.78rem;
  color: var(--color-ink-soft);
  text-align: center;
}

@media (max-width: 860px) {
  .project-grid {
    grid-template-columns: 1fr;
    gap: 40px;
    max-width: 360px;
    margin: 0 auto;
  }
}

/* ============================================
   PROJECT PAGE — CAROUSEL, TEXT PLACEHOLDER,
   BOOKLET COVERS (kempton.html etc.)
   ============================================ */

/* Full-bleed hero: intro text ~35% left, carousel ~65% right. The
   carousel keeps the mockup images' true 3:2-ish aspect ratio (no
   stretch) — min-height just reserves a full first fold so the
   zigzag section below doesn't peek into view; align-items:center
   means any leftover space becomes whitespace around the centered
   content rather than stretching anything to fill it. Direct child
   of body (like the homepage hero), not inside .page-shell, so it
   spans the full width. */
.project-hero-top {
  display: grid;
  grid-template-columns: 35fr 65fr;
  align-items: center;
  width: 100%;
  min-height: 100vh;
}

.project-hero-top__intro {
  position: relative;
  padding: 40px 48px;
}

.project-hero-top__media {
  padding: 0 56px;
}

.carousel {
  position: relative;
  width: 100%;
}

.carousel__viewport {
  /* Slightly shorter than the source images' true 3:2 ratio, so
     object-fit: cover crops a little off the top/bottom (into the
     mockups' own grey margin) instead of showing letterboxed grey
     bars — a deliberate small crop, not a stretch. */
  aspect-ratio: 8 / 5;
  background: #f2f0ea;
  overflow: hidden;
}

.carousel__slide {
  display: none;
  width: 100%;
  height: 100%;
}

.carousel__slide.is-active {
  display: block;
}

.carousel__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Crop from the top instead of centered, so the bottom of each image
   (captions, labels) always stays fully visible. Scoped to mazor.html
   specifically so it doesn't change kempton.html's already-tuned crop. */
.carousel--anchor-bottom .carousel__slide img {
  object-position: bottom;
}

/* mazor.html only — match the carousel's background to the page
   background instead of the default cream mockup background. */
.carousel--anchor-bottom .carousel__viewport {
  background: #faf8f5;
}

/* Single-image slide that shouldn't be cropped (nantes.html's sites
   map, slide 1) — object-fit: contain shrinks it to fit instead. */
.carousel__slide--fit img {
  object-fit: contain;
}

/* nantes.html only — match the carousel's background to the page
   background instead of the default cream mockup background. */
.carousel--nantes .carousel__viewport {
  background: #faf8f5;
}

.carousel__stack {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

.carousel__stack-item {
  position: relative;
  flex: 1 1 0;
  min-height: 0;
}

.carousel__stack-item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Slide 2 (aerials): object-fit: contain instead, guaranteeing no
   cropping — shrinks each image and letterboxes as needed. */
.carousel__stack--contain .carousel__stack-item img {
  object-fit: contain;
}

/* Slide 4 (sections): same fixed-height slide as everything else —
   each image gets an equal share of that height via object-fit:
   contain (no cropping, shrinks to fit). The label is a normal
   caption line sitting directly above the image (flush left, tight
   gap) rather than an absolute overlay, since with contain's
   letterboxing an overlay can end up floating over empty space
   instead of over the image itself. */
.carousel__stack--caption .carousel__stack-item {
  display: flex;
  flex-direction: column;
}

.carousel__stack--caption .carousel__stack-label {
  position: static;
  display: block;
  margin-bottom: 4px;
}

.carousel__stack--caption .carousel__stack-item img {
  display: block;
  width: 100%;
  flex: 1 1 0;
  min-height: 0;
  object-fit: contain;
}

.carousel__stack--gap {
  gap: 12px;
}

/* Small caption in the corner of a stacked image, styled like the
   carousel's page counter (same size/letter-spacing/color). */
.carousel__stack-label {
  position: absolute;
  top: 12px;
  left: 12px;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

@media (max-width: 900px) {
  .project-hero-top {
    grid-template-columns: 1fr;
  }
  .project-hero-top__intro {
    padding: 48px 24px 24px;
  }
  .project-hero-top__media {
    padding: 0 40px;
  }
}

/* Arrows sit beside the carousel (in the reserved side padding),
   not overlaid on the image itself — minimal thin chevrons, no
   background circle needed since they're on plain page background. */
.carousel__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--color-nav-text);
  opacity: 0.7;
  transition: opacity 0.2s ease;
}

.carousel__arrow:hover {
  opacity: 1;
}

.carousel__arrow--prev {
  left: -48px;
}

.carousel__arrow--next {
  right: -48px;
}

.carousel__arrow svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  stroke-width: 1.5;
  fill: none;
}

.carousel__counter {
  margin-top: 14px;
  text-align: center;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--color-ink-soft);
}

/* Carousel full-width with arrows moved onto the image, and closing
   the gap above it — shared by kempton/mazor/nantes, since all use
   the same .carousel/.project-hero-top markup. Placed after the
   desktop .carousel__arrow--prev/--next rules above (not just inside
   its own media query) so it actually wins the cascade — CSS applies
   the later same-specificity rule regardless of which is inside a
   media query, so putting this block earlier in the file left the
   desktop -48px values winning even under 768px viewports. */
@media (max-width: 768px) {
  /* min-height: 100vh plus align-items: center is what was leaving a
     large empty gap between the intro text and the carousel once
     they stack into one column — the section no longer needs to
     force itself to a full screen tall on mobile. */
  .project-hero-top {
    min-height: auto;
  }

  /* Removes the side padding that reserved room for the arrows
     outside the carousel, so the carousel (already width: 100% from
     its base rule) has no horizontal margin left around it. */
  .project-hero-top__media {
    padding: 0;
  }

  /* Arrows were positioned in that now-removed side padding
     (left/right: -48px, outside the image). Move them onto the
     image itself instead. */
  .carousel__arrow--prev {
    left: 12px;
  }

  .carousel__arrow--next {
    right: 12px;
  }

  /* Kempton's mind-map row bleeds up and left into the row above it
     on desktop via a deliberate negative margin + oversized width
     (see the comment on .zigzag__media--mindmap above) — that's a
     two-column-layout trick. Once rows stack to a single column on
     mobile, the same negative margin instead drags the image up on
     top of the row above it (the game-board photo), overlapping the
     two. Reset it to a normal, non-overlapping full-width image. */
  .zigzag__media--mindmap {
    width: 100%;
    margin-top: 0;
    margin-left: 0;
    align-self: auto;
  }
}

/* Optional small project logo (e.g. mazor.html). Positioned absolute,
   sitting just above the intro block rather than in normal flow, so
   it doesn't add to the block's height and push the vertically-
   centered title down — the title lines up with pages that have no
   logo at all (e.g. kempton.html). */
.project-meta__logo {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 24px);
  transform: translateX(-50%);
  height: 160px;
  width: auto;
}

/* Title + location + intro + booklet link — left column of
   .project-hero-top, or standalone (no special width needed either
   way since it just fills its container). */
.project-meta__title {
  font-size: 1.6rem;
  font-weight: 400;
  margin: 0 0 4px;
  color: var(--color-ink);
}

.project-meta__location {
  font-size: 0.95rem;
  font-weight: 400;
  margin: 0;
  color: var(--color-ink-soft);
}

.project-meta__credit {
  font-size: 0.8rem;
  font-style: italic;
  font-weight: 400;
  margin: 6px 0 0;
  color: var(--color-ink-soft);
}

.project-meta__intro {
  font-size: 0.95rem;
  font-weight: 400;
  line-height: 1.7;
  color: var(--color-ink-soft);
  margin: 18px 0 0;
  max-width: 440px;
}

.project-meta__link {
  display: inline-block;
  margin-top: 16px;
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  color: var(--color-green-dark);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}

.project-meta__link:hover {
  border-color: var(--color-green-dark);
}

/* Placeholder text block below the carousel */
.project-text-placeholder {
  max-width: 720px;
  margin: 70px auto 0;
  padding: 40px 32px;
  border: 1.5px dashed var(--color-ink-soft);
  text-align: center;
  color: var(--color-ink-soft);
  font-size: 0.95rem;
  line-height: 1.7;
}

/* Small left-aligned heading above the booklet row, matching
   .project-meta__title's weight/alignment. */
.booklet-section__title {
  max-width: 860px;
  margin: 90px auto 0;
  padding-left: 6px;
  font-size: 1rem;
  font-weight: 400;
  color: var(--color-ink);
  text-align: left;
}

.booklet-section__subtitle {
  max-width: 860px;
  margin: 6px auto 0;
  padding-left: 6px;
  font-size: 0.82rem;
  font-weight: 400;
  color: var(--color-ink-soft);
  text-align: left;
}

/* Physical booklet covers, resting side by side */
.booklet-row {
  margin-top: 28px;
  padding-bottom: 70px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 56px;
  flex-wrap: wrap;
}

.booklet-cover {
  background: linear-gradient(160deg, #f6f4ef, #e9e6de 140%);
  border: 1px solid var(--color-line);
  box-shadow: 0 20px 34px -16px rgba(43, 43, 35, 0.3);
  overflow: hidden;
}

.booklet-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.booklet-cover__label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  text-align: center;
  padding: 14px;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  color: var(--color-ink-soft);
  line-height: 1.6;
}

/* Sized to each real cover's own aspect ratio */
.booklet-cover--square {
  width: 220px;
  height: 218px;
}

.booklet-cover--portrait {
  width: 164px;
  height: 230px;
}

.booklet-cover--landscape {
  width: 250px;
  height: 176px;
}

@media (max-width: 700px) {
  .booklet-row {
    gap: 32px;
  }
  .booklet-cover--square {
    width: 160px;
    height: 158px;
  }
  .booklet-cover--portrait {
    width: 120px;
    height: 168px;
  }
  .booklet-cover--landscape {
    width: 182px;
    height: 128px;
  }
}

/* ============================================
   POEM BANNER (mazor.html)
   ============================================ */

/* Full-width strip sitting between the zigzag content and the
   footer, both inside .page-shell — breaks out of the shell's
   max-width/padding via the viewport-width technique so it still
   spans edge to edge despite being nested. */
.poem-banner {
  position: relative;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  display: block;
}

.poem-banner img {
  display: block;
  width: 100%;
  height: auto;
}

/* Zero out the zigzag's trailing space (the last row's bottom
   margin collapses up through <main>, which has no padding/border
   of its own) and the footer's leading space, so the banner sits
   flush against both. */
.project-hero:has(+ .poem-banner) .zigzag__row:last-child {
  margin-bottom: 0;
}

.poem-banner + .footer {
  margin-top: 0;
}

/* Opt-in extra breathing room above the banner (nantes.html) — the
   zigzag's last row is still zeroed out by the rule above, so this
   padding is the entire visible gap, not layered on top of it. */
.poem-banner--spaced {
  padding-top: 96px;
  padding-bottom: 72px;
}

/* ============================================
   EARLY PROJECTS (early-projects.html) — zigzag
   text/image rows, same as mazor.html/nantes.html
   ============================================ */

.early-projects__list {
  font-size: 0.98rem;
  line-height: 1.8;
  color: var(--color-ink-soft);
  margin: 0 0 20px;
  padding-left: 22px;
}

.early-projects__list li {
  margin-bottom: 8px;
}

.early-projects__list li:last-child {
  margin-bottom: 0;
}

/* JS-driven slideshow (wheel events move slides via `top`, see the
   inline script at the bottom of early-projects.html) — no native
   scrolling or CSS scroll-snap involved at all. */
html:has(body.page-early-projects) {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

.page-early-projects {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

.page-early-projects .site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  background-color: var(--color-bg);
}

.page-early-projects #slider {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* All slides rest at top: 0, stacked directly on top of each other —
   it's the z-index order (assigned once in script.js, earlier slide
   = higher = on top) that makes only the current one visible, not
   position. Scrolling down animates the current slide's own top to
   -100% (wiping it up and off-screen) to reveal whichever slide is
   already sitting beneath it; scrolling up animates that same slide
   's top back to 0, and since its z-index was always higher than
   the one it's covering, no z-index needs to change at runtime. */
.page-early-projects .zigzag__slide {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  /* Lets a slide scroll internally if its centered content is
     taller than the viewport, instead of being clipped by #slider's
     own overflow: hidden (which has to stay hidden — it's what
     keeps off-screen slides invisible during the wipe). */
  overflow-y: auto;
  /* Opaque so the covering slide actually hides the one beneath it,
     instead of both showing through in the gaps around each other's
     centered content. */
  background-color: var(--color-bg);
  /* Nav is a fixed overlay, so the top ~80px of each slide would
     otherwise sit behind it. */
  padding-top: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: top 1s cubic-bezier(0.77, 0, 0.175, 1);
}

/* Slide 4 only: its content (composite images + the lessons list)
   is the tallest of the four, so on shorter screens center-aligning
   it clips the top before the user can scroll up to see it. Top-
   aligning it instead means the top of the content is always the
   first thing in view. padding-top adds 10vh of breathing room on
   top of (not instead of) the base rule's 80px nav clearance above —
   at 10vh alone, short viewports (under ~800px tall) would put the
   content behind the fixed nav. overflow-y: auto already applies via
   the base .zigzag__slide rule above. */
.page-early-projects .zigzag__slide--top-aligned {
  align-items: flex-start;
  padding-top: calc(80px + 10vh);
}

/* Slide 2 only: same fix as slide 4 above — its composite image
   group plus two paragraphs was tall enough to have its top clipped
   when center-aligned on shorter screens. 8vh instead of 10vh since
   its content runs a bit shorter than slide 4's. */
.page-early-projects .zigzag__slide--top-aligned-sm {
  align-items: flex-start;
  padding-top: calc(80px + 8vh);
}

/* Slide 4 now holds its own content plus the footer stacked below
   it, both wrapped in one full-width block so they stack vertically
   as the slide's single flex child — .zigzag__slide's own
   display: flex (row by default) would otherwise lay two direct
   .page-shell children out side by side instead of top-to-bottom. */
.page-early-projects .zigzag__slide-inner {
  width: 100%;
}

/* .zigzag's (and .footer's) normal top margin would offset a
   slide's content away from true vertical center now that each
   slide centers its content via flex. */
.page-early-projects .zigzag,
.page-early-projects .footer {
  margin-top: 0;
}

/* Scroll hint — a small bouncing chevron at the bottom of every
   slide except the last. It's a normal child of its own
   .zigzag__slide (which is already position: absolute, so it
   establishes the containing block this positions against), so it
   moves with that slide and disappears the instant it wipes away. */
.page-early-projects .zigzag__slide-hint {
  position: absolute;
  left: 50%;
  bottom: 30px;
  width: 20px;
  height: 20px;
  color: var(--color-ink-soft);
  transform: translateX(-50%);
  animation: zigzag-slide-hint-bounce 1.8s ease-in-out infinite;
}

.page-early-projects .zigzag__slide-hint svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@keyframes zigzag-slide-hint-bounce {
  0%, 100% {
    transform: translateX(-50%) translateY(0);
  }
  50% {
    transform: translateX(-50%) translateY(6px);
  }
}

/* ============================================
   POEM SECTION (mazor.html) — real HTML text,
   Hebrew + English side by side, no image
   ============================================ */

.poem-section {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 64px;
  padding: 96px 24px;
  background: transparent;
}

.poem-section__col--he {
  text-align: right;
}

.poem-section__col--en {
  text-align: left;
}

.poem-section__lines {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: 1.05rem;
  line-height: 2;
  color: var(--color-ink-soft);
  margin: 0 0 24px;
}

.poem-section__credit {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--color-ink-soft);
  margin: 0;
}

@media (max-width: 700px) {
  .poem-section {
    flex-direction: column;
    align-items: center;
    gap: 40px;
    padding: 64px 24px;
  }
  .poem-section__col--he,
  .poem-section__col--en {
    text-align: center;
  }
}

/* ============================================
   ABOUT (about.html) — sticky photo right,
   scrolling text left, no hero
   ============================================ */

/* Scoped to about.html only — the nav is shared across every page,
   so this shouldn't make it sticky site-wide. */
.page-about .site-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: #faf8f5;
  backdrop-filter: none;
}

/* The global body rule sets overflow-x:hidden for other pages' full-
   bleed breakout tricks (see .poem-banner) — about.html doesn't use
   that technique, so let the right column be the only thing that
   clips its own content. */
body.page-about {
  overflow-x: visible;
}

/* Grid, not flex: flex-basis percentages that sum to 100% (55%+45%)
   don't automatically account for `gap`, so the old flex version
   overflowed its own container by exactly the gap width (60px) —
   the photo column was hanging 60px past page-shell's right edge.
   Grid's fr tracks correctly subtract the gap before dividing up
   the remaining space, so 55fr/45fr can't overflow this way. */
.about-main {
  display: grid;
  grid-template-columns: 55fr 45fr;
  align-items: start;
  gap: 60px;
  margin-top: 0;
  padding-bottom: 160px;
}

.about__text {
  padding-top: 100px;
}

/* calc()/margin-bottom on the sticky element itself proved
   unreliable, so the column is a plain sticky positioning context —
   the actual inset (top/bottom/left breathing room) lives on an
   absolutely-positioned inner wrapper instead. `top` is pinned to the
   nav's own rendered height (79px, measured) rather than 0 — with
   top:0 the browser lets the column keep scrolling with the page
   until it reaches the very top of the viewport, so the image visibly
   slides that distance on the first scroll before locking in place
   under the nav. Pinning top to the nav height makes it stick the
   instant it reaches that position instead. Height is reduced by the
   same nav height plus 40px for the bottom breathing room, so the box
   still doesn't run past the viewport's bottom edge at rest. */
.about__photo {
  position: sticky;
  top: 80px;
  height: calc(100vh - 80px - 40px);
  overflow: visible;
}

/* Aligns the image's right edge with the nav's "About" link. The
   nav spans the full window (its own 48px padding), while this
   column is bound to page-shell's centered max-width — the gap
   between those two edges grows by exactly half of any viewport
   width change (page-shell's edge only moves at half rate since
   it's centered, nav's moves 1:1 with the window), so a flat pixel
   offset only lines up at one specific window width. This formula
   was fit from real measurements at 1400px and 1920px viewports
   (94.5px and 354.5px of native gap respectively — an exact 50vw
   slope), not guessed. */
.about__photo-inner {
  position: absolute;
  top: 20px;
  bottom: 40px;
  left: 42px;
  right: calc(606px - 50vw);
  overflow: hidden;
}

/* contain, not cover: the photo is a tall vertical strip (ratio
   ~0.56) but its box is much wider/shorter than that (~0.87), so
   cover was scaling the image up and cropping off roughly a third
   of its height (top and bottom) to fill the box's width. contain
   shows the whole photo, letterboxed left/right instead. */
.about__photo-inner img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.about__cv-link {
  display: block;
  margin-top: 4px;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  color: var(--color-ink-soft);
  text-decoration: none;
}

.about__cv-link:hover {
  text-decoration: underline;
}

.about__title {
  font-family: var(--font-hand);
  font-size: 3.2rem;
  font-weight: 400;
  line-height: 1.1;
  color: #e44d3c;
  margin: 0 0 28px;
}

.open-to-section {
  margin-top: 60px;
}

.open-to-label {
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #888;
  margin-bottom: 14px;
}

.open-to-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.tag {
  display: inline-block;
  padding: 8px 16px;
  border: 1px solid #ccc;
  border-radius: 999px;
  font-size: 0.85rem;
  color: #333;
  background: transparent;
}

.about__self-portrait {
  text-align: center;
}

.about__self-portrait-caption {
  font-size: 0.8rem;
  font-style: italic;
  color: var(--color-ink-soft);
  margin: 10px 0 0;
}

@media (max-width: 860px) {
  .about-main {
    grid-template-columns: 1fr;
    gap: 40px;
    margin-top: 64px;
    padding-bottom: 96px;
  }
  .about__text {
    padding-top: 0;
  }
  .about__photo {
    position: relative;
    height: 60vh;
  }
  .about__title {
    font-size: 2.4rem;
  }
}

/* ============================================
   MOBILE OVERRIDES (max-width: 768px)
   Added as its own standalone block, appended after everything else
   in this file (per request — nothing above this point was changed).

   Two things worth knowing about how this interacts with the rest
   of the file:
   1. .zigzag__row and .about-main are CSS Grid, not Flexbox, so
      collapsing them to one column uses grid-template-columns, not
      flex-direction (which has no effect on a grid container).
   2. This is not the only responsive breakpoint in the file — nav
      already adjusts at 780px, the homepage hero nav at 700px, and
      both .zigzag__row and .about-main (including un-stickying the
      about-page photo) at 860px. Since all of those thresholds are
      above 768px, their rules already apply here too; this block
      only adds what those don't already cover, and re-states a
      couple of already-true values (like grid-template-columns: 1fr)
      so this block reads as complete on its own. It does not touch
      .about__photo's height/position, since that's already correctly
      handled by the 860px block — redeclaring it here with a
      different value risked collapsing that column's height.
   ============================================ */
@media (max-width: 768px) {
  /* ---- Nav bar ---- */
  .site-nav__inner {
    flex-wrap: wrap;
  }

  .site-nav__logo {
    font-size: 1.8rem;
  }

  .symbol-nav__list {
    flex-wrap: wrap;
    gap: 16px;
  }

  .symbol-nav__item a {
    font-size: 0.65rem;
  }

  /* ---- Homepage nav ---- */
  .landing-hero__topbar {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }

  .landing-hero__logo {
    font-size: 1.8rem;
  }

  .landing-hero__nav {
    flex-wrap: wrap;
    gap: 16px;
    padding-top: 0;
  }

  /* ---- Zigzag two-column sections (mazor, nantes, kempton,
     early-projects) — grid, not flex, so this is the property that
     actually stacks text and image vertically. ---- */
  .zigzag__row,
  .zigzag__row--intro,
  .zigzag__row--sketch {
    grid-template-columns: 1fr;
  }

  /* ---- About page two-column layout — text stays first in source
     order, so it already renders above the photo once stacked; the
     photo itself stops being sticky via the existing 860px rule. ---- */
  .about-main {
    grid-template-columns: 1fr;
  }

  /* ---- General: scale down the largest remaining headings ---- */
  .about__title {
    font-size: 2rem;
  }

  .stub-main h1 {
    font-size: 1.8rem;
  }
}

/* ============================================
   MAZOR.HTML — mobile-only fixes
   Placed at the very end of the file so these overrides reliably
   win the cascade against the earlier desktop/860px rules they
   target (.project-meta__logo, .zigzag__media-solo--lg), regardless
   of where else in the file those get referenced.
   ============================================ */
@media (max-width: 768px) {
  /* The logo floats above .project-hero-top__intro via
     position: absolute + bottom: calc(100% + 24px), which only
     clears the nav bar because desktop's min-height: 100vh hero
     gives it a lot of vertical room to float upward into. On mobile
     (already min-height: auto from the shared carousel fix above),
     that same offset can push it up into the nav. Put it back in
     normal document flow instead, with its own margin for spacing,
     so it always renders below the nav and directly above the
     title. */
  .project-meta__logo {
    position: static;
    left: auto;
    bottom: auto;
    transform: none;
    display: block;
    margin: 24px auto 16px;
  }

  /* Concept sketch — full screen width instead of the 320px cap the
     shared 860px rule gives every other .zigzag__media-solo, with
     height: auto so it scales proportionally rather than cropping
     or distorting. */
  .zigzag__media-solo--lg {
    width: 100%;
    max-width: 100%;
    height: auto;
  }

  /* Closing row: reorder so the graphic sits between the closing
     paragraph and the poem section that follows it — text first,
     then image — using `order` (works on grid items exactly like
     flex items; .zigzag__row is a grid, not flex) so the HTML itself
     doesn't need to change. */
  .zigzag__row--closing-reorder .zigzag__media-solo {
    order: 2;
  }
}

/* Closing row's graphic (colorful-sketch), stacked view — the row
   carries .zigzag__row--reverse for its desktop justify-self: end
   (pins the image to the gutter next to the text column), but that
   2-class selector outranks the general .zigzag__media-solo {
   justify-self: center } every other stacked solo image gets at
   860px, leaving this one alone flush against the right edge instead
   of centered once the columns collapse. Same 2-class specificity as
   that --reverse rule, placed after it, wins the tie. */
@media (max-width: 860px) {
  .zigzag__row--closing-reorder .zigzag__media-solo {
    justify-self: center;
  }
}

/* ============================================
   MOBILE NAV — hide the old link list everywhere
   Site-wide (all 9 pages): on mobile, the + menu is now the only
   way to navigate. The name/logo on the left stays untouched;
   desktop is untouched too — this only removes the horizontal link
   list at 768px and below. Placed at the true end of the file so it
   reliably wins over every earlier .symbol-nav__list /
   .landing-hero__nav rule regardless of their own source order.
   ============================================ */
@media (max-width: 768px) {
  /* The 8 pages using the standard header (about, kempton, mazor,
     nantes, landscape, workshops, other-mediums, early-projects). */
  .symbol-nav__list {
    display: none;
  }

  /* index.html's homepage hero nav — already hidden by an earlier
     rule, restated here for clarity/completeness now that hiding
     the link nav is a site-wide rule, not homepage-specific. */
  .landing-hero__nav {
    display: none;
  }

  /* index.html only: the + button sits over the photo hero, so it
     stays white instead of the brown used on the other 8 pages. */
  .page-home #mobile-menu-btn {
    color: var(--color-surface);
  }
}

/* ============================================
   EARLY-PROJECTS.HTML — mobile layout, slide system stays active
   The desktop wipe slideshow (position: fixed, height: 100vh per
   slide, wheel-driven wipe transitions) keeps running on mobile too
   — the JS just gained touch support alongside the existing wheel
   listener (see the touchstart/touchend block in the page's own
   <script>). What changes here is purely what's INSIDE each slide:
   text on top, its 3 images below in a 2-over-1 triangle.
   ============================================ */
@media (max-width: 768px) {
  /* Breathing room on every edge, in addition to (not instead of)
     the existing padding-top that clears the fixed nav — the base
     rule and the --top-aligned/--top-aligned-sm variants already
     set that per slide, so it's deliberately left alone here. */
  .page-early-projects .zigzag__slide {
    padding-left: 20px;
    padding-right: 20px;
    padding-bottom: 20px;
  }

  /* Rows 2 and 4 put the image group first in the DOM
     (.zigzag__row--reverse, for desktop's side-by-side layout) —
     reorder so text always renders above the images on mobile. */
  .page-early-projects .zigzag__row--reverse .zigzag__text {
    order: 1;
  }

  .page-early-projects .zigzag__row--reverse .zigzag__media-composite {
    order: 2;
  }

  /* Rows 1 and 3: three flat images in a row — wrap into a triangle
     (2 up top, 1 centered below) instead of a single row. The base
     rule's max-width: 320px (shared with kempton/mazor/nantes) plus
     its 16px gap is too tight for two 48%-wide images to fit on one
     line (2 × 48% + 16px comes out wider than a 320px box), which
     was wrapping every image onto its own line instead of pairing
     the first two — widening the box and switching to a percentage
     gap fixes that regardless of the exact screen width. */
  .page-early-projects .zigzag__media-trio {
    /* The shared 860px rule (.zigzag__media-trio, .zigzag__media-duo)
       sets flex-direction: column for every other page's trio — since
       that's a different property than the ones overridden below, the
       cascade lets it fall through here even though this selector is
       more specific, so it has to be reset back to row explicitly. */
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    max-width: 100%;
    gap: 3%;
  }

  .page-early-projects .zigzag__media-trio img:nth-child(1),
  .page-early-projects .zigzag__media-trio img:nth-child(2) {
    width: 48%;
    flex: 0 0 48%;
  }

  .page-early-projects .zigzag__media-trio img:nth-child(3) {
    width: 60%;
    flex: 0 0 60%;
    margin: 0 auto;
  }

  /* Rows 2 and 4: same triangle, built from the existing single +
     stack structure instead of 3 flat images — the stack's 2 images
     become the top pair, the single image becomes the bottom one.
     flex: 0 0 auto resets the base rule's fixed pixel flex-basis
     (304px/217px, sized for the desktop row's horizontal axis),
     which would otherwise size these as heights now that the
     container's main axis has switched to column. */
  .page-early-projects .zigzag__media-composite {
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: 100%;
  }

  .page-early-projects .zigzag__media-composite-single,
  .page-early-projects .zigzag__media-composite-stack {
    flex: 0 0 auto;
  }

  .page-early-projects .zigzag__media-composite-stack {
    order: 1;
    flex-direction: row;
    justify-content: center;
    width: 100%;
  }

  .page-early-projects .zigzag__media-composite-stack img {
    width: 48%;
  }

  .page-early-projects .zigzag__media-composite-single {
    order: 2;
    width: 60%;
  }
}

/* ============================================
   NANTES.HTML — mobile-only fixes
   Carousel full-width + inside arrows is already covered by the
   shared kempton/mazor 768px rules above (.project-hero-top,
   .project-hero-top__media, .carousel__arrow--prev/--next are all
   unscoped, so they already apply here too).
   ============================================ */
@media (max-width: 768px) {
  /* The 4 section sketches sit before the ecology paragraph in this
     row's markup (image first, .zigzag__row--reverse), so once
     stacked to one column on mobile they render above that text.
     Re-order so the text comes first and the sketches land between
     the ecology paragraph and the next row (the site section), which
     already immediately follows in the DOM — no HTML move needed. */
  .zigzag__row--ecology-reorder .zigzag__media-grid {
    order: 2;
  }

  /* The shared 860px rule sets .zigzag__media-grid to
     justify-self: center (the grid equivalent of margin: 0 auto for
     a block), but .zigzag__row--reverse .zigzag__media-grid
     (justify-self: end, for desktop) is more specific and wins
     regardless of source order — so it has to be re-overridden here
     with an equally-specific selector. justify-content centers the
     2x2 grid's own tracks/images within that centered box. */
  .zigzag__row--ecology-reorder .zigzag__media-grid {
    justify-self: center;
    justify-content: center;
  }

  /* Reflection row's own bottom margin (120px, from the shared base
     .zigzag__row rule) plus this padding was leaving roughly 200px+
     of empty space above the closing banner. */
  .poem-banner--spaced {
    padding-top: 24px;
  }

  .project-hero + .zigzag .zigzag__row:last-child {
    margin-bottom: 0;
  }
}

/* ============================================
   ABOUT.HTML — mobile fixes
   Placed at the true end of the file so these reliably win the
   cascade against the desktop/860px rules they target.
   ============================================ */
@media (max-width: 860px) {
  /* Desktop pins this photo next to the text via .about__photo-inner's
     absolute-positioning formula (right: calc(606px - 50vw), etc.),
     which only resolves to a sane width at wide viewports — well
     under it the computed right-inset exceeds the column's own
     width, collapsing the image to near-zero width and making it
     effectively invisible once the columns stack for mobile. Reset
     the wrapper chain back to normal flow instead of patching that
     formula for narrow widths, and pull the whole .about__photo grid
     item above .about__text (which starts with the "I'm Naomi,"
     heading) via order, so the photo renders at the very top of the
     page content instead of at the bottom or not at all. */
  .about__photo {
    order: -1;
    position: static;
    height: auto;
    overflow: visible;
  }

  .about__photo-inner {
    position: static;
    top: auto;
    bottom: auto;
    left: auto;
    right: auto;
    overflow: visible;
  }

  .about__photo-inner img {
    width: 50%;
    max-width: 200px;
    height: auto;
    display: block;
    margin: 0 auto 24px;
  }

  /* Self portrait (Grade 4 drawing) is now the last image on the
     page once the photo above moves to the top — its own caption
     already sits flush against it (margin-bottom: 0), so the two
     real sources of the gap before the footer are .about-main's
     desktop padding-bottom (96px, from the 860px rule above) and
     the .footer rule's own margin-top: 100px, which apply
     regardless of what content is actually last inside the column. */
  .about-main {
    padding-bottom: 24px;
  }

  .page-about .footer {
    margin-top: 24px;
  }
}

/* ============================================
   WORKSHOPS.HTML
   ============================================ */
/* Top of the page: inset hero photo with a hand-drawn bubble on it,
   then a two-column intro (scribble illustration left, welcome text
   right). The scribble PNGs have transparent backgrounds, so they
   composite correctly with no blend mode (mix-blend-mode: screen
   would wash them out against the off-white page). */
.ws-main {
  padding-top: 0;
}

.workshops-hero {
  position: relative;
}

.workshops-hero__img {
  display: block;
  width: 100%;
  height: 50vh;
  object-fit: cover;
  object-position: center 50%;
}

.workshops-hero__bubble {
  position: absolute;
  top: 40px;
  left: 20px;
  width: 280px;
  height: auto;
  pointer-events: none;
}

.ws-intro {
  position: relative;
  overflow: visible;
  display: grid;
  grid-template-columns: 48fr 52fr;
  gap: 64px;
  align-items: start;
}

/* top pulls the whole illustration up into the hero; the matching
   negative margin-bottom stops that from leaving a gap below it. */
.workshops-scribbles {
  position: relative;
  top: -60px;
  margin-bottom: -60px;
  overflow: visible;
  grid-column: 1;
  grid-row: 1;
  min-height: 400px;
}

.workshops-scribbles img {
  position: absolute;
  display: block;
  height: auto;
  pointer-events: none;
}

.workshops-scribbles__blue {
  left: 5%;
  top: 40px;
  width: 88%;
  z-index: 1;
}

.workshops-scribbles__pink {
  left: -50px;
  top: -60px;
  width: 38%;
  z-index: 3;
}

.workshops-scribbles__red {
  right: -80px;
  top: -70px;
  width: 60%;
  z-index: 2;
}

.ws-intro__text {
  grid-column: 2;
  grid-row: 1;
}

.ws-title {
  font-family: var(--font-hand);
  font-size: 2rem;
  font-weight: 400;
  line-height: 1.2;
  color: #e44d3c;
  margin: 0 0 8px;
}

.workshops-subtitle {
  font-family: var(--font-hand);
  font-size: 1.4rem;
  font-weight: 400;
  line-height: 1.3;
  color: var(--color-pink);
  margin: 0 0 28px;
}

.ws-body {
  font-size: 0.98rem;
  line-height: 1.8;
  color: var(--color-ink-soft);
  margin: 0 0 20px;
}

.ws-body strong {
  color: var(--color-ink);
}

.ws-note {
  margin-top: 32px;
}

h2.eyebrow {
  margin-top: 0;
  font-weight: 400;
}

/* Warm orange section labels. */
.ws-main .eyebrow {
  color: #c4824a;
  font-size: 0.85rem;
  font-weight: 600;
  text-transform: uppercase;
  margin-bottom: 20px;
}

/* Uppercase means nothing in Hebrew, so those labels go back to normal
   case at a slightly larger size. */
body.lang-he .ws-main .eyebrow {
  text-transform: none;
  font-size: 1rem;
}

/* Vertical rhythm: every major section carries its own 48px top and
   bottom padding, so sections get no extra margin between them. */
.workshops-intro,
.workshops-what-we-do,
.workshops-how-it-works,
.workshops-closing {
  padding-top: 48px;
  padding-bottom: 48px;
}

/* The intro sits at its natural position under the hero; only the
   scribble column pulls up into the photo. z-index keeps the scribbles
   above the hero. */
.workshops-intro {
  position: relative;
  z-index: 2;
  padding-top: 40px;
  padding-bottom: 0;
}

.ws-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
}

/* Photos keep their natural proportions and sit at 60% of their column
   instead of filling the grid cell. */
.ws-photo img {
  display: block;
  width: auto;
  max-width: 60%;
  height: auto;
  margin: 0 auto;
}

/* Closing: text + form on the left, photo on the right. Horizontal
   padding is 0 because .ws-main already sits inside .page-shell, whose
   own padding would otherwise be doubled and indent this block past
   the sections above it. */
.workshops-closing {
  display: grid;
  grid-template-columns: 55fr 45fr;
  gap: 64px;
  align-items: start;
}

.workshops-closing__media img {
  display: block;
  width: auto;
  max-width: 60%;
  height: auto;
  margin: 0 auto;
}

.ws-closing__line {
  font-family: var(--font-hand);
  font-size: 2.3rem;
  line-height: 1.2;
  color: var(--color-pink);
  text-align: left;
  margin: 0 0 24px;
}

.workshops-contact__note {
  font-size: 0.98rem;
  line-height: 1.8;
  color: var(--color-ink-soft);
  margin: 0;
}

.workshops-form-embed {
  width: 100%;
  max-width: 600px;
  margin-top: 32px;
}

.workshops-form-embed iframe {
  width: 100%;
  border: none;
  display: block;
}

@media (max-width: 768px) {
  .ws-intro,
  .ws-split {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .ws-intro__text,
  .workshops-scribbles {
    grid-column: 1;
  }

  .ws-intro__text {
    grid-row: 1;
  }

  .workshops-scribbles {
    grid-row: 2;
    min-height: 320px;
    top: 0;
    margin-bottom: 0;
  }

  .workshops-hero__bubble {
    width: 200px;
    left: 12px;
    top: 24px;
  }

  /* Stacked below the text, so the desktop pull-up offsets would put
     these over the paragraphs - sit them inside the container instead. */
  .workshops-scribbles__pink {
    left: -4%;
    top: auto;
    bottom: 0;
  }

  .workshops-scribbles__red {
    right: -4%;
    top: 0;
  }

  .workshops-intro,
  .workshops-what-we-do,
  .workshops-how-it-works,
  .workshops-closing {
    padding-top: 48px;
    padding-bottom: 48px;
  }

  .workshops-intro {
    padding-top: 40px;
    padding-bottom: 0;
  }

  .ws-photo img,
  .workshops-closing__media img {
    max-width: 80%;
  }

  .ws-closing__line {
    font-size: 2.2rem;
    text-wrap: balance;
  }

  .workshops-closing {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}

/* ============================================
   WORKSHOPS.HTML - EN / HE language toggle
   ============================================ */
.lang-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: flex-end;
  padding: 8px 48px;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
}

.lang-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--color-ink-soft);
  padding: 0;
}

.lang-btn.active {
  color: var(--color-ink);
  font-weight: 600;
}

/* Each translatable string ships in both languages; the body class
   decides which one shows. */
body:not(.lang-he) .he {
  display: none;
}

body.lang-he .en {
  display: none;
}

/* Hebrew mirrors every two-column section. The intro places its columns
   explicitly (scribbles in column 1, text in column 2), so under rtl the
   text lands on the left and the scribbles on the right with the same
   48/52 track sizes - no grid-template-columns change is needed. */
body.lang-he .workshops-intro,
body.lang-he .workshops-what-we-do,
body.lang-he .workshops-how-it-works,
body.lang-he .workshops-closing {
  direction: rtl;
}

/* The closing line is hard-left-aligned for English; in Hebrew it reads
   from the right. Letter-spaced uppercase labels lose the spacing too. */
body.lang-he .ws-closing__line {
  text-align: right;
}

body.lang-he .eyebrow {
  letter-spacing: 0;
}

@media (max-width: 768px) {
  .lang-toggle {
    padding: 8px 28px;
  }
}
