/* ==========================================================================
   Content layouts (rows → columns) and blocks
   ========================================================================== */

/* Rows ---------------------------------------------------------------------- */

.row + .row                 { margin-top: var(--space-section); }
.row + .row--space-none     { margin-top: 0; }
.row + .row--space-small    { margin-top: var(--space-6); }
.row + .row--space-large    { margin-top: var(--space-section-lg); }

.row__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--space-8) var(--grid-gap);
  max-width: var(--width-wide);
  margin-inline: auto;
}
.row__column { grid-column: 1 / -1; min-width: 0; }

/* Mobile: one column. The 12-track grid can't collapse below 768 — 11 × 40px
   of column-gap alone exceeds the viewport, which overflows the document. */
@media (max-width: 767px) {
  .row__grid { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
}

@media (min-width: 768px) {
  .row__column { grid-column: span var(--span, 12); }
}

/* Single-column rows: the column box dissolves so its blocks become grid items
   of .row__grid directly, and each block can be placed on the 12-col grid
   individually. That's what lets text hold the spine while media goes wide
   inside the same row. Row gap is zeroed — block margins carry the rhythm. */
.row--cols-1 .row__column { display: contents; }
.row--cols-1 .row__grid { row-gap: 0; }
.row--cols-1 .block { grid-column: var(--spine); min-width: 0; }

/* The measure is capped independently of the grid. Above 1440 the spine widens
   with --width-wide (to ~800px at 2200), which would push body copy back to
   ~89 characters — so text stops at --width-text and the extra column space
   becomes margin. The left edge holds; only the right edge stops growing. */
.row--cols-1 .block:not(.block--media) { max-width: var(--width-text); }

/* Width: `auto` — text on the spine, media escapes to full grid width (default) */
.row--auto.row--cols-1 .block--media { grid-column: 1 / -1; }

/* Width: `text` — everything on the spine, media included */
.row--text.row--cols-1 .block { grid-column: var(--spine); }

/* Width: `wide` — everything full grid width */
.row--wide.row--cols-1 .block { grid-column: 1 / -1; }

/* Multi-column rows set to `text`: the columns divide the spine rather than the
   full grid, so a 1/2 + 1/2 text row still reads at the page's measure.
   Percentages are the spine's offset and width as a proportion of --width-wide
   (291.5 / 1126 and 640 / 1126); the fixed column-gap makes them drift by ~2px
   between 768 and 1126, which is below the threshold of visible misalignment. */
@media (min-width: 768px) {
  .row--text:not(.row--cols-1) .row__grid {
    width: 56.84%;
    max-width: var(--width-text);
    margin-inline-start: 25.89%;
  }
}

/* Block rhythm ---------------------------------------------------------------- */

.block + .block                 { margin-top: var(--space-7); }
.block + .block--h2             { margin-top: var(--space-11); }
.block + .block--h3             { margin-top: var(--space-7); }
.block + .block--h4             { margin-top: var(--space-6); }
.block + .block--h5,
.block + .block--h6             { margin-top: var(--space-6); }
.block--h4 + .block             { margin-top: var(--space-4); }
.block--h5 + .block,
.block--h6 + .block             { margin-top: var(--space-3); }
.block--h2 + .block             { margin-top: var(--space-6); }
.block + .block--media,
.block--media + .block          { margin-top: var(--space-9); }
.block + .block--quote,
.block + .block--metric         { margin-top: var(--space-9); }

/* Chapter break (blocks/chapter.php) ---------------------------------------------
   Between the summary at the top of a case study (recap, result) and the
   story: a full-width line, then the label in the margin column, the title
   and reading time on the text column, the section index under them. A
   change of part, so the largest gap on the page sits on both sides of it. */
.row--cols-1 .block.block--chapter { grid-column: 1 / -1; max-width: none; } /* beats the text-width cap */
.block--chapter { padding-top: var(--space-section-lg); }
.block--chapter:first-child { padding-top: 0; }
.row:has(.block--chapter:first-child) { margin-top: var(--space-section-lg); }
.block + .block--chapter { margin-top: 0; }
.block--chapter + .block,
.block--chapter + .block--section-num { margin-top: var(--space-section-lg); }
.row:has(.block--chapter:last-child) + .row { margin-top: var(--space-section-lg); }

.chapter {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4) var(--grid-gap);
}
@media (min-width: 768px) {
  .chapter { grid-template-columns: repeat(12, minmax(0, 1fr)); }
}
.chapter__rule {
  grid-column: 1 / -1;
  margin: 0 0 var(--space-8);
  border: 0;
  border-top: 1px solid var(--color-border-strong);
}
.chapter__label {
  grid-column: var(--margin-col);
  font-size: var(--text-caption);
  font-weight: var(--weight-medium);
  line-height: 1.3;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-subtle);
}
.chapter__head { grid-column: var(--spine); }
.chapter__title {
  font-family: var(--font-serif);
  font-size: var(--text-display-m);
  font-weight: var(--weight-regular);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--color-text);
}
.chapter__meta { margin-top: var(--space-4); color: var(--color-text-muted); }
.chapter__index { margin-top: var(--space-6); }
@media (min-width: 1024px) {
  .chapter__label { padding-top: 1.4em; } /* level with the title's capitals */
}

/* Section numbers (Chapter break with its index on): in the margin column, on the
   heading's row and with the heading's spacing above it. Below 1024 there is
   no margin column, so it sits just above the heading. */
.row--cols-1 .block--section-num { grid-column: var(--margin-col); }
.block + .block--section-num { margin-top: var(--space-11); }
.block--section-num + .block--h2 { margin-top: var(--space-2); }
.block--h2 { scroll-margin-top: var(--space-9); } /* contents links land with some air above */
@media (min-width: 1024px) {
  .block--section-num { padding-top: 0.9em; } /* level with the heading's first line */
  .block + .block--section-num + .block--h2 { margin-top: var(--space-11); }
  .block--chapter + .block--section-num + .block--h2 { margin-top: var(--space-section-lg); }
  .block--section-num:first-child + .block--h2 { margin-top: 0; }
}

/* Headings / text / list ---------------------------------------------------- */

.block--heading h1,
.block--heading h2 {
  font-family: var(--font-serif);
  font-size: var(--text-h2);
  line-height: var(--leading-heading);
}
/* Sans headings, all Medium like the Figma paragraph styles; the levels step
   down in size, then switch to caption labels so h5/h6 still read as headings
   rather than as short paragraphs. */
.block--heading h3,
.block--heading h4,
.block--heading h5,
.block--heading h6 {
  font-weight: var(--weight-medium);
  color: var(--color-text);
}
.block--heading h3 { font-size: var(--text-h3);      line-height: 1.3; }  /* 18 → 20 */
.block--heading h4 { font-size: var(--text-reading); line-height: 1.35; } /* 16 → 18 */
.block--heading h5,
.block--heading h6 {
  font-size: var(--text-caption);
  line-height: 1.3;
  color: var(--color-text-muted);
}
.block--heading h5 { text-transform: uppercase; letter-spacing: 0.06em; }

/* Bold toggled on in the Panel's heading editor mustn't override the heading's
   own weight (browsers render <strong> as 700). */
.block--heading :is(strong, b) { font-weight: inherit; }

.block--text,
.block--list {
  font-size: var(--text-reading);
  line-height: var(--leading-reading);
  color: var(--color-text-body);
}
.block--text p + p,
.block--list + .block--list { margin-top: var(--space-paragraph); }
.block--text a,
.block--list a { text-decoration: underline; text-underline-offset: 0.15em; }
.block--text strong,
.block--list strong { font-weight: var(--weight-semibold); color: var(--color-text); }
.block--list ul,
.block--list ol { padding-left: 1.5em; }

.block--line hr { border: 0; border-top: 1px solid var(--color-border); }

/* Media ------------------------------------------------------------------------- */

.media .picture,
.media__video,
.media__embed {
  width: 100%;
  border-radius: var(--radius-media);
  background: var(--color-placeholder);
  object-fit: cover;
  overflow: hidden;
}
.media__embed { aspect-ratio: 16 / 9; }
.media__embed iframe { width: 100%; height: 100%; border: 0; }

.gallery {
  display: grid;
  gap: var(--space-8) var(--grid-gap);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 768px) {
  .gallery { grid-template-columns: repeat(var(--columns, 2), minmax(0, 1fr)); }
}

/* Full-width images --------------------------------------------------------------
   One to three images across the page width (blocks/fullwidth.php): out of
   the project column to the same margins and 1800px cap as the home page,
   or edge to edge. Only from a single-column row; in a column it stays a
   plain image set. --page-w is the page width without the scrollbar
   (main.js), so the breakout lines up exactly with the screen edges. */
.row--cols-1 .block--fullwidth { grid-column: 1 / -1; }
.row--cols-1 .fullwidth {
  margin-inline: calc(50% - var(--page-w) / 2);
  padding-inline: var(--gutter-full);
}
.row--cols-1 .fullwidth--bleed { padding-inline: 0; }

.fullwidth__grid {
  display: grid;
  gap: var(--gap-media);
  max-width: var(--width-full);
  margin-inline: auto;
}
.fullwidth--bleed .fullwidth__grid { max-width: none; }
.fullwidth .picture {
  display: block;
  width: 100%;
  border-radius: var(--radius-media);
  background: var(--color-placeholder);
}
.fullwidth--bleed .picture { border-radius: 0; }
/* Phones: one image per row. Wider: side by side, sharing one height (the
   tallest decides, the others crop to fill) */
@media (min-width: 768px) {
  .fullwidth--two .fullwidth__grid        { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fullwidth--wide-left .fullwidth__grid  { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .fullwidth--wide-right .fullwidth__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  .fullwidth--three .fullwidth__grid      { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .fullwidth__grid > * { height: 100%; } /* the image, or the gallery button around it */
  .fullwidth__grid .picture { height: 100%; object-fit: cover; }
}
.fullwidth__caption { max-width: var(--width-full); margin: var(--space-3) auto 0; }
.fullwidth--bleed .fullwidth__caption { max-width: none; padding-inline: var(--gutter-full); }
/* A run of full-width blocks in the same row sits one gap apart: one grid */
.block--fullwidth + .block--fullwidth { margin-top: var(--gap-media); }

/* Quote ------------------------------------------------------------------------ */

.quote__text {
  font-family: var(--font-serif);
  font-size: var(--text-quote);
  line-height: var(--leading-heading);
}
.quote .caption { margin-top: var(--space-5); }

/* Metric ----------------------------------------------------------------------- */

.metric {
  padding: var(--space-6) var(--space-5);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-card);
  text-align: center;
}
.metric__value {
  font-family: var(--font-serif);
  font-size: var(--text-metric);
  line-height: var(--leading-heading);
}

/* Media + text ------------------------------------------------------------------ */

.media-text {
  display: grid;
  gap: var(--space-6) var(--grid-gap);
  align-items: center;
}
.media-text .picture { width: 100%; border-radius: var(--radius-media); background: var(--color-placeholder); }
.media-text__heading {
  font-family: var(--font-serif);
  font-size: var(--text-h2);
  line-height: var(--leading-heading);
  margin-bottom: var(--space-5);
}
@media (min-width: 768px) {
  .media-text { grid-template-columns: 1fr 1fr; }
  .media-text--image-right .media-text__media { order: 2; }
}

/* Slider --------------------------------------------------------------------
   One shared height, natural proportions, horizontal snap. Heights are fluid
   and capped at 38vw so even a 2:1 slide stays at ~76% of a phone screen and
   the next one peeks in: that edge is the "there's more" signal. */
.slider { --slider-h: clamp(14rem, 9rem + 18vw, 26rem); }      /* ~224 → 416 */
.slider--small { --slider-h: clamp(11rem, 7rem + 12vw, 18rem); } /* ~176 → 288 */
.slider--large { --slider-h: clamp(18rem, 11rem + 26vw, 34rem); } /* ~288 → 544 */
/* Extra large: a 2:1 slide takes ~88% of the width (the next still peeks
   in), capped by the screen height so a slide always fits on screen */
.slider--xl { --slider-h: min(44vw, 80svh); }

.slider__track {
  position: relative; /* offsetLeft of slides is measured from here (main.js) */
  display: flex;
  gap: var(--space-5);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none; /* buttons, swipe, trackpad and arrow keys do the scrolling */
}
.slider__track::-webkit-scrollbar { display: none; }
.slider__track:focus-visible { outline-offset: 6px; border-radius: var(--radius-media); }
/* Drag to slide (main.js, mouse only). Snap is off while dragging so the row
   follows the pointer; it comes back on release, when JS settles on a slide. */
@media (hover: hover) and (pointer: fine) {
  .slider__track { cursor: grab; }
  .slider__track .lightbox-trigger { cursor: inherit; }
}
.slider__track.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  user-select: none;
}
.slider__track.is-dragging .lightbox-trigger { cursor: grabbing; }
.slider__track.is-settling { scroll-snap-type: none; } /* gliding to a slide after a drag (main.js) */

/* Full bleed: in a single-column row the track runs edge to edge of the
   screen, while padding (and snap padding) keep the first slide on the
   grid's left edge. Slides leave at the screen edge instead of being sliced
   off mid-page. Needs the slider centred, so it always takes the full grid
   there; in multi-column rows it stays inside its column. */
.row--cols-1 .block--slider { grid-column: 1 / -1; }
.row--cols-1 .slider__track {
  /* Distance from the grid edge to the screen edge, without percentages:
     scroll-padding resolves % against the (now screen-wide) track, padding
     against its parent, so a % formula would give two different numbers. */
  --bleed: max(var(--gutter), (var(--page-w) - var(--width-wide)) / 2);
  --start: var(--bleed); /* where the first slide sits, from the screen edge */
  margin-inline: calc(var(--bleed) * -1);
  padding-inline: var(--start);
  scroll-padding-inline: var(--start);
}

/* Start: Full width puts the first slide on the full-width images' margin
   (and the arrows on its right edge); Edge to edge on the screen edge, with
   square corners. Slides then sit one media gap apart, like those images. */
.row--cols-1 .slider--page .slider__track { --start: max(var(--gutter-full), (var(--page-w) - var(--width-full)) / 2); }
.row--cols-1 .slider--bleed .slider__track { --start: 0px; }
.row--cols-1 :is(.slider--page, .slider--bleed) .slider__track { gap: var(--gap-media); }
.row--cols-1 :is(.slider--page, .slider--bleed) .slider__controls {
  margin-inline: calc(50% - var(--page-w) / 2);
  padding-inline: max(var(--gutter-full), (var(--page-w) - var(--width-full)) / 2);
}
.slider--bleed .slider__slide .picture { border-radius: 0; }

.slider__slide {
  flex: none;
  scroll-snap-align: start;
}
.slider__slide .picture {
  width: auto;
  max-width: none;
  height: min(var(--slider-h), 38vw);
}
.slider--xl .slider__slide .picture { height: var(--slider-h); }

.slider__controls {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-4);
}
.slider__button {
  width: var(--control-height);
  padding: 0;
}
.slider__button:disabled { opacity: 0.35; cursor: default; }
.slider__button:disabled:hover { border-color: var(--color-border-strong); }
@media (max-width: 767px) {
  .slider__button { width: 2.75rem; min-height: 2.75rem; }
}
