/* ==========================================================================
   יובל דנוך — תיק עבודות
   Swiss-grid editorial, RTL. Zero dependencies.
   ========================================================================== */

/* ---------- Yuval's own Fontbit families, self-hosted ----------
   Animator for headings, Alexander for running text, Art for the small headings.
   All three are Hebrew-only — they carry no Latin at all — so each is declared
   with a Hebrew unicode-range and Tubic Sans Eng fills in every Latin letter.
   The browser then treats each as a single typeface across both scripts.
   Hebrew ranges cover the block, presentation forms, the maqaf and the geresh. */

@font-face { font-family: "Animator"; font-weight: 300; font-display: swap;
  src: url("fonts/FbAnimator-Light.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Animator"; font-weight: 400; font-display: swap;
  src: url("fonts/FbAnimator-Regular.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Animator"; font-weight: 700; font-display: swap;
  src: url("fonts/FbAnimator-Bold.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Animator"; font-weight: 900; font-display: swap;
  src: url("fonts/FbAnimator-Black.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }

@font-face { font-family: "Alexander"; font-weight: 300; font-display: swap;
  src: url("fonts/FbAlexander-Light.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Alexander"; font-weight: 400; font-display: swap;
  src: url("fonts/FbAlexander-Regular.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Alexander"; font-weight: 700; font-display: swap;
  src: url("fonts/FbAlexander-Bold.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Alexander"; font-weight: 900; font-display: swap;
  src: url("fonts/FbAlexander-Black.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }

/* Art ships in one weight only, so "a little bolder" is done with a hairline
   stroke on .label rather than a synthetic bold, which would smear it. */
@font-face { font-family: "Art"; font-weight: 400; font-display: swap;
  src: url("fonts/FbArt-Regular.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }

/* Balata — used for one thing only: the name on the front page. */
@font-face { font-family: "Balata"; font-weight: 300; font-display: swap;
  src: url("fonts/FbBalata-Light.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Balata"; font-weight: 400; font-display: swap;
  src: url("fonts/FbBalata-Regular.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Balata"; font-weight: 700; font-display: swap;
  src: url("fonts/FbBalata-Bold.woff2") format("woff2");
  unicode-range: U+0590-05FF, U+200F, U+FB1D-FB4F; }
@font-face { font-family: "Balata"; font-weight: 300; font-display: swap;
  src: url("fonts/FbBalataEng-Light.woff2") format("woff2"); }
@font-face { font-family: "Balata"; font-weight: 400; font-display: swap;
  src: url("fonts/FbBalataEng-Regular.woff2") format("woff2"); }

/* the Latin half of all three */
@font-face { font-family: "TubicEng"; font-weight: 300; font-display: swap;
  src: url("fonts/FbTubic-SansEng-Light.woff2") format("woff2"); }
@font-face { font-family: "TubicEng"; font-weight: 400; font-display: swap;
  src: url("fonts/FbTubic-SansEng-Regular.woff2") format("woff2"); }
@font-face { font-family: "TubicEng"; font-weight: 700; font-display: swap;
  src: url("fonts/FbTubic-SansEng-Bold.woff2") format("woff2"); }
@font-face { font-family: "TubicEng"; font-weight: 900; font-display: swap;
  src: url("fonts/FbTubic-SansEng-Black.woff2") format("woff2"); }

:root {
  --paper: #ffffff;
  --ink: #171717;
  --ink-2: #404040;
  --ink-3: #737373;
  --line: #e5e5e5;
  --muted: #f4f4f5;
  --accent: #171717;

  /* Three roles, three faces. Headings carry the voice, the text face carries
     the reading, and the small headings get their own narrow display cut so a
     label never reads as a shrunken headline. */
  --font-display: "Animator", "TubicEng", "Arial Hebrew", Arial, sans-serif;
  --font-text: "Alexander", "TubicEng", "Arial Hebrew", Arial, sans-serif;
  --font-label: "Art", "TubicEng", "Arial Hebrew", Arial, sans-serif;

  --gut: clamp(16px, 3.2vw, 40px);
  --maxw: 1500px;
  /* Tightened one step across the board: the old scale topped out at 200px and
     left whole screens of empty paper between bands. */
  --s1: 8px;  --s2: 14px; --s3: 22px; --s4: 34px;
  --s5: 52px; --s6: 76px; --s7: 104px; --s8: 132px;

  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-io: cubic-bezier(.76, 0, .24, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  --hdr: 68px;

  /* The single most important number on a portfolio: how tall a drawing is
     allowed to be. Every figure is capped to this, so you never scroll to see
     one sheet — the whole thing is in front of you, then the next one.
     100vh minus the header, minus the caption, minus air. */
  /* Set so a normal landscape sheet fills the column exactly — at a 900px-tall
     window this is 756px, which is precisely the height of a 16:9 image at
     column width. Below that the drawing would be pulled in from the left and
     right edges and stop lining up with the headings above it; above it, it
     would not fit on one screen. */
  --figh: min(84vh, 940px);
  /* The lead still only. The films stay on --figh with everything else; this is
     raised so that a hero whose proportion is squarer than 16:9 still fills the
     column width rather than being pulled in narrower than the film above it.
     Height is what gives way, because width is what the eye compares. */
  --heroh: min(100vh, 1200px);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 1.62;
  font-weight: 400;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  /* clip, not hidden: `hidden` would make body a scroll container and kill
     position:sticky on the lead portrait. */
  overflow-x: clip;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.skip {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 999;
  background: var(--ink); color: #fff; padding: 12px 20px;
}
.skip:focus { inset-inline-start: 0; }

/* ---------- layout ---------- */

/* Content is capped and centred so it never smears edge to edge on a wide
   display; the gutters then stay equal on both sides at every width. */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gut);
}

.grid12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--s3);
}

.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* ---------- type ---------- */

/* The weight ladder: Animator runs 300 at display size, 400 for section heads
   and 700 where a heading has to hold its own next to body copy. Alexander sits
   at 300 when it is set large and 400 when it is being read. */
.display {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(2.1rem, 7vw, 5rem);
  line-height: 1;
  letter-spacing: -.005em;
  margin: 0;
}

.h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.45rem, 3.2vw, 2.35rem);
  line-height: 1.08;
  letter-spacing: -.003em;
  margin: 0;
}

.h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.05rem, 1.7vw, 1.35rem);
  line-height: 1.25;
  letter-spacing: 0;
  margin: 0;
}

.lede {
  font-family: var(--font-text);
  font-size: clamp(.97rem, 1.15vw, 1.1rem);
  line-height: 1.68;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-2);
  max-width: 66ch;
}

/* Art has a single weight, so the "slightly bolder" is a hairline stroke —
   about a third of a pixel, which thickens the stem without the smearing a
   browser-synthesised bold would give it. */
.label {
  font-family: var(--font-label);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-3);
  -webkit-text-stroke: .35px currentColor;
}
.meta__k, .grp__n, .card__idx, .geo__city, .hdr__nav {
  -webkit-text-stroke: .3px currentColor;
}

.num { font-variant-numeric: tabular-nums; }

/* ---------- header ---------- */

.hdr {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
  height: var(--hdr);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* The bar itself stays full-bleed, but its contents line up with the capped
     .wrap column — otherwise on a wide screen the name in the header sits ~200px
     outside the name in the hero directly below it. */
  padding-inline: max(var(--gut), calc((100% - var(--maxw)) / 2 + var(--gut)));
  /* solid, not blended: it has to stay legible over every section as the page
     scrolls under it, including the black footer and the film */
  background: rgba(255, 255, 255, .88);
  backdrop-filter: saturate(150%) blur(10px);
  -webkit-backdrop-filter: saturate(150%) blur(10px);
  border-block-end: 1px solid var(--line);
  color: var(--ink);
  pointer-events: none;
  transition: background .5s var(--ease), border-color .5s var(--ease);
}
.hdr a, .hdr button { pointer-events: auto; }
/* stays put — only the paper behind it firms up once you leave the top */
.hdr.is-stuck {
  background: rgba(255, 255, 255, .96);
  border-block-end-color: #d4d4d4;
}

/* hairline reading-progress rule along the header's own bottom edge */
.prog {
  position: absolute;
  inset-block-end: -1px;
  inset-inline-start: 0;
  height: 1px;
  width: 100%;
  background: var(--ink);
  transform: scaleX(var(--sp, 0));
  transform-origin: inline-start;
  pointer-events: none;
}

.hdr__name {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 14px;
  letter-spacing: .01em;
}

/* 24px is the floor for this mark: its stroke is 9 units of a 229-unit box, so
   below that the hairlines fall under a device pixel and go grey. */
.hdr__logo { display: block; height: 24px; width: auto; flex: none; }

.hdr__nav {
  font-family: var(--font-label);
  display: flex;
  gap: var(--s3);
  font-size: 13.5px;
  font-weight: 400;
}
.hdr__nav a { position: relative; padding: 6px 0; }
.hdr__nav a::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: inline-end;
  transition: transform .4s var(--ease);
}
.hdr__nav a:hover::after { transform: scaleX(1); transform-origin: inline-start; }

@media (max-width: 640px) {
  .hdr__nav { gap: var(--s2); font-size: 12px; }
  /* the bar fits the mark or the name, not both — the mark wins, and the name
     survives as the link's aria-label */
  .hdr__name span { display: none; }
}

/* ---------- hero ---------- */

.hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-block: calc(var(--hdr) + var(--s5)) var(--s4);
  position: relative;
}

/* ---------- lead: hero + about share a grid so the portrait can pin ---------- */

/* DOM order is hero → portrait → about, which is exactly the mobile stack.
   On desktop the portrait is lifted into its own column spanning both rows. */
.lead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--s4);
}
.lead > .hero  { grid-column: 1; grid-row: 1; min-width: 0; }
.lead > .about { grid-column: 1; grid-row: 2; min-width: 0; }
/* spans under the portrait column too, so 13 chips get the full page width */
.lead > .toolsband { grid-column: 1 / -1; grid-row: 3; min-width: 0; padding-block-end: var(--s6); }

/* full-height column; the image itself sticks to the viewport bottom, so it
   rides down out of the hero and through the about section, then parks. */
.lead__portrait {
  grid-column: 2;
  grid-row: 1 / 3;
  margin: 0;
  align-self: stretch;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
}
.lead__portrait img {
  position: sticky;
  bottom: var(--s4);
  height: clamp(240px, 58vh, 560px);
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* The name on the front page is the one place Balata is used — it is the
   signature, so it gets its own face and nothing else on the site does. */
.hero .display {
  font-family: "Balata", var(--font-display);
  font-weight: 400;
  font-size: clamp(2.1rem, 6.4vw, 4.75rem);
  letter-spacing: 0;
}
.hero__sub {
  margin: var(--s2) 0 0;
  font-family: var(--font-label);
  font-size: clamp(.78rem, 1vw, .92rem);
  font-weight: 400;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* standalone projects / about pages start below the fixed header */
.page-top { padding-block-start: var(--hdr); }
.about--solo { padding-block: clamp(var(--s4), 5vw, var(--s6)); }
.about--solo .about__body { margin-inline: 0; }
.about--solo .toolsband { margin-block-start: var(--s5); }

/* On the index the portrait fills the second column. Here there is no portrait,
   so a single right-hand text column left half the page blank — statement and
   running text face each other across the spread instead. */
/* mobile: portrait sits under the text, as on the index */
.about__portrait { margin: var(--s5) 0 0; text-align: center; }
.about__portrait img {
  height: clamp(220px, 40vh, 360px);
  width: auto;
  max-width: 100%;
  object-fit: contain;
  margin-inline: auto;
}

@media (min-width: 900px) {
  /* Two columns since the opening statement was removed: running text, then
     the portrait. It was three, and leaving it that way left the whole first
     column empty with the text stranded in the middle of the page. */
  .about--solo {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: clamp(var(--s4), 4vw, var(--s6));
    align-items: end;
  }
  .about--solo .about__body {
    grid-column: 1;
    grid-row: 1;
    align-self: start;
    max-width: 58ch;
  }
  .about--solo .about__portrait {
    grid-column: 2;
    grid-row: 1;
    margin: 0;
    align-self: end;
  }
  .about--solo .about__portrait img { height: clamp(300px, 46vh, 470px); }
  .about--solo .toolsband { grid-column: 1 / -1; grid-row: 2; }
}

/* ---------- hero backdrop: cross-fading B/W sketches ---------- */

/* Occupies the hero's own grid row, so its height always matches the hero.
   The inner box then bleeds out through the .wrap gutters to the screen edge. */
.hero__bg {
  grid-column: 1 / -1;
  grid-row: 1;
  position: relative;
  z-index: 0;
  pointer-events: none;
}
/* Sits inside the capped container like everything else, so the page keeps one
   set of edges. 100vw would have overhung by the scrollbar width. The mask
   feathers its left and right so the crop is not a hard vertical line. */
.hero__bg-in {
  position: absolute;
  inset-block: 0;
  inset-inline: calc(var(--gut) * -1);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 7%, #000 93%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 7%, #000 93%, transparent 100%);
}
.lead > .hero, .lead > .about { position: relative; z-index: 1; }
.hero__bg .sk {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1s var(--ease);
}
.hero__bg .sk.is-on { opacity: .5; }

/* the light white wash the sketches sit under */
.hero__bg-in::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
              rgba(255, 255, 255, .60) 0%,
              rgba(255, 255, 255, .74) 55%,
              rgba(255, 255, 255, .92) 100%);
}

.lead__portrait { z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  .hero__bg .sk { transition: none !important; }
}

@media (max-width: 860px) {
  .lead { grid-template-columns: 1fr; row-gap: var(--s3); }
  /* explicit rows: the backdrop must share row 1 with the hero, not push it down */
  .hero__bg      { grid-column: 1; grid-row: 1; }
  .lead > .hero  { grid-column: 1; grid-row: 1; }
  .lead__portrait { grid-column: 1; grid-row: 2; }
  .lead > .about { grid-column: 1; grid-row: 3; }
  .lead > .toolsband { grid-column: 1; grid-row: 4; padding-block-end: var(--s5); }
  .hero { min-height: auto; padding-block: calc(var(--hdr) + var(--s6)) var(--s3); }
  .lead__portrait { justify-content: center; align-self: auto; }
  .lead__portrait img { position: static; height: clamp(200px, 38vh, 340px); }
  .about { padding-block: var(--s6) var(--s5); }
}

/* ---------- about ---------- */

.about { padding-block: clamp(var(--s5), 7vw, var(--s7)) var(--s5); }

.about__body {
  max-width: 56ch;
  /* Was margin-inline-start:auto, which pushed the text to the inline-end so the
     opening statement could hold the other half. With the statement gone that
     rule left a 527px hole on the inline-start side, so the text now starts at
     the edge like every other block on the site. */
  margin-inline: 0;
  font-size: clamp(.93rem, 1vw, 1rem);
  line-height: 1.78;
  color: var(--ink-2);
}
.about__body p { margin: 0 0 var(--s3); }
.about__body .h2 { margin: 0 0 var(--s3); color: var(--ink); }
.about__h { font-size: clamp(1.25rem, 2.2vw, 1.75rem); }

/* ---------- locations map ---------- */

/* big centred map; cards are absolutely placed over it in % of the same viewBox */
.geo { display: flex; justify-content: center; }
.geo__in {
  position: relative;
  height: clamp(460px, 88vh, 920px);
  aspect-ratio: 242 / 595;
}

/* The standalone map page: the whole country has to sit inside one window,
   under the header and under its own title, with nothing to scroll to. */
.map-page { padding-block: calc(var(--hdr) + var(--s3)) 0; }
.map-page .sec__head { margin-bottom: 0; padding-block-end: var(--s1); border: 0; }
.geo--page { padding-block: var(--s2) var(--s3); }
.geo--page .geo__in {
  /* header + the page title block + this band's own padding, measured */
  height: min(calc(100vh - var(--hdr) - 164px), 880px);
  min-height: 360px;
}
/* clipped, so the sea can run off-canvas instead of ending in a straight edge */
.map { width: 100%; height: 100%; display: block; overflow: hidden; }

/* greys for land, תכלת for water */
.map__sea {
  fill: #cfe6f4;
  stroke: none;
}
.map__land {
  fill: #edeff0;
  stroke: #a3aaaf;
  stroke-width: 1.1;
  stroke-linejoin: round;
}
.map__water {
  fill: #bcdcee;
  stroke: #8fbdd6;
  stroke-width: .8;
  stroke-linejoin: round;
}

.cty {
  font-family: var(--font-label);
  font-size: 10px;
  font-weight: 400;
  fill: var(--ink-3);
  direction: ltr;              /* RTL flips SVG text-anchor; pin it */
  paint-order: stroke;
  stroke: var(--paper);
  stroke-width: 3px;
  pointer-events: none;
}

/* leader from a city to its fanned-out dot */
.lead-l { stroke: var(--ink); stroke-width: .8; opacity: .3; }

.dot { cursor: pointer; }
/* only .dot__hit takes pointer events — an opacity:0 shape is still hit-testable
   in SVG, so the halo would otherwise inflate every target and make neighbouring
   dots steal each other's hovers. */
/* the Tel Aviv trio sit ~12 units apart, so the target must stay under half that
   or neighbouring dots steal each other's hover */
.dot__hit  { fill: transparent; r: 7; }
.dot__halo { fill: var(--ink); opacity: 0; pointer-events: none;
             transition: opacity .3s var(--ease), r .3s var(--ease); }
.dot__c    { fill: var(--ink); pointer-events: none; transition: r .3s var(--ease); }
.tools .chip--plain { padding-inline: 12px; }

.dot:hover .dot__c, .dot.on .dot__c { r: 9; }
.dot:hover .dot__halo, .dot.on .dot__halo { opacity: .13; r: 22; }
.dot:focus-visible { outline: none; }
.dot:focus-visible .dot__c { r: 9; }
.dot:focus-visible .dot__halo { opacity: .22; r: 22; }

/* hover card */
.gc {
  position: absolute;
  z-index: 5;
  width: 212px;
  background: var(--paper);
  border: 1px solid var(--ink);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .12);
  padding: 10px;
  pointer-events: none;          /* the dot stays the click target */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-50%) scale(.94);
  transition: opacity .28s var(--ease), transform .28s var(--ease), visibility .28s;
}
.gc--w { transform-origin: right center; margin-left: -26px; translate: -100% 0; }
.gc--e { transform-origin: left center;  margin-left: 26px; }
.gc.on { opacity: 1; visibility: visible; transform: translateY(-50%) scale(1); }

.gc__shot {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: contain;   /* show the whole project, never crop it */
  display: block;
  background: var(--paper);   /* letterboxing disappears into the card */
}
.gc__logo {
  height: 50px;
  width: auto;
  max-width: 78%;
  object-fit: contain;
  object-position: right center;
  margin-block-start: 8px;
}
.gc__t {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15.5px;
  letter-spacing: -.005em;
  line-height: 1.25;
  margin-block-start: 8px;
}
.gc__c { display: block; font-size: 12px; color: var(--ink-3); margin-block-start: 2px; }

@media (max-width: 700px) {
  .geo__in { height: clamp(440px, 70vh, 620px); }

  /* The map is too narrow here for side callouts: a card pinned to a dot would
     hang off-screen and, being only visibility:hidden, would widen the page.
     Park every card centred under the map instead. */
  .gc {
    width: min(272px, 82vw);
    padding: 8px;
    left: 50% !important;
    top: auto !important;
    bottom: -10px;
    margin: 0 !important;
    translate: -50% 0 !important;
    transform: scale(.96);
    transform-origin: center bottom;
  }
  .gc.on { transform: scale(1); }
  .gc__t { font-size: 13px; }
  .gc__logo { height: 26px; }

  /* tighter hit circles so neighbouring dots stop overlapping at this scale */
  .dot__hit { r: 6; }
}

.lnk {
  font-family: var(--font-text);
  display: inline-block;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--ink);
  border-block-end: 1px solid var(--ink);
  padding-block-end: 3px;
  transition: opacity .3s var(--ease);
}
.lnk:hover { opacity: .55; }

.about .facts { margin-block: clamp(var(--s4), 5vw, var(--s5)) var(--s4); }

.line {
  display: block;
  overflow: hidden;
}
.line > span {
  display: block;
  transform: translateY(105%);
  filter: blur(6px);
  transition: transform .95s var(--ease-out), filter .7s var(--ease-out);
}
.is-in .line > span { transform: translateY(0); filter: none; }
.line:nth-child(2) > span { transition-delay: .07s; }
.line:nth-child(3) > span { transition-delay: .14s; }

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3) var(--s5);
  align-items: end;
  justify-content: space-between;
  border-block-start: 1px solid var(--line);
  padding-block-start: var(--s3);
}

.hero__scroll {
  margin-inline-start: auto; /* stays on the left now that it is alone in the row */
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.hero__scroll svg { animation: bob 2.4s var(--ease-io) infinite; }
@keyframes bob { 0%,100% { transform: translateY(0) } 50% { transform: translateY(5px) } }

/* ---------- section shell ---------- */

.sec { padding-block: clamp(var(--s5), 7vw, var(--s7)); }

.sec__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s4);
  padding-block-end: var(--s2);
  border-block-end: 1px solid var(--line);
  flex-wrap: wrap;
}

/* ---------- marquee ---------- */

.marquee {
  border-block: 1px solid var(--line);
  padding-block: var(--s3);
  overflow: hidden;
  white-space: nowrap;
  user-select: none;
}
.marquee__track {
  display: inline-flex;
  gap: var(--s4);
  animation: slide 38s linear infinite;
  will-change: transform;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee span {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(1.05rem, 2.2vw, 1.7rem);
  letter-spacing: -.01em;
  line-height: 1.1;
  color: var(--ink);
}
.marquee span.o {
  -webkit-text-stroke: 1px var(--ink);
  color: transparent;
}
@keyframes slide { to { transform: translateX(50%); } }

/* ---------- project index ---------- */

.projects {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(var(--s4), 5vw, var(--s6)) var(--s4);
}
@media (max-width: 860px) { .projects { grid-template-columns: 1fr; } }

/* ---------- study models ---------- */

/* Not projects, so not project cards: a plain even grid, every cell the same
   width and the same gap, captions on one baseline. */
.studies {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--s4) var(--s3);
}
.sfig { margin: 0; }
/* white, not grey: the models are cut-outs on transparency, and a grey plate
   behind them made every one look like it sat in a box */
.sfig .fig__box {
  overflow: hidden;
  background: transparent;
  aspect-ratio: 4 / 3;
  align-items: center;
}
.sfig .fig__box img {
  width: 100%; height: 100%;
  object-fit: contain;
  max-height: 100%;
  background: transparent;
  transition: transform .7s var(--ease);
}
.sfig:hover .fig__box img { transform: scale(1.03); }
.sfig figcaption {
  font-family: var(--font-text);
  font-size: 13px;
  color: var(--ink-3);
  margin-block-start: var(--s2);
  padding-block-start: var(--s1);
  border-block-start: 1px solid var(--line);
  transition: color .35s var(--ease);
}
.sfig:hover figcaption { color: var(--ink); }
@media (max-width: 520px) { .studies { grid-template-columns: repeat(2, 1fr); } }

.card { position: relative; display: block; }
/* the drop on the second column is what makes the grid read as a portfolio and
   not a catalogue — but at 110px it opened a hole under the last row */
.card:nth-child(even) { transform: translateY(clamp(16px, 4vw, 64px)); }
@media (max-width: 860px) { .card:nth-child(even) { transform: none; } }

.card__media {
  position: relative;
  overflow: hidden;
  background: var(--muted);
  aspect-ratio: 4 / 3;
  /* a short curtain and a fade, not a full-height sweep — the old version
     uncovered the whole frame from nothing, which read as a slot machine */
  clip-path: inset(0 0 24% 0);
  opacity: 0;
  /* --d is the grid stagger, set per card in motion.js */
  transition: clip-path .95s var(--ease-out) var(--d, 0s),
              opacity .7s var(--ease-out) var(--d, 0s);
}
.is-in .card__media, .card.is-in .card__media { clip-path: inset(0 0 0 0); opacity: 1; }

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.06);
  transition: transform 1.1s var(--ease), filter .6s var(--ease);
  will-change: transform;
}
.card:hover .card__media img { transform: scale(1.015); }

/* a thin ink veil that lifts on hover — reads as focus, costs one composite */
.card__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ink);
  opacity: .06;
  transition: opacity .55s var(--ease);
  pointer-events: none;
}
.card:hover .card__media::after { opacity: 0; }

.card__idx {
  font-family: var(--font-label);
  position: absolute;
  inset-block-start: var(--s2);
  inset-inline-start: var(--s2);
  z-index: 2;
  background: var(--paper);
  color: var(--ink);
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: .14em;
  padding: 5px 9px;
  transition: background .4s var(--ease), color .4s var(--ease);
}
.card:hover .card__idx { background: var(--ink); color: #fff; }

.card__body {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  padding-block-start: var(--s2);
  border-block-start: 1px solid var(--ink);
  margin-block-start: var(--s2);
}
.card__id { min-width: 0; }
/* the mark leads the name on the inline-start side, set a little taller than the
   type so it reads as the project's own signature rather than a bullet */
.card__name { display: flex; align-items: center; gap: 12px; min-width: 0; }
.card__logo {
  flex: 0 0 auto;
  /* set against .card__title (20–30px): the mark reads a step above the name */
  height: clamp(30px, 2.8vw, 38px);
  width: auto;
  /* the marks run from square to 2.6:1 — a tight width cap silently shrank the
     wide ones by a third, so it is set past the widest of them */
  max-width: 200px;
  object-fit: contain;
  object-position: right center;
  transition: transform .6s var(--ease-out), opacity .4s var(--ease);
}
.card:hover .card__logo { transform: translateY(-2px); }
.card__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.55vw, 1.32rem);
  letter-spacing: -.01em;
  line-height: 1.15;
  min-width: 0;
}
@media (max-width: 480px) {
  .card__logo { height: 30px; }
  .card__name { gap: 9px; }
}
.card__sub {
  font-weight: 400;
  font-family: var(--font-text); color: var(--ink-3); font-size: 14px; margin-block-start: 4px; }
.card__yr { font-size: 13px; color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }

.card__bar {
  height: 2px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: inline-end;
  transition: transform .7s var(--ease);
  margin-block-start: -1px;
}
.card:hover .card__bar { transform: scaleX(1); transform-origin: inline-start; }

/* ---------- reveal primitives ---------- */

/* --d carries a per-item stagger written by motion.js, so a row of figures
   arrives as a wave instead of all at once. Content lifts out of a soft blur
   rather than sliding — a shorter travel reads as more composed, and the blur
   does the work the distance used to. */
.rv {
  opacity: 0;
  transform: translateY(14px);
  filter: blur(5px);
  transition: opacity .75s var(--ease-out) var(--d, 0s),
              transform .75s var(--ease-out) var(--d, 0s),
              filter .6s var(--ease-out) var(--d, 0s);
}
.rv.is-in { opacity: 1; transform: none; filter: none; }
/* Blurring a full-bleed drawing costs a large GPU surface for no visual gain at
   that size — figures fade and lift only. */
.fig.rv { filter: none; transition: opacity .75s var(--ease-out) var(--d, 0s),
                                    transform .75s var(--ease-out) var(--d, 0s); }
.rv-d1 { --d: .07s } .rv-d2 { --d: .14s } .rv-d3 { --d: .21s }

.wipe { clip-path: inset(0 0 28% 0); opacity: 0; transition: clip-path .95s var(--ease-out) var(--d, 0s), opacity .7s var(--ease-out) var(--d, 0s); }
.wipe.is-in { clip-path: inset(0 0 0 0); opacity: 1; }

/* word-level reveal — the SplitText effect, done by motion.js with plain spans */
/* No `display` here on purpose: .split lands on a block <p>, and forcing it
   inline would silently drop that paragraph's max-width and vertical margins.
   The .w children are inline-block, which works inside any display type. */
/* the padding/negative-margin pair grows the clipping box past the baseline so
   ק ן ך ף ץ and Latin descenders are not shaved off, without moving the line */
.split .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-block-end: .18em;
  margin-block-end: -.18em;
}
.split .w > span {
  display: inline-block;
  transform: translateY(105%);
  filter: blur(4px);
  transition: transform .8s var(--ease-out) var(--d, 0s),
              filter .55s var(--ease-out) var(--d, 0s);
}
.split.is-in .w > span { transform: none; filter: none; }

/* ---------- cursor ---------- */

/* A frosted disc rather than a black puck — it sits over the drawing it is
   pointing at, so it has to stay quiet enough to see through. */
.cursor {
  font-family: var(--font-label);
  position: fixed;
  z-index: 200;
  inset-block-start: 0; inset-inline-start: 0;
  width: 68px; height: 68px;
  border-radius: 50%;
  background: rgba(23, 23, 23, .72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: .08em;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(.5);
  transition: opacity .35s var(--ease-out), transform .45s var(--ease-out);
}
.cursor.on { opacity: 1; transform: translate(-50%, -50%) scale(1); }
@media (hover: none), (pointer: coarse) { .cursor { display: none; } }

/* ---------- about / facts ---------- */

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--s4);
  border-block-start: 1px solid var(--line);
  padding-block-start: var(--s3);
}
.fact__n { font-family: var(--font-display); font-weight: 300; font-size: clamp(1.55rem, 3vw, 2.3rem); line-height: 1; letter-spacing: -.015em; }
.fact__l {
  font-weight: 400;
  font-family: var(--font-text); color: var(--ink-3); font-size: 14px; margin-block-start: var(--s1); }

.skills { display: flex; flex-wrap: wrap; gap: var(--s1); }

/* one line of all thirteen tools; scrolls inside itself if the width runs out */
.tools {
  display: flex;
  flex-wrap: nowrap;
  gap: 4px;
  overflow-x: auto;
  padding-block-end: 6px;
  scrollbar-width: thin;
  overscroll-behavior-x: contain;
}
/* `.chip` is declared later in this file with the same specificity, so these
   need one extra class to win the cascade. */
.tools .chip--tool {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 6px 12px 6px 8px;
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: -.005em;
}
.tools .chip__ico {
  width: 17px; height: 17px; flex: 0 0 auto;
  border-radius: 4px;
  object-fit: contain;   /* the three real logos are bitmaps */
}
.tools .chip__n { white-space: nowrap; }
.chip {
  border: 1px solid var(--line);
  padding: 7px 14px;
  font-size: 13px;
  border-radius: 100px;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.chip:hover { border-color: var(--ink); background: var(--muted); }

/* ---------- footer ---------- */

.ftr { background: var(--ink); color: #fff; padding-block: var(--s5) var(--s3); }
.ftr a { color: #fff; }
.ftr .rule { background: #3a3a3a; }
.ftr__big {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(1rem, 1.9vw, 1.55rem);
  line-height: 1.1;
  letter-spacing: -.01em;
  margin: 0 0 var(--s4);
}
.ftr__big a { position: relative; display: inline-block; }
.ftr__big a::after {
  content: ""; position: absolute; inset-block-end: .06em; inset-inline-start: 0;
  width: 100%; height: 3px; background: #fff;
  transform: scaleX(0); transform-origin: inline-end;
  transition: transform .6s var(--ease);
}
.ftr__big a:hover::after { transform: scaleX(1); transform-origin: inline-start; }

.ftr__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s4);
  padding-block: var(--s4);
}
.ftr__cols .label { color: #8a8a8a; }
.ftr__end {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--s2);
  font-size: 12px; color: #8a8a8a; padding-block-start: var(--s3);
}

/* ==========================================================================
   PROJECT PAGE
   ========================================================================== */

.p-hero { padding-block: calc(var(--hdr) + var(--s4)) var(--s2); }
/* The year is the only thing on its row and belongs on the left. Aligning it
   from the container, not with an auto margin on the year itself: the year
   carries dir="ltr" so that 2023 reads as a number, which flips which side its
   own inline-start refers to and sent the auto margin the wrong way. */
.p-hero__head { justify-content: flex-end; }
/* a project title, not a poster: one step above a section head, no more */
.p-hero__title {
  margin-block: var(--s1) 0;
  font-size: clamp(1.6rem, 3.6vw, 2.7rem);
}

/* the project's own mark, above its name */
.p-hero__logo { margin: var(--s2) 0 0; }
/* The project title runs 36–88px, so the mark is set a step above it at
   46–104px — big enough to read as the project's signature, not a bullet. */
.p-hero__logo img {
  height: clamp(48px, 5.4vw, 72px);
  width: auto;
  max-width: min(460px, 82%);
  object-fit: contain;
  object-position: right center;
}

/* The opening render animates itself. It used to depend on a JS class landing
   on it, and when that class did not arrive the image stayed clipped to zero
   height — present in the DOM, invisible on screen. CSS alone cannot miss. */
/* No fixed ratio. A hard 16:9 box with object-fit:cover cut the top and bottom
   off any lead image that was not 16:9 — the 45 מעלות west elevation is 1.31:1
   and lost a third of the building. Each hero now keeps its own shape, capped by
   height so a tall one cannot swallow the screen. */
.p-hero__media {
  overflow: hidden;
  background: transparent;
  animation: heroWipe 1.05s var(--ease) both;
}
/* The hidden state lives in the keyframe, never on the element itself. If the
   animation is suspended, disabled or unsupported, the fallback is a fully
   visible image — the opposite of the old behaviour, where a reveal that failed
   to fire left the opening render clipped to nothing. */
@keyframes heroWipe {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}
.p-hero__media img {
  display: block;
  width: 100%;
  height: auto;
  max-height: var(--heroh);
  object-fit: contain;
  animation: heroSettle 1.6s var(--ease) both;
}
@keyframes heroSettle {
  from { transform: scale(1.05); }
  to   { transform: scale(1); }
}
/* Watchdog, set by motion.js ~1.8s in. The element's own style carries no
   clip-path, so dropping the animation always lands on "visible". Two
   independent mechanisms — CSS and JS — and either one alone opens the image. */
.p-hero__media.is-open, .p-hero__media.is-open img { animation: none; }

.meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--s3) var(--s4);
  padding-block-start: var(--s3);
  border-block-start: 1px solid var(--line);
}
.meta__k {
  font-weight: 400;
  font-family: var(--font-label); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px; }
.meta__v {
  font-family: var(--font-text); font-size: 15px; font-weight: 400; }

/* project film */

.p-film { padding-block: var(--s3) 0; }
.p-hero__still { padding-block: var(--s3) 0; }

/* Two columns, not a flex row that wraps: with wrapping, a long project name
   filled the line and pushed the locator onto a second row, so the map ended up
   under the title instead of beside it. A grid keeps it in its own column on
   the inline-end — the left — on every project, whatever the name's length. */
.p-hero__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: var(--s4);
}
.p-hero__id { min-width: 0; }

.p-hero__geo { margin: 0; text-align: center; }
.p-hero__geo figcaption {
  margin-block-start: 10px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.geo__city {
  font-family: var(--font-label);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: .04em;
  color: var(--ink-2);
}
.geo__street {
  font-weight: 400;
  font-family: var(--font-text); font-size: 11px; color: var(--ink-3); letter-spacing: .02em; }

/* ---------- street-level locator (OpenStreetMap geometry, baked to SVG) ---------- */

/* Big enough that the street names are readable: at 230px a 6.6-unit label
   lands near 8px on screen. */
.smap {
  width: clamp(164px, 17vw, 230px);
  height: auto;
  aspect-ratio: 1;
  display: block;
  margin-inline: auto;
  overflow: visible;
}
.sm__bg   { fill: #f7f8f8; }
.sm__edge { fill: none; stroke: var(--line); stroke-width: 1.4; }
.smap rect { vector-effect: non-scaling-stroke; }
.smap path { fill: none; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
/* four weights, so the network reads as hierarchy at 170px rather than as noise.
   These are darker than they look on paper — at 1px on near-white, anything
   lighter than ~#b0 disappears entirely on a normal laptop screen. */
.sm__water { stroke: #cbe4f3; stroke-width: 6; }
/* a lake is an area, so it is filled rather than traced */
.smap .sm__wfill { fill: #cbe4f3; stroke: #a8d3ea; stroke-width: .8; }
.sm__p  { stroke: #cdd2d5; stroke-width: .7; }
.sm__mn { stroke: #a9b0b4; stroke-width: 1; }
.sm__md { stroke: #868e93; stroke-width: 1.5; }
.sm__mj { stroke: #6b7378; stroke-width: 2.2; }
/* the street the building actually stands on, in the project's own colour */
.sm__site { stroke: var(--accent); stroke-width: 2.6; opacity: .85; }
.sm__ring { fill: var(--accent); opacity: .18; }
.sm__dot  { fill: var(--accent); stroke: var(--paper); stroke-width: 1.6; }

/* Street names ride along their own line. paint-order puts a paper-coloured
   stroke behind the glyphs so a name stays readable where it crosses the road
   it belongs to. */
/* a named place — square, park, campus — set darker than a street name */
.sm__mk circle { fill: #6b7378; }
.sm__mk text {
  font-family: var(--font-text);
  font-size: 6.8px;
  font-weight: 700;
  fill: #3f4145;
  text-anchor: middle;
  direction: rtl;
  paint-order: stroke;
  stroke: #f7f8f8;
  stroke-width: 2.8px;
  stroke-linejoin: round;
}

.sm__lbl {
  font-family: var(--font-text);
  font-size: 6.6px;
  font-weight: 400;
  fill: #4b5257;
  text-anchor: middle;
  direction: rtl;
  paint-order: stroke;
  stroke: #f7f8f8;
  stroke-width: 2.4px;
  stroke-linejoin: round;
  pointer-events: none;
}

@media (max-width: 700px) {
  .p-hero__row { grid-template-columns: minmax(0, 1fr); }
  .p-hero__geo { justify-self: end; }
}
/* The film now measures exactly what a full-width figure measures: same left
   and right edge, same column, no step in the page's vertical rhythm. Landscape
   films fill the column; the one portrait film is capped by height instead so it
   cannot run past a screenful, and centres in the same column. */
/* the film obeys exactly the same ceiling as a drawing, so a project page has
   one rhythm rather than two */
/* Identical rule to a drawing: height first, width second. With width:100% the
   element stayed column-wide while the picture inside it was height-capped, so
   the film's frame and its control bar ran 160px past every image on the page. */
.film {
  display: block;
  width: 100%;
  height: auto;
  max-height: var(--figh);   /* the same ceiling as every drawing on the site */
  object-fit: contain;
  background: transparent;   /* no frame or plate around the film */
}

/* gallery */

.gal { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--s3); }
.fig { margin: 0; grid-column: span 12; }
.fig--half { grid-column: span 6; }
.fig--wide { grid-column: span 12; }
/* lone portrait figure — centred rather than stranded in half a row */
.fig--solo { grid-column: 4 / span 6; }

/* A 1:2500 urban plan at text-column width gives each building two pixels. This
   runs it the full width of the window instead. --sbw is the scrollbar width,
   measured in motion.js: subtracting it is what keeps 100vw from overhanging the
   page and creating a horizontal scroll. */
.fig--bleed { grid-column: 1 / -1; }
.fig--bleed .fig__box {
  width: calc(100vw - var(--sbw, 0px));
  margin-inline: calc((100% - (100vw - var(--sbw, 0px))) / 2);
}

/* every figure fits a screen now, so this only widens the column it may use */
.fig--fit { grid-column: span 12; }

@media (max-width: 760px) {
  .fig--half, .fig--solo { grid-column: span 12; }
}

/* no frame, no plate: the drawings sit straight on the page */
.fig__box {
  overflow: hidden;
  background: transparent;
  display: block;
  width: 100%;
}
/* The box always spans its full column — so every figure begins and ends on the
   same two lines as the title, the logo and the map above it. The drawing then
   sits inside that box: a wide sheet fills it edge to edge, and a tall one is
   capped in height and centred, its spare room being plain white page that you
   cannot see. Sizing the image itself instead (width:auto) is what used to pull
   the tall ones in from the margins and break the line. */
.fig__box img {
  width: 100%;
  height: auto;
  max-height: var(--figh);
  object-fit: contain;
  object-position: center;
  transition: transform .7s var(--ease), opacity .4s var(--ease);
}

/* Groups read as a matched set: one box height for all of them. */
.gal--even .fig__box img { height: var(--figh); }
.fig:hover .fig__box img { transform: scale(1.012); }
.fig figcaption {
  font-weight: 400;
  font-family: var(--font-text);
  font-size: 13px;
  color: var(--ink-3);
  margin-block-start: var(--s2);
  transition: color .35s var(--ease);
}
.fig figcaption span {
  display: inline-block;
  padding-block-end: 3px;
  background: linear-gradient(currentColor, currentColor) right bottom / 0 1px no-repeat;
  transition: background-size .45s var(--ease);
}
.fig:hover figcaption { color: var(--ink); }
.fig:hover figcaption span { background-size: 100% 1px; }

/* Each group heading parks under the fixed header while its own figures scroll
   past, then the next one pushes it out — so you always know which set you are
   looking at without a sidebar. */
.grp {
  position: sticky;
  inset-block-start: var(--hdr);
  z-index: 6;
  margin-block: var(--s5) var(--s2);
  padding-block: var(--s2) 10px;
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  background: var(--paper);
}
.grp:first-child { margin-block-start: var(--s3); }
.grp__n {
  font-weight: 400;
  font-family: var(--font-label); font-size: 10.5px; letter-spacing: .2em; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.grp__t {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.08rem, 1.8vw, 1.45rem);
  letter-spacing: -.01em;
  line-height: 1.15;
}
.grp__line { flex: 1; height: 1px; background: var(--line); }

/* prev / next */

.pn {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-block-start: 1px solid var(--line);
  max-width: var(--maxw);          /* line up with every other band */
  margin-inline: auto;
}
@media (max-width: 700px) { .pn { grid-template-columns: 1fr; } }
.pn__a {
  padding-block: var(--s4);
  padding-inline: var(--gut);
  transition: background .4s var(--ease), color .4s var(--ease);
}
.pn__a:hover { background: var(--ink); color: #fff; }
.pn__a:hover .label { color: #9a9a9a; }
.pn__a + .pn__a { border-inline-start: 1px solid var(--line); }
@media (max-width: 700px) { .pn__a + .pn__a { border-inline-start: 0; border-block-start: 1px solid var(--line); } }
.pn__t { font-family: var(--font-display); font-weight: 400; font-size: clamp(1.02rem, 1.6vw, 1.3rem); letter-spacing: -.01em; margin-block-start: var(--s1); }

/* lightbox */

/* A paper ground, not a black one: these are pencil drawings and pale plans —
   on black they invert into negatives, and it was the only dark surface on the
   site apart from the footer. */
.lb {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(140%) blur(18px);
  -webkit-backdrop-filter: saturate(140%) blur(18px);
  display: grid;
  place-items: center;
  padding: var(--s4);
  opacity: 0;
  visibility: hidden;
  transition: opacity .34s var(--ease-out), visibility .34s;
}
.lb.on { opacity: 1; visibility: visible; }
.lb__stage {
  transform: scale(.985) translateY(6px);
  transition: transform .45s var(--ease-out);
}
.lb.on .lb__stage { transform: none; }
.lb img {
  max-width: 100%; max-height: 84vh; object-fit: contain;
  box-shadow: 0 18px 60px rgba(0, 0, 0, .13);
  transition: opacity .24s var(--ease);
}
.lb.is-swapping img { opacity: .3; }
.lb__cap { color: var(--ink-3); font-size: 13px; text-align: center; margin-block-start: var(--s2); }
.lb__n {
  position: absolute; inset-block-end: var(--s3); inset-inline-start: 50%;
  translate: -50% 0;
  color: var(--ink-3); font-size: 12px; letter-spacing: .16em;
  font-variant-numeric: tabular-nums; direction: ltr;
}
.lb__x {
  position: absolute; inset-block-start: var(--s3); inset-inline-end: var(--s3);
  color: var(--ink); font-size: 13px; letter-spacing: .1em;
  border: 1px solid var(--line); background: var(--paper);
  padding: 10px 18px; border-radius: 100px;
  min-width: 44px; min-height: 44px;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.lb__x:hover { border-color: var(--ink); background: var(--muted); }
.lb__nav {
  position: absolute; inset-block-start: 50%; transform: translateY(-50%);
  color: var(--ink); font-size: 26px; padding: 14px 18px;
  min-width: 44px; min-height: 44px;
  opacity: .45;
  transition: opacity .3s var(--ease);
}
.lb__nav:hover { opacity: 1; }
.lb__nav.prev { inset-inline-start: var(--s2); }
.lb__nav.next { inset-inline-end: var(--s2); }
.zoomable { cursor: zoom-in; }

/* ---------- page transition ---------- */

/* No curtain. A black panel sweeping the screen between two white pages is the
   loudest thing on the site; a cross-fade lets one page dissolve into the next.
   Browsers with cross-document view transitions get it natively — nothing to
   download, nothing to block navigation on. */
@view-transition { navigation: auto; }

::view-transition-old(root) {
  animation: vtOut .26s cubic-bezier(.4, 0, 1, 1) both;
}
::view-transition-new(root) {
  animation: vtIn .42s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes vtOut { to { opacity: 0; transform: translateY(-6px); } }
@keyframes vtIn { from { opacity: 0; transform: translateY(10px); } }

/* Fallback for everything else: the arriving page settles in by itself. Exit is
   the browser's own, which is instant — and an entrance that outlasts the exit
   is what makes a transition feel considered rather than slow.
   `main` fades only, no transform: the group headings inside it are sticky, and
   a transform on their ancestor drags them off the header they park against. */
/* Kept short: where cross-document view transitions do run, this lands on top
   of the browser's own cross-fade, and two long ramps stacked read as lag. */
main { animation: pageFade .38s cubic-bezier(.16, 1, .3, 1) both; }
.hdr { animation: pageIn .42s cubic-bezier(.16, 1, .3, 1) both; }
@keyframes pageFade { from { opacity: 0; } }
@keyframes pageIn { from { opacity: 0; transform: translateY(-8px); } }

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .line > span, .split .w > span { transform: none !important; filter: none !important; }
  .rv { opacity: 1 !important; transform: none !important; filter: none !important; }
  .wipe, .card__media, .p-hero__media { clip-path: none !important; opacity: 1 !important; }
  .card__media img, .p-hero__media img { transform: none !important; }
  .card:nth-child(even) { transform: none !important; }
  .marquee__track { animation: none !important; }
  .grp { position: static !important; }
  main, .hdr { animation: none !important; opacity: 1 !important; transform: none !important; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
}
