/* ============================================================
   SHOW PHOTOS — page-specific styles
   Loaded only by photos.html, so nothing here touches another page.
   ============================================================ */

/* ---- THE OPENER ----------------------------------------------------------

   Beth's brief (2026-10-08, second pass): model it on the About and Reels
   openers — same depth plane as the text, hard right, play with the gradient
   — but find something slightly its own.

   HOW THE THREE ARE BUILT, AND WHY THIS ONE IS NOT EITHER OF THEM:

     ABOUT   a --bone-2 field on the left, the photograph bleeding off the
             right, and a gradient laid OVER THE PICTURE that drags the
             field across its left edge until the seam disappears.
     REELS   no field colour at all. The photograph's own backdrop is
             sampled down the frame and run out sideways as the page's
             ground, so the picture has no edge because the page IS it.
     PHOTOS  BOTH, IN SEQUENCE, AND THE GRADIENT IS ON THE FIELD RATHER THAN
             ON THE PICTURE. Reading left to right the page goes
                 bone  →  the photograph's own backdrop  →  the photograph.
             The site's colour holds the words; it melts into the picture's
             colour; and the picture then emerges from its own backdrop with
             no seam at all, the way reels does. About melts the FIELD INTO
             THE PHOTO; this melts the PAGE INTO THE FIELD and leaves the
             photo's own edge to do the rest.

   THE WALL IS NOT AN INVENTED COLOUR — same rule as reels. It is this
   photograph's left-hand edge, sampled down the frame and stretched
   sideways, so at any height the field beside the picture is exactly the
   blue-grey the picture has at that height:

      0%  #93abc0     40%  #b2c2d2     80%  #a8b8c8
     10%  #a8b9cd     50%  #b1c1d1     90%  #a3b4c4
     20%  #acbdcf     60%  #afbfcf    100%  #9eafbf
     30%  #b0c0d0     70%  #acbccc

   Unlike the reels frame, her hair never reaches this one's left edge, so
   every stop above is sampled — none are extrapolated.

   THE STOPS MAP THE VISIBLE BAND, NOT THE FILE, AND THE BAND MOVES. `cover`
   crops the picture vertically, and how much it shows depends on the shape
   of the viewport, not just its size: 85% of the frame at 920x700, 70% at
   1280x800 and 1440x900, 63% at 1920x1080. One set of stops cannot match
   all three, so they are sampled across 0-72% — the MIDDLE of that range —
   which spreads the error to both ends instead of piling it at one.

   Measured worst-case mismatch at the join, over 99 heights: 12/255 at 1280
   and 1440, 14 at 920, 15 at 1920, always at the very foot where the band
   ends. A first pass sampled 0-78% and reached 21 at 1920. RE-SAMPLE IF THE
   PHOTO CHANGES, or its left edge becomes an edge again.

   NO SCRIM, BECAUSE THE WALL IS PALE. Full-strength ink reads 9-10:1 on the
   melt, so the headline, the nav and the wordmark all clear the floor
   untouched — compare the reels opener, whose mid-grey ground suited
   neither ink nor cream and needed two measured scrims.

   WHERE THE MELT STARTS IS SET BY WHERE THE TEXT ENDS (2026-10-08). Beth
   asked for the words to sit COMPLETELY on beige AND for the blend to get
   softer. Those pull against each other: the melt's entire budget is the gap
   between the end of the text and the picture's edge. Three things bought
   that gap — the lede wraps at 22em, the picture's column went 1.08fr to
   0.95fr (its edge 48% -> 51%), and the melt now holds full bone to 45%.
   Measured at 920, 1280, 1440 and 1920: the text ends at 42-44% with the
   bone at FULL strength under it at every one.

   AND THE TAIL RUNS PAST THE PICTURE'S EDGE (42% -> 58%, edge at 52.9%), which
   is what makes it gradual rather than merely smooth. That costs nothing,
   because a background layer sits BEHIND the <img>: past 51% the bone is
   only visible through the picture's own 7% fade, where it reads as the last
   of the beige letting go rather than as a wash over her. The two ramps
   cross-dissolve instead of meeting.

   LENGTH IS THE LEVER, and three things set it. Beth asked twice for more
   seamlessness, and each time the answer was a longer visible run, not a
   different curve — a smoothstep already has zero slope at both ends, so
   the only thing left to change is how far it is spread.

     the melt starts at 36%   — as early as the text allows. Beth shortened
                                the headline to "Show photos" on 2026-10-08
                                to buy part of this; the lede at 15em buys
                                the rest.
     the picture's edge 52.9% — column 1.08fr -> 0.95fr -> 0.89fr over three
                                rounds; the picture is still 47% of the
                                screen, which is no visible loss
     the mask carries to ~58% — 11% of the frame on any screen wider than
                                3:2, 7% on the narrow-tall case (see the
                                aspect-gated rule at the foot of this file)

   That is a visible transition of about 22% of the screen, against 17%, 14%,
   9% and 6% in the rounds before it.

   Measured along a row of pure backdrop, luminance falls
   240 -> 237 -> 220 -> 196 -> 186 across 40/44/48/52/56% and then RISES to
   189 at 58% — that last rise is the photograph's own backdrop brightening
   toward the middle of the frame, not a seam. Worst slope change through
   the melt: 0.66 at 1920, 0.69 at 1440, 0.84 at 1280, 1.17 at 920, out of
   255 — against 0.8-1.86 for the version before it.

   THE ONE THING THAT DID NOT SURVIVE IS --ink-soft. The lede's text runs out
   to 42-44% of the screen, which is into the melt, and the site's soft
   secondary ink is too light to live there: measured 3.96:1 at 1280 and
   3.63:1 at 1920, under the 4.5 floor. It is --ink on this page only (see
   the rule at the foot of this file). The melt's solid-bone zone was pushed
   from 20% to 30% at the same time, so less of the paragraph sits on it.

   Measure glyph boxes, not element boxes, if you re-check this. A block
   <p> spans its whole column even when its text does not, and measuring the
   box reported the eyebrow at 3.17:1 when the word "SHOW PHOTOS" actually
   ends at 14% of the screen, on solid bone, at 4.97:1. */

.photos-hero {
  /* the stage carries its own height, ground and insets */
  padding: 0;
}

.photos-hero__stage {
  position: relative;
  display: grid;
  gap: clamp(1.75rem, 4vw, 2.5rem);
  padding-top: calc(var(--header-h) + clamp(1.5rem, 5vw, 3rem));
  padding-bottom: clamp(2rem, 5vw, 3.5rem);
  padding-inline: var(--gutter);

  /* THE GROUND. Two layers, and the order matters: the bone wash is first,
     so it paints ON TOP of the sampled wall. */
  background-image:
    /* 1. the page's own colour, holding the words and then letting go
          before it reaches the picture. The stops follow a smoothstep curve
          rather than a straight ramp — see the note on the picture's mask
          below for why a linear fade draws a visible line. */
    linear-gradient(
      to right,
      var(--bone) 0%,
      var(--bone) 36%,
      rgba(245, 240, 232, 0.957) 39%,
      rgba(245, 240, 232, 0.844) 42%,
      rgba(245, 240, 232, 0.684) 45%,
      rgba(245, 240, 232, 0.5) 48%,
      rgba(245, 240, 232, 0.316) 51%,
      rgba(245, 240, 232, 0.156) 54%,
      rgba(245, 240, 232, 0.043) 57%,
      rgba(245, 240, 232, 0) 60%
    ),
    /* 2. the photograph's left edge, run down the page */
    linear-gradient(
      to bottom,
      #93abc0 0%,
      #a8b9cd 10%,
      #acbdcf 20%,
      #b0c0d0 30%,
      #b2c2d2 40%,
      #b1c1d1 50%,
      #afbfcf 60%,
      #acbccc 70%,
      #a8b8c8 80%,
      #a3b4c4 90%,
      #9eafbf 100%
    );
  /* what the wall stands on if the gradient is ever outrun */
  background-color: #a8b9cd;
}

/* PHONES AND TABLETS: words first, then the picture under them.

   The opposite of the contact opener, deliberately. A portrait at full phone
   width is taller than the screen, so leading with the picture buries the
   page title below the fold — round 54's bug on the reels page. The markup
   order IS the phone order, so it cannot regress. The bone wash is vertical
   here instead of horizontal, so the words still sit on the page's own
   colour and the picture still meets the wall. */
@media (max-width: 900px) {
  .photos-hero__stage {
    background-image:
      linear-gradient(
        to bottom,
        var(--bone) 0%,
        var(--bone) 26%,
        rgba(245, 240, 232, 0.957) 29.3%,
        rgba(245, 240, 232, 0.844) 32.5%,
        rgba(245, 240, 232, 0.684) 35.8%,
        rgba(245, 240, 232, 0.5) 39%,
        rgba(245, 240, 232, 0.316) 42.3%,
        rgba(245, 240, 232, 0.156) 45.5%,
        rgba(245, 240, 232, 0.043) 48.8%,
        rgba(245, 240, 232, 0) 52%
      ),
      linear-gradient(
        to bottom,
        #93abc0 0%,
        #adbed0 25%,
        #b0c0d0 50%,
        #a5b5c5 75%,
        #97a8ba 100%
      );
  }
}

/* PHONES ONLY (≤600): PLAIN BONE, NO WALL, NO MELT. Beth, 2026-10-27: "on the
   phone version the background is blue i want it to be the normal beige and
   on the phone version only i want no gradient" — "on the show photos page".
   The sampled blue-grey wall and the bone wash above it are both gone here;
   the words and the picture sit on the page's own colour like every other
   phone opener. The picture keeps its own hard edges (it never had a mask at
   this size). Tablets (601-900) keep the stacked wall and melt above. */
@media (max-width: 600px) {
  .photos-hero__stage {
    background-image: none;
    background-color: var(--bone);
    /* the words and the picture sit closer — one block, not two */
    gap: 1.25rem;
  }
}

/* PHONES ONLY (≤600): THE PICTURE IS THE BASE. Beth, 2026-11-08: "lets make
   the hero image the base and put show photos on the blue background." The
   photograph runs edge to edge, scaled a little past the screen and pinned
   top-left so the plain strip of backdrop above her head is tall enough to
   carry the one-line headline — ink and rosewood, which read on that
   blue-grey; cream would not. No intro line on phones; the photographer
   credit sits under the picture. The framed-and-captioned 4:5 version of round 118 lasted an
   hour; this replaces it. The stage is position: relative so the headline
   can be placed against the picture, which is the stage's first row. */
.photos-hero__caption {
  display: none;
}

@media (max-width: 600px) {
  .photos-hero__stage {
    position: relative;
    /* a hairline of bone between the header and the picture, nothing more;
       the band of backdrop colour that stood here briefly is gone (Beth,
       2026-11-08: "i liked it better before. you can move the image around
       to make room for the words show photos to be on the same plane") */
    padding-top: calc(var(--header-h) + 0.5rem);
    padding-inline: 0;
    gap: 0;
  }

  /* THE BACKDROP RUNS UP BEHIND THE NAME AND THE MENU. Beth, 2026-11-08:
     "expand the plain blue background seamlessly to extend up behind the
     name and hamburger icon." The header is see-through until the page
     scrolls, so whatever sits under it shows. A flat colour would not do:
     the top row of the photograph is a vignette (darker at both edges,
     lighter in the middle), and a solid fill meets it with a visible step.
     Instead this layer is the picture itself, same 112% width and same
     left pin as the <img>, stretched to 30,000% of its height so that only
     its top few rows fill the strip — every column simply continues its
     own colour upward, so the join is invisible. It overlaps the picture
     by a pixel to hide any rounding seam; the headline (z 2) sits above. */
  .photos-hero__stage::before {
    content: "";
    position: absolute;
    z-index: 1;
    inset: 0 0 auto 0;
    height: calc(var(--header-h) + 0.5rem + 1px);
    background: url("../../assets/img/photos-hero.jpg") left top / 112% 30000% no-repeat;
    pointer-events: none;
  }

  /* THE PICTURE, MOVED TO MAKE ROOM. Measured on the file: the top 5% of
     the frame is plain backdrop across its whole width, then her hair
     arrives from the right. A one-line headline needs ~200px of blue, so
     the picture is scaled to 112% of the screen's width and pinned top-left
     (the 12% that falls off the right edge is backdrop and the outer edge
     of her shoulder), which makes that top strip 5% of 636px = 32px tall
     at 375 wide — enough for the headline at 1.75rem. The figure clips it
     sideways, so nothing overflows the page. */
  .photos-hero__figure {
    order: -1;
    justify-self: stretch;
    max-width: none;
    margin: 0;
    /* clip only sideways (the 12% of picture past the right edge); the
       caption under the picture must stay visible, so no overflow: hidden */
    overflow-x: clip;
    overflow-y: visible;
  }

  .photos-hero__figure .photos-hero__img {
    display: block;
    width: 112%;
    max-width: none;
    height: auto;
    aspect-ratio: auto;
  }

  /* the headline, one line, on the blue strip above her head: ink and
     rosewood on #aec0d3 read at about 8:1 and 4.4:1 */
  .photos-hero__content h1 {
    position: absolute;
    z-index: 2;
    /* as low as it goes: 7px further down and the tail of "photos" would
       meet her hair, which arrives from the right at ~6% of the frame
       (Beth, 2026-11-08: "can it be pushed down anymore without overlapping
       with my hair") */
    top: calc(var(--header-h) + 0.5rem + 0.65rem);
    left: var(--gutter);
    margin: 0;
    font-size: 1.75rem;
    line-height: 1;
    text-align: left;
    white-space: nowrap;
  }

  /* no intro line on phones (Beth, 2026-11-08: "we also can do away with
     the description line"); the content box holds only the placed h1 */
  .photos-hero__content {
    padding: 0;
  }

  .photos-hero__content .lede {
    display: none;
  }

  .photos-hero__caption {
    display: block;
    margin: 0.6rem var(--gutter) 0;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    letter-spacing: 0.08em;
    color: var(--ink-soft);
    text-align: right;
  }

  .photos-hero__caption a {
    color: var(--rose);
    text-decoration: none;
  }
}

.photos-hero__figure {
  margin: 0;
  justify-self: center;
  /* Capped for the stacked layout, and the cap is about scrolling rather
     than taste: uncapped at 820 the picture ran 754px across, which on this
     frame's proportions is over 1100px tall, and the gallery began a screen
     and a half down. Phones sit under the cap already. */
  max-width: min(100%, 26rem);
}

.photos-hero__img {
  display: block;
  width: 100%;
  height: auto;
  /* Stated explicitly. An <img> with no aspect-ratio and no object-fit
     defaults to `fill` and squashes the moment it is sized in one direction
     and clamped in the other — the trap that flattened the contact photo in
     round 35. Stacked, the picture shows whole at its own proportions. */
  aspect-ratio: 1236 / 1872;
  object-fit: cover;
}

@media (min-width: 901px) {
  .photos-hero__stage {
    /* Words left, picture hard right and slightly the larger of the two. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.89fr);
    gap: 0;
    align-items: center;
    /* A definite height, NOT min-height: with min-height the row stays free
       to grow to the image's intrinsic height and the opener overshoots the
       viewport — the bug the About stage documents. 88svh sits deliberately
       between reels' 82 and About's 100, so the three openers do not even
       stand the same height. */
    height: 88svh;
    grid-template-rows: minmax(0, 1fr);
    overflow: hidden;
    /* the picture has to reach the top, bottom and right edges */
    padding: 0;
  }

  .photos-hero__content {
    grid-column: 1;
    grid-row: 1;
    /* the container's own inset, so the words line up with every other page */
    padding-left: max(var(--gutter), (100vw - var(--container)) / 2);
    padding-right: clamp(1.5rem, 4vw, 3rem);
  }

  .photos-hero__figure {
    grid-column: 2;
    grid-row: 1;
    /* SAME DEPTH PLANE AS THE TEXT. The picture is not a panel laid on the
       page any more — it fills its column top to bottom and runs off the
       right edge, exactly as About's and Reels' do. */
    justify-self: stretch;
    align-self: stretch;
    width: 100%;
    height: 100%;
    max-width: none;
  }

  .photos-hero__img {
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    /* TOP, not centre. `cover` here shows the top 63-85% of the frame
       depending on the viewport's shape; anchored to the top that keeps the
       air above her head and her whole face in shot, and it is the band the
       wall stops are sampled across. Move this and the stops move with it. */
    object-position: 50% 0%;

    /* THE LEFT EDGE DISSOLVES — this is the page's own idea, and it is what
       makes matching the wall exactly unnecessary.

       Reels dissolves its picture's TOP and FOOT into the sampled wall;
       About lays a gradient OVER its picture to drag the field across. This
       one fades the picture's LEFT EDGE into the wall behind it, so the two
       meet as a blend rather than a line.

       It earns its place: the band `cover` shows moves with the viewport's
       shape (85% of the frame at 920x700, 63% at 1920x1080), so one set of
       wall stops can never match the picture's edge at every size. Matched
       as closely as the stops allow, the worst mismatch was still 29/255 at
       920x700. Over a 5% fade — about 33px — a step that size stops being a
       step. The fade is spent on backdrop, never on her: in the leftmost 5%
       of this frame (61px) nothing warm appears until 96% of the way down,
       and the deepest band the opener ever shows is 85%.

       EASED, NOT LINEAR, AND WIDENED 5% -> 7% (2026-10-08). Beth: "the line
       gradient is a little harsh specifically on the left side of the
       image." She was seeing a Mach band — the eye finds the place where a
       gradient's SLOPE changes abruptly and draws a line there, even though
       the colours either side are continuous. A linear ramp kinks twice,
       once at each end. These stops follow a smoothstep (3t^2-2t^3), so the
       fade arrives and leaves at zero slope and there is nothing for the eye
       to catch. The same curve is on the bone melt above, which kinked the
       same way. 7% still lands entirely on backdrop: nothing warm enters the
       leftmost 7% of this frame at any height the opener shows.

       Both properties, and -webkit- first: Safari still needs the prefix. */
    -webkit-mask-image: linear-gradient(
      to right,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, 0.043) 0.9%,
      rgba(0, 0, 0, 0.156) 1.8%,
      rgba(0, 0, 0, 0.316) 2.6%,
      rgba(0, 0, 0, 0.5) 3.5%,
      rgba(0, 0, 0, 0.684) 4.4%,
      rgba(0, 0, 0, 0.844) 5.3%,
      rgba(0, 0, 0, 0.957) 6.1%,
      rgba(0, 0, 0, 1) 7%
    );
    mask-image: linear-gradient(
      to right,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, 0.043) 0.9%,
      rgba(0, 0, 0, 0.156) 1.8%,
      rgba(0, 0, 0, 0.316) 2.6%,
      rgba(0, 0, 0, 0.5) 3.5%,
      rgba(0, 0, 0, 0.684) 4.4%,
      rgba(0, 0, 0, 0.844) 5.3%,
      rgba(0, 0, 0, 0.957) 6.1%,
      rgba(0, 0, 0, 1) 7%
    );
  }
}

/* --ink, not --ink-soft, and only on this page. The site's secondary ink is
   right on flat bone (5.4:1) but cannot survive this opener's melt, where
   the ground darkens toward the photograph's blue-grey: measured 3.96:1 at
   1280 and 3.63:1 at 1920 against a 4.5 floor. Full ink reads over 7:1 on
   the same ground. The size and measure still carry the hierarchy. */
.photos-hero__content .lede {
  color: var(--ink);
}

/* The lede wraps narrower here than the site default, and that is what buys
   the melt its length. Beth asked for the words to sit COMPLETELY on beige
   AND for the blend to be gradual, and those pull against each other: the
   melt's whole budget is the gap between where the text ends and where the
   picture starts. At the site's usual measure the paragraph ran to 44% of
   the screen against a picture edge at 48% — 4% of room, which is a ramp
   steep enough to read as the hard line she asked to lose.

   15em. With the headline shortened AND the lede at 15em the two are now
   level — the furthest text is the HEADLINE again at 28-35%, the lede at
   26-33%. The melt starts at 36%. Widen either and the melt's start has to
   move right with it, which is the whole budget. */
.photos-hero__content .lede {
  max-width: 15em;
}

/* ---- A WIDER EDGE FADE WHERE THE VIEWPORT'S SHAPE ALLOWS IT ----

   The 7% cap above is set by one awkward case, not by the common one. How
   much of the frame `cover` shows depends on the viewport's SHAPE, not its
   size: band = 1.234 x height / width. A tall, narrow desktop window
   (1100x1000, say) shows the whole frame, and an 11% fade would then reach
   her hair, which first appears in the leftmost 11% at 87% of the way down.

   Wider than 3:2 the band can never exceed 82%, so an 11% fade stays on
   backdrop with five points to spare. That covers essentially every real
   desktop screen — 1280x800 and 1440x900 are 1.6, 1920x1080 is 1.78 — while
   the narrow-tall case quietly keeps the 7% version above.

   THE ASPECT QUERY IS DOING REAL WORK; do not simplify it to a width query,
   which would let 1100x1000 through. */
@media (min-width: 901px) and (min-aspect-ratio: 3 / 2) {
  .photos-hero__img {
    -webkit-mask-image: linear-gradient(
        to right,
        rgba(0, 0, 0, 0) 0%,
        rgba(0, 0, 0, 0.043) 1.4%,
        rgba(0, 0, 0, 0.156) 2.8%,
        rgba(0, 0, 0, 0.316) 4.1%,
        rgba(0, 0, 0, 0.5) 5.5%,
        rgba(0, 0, 0, 0.684) 6.9%,
        rgba(0, 0, 0, 0.844) 8.3%,
        rgba(0, 0, 0, 0.957) 9.6%,
        rgba(0, 0, 0, 1) 11%
      );
    mask-image: linear-gradient(
        to right,
        rgba(0, 0, 0, 0) 0%,
        rgba(0, 0, 0, 0.043) 1.4%,
        rgba(0, 0, 0, 0.156) 2.8%,
        rgba(0, 0, 0, 0.316) 4.1%,
        rgba(0, 0, 0, 0.5) 5.5%,
        rgba(0, 0, 0, 0.684) 6.9%,
        rgba(0, 0, 0, 0.844) 8.3%,
        rgba(0, 0, 0, 0.957) 9.6%,
        rgba(0, 0, 0, 1) 11%
      );
  }
}
