:root {
  --bg: #0e0c0a;
  --bg2: #16120d;
}

* { box-sizing: border-box; cursor: none; } /* custom cursor everywhere, no native */

html, body {
  margin: 0;
  height: 100%;
  background: #000;
  color: #f3ecdd;
  font-family: "Playfair Display", serif;
  font-size: 16px;
  overflow: hidden;
  cursor: none; /* replaced by the custom dotted cursor */
}

/* Fixed viewport. No native scroll — the camera (#world) is the only motion. */
#scroller {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: #000;
}

/* Holds the falling field + the title. Fixed in place. */
#world {
  position: fixed;
  inset: 0;
}

/* The falling-item container. Each .fall is absolutely positioned inside and
   driven every frame by a JS-written transform (see landing.js). */
#canvas {
  position: absolute;
  inset: 0;
}


/* ── falling items ───────────────────────────────────────────────────────────
   Both artwork tiles (.fall--art) and star glyphs (.fall--star) fall with the
   same depth engine. Their base size is set from JS (px), position + depth-scale
   are written into `transform` per frame, and depth-of-field (blur/dim) is
   written into `filter` + `opacity`. transform-origin is the item's own center
   so depth-scale and the 2× hover pop both grow about the middle. */
.fall {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: center center;
  /* only transform changes per frame — promote just that (filter/opacity are set
     once per spawn). Keeping filter/opacity out of will-change avoids pinning a
     needlessly heavy layer for every one of the ~280 falling items. */
  will-change: transform;
  /* items are placed off-screen (via transform) before the field starts */
  opacity: 0;
}

/* artwork tile: a framed thumbnail, hover-interactive */
.fall--art {
  border-radius: calc(2px * var(--rs, 1));
  box-shadow: 0 4px 22px rgba(0, 0, 0, 0.55);
  background: #000;
  cursor: none;
  pointer-events: none; /* Hit-testing optimization: JS enables this only for nearest tiles */
}

/* GPU-accelerated darkness overlay (so image stays opaque and hides trails behind it) */
.fall--art::before {
  content: "";
  position: absolute;
  inset: 0;
  background: #000;
  opacity: var(--dark, 0);
  pointer-events: none;
  z-index: 5;
  border-radius: inherit;
  transition: opacity 0.4s ease;
}

.fall--art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: inherit;
}

.fall--art img.high-res-img {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  transition: opacity 0.4s ease;
  z-index: 2;
}

.fall--art.hi-res-ready img.high-res-img {
  opacity: 1;
}

/* Subtle corner spinner shown while a focused tile's full-res image downloads.
   ::before/::after are taken (darkness overlay / marching ants), so it's a real
   child node (added lazily in focusItem). --rs scales it with the magnified tile. */
.fall--art .hi-res-spinner {
  position: absolute;
  top: calc(6px * var(--rs, 1));
  right: calc(6px * var(--rs, 1));
  width: calc(14px * var(--rs, 1));
  height: calc(14px * var(--rs, 1));
  border-radius: 50%;
  border: calc(2px * var(--rs, 1)) solid rgba(243, 236, 221, 0.35);
  border-top-color: rgba(243, 236, 221, 0.95);
  opacity: 0;
  /* delay so it only appears if the hi-res is actually slow (>~150ms) */
  transition: opacity 0.2s ease 0.15s;
  z-index: 4;
  pointer-events: none;
}

.fall--art.hi-res-loading .hi-res-spinner {
  opacity: 1;
  animation: hi-res-spin 0.8s linear infinite;
}

@keyframes hi-res-spin { to { transform: rotate(360deg); } }

/* Stars are no longer DOM nodes — they're drawn as canvas sprites (see paintStar
   in landing.js) to avoid ~160 compositor layers + per-frame transform strings. */

/* ── hover pop ───────────────────────────────────────────────────────────────
   Hovering an artwork freezes it (landing.js stops advancing its fall) and adds
   .magnify. The scale-up/relax is eased in JS (transform is written every frame,
   so it must NOT be a CSS transition or it would lag the fall); only filter,
   opacity and shadow — which JS writes just once — are transitioned here. */
.fall--art {
  transition: filter 0.4s ease, opacity 0.4s ease, box-shadow 0.35s ease;
}

.fall--art.magnify {
  z-index: 90000 !important;
  filter: none !important;
  opacity: 1 !important;
  box-shadow: 0 calc(12px * var(--rs, 1)) calc(44px * var(--rs, 1)) rgba(0, 0, 0, 0.7);
}

/* Clear the darkness overlay on hover */
.fall--art.magnify::before {
  opacity: 0 !important;
}

/* Rotating dashed border (marching ants) for hovered artwork */
@keyframes march {
  0% { background-position: 0px 0px, 0px 100%, 100% 0px, 0px 0px; }
  100% { background-position: 24px 0px, -24px 100%, 100% 24px, 0px -24px; }
}

.fall--art.hovering::after,
.fall--art.magnify::after {
  content: "";
  position: absolute;
  top: -2px;
  left: -2px;
  right: -2px;
  bottom: -2px;
  /* 4 linear gradients acting as the 4 borders */
  background-image: 
    linear-gradient(90deg, rgba(243, 236, 221, 0.9) 50%, transparent 50%),
    linear-gradient(90deg, rgba(243, 236, 221, 0.9) 50%, transparent 50%),
    linear-gradient(180deg, rgba(243, 236, 221, 0.9) 50%, transparent 50%),
    linear-gradient(180deg, rgba(243, 236, 221, 0.9) 50%, transparent 50%);
  background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
  /* 24px long dashes, 2px thick */
  background-size: 24px 2px, 24px 2px, 2px 24px, 2px 24px;
  animation: march 0.6s infinite linear;
  pointer-events: none;
  z-index: -1; /* Place it nicely behind/around */
  border-radius: 4px; /* Slightly round the corners */
}

/* Only a MAGNIFIED tile has a caption under it (.fall-info is hidden otherwise), so only
   there do the ants stretch past the image to enclose it. Written as an override rather
   than in the shared rule above, because that rule is also what a merely-hovered tile
   gets: --info-h is a leftover from the last magnify, and a hovered tile wearing it grew
   a dashed skirt below itself with nothing inside it. landing.js clears the variable when
   a tile returns to its falling size; this is the half that cannot go stale. */
.fall--art.magnify::after {
  bottom: calc(-2px - var(--info-h, 0px));
}

/* ── artwork info card (shown on hover) ────────────────────────────────────── */
.fall-info {
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  background: #0e0c0a;
  color: #f3ecdd;
  padding: calc(4px * var(--rs, 1));
  box-sizing: border-box;
  opacity: 0;
  pointer-events: none;
  text-align: center;
  transition: opacity 0.3s ease, transform 0.3s ease;
  transform: translateY(calc(-4px * var(--rs, 1)));
  border-radius: 0 0 calc(2px * var(--rs, 1)) calc(2px * var(--rs, 1));
  box-shadow: 0 calc(12px * var(--rs, 1)) calc(24px * var(--rs, 1)) rgba(0, 0, 0, 0.7);
  z-index: -2; /* drop from behind the image */
}

.fall--art.magnify .fall-info {
  opacity: 1;
  transform: translateY(0);
}

/* Magnified tiles are enlarged via real layout width/height (not transform:scale),
   so these absolute px metrics are multiplied by --rs (the tile's magnify factor,
   set per-tile in landing.js) to preserve the original proportions. --rs defaults
   to 1 for falling tiles, which don't show their caption anyway. */
.fall-info strong {
  display: block;
  font-family: "Playfair Display", serif;
  font-size: calc(8.5px * var(--rs, 1));
  font-weight: 700;
  line-height: 1.1;
  margin-bottom: calc(1px * var(--rs, 1));
}

.fall-info span {
  display: block;
  font-family: "Playfair Display", serif;
  font-size: calc(6px * var(--rs, 1));
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.7;
  line-height: 1.1;
}

/* ── title overlay ───────────────────────────────────────────────────────────
   "The Genesis Experience" — a fixed, centered overlay (no longer a mosaic
   cell). Sits at a mid z-index so near artworks fall in FRONT of it and far
   ones fall BEHIND it. pointer-events:none so it never blocks hovering a
   behind-title tile. */
#title {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  z-index: 5000;            /* items with depth z >= TITLE_Z get a higher z-index */
  pointer-events: none;
  padding: 0 6vw;
}

#title span {
  display: block;
  max-width: 100%;
  font-family: "Playfair Display", serif;
  font-optical-sizing: auto;
  font-weight: 700;
  font-size: clamp(2rem, 7vw, 6rem);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.12;
  text-align: center;
  color: #f3ecdd;
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.7);
  white-space: normal;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ── custom cursor: a dotted circle that slowly rotates ── */
#cursor {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 30000;
  opacity: 0;
  transition: opacity 0.18s ease;
  will-change: transform;
}

#cursor.ready { opacity: 1; }

#cursor span {
  display: block;
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px; /* center on the pointer */
  border: 3px dashed rgba(240, 232, 214, 0.9);
  border-radius: 50%;
  animation: spin 2s linear infinite;
}

/* near the scroll cue, artwork focus is disabled — the cursor halts its spin to
   signal that clicking here won't magnify a tile (see landing.js). */
#cursor.no-spin span { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  #cursor span { animation: none; }
}

/* ── background dimmer when an artwork is focused ── */
#dimmer {
  position: absolute;
  inset: 0;
  background: #000;
  opacity: 0;
  pointer-events: none;
  z-index: 80000; /* above all falling items except the magnified one (90000) */
  transition: opacity 0.4s ease;
}

#dimmer.active {
  opacity: 0.45; /* darkens the background and other artworks heavily */
}

/* ── page-to-page transition ─────────────────────────────────────────────────
   Page 1 is the whole falling field + title + scroll cue (all inside #world).
   Advancing adds .to-page2 to <body>: #world lifts up and fades while #page2
   rises from below — both moving up in screen space, so it reads as the camera
   descending to the next page. The RAF fall loop is paused once #world is gone
   (see landing.js) so we don't animate an invisible field. */
#world {
  /* removed transform transition so JS can handle parallax sweep */
}

body.to-page2 #title, body.to-page2 #scroll-cue-1 {
  transform: translateY(-100dvh);
  opacity: 0;
}

#title {
  transition: transform 0.7s ease-in-out, opacity 0.7s ease-in-out;
}

/* the empty second page: a full-screen dark surface parked just below the
   viewport, sliding up into place on transition. */
#page2 {
  position: fixed;
  inset: 0;
  background: transparent;
  z-index: 20000; /* above field/title (5000), below the cursor (30000) */
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-sizing: border-box;
}

body.to-page2:not(.to-page3) #page2 {
  pointer-events: auto;
}

.page2-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  width: 100%;
  height: 100%;
  gap: 0;
  min-width: 0; /* as a flex child of #page2, don't let content min-width overflow the viewport */
}

.page2-col {
  display: flex;
  flex-direction: column;
  justify-content: center;
  opacity: 0;
  will-change: transform, opacity;
  /* Quick exit without delay when leaving page 2 */
  transition: transform 0.8s ease-in-out, opacity 0.5s ease-in-out;
}

/* Initial positions (out of view) */
.page2-col:nth-child(1) { transform: translateY(100dvh); }
.page2-col:nth-child(2) { transform: translateY(-100dvh); }
.page2-col:nth-child(3) { transform: translateY(100dvh); }

/* Active state */
body.to-page2 .page2-col {
  transform: translateY(0);
  opacity: 1;
  /* Enters right when the previous screen is about to disappear (0.35s delay) */
  transition: transform 1.8s cubic-bezier(0.16, 1, 0.3, 1) 0.35s, opacity 1.2s ease-in-out 0.35s;
}

body.no-field .page2-col {
  transition: none !important;
}

/* Arriving on page 2 with no journey: the reader's "← Library" (the #library hash,
   handled in landing.js). Same end state as advancing normally, minus its
   introduction — the class is on <body> for exactly one frame, so everything here
   animates as usual for the rest of the visit. Named per element rather than as a
   blanket `*`: the tiles behind #page2 keep their own hover and focus transitions,
   and the reader can walk back into the field. */
body.no-anim #title,
body.no-anim #scroll-cue-1,
body.no-anim #cursor,
body.no-anim .page2-col,
body.no-anim .lo-credits {
  transition: none !important;
}

.artworks-col {
  height: 100%;
  min-width: 0;
  min-height: 0;
}

.artwork-cell {
  flex: 1;
  min-width: 0; /* let cells shrink to share the row instead of overflowing (flex min-width:auto blowout) */
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 3.5vmin;
  position: relative;
}

/* Positioning context + reserved space for the scattered images, so the label
   below sits in normal flow and the [images + label] group centers as a unit. */
.artwork-cell__stage {
  position: relative;
  /* smaller inner cell, centered by the cell's flex centering, with margin around it */
  width: 82%;
  height: 82%;
  flex-shrink: 0;
  transform-style: preserve-3d; /* pass the cell's orbit.js perspective through to the images */
}

.artwork-ph {
  display: block;
  width: 24vmin;
  height: auto;         /* true aspect, no crop; clusters vary in height (painterly) */
  aspect-ratio: auto;
  flex-shrink: 0;
  object-fit: contain;
  border: 1px solid rgba(61, 54, 44, 0.9);
  border-radius: 4px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45); /* light: orbit.js animates a per-depth shadow on top */
  transition: border-color 0.3s ease;
  position: absolute;
  top: 50%;
  left: 50%;
  background-color: #1a1713; /* fills any transparent PNG edge behind the art */
}

/* Fix cursor disappearing on page 2 due to cue pointerleave bug */
body.to-page2 #cursor.ready {
  opacity: 1 !important;
}

/* Size + placement of the .artwork-ph images is computed in orbit.js from the
   box geometry (so they stay contained and as large as the box allows), and the
   transform is driven every frame. No CSS scatter/z-index here. */

.artwork-cell__label {
  /* sits in the margin band between the inner stage box and the outer cell edge */
  position: absolute;
  left: 50%;
  bottom: 6.5%;              /* hugs the inner box, leaving more space toward the outer edge */
  transform: translate(-50%, 50%);
  max-width: none;
  white-space: nowrap;      /* keep each label on a single line */
  text-align: center;
  font-family: "Playfair Display", serif;
  font-size: clamp(1.2rem, 1.8vw, 1.6rem);
  font-weight: 400;
  color: rgba(243, 236, 221, 0.9);
  letter-spacing: 0.02em;
  text-shadow: 0 2px 8px rgba(0,0,0,0.6);
  pointer-events: none;
}

/* Artist of the front-most painting in the stack. It is anchored at the stage
   center; orbit.js drives the transform every frame so it rides the bottom edge of
   whichever painting is on top (barely touching it), fading between artists as the
   depth cycles. NOTE: the transform is owned by JS — do not set one here. */
.artwork-cell__artist {
  position: absolute;
  left: 50%;
  top: 50%;
  margin-top: 0.35em;          /* the hair of gap so it barely kisses the edge */
  white-space: nowrap;
  text-align: center;
  font-family: "Playfair Display", serif;
  font-style: italic;
  font-size: clamp(0.55rem, 0.7vw, 0.75rem);
  color: rgba(243, 236, 221, 0.85);
  letter-spacing: 0.03em;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.7);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
  z-index: 2;
}

/* Landscape/desktop: cells stack vertically, so the lower cell of each column
   would have its label jammed against the screen edge — put it in the TOP margin. */
@media (orientation: landscape) {
  .artworks-col .artwork-cell:first-child .artwork-cell__label {
    transform: translate(-50%, calc(50% - 3.5vh));
  }
  
  .artworks-col .artwork-cell:last-child .artwork-cell__label {
    top: 6.5%;
    bottom: auto;
    transform: translate(-50%, calc(-50% + 3.5vh));
  }

  /* Shift each inner box toward its outer screen edge: smaller outward margin
     (top/bottom edge), larger inward margin (toward the center text row).
     vh, not %, because percentage margins resolve against width, not height. */
  .artworks-col .artwork-cell:first-child .artwork-cell__stage {
    transform: translateY(-3.5vh);   /* upper cell moves toward the top edge */
  }
  .artworks-col .artwork-cell:last-child .artwork-cell__stage {
    transform: translateY(3.5vh);    /* lower cell moves toward the bottom edge */
  }
}

.artwork-ph:hover {
  border-color: #a6987a;
}

.text-col {
  text-align: center;
  padding: 0 2vw;
}

.text-col h2 {
  font-family: "Playfair Display", serif;
  font-size: clamp(2rem, 4vw, 4rem);
  font-weight: 700;
  margin: 0 0 1.5rem 0;
  color: #f3ecdd;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-shadow: 0 2px 10px rgba(0,0,0,0.5);
}

.text-col p {
  font-family: "Playfair Display", serif;
  font-size: clamp(1.1rem, 1.5vw, 1.35rem);
  line-height: 1.6;
  color: rgba(243, 236, 221, 0.85);
  margin: 0;
  text-align: justify;
  text-align-last: center;
}

/* Inline call-to-action that sits at the end of the paragraph line. */
.reader-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  margin-left: 0.5em;
  margin-top: 0.25em;
  padding: 0.12em 0.7em 0.16em;
  font-family: "Playfair Display", serif;
  font-size: 0.82em;                 /* a touch smaller than the running text */
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  vertical-align: baseline;
  color: #f3ecdd;
  border: 1px solid rgba(166, 152, 122, 0.7);
  border-radius: 2px;
  background: rgba(166, 152, 122, 0.06);
  transition: background-color 0.35s ease, border-color 0.35s ease, color 0.35s ease;
}

.reader-cta__chev {
  display: inline-flex;
  align-items: center;
  transition: transform 0.35s ease;
}

.reader-cta__chev svg {
  display: block;
  width: 0.5em;
  height: 0.7em;
  overflow: visible;
}

.reader-cta__chev svg:nth-child(2) {
  margin-left: -0.28em;              /* overlap the two into a tight >> */
}

.reader-cta__chev path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.reader-cta:hover {
  background: rgba(166, 152, 122, 0.18);
  border-color: #a6987a;
  color: #fff;
}

.reader-cta:hover .reader-cta__chev {
  transform: translateX(0.15em);
}

/* Single-column stacked layout is for portrait phones/tablets only. Landscape
   tablets (e.g. iPad 1024×768) are wide-but-short: stacking 3 rows there
   cramps them and the tall image cluster overruns its row, so they fall through
   to the 3-column layout above, which fits fine down to ~700px tall. */
@media (max-width: 1024px) and (orientation: portrait) {
  #page2 {
    align-items: flex-start;
    overflow-y: hidden;
    overflow-x: hidden;
    padding: 0;
  }

  .page2-grid {
    grid-template-columns: minmax(0, 1fr);
    /* middle (text) row = 1/4 of height; two artwork rows share the rest (3/8 each) */
    grid-template-rows: 1.5fr 1fr 1.5fr;
    height: 100%;
    width: 100%;
    gap: 0;
  }

  /* Horizontal slide for mobile rows */
  .page2-col:nth-child(1) { transform: translateX(-100dvw); }
  .page2-col:nth-child(2) { transform: translateX(100dvw); }
  .page2-col:nth-child(3) { transform: translateX(-100dvw); }

  body.to-page2 .page2-col {
    transform: translateX(0);
  }

  .artworks-col {
    flex-direction: row;
    align-items: stretch;   /* cells fill the full row height */
    height: 100%;
    gap: 0;                 /* clean 50/50 split, no center gap */
  }

  .artwork-cell {
    flex: 1 1 0;            /* two equal halves */
    min-width: 0;
    height: 100%;          /* fill the row height */
  }

  .text-col {
    padding: 0 6vw;        /* text keeps side margins; artwork cells stay full-bleed */
  }

  .artwork-ph {
    display: block;
    width: 56%; /* fills the cell to a small padding; cluster is 1.4× this wide */
    max-width: 22vh;
    max-height: 30vh; /* override the vmin cap so portrait art isn't over-cropped */
    aspect-ratio: auto;
    height: auto;
  }

  .artwork-cell__label {
    line-height: 1.25;
    font-size: clamp(1rem, 3.2vw, 1.4rem);
  }

  .text-col h2 {
    font-size: clamp(1.4rem, 6vw, 2.2rem);
    margin: 0 0 1rem 0;
  }

  .text-col p {
    font-size: clamp(0.95rem, 3.5vw, 1.15rem);
  }

  /* bottom row: labels sit in the TOP margin band instead of the bottom */
  .page2-col:nth-child(3) .artwork-cell__label {
    top: 6.5%;
    bottom: auto;
    transform: translate(-50%, -50%);
  }
}

/* ── scroll / continue indicator ──────────────────────────────────────────────
   A downward-flowing stream of chevrons: each fades in at the top, travels down
   through the two slots, then shoots out the bottom fading away. Three chevrons
   run the SAME animation offset by a third of the cycle, so at any moment the
   bottom one is leaving while the next takes its place and a fresh one enters up
   top. Lives inside #world, so it lifts and fades with everything during the
   page transition. */
.scroll-cue {
  position: absolute;
  bottom: 1.5vh;
  left: 50%;
  transform: translateX(-50%) scale(0.7);
  width: 66px;
  height: 75px;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  cursor: none; /* keep the custom dotted cursor */
  pointer-events: auto;
  z-index: 6000; /* above the falling field & title within #world */
  opacity: 1;
  transition: transform 0.7s ease-in-out, opacity 0.7s ease-in-out;
}

body.to-page2 #scroll-cue-1 {
  opacity: 0;
  pointer-events: none;
}

/* each chevron is an SVG "v" so its stroke can be solid while flowing and switch
   to marching dashes on hover. Absolutely stacked; the flow is pure transform. */
.scroll-cue .chev {
  position: absolute;
  left: 0;
  right: 0;
  top: 9px;
  margin: 0 auto;
  width: 42px;
  height: 27px;
  opacity: 0;
  animation: chev-flow 3.6s linear infinite;
}

.scroll-cue .chev svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.scroll-cue .chev path {
  fill: none;
  stroke: rgba(243, 236, 221, 0.95);
  stroke-width: 3.5;
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

/* stagger the stream by a third of the cycle each. NEGATIVE delays start each
   chevron already advanced into the cycle, so the field is full from the first
   frame (no ramp-up) and the flow can be paused/resumed seamlessly. */
.scroll-cue .chev:nth-child(2) { animation-delay: -1.2s; }
.scroll-cue .chev:nth-child(3) { animation-delay: -2.4s; }

/* one chevron's life: hold briefly at the top (a small delay), fade in while
   sliding into the top slot, ride down to the bottom slot, then shoot out the
   bottom fading. ~11px between the two slots reads as a tight double chevron. */
@keyframes chev-flow {
  0%   { opacity: 0; transform: translateY(-12px); }
  33%  { opacity: 0; transform: translateY(-12px); }  /* hold invisibly at the top — the delay */
  45%  { opacity: 1; }                                /* faded in, already mid-glide (no stall) */
  90%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(24px); }   /* ONE continuous linear glide down + fade out */
}

/* cursor in the disabled zone (near the cue) OR hovering it: FREEZE the flow
   where it is — paused, NOT removed, so leaving the zone resumes the very same
   chevrons seamlessly instead of restarting them (which would blink them away).
   The steady flow always keeps ≥2 chevrons on screen, so the frozen frame reads
   as a static arrow stack. */
.scroll-cue.cue-frozen .chev,
.scroll-cue.cue-hot .chev {
  animation-play-state: paused;
}

/* hovering directly: the frozen chevrons simply grow, and the custom cursor is
   hidden (JS), so the cue itself becomes the pointer. */
.scroll-cue.cue-hot {
  transform: translateX(-50%) scale(0.85);
}

@media (prefers-reduced-motion: reduce) {
  /* static double chevron, no flow or march */
  .scroll-cue .chev { animation: none; opacity: 0.85; }
  .scroll-cue .chev:nth-child(1) { transform: translateY(-6px); }
  .scroll-cue .chev:nth-child(2) { transform: translateY(13.5px); }
  .scroll-cue .chev:nth-child(3) { opacity: 0; }
}

/* ── page 3 ────────────────────────────────────────────────────────────────── */
#page3 {
  --p3-bg: #000;
  position: fixed;
  inset: 0;
  background: var(--p3-bg);
  z-index: 15000; /* below page 2 */
  pointer-events: none;
  box-sizing: border-box;
  color: #f3ecdd;
  overflow: hidden;                 /* clip any stray overflow (esp. the tree card) */
  opacity: 0;                       /* hidden until active — don't cover pages 1/2 */
  visibility: hidden;
  transition: opacity 0.4s ease-in-out, visibility 0s linear 0.4s;
}

body.to-page3 #page3 {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.4s ease-in-out, visibility 0s;
}

/* Layout: card 1 top-left, text top-right, tree across the bottom */
.p3-grid {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-rows: minmax(0, 0.9fr) minmax(0, 1.35fr);
  gap: clamp(1.4rem, 3vw, 3rem);
  /* vertical padding only */
  padding: clamp(1.6rem, 4vh, 3.4rem) 0;
  box-sizing: border-box;
}

.p3-card1 { grid-column: 1; grid-row: 1; }
.p3-text  { grid-column: 2; grid-row: 1; }
.p3-card2 { grid-column: 1 / -1; grid-row: 2; }

/* ── card 1: artwork + scripture, left edge dissolving into the page ── */
.p3-card1 {
  position: relative;
  margin: 4rem 0 0 0;
  transform-origin: top left;
  z-index: 10;
  min-height: 0;
  height: 100%;
  aspect-ratio: 822 / 1134;   /* match card1.png so the full composition shows */
  max-width: 100%;
  justify-self: start;
  overflow: hidden;
  border-radius: 6px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  pointer-events: none; /* Prevents scaled card from blocking the tree below it */
  container-type: size; /* Enables tracking object-fit: cover crop */
}
.p3-card1 img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
/* dark gradient in from the left so the card blends into the background */
.p3-card1::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg,
      var(--p3-bg) 0%,
      rgba(11, 9, 8, 0.75) 16%,
      rgba(11, 9, 8, 0) 42%);
  z-index: 1;
}
/* anchor for the arrow's origin — sits on the little tree icon baked into card1.png */
.p3-arrow-source {
  position: absolute;
  left: calc(50cqw + 0.2293 * max(100cqw, 72.4868cqh) - 5px);
  top: calc(50cqh - 0.0736 * max(100cqh, 137.9562cqw) - 5px);
  width: 10px;
  height: 10px;
  z-index: 2;
}
.p3-card1-tree-btn {
  position: absolute;
  /* Track the baked-in icon exactly through object-fit: cover cropping */
  left: calc(50cqw + 0.2293 * max(100cqw, 72.4868cqh) - 0.575rem);
  top: calc(50cqh - 0.0736 * max(100cqh, 137.9562cqw) - 0.575rem);
  width: 1.15rem;
  height: 1.15rem;
  z-index: 3;
  background: #000; /* hide the baked-in icon */
  color: #45a366; /* var(--soy-green) */
  opacity: 1; /* keep solid so black background hides the image beneath */
  border: none;
  border-radius: 50%;
  box-shadow: none;
  padding: 0;
  display: block; /* Removed flex to avoid Safari SVG flexbugs */
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.2, 0, 0, 1), opacity 0.15s;
  pointer-events: auto;
}
.p3-card1-tree-btn:hover {
  transform: scale(1.15);
  opacity: 1;
}
.p3-card1-tree-btn svg {
  width: 100%;
  height: 100%;
  display: block;
  flex-shrink: 0; /* extra safety for Safari */
}

/* ── right-hand text block: horizontally centered in the right column ── */
.p3-text {
  align-self: start;
  justify-self: center;
  margin-top: auto;
  margin-bottom: auto;
  padding: 1rem clamp(1.5rem, 3.5vw, 3.5rem) 1rem 0;
  min-height: 0;
}
.p3-text h2 {
  font-family: "Playfair Display", serif;
  font-size: clamp(1.2rem, 3.4vw, 3.4rem);
  white-space: nowrap;
  font-weight: 700;
  margin: 0 0 1.1rem 0;
  color: #f3ecdd;
  letter-spacing: 0.01em;
  line-height: 1.05;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}
.p3-text p {
  font-family: "Playfair Display", serif;
  font-size: clamp(1rem, 1.35vw, 1.28rem);
  line-height: 1.65;
  color: rgba(243, 236, 221, 0.82);
  margin: 0;
  max-width: 34ch;
  text-align: justify;
  text-align-last: center;
}

/* ── card 2: the embedded genealogy tree ── */
.p3-card2 {
  position: relative;
  min-height: 0;
  margin: 0 clamp(1.4rem, 3.5vw, 3.4rem);   /* inset from the edges (card 1/text hug them) */
  border: none;
  border-radius: 6px;
  overflow: hidden;
  background: #000;
  /* palette for the ported tree (soy-agaci uses these vars + currentColor) */
  --surface: #000;
  --surface-border: rgba(166, 152, 122, 0.28);
  color: #e9e0cf;
}
.p3-card2 .tree-scroll {
  position: absolute;
  inset: 0;
  overflow: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.p3-card2 .tree-scroll::-webkit-scrollbar {
  display: none;
}
.p3-card2 .tree-sizer {
  position: relative;
  width: 1820px;
  height: 1950px;
}
@media (min-width: 1100px) {
  .p3-card2 .tree-sizer {
    margin: 0 auto;
  }
}
.p3-card2 .tree-canvas { position: relative; width: 1820px; height: 1950px; transform-origin: 0 0; }
.p3-card2 .tree-svg    { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }

.p3-card2 .tn { position: absolute; transform: translate(-50%, -50%); cursor: pointer; z-index: 2; }
.p3-card2 .tn-pill {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.51rem 1.08rem;
  border: 1px solid var(--surface-border);
  background: var(--surface);
  border-radius: 999px;
  font-size: 1.5rem; letter-spacing: 0.04em; white-space: nowrap;
  color: inherit; opacity: 0.9;
  transition: border-color 0.15s, opacity 0.15s, transform 0.15s, box-shadow 0.15s;
}
.p3-card2 .tn-dot {
  width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0;
  background: color-mix(in srgb, currentColor 35%, transparent);
}
.p3-card2 .tn:hover .tn-pill,
.p3-card2 .tn.active .tn-pill {
  opacity: 1; transform: scale(1.05);
  border-color: color-mix(in srgb, currentColor 45%, transparent);
}
.p3-card2 .tn[data-b="root"] .tn-pill { font-size: 1.65rem; font-weight: 600; }
.p3-card2 .tn[data-b="kayin"] .tn-dot { background: #a83b3b; }
.p3-card2 .tn[data-b="habil"] .tn-dot { background: #4f7a4f; }
.p3-card2 .tn[data-b="habil"] .tn-pill { opacity: 0.6; }
.p3-card2 .tn[data-id="hanok"] .tn-dot { background: #4aafaf; }
.p3-card2 .tn[data-id="ibram"] .tn-dot,
.p3-card2 .tn[data-id="ismail"] .tn-dot { background: #c79a36; }
.p3-card2 .tn[data-id="nuh"] .tn-pill,
.p3-card2 .tn[data-id="ibram"] .tn-pill,
.p3-card2 .tn[data-id="ishak"] .tn-pill,
.p3-card2 .tn[data-id="betuel"] .tn-pill,
.p3-card2 .tn[data-id="yakup"] .tn-pill { font-weight: 600; }
.p3-card2 .tn[data-id="ibram"]:hover .tn-pill,
.p3-card2 .tn[data-id="ibram"].active .tn-pill { border-color: #c79a36; box-shadow: 0 0 16px rgba(180,140,50,0.35); }
/* Terah — arrow target: a steady gold glow so it reads as the head node */
.p3-card2 .tn[data-id="tera"] .tn-pill {
  font-weight: 600;
  border-color: #c79a36;
  opacity: 1;
  box-shadow: 0 0 18px rgba(199, 154, 54, 0.35);
}
.p3-card2 .tn[data-id="tera"] .tn-dot { background: #c79a36; }
.p3-card2 .tn--focus .tn-pill {
  border-color: #c79a36; font-weight: 600; opacity: 1;
  box-shadow: 0 0 16px rgba(199,154,54,0.4);
}
.p3-card2 .tn--focus .tn-dot { background: #c79a36; }
.p3-card2 .tn-toggle .tn-pill {
  border-style: dashed; opacity: 0.62;
  font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
}
.p3-card2 .tn-toggle:hover .tn-pill { opacity: 0.95; }

/* zoom controls, docked to the card */
.p3-card2 .tree-zoom {
  position: absolute;
  right: 0.9rem;
  bottom: 0.9rem;
  z-index: 5;
  display: none;
  flex-direction: column;
  border: 1px solid var(--surface-border);
  border-radius: 999px;
  overflow: hidden;
  box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.p3-card2 .tree-zoom button {
  width: 2.3rem; height: 2.3rem;
  border: none; border-bottom: 1px solid var(--surface-border);
  background: var(--surface); color: inherit;
  font-size: 1.1rem; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.12s;
}
.p3-card2 .tree-zoom button:last-child { border-bottom: none; }
.p3-card2 .tree-zoom button:hover { background: color-mix(in srgb, currentColor 14%, var(--surface)); }

/* ── entrance: card1 from left, text from right, card2 from bottom (together) ── */
.p3-card1, .p3-text, .p3-card2 {
  min-width: 0;
  min-height: 0;
  opacity: 0;
  will-change: transform, opacity;
  transition: transform 1.2s cubic-bezier(0.16, 1, 0.3, 1) 0.35s,
              opacity 0.9s ease-in-out 0.35s;
}
.p3-card1 { transform: translate(-120%, clamp(0rem, 20.457rem - 52.28vw, 10rem)); }
.p3-text  { transform: translateX(120%); }
.p3-card2 { transform: translateY(120%); }
body.to-page3 .p3-card1 {
  transform: translateY(clamp(0rem, 20.457rem - 52.28vw, 10rem));
  opacity: 1;
}

@media (min-width: 1100px) {
  /* Fluidly scale card1 up to 2x on large desktop screens, settling back to 1x at 1100px */
  .p3-card1 { 
    transform: translate(-120%, clamp(0rem, 20.457rem - 52.28vw, 10rem)) scale(var(--card1-scale, 1)); 
  }
  body.to-page3 .p3-card1 {
    transform: translateY(clamp(0rem, 20.457rem - 52.28vw, 10rem)) scale(var(--card1-scale, 1));
  }
  
  /* Align text block near the top to balance the larger card1 */
  .p3-text {
    margin-top: 3rem;
    margin-left: 1rem;
  }
}
body.to-page3 .p3-text {
  transform: none;
  opacity: 1;
}
body.to-page3 .p3-card2 {
  transform: translateY(clamp(0rem, 18.457rem - 52.28vw, 8rem));
  opacity: 1;
}

/* ── the arrow: icon in card1 → Terah in card2 ── */
.p3-arrow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 40;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.p3-arrow--on { opacity: 1; }
.p3-arrow__line, .p3-arrow__head {
  stroke: #c79a36;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 6px rgba(199, 154, 54, 0.45));
}
/* draw-in: the line reveals itself, then the head fades in */
.p3-arrow__head { opacity: 0; transition: opacity 0.25s ease; }
.p3-arrow--head .p3-arrow__head { opacity: 1; }

/* ── person modal (ported) ── */
.p3-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.82);
  z-index: 22000;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s;
}
.p3-modal-overlay.show { opacity: 1; pointer-events: auto; }
.p3-modal-card {
  position: relative;
  display: flex;
  width: min(680px, 92vw);
  max-height: 90vh;
  background: #0a0a0a;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  overflow: hidden;
  color: #f3ecdd;
}
.p3-modal-portrait { width: 240px; flex-shrink: 0; overflow: hidden; background: #0e0c0a; }
.p3-modal-portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
.p3-modal-body {
  flex: 1;
  padding: 2rem 1.8rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.5rem;
}
.p3-modal-name {
  font-family: "Playfair Display", serif;
  font-size: 2.2rem;
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1.05;
  margin-bottom: 0.15rem;
}
.p3-modal-sub {
  font-family: "Playfair Display", serif;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: inherit;
  opacity: 0.5;
}
.p3-modal-text {
  font-family: "Playfair Display", serif;
  font-size: 1.05rem;
  line-height: 1.7;
  opacity: 0.85;
  margin-top: 0.8rem;
}
.p3-modal-close {
  position: absolute; top: 0.8rem; right: 1rem;
  background: none; border: none; color: inherit;
  opacity: 0.45; font-size: 1.2rem; line-height: 1; cursor: pointer;
  transition: opacity 0.15s;
}
.p3-modal-close:hover { opacity: 0.9; }
@media (max-width: 560px) {
  .p3-modal-card { flex-direction: column; }
  .p3-modal-portrait { width: 100%; height: 200px; }
}



@media (prefers-reduced-motion: reduce) {
  .p3-card1, .p3-text, .p3-card2 {
    transition: opacity 0.3s ease;
    transform: none;
  }
  .p3-arrow { transition: none; }
}

/* Page 2 exits by continuing its entrance movement to reveal Page 3 */
body.to-page3 .page2-col {
  transition: transform 0.8s ease-in-out, opacity 0.5s ease-in-out;
}

body.to-page3 .page2-col:nth-child(1) { transform: translateY(-100vh); opacity: 0; }
body.to-page3 .page2-col:nth-child(2) { transform: translateY(100vh); opacity: 0; }
body.to-page3 .page2-col:nth-child(3) { transform: translateY(-100vh); opacity: 0; }

@media (max-width: 1024px) and (orientation: portrait) {
  body.to-page3 .page2-col:nth-child(1) { transform: translateX(100vw); opacity: 0; }
  body.to-page3 .page2-col:nth-child(2) { transform: translateX(-100vw); opacity: 0; }
  body.to-page3 .page2-col:nth-child(3) { transform: translateX(100vw); opacity: 0; }
  .p3-card2 .tree-scroll { overflow: hidden; }
}

/* Page 2 scroll cue behavior */
#scroll-cue-2 {
  z-index: 21000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.7s ease-in-out 0s, transform 0.7s ease-in-out 0s;
}

body.to-page2:not(.to-page3) #scroll-cue-2 {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.7s ease-in-out 1.2s, transform 0.7s ease-in-out 0s; /* delay only opacity */
}

body.to-page3 #scroll-cue-2 {
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(40px) scale(0.7);
  transition: opacity 0.5s ease-in, transform 0.5s ease-in;
}

/* Tree Expansion Animation */
.tree-canvas .tn {
  opacity: 0; 
  transform: translate(-50%, -50%);
}
.tree-canvas svg path,
.tree-canvas svg line,
.tree-canvas svg polygon {
  opacity: 0;
}

.tree-canvas.tree-revealing .tn {
  animation: treeNodeReveal 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
  animation-delay: var(--delay, 0ms);
}

.tree-canvas.tree-revealing svg path,
.tree-canvas.tree-revealing svg line,
.tree-canvas.tree-revealing svg polygon {
  animation: treeEdgeReveal 0.5s ease-out both;
  animation-delay: var(--delay, 0ms);
}

@keyframes treeNodeReveal {
  0% { transform: translate(-50%, -50%) scale(0.4); opacity: 0; }
  100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}

@keyframes treeEdgeReveal {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

@media (max-width: 400px), (max-height: 700px) {
  .p3-card2 .tree-sizer,
  .p3-card2 .tree-canvas {
    width: 1400px;
    height: 1500px;
  }
  .p3-card2 .tn-pill {
    font-size: 1rem;
    padding: 0.34rem 0.72rem;
    gap: 0.4rem;
  }
  .p3-card2 .tn[data-b="root"] .tn-pill {
    font-size: 1.08rem;
  }
  .p3-card2 .tn-dot {
    width: 11px;
    height: 11px;
  }
}

@keyframes subtleBlink {
  0%, 40%, 100% { transform: scale(1); }
  10%, 30% { transform: scale(1.18); }
  20% { transform: scale(1); }
}
.blink-anim {
  animation: subtleBlink 5s cubic-bezier(0.2, 0, 0, 1) infinite !important;
}

/* ── page 4 transition (exit of page 3) ── */

body.to-page2 #scroll-cue-1 {
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(40px) scale(0.7);
  transition: opacity 0.5s ease-in, transform 0.5s ease-in;
}

body.to-page4 #scroll-cue-3 {
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(40px) scale(0.7);
  transition: opacity 0.5s ease-in, transform 0.5s ease-in;
}

body.to-page4 .p3-card1,
body.to-page4 .p3-text,
body.to-page4 .p3-card2 {
  transform: translateY(-50px) scale(0.98);
  opacity: 0;
  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease-in-out;
}

.tree-canvas.tree-unrevealing .tn {
  animation: treeNodeUnreveal 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
}
.tree-canvas.tree-unrevealing svg path,
.tree-canvas.tree-unrevealing svg line,
.tree-canvas.tree-unrevealing svg polygon {
  animation: treeEdgeUnreveal 0.3s ease-in both;
}

@keyframes treeNodeUnreveal {
  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(0.4); opacity: 0; }
}
@keyframes treeEdgeUnreveal {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

/* Page 3 scroll cue behavior */
#scroll-cue-3 {
  z-index: 22000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease-in-out 0s, transform 0.7s ease-in-out 0s;
}

body.to-page3:not(.to-page4) #scroll-cue-3 {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.4s ease-in-out 0.8s, transform 0.7s ease-in-out 0s;
}

/* ── page 4: ancient-context / info-box showcase ──────────────────────────── */
/* Sits ABOVE page 3 (whose bg is opaque black) and fades in when active. */
#page4 {
  position: fixed;
  inset: 0;
  background: #000;
  color: #f3ecdd;
  z-index: 16000;
  overflow: hidden;
  box-sizing: border-box;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.4s ease-in-out, visibility 0s linear 0.4s;
}
body.to-page4 #page4 {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.4s ease-in-out, visibility 0s;
}

/* Left 2/3 = three 1/3-height rows (b | text | c); right 1/3 = asyr image */
.p4-grid {
  position: absolute;
  inset: 0;
  height: 100vh;
  height: 100dvh;
  display: grid;
  grid-template-columns: 0.6fr 1fr 1fr 0.6fr;
  grid-template-rows: 2fr 3fr;
  gap: clamp(0.5rem, 1.2vw, 1rem);
  padding: 0 clamp(1rem, 2.5vw, 2.4rem);
  box-sizing: border-box;
}

.p4-asyr-left { grid-column: 1; grid-row: 1 / -1; display: flex; }
.p4-text { grid-column: 2 / 4; grid-row: 1; }
.p4-b    { grid-column: 2; grid-row: 2; }
.p4-c    { grid-column: 3; grid-row: 2; }
.p4-asyr { grid-column: 4; grid-row: 1 / -1; display: flex; }

/* rows b and c: single screenshot segment */
.p4-b,
.p4-c {
  display: flex;
  align-items: flex-start;
  min-height: 0;
  min-width: 0;
}
.p4-b { justify-content: flex-end; padding: 0 0 0 1.5rem; }
.p4-c { justify-content: flex-start; padding: 0 1.5rem 0 0; }

.p4-shot {
  position: relative;
  margin: 0;
  min-height: 0;
  min-width: 0;
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.p4-shot img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  border-radius: 6px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}


/* middle text card, centered in the left column */
.p4-text {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  text-align: center;
  padding: 0 clamp(1rem, 3vw, 3rem) 0.5rem clamp(1rem, 3vw, 3rem);
  min-height: 0;
}
.p4-text h2 {
  font-family: "Playfair Display", serif;
  font-size: clamp(1.4rem, 3vw, 3rem);
  font-weight: 700;
  margin: 0 0 1rem 0;
  color: #f3ecdd;
  letter-spacing: 0.01em;
  line-height: 1.05;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}
.p4-text p {
  font-family: "Playfair Display", serif;
  font-size: clamp(1rem, 1.25vw, 1.22rem);
  line-height: 1.65;
  color: rgba(243, 236, 221, 0.82);
  margin: 0;
  max-width: 46ch;
  text-align: justify;
  text-align-last: center;
}

/* side columns: asyr relief flanks, vertically centered */
.p4-asyr, .p4-asyr-left {
  margin: 0;
  min-height: 0;
  min-width: 0;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.p4-asyr {
  justify-content: flex-start;
  -webkit-mask-image: linear-gradient(to right, black 85%, transparent 100%);
  mask-image: linear-gradient(to right, black 85%, transparent 100%);
}

.p4-asyr-left {
  justify-content: flex-end;
  -webkit-mask-image: linear-gradient(to left, black 85%, transparent 100%);
  mask-image: linear-gradient(to left, black 85%, transparent 100%);
}

.p4-asyr img, .p4-asyr-left img {
  display: block;
  height: 60%;
  width: 100%;
  object-fit: cover;
}

.p4-asyr img {
  object-position: left center;
}

.p4-asyr-left img {
  object-position: left center;
  transform: scaleX(-1);
}

/* entrance: settle the four blocks in once page 4 is active */
.p4-b,
.p4-text,
.p4-c {
  opacity: 0;
  transform: translateY(100px);
  transition: opacity 1.5s ease-out, transform 1.8s cubic-bezier(0.25, 0.8, 0.25, 1);
}

.p4-asyr,
.p4-asyr-left {
  opacity: 0;
  transition: opacity 1.5s ease-out, transform 1.8s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.p4-asyr-left { transform: translateX(-80px); }
.p4-asyr { transform: translateX(80px); }
body.to-page4 .p4-b    { opacity: 1; transform: none; transition-delay: 0.15s; }
body.to-page4 .p4-text { opacity: 1; transform: none; transition-delay: 0.35s; }
body.to-page4 .p4-c    { opacity: 1; transform: none; transition-delay: 0.55s; }
body.to-page4 .p4-asyr { opacity: 1; transform: none; transition-delay: 0.25s; }
body.to-page4 .p4-asyr-left { opacity: 1; transform: none; transition-delay: 0.25s; }

.ib-card {
  background: var(--surface);
  max-width: 560px; width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding: 2rem 1.25rem; position: relative;
  overflow-y: auto;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.ib-card__head {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.6rem;
  margin-bottom: 1.2rem; padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--surface-border);
}
.ib-card__head-icon { font-size: 2rem; line-height: 1; }
.ib-card__head h3 { margin: 0; font-size: 0.95rem; font-weight: 600; color: inherit; opacity: 0.9; }
.ib-card__intro { font-size: 0.86rem; color: inherit; opacity: 0.7; line-height: 1.65; margin: 0 0 1.4rem; text-align: justify; }
.ib-entries { display: flex; flex-direction: column; gap: 1.1rem; }
.ib-entry { border-left: 2px solid var(--surface-border); padding-left: 1rem; }
.ib-entry__tag {
  font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase;
  color: inherit; opacity: 0.45; margin-bottom: 0.35rem;
}
.ib-entry p { margin: 0; font-size: 0.85rem; color: inherit; opacity: 0.62; line-height: 1.62; text-align: justify; }


@media (max-width: 1100px) {
  .p4-grid {
    grid-template-columns: 1fr 1fr;
  }
  .p4-text { grid-column: 1 / 3; }
  .p4-b { grid-column: 1; padding: 0; }
  .p4-c { grid-column: 2; padding: 0; }
  .ib-card { padding: 2rem clamp(1rem, 3vw, 3rem); }
  .p4-asyr, .p4-asyr-left {
    display: none;
  }
}

@media (max-width: 768px) {
  .p4-grid {
    grid-template-rows: auto auto;
    align-content: center;
    padding-top: 0;
  }
  .p4-text {
    align-self: center;
    transform: none;
    padding: 0 1.5rem 1.5rem 1.5rem; /* Restore normal bottom padding */
  }
  .ib-card {
    padding: 0.5rem 0.375rem; /* Reduce top/bottom padding to prevent scrollbars */
  }
  .ib-card__head {
    margin-bottom: 0.8rem;
    padding-bottom: 0.8rem;
  }
  .ib-card__intro {
    padding-left: 1.125rem;
  }
  .p4-c .ib-card__intro,
  .p4-c .ib-entries {
    padding-right: 1.125rem;
  }
}
