/* ==========================================================================
   Portfolio Moguls — Home page
   Seven bands, flattened from raw/Home.dc.html. Mobile-first; the design's
   own vw<900 threshold is honoured where it changes layout meaningfully.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1 · Hero
   -------------------------------------------------------------------------- */

.pm-hero {
  position: relative;
  background: var(--pm-navy);
  color: var(--pm-on-navy);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.pm-hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Left-weighted scrim so the headline holds contrast over any photograph
   while the right side of the image stays legible. */
.pm-hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    rgba(20, 32, 58, 0.90) 0%,
    rgba(27, 42, 74, 0.66) 46%,
    rgba(27, 42, 74, 0.16) 100%
  );
}

/* The text block starts below the tile's bottom edge plus the brief's gap
   (32px mobile, 56px desktop; 44 splits the difference at tablet), and
   justify-center lets it optically centre in whatever hero space the
   min-height opens up — spacing, not absolute positioning. */
.pm-hero__inner {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 104px 80px; /* 64px tile + 40 */
}

.pm-hero__measure { max-width: 900px; }
/* Correction pass 2026-08-06: clamp(32, 3.4vw, 50) in a 20ch measure — the
   previous 38/5vw/64 set the long headline in four oversized lines; at these
   sizes it settles into three balanced ones on desktop. */
.pm-hero__heading {
  font-family: var(--pm-font-body);
  font-weight: 700;
  font-size: clamp(32px, 3.4vw, 50px);
  line-height: 1.12;
  letter-spacing: -0.005em;
  margin: 0;
  max-width: 20ch;
  text-wrap: balance;
}

.pm-hero__sub {
  font-family: var(--pm-font-body);
  font-size: 17px;
  line-height: 1.6;
  color: #E2E7EF;
  margin: 20px 0 0;
  max-width: 56ch;
  text-wrap: pretty;
}

@media (min-width: 768px) {
  /* 88px tile + 40 — the correction pass sets a single 40px gap after the
     tile at every scale. */
  .pm-hero__inner { padding-block: 128px 88px; }
}

@media (min-width: 900px) {
  /* 72vh/700, down from 88vh/900: the fold test wins — the intent router's
     cards must be at least half visible without scrolling at 1440x900 AND
     1366x768, and qa-header.js holds that gate. */
  .pm-hero { min-height: min(72vh, 700px); }
  .pm-hero__sub { font-size: 19px; }
}

@media (min-width: 1024px) {
  /* 112px tile + 40. */
  .pm-hero__inner { padding-block: 152px 96px; }
}

/* --------------------------------------------------------------------------
   2 · Intent router
   -------------------------------------------------------------------------- */

.pm-router { border-bottom: 1px solid var(--pm-border-faint); }

/* The 1px gap over a tinted background draws the hairlines between tiles,
   so no tile needs its own border. */
.pm-router__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--pm-border-faint);
}

.pm-router__tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* flex-start, not space-between: with the duplicate label gone there are two
     children, and the 24px gap is what puts the sub-line exactly where that
     label used to sit (measured: mark ended at 58, label began at 82). */
  justify-content: flex-start;
  gap: 24px;
  min-height: 132px;
  background: var(--pm-white);
  padding: 26px 22px;
  color: var(--pm-navy);
}

.pm-router__tile:hover,
.pm-router__tile:focus-visible {
  background: #F6F8FB;
  color: var(--pm-navy);
}

/*
 * The destination, carrying the chevron so it reads as something to press.
 *
 * Mobile-first per LESSON-009, and the two sizes are a deliberate split rather
 * than one size that compromises: at 390px a tile is only ~171px wide, and the
 * full button proportions crowded it. Compact here, full size from 768px where
 * the tile has roughly twice the width to give it.
 */
.pm-router__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-radius: 3px;
  background: var(--pm-action);
  color: var(--pm-action-text);
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 14px;
  line-height: 1.2;
  letter-spacing: 0.01em;
  padding: 7px 13px;
  flex: none;
  transition: background 180ms ease;
}

.pm-router__tile:hover .pm-router__chip,
.pm-router__tile:focus-visible .pm-router__chip {
  background: var(--pm-action-hover);
}

.pm-router__sub {
  display: block;
  font-size: 12.5px;
  color: var(--pm-muted-cool);
}

/* Inside the chip now, so it takes the chip's own navy rather than the link
   blue it used when it trailed the description. */
.pm-router__chev {
  color: currentColor;
  font-size: 1.15em;
  line-height: 1;
}

/*
 * Three-card variant, used while Rent is switched off. On a phone the first
 * card takes the full width and the other two pair beneath it — a 1 + 2 that
 * avoids the dangling half-tile a plain two-column grid would leave.
 */
.pm-router__grid--3 .pm-router__tile:first-child { grid-column: 1 / -1; }

/* From here a tile is wide enough for the chip to be a full-size button. */
@media (min-width: 768px) {
  .pm-router__tile { gap: 18px; }

  .pm-router__chip {
    gap: 10px;
    border-radius: 4px;
    font-size: 17px;
    padding: 15px 22px;
  }
}

/* Two tiles already pair cleanly in the base two-column grid — nothing to do
   on mobile, and they simply stay a pair at desktop rather than stretching
   across the full measure. */

@media (min-width: 900px) {
  .pm-router__grid { grid-template-columns: repeat(4, 1fr); }
  .pm-router__grid--3 { grid-template-columns: repeat(3, 1fr); }
  .pm-router__grid--3 .pm-router__tile:first-child { grid-column: auto; }
  .pm-router__grid--2 { grid-template-columns: repeat(2, 1fr); }
}

/* --------------------------------------------------------------------------
   3 · Numbers wall
   -------------------------------------------------------------------------- */

.pm-numbers { padding-block: 62px 58px; }

.pm-numbers__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 26px 28px;
}

.pm-numbers__item {
  border-top: 1px solid var(--pm-navy);
  padding-top: 18px;
}

.pm-numbers__figure {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 38px;
  line-height: 1;
  color: var(--pm-navy);
  letter-spacing: -0.01em;
}

.pm-numbers__label {
  font-size: 13.5px;
  color: var(--pm-muted-cool);
  margin-top: 10px;
  line-height: 1.35;
}

.pm-numbers__quote {
  margin-top: 44px;
  max-width: 760px;
}

.pm-numbers__rule {
  display: block;
  width: 52px;
  height: 1px;
  background: var(--pm-gold);
}

.pm-numbers__quotetext {
  font-family: var(--pm-font-body);
  font-size: 22px;
  line-height: 1.4;
  color: var(--pm-navy);
  margin: 18px 0 0;
  text-wrap: pretty;
}

.pm-numbers__quote .pm-stamp {
  display: block;
  margin-top: 14px;
  letter-spacing: 0.18em;
}

@media (min-width: 900px) {
  .pm-numbers__grid { grid-template-columns: repeat(4, 1fr); }
  .pm-numbers__figure { font-size: 46px; }
  .pm-numbers__quotetext { font-size: 27px; }
}

/* --------------------------------------------------------------------------
   4 · Protocol strip
   -------------------------------------------------------------------------- */

.pm-proto { padding-block: 62px; }

.pm-proto__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
}

.pm-proto__head .pm-eyebrow {
  letter-spacing: 0.2em;
  font-size: 11px;
}

.pm-proto__heading { margin-top: 10px; }

.pm-proto__intro {
  font-family: var(--pm-font-body);
  font-size: 16.5px;
  color: var(--pm-text);
  margin: 16px 0 30px;
  max-width: 620px;
}

.pm-proto__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.pm-proto__card {
  background: var(--pm-white);
  border: 1px solid var(--pm-border-soft);
  border-radius: var(--pm-radius-sm);
  padding: 20px 20px 18px;
  box-shadow: var(--pm-shadow-card);
}

.pm-proto__cardhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.pm-proto__num {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 22px;
  color: var(--pm-link-hover);
}

.pm-tick { flex: none; line-height: 0; }

.pm-proto__name {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--pm-navy);
  margin: 13px 0 0;
  line-height: 1.3;
}

.pm-proto__note {
  font-size: 12.5px;
  color: var(--pm-muted-cool);
  margin: 6px 0 0;
  line-height: 1.45;
}

.pm-proto__cta { margin: 26px 0 0; }

@media (min-width: 768px) {
  .pm-proto__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .pm-proto__grid { grid-template-columns: repeat(4, 1fr); }
}

/* --------------------------------------------------------------------------
   5 · Featured listings
   -------------------------------------------------------------------------- */

.pm-listings { padding-block: 68px; }

.pm-listings__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 30px;
}

.pm-listings__head .pm-eyebrow {
  letter-spacing: 0.2em;
  font-size: 11px;
}

.pm-listings__heading { margin-top: 10px; }

.pm-listings__intro {
  font-size: 14.5px;
  color: var(--pm-muted-cool);
  margin: 8px 0 0;
}

/* --------------------------------------------------------------------------
   6 · Segment doorways
   -------------------------------------------------------------------------- */

.pm-doorways { padding-block: 62px; }

.pm-doorways__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

.pm-doorway {
  background: var(--pm-white);
  border: 1px solid var(--pm-border-soft);
  border-radius: var(--pm-radius-sm);
  padding: 28px;
  display: flex;
  flex-direction: column;
  box-shadow: var(--pm-shadow-card);
}

.pm-doorway .pm-eyebrow {
  letter-spacing: 0.2em;
  font-size: 11px;
}

.pm-doorway__title {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 20px;
  color: var(--pm-navy);
  margin: 10px 0 8px;
}

.pm-doorway__line {
  font-family: var(--pm-font-body);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--pm-text);
  margin: 0 0 20px;
  flex: 1;
}

.pm-doorway__cta { align-self: flex-start; }

@media (min-width: 768px) {
  .pm-doorways__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .pm-doorways__grid { grid-template-columns: repeat(3, 1fr); }
}

/* --------------------------------------------------------------------------
   7 · Proof & fees band
   -------------------------------------------------------------------------- */

.pm-proof { padding-block: 68px; }

.pm-proof__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 22px;
  align-items: stretch;
}

.pm-proof__stack {
  display: flex;
  flex-direction: column;
  gap: 22px;
}

/* Fees card */

.pm-feecard {
  border: 1px solid var(--pm-border-soft);
  border-radius: var(--pm-radius-sm);
  padding: 30px;
  display: flex;
  flex-direction: column;
  box-shadow: var(--pm-shadow-card);
}

.pm-feecard .pm-eyebrow {
  letter-spacing: 0.2em;
  font-size: 11px;
}

.pm-feecard__heading {
  font-family: var(--pm-font-ui);
  font-weight: 600;
  font-size: 23px;
  color: var(--pm-navy);
  margin: 10px 0 20px;
}

/* One of the three sanctioned uses of gold: a thin rule. */
.pm-feecard__rule { border-top: 1px solid var(--pm-gold); }

.pm-feerow {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--pm-border-faint);
}

.pm-feerow__service {
  font-size: 15px;
  color: var(--pm-text);
}

.pm-feerow__amount {
  font-family: var(--pm-font-ui);
  font-size: 18px;
  font-weight: 700;
  color: var(--pm-navy);
  white-space: nowrap;
}

.pm-feecard__note {
  font-family: var(--pm-font-body);
  font-size: 13px;
  color: var(--pm-muted-cool);
  font-style: italic;
  margin: 12px 0 0;
}

.pm-feecard__link {
  margin-top: auto;
  padding-top: 20px;
  font-size: 14.5px;
}

/* Yield card */

.pm-yieldcard {
  background: var(--pm-navy);
  color: var(--pm-on-navy);
  border-radius: var(--pm-radius-sm);
  padding: 28px;
  display: block;
}

.pm-yieldcard:hover,
.pm-yieldcard:focus-visible { color: var(--pm-on-navy); }

.pm-yieldcard__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}

.pm-yieldcard__head .pm-eyebrow {
  letter-spacing: 0.2em;
  font-size: 11px;
}

.pm-yieldcard__headline {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 28px;
  color: var(--pm-white);
  margin: 14px 0 0;
}

.pm-yieldcard__desc {
  font-size: 13.5px;
  color: var(--pm-on-navy-soft);
  margin: 8px 0 0;
  line-height: 1.5;
}

.pm-yieldcard__link { color: var(--pm-on-navy-accent); }

/* Case study card */

.pm-casecard {
  border: 1px solid var(--pm-border-soft);
  border-radius: var(--pm-radius-sm);
  padding: 26px;
  display: block;
  color: inherit;
  box-shadow: var(--pm-shadow-card);
}

.pm-casecard:hover,
.pm-casecard:focus-visible {
  color: inherit;
  border-color: var(--pm-action);
}

.pm-casecard__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}

.pm-casecard__head .pm-stamp { letter-spacing: 0.18em; }

.pm-casecard__badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--pm-green);
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}

.pm-casecard__heading {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 18px;
  color: var(--pm-navy);
  margin: 10px 0 6px;
}

.pm-casecard__desc {
  font-family: var(--pm-font-body);
  font-size: 14px;
  line-height: 1.55;
  color: var(--pm-muted-cool);
  margin: 0;
}

.pm-casecard__link {
  color: var(--pm-navy);
  font-weight: 600;
  font-family: var(--pm-font-ui);
}

@media (min-width: 900px) {
  .pm-proof__grid { grid-template-columns: 1fr 1fr; }
  .pm-yieldcard__headline { font-size: 34px; }
}

/* --------------------------------------------------------------------------
   6 · Client Stories
   --------------------------------------------------------------------------
   The pull-quote is the centrepiece and the cards are its controls, which is
   why the quote sits above them at display size. The band is deliberately
   mostly air: ~1.3x the vertical padding of its neighbours, an ivory ground,
   and one italic sentence doing the work.
   -------------------------------------------------------------------------- */

.pm-stories {
  /* 62px is the house section rhythm; this band takes 1.3x of it. */
  padding-block: 80px;
  background: #FCFBF8;
  border-block: 1px solid var(--pm-border-faint);
}

.pm-stories__head { text-align: center; }

.pm-stories__kicker {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--pm-muted-cool);
  margin: 0;
}

.pm-stories__heading {
  font-family: var(--pm-font-body);
  font-weight: 700;
  font-size: 30px;
  line-height: 1.15;
  color: var(--pm-navy);
  margin: 14px 0 0;
}

.pm-stories__intro {
  font-size: 14.5px;
  color: var(--pm-muted-cool);
  margin: 10px 0 0;
}

/* ---- The quote moment ---------------------------------------------------- */

.pm-stories__quote {
  position: relative;
  /* Measured in px, not ch: a ch of italic PT Serif is narrow enough that a
     ch-based measure collapsed this to six short lines instead of two. */
  max-width: 330px;
  margin: 40px auto 44px;
  padding-inline: 26px;
  text-align: center;
}

.pm-stories__quotetext {
  font-family: var(--pm-font-body);
  font-style: italic;
  font-weight: 400;
  font-size: 23px;
  line-height: 1.42;
  color: var(--pm-navy);
  margin: 0;
  text-wrap: pretty;
  /* The crossfade. Script swaps .is-fading on and off around the text change;
     with no script the quote is simply static and fully opaque. */
  opacity: 1;
  transition: opacity 260ms ease;
}

.pm-stories__quotetext.is-fading { opacity: 0; }

/* Oversized hairline marks — outline weight, not filled, so they read as
   typography rather than punctuation. */
.pm-stories__mark {
  position: absolute;
  font-family: var(--pm-font-body);
  font-size: 86px;
  line-height: 1;
  color: var(--pm-border-soft);
  pointer-events: none;
  user-select: none;
}

.pm-stories__mark--open {
  inset: -18px auto auto -4px;
}

.pm-stories__mark--close {
  inset: auto -4px -46px auto;
}

.pm-stories__attrib {
  margin-top: 20px;
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--pm-muted-cool);
  transition: opacity 260ms ease;
}

.pm-stories__attrib.is-fading { opacity: 0; }

/* ---- Cards --------------------------------------------------------------- */

.pm-stories__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 84%;
  gap: var(--pm-space-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  /* Room for the lifted centre card's shadow at wide widths. */
  padding: 10px 0 16px;
}

.pm-stories__track::-webkit-scrollbar { display: none; }

.pm-story {
  scroll-snap-align: center;
  min-width: 0;
  display: flex;
  flex-direction: column;
  color: inherit;
  transition: transform 260ms ease, box-shadow 260ms ease;
}

.pm-story__media {
  position: relative;
  display: block;
  /* Reserved before the poster loads, so nothing reflows (LESSON-003). */
  aspect-ratio: 16 / 9;
  background: var(--pm-stripe-cool);
  border: 1px solid var(--pm-border);
  border-radius: var(--pm-radius-lg);
  overflow: hidden;
  box-shadow: 0 18px 40px -22px rgba(27, 42, 74, 0.55);
  transition: box-shadow 260ms ease, transform 260ms ease;
}

.pm-story__poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.pm-story__play {
  position: absolute;
  inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  width: 52px;
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--pm-navy);
  color: var(--pm-white);
  /* Optically centres the triangle inside the disc. */
  padding-left: 3px;
  transition: background 200ms ease, color 200ms ease;
}

.pm-story:hover .pm-story__play,
.pm-story:focus-visible .pm-story__play {
  background: var(--pm-action);
  color: var(--pm-action-text);
}

.pm-story:focus-visible .pm-story__media {
  outline: 3px solid var(--pm-focus);
  outline-offset: 3px;
}

.pm-story__length,
.pm-story__badge {
  position: absolute;
  font: var(--pm-stamp-type);
  letter-spacing: var(--pm-stamp-tracking);
  text-transform: uppercase;
  border-radius: var(--pm-radius-sm);
  padding: 4px 8px;
}

.pm-story__length {
  inset: auto 10px 10px auto;
  background: rgba(27, 42, 74, 0.82);
  color: var(--pm-white);
}

.pm-story__badge {
  inset: 10px auto auto 10px;
  background: var(--pm-white);
  border: 1px solid var(--pm-border);
  color: var(--pm-stamp);
}

.pm-story__body {
  display: block;
  padding: 16px 2px 0;
  text-align: center;
}

.pm-story__name {
  display: block;
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pm-navy);
}

.pm-story__context {
  display: block;
  font-size: 13.5px;
  color: var(--pm-muted-cool);
  margin-top: 6px;
}

/* ---- Dots ---------------------------------------------------------------- */

.pm-stories__dots {
  display: flex;
  justify-content: center;
  gap: 9px;
  margin-top: 22px;
}

.pm-stories__dots[hidden] { display: none; }

.pm-stories__dot {
  width: 7px;
  height: 7px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--pm-border-crumb);
  transition: background 200ms ease, transform 200ms ease;
}

.pm-stories__dot.is-active {
  background: var(--pm-link-hover);
  transform: scale(1.35);
}

@media (min-width: 768px) {
  .pm-stories__track { grid-auto-columns: 46%; }
  .pm-stories__quote { max-width: 620px; }
}

@media (min-width: 1024px) {
  .pm-stories { padding-block: 96px; }
  .pm-stories__heading { font-size: 38px; }
  .pm-stories__quote { max-width: 800px; margin-block: 48px 56px; }
  .pm-stories__quotetext { font-size: 30px; }
  .pm-stories__mark { font-size: 110px; }

  /* All three fit, so the track stops scrolling and becomes a row. */
  .pm-stories__track {
    grid-auto-columns: minmax(0, 1fr);
    gap: var(--pm-space-5);
  }

  /*
   * The centre card sits fractionally forward. Deliberately small — 1.03 and a
   * deeper shadow read as depth; anything more reads as a carousel.
   */
  .pm-story:nth-child(2) .pm-story__media {
    /* The poster lifts, not the whole card. Scaling the card moved its caption
       down with it, which read as misalignment rather than as depth. */
    transform: scale(1.03);
    box-shadow: 0 26px 54px -24px rgba(27, 42, 74, 0.62);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pm-stories__quotetext,
  .pm-stories__attrib,
  .pm-story,
  .pm-story__media,
  .pm-story__play,
  .pm-stories__dot,
  .pm-router__chip { transition: none; }

  /* The crossfade is what reduced motion is asking us not to do, so the swap
     is instant and the text never passes through zero opacity. */
  .pm-stories__quotetext.is-fading,
  .pm-stories__attrib.is-fading { opacity: 1; }
}

/* --------------------------------------------------------------------------
   9 · The window — press clippings, closing CTA, message strip
   -------------------------------------------------------------------------- */

.pm-window { padding-block: 66px 0; }

.pm-window__head {
  max-width: 62ch;
  margin-bottom: 30px;
}

.pm-window__head .pm-eyebrow {
  letter-spacing: 0.2em;
  font-size: 11px;
}

.pm-window__heading { margin-top: 10px; }

.pm-window__intro {
  font-size: 14.5px;
  color: var(--pm-muted-cool);
  margin: 8px 0 0;
}

/* --------------------------------------------------------------------------
   The stacked clippings
   --------------------------------------------------------------------------
   Every clipping occupies the same grid cell, so the pile sizes itself to the
   tallest one and the fan is pure transform on top — no absolute positioning,
   no fixed heights, nothing that reflows when a client writes a longer
   headline.

   The fan is driven by one registered custom property, --pm-p, running 0
   (closed: aligned and overlapping) to 1 (open: fanned). Two things can drive
   it and they never both run:

     · a CSS scroll-driven animation where animation-timeline: view() exists
     · assets/js/pile.js, which sets it from scroll position everywhere else

   Because both write the same property, there is one transform rule rather
   than two implementations that can drift apart.

   The initial value is 1, deliberately. With no script and no scroll timeline
   — and under prefers-reduced-motion — the pile simply renders open and
   static, which is the intended fallback rather than an accident.
   -------------------------------------------------------------------------- */

@property --pm-p {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

.pm-pile {
  display: grid;
  justify-items: center;
  justify-content: center;
  /*
   * Padding has to cover the cascade, not just breathe. Cards are centred in
   * the grid cell and then translated, so anything the padding does not cover
   * paints over the heading above and the closing line below. Two cascade
   * steps plus the largest jitter is the number to beat at each breakpoint.
   */
  padding-block: 260px 268px;
  --pm-card-w: min(255px, 62vw);
  --pm-spread: 15px;
  /*
   * The scrub window, as a share of the element's cover range. Declared here
   * rather than only in animation-range because assets/js/pile.js reads these
   * two values back and reproduces the same window — one source of truth for
   * both drivers. Mobile gets the longer window: the pile is much taller here,
   * so the same fraction of scroll would fan it open far too abruptly.
   */
  /*
   * The scrub window, tuned by where the pile's TOP EDGE sits on screen rather
   * than by feel — that is what the viewer actually perceives.
   *
   *   start  top edge at ~0.70 x viewport — roughly a third of the pile
   *          showing, so the closed stack is visible before it begins to move
   *   end    top edge just inside the screen — fully fanned while it fills the
   *          view, and crucially before the first clipping scrolls off the top
   *
   * History, because this has been wrong in both directions. It once ran to
   * 64% of cover: on a phone that put the top edge 204px PAST the top of the
   * screen at completion, so the first clipping finished opening after it had
   * gone. Correcting that (2%→34%) overshot the other way — starting at 2%
   * means the pile has barely crested the bottom edge, so most of the movement
   * happened below the fold and the fan was already over by the time you
   * arrived. Starting at 15% fixes the position; ending at 48% keeps the
   * §32 guarantee and buys back the leisurely travel.
   *
   * THIS PAIR IS MOBILE ONLY. The ≥768px rule deliberately keeps a different
   * window — the pile-to-viewport ratio there is nothing like this one, so the
   * same percentages do not mean the same thing. Do not sync them.
   */
  --pm-scrub-start: 15%;
  --pm-scrub-end: 48%;
  /*
   * The systematic downward step. On a narrow screen the horizontal offsets
   * have to stay tight — five cuttings cannot fan sideways inside 342px — so
   * the pile cascades downward instead. Combined with the ascending z-order
   * set in the template, that leaves every clipping's masthead strip visible
   * and tappable rather than burying four of the five citations completely.
   * The wide breakpoints turn it off and fan horizontally instead.
   */
  /*
   * 52px, not less: the masthead sits 18px down and stands about 21px tall,
   * and the covering clipping's own rotation tilts its top edge by roughly
   * 7px either side of centre. At 42px the Forbes masthead was sliced through
   * the middle, which reads as a bug rather than as a pile.
   */
  --pm-cascade: 123px;
  /*
   * Gentler than the wide fan, and for a specific reason: the covering
   * clipping's tilt is what decides how cleanly the cut lands. Inside the
   * paper the masthead ends at 34px and the headline starts at 66px, so
   * the cut has to land in a gap rather than through a line of type. 1.1deg
   * keeps the wander to about ±6px, which the gaps can absorb; 1.4deg did not.
   */
  --pm-rot: 1.1deg;
}

.pm-clip {
  /* One cell, five clippings. */
  grid-area: 1 / 1;
  width: var(--pm-card-w);
  --pm-fan-x: calc(var(--pm-i) * var(--pm-spread));
  --pm-fan-y: calc(var(--pm-i) * var(--pm-cascade) + var(--pm-y-jitter, 0px));
  --pm-fan-r: calc(var(--pm-i) * var(--pm-rot) + var(--pm-rot-nudge, 0deg));
  /* Transform and opacity only — nothing here can trigger layout. */
  transform:
    translate3d(
      calc(var(--pm-fan-x) * var(--pm-p)),
      calc(var(--pm-fan-y) * var(--pm-p)),
      0
    )
    rotate(
      calc(
        var(--pm-shut-r, 0deg) * (1 - var(--pm-p)) + var(--pm-fan-r) * var(--pm-p)
      )
    );
  color: inherit;
}

/* Hover and focus raise a clipping clear of the pile so it is legible while
   being read, not just outlined behind its neighbours. */
.pm-clip:hover,
.pm-clip:focus-visible { z-index: 20 !important; }

/* ---- The paper itself ----------------------------------------------------
   Separated from .pm-clip because that element is carrying the scroll-scrubbed
   transform. A transition there would smear every scroll frame; here the lift
   can transition freely. */

.pm-clip__paper {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 9px;
  /* Off-white newsprint. Warmer than the page, still quiet enough to sit
     inside a cool navy/teal palette without reading as a second accent. */
  background: #FBFAF6;
  border: 1px solid #E4E0D6;
  padding: 18px 18px 15px;
  box-shadow:
    0 1px 1px rgba(27, 42, 74, 0.06),
    0 8px 18px -6px rgba(27, 42, 74, 0.22);
  transition: transform 180ms ease, box-shadow 180ms ease;
}

/* Paper grain: two nearly-invisible gradients, one fine and one broad, so the
   surface is not perfectly flat under the shadow. Cheap, and no image. */
.pm-clip__paper::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(
      92deg,
      rgba(27, 42, 74, 0.022) 0 1px,
      transparent 1px 3px
    ),
    repeating-linear-gradient(
      4deg,
      rgba(27, 42, 74, 0.016) 0 1px,
      transparent 1px 4px
    ),
    radial-gradient(120% 90% at 30% 0%, rgba(255, 255, 255, 0.7), transparent 60%);
}

.pm-clip:hover .pm-clip__paper,
.pm-clip:focus-visible .pm-clip__paper {
  transform: translateY(-3px);
  box-shadow:
    0 2px 2px rgba(27, 42, 74, 0.07),
    0 16px 30px -8px rgba(27, 42, 74, 0.32);
}

.pm-clip:focus-visible .pm-clip__paper {
  outline: 3px solid var(--pm-focus);
  outline-offset: 3px;
}

/* ---- Rough-cut edges -----------------------------------------------------
   Two of the five are hand-cut rather than trimmed. clip-path would clip a
   box-shadow, so those clippings drop the box-shadow and take a drop-shadow
   filter instead, which follows the torn silhouette properly. */

.pm-clip--torn .pm-clip__paper {
  box-shadow: none;
  filter: drop-shadow(0 1px 1px rgba(27, 42, 74, 0.07))
    drop-shadow(0 8px 14px rgba(27, 42, 74, 0.2));
  clip-path: polygon(
    0 0, 100% 0,
    100% calc(100% - 5px), 93% 100%, 86% calc(100% - 4px),
    79% calc(100% - 1px), 72% calc(100% - 6px), 65% calc(100% - 2px),
    58% 100%, 51% calc(100% - 5px), 44% calc(100% - 1px),
    37% calc(100% - 6px), 30% calc(100% - 2px), 23% 100%,
    16% calc(100% - 4px), 9% calc(100% - 1px), 0 calc(100% - 5px)
  );
  /* The cut edge needs a little more paper below the date so the tear does
     not bite into the type. */
  padding-bottom: 21px;
}

.pm-clip--torn:hover .pm-clip__paper,
.pm-clip--torn:focus-visible .pm-clip__paper {
  filter: drop-shadow(0 2px 2px rgba(27, 42, 74, 0.08))
    drop-shadow(0 15px 24px rgba(27, 42, 74, 0.3));
}

/* ---- Masthead ------------------------------------------------------------
   Three treatments across the two families the design allows, assigned per
   slot in template-parts/home-window.php. */

.pm-clip__masthead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  /*
   * Uniform height across all three masthead faces. They are set at different
   * sizes to approximate their publications, which left each clipping's
   * internals sitting at a slightly different height — and the cascade needs
   * every covered clipping to break at the same point. Measured, the tallest
   * (the display face) is 21px; without this the shared clean-cut window
   * across the five was 3px wide instead of 21px.
   */
  min-height: 22px;
}

.pm-clip__pub {
  color: var(--pm-navy);
  line-height: 1.1;
}

/* Slot 1 — heavy, tight, small caps. */
.pm-clip--display .pm-clip__pub {
  font-family: var(--pm-font-body);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

/* Slot 2 — an institution rather than a newspaper, so the UI face. */
.pm-clip--sans .pm-clip__pub {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 13.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* Slots 3–5 — broadsheet serif. */
.pm-clip--serif .pm-clip__pub {
  font-family: var(--pm-font-body);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.005em;
}

/* Double rule under the masthead — 1px, gap, 1px. */
.pm-clip__rule {
  display: block;
  height: 3px;
  border-top: 1px solid var(--pm-navy);
  border-bottom: 1px solid var(--pm-navy);
  /*
   * Extra air under the rule, which a masthead wants anyway — and which the
   * cascade needs. Where one clipping covers the next, the cut has to land
   * between the rule and the headline or it slices a line of type in half.
   * Measured, that gap was 9px while the relative tilt of two adjacent
   * clippings moves the cut by about ±6px. 9px was not a target you could
   * hit; 20px is.
   */
  margin-bottom: 11px;
}

/* Safety net only: visible if a source URL is ever cleared. */
.pm-clip__sample {
  flex: none;
  font: var(--pm-stamp-type);
  letter-spacing: var(--pm-stamp-tracking);
  text-transform: uppercase;
  color: var(--pm-stamp);
  border: 1px solid var(--pm-border);
  border-radius: var(--pm-radius-sm);
  padding: 3px 6px;
}

/* ---- Cutting body -------------------------------------------------------- */

.pm-clip__headline {
  display: block;
  font-family: var(--pm-font-body);
  font-weight: 700;
  font-size: 16.5px;
  line-height: 1.24;
  color: var(--pm-navy);
  text-wrap: balance;
}

/* Hairline under the headline, as a cutting has. */
.pm-clip__hrule {
  display: block;
  height: 1px;
  background: #D8D3C6;
}

/*
 * On a narrow screen the pile cascades downward and each clipping shows only
 * its top strip. Left alone, that strip ends wherever the covering clipping
 * happens to fall — which is a different point inside every headline, because
 * headlines run to different lengths, and it sliced lines of type in half.
 *
 * Fixing the strip's height instead makes the cut predictable: every covered
 * clipping shows exactly two lines, the rest is hidden with no ellipsis, and
 * the clipping in front lands just below in the resulting gap. The frontmost
 * clipping is excluded — nothing covers it, so it shows everything.
 *
 * From 768px the pile fans sideways rather than down, nothing is cut
 * horizontally, and this is switched back off.
 */
.pm-clip:not(:last-child) .pm-clip__headline {
  height: 2.48em; /* 2 lines at the 1.24 line-height set above */
  overflow: hidden;
  /*
   * On top of the paper's own 9px gap, giving the cut a 21px window to land
   * in rather than 9px. The tilt between two adjacent clippings moves it by
   * about ±6px, so 9px was not a target that could be hit reliably.
   */
  margin-bottom: 12px;
}

.pm-clip__standfirst {
  display: block;
  font-family: var(--pm-font-ui);
  font-size: 13px;
  line-height: 1.5;
  color: var(--pm-muted-cool);
}

.pm-clip__foot {
  margin-top: auto;
  padding-top: 11px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.pm-clip__date { color: #8A8371; }

.pm-clip__source {
  font-family: var(--pm-font-ui);
  font-size: 12.5px;
  font-weight: 700;
  /* Stays navy by instruction — the clippings keep their paper styling. */
  color: var(--pm-navy);
}

/* No source — reads as a label, not as something to click. */
.pm-clip__source--inert {
  font-weight: 600;
  color: var(--pm-border-crumb);
}

/* ---- Driving the fan ----------------------------------------------------- */

@keyframes pm-pile-open {
  from { --pm-p: 0; }
  to { --pm-p: 1; }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .pm-pile {
      animation: pm-pile-open linear both;
      animation-timeline: view();
      /*
       * Both ends are named in the SAME range — cover — on purpose. The
       * fallback in assets/js/pile.js has to reproduce this window from
       * getBoundingClientRect, and cover progress is a single expression
       * ((viewport - top) / (viewport + height)) with no phase boundary in
       * it. Mixing entry and cover here is what made the two drivers
       * disagree the first time, with the script reaching only 0.64 where
       * CSS reached 1.
       *
       * The window itself is --pm-scrub-start/--pm-scrub-end, set per
       * breakpoint on .pm-pile above: long enough to read as a fan opening
       * rather than a state change, and fully open while the pile is still
       * comfortably on screen.
       */
      animation-range: cover var(--pm-scrub-start) cover var(--pm-scrub-end);
    }
  }
}

/* Static, fully fanned, no animation of any kind. */
@media (prefers-reduced-motion: reduce) {
  .pm-pile {
    --pm-p: 1;
    animation: none !important;
  }

  .pm-clip__paper { transition: none; }
}

.pm-window__close {
  max-width: 56ch;
  margin: 40px auto 0;
  text-align: center;
  padding-bottom: 62px;
}

.pm-window__line {
  font-family: var(--pm-font-body);
  font-size: 19px;
  line-height: 1.5;
  color: var(--pm-navy);
  margin: 0 0 22px;
  text-wrap: pretty;
}

.pm-window__note {
  font-size: 13px;
  color: var(--pm-muted-cool);
  margin: 12px 0 0;
}

/* Closing message strip — the softest band on the page, immediately above the
   navy footer, so the page steps down into it rather than cutting to navy. */
.pm-msgstrip {
  background: var(--pm-surface-alt);
  border-top: 1px solid var(--pm-border-faint);
}

.pm-msgstrip__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--pm-space-4);
  padding-block: 34px;
  text-align: center;
}

.pm-msgstrip__line {
  font-family: var(--pm-font-ui);
  font-weight: 700;
  font-size: 16px;
  color: var(--pm-navy);
  margin: 0;
}

.pm-msgstrip__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
}

/* Enough room to start trading vertical cascade for horizontal spread. */
@media (min-width: 768px) {
  .pm-pile {
    --pm-card-w: 250px;
    --pm-spread: 118px;
    --pm-cascade: 20px;
    --pm-rot: 2.2deg;
    /* NOT the same window as mobile, and the difference is not an oversight —
       see the note on the base rule. The pile is far shorter than the viewport
       here (359px in 900px against 793px in 844px), so identical cover
       percentages put the top edge in completely different places.

       §43 moved this to 21%/68% alongside the mobile fix and overshot: at this
       aspect the fan then finished with the pile already leaving the top, i.e.
       it opened after you had scrolled past it. Reverted to the §38 window,
       which was only ever wrong on mobile. Mobile keeps 15%/48%.

       Do not "harmonise" these two pairs. They are different numbers because
       they have to be. */
    --pm-scrub-start: 4%;
    --pm-scrub-end: 46%;
    padding-block: 58px 66px;
  }

  .pm-clip__headline { font-size: 17px; }

  /* Fanned sideways from here, so nothing needs its headline cropped. */
  .pm-clip:not(:last-child) .pm-clip__headline {
    height: auto;
    overflow: visible;
    margin-bottom: 0;
  }
}

@media (min-width: 1024px) {
  .pm-pile {
    --pm-card-w: 268px;
    --pm-spread: 162px;
    --pm-cascade: 12px;
    --pm-rot: 2.5deg;
    padding-block: 46px 56px;
  }

  .pm-clip__paper { padding: 20px 20px 17px; }
  .pm-clip--torn .pm-clip__paper { padding-bottom: 23px; }
  .pm-clip__headline { font-size: 17.5px; }
}

/*
 * The full fan. Below this width five cuttings cannot spread far enough to
 * clear each other's headlines, so they stay a pile and the top one carries
 * the reading; from here there is room to open out until only the outer
 * margin of each clipping is covered.
 */
@media (min-width: 1280px) {
  .pm-pile {
    --pm-card-w: 282px;
    --pm-spread: 218px;
    --pm-cascade: 0px;
    --pm-rot: 2.8deg;
  }

  .pm-clip__paper { padding: 22px 22px 18px; }
  .pm-clip--torn .pm-clip__paper { padding-bottom: 25px; }
  .pm-clip__headline { font-size: 18px; }
}

@media (min-width: 900px) {
  .pm-window { padding-block: 76px 0; }
  .pm-window__line { font-size: 22px; }

  .pm-msgstrip__inner {
    flex-direction: row;
    justify-content: center;
    gap: var(--pm-space-6);
    text-align: left;
  }
}
