:root {
  --bg: #F0F1F3;          /* platinum */
  --ink: #255BFC;         /* full spectrum blue */
  --muted: #255BFCcc;
  --rule: #255BFC22;
  --accent: #255BFC;
  --footer-blue: #255BFC;
  --serif: "Google Sans Flex", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --sans: "Google Sans Flex", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --max: 1280px;
  --pad: clamp(1.25rem, 4vw, 3rem);
  /* Reduced from 40 → 20 max so the hero logo sits closer to the page edge
     once the video boxes in. Feels more iOS-restrained. */
  --hero-pad: clamp(12px, 2.2vw, 20px);
  --hero-top: 132px;
  /* Apple-style spring curve. Used for taps and the bottom-sheet slide. */
  --ease-ios: cubic-bezier(0.32, 0.72, 0, 1);
  /* Editorial / drift curve. Used for ambient motion (scroll, FLIP). */
  --ease-editorial: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  /* Kill the default gray flash on tap; we provide our own active states. */
  -webkit-tap-highlight-color: transparent;
}

/* Pin html to the page bg so iOS rubber-band overscroll never flashes white,
   and ensure the page covers the full dynamic viewport on mobile. */
html {
  min-height: 100dvh;
  background-color: var(--bg);
}

a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; height: auto; }

/* iOS-style press feedback on every tappable element. ~120ms is short enough
   to feel haptic; the Apple ease has the right "settle" on release. */
@media (hover: none), (pointer: coarse) {
  a, button, [role="button"], .work__media, .site-footer__wordmark {
    transition: transform 120ms var(--ease-ios), opacity 120ms var(--ease-ios);
  }
  a:active, button:active, [role="button"]:active,
  .work__media:active, .site-footer__wordmark:active {
    transform: scale(0.97);
    opacity: 0.85;
  }
}

/* ---------- Hero (scroll-driven) ----------
   Section is taller than the viewport to give the animation runway.
   .hero__pin sticks for that runway, then unsticks and the page continues.

   The mark is TWO stacked copies of the same ALAB SVG:
     • back  — solid blue (#255BFC)
     • front — solid white, sits on top, offset by --diverge
   On the dark video they're aligned, so only white reads. As the logo
   travels up onto the platinum band, the front shifts up-left; the blue
   back peeks out down-right, producing the cursive "j-hook" silhouette
   from Figma Phases 2 & 3.

   Phases:
     Phase 1 (0.00 → 0.45)  shrink + travel to top   (band 0 → 132px)
     Phase 2 (0.45 → 0.65)  hold                     (band 132px, small)
     Phase 3 (0.65 → 1.00)  grow at top              (band 132 → 180px)
   Diverge ramps 0 → 1 across (0.40 → 0.60), centered on band arrival.

   Variables driven by JS:
     --travel       0 → 1   logo Y position (center → band)
     --logo-scale   1 → s2 → s3   container scale (s2 = 225/491, s3 = 423/491)
     --diverge      0 → 1   front-copy offset away from back
     --frame-inset  0 → 1   video full-bleed → boxed
     --band-h       animated band height (px)
*/
.hero {
  --travel: 0;
  --logo-scale: 1;
  --diverge: 0;
  --frame-inset: 0;
  --band-h: 0px;
  /* Cursor follow on the front mark only; -1 → +1, normalized within the logo. */
  --front-dx: 0;
  --front-dy: 0;
  position: relative;
  /* dvh tracks the currently visible viewport on iOS — as the URL bar
     hides/shows, the runway and pin resize together. */
  height: 260dvh;
  background: var(--bg);
}

.hero__pin {
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow: hidden;
}

.hero__frame {
  position: absolute;
  /* top band grows from 0 → 132px → 180px across phases (driven by JS --band-h);
     other three sides use --hero-pad once boxed */
  top: var(--band-h);
  right: calc(var(--hero-pad) * var(--frame-inset));
  bottom: calc(var(--hero-pad) * var(--frame-inset));
  left: calc(var(--hero-pad) * var(--frame-inset));
  background: #111;
  overflow: hidden;
  /* Grows from 0 → 80px as the video boxes in. Squircled where supported. */
  border-radius: calc(80px * var(--frame-inset));
  corner-shape: squircle;
}

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

.hero__logo {
  /* Container handles position + scale; SVG children handle z-stacking and divergence. */
  --logo-w: clamp(280px, 38vw, 489px);
  position: absolute;
  left: 50%;
  /* travel from viewport center to the center of the (animating) top band */
  top: calc(50vh - (50vh - (var(--band-h) / 2)) * var(--travel));
  width: var(--logo-w);
  aspect-ratio: 489 / 113;
  transform: translate(-50%, -50%) scale(var(--logo-scale));
  transform-origin: 50% 50%;
  z-index: 5;
  user-select: none;
  will-change: transform, top;
}

.hero__mark {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

/* Back: solid blue. Stays anchored to the container. */
.hero__mark--back {
  color: var(--ink);  /* #255BFC */
  z-index: 1;
}

/* Front: same color as the page bg, sits on top. Offsets up-left as --diverge
   grows. On the platinum band the front blends with the bg, so the blue back
   reads as the cursive "j-hook" silhouette. At full divergence:
   ~5% of width left, ~21% of height up — matches Figma.
   --front-dx / --front-dy add a small cursor-follow translate when the pointer
   is over the logo (driven by JS). */
.hero__mark--front {
  --follow-max: 4%;
  color: var(--bg);  /* #F0F1F3 — same as page bg */
  z-index: 2;
  transform: translate(
    calc(var(--diverge) * -5% + var(--front-dx) * var(--follow-max)),
    calc(var(--diverge) * -21% + var(--front-dy) * var(--follow-max))
  );
  transition: transform 0s;
}

@media (prefers-reduced-motion: reduce) {
  .hero { height: 100dvh; }
  .hero__pin { position: static; height: 100dvh; }
}

/* ---------- Work section (Figma node 2017:100) ----------
   Two rows on an 8-column grid:
   • Top row: lede text (cols 1–3) | square vase (4–6) | portrait luv lamp (7–8)
   • Bottom row: portrait timothy (1–2) | square bubble (3–5) | square tall vase (6–8)
*/
.work {
  --work-gap: 48px;
  --work-pad: clamp(20px, 2.31vw, 40px);   /* 40px at 1728px */
  padding: clamp(4rem, 8.5vw, 8.5rem) var(--work-pad) clamp(4rem, 7.5vw, 7.5rem);
  display: flex;
  flex-direction: column;
  gap: 48px;
}

.work__row {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: var(--work-gap);
  align-items: start;
  /* Perspective for 3D tilt on .work__media children. */
  perspective: 1400px;
}

/* Top row: align card BOTTOMS so the square (remnant) and portrait (luv lamp)
   share an end edge. Without this the square ends ~250px higher than the
   portrait, making the visible gap below it read as gap-plus-height-diff
   instead of the intended 48px. The lede keeps its own align-self: center. */
.work__row--top { align-items: end; }

.work__lede {
  grid-column: 1 / span 3;
  align-self: center;        /* vertically centered within the row */
  margin: 0;
  font-family: var(--sans);
  font-weight: 700;
  font-size: clamp(20px, 2.2vw, 38px);
  line-height: 1.2;
  color: var(--ink);
}

/* Top row image placement */
.work__item--remnant { grid-column: 4 / span 3; }
.work__item--luv     { grid-column: 7 / span 2; }

/* Bottom row image placement */
.work__item--timothy { grid-column: 1 / span 2; }
.work__item--bubble  { grid-column: 3 / span 3; }
.work__item--tallvase{ grid-column: 6 / span 3; }

.work__item {
  margin: 0;
  display: flex;
  flex-direction: column;
  /* Cursor-driven 3D tilt vars cascade to .work__inner (the tilting layer).
     --tilt-x/y range -1..+1 (cursor position from item center). */
  --tilt-x: 0;
  --tilt-y: 0;
}

/* Inner wrapper — receives the 3D tilt so the whole container (caption +
   photo) lifts together. Kept separate from .work__item so the entrance
   transform on the figure isn't fighting the tilt rotation.
   Tilt is restrained (3deg max) — the goal is "subtly leaning toward you",
   not a parlour-trick wobble. */
.work__inner {
  display: flex;
  flex-direction: column;
  transform-style: preserve-3d;
  transform:
    rotateY(calc(var(--tilt-x) * 3deg))
    rotateX(calc(var(--tilt-y) * -3deg));
  will-change: transform;
}

.work__media {
  position: relative;
  width: 100%;
  overflow: hidden;
  /* Warm cream paper tone — visible behind the photo's cream studio bg and
     fills any letterboxed area. Matches the Figma 2029:185 mock. */
  background: #ECE6D6;
  border-radius: 40px;
  /* Continuous corners (squircle) where supported — falls back to standard
     border-radius elsewhere. Apple uses this rounding everywhere. */
  corner-shape: squircle;
  cursor: pointer;
  /* Layered drop shadow: a tight, low-opacity contact shadow + a wider,
     softer ambient shadow. Reads as "card sitting on the page". */
  box-shadow:
    0 1px 2px rgba(20, 30, 60, 0.06),
    0 18px 40px -12px rgba(20, 30, 60, 0.18);
}
.work__media--square   { aspect-ratio: 1 / 1; }
.work__media--portrait { aspect-ratio: 396 / 606; }   /* ≈ 0.653 */

/* Photo wrapper — gets the slow expo-out hover scale. Separate from the img
   so the img can keep its instant scroll-parallax translate without inheriting
   the long transition. */
.work__photo {
  position: absolute;
  inset: 0;
  transform: scale(1);
  transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}
.work__item:hover .work__photo {
  transform: scale(1.05);
}

.work__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Subtle warm-paper print tone. Much lighter than a heavy filter — just
     enough to unify all photos on the catalog page. */
  filter: saturate(0.88) contrast(0.97);
  /* Slight overscale leaves room for the scroll-parallax translate
     (--parallax  -1 at top of viewport → +1 at bottom). */
  transform: scale(1.08) translate3d(0, calc(var(--parallax, 0) * -6%), 0);
  will-change: transform;
}

/* Light paper overlay — a faint speckle multiplied over the photo at very
   low opacity. Gives a "printed on uncoated paper" feel without being
   heavy-handed. Sits below the catalog text. */
.work__photo::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='320' height='320'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.1' numOctaves='1' seed='5' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.55  0 0 0 0 0.50  0 0 0 0 0.42  1 0 0 0 -0.4'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 320px 320px;
  background-repeat: repeat;
  mix-blend-mode: multiply;
  opacity: 0.18;
  z-index: 1;
}


/* ---------- Catalog label (Figma 2029:185) ----------
   The caption fills the card. Index sits top-left, details (title + year +
   clay + firing + dimensions) sit bottom-left. Inset is 9.4% on all sides
   to match the Figma's 56/593 ratio. */
.work__caption {
  --inset: 9.4%;
  position: absolute;
  inset: 0;
  z-index: 3;
  margin: 0;
  color: var(--ink);
  font-family: var(--sans);
  font-feature-settings: "tnum";
  pointer-events: none;
  display: block;
}
.work__caption .work__index {
  position: absolute;
  top: var(--inset);
  left: var(--inset);
  font-size: clamp(22px, 2vw, 30px);
  font-weight: 700;
  letter-spacing: -0.005em;
  line-height: 1;
}
.work__caption .work__details {
  position: absolute;
  left: var(--inset);
  right: var(--inset);
  bottom: var(--inset);
  display: flex;
  flex-direction: column;
}
.work__caption .work__title {
  font-size: clamp(17px, 1.55vw, 24px);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.005em;
  /* 8px gap between title and metadata block, matching Figma. */
  margin-bottom: 8px;
}
.work__caption .work__year,
.work__caption .work__clay,
.work__caption .work__firing,
.work__caption .work__dims {
  font-size: clamp(13px, 1.05vw, 17px);
  font-weight: 400;
  line-height: 1.6;        /* 28px line-height at 17px font (matches Figma) */
  letter-spacing: 0;
}

/* Don't let the caption block obscure clicks targeted at the photo —
   clicks pass through it to the .work__media (which is the lightbox trigger). */
.work__caption * { pointer-events: none; }

/* Entrance: each work fades + lifts into place when it enters the viewport. */
.work__item {
  --enter: 0;            /* 0 = hidden, 1 = visible */
  opacity: calc(0.001 + var(--enter));
  transform: translate3d(0, calc((1 - var(--enter)) * 24px), 0)
             scale(calc(0.97 + 0.03 * var(--enter)));
  transition:
    opacity 0.7s cubic-bezier(0.2, 0.8, 0.2, 1),
    transform 0.9s cubic-bezier(0.2, 0.8, 0.2, 1);
  will-change: transform, opacity;
}
.work__item.is-visible { --enter: 1; }

/* Reduced-motion users get static, visible items with no parallax. */
@media (prefers-reduced-motion: reduce) {
  .work__item {
    --enter: 1;
    transition: none;
  }
  .work__media img { transform: none; }
}

/* ---------- Mobile stack ---------- */
@media (max-width: 760px) {
  .work__row { grid-template-columns: 1fr; }
  .work__lede,
  .work__item--remnant,
  .work__item--luv,
  .work__item--timothy,
  .work__item--bubble,
  .work__item--tallvase { grid-column: 1; }
  .work__lede { padding-top: 0; font-size: clamp(20px, 5vw, 28px); }
}

/* ---------- Footer (Figma node 1:41) ---------- */
.site-footer {
  background: var(--bg);   /* platinum, matches page */
  padding: clamp(2rem, 3.35vw, 48px) clamp(1.25rem, 2.78vw, 40px) clamp(1.75rem, 2.85vw, 41px);
  border-top: none;
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 5.3vw, 3.3rem);
}

.site-footer__inner {
  max-width: 1440px;
  width: 100%;
  margin: 0 auto;
}

.site-footer__wordmark {
  /* Container for the two stacked SVG marks. Diverged so the cursive
     silhouette reads. Front shifts toward the cursor on hover, and squishes
     toward the pointer while being dragged (pinched). */
  --diverge: 0.6;
  --front-dx: 0;
  --front-dy: 0;
  --follow-max: 2%;
  --pinch-x: 0;
  --pinch-y: 0;
  --pinch-max: 14%;
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 489 / 113;
  color: var(--footer-blue);
  cursor: grab;
  touch-action: none;   /* prevent page scroll while dragging on touch */
}

.site-footer__wordmark.is-pinched { cursor: grabbing; }

.site-footer__mark {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.site-footer__mark--back {
  color: var(--footer-blue);   /* #255BFC */
  z-index: 1;
}

.site-footer__mark--front {
  color: var(--bg);            /* #F0F1F3 — same as page bg */
  z-index: 2;
  transform: translate(
    calc(var(--diverge) * -5% + var(--front-dx) * var(--follow-max) + var(--pinch-x) * var(--pinch-max)),
    calc(var(--diverge) * -21% + var(--front-dy) * var(--follow-max) + var(--pinch-y) * var(--pinch-max))
  );
}

.site-footer__meta {
  display: grid;
  /* Mirrors Figma columns: ©2026 at left, Instagram/Contact right-aligned ~73%,
     gap, then SLC time ~86% across. */
  grid-template-columns: auto 1fr 14% auto;
  align-items: start;
  font-family: "Google Sans Flex", var(--sans);
  font-weight: 700;
  font-size: clamp(1rem, 1.67vw, 24px);
  line-height: 1.25;
  color: var(--footer-blue);
}

.site-footer__copy {
  grid-column: 1;
  justify-self: start;
}

.site-footer__links {
  grid-column: 2;
  justify-self: end;
  text-align: right;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35em;
}

.site-footer__links a {
  color: var(--footer-blue);
  text-decoration: none;
}

.site-footer__links a:hover { opacity: 0.7; }

.site-footer__time {
  grid-column: 4;
  justify-self: end;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 600px) {
  .site-footer__meta {
    grid-template-columns: 1fr 1fr;
    row-gap: 1.25rem;
  }
  .site-footer__copy { grid-column: 1; }
  .site-footer__links { grid-column: 2; }
  .site-footer__time { grid-column: 1 / -1; justify-self: start; }
}

/* ---------- Lightbox (work piece detail) ---------- */
/* ---------- Lightbox ----------
   Shared-element transition: the clicked photo's bounding rect is captured,
   then the modal's media slot is inverse-transformed to sit on top of it
   exactly. Releasing the inverse transform with a CSS transition makes the
   photo appear to grow out of the grid into the modal. The modal's media
   slot uses --src-aspect (set per-piece via JS) so it shares the source's
   aspect ratio — no object-fit recropping during flight. The panel chrome
   (background + shadow) fades in around the growing photo. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 3vw, 2.5rem);
  pointer-events: none;
}
.lightbox[hidden] { display: none; }
.lightbox.is-open { pointer-events: auto; }

.lightbox__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(240, 241, 243, 0);
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  transition:
    background 0.55s cubic-bezier(0.16, 1, 0.3, 1),
    backdrop-filter 0.55s cubic-bezier(0.16, 1, 0.3, 1),
    -webkit-backdrop-filter 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}
.lightbox.is-open .lightbox__backdrop {
  background: rgba(240, 241, 243, 0.86);   /* platinum tint */
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}

.lightbox__panel {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  width: min(1180px, 100%);
  max-height: calc(100dvh - clamp(2rem, 6vw, 5rem));
  /* Chrome (bg + shadow) materializes around the FLIP'ing photo. */
  background: rgba(240, 241, 243, 0);
  border-radius: 24px;
  padding: clamp(1.25rem, 2.4vw, 2.25rem);
  box-shadow: 0 30px 80px -20px rgba(37, 91, 252, 0);
  transition:
    background 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0.1s,
    box-shadow 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0.1s;
}
.lightbox.is-open .lightbox__panel {
  background: var(--bg);
  box-shadow: 0 30px 80px -20px rgba(37, 91, 252, 0.18);
}

.lightbox__close {
  position: absolute;
  top: clamp(0.75rem, 1.4vw, 1.25rem);
  right: clamp(0.75rem, 1.4vw, 1.25rem);
  z-index: 2;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.lightbox__close:hover {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}

.lightbox__media {
  position: relative;
  border-radius: 20px;
  overflow: hidden;
  background: #d8dde4;
  /* Aspect inherits source aspect ratio per-piece (set inline by JS) so the
     FLIP doesn't recrop the photo mid-flight. Falls back to 4:5 if unset. */
  aspect-ratio: var(--src-aspect, 4 / 5);
  max-height: calc(100dvh - clamp(4rem, 10vw, 8rem));
  min-height: 0;
  /* FLIP origin at top-left keeps inverse-transform math straightforward. */
  transform-origin: 0 0;
  will-change: transform, border-radius;
  transition:
    transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1),
    border-radius 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.lightbox__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Source's photo wrapper is at scale(1.05+1.08) — modal img starts slightly
     zoomed and settles to scale(1) so the photo content "tightens" into place
     as it lands. JS clears these inline values after the transition. */
  transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.lightbox__info {
  display: flex;
  flex-direction: column;
  gap: clamp(1rem, 1.5vw, 1.5rem);
  padding: clamp(0.5rem, 1vw, 1rem) clamp(0.5rem, 1.5vw, 1rem);
  overflow-y: auto;
  min-height: 0;
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0.25s,
    transform 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.25s;
}
.lightbox.is-open .lightbox__info {
  opacity: 1;
  transform: translateY(0);
}
.lightbox__close {
  opacity: 0;
  transition:
    opacity 0.3s ease 0.3s,
    background 0.2s,
    color 0.2s,
    border-color 0.2s,
    transform 120ms var(--ease-ios);
}
.lightbox.is-open .lightbox__close { opacity: 1; }
.lightbox__close:active { transform: scale(0.92); }

/* Share button — iOS-shaped pill, only shown when navigator.share is available
   (JS removes [hidden]). Sits next to the close button. */
.lightbox__share {
  position: absolute;
  top: clamp(0.75rem, 1.4vw, 1.25rem);
  right: calc(clamp(0.75rem, 1.4vw, 1.25rem) + 48px);
  z-index: 2;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 50%;
  cursor: pointer;
  opacity: 0;
  transition:
    opacity 0.3s ease 0.32s,
    background 0.2s,
    color 0.2s,
    border-color 0.2s,
    transform 120ms var(--ease-ios);
}
.lightbox.is-open .lightbox__share { opacity: 1; }
.lightbox__share:hover {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}
.lightbox__share:active { transform: scale(0.92); }

/* Grabber pill: visible only on mobile, sits at the top-center of the sheet.
   Communicates "this can be dragged down to dismiss". */
.lightbox__grabber {
  display: none;
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 36px;
  height: 5px;
  border-radius: 999px;
  background: rgba(37, 91, 252, 0.25);
  pointer-events: none;
  z-index: 3;
}

/* Source media is hidden during FLIP so it doesn't ghost beneath the
   growing modal photo. Visibility (not display) preserves grid layout. */
.work__media.is-flip-source { visibility: hidden; }

.lightbox__title {
  margin: 0;
  font-family: var(--sans);
  font-weight: 700;
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  line-height: 1.1;
  color: var(--ink);
}

.lightbox__meta {
  margin: 0;
  display: grid;
  gap: 0.6rem;
}
.lightbox__row {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 1rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--rule);
  font-size: 0.95rem;
}
.lightbox__row:last-child {
  border-bottom: 1px solid var(--rule);
}
.lightbox__row dt {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  align-self: center;
}
.lightbox__row dd {
  margin: 0;
  color: var(--ink);
  font-weight: 500;
}

.lightbox__notes {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.55;
  color: var(--ink);
}

/* While lightbox is open, lock background scrolling. */
body.lightbox-open { overflow: hidden; }

/* ====================================================================
   Mobile: iOS-y treatments
   ==================================================================== */

/* ---------- Mobile: card modal (Figma 2031:201) ----------
   Below 760px the lightbox is a centered card with 8px insets from every
   screen edge — the page peeks around it so the modal feels "set on" the
   page rather than swallowing it. Drag the photo down to dismiss.
   FLIP is bypassed on mobile (the panel slide-up does the heavy lifting).
*/
@media (max-width: 760px) {
  .lightbox {
    /* Card is anchored to the bottom of the screen so it reads as a sheet
       sitting on the page. 8px horizontal/bottom insets give the page a
       sliver of breathing room around the card. Safe-area insets keep it
       clear of the iOS home indicator. */
    place-items: end stretch;
    padding:
      0
      8px
      calc(8px + env(safe-area-inset-bottom));
  }

  .lightbox__panel {
    width: 100%;
    /* 80% of the viewport height — leaves the page peeking above the card. */
    height: 80dvh;
    max-width: none;
    max-height: 80dvh;
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;

    background: var(--bg);
    border-radius: 28px;
    corner-shape: squircle;
    /* 8px inner padding on top/sides so the photo has breathing room
       inside the card. Bottom padding lives on .lightbox__info instead so
       its scrollable area absorbs any overflow. */
    padding: 8px 8px 0;
    gap: 0;

    /* Card chrome: layered drop shadow matches the catalog card style. */
    box-shadow:
      0 1px 2px rgba(20, 30, 60, 0.06),
      0 18px 40px -12px rgba(20, 30, 60, 0.18);

    overflow: hidden;

    /* Slide-up entrance from below the screen, plus extra travel so it
       clears its own bottom-shadow during the drag-out animation. */
    transform: translateY(calc(100% + 24px));
    transition: transform 0.42s var(--ease-ios);
  }
  .lightbox.is-open .lightbox__panel { transform: translateY(0); }
  /* Class added by JS during pointer drag — kills CSS transition so the
     panel tracks the finger 1:1 instead of easing on every move. */
  .lightbox__panel.is-dragging { transition: none; }

  /* No grabber pill in this design — drag is initiated from the photo. */
  .lightbox__grabber { display: none; }

  /* Photo slot: full width at top of card, cream paper backdrop, slightly
     smaller corner radius than the card itself. */
  .lightbox__media {
    border-radius: 22px;
    corner-shape: squircle;
    background: #ECE6D6;
    /* Tap target hint — the photo IS the drag handle on mobile. */
    cursor: grab;
    /* Cap so portrait pieces don't push the info area off-screen. */
    max-height: 46dvh;
    transition: none;
    transform: none;
    /* Don't let aspect-ratio collapse the photo when info is tall. */
    flex: 0 0 auto;
    /* Capture vertical gestures here so the panel drag-to-dismiss
       beats native scroll. The info area below still scrolls freely. */
    touch-action: none;
  }
  .lightbox__media img { pointer-events: none; -webkit-user-drag: none; }
  .lightbox__panel.is-dragging .lightbox__media { cursor: grabbing; }
  .lightbox__img {
    transition: none;
    filter: saturate(0.88) contrast(0.97);
  }

  /* Close button: circular, blue-bordered, floats over the photo's top-right.
     Uses the page bg so it reads as a chip, not a fill. */
  .lightbox__close {
    position: absolute;
    top: 20px;
    right: 20px;
    z-index: 4;
    width: 36px;
    height: 36px;
    background: var(--bg);
    color: var(--ink);
    border: 2px solid var(--ink);
    border-radius: 50%;
    box-shadow: 0 2px 6px rgba(20, 30, 60, 0.12);
  }
  .lightbox__close:hover {
    /* Disable desktop's invert-on-hover; on touch this state never fires. */
    background: var(--bg);
    color: var(--ink);
    border-color: var(--ink);
  }
  /* Share button hidden in this design — it's not part of the Figma. */
  .lightbox__share { display: none !important; }

  /* Info area below the photo: scrollable, with the title centered and
     metadata as label-left / value-right rows separated by hairlines. */
  .lightbox__info {
    padding: 24px 16px calc(16px + env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    gap: 16px;
    min-height: 0;
    /* The info section reveals as the panel finishes its slide-up; matches
     the desktop info reveal but driven by the panel's transform instead. */
    opacity: 1;
    transform: none;
    transition: none;
  }

  .lightbox__title {
    text-align: center;
    font-size: 28px;
    font-weight: 700;
    line-height: 1.15;
    color: var(--ink);
    margin: 0;
  }

  /* Metadata rows: label uppercase-ish on left, value right-aligned, with a
     hairline rule above each row (and below the last). */
  .lightbox__meta { gap: 0; }
  .lightbox__row {
    grid-template-columns: 1fr auto;
    gap: 1rem;
    padding: 14px 0;
    border-top: 1px solid var(--rule);
    border-bottom: none;
    font-size: 16px;
    align-items: center;
  }
  .lightbox__row:last-of-type { border-bottom: 1px solid var(--rule); }
  .lightbox__row dt {
    color: var(--ink);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }
  .lightbox__row dd {
    margin: 0;
    color: var(--ink);
    font-size: 16px;
    font-weight: 700;
    text-align: right;
  }

  .lightbox__notes {
    color: var(--ink);
    font-size: 15px;
    line-height: 1.5;
    margin: 0;
  }
}

/* ---------- Mobile: horizontal snap gallery ----------
   On mobile, both .work__row containers are flattened with `display: contents`
   so their children become direct flex children of .work. The whole work
   section becomes ONE horizontal scroller — lede card first, then all five
   photos in a single uninterrupted swipe (like an App Store / Photos shelf).
*/
@media (max-width: 760px) {
  .work {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: visible;
    gap: 16px;
    padding: clamp(2rem, 6vw, 3rem) 6vw clamp(2.5rem, 7vw, 4rem);
    scroll-snap-type: x mandatory;
    scroll-padding-left: 6vw;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .work::-webkit-scrollbar { display: none; }

  /* Rows collapse to display: contents so .work__lede + all .work__item
     elements become siblings under .work (the flex/scroll container). */
  .work__row {
    display: contents;
    perspective: none;          /* tilt is desktop-only */
  }

  .work__lede,
  .work__item--remnant,
  .work__item--luv,
  .work__item--timothy,
  .work__item--bubble,
  .work__item--tallvase {
    grid-column: auto;
  }

  .work__lede {
    flex: 0 0 78vw;
    align-self: stretch;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    padding: 0;
    font-size: clamp(20px, 5.5vw, 28px);
    display: flex;
    align-items: center;
  }

  .work__item {
    flex: 0 0 78vw;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    /* Disable entrance offset/scale on mobile — items appear as you swipe to
       them, the entrance transition would fight horizontal scroll-snap. */
    --enter: 1;
    transform: none !important;
    opacity: 1;
    transition: none;
  }

  /* Smaller iOS-style corners on photos, replaces the 80px desktop pebble. */
  .work__media {
    border-radius: 32px;
    corner-shape: squircle;
  }

  /* Catalog label keeps 9.4% inset on mobile (matches Figma ratio) so the
     type sits cleanly inside the 78vw card. */
  .work__caption .work__index { font-size: 19px; }
  .work__caption .work__title { font-size: 17px; margin-bottom: 6px; }
  .work__caption .work__year,
  .work__caption .work__clay,
  .work__caption .work__firing,
  .work__caption .work__dims { font-size: 13px; line-height: 1.45; }

  /* Hover scale isn't relevant on coarse pointers — the :active scale takes
     over via the global tap rules above. */
  .work__photo { transition: none; }
  .work__item:hover .work__photo { transform: scale(1); }
}

/* ---------- Mobile: footer adopts the home-indicator ---------- */
@media (max-width: 760px) {
  .site-footer {
    padding-bottom: calc(clamp(1.75rem, 2.85vw, 41px) + env(safe-area-inset-bottom));
  }
}

/* ---------- Smallest screens: hero compaction ---------- */
@media (max-width: 600px) {
  .hero { height: 220dvh; }
  .hero__logo { --logo-w: clamp(220px, 60vw, 360px); }
}
