/* ==========================================================================
   EC · Image Hero — block styles
   ==========================================================================
   v9b RESYNC. The block now emits the mockup's OWN hero class names rather than
   a consolidated `.image-hero--page` invention, because v9b ships two distinct
   banner shapes and pb-shell.css already names one of them: its .u-caps note
   lists `.edit-hero__text h1  -0.012em  (block sheet, 0,1,1)` — i.e. the shell
   expects THIS sheet to be where that selector lives.

   Sources (all v9b):
     - Page Banner  `.guide-hero.image-band`
         css/size-shape-guide.css §1 (~93-169) — the canonical recipe
         css/faq.css §2 (~48-93) — restated there verbatim; diffed, identical
     - Editorial Hero `.edit-hero`
         css/designers-edit.css §2 (~85-182)
     - `.ph > img` photography drop-in
         css/faq.css (~16-22) / css/designers-edit.css (~36-42), scoped here
     - Landing Banner `.shop-hero` / `.samples-hero`
         css/shop.css §1 (~88-193) and css/order-samples.css §1 (~30-142) — the
         same recipe under two class names; carried here ONCE, as a style on the
         Page Banner shape (§1b)
     - `.image-band` base + scrim
         css/shell.css (~1143-1165) — ALREADY in pb-shell.css, not restated

   Section-isolated per docs/DESIGN-SYNC rule 3. Consumes tokens from
   pb-tokens.css. Enqueued only when the block is present via block.json's
   file:./style.css.

   LOAD ORDER, and why several selectors carry a class the mockup does not
   write: pb-shell.css is enqueued AFTER block sheets here, the reverse of the
   mockup, so any block rule that TIES with a shell primitive on specificity
   silently loses. The Page Banner sits ON the shell `.image-band` primitive and
   overrides four of its declarations, so each of those rules is written at
   (0,2,0) with the `.image-band` class doubled in. Marked LOAD-BEARING below.
   ========================================================================== */

/* --- Real photography drop-in: an <img> inside a .ph reserved field fills it
   exactly, honouring the slot's aspect via object-fit (never distorts). Scoped
   to this block's two shapes — the theme ships no global `.ph > img` rule, so
   each block carries its own copy per section isolation (as pb_ec_cta_band and
   pb_ec_entry_tiles do). Without it the shell's `.ph { display: grid;
   place-items: center }` centres the photo at intrinsic size and clips it
   instead of covering the banner. pb-shell.css already suppresses the
   placeholder tick + caption once a .ph holds an <img>. --- */
.guide-hero .ph > img,
.edit-hero .ph > img,
.image-hero .ph > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ==========================================================================
   1. PAGE BANNER — `.guide-hero.image-band`
   faq.html and size-shape-guide.html. A short, wide photographic band with the
   H1 left-anchored on the site's main content column and centred vertically in
   the portion of the band visible BELOW the floating glass chrome.
   ========================================================================== */

/* --chrome-bottom grows the min-height back to the intended visible band, and
   the matching top padding seats the content (border-box) in the portion below
   the chrome, vertically centred there — the home hero's treatment.
   (0,2,0) — LOAD-BEARING. `min-height` and `align-items` both tie with the
   shell's `.image-band` at (0,1,0), which loads later; unprefixed (the mockup
   writes a bare `.guide-hero`) the shell would win and the band would keep its
   60vh height and bottom-aligned copy. */
.guide-hero.image-band {
  min-height: calc(clamp(260px, 23vw, 340px) + var(--chrome-bottom));
  align-items: center;
  padding-top: var(--chrome-bottom);
}
/* Pull the banner out of the shell `.image-band` framed-inset treatment: run it
   edge-to-edge with square corners (a full-width page banner the layout flows
   THROUGH, not a rounded feature frame). Already (0,2,0) in the mockup, and
   load-bearing for the same reason. */
.guide-hero.image-band {
  width: 100%;
  margin-inline: 0;
  border-radius: 0;
}
/* Text container back to the standard content column, left-aligned, so the H1's
   left edge sits on the site's main column. max-width must be set explicitly or
   it falls through to the shell's `.image-band__text { max-width: 44ch }`
   (~540px), which confines the H1 to a narrow centred column and wraps it. */
.guide-hero .image-band__text {
  max-width: var(--container-max);
  text-align: left;
  padding-block: var(--space-lg);
}
/* Now full-bleed, the overlaid copy takes the normal page gutter (not the
   tighter inner gutter the framed inset used) so the H1 aligns with the page
   content below. (0,3,0) over the shell's (0,2,0). */
.guide-hero .image-band__text.container { padding-inline: var(--gutter); }
/* The shell's folded [J] serif rule targets h2 + .hero__title + .cta-band__title,
   not this banner's h1, so the IvyPresto Display face and the hero-scale clamp
   are mirrored here. White over the scrimmed photo: the shell's base heading
   rule would otherwise render it dark and invisible over a light lifestyle
   shot. (0,1,1) clears that base `h1, h2, …` rule at (0,0,1). */
.guide-hero h1 {
  color: var(--white);
  font-family: var(--font-serif);
  font-weight: 400;
  font-style: normal;
  font-size: clamp(2.75rem, 1.4rem + 5.4vw, 5rem);
  line-height: 1.08;
  letter-spacing: -0.012em;
}
/* Scrim for a VERTICALLY CENTRED heading: a symmetric darken, heavier through
   the middle band where the glyphs sit, easing to near-clear at both edges so
   the photograph never over-darkens. Kept as light as AA-large (3.0) allows.
   Mockup's real-pixel probe, robust worst case (brightest-quartile mean under
   the glyph run): 1440 → 3.80:1 · 390 → 3.71:1. Both clear AA-large.
   (0,2,0) — LOAD-BEARING against the shell's `.image-band::before`, which is
   the bottom-weighted default and loads later. */
.guide-hero.image-band::before {
  background: linear-gradient(to bottom,
    rgba(35, 41, 44, 0.06) 0%,
    rgba(35, 41, 44, 0.34) 34%,
    rgba(35, 41, 44, 0.42) 50%,
    rgba(35, 41, 44, 0.34) 66%,
    rgba(35, 41, 44, 0.06) 100%);
}

/* ==========================================================================
   1b. LANDING BANNER — `.guide-hero.image-band.is-style-landing`
   shop.html and order-samples.html. THE PAGE BANNER OF §1 ON A TALLER BAND, and
   a style on that shape rather than a shape of its own because that is what the
   mockup is: css/order-samples.css §1 opens by saying its geometry "mirrors
   css/shop.css §1, which in turn mirrors css/faq.css §1", and diffing the three
   bears it out. Only two declarations differ from §1 across both pages, and both
   are here. Same argument, same shape, as §2b's Story Banner sits on §2.

   Sources (all v9b):
     - css/shop.css §1 (~88-193)          `.shop-hero`
     - css/order-samples.css §1 (~30-142)  `.samples-hero`
   The two sheets are the same recipe under two class names; the theme carries
   ONE of it, and this is that one.

   Specificity: (0,3,x) against §1's (0,2,x), so these win on WEIGHT and not on
   order. That matters here for the same reason it does in §2b: the block sheets
   load BEFORE pb-shell.css on this project, so "later in the cascade" is not a
   safe instinct.
   ========================================================================== */

/* 1. THE BAND. Deliberately taller than the §1 guide banners' 260-340px: these
   are the two landing pages and the brief asked for a big banner image. It
   still stops well short of the home hero's full viewport, so the hierarchy
   home > shop / order samples > guide pages holds.
   --chrome-bottom is added exactly as §1 adds it, and inherited from §1
   unchanged: only the clamp moves. */
.guide-hero.image-band.is-style-landing {
  min-height: calc(clamp(440px, 40vw, 660px) + var(--chrome-bottom));
}

/* 2. THE SCRIM. IDENTICAL IN CONSTRUCTION to §1 — the same symmetric
   centre-weighted darken, the same ink rgb(35,41,44), the same five stop
   positions — with the alphas deepened uniformly by x1.4. That multiplier is
   forced by the photography rather than chosen. banner-bordeaux.jpg is a
   high-key pale ivory pebble-loop crop and Commercial_Gallery_TheLouise-2.jpg is
   a high-key sunlit interior; v9b swept both independently and both landed on
   1.4, which is why one curve serves the pair.

   THE MOCKUP'S OWN MEASUREMENTS, kept because re-deriving them costs a browser
   run. Robust worst case (brightest-quartile mean under the glyph runs) against
   the 3.0 bar white display type owes at this size:
     shop         1440 4.20 · 1024 4.02 · 390 4.56
     samples      1920 4.03 · 1440 3.64 · 1024 3.97 · 768 4.11 · 390 9.99
   1440 on the samples page is the tightest row in the pair. Both mockup sheets
   record that the curve is LOOSER THAN IT HAS TO BE and say to leave it: it was
   tuned with a supporting deck in the band, the client then removed the deck,
   and re-tuning it for a one-line banner would break the family it is shared
   with to bank a margin nobody asked for.

   A DARKENED BANNER DOES NOT BREAK THE FLOATING CHROME, which is the thing that
   would otherwise make a deeper scrim risky here: the black-inked utility strip
   and header sit where the curve is only 0.08. Measured in the mockup at
   12.2-15.6:1 (strip) and 6.5-9.0:1 (header). */
.guide-hero.image-band.is-style-landing::before {
  background: linear-gradient(to bottom,
    rgba(35, 41, 44, 0.08) 0%,
    rgba(35, 41, 44, 0.48) 34%,
    rgba(35, 41, 44, 0.59) 50%,
    rgba(35, 41, 44, 0.48) 66%,
    rgba(35, 41, 44, 0.08) 100%);
}

/* 3. THE AIR BELOW THE BANNER, and the one declaration that is true of the shop
   page and not of Order Samples, stated rather than hidden. shop.css §1 carries
   it because the client's round deleted the intro band that used to sit between
   the banner and the filter chips; without it the banner's foot runs into the
   chips on the bar's own 16px of padding and reads as the bar being stuck to the
   photograph. It is NOT on the bar: `.shop-filter`'s padding-block is a measured
   quantity that the chip row height, the facet popovers and the docking reserve
   all read (blocks/pb_ec_range_grid/style.css), and the theme's bar carries
   `margin: 0` for the same reason v9b's does.

   ORDER SAMPLES DOES NOT NEED IT and gets it anyway. On that page the next
   element is a `.section`, which already carries its own padding-block, so this
   adds one --section-gap-s of extra air. That page has no wp_posts row, no
   template and no block folder today, so this is a difference of one token on a
   page nobody can look at; when it is built, measure it there and scope this
   rule if it reads long. Recorded here so that is a decision and not a
   discovery. */
.guide-hero.image-band.is-style-landing {
  margin-bottom: var(--section-gap-s);
}

/* ==========================================================================
   2. EDITORIAL HERO — `.edit-hero`
   designers-edit.html. A full-bleed lifestyle stage with the page's single H1
   overlaid — calm and image-led, not a boxed banner. Same DNA as `.image-band`
   (dark scrim baked in for legibility) but home-hero tall, with the title
   centred. Built standalone in the mockup rather than on `.image-band`, and
   reproduced standalone here, so it carries the full primitive itself.
   ========================================================================== */
.edit-hero {
  position: relative;
  /* MATCH HOME EXACTLY — the same full dynamic-viewport height pair home.css
     uses (vh fallback first, svh where supported). The floating glass chrome
     overlays this banner, so --chrome-bottom is added as TOP PADDING: with
     border-box the content area is the band visible below the glass, and the
     H1 centres in that. --chrome-bottom = inset + strip + gap + header. */
  min-height: 100vh;
  min-height: 100svh;
  padding-top: var(--chrome-bottom);
  display: grid;
  align-items: center;
  overflow: hidden;
  isolation: isolate;
  /* A PAGE BANNER runs edge-to-edge with square corners — a normal full-bleed
     hero, distinct from the rounded feature-frame language reserved for content
     imagery (tiles, gallery, mid-page atmosphere bands). */
  width: 100%;
  margin: 0;
  border-radius: 0;
}
.edit-hero .ph { position: absolute; inset: 0; z-index: -2; border-radius: 0; }
.edit-hero .ph::after { inset: 0; border: 0; }   /* drop the reserved-slot tick on a full-bleed hero */
.edit-hero .ph__cap { display: none; }
/* Legibility scrim tuned for a CENTRED heading: a symmetric CENTRE-BAND lens,
   near-clear at the top (artworks, panelling, bulbs) and at the foot (rug,
   floor) so the photo stays as light as AA-large comfortably allows, peaking
   through the middle third to seat the centred white H1. */
.edit-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom,
    rgba(35,41,44,0.06) 0%,
    rgba(35,41,44,0.22) 24%,
    rgba(35,41,44,0.56) 50%,
    rgba(35,41,44,0.22) 76%,
    rgba(35,41,44,0.06) 100%);
}
.edit-hero__text {
  color: var(--white);
  width: 100%;
  text-align: center;
}
/* No eyebrow in designers-edit.html today — the banner is title-only. Kept, on
   the PALE step: this hero is real photography under a dark gradient scrim,
   where the base accent is a mid tone and would read at ~2:1. */
.edit-hero__eyebrow { color: var(--woodland-sage-pale); }
/* The banner is home-hero tall, so the title takes a full display scale to
   carry the stage. Set in IvyPresto Display Regular here because the shell's
   folded [J] rule covers .hero__title / .cta-band__title but NOT this heading.
   Serif display reads smaller than a sans at the same px and wants tighter
   tracking, so the clamp is generous and the metrics match [J]'s banner
   treatment. No max-width cap: uncapped, the three words sit on one line at
   1440 and only break naturally at narrow widths.

   SPECIFICITY IS DELIBERATE at (0,1,1). pb-shell.css's `.u-caps.u-caps`
   (0,2,0) is doubled precisely so it beats this rule's letter-spacing and
   renders the capitals untracked (user, 2026-08-14) — the shell's own comment
   names this selector and this value. Do not raise it. */
.edit-hero__text h1 {
  color: var(--white);
  font-family: var(--font-serif);
  font-weight: 400;
  font-style: normal;
  font-size: clamp(3rem, 1.9rem + 5vw, 6rem);
  line-height: 1.06;
  letter-spacing: -0.012em;
  margin: 0;
}

/* ==========================================================================
   2b. STORY BANNER: `.edit-hero.is-style-story`
   our-story.html. The Designers Edit hero recipe, reused whole: our-story.css §1
   restates that sheet's geometry declaration for declaration and says outright
   that the two banners are siblings, so §2 above supplies all of it and this
   section carries only the two things that genuinely differ.

   1. A LIGHTER SCRIM. Same stop POSITIONS as §2, alphas at x0.7. The Designers
      Edit curve was tuned for a banner whose middle third is artwork and bulbs;
      this one seats its heading over the shadowed middle of a carpet, so those
      values overshoot and flatten a photograph that never needed the help.
      Measured in the mockup (_dev/our-story-hero-contrast.mjs), robust worst
      case under the glyph runs: 1920 8.24 · 1440 7.45 · 1024 8.07 · 390 8.60.
      The top and foot stops stay DELIBERATELY SHALLOW: the black-inked utility
      strip and header float over this banner, and deepening the 0% stop is what
      would break them.
   2. A PHONE CROP. A 1920x1080 photograph in a 390px viewport keeps a 26% wide
      vertical slice, and centred that slice lands on a plain white door and bare
      wall. Biasing right brings the bed, the cushions and the ottoman into
      frame. The scrim takes one step back up the curve (x0.85) at the same
      breakpoint because the heading now lands on white bed linen.

   BOTH FRAMINGS LIVE HERE rather than on the `pos` preset in render.php, which
   would emit them as an inline style attribute no media query could reach. This
   is the one preset with an empty `pos`; see the note beside it.

   Specificity: `.edit-hero.is-style-story` is (0,2,x) against §2's (0,1,x), so
   these win on weight and not on order. The block sheets load BEFORE the theme
   parts here, so "later in the cascade" is not a safe instinct on this project.
   ========================================================================== */
.edit-hero.is-style-story::before {
  background: linear-gradient(to bottom,
    rgba(35, 41, 44, 0.04) 0%,
    rgba(35, 41, 44, 0.15) 24%,
    rgba(35, 41, 44, 0.39) 50%,
    rgba(35, 41, 44, 0.15) 76%,
    rgba(35, 41, 44, 0.04) 100%);
}
/* The X value is the whole of this rule. Measured 2026-09-04 on the 1920x1080
   source: under object-fit: cover in a 100vh band the VERTICAL overflow is
   zero on any viewport narrower than 16:9, so a Y value changes nothing at
   any width this site is read at. v9b carries 62% here and 55% below, and
   that difference encodes an effect that does not occur. The X shift is real
   and does the work: 50% to 72% moves the frame 160px at 1440 and 1110px at
   390, which is 63% of the frame on a phone against 2.4% on a laptop. Y is
   held at 50% in both rules so nobody reads a difference into it later. */
.edit-hero.is-style-story .ph > img { object-position: 50% 50%; }

@media (max-width: 640px) {
  .edit-hero.is-style-story .ph > img { object-position: 72% 50%; }
  .edit-hero.is-style-story::before {
    background: linear-gradient(to bottom,
      rgba(35, 41, 44, 0.05) 0%,
      rgba(35, 41, 44, 0.19) 24%,
      rgba(35, 41, 44, 0.48) 50%,
      rgba(35, 41, 44, 0.19) 76%,
      rgba(35, 41, 44, 0.05) 100%);
  }
}

/* ==========================================================================
   3. MID-PAGE CTA BAND — `.image-band.image-hero.image-hero--cta`
   ORPHANED IN v9b. The `.deciding.image-band` section this shape reproduced was
   deleted from the mockup, so no v9b page emits it. Reached only by setting
   `heading_level` = h2. Retained unchanged pending a decision — see _sync.md.
   ========================================================================== */
.image-hero {
  width: 100%;
  margin-inline: 0;
  border-radius: 0;
}
.image-hero .image-band__text.container { padding-inline: var(--gutter); }
.image-hero--cta::before {
  background: linear-gradient(to top,
    rgba(35, 41, 44, 0.78) 0%,
    rgba(35, 41, 44, 0.58) 42%,
    rgba(35, 41, 44, 0.38) 72%,
    rgba(35, 41, 44, 0.14) 100%);
}
.image-hero__actions { margin-top: var(--space-md); }
/* Accent ink over dark imagery. v9b retires gold: this banner is real
   photography under a dark gradient scrim, where the base accent is a mid tone
   and would read at ~2:1, so the eyebrow takes the PALE step — the same value
   the surviving `.edit-hero__eyebrow` carries for exactly this case. */
.image-hero__eyebrow { color: var(--woodland-sage-pale); }

/* ==========================================================================
   4. OPTIONAL OVERLAY PARTS — shared by all three shapes
   No v9b banner carries a lead or a down-cue; both are field-driven extras the
   block keeps available, and both are omitted from the markup entirely when
   their field is empty.
   ========================================================================== */
.image-hero__lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: rgba(255,255,255,0.9);
  margin-top: var(--space-md);
}
.image-hero__cue {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  min-height: var(--tap-min);
  margin-top: var(--space-lg);
  font-size: var(--fs-sm);
  font-weight: var(--w-medium);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--white);
}
.image-hero__cue svg { width: 18px; height: 18px; transition: transform var(--dur-base) var(--ease-out); }
.image-hero__cue:hover svg { transform: translateY(3px); }
