/*
  Case study template - shared by every /work/<slug>/ page. See ARCHITECTURE.md §6
  for the content model these classes map to (hero, meta, narrative, gallery, next).
*/

/* ---------- 1. Hero ---------- */

.project-hero {
  padding-block-start: var(--space-7);
}

.project-hero__title {
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-regular);
  margin-block: var(--space-4) var(--space-3);
  max-width: 20ch;
}

.project-hero__desc {
  font-size: var(--font-size-lg);
  color: var(--color-text-muted);
  max-width: 60ch;
  margin-block-end: var(--space-7);
}

.project-hero__image {
  /* Full aspect ratio, never cropped - height follows the image's own natural
     proportions, capped so the whole photo reads on screen without scrolling
     rather than running taller than the viewport. object-fit:contain is the
     letterboxing safety net for whenever max-height is the binding constraint on a
     tall/portrait shot. */
  display: block;
  width: 100%;
  height: auto;
  max-height: var(--media-max-h);
  object-fit: contain;
  /* The hero has no wrapper element, so the sheet goes on the image. box-sizing is
     border-box globally (reset.css), so this padding shrinks the picture inside its
     own width and the stock shows around it. */
  margin-inline: auto;
}

/* Same rule as the gallery: a cut-out hero floats. */
.project-hero__image--cutout {
  padding: 0;
  background: none;
  box-shadow: none;
}


/* ---------- 2. Meta / credits ---------- */

.project-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-6);
  padding-block: var(--space-7);
  margin-block: var(--space-8);
  border-block: 1px solid var(--color-border);
}

.project-meta dt {
  font-size: var(--font-size-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-label);
  color: var(--color-text-muted);
  margin-block-end: var(--space-2);
}

.project-meta dd {
  font-size: var(--font-size-base);
  line-height: var(--line-height-snug);
}

.project-meta dd a {
  color: var(--color-text);
  text-decoration: underline;
  text-decoration-color: var(--color-accent);
  text-underline-offset: 0.2em;
}

/* ---------- 3. Narrative ---------- */

.project-narrative {
  max-width: var(--container-text);
  margin-inline: auto;
  padding-block: var(--space-6);
}

.project-narrative + .project-narrative {
  padding-block-start: 0;
}

.project-narrative h2 {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-regular);
  margin-block-end: var(--space-4);
}

.project-narrative p {
  color: var(--color-text-muted);
  margin-block-end: var(--space-5);
}

.project-narrative p:last-child {
  margin-block-end: 0;
}

/* ---------- 4. Gallery ---------- */

.project-gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--space-5);
  row-gap: var(--space-9);
  padding-block: var(--space-9);
}

/* Plates alternate sides and never run edge to edge, so the gallery reads as loose
   pinned prints rather than a contact sheet. */
.project-gallery__item {
  grid-column: 1 / 8;
  align-self: start;
}

.project-gallery__item:nth-child(even) {
  grid-column: 7 / -1;
  margin-block-start: var(--space-9);
}

.project-gallery > .project-gallery__item--wide {
  grid-column: 2 / 12;
  margin-block-start: 0;
}

/*
  Gallery plates sit on the same bone stock as everything else on the site. The sheet
  goes on the wrapper rather than the image so the padding reads as a margin of paper
  around the print.
*/
.project-gallery__item {
  padding: 0;
}

/*
  Artwork that carries its own silhouette gets no sheet. A cut-out was cut out
  precisely so it would not sit in a rectangle, and putting one back behind it undoes
  the whole point. The modifier is stamped from the file's actual alpha channel, not
  by eye.
*/
.project-gallery__item--cutout {
  padding: 0;
  background: none;
  box-shadow: none;
}

.project-gallery img {
  display: block;
  width: 100%;
  height: auto;
  max-height: var(--media-max-h);
  object-fit: contain;
  margin-inline: auto;
}

@media (max-width: 768px) {
  .project-gallery {
    row-gap: var(--space-8);
  }

  .project-gallery__item,
  .project-gallery__item:nth-child(even),
  .project-gallery > .project-gallery__item--wide {
    grid-column: 1 / -1;
    margin-block-start: 0;
  }
}

/* ---------- 5. Editorial case study ("cs") ----------
   An alternative to the narrative-then-gallery structure above, for case studies
   where the artifacts ARE the argument (a UX/UI project, where a screenshot of the
   thing is the evidence for the claim next to it). Instead of a wall of copy
   followed by a grid of loose images, each chapter pairs one idea with the one
   artifact that proves it, and every screenshot carries a caption saying what
   decision it shows. Used by work/pacific-outdoor-living/; the classic
   .project-narrative/.project-gallery structure above still serves the other
   case studies. */

.cs-chapter {
  padding-block: clamp(var(--space-8), 8vh, var(--space-9));
  border-block-start: 1px solid var(--color-border);
}

.cs-chapter:first-of-type {
  border-block-start: 0;
}

/* Deep links from the work index land on a section, and the header would otherwise
   sit on top of the heading they landed on. Roughly header height plus a breath.
   Covers both page structures: the editorial chapters and the classic narrative
   sections, since either can be a deep-link target. */
.cs-chapter[id],
.project-narrative[id] {
  /* Has to clear the 80px sticky header (was 155px, see components.css). A chapter's
     own generous top padding absorbs most of this, but .project-narrative only pads
     32px, so too small an offset lands its heading UNDER the header. Sized for the
     tighter of the two rather than per-section, so a new deep-link target can't
     reintroduce it. */
  scroll-margin-top: calc(var(--space-8) + var(--space-4));
}

/* Narrow measure for reading - deliberately NOT the full container width, so the
   copy stays a column and the artifacts below it read as wider than the text. */
.cs-chapter__lede {
  max-width: 56ch;
  margin-block-end: var(--space-7);
}


.cs-chapter__lede h2 {
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-tight);
  max-width: 18ch;
  margin-block-end: var(--space-5);
}

.cs-chapter__lede p {
  color: var(--color-text-muted);
}

.cs-chapter__lede p + p {
  margin-block-start: var(--space-4);
}

/* An index list inside a lede, set as hairline-separated rows so it reads like a
   catalog of requirements rather than a bulleted list. */
.cs-chapter__lede ul {
  margin-block-start: var(--space-5);
  padding-inline-start: 0;
  list-style: none;
  color: var(--color-text-muted);
}

.cs-chapter__lede li {
  padding-block: var(--space-3);
  border-block-start: 1px solid var(--color-border);
}

/* Every screenshot gets the same treatment - a bordered "screen" on a tinted
   ground - so a page built almost entirely from screenshots reads as one system
   instead of a pile of unrelated pictures. Square corners on purpose. */
.cs-figure {
  margin: 0;
}

/* Capped to the viewport, like every other full-size artifact on the site. This rule
   was the one that wasn't, and it showed: a portrait photo at full container width
   rendered 1749px tall on a 900px screen, so you scrolled through a picture instead
   of looking at one.

   `object-fit: contain` rather than shrinking the element, because these figures sit
   in aligned pairs. Letting the element shrink would leave the two halves of a pair
   at different widths. Instead the box keeps its place and a tall image mats itself
   against its own ground, which is the same thing the hero and the gallery plates
   already do. Still never cropped.

   The separation from the paper comes from a contact shadow, not from a hairline box.
   These used to carry a 1px border on a flat tint, which put every screenshot on
   every case study inside a frame: a card by another name, and the one treatment the
   brief rules out. A shadow tinted to the oat does the same job of telling a pale
   screenshot apart from the paper behind it, and it does it by putting the sheet ON
   the paper rather than in a box. Same vocabulary as .object in components.css. */
.cs-figure img,
.cs-figure video {
  display: block;
  width: 100%;
  height: auto;
  max-height: var(--media-max-h);
  object-fit: contain;
}

/* Artwork with a transparent background. The sheet treatment exists to make a pile of
   screenshots read as one system; a cut-out logo doesn't need it and looks better
   sitting straight on the paper, which is the whole point of cutting the background
   off in the first place. A contact shadow on a shape with no edge just fogs the
   paper around it. */
.cs-figure--cutout img,
.cs-figure--cutout video {
  background: none;
  box-shadow: none;
}

/* A figure standing on its own, rather than one half of a pair, lets the box shrink
   to the picture instead of matting it. Matting is the right answer inside a pair,
   where both halves have to stay the same width and aligned to the column. On a solo
   plate it strands a portrait photo in the middle of a 1300px field of paper, and it
   upscales a 960px video to fill a width it doesn't have the pixels for. */
.cs-chapter > .cs-figure img,
.cs-chapter > .cs-figure video {
  width: auto;
  max-width: 100%;
  margin-inline: auto;
}

.cs-figure figcaption {
  margin-block-start: var(--space-3);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-snug);
  color: var(--color-text-muted);
  max-width: 60ch;
}

.cs-figure figcaption b {
  color: var(--color-text);
  font-weight: 600;
}

/* Artifacts that were never full-bleed to begin with. The BRTR style tile is only
   802px square at source, so running it the full width of the container upscaled it
   ~1.6x and made a crisp thing look soft. Capping it keeps it near 1:1 and, as a
   bonus, a square held at two-thirds width reads as a specimen rather than a
   screenshot. Use this for anything small and self-contained, not for screens. */
.cs-figure--inset {
  max-width: 720px;
}

/* Figure groupings.

   Capped rather than full-bleed. Two screenshots side by side across a 1312px
   container come out ~640px each, and stacked pairs of tall page captures turned the
   back half of a case study into a wall of enormous images with the copy lost between
   them. At 1000px they're ~480 each: still legible as designs, and the page gets a
   right-hand margin that matches the narrow measure of the ledes above. */
.cs-figures {
  display: grid;
  gap: var(--space-7);
  max-width: 1000px;
}

.cs-figures--pair {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6);
}

/* Lineups of cut-out products (Pate bottles, Apple Park packages): standing on one
   baseline, so align to the bottom rather than the top. */
.cs-figures--trio,
.cs-figures--quad {
  gap: var(--space-6);
  align-items: end;
}

.cs-figures--trio { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cs-figures--quad { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.cs-figures--trio .cs-figure img,
.cs-figures--quad .cs-figure img {
  max-height: min(60vh, 560px);
  filter: drop-shadow(0 22px 20px rgb(40 40 36 / 0.25));
}

/* Consecutive figure blocks inside one chapter had NO space between them: `gap` only
   separates a grid's own children, not one grid from the next. A caption and the
   plate below it were touching.

   The `.cs-chapter >` child combinator is load-bearing, not decoration. Without it
   these rules also hit figures nested INSIDE a .cs-figures grid - the two halves of
   a pair are adjacent siblings too, so the right-hand plate picked up 72px of top
   margin and hung below its partner. Anything inside a .cs-figures is spaced by that
   grid's own `gap` and must never get a margin on top of it. */
.cs-chapter > .cs-figures + .cs-figures,
.cs-chapter > .cs-figure + .cs-figures,
.cs-chapter > .cs-figures + .cs-figure,
.cs-chapter > .cs-figure + .cs-figure,
.cs-chapter > .cs-devices + .cs-figures,
.cs-chapter > .cs-figures + .cs-devices {
  margin-block-start: var(--space-8);
}

/* Phone screenshots: a row of devices, narrower than the desktop artifacts so the
   change in viewport is legible at a glance rather than needing a caption. */
.cs-devices {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
  max-width: 860px;
}

/* The phone shots needed their own hairline back when figures were borderless on a
   tint. They inherit the sheet treatment now, so a second edge on top of it just
   reads as a stray outline. */

/* Results band - the numbers are the climax of the story, so they get their own
   full-bleed moment in ink rather than being a sentence in a paragraph. (This was
   brand red until the wabi-sabi pass; a red field that size overpowered a page whose
   whole argument is restraint, so red retreated to seal-sized marks.) */
.cs-results {
  background: var(--color-ink);
  color: var(--color-ink-text);
}

.cs-results__inner {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-8);
  padding-block: var(--space-9);
}

.cs-stat__label {
  font-size: var(--font-size-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-label);
  opacity: 0.75;
  margin-block-end: var(--space-4);
}

.cs-stat__value {
  font-family: var(--font-family-brand);
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-tight);
  margin-block-end: var(--space-3);
}

.cs-stat__note {
  font-size: var(--font-size-sm);
  opacity: 0.85;
  max-width: 34ch;
}

@media (max-width: 900px) {
  .cs-figures--pair,
  .cs-results__inner {
    grid-template-columns: 1fr;
  }

  .cs-figures--trio,
  .cs-figures--quad {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .cs-results__inner {
    gap: var(--space-7);
  }
}

@media (max-width: 600px) {
  .cs-devices {
    grid-template-columns: 1fr;
    max-width: 320px;
  }
}

/* ---------- 7. Next project ---------- */

.project-next {
  border-top: 1px solid var(--color-border);
  padding-block: var(--space-8);
  margin-block-start: var(--space-6);
}

.project-next__label {
  display: block;
  margin-block-end: var(--space-2);
}

.project-next__title {
  font-family: var(--font-family-brand);
  font-size: var(--font-size-2xl);
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}

.project-next a {
  display: inline-block;
}

.project-next a:hover .project-next__title::after {
  transform: translateX(6px);
}

.project-next__title::after {
  content: '→';
  transition: transform var(--duration-short) var(--ease-default);
}

/* ---------- Click-to-load prototype embed ---------- */
/* Behaviour and the reasoning behind the facade live in
   assets/js/components/embed.js. This is just its clothes. */

/* At rest this is a band, not a screen. Holding the full 16:10 before anything has
   loaded leaves ~800px of flat tint around four lines of type, which reads as a
   broken image rather than an invitation. It grows to prototype proportions once
   there's a prototype in it. */
.cs-embed__frame {
  position: relative;
  min-height: clamp(280px, 34vh, 380px);
  border: 1px solid var(--color-border);
  background-color: var(--color-surface);
  background-image: var(--texture-scan);
  background-size: var(--texture-scan-size);
  background-blend-mode: multiply;
  overflow: hidden;
  transition: min-height var(--duration-medium) var(--ease-default);
}

.cs-embed__frame[data-embed-state='live'] {
  aspect-ratio: 16 / 10;
  /* Same ceiling as every other artifact: a prototype you have to scroll to see the
     top and bottom of is worse than a slightly wider-than-16:10 one. */
  max-height: var(--media-max-h);
}

/* The resting state: a quiet panel, no preview image. A cropped screenshot behind
   this would fight its own caption and break the page's one rule about never
   cropping an artifact, so the panel stays typographic. */
.cs-embed__facade {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-6);
  text-align: center;
}

.cs-embed__label {
  font-size: var(--font-size-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-label);
  color: var(--color-text-muted);
}

.cs-embed__title {
  margin: 0;
  font-family: var(--font-family-display);
  font-size: var(--font-size-2xl);
  font-weight: 400;
  line-height: var(--line-height-snug);
  max-width: 20ch;
}

.cs-embed__play {
  margin-block-start: var(--space-2);
}

.cs-embed__note {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  max-width: 40ch;
}

.cs-embed__note a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.cs-embed__iframe {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Figma's player has its own minimum before it starts hiding its controls, and a
   16:10 box on a phone is a letterbox. Taller and narrower suits it better there. */
@media (max-width: 700px) {
  .cs-embed__frame[data-embed-state='live'] {
    aspect-ratio: 3 / 4;
  }
}
