/*
 * Reusable section scenery — an arctic photograph behind a section, under a contrast-guaranteed
 * scrim. Markup: parts/xw-scenery.php. Enqueued by the page template that uses it.
 *
 * THE GUARANTEE, AND WHAT IT IS MEASURED AGAINST.
 * --xw-scenery-floor is the scrim's MINIMUM alpha anywhere behind text. Contrast is not measured
 * against the pretty dark part of the photograph — it is measured against the worst pixel any
 * photograph could put there: a PURE WHITE one (snow, a blown highlight). Composite =
 * floor x tint + (1 - floor) x #ffffff, then WCAG 2.1 relative luminance.
 *
 * Ranges below span all three veil rules, because each variant tints differently and the Family
 * one also paints a LIGHTENING green highlight over its base - so quoting only the default tint's
 * numbers would flatter the worst case by half a point. Worst composite of the three is the
 * fwh-reviews one at rgb(57, 60, 54); the default and nlh-closing land at rgb(44, 53, 52).
 *
 *     11.24 - 12.66 : 1   AAA   #ffffff                headings
 *     10.24 - 11.62 : 1   AAA   #f7f4ee / #f8f5ed      body
 *      6.75 -  7.60 : 1   AA+   #e4c758                --fwh-gold eyebrow
 *      6.96 -  7.70 : 1   AA+   rgba(247,244,238,.78)  review count
 *      6.06 -  6.64 : 1   AA    rgba(255,255,255,.67)  nlh fine print
 *      5.49 -  6.00 : 1   AA    rgba(247,244,238,.66)  fwh fine print  <- the binding case
 *
 * These are the FLOOR, not the expectation: they assume every pixel behind the text is pure white,
 * which no frame here is. The real ratio over a given photograph is higher, by an amount that
 * depends on that frame and is not claimed here. Re-derive rather than trust this comment:
 *     php tools/verify-scenery-contrast.php
 * which reads the floor and the tints back OUT of this file, composites the layers the way a
 * browser does, and exits 1 below 4.5:1. Dropping the floor to .40 makes it report 9 failures.
 *
 * CHOOSING A PHOTOGRAPH FOR THIS. Pick one with strong INTERNAL contrast — bright highlights
 * against dark ground — not one that is simply dark. The scrim preserves (1 - floor) = 16% of the
 * original signal, so what survives is the DIFFERENCE between the light and dark parts of the
 * frame, and a uniformly low-key image has almost none to survive with. That is the opposite of
 * the intuition that a dark photograph is the safe choice, and it was found by looking at a
 * screenshot rather than by reasoning: the first frame picked here was chosen for being dark and
 * rendered as flat black.
 *
 * NO PARALLAX, BY DESIGN. No scroll transform and no `background-attachment: fixed` anywhere in
 * this component, so prefers-reduced-motion has nothing to switch off. Fixed backgrounds also
 * repaint every scroll frame on mobile, which is a real cost for decoration.
 *
 * NO LAYOUT SHIFT IS POSSIBLE. The image is `position: absolute; inset: 0` inside an absolutely
 * positioned layer: it is out of flow, so it cannot move anything whatever its intrinsic size, and
 * the section's height is set entirely by its content as it was before.
 */

.xw-has-scenery {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

/*
 * Content sits above the scenery. Stated once, for every direct child, so a section that gains a
 * block later cannot quietly end up behind the photograph. No negative z-index is used: at -1 the
 * layer would fall behind the section's own background-color, and that colour is the fallback that
 * has to stay visible when the image is still loading or fails outright.
 */
.xw-has-scenery > *:not(.xw-scenery) {
  position: relative;
  z-index: 1;
}

.xw-scenery {
  --xw-scenery-floor: .84;
  --xw-scenery-focus: center 45%;
  --xw-scenery-tint: 4, 14, 13;
  /* Where the floor plateau starts and ends. Variables, not literals, so the one media query at
     the foot of this file retunes every variant's gradient without any of them repeating it. */
  --xw-scenery-plateau-start: 28%;
  --xw-scenery-plateau-end: 72%;
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.xw-scenery .xw-scenery__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--xw-scenery-focus);
}

/*
 * One gradient, and the middle of it is a PLATEAU at the floor rather than a single point. That
 * detail is the difference between scenery and a dark rectangle: with one floor stop only a thin
 * band of the section ever sits at the floor and everything above and below it is darker, which is
 * how the first version of this component rendered a photograph nobody could see. Screenshotting
 * it is what caught that — the markup assertions and the contrast ratios were both already green.
 *
 * The floor is the whole accessibility promise — the shape above it is only taste, and a variant
 * may restyle the gradient freely as long as no stop goes below var(--xw-scenery-floor).
 */
.xw-scenery__veil {
  position: absolute;
  inset: 0;
  display: block;
  background: linear-gradient(
    180deg,
    rgba(var(--xw-scenery-tint), .95) 0%,
    rgba(var(--xw-scenery-tint), var(--xw-scenery-floor)) var(--xw-scenery-plateau-start),
    rgba(var(--xw-scenery-tint), var(--xw-scenery-floor)) var(--xw-scenery-plateau-end),
    rgba(var(--xw-scenery-tint), .95) 100%
  );
}

/*
 * A narrow viewport makes these sections far taller than they are wide, so the dense shoulders at
 * top and bottom cover a much larger share of the area than they do on desktop and the photograph
 * all but vanishes - measured on a 390x844 emulation, where the closing block came out at 856px
 * tall against 390 wide. Widen the plateau there. The FLOOR does not move, so every ratio in the
 * header still holds; this trades shoulder for plateau and nothing else.
 */
@media (max-width: 48rem) {
  .xw-scenery {
    --xw-scenery-plateau-start: 14%;
    --xw-scenery-plateau-end: 86%;
  }
}

/*
 * Windows High Contrast / forced-colors replaces the text colours but not the photograph, which is
 * exactly how a background image becomes an unreadable section. Drop the decoration and let the
 * section's own colour stand.
 */
@media (forced-colors: active) {
  .xw-scenery { display: none; }
}

/* Decoration does not belong on paper, and it wrecks the ink budget. */
@media print {
  .xw-scenery { display: none; }
}

/*
 * The component ships with no motion at all. This rule is a guard rather than a fix: if anyone
 * later adds a transition or a transform here, it is already switched off for the readers who
 * asked for that.
 */
@media (prefers-reduced-motion: reduce) {
  .xw-scenery,
  .xw-scenery .xw-scenery__img,
  .xw-scenery__veil {
    animation: none !important;
    transform: none !important;
    transition: none !important;
  }
}
