/* ══ the showcase chapter ═══════════════════════════════════════════════════
   Five sections from the Wabi 2.0 app-store frames. One statement, then the
   thing, and nothing else on the row.

   The ground is #f9f9f9 and that is load-bearing, not a mood: four of the five
   plates are the Figma frame cropped, so the frame's own #f9f9f9 fill is baked
   into their corners and their surround. A chapter on the page's #f0f0f0 would
   show every plate as a paler rectangle with a visible edge. Matched, the
   devices simply stand on the page. */
/* ⚠ NO GROUND OF ITS OWN. This painted #f9f9f9, which is what put a hard edge across
   the page where the white hero ended and the chapter began — the "hard cut" is not
   the hero's fault, it is a second element painting its own colour underneath it. The
   page carries one long white-to-paper gradient (see .page in css/app.css) and this
   chapter simply sits on it; the plates are white with their own shadows, which is
   what defines a block anyway. */
.show { background:transparent; }

.show .sec {
  padding-block:clamp(96px, 12vh, 168px) 0;
  /* the artwork runs off the bottom of its own plate, so nothing may spill
     sideways out of the section */
  overflow:hidden;
}
.show .sec:first-child { padding-top:clamp(112px, 14vh, 190px); }
.show .sec:last-child { padding-bottom:clamp(96px, 12vh, 160px); }

/* the headline is the page's own h2 — same size, same tracking, same effect as
   every other section here. Only the copy and the two-line break are Figma's. */
.show .fxwrap {
  display:flex; justify-content:center; align-self:stretch; width:100%;
}
.show .sec h2.line { text-align:center; }

/* ── the plate ─────────────────────────────────────────────────────────────
   1290 × 2382 of Figma, at whatever width the page gives it. `--u` is one fig
   px, so every length in the built composition is the Figma number times a unit
   and the whole thing scales without a scale transform — which matters, because
   a transform would break the `mix-blend-mode` inside the send buttons and
   would report a rotated photograph's box as its axis-aligned bounds. */
.plate {
  position:relative;
  /* ⚠ THE PLATE'S OWN WIDTH IS A VARIABLE, and it has to be, because the inset
     is a fraction of it. Written as `padding:7% 8%`, the percentages resolve
     against the CONTAINING BLOCK's width — 1440 in a full-width section, not the
     plate's 520 — so the padding came out 101px/115px instead of 36/42 and the
     artwork was squeezed to 290px inside a 520px plate. A container cannot query
     itself for its own padding either (that is circular), so the width is named
     once and the inset is arithmetic on it. */
  --pw:min(520px, 84vw);
  width:var(--pw);
  margin:clamp(46px, 5.5vh, 78px) auto 0;
  /* ⚠ 1290:2200, not the crop's own 1290:2382 — the artwork is INSET now, so the
     plate has to be a little taller than the picture to leave air under it. At
     8% each side the image is 84% wide and 155.1% of the plate's width tall; 7%
     above it and 8% below comes to 170.1%, which is this ratio. Get it wrong and
     the plate either crops the foot again or grows a white band. */
  aspect-ratio:1290 / 2200;
  overflow:hidden;
  /* the artwork is inset by PADDING and flows — see the note below */
  --pad-y:0.07; --pad-x:0.08;
  padding:calc(var(--pw) * var(--pad-y)) calc(var(--pw) * var(--pad-x)) 0;
  /* ⚠ EVERY COMPOSITION HERE IS CROPPED BY ITS FIGMA FRAME, on all four sides,
     and there is no uncut version to fetch: a frame clips its children, and a
     NODE export is clipped by that frame too — the phone in §2 exports 1798px
     tall, which is exactly the 1769 the frame leaves it. The pixels outside do
     not exist. So the crop is made to read as DELIBERATE rather than as the page
     slicing something: the artwork sits inside a rounded plate with air round it.
     A composition in a card is a picture; the same composition flush to the page
     edge is a mistake. */
  border-radius:clamp(20px, 2.2vw, 30px);
  /* ⚠ WHITE, and the ARTWORK had to come with it. The four plate images carry
     #f9f9f9 as their own ground — measured, 249 at every corner — so a white plate
     left each composition sitting on a visibly darker rectangle. The images are
     re-encoded through a piecewise top-end curve (234..245 -> 234..255) which lifts
     the ground and the tones touching it and leaves everything below 234 exactly
     where it was, so no photograph in them shifts. */
  background:#fff;
  box-shadow:
    inset 0 0 0 1px rgba(25, 25, 25, .05),
    0 42px 64px -26px rgba(25, 25, 25, .10),
    0 4px 12px -4px rgba(25, 25, 25, .045);
}
/* ⚠ STATIC, not absolute. A replaced element does not resolve an `auto` width
   against its insets, and an absolute one ignored a stated `top` here — in the
   flow, padding is the inset and it cannot go wrong. */
.plate > img.pl {
  position:static;
  display:block;
  width:100%; height:auto;
}
/* ⚠ The stage is absolute — padding does NOT move an absolutely-positioned
   child, whose containing block is the padding box — so it states its own box,
   matching the padding above. */
.plate > .stage {
  position:absolute;
  /* percentages on an ABSOLUTE child do resolve against the plate's own box, so
     these are correct as written — they mirror the padding above */
  left:calc(var(--pad-x) * 100%); top:calc(var(--pw) * var(--pad-y));
  right:auto; bottom:auto;
  width:calc(100% - var(--pad-x) * 200%); height:auto;
  container-type:inline-size;
  --u:calc(100cqw / 1290);
}

/* the way in: the plate rises under its own headline */
.plate { opacity:0; transform:translateY(26px); transition:opacity .8s var(--ease), transform .9s var(--pop); }
.sec.in .plate { opacity:1; transform:none; }
@media (prefers-reduced-motion:reduce) {
  .plate { opacity:1; transform:none; transition:none; }
}

/* ── the built plate: photographs ─────────────────────────────────────────
   Placed by CENTRE, because Figma rotates a frame about its centre. The shadow
   is the file's: 0 50px 100px rgba(0,0,0,.1) at 1290 wide. */
.plate .ps {
  position:absolute;
  overflow:hidden;
  box-shadow:0 calc(var(--u) * 50) calc(var(--u) * 100) rgba(0, 0, 0, .1);
  background:#e9e8e6;             /* while the photograph decodes */
}
.plate .ps > img {
  position:absolute;
  display:block;
  max-width:none;                 /* these are sized past 100% on purpose */
  object-fit:cover;
}

/* ── the built plate: prompt cards ────────────────────────────────────────
   The card is 70% white with NO backdrop blur — the file has none, and the
   photograph really does read through it unblurred. What gives it its edge is
   the pair of inset shadows: dark from the bottom-right at .2, a whisper from
   the top-left at .03. */
.plate .pc { position:absolute; }
.plate .pc-body {
  position:absolute;
  overflow:hidden;
  background:rgba(255, 255, 255, .7);
  box-shadow:
    0 calc(var(--u) * 25.038) calc(var(--u) * 37.557) rgba(0, 0, 0, .07),
    inset calc(var(--u) * -3.298) calc(var(--u) * -3.298) calc(var(--u) * 3.298) rgba(0, 0, 0, .2),
    inset calc(var(--u) * 3.298) calc(var(--u) * 3.298) calc(var(--u) * 3.298) rgba(0, 0, 0, .03);
}
.plate .pc-text {
  position:absolute;
  margin:0;
  font-family:var(--face);
  font-weight:400;
  font-size:calc(var(--u) * 53.472);
  line-height:1.2;
  letter-spacing:-.01em;          /* -0.5347px of 53.472 */
  color:#000;
  font-feature-settings:"dlig" 1;
  /* the file trims the line box to the cap band, which is what puts the first
     line's CAP exactly 71.3 below the card's top edge rather than its ascent */
  text-box:trim-both cap alphabetic;
}
.plate .pc-plus { position:absolute; display:block; }

.plate .pc-btn {
  position:absolute;
  border-radius:50%;
  background:#292929;
  /* the ring's own shadow stack, from the file */
  box-shadow:
    0 calc(var(--u) * 30.645) calc(var(--u) * 18.606) rgba(0, 0, 0, .04),
    0 calc(var(--u) * 14.228) calc(var(--u) * 14.228) rgba(0, 0, 0, .07),
    0 calc(var(--u) * 3.283) calc(var(--u) * 7.661) rgba(0, 0, 0, .08),
    inset 0 calc(var(--u) * 8.756) calc(var(--u) * 6.567) rgba(0, 0, 0, .02);
  /* ⚠ The orb inside is screen-blended and its backdrop must be THIS button's
     dark fill. Without isolation the blend reaches past the button to whatever
     is under the card — the photograph — and the orb turns up as a bright smear
     that moves when the artwork does. */
  isolation:isolate;
}
.plate .pc-arw {
  position:absolute; left:50%; top:50%;
  display:block;
  /* the file draws the glyph flipped: the exported arrow points DOWN */
  transform:translate(-50%, -50%) scaleY(-1);
}
.plate .pc-ring, .plate .pc-ring2 {
  position:absolute;
  border-radius:50%;
  border-style:solid;
}
.plate .pc-ring { inset:0; border-color:#fff; }
.plate .pc-ring2 { border-color:#dcdcdc; }
.plate .pc-orb {
  position:absolute;
  border-radius:50%;
  overflow:hidden;
}
.plate .pc-orb > img {
  position:absolute;
  display:block;
  max-width:none;
  opacity:.32;
  mix-blend-mode:screen;
}

/* ── narrow ───────────────────────────────────────────────────────────────
   Nothing changes but the plate's width, which is what makes a phone and a desk
   the same composition: every length inside is a share of it. */
@media (max-width:640px) {
  .plate { --pw:min(400px, 88vw); }
}

/* ══ THE CHAPTER HAS THREE LAYOUTS ══════════════════════════════════════════
   One DOM, styled three ways. The plates are the heavy part of this page and the
   Line engine collects every headline once at boot, so a layout that rebuilt the
   chapter would either re-fetch the artwork or hand the engine headlines it has
   never seen. `data-layout` on <html> is the whole switch.

   The DOM is, per section: a `.wrap` holding the headline, then the `.plate`.
   Stack reads it top to bottom, Side turns it into two columns, and Blocks turns
   the rail into a scroller and reverses the column so the artwork leads. */

/* ── Side by side ──────────────────────────────────────────────────────────
   The headline beside its design rather than over it, and the sides ALTERNATE —
   five rows with the artwork on the same side is a list, and the alternation is
   what makes it read as a conversation between the copy and the thing. */
@media (min-width:900px) {
  html[data-layout="side"] .show .sec {
    display:grid;
    grid-template-columns:minmax(0, 1fr) minmax(0, 1fr);
    align-items:center;
    column-gap:clamp(40px, 6vw, 110px);
    max-width:var(--wide);
    margin-inline:auto;
    padding-inline:var(--gut);
    padding-block:clamp(72px, 9vh, 130px) 0;
  }
  /* the copy cell is the headline's own wrap, with the page gutter taken off it
     — the row carries the gutter now, and two of them is an inset column */
  html[data-layout="side"] .show .sec > .wrap {
    max-width:none; padding-inline:0; margin-inline:0;
    grid-column:1; grid-row:1;
  }
  html[data-layout="side"] .show .sec > .plate {
    grid-column:2; grid-row:1;
    margin:0;
    --pw:min(430px, 40vw);
    width:var(--pw);
    justify-self:center;
  }
  /* ⚠ EVEN rows swap, not odd: `create` is first and it keeps the artwork on the
     right, so the alternation starts on the second row. `:nth-child` counts
     inside .show-rail, which holds nothing but sections. */
  html[data-layout="side"] .show .sec:nth-child(even) > .wrap { grid-column:2; }
  html[data-layout="side"] .show .sec:nth-child(even) > .plate { grid-column:1; }

  html[data-layout="side"] .show .fxwrap { justify-content:flex-start; }
  html[data-layout="side"] .show .sec h2.line {
    text-align:left;
    font-size:clamp(34px, 4.6vw, 66px);
  }
}

/* ── Blocks ────────────────────────────────────────────────────────────────
   All five in ONE section: a sideways rail of big blocks, the artwork leading and
   its line under it. The rail deliberately runs off the right edge — that is what
   says there is more of it than fits, and it is the same argument the wall makes
   two sections later. */
html[data-layout="blocks"] .show {
  /* ⚠ THE GROUND DOES NOT MOVE, and an earlier version had it move. A block's
     fill has to be #f9f9f9, because that is what is baked into the plates' own
     corners — so the first answer was to put the chapter on the page's paper so
     the blocks would read against it. But the hero is #f9f9f9 too, and that left
     a visible seam across the top of the chapter in this layout and no other.
     The block is defined by its SHADOW and a hairline instead, which is what a
     card on the same paper is defined by anyway. */
  /* ⚠ +60px at the FOOT only: the captions sit under the blocks and the dark wall
     section starts straight after them, so the air below the chapter has to carry
     both the end of this section and the start of that one. */
  /* ⚠ +50px at the head and +60 at the foot, on top of the clamp — the section grows
     with them rather than absorbing them, so the phones above and the wall below each
     get their own air. */
  padding-block:calc(clamp(96px, 12vh, 168px) + 50px) calc(clamp(96px, 12vh, 168px) + 60px);
}
html[data-layout="blocks"] .show-rail {
  display:flex;
  align-items:flex-start;
  gap:clamp(18px, 2.2vw, 34px);
  overflow-x:auto;
  overflow-y:hidden;
  scroll-snap-type:x proximity;
  /* the first block lines up with the page's own gutter; the last one is allowed
     to end past the edge, which is the point of a rail */
  /* ⚠ The rail starts well in from the edge — at the page gutter it began almost
     flush with the window and the first block read as cropped rather than as the
     first of a row. And the bottom padding is what the blocks' own shadows fall
     into; without it they are sheared at the scroller's edge. */
  /* ⚠ The LEFT is its own number, not the same clamp on both sides. The rail's
     right-hand padding only has to let the last block's shadow finish; the left is
     where the row STARTS, and it is what decides how many blocks a screen shows —
     asked for two and a half, so the first block begins 100px further in than the
     page's gutter. `scroll-padding-left` has to carry the same number or a snap
     puts the first block back against the edge the padding just moved it off. */
  padding:14px clamp(28px, 6vw, 108px) 146px;
  padding-left:calc(clamp(28px, 6vw, 108px) + 100px);
  scroll-padding-left:calc(clamp(28px, 6vw, 108px) + 100px);
  /* the scrollbar is the browser's answer to a question the rail already answers
     by running off the edge */
  scrollbar-width:none;
  -ms-overflow-style:none;
  cursor:grab;
}
html[data-layout="blocks"] .show-rail::-webkit-scrollbar { display:none; }
html[data-layout="blocks"] .show-rail:active { cursor:grabbing; }

html[data-layout="blocks"] .show .sec {
  /* ⚠ column-REVERSE, not a reordered DOM: the artwork leads in this layout and
     the headline follows it, and the DOM order is the one the other two layouts
     want. One order, two readings. */
  display:flex; flex-direction:column-reverse; align-items:stretch;
  flex:0 0 auto;
  --pw:min(539px, 86vw);
  width:var(--pw);
  padding:0;
  overflow:visible;
  scroll-snap-align:start;
}
html[data-layout="blocks"] .show .sec > .wrap {
  max-width:none; padding-inline:0; margin:clamp(20px, 2.4vw, 30px) 0 0;
}
html[data-layout="blocks"] .show .fxwrap { justify-content:flex-start; }
html[data-layout="blocks"] .show .sec h2.line {
  text-align:left;
  /* ⚠ 20% down on 21/1.9vw/29 — every term, so the whole clamp scales rather than
     only its ceiling: leaving the middle term alone would keep the old size at every
     width where the vw term was already binding. */
  /* ⚠ ×1.35 IN EVERY TERM. The captions used to be multiplied by the headline
     slider, so this clamp was the size at scale 1.00 and what anybody actually
     saw was 1.35× it under preset 3. fitLine() no longer scales anything inside
     .show, so the number here has to BE the size — which is the one that was
     approved, i.e. the old clamp times 1.35. */
  font-size:clamp(23px, 2.05vw, 31px);
  line-height:1.08;
  letter-spacing:-.024em;
}
html[data-layout="blocks"] .show .sec > .plate {
  --pw:min(539px, 86vw);
  width:100%;
  margin:0;
  /* ⚠ LESS TALL, and the artwork INSET. At the frame's own 1290:2382 a block is
     nearly twice as tall as it is wide and five of them make a wall; and with the
     artwork bled to the block's edges there is nothing of the block left to see.
     Shorter box, artwork held off all three visible sides, and the foot of the
     composition cropped by the block — which is what the block is for. */
  /* 25% larger and wider again: at 1290:1760 five of these were still a wall of
     portraits, and a block is a picture of a screen rather than the screen */
  aspect-ratio:1290 / 1470;
  border-radius:clamp(20px, 2.2vw, 28px);
  /* ⚠ WHITE, and the ARTWORK had to come with it. The four plate images carry
     #f9f9f9 as their own ground — measured, 249 at every corner — so a white plate
     left each composition sitting on a visibly darker rectangle. The images are
     re-encoded through a piecewise top-end curve (234..245 -> 234..255) which lifts
     the ground and the tones touching it and leaves everything below 234 exactly
     where it was, so no photograph in them shifts. */
  background:#fff;
  /* subtler, and further down: the block sits ON the paper rather than hovering
     over it, so the shadow is a long soft one below and almost nothing around */
  box-shadow:
    inset 0 0 0 1px rgba(25, 25, 25, .05),
    0 42px 64px -26px rgba(25, 25, 25, .10),
    0 4px 12px -4px rgba(25, 25, 25, .045);
  /* a block is a card and its content is cropped by the card, not faded out of
     it — the radius is the crop, and a fade inside a rounded card reads as the
     card being unfinished */
  -webkit-mask-image:none;
  mask-image:none;
}
/* ⚠ THE ARTWORK IS INSET BY PADDING AND A STATIC IMAGE, not by insets on an
   absolute one. Two goes at the absolute version failed differently and both
   read as "the blocks are empty":
     · `inset:7.5% 8.5% auto; width:auto` — a replaced element does not resolve
       `auto` width against its insets, so every plate laid out at its own
       1290 × 2382 inside a 392px block and the clip showed the frame's blank
       top-left corner.
     · then with the width STATED, the computed `top` was right (40.11px) and the
       image's rect top still came back equal to the PLATE's — the offset simply
       did not land.
   In the flow it cannot go wrong: padding is the inset, the image is the content,
   and the block's own overflow crops the foot — which is what the block is for. */
html[data-layout="blocks"] .show .sec > .plate {
  /* more air inside the block than round it — the artwork is a picture hung on
     the block, and the margin is what makes it one */
  --pad-y:0.11; --pad-x:0.12;
}

/* ⚠ The stage is absolute and padding does NOT move an absolutely-positioned
   child — its containing block is the padding box — so it states its own box. */

/* ⚠ THE BLOCKS ARRIVE ONE BY ONE. They used to be forced to `transition-delay:0ms`
   — "they arrive together, because they are one section" — and together is what five
   plates entering at the same instant looks like: one lump. The stagger is written by
   the observer in js/app.js, which cascades everything entering in the same batch at
   130ms apiece (the creator-program site's own number), so this rule only has to get
   out of the way. The caption follows its own plate by a beat, which is what makes a
   block read as a picture and then its words. */
html[data-layout="blocks"] .show .sec .plate { transition-timing-function:var(--ease-golden); }
.show .sec .plate { transition-duration:.9s, .9s; }
/* ⚠ THE DELAY COMES OFF THE SECTION, so one variable moves the plate and its caption
   together and the two cannot drift apart. The caption is one beat behind its own
   plate — 120ms, about an eighth of the transition — which is what makes a block read
   as a picture and then its words rather than as one object with type on it. */
.show .sec .plate { transition-delay:var(--rise-delay, 0ms); }
.show .sec .copy-in { transition-delay:calc(var(--rise-delay, 0ms) + 120ms); }

@media (max-width:640px) {
  html[data-layout="blocks"] .show .sec,
  html[data-layout="blocks"] .show .sec > .plate { --pw:min(330px, 84vw); }
  html[data-layout="blocks"] .show .sec { width:var(--pw); }
  /* ⚠ ON A PHONE THE RAIL IS A CAROUSEL, and the padding is what makes it one.
     `scroll-snap-align:center` can only centre a card the scroller can actually
     scroll to the middle — with a 20px inset the first and last cards have nowhere
     to go, so they sit against the edges and only the middle ones snap. Half the
     viewport minus half a card either end, and every card locks into the middle,
     one swipe at a time; `mandatory` is what makes a flick settle on the NEXT card
     rather than sliding past two. The easing is the browser's own scroll-snap
     animation, which is smoother than anything a rAF loop does here. */
  html[data-layout="blocks"] .show-rail {
    padding-inline:calc((100vw - min(330px, 84vw)) / 2);
    scroll-snap-type:x mandatory;
    scroll-padding-inline:calc((100vw - min(330px, 84vw)) / 2);
  }
  html[data-layout="blocks"] .show .sec { scroll-snap-align:center; scroll-snap-stop:always; }
}
