/* ---- Editorial layout modules ----
   Reusable image/text section patterns used across multiple pages (Melody
   House, Our Story, Architectural Design, and the Journal article page) —
   moved out of project-detail.css, which only ever held the truly
   project-page-specific pieces (the intro fact-list, the Melody House
   panel-sequence crops, the Values sequence) alongside these. Splitting them
   out is a pure file move: no selector or value changed, so every existing
   page's rendered output is unaffected. Load this file before
   project-detail.css/pages/*.css so any page-scoped overrides of these
   classes (e.g. body.project-page's own .editorial-duo gap override) still
   win on selector specificity, as they already did. */

/* Editorial Image + Text Module — asymmetric split */
.editorial-module {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  align-items: stretch;
}

@media (min-width: 1024px) {
  .editorial-module {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-16);
    align-items: start;
  }
}

.editorial-image {
  width: 100%;
  display: block;
  object-fit: cover;
  aspect-ratio: 4 / 5;
}

/* --landscape/--tall keep their desktop crop at every width. These are
   deliberately composed crops chosen per-image (a stone entry portico, a
   hallway, etc.) — not a mobile-only accommodation like Editorial Module
   1's old text-overlay workaround below — so unlike that case there's no
   separate mobile-specific ratio to preserve; the modifier's ratio now just
   applies unconditionally instead of only from 768px up. */
.editorial-image--landscape {
  aspect-ratio: 16 / 9;
}

.editorial-image--landscape.editorial-image--tall {
  aspect-ratio: 4 / 3;
}

/* Feature variant — wider image column, text bottom-anchored against the
   image's own bottom edge with generous whitespace above it (rather than
   top-aligned like the default module). Mirrors an editorial reference
   layout; only the placement is borrowed — type, colour and sizing stay on
   the standard brand tokens via .eyebrow/.heading-h3/.editorial-text. */
@media (min-width: 1024px) {
  .editorial-module--feature {
    grid-template-columns: 3fr 2fr;
    align-items: end;
  }

  .editorial-module--feature .editorial-text-block {
    max-width: 24rem;
  }
}

/* Reverse variant — mirrors a module's column order (image/text swap sides)
   without touching the base layout rules those modules share with other
   pages. Scoped as an additive modifier so it can be dropped onto a single
   instance of .editorial-module (e.g. one page's copy of --feature) while
   every other instance of the same base class stays unaffected. Works in
   both the mobile flex stack and the desktop grid, since `order` applies to
   flex and grid children alike. */
.editorial-module--reverse > *:first-child {
  order: 2;
}

.editorial-module--reverse > *:last-child {
  order: 1;
}

/* `order` only changes which grid cell each child lands in — it doesn't
   move the column track sizes with it, so without this the image would
   land in --feature's narrower 2fr track instead of keeping the wider 3fr
   one it had on the left. Swapping the track sizes here keeps the image at
   its original size now that it's on the right. */
@media (min-width: 1024px) {
  .editorial-module--feature.editorial-module--reverse {
    grid-template-columns: 2fr 3fr;
    align-items: center;
  }

  /* On the non-reversed layout, the text block's column IS the right
     column, so its default start-alignment already sits it flush against
     the gap next to the image. Reversed, that same column is now on the
     left, so start-alignment leaves it flush against the far-left edge
     instead — pushing it away from the image. Aligning it to the end of
     its column here pulls it back over next to the image, mirroring the
     non-reversed spacing. */
  .editorial-module--reverse .editorial-text-block {
    justify-self: end;
  }
}

/* Asymmetric variant — narrow text column (auto-sized to its own capped
   content width) beside a portrait image, text vertically centred against
   the image. No justify-content centring here deliberately — both columns
   are pinned to start at the grid's own start edge, so resizing the image
   column (e.g. to make the image bigger) only grows it further right and
   never shifts the text's position. Image stays capped (not full-width) on
   mobile too; the cap lifts once the grid takes over at 768px and the
   image column governs its width instead. */
.editorial-module--4-8 .editorial-image {
  max-width: 22rem;
}

/* Text + small image stack in the left column — text on top, a small
   secondary image below it, both left-aligned against the grid's start
   edge (see align-items: start below). */
.editorial-module--4-8__stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.editorial-module--4-8__stack .editorial-text {
  margin-top: var(--space-4);
}

.editorial-module--4-8__small-image {
  max-width: 24rem;
  margin-top: auto;
}

@media (min-width: 768px) {
  .editorial-module--4-8 {
    display: grid;
    grid-template-columns: auto 50%;
    gap: var(--space-8);
    align-items: stretch;
  }

  .editorial-module--4-8 .editorial-text-block {
    max-width: 24rem;
  }

  .editorial-module--4-8 .editorial-image {
    max-width: none;
  }
}

@media (min-width: 1024px) {
  .editorial-module--4-8 {
    gap: var(--space-16);
  }
}

.editorial-heading {
  margin-bottom: var(--space-6);
}

.editorial-text {
  color: var(--color-text-muted);
  line-height: var(--line-height-relaxed);
  margin-bottom: var(--space-6);
}

/* Story Module — eyebrow, lede paragraph, and a two-column body split,
   beside a media column. Uses the site's 12-column grid directly (.grid on
   the wrapper + .col-span-6 on both media and content in the HTML) rather
   than a bespoke flex split — media is deliberately 6/12 columns. */
.editorial-story {
  gap: var(--space-8);
}

@media (min-width: 768px) {
  .editorial-story {
    gap: var(--space-16);
  }
}

.editorial-story__media img {
  width: 100%;
  display: block;
  object-fit: cover;
  aspect-ratio: 4 / 5;
}

/* Compact variant — for a graphic (e.g. an SVG map) rather than a full-bleed
   photo: sized to its own natural proportions and capped narrower than the
   column, instead of being stretched/cropped to fill it edge-to-edge like a
   photograph. */
.editorial-story__media--compact img {
  width: 100%;
  max-width: 20rem;
  aspect-ratio: 340 / 283;
  object-fit: contain;
}

/* Content column deliberately left to the grid's default align-items:
   stretch (no override here) so its box matches the media column's full
   height — that's what lets .editorial-story__columns below grow to reach
   the image's bottom edge. */
.editorial-story__content {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-6);
}

.editorial-story__columns {
  display: grid;
  /* Same paragraph-to-paragraph spacing as .prose — below 768px this grid
     is still a single stacked column, so the two <p>s read as continuous
     body copy, not side-by-side columns yet. */
  gap: var(--space-4);
  margin-top: var(--space-4);
}

@media (min-width: 768px) {
  .editorial-story__columns {
    grid-template-columns: 1fr 1fr;
    /* Now an inter-column gutter rather than a paragraph gap. */
    gap: var(--space-16);
    /* Grows to fill the rest of the (now image-height-tall) content
       column, so the "end" alignment below has room to push the second
       paragraph down to the image's bottom edge. */
    flex: 1;
  }

  .editorial-story__columns > :last-child {
    align-self: end;
  }

  /* Matches one .editorial-story__columns track exactly: half the shared
     width minus half the same gap those columns use. */
  .editorial-story__content .editorial-heading {
    max-width: calc(50% - (var(--space-16) / 2));
  }
}

/* Duo Module — heading + tall image stack in the left grid column; the
   right column's image is the grid row's sibling, so its top edge starts
   level with the heading (not the tall image below it), and it stretches
   (grid's default align-items: stretch) to match the left column's full
   combined height — heading, gap, and tall image together. */
.editorial-duo__grid {
  display: grid;
  gap: var(--space-8);
}

@media (min-width: 1024px) {
  .editorial-duo__grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-16);
  }
}

.editorial-duo__primary {
  display: flex;
  flex-direction: column;
  gap: var(--space-40);
}

.editorial-duo__intro {
  max-width: 24rem;
  margin-top: var(--space-6);
}

.editorial-duo__intro .editorial-text {
  margin-top: var(--space-4);
}

.editorial-duo__media--tall img {
  width: 100%;
  display: block;
  object-fit: cover;
  aspect-ratio: 4 / 4;
}

.editorial-duo__secondary {
  display: flex;
  flex-direction: column;
  gap: var(--space-40);
  height: 100%;
}

.editorial-duo__secondary-media {
  flex: 1;
  min-height: 20rem;
}

.editorial-duo__secondary-media img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.editorial-duo__secondary p {
  max-width: 26rem;
}

/* Offset Pair Module — small image bottom-left, large image right. Mirrors
   project-grid.css's Row 2 layout: an explicit grid-column start on the
   large image skips a track, leaving a deliberate empty gap, and
   align-self: end bottom-aligns the small image with the larger one.
   Images reuse .editorial-image's own aspect-ratio rules (default portrait
   / --landscape 4:3) — no new ratio values needed here. */
.editorial-offset {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--space-8);
}

@media (min-width: 1024px) {
  .editorial-offset {
    gap: var(--space-16);
  }
}

.editorial-offset__small,
.editorial-offset__large {
  grid-column: span 12;
}

@media (min-width: 768px) {
  .editorial-offset__small {
    grid-column: span 4;
    align-self: end;
  }

  .editorial-offset__small--top {
    align-self: start;
    margin-top: var(--space-6);
  }

  .editorial-offset__large {
    grid-column: span 8;
  }
}

@media (min-width: 1024px) {
  .editorial-offset__small {
    grid-column: span 3;
  }

  .editorial-offset__small--top {
    margin-top: var(--space-10);
  }

  .editorial-offset__large {
    grid-column: 6 / span 7;
  }
}

/* Reversed variant — large image left, small image right. order flips the
   768px tier's auto-placed span4/span8 pair (no explicit lines there to
   fight); 1024px+ needs explicit lines since .editorial-offset__large is
   already line-positioned and unaffected by order. */
@media (min-width: 768px) {
  .editorial-offset--reversed .editorial-offset__small {
    order: 2;
  }

  .editorial-offset--reversed .editorial-offset__large {
    order: 1;
  }
}

@media (min-width: 1024px) {
  .editorial-offset--reversed .editorial-offset__small {
    grid-column: 10 / span 3;
  }

  .editorial-offset--reversed .editorial-offset__large {
    grid-column: 1 / span 7;
  }
}

/* Image Row — two or three side-by-side images (.col-span-6 or
   .col-span-4), wider gap than the standard .grid (24px) reads as too
   tight between large photos with no text to separate them. Every other
   column drops down slightly once the row goes multi-column, so the
   images read as a staggered set rather than a rigid aligned strip. */
.editorial-image-row {
  gap: var(--space-8);
}

@media (min-width: 1024px) {
  .editorial-image-row {
    gap: var(--space-16);
  }
}

@media (min-width: 768px) {
  .editorial-image-row {
    align-items: start;
  }

  .editorial-image-row > :nth-child(2n) {
    margin-top: var(--space-10);
  }
}

@media (min-width: 1024px) {
  .editorial-image-row > :nth-child(2n) {
    margin-top: var(--space-16);
  }
}

/* Solo tall image — a single centred portrait-crop image, capped narrower
   than the full container so it reads as one deliberate tall moment rather
   than stretching edge to edge (used between two text sections, e.g. the
   Great Indoors article's indoor/outdoor corridor image). */
.article-solo-image {
  grid-column: 1 / -1;
  max-width: 26rem;
  margin-inline: auto;
}

@media (min-width: 1024px) {
  .article-solo-image {
    max-width: 32rem;
  }
}

.article-solo-image img {
  width: 100%;
  display: block;
  object-fit: cover;
  aspect-ratio: 4 / 5;
}

/* Full-Image Text Module — text overlaid on wide image */
.full-image-module {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.full-image-module--short {
  aspect-ratio: 21 / 9;
}

/* Gentler crop than the default 16:9 — for a wide transition image whose
   own composition (e.g. a cantilevered structure) needs more of its height
   kept than a strict 16:9 band allows. */
.full-image-module--gentle {
  aspect-ratio: 4 / 3;
}

/* Variants that carry overlay copy (.full-image-overlay) work differently
   below 1024px (desktop): rather than the text overlaying the image (and
   the image itself needing a taller, non-16:9 crop below desktop purely to
   leave the overlaid copy room to wrap without clipping — the original
   approach here), the text now sits in normal flow BELOW the image, in the
   page's normal heading colour, and the image keeps its true desktop 16:9
   crop at every width. That means the module itself can no longer be a
   single fixed-ratio, overflow-hidden box (it has to grow to fit the image
   *and* the stacked text below it on mobile/tablet) — the ratio + overflow
   mask move onto a dedicated inner .full-image-module__media wrapper
   instead, which also happens to be the correct [data-parallax] wrapper
   per CLAUDE.md's convention (contains only the image, nothing else).
   Scoped via :has() so plain image-only instances (no overlay, e.g. the
   journal gallery reuse — module wraps the <img> directly, no media
   wrapper) keep the original single-box behaviour untouched. */
.full-image-module:has(.full-image-overlay) {
  aspect-ratio: auto;
  overflow: visible;
}

.full-image-module__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}

.full-image-module img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Mobile/tablet (<1024px): plain stacked block below the image, spaced off
   it, no background/positioning tricks. */
.full-image-overlay {
  margin-top: var(--space-6);
}

.full-image-text {
  max-width: 100%;
}

/* Desktop (1024px+): reverts to the original overlay treatment — text
   absolutely positioned over the image (.full-image-module is still the
   positioning context; at this width the overlay contributes no flow
   height, so the module's own flow height ends up exactly matching the
   media wrapper's, which is what keeps the overlay pinned to the image's
   bounds without needing to reparent it onto the media wrapper directly),
   white text over a dark gradient for legibility against photography. */
@media (min-width: 1024px) {
  .full-image-overlay {
    position: absolute;
    inset: 0;
    margin-top: 0;
    display: flex;
    align-items: flex-start;
    padding: var(--space-12);
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 60%);
  }

  .full-image-text {
    max-width: 40%;
    color: var(--color-paper);
  }
}
