/* ============================================================
   HOMEPAGE SECTIONS: case studies, about, contact banner
   Sits below the hero. Depends on tokens declared in the hero's
   inline style block (--font-heading, --font-body, --ink,
   --body-ink) and on components.css for .label.

   GEOMETRY (from the 2x export at 1440):
   - Container: same as hero (max-width 1248, padding 24)
     -> content edge at x = 120 at 1440.
   - Section content is inset a further 48px per side
     -> 1104px content area: two 520px columns, 64px center gap.
   - Decorative hairlines, 1px #EFEFFE:
     verticals at content edge, +24, center -12/+12, -24, edge;
     horizontals as full-bleed row borders.
   ============================================================ */

:root {
  --grid-line: #EFEFFE;

  /* Type tokens new in this milestone (confirmed by Dayana):
     H3 24/32 Poppins, weight 500 provisional (to be tuned in
     browser); Body/md 16/24 Geist 400. */
  --h3-size: 24px;
  --h3-lh: 32px;
  --heading-weight: 500;
  --body-md-size: 16px;
  --body-md-lh: 24px;

  --radius-card: 16px;
  --row-pad: 64px;      /* vertical padding, cards row */
  --card-gap: 64px;     /* center gap between columns  */
  --stack-gap: 32px;    /* thumb -> title -> labels    */

  /* Cross-fade to the card's hover media (v1.12.0). PROVISIONAL:
     no design value exists for this, 200ms is a neutral starting
     point. Tune here, it is the only place the duration lives. */
  --card-hover-fade: 200ms;

  /* Card title to status chip, v1.13.0. 16px is Dayana's value from
     the annotated screenshot. --card-status-rowgap only applies if
     the chip wraps below the title on a narrow viewport, which the
     design does not cover: PROVISIONAL. */
  --card-status-gap: 16px;
  --card-status-rowgap: 8px;

  /* ---- Footer link row, v1.18.0 ----
     Type is Dayana's Figma Dev Mode value: Poppins 12/20, weight 400,
     #74757F. Note that #74757F is NOT --ink-muted (#85858A), which
     single.css uses for captions and photo credits and which is
     itself flagged "sampled; tune". Two grays doing a similar job is
     worth a decision at some point; this one is the supplied number,
     so it wins here and gets its own token rather than being folded
     into the other.

     --footer-meta-pad is MEASURED, NOT SUPPLIED: 31px above and 30px
     below the link's line box in the 2x reference, rounded to 32 to
     land on the theme's spacing rhythm. Change this one value if the
     row should sit tighter or looser. */
  --footer-meta-size: 12px;
  --footer-meta-lh: 20px;
  --footer-meta-ink: #74757F;
  --footer-meta-pad: 32px;
  --footer-link-gap: 24px;

  /* ---- Colophon row, v1.24.0 ----
     PROVISIONAL, EVERY VALUE. No Dev Mode numbers were supplied for
     this row; all four are measured off the 2x export and one of them
     is deliberately NOT what the export says. Read before tuning.

     --footer-note-ink: sampled at #1D1D4A, which is --body-ink
       (#1D1D4C) to within the PNG's rounding, so the token is used
       rather than a new hex. This is the only value here I am
       confident about.
     --footer-note-size: measured two ways and they disagree slightly.
       The sentence is 147 characters across 966.5 CSS px, which is
       6.58px per character; calibrating the per-character advance
       against the 12px link row in the same export puts the size at
       ~13.2. Calibrated x-height puts it at ~13.6. Both round to 14
       as the nearest size anyone actually specifies, so 14 is the
       inference, not a supplied number. If Dev Mode says 13, change
       this one line.
     --footer-note-lh: derived, not measured. A single line gives no
       line-height to read. 22 keeps the theme's ratio band (16/24,
       18/28, 12/20).
     --footer-note-pad: the export measures ~30, and the link row in
       the SAME export measures ~29 against the 32 this theme ships.
       The mock runs uniformly tighter than the build, so this follows
       the build's rhythm rather than the mock's, which puts the row
       at 22 + 64 = 86 tall against the mock's 82.5. Set it to 30 if
       you want the export matched exactly.

     Family is --font-body (Geist), not Poppins: the 'a' in the export
     is double-storey and Poppins' is a geometric single-storey. */
  --footer-note-size: 14px;
  --footer-note-lh: 22px;
  --footer-note-ink: var(--body-ink);
  --footer-note-pad: var(--footer-meta-pad);

  /* Contact banner link states, v1.14.1. Same pair as the article
     pages' --accent-link / --accent-link-hover; duplicated
     deliberately, since single.css does not load on the homepage. */
  --contact-link-hover: #6160FD;
  --contact-link-active: #5756E4;
}

/* ---------- Section wrapper + decorative grid ---------- */

.work {
  position: relative;
  background: #ffffff;
}

/* Vertical hairlines, two layers:
   - .gridlines: the four OUTER lines (page-margin pairs), one
     absolutely positioned overlay spanning all rows.
   - .row-centerlines: the CENTER pair (50% -12 / +12). Per Dayana,
     these stop at the horizontal line above the contact row instead
     of running behind the banner, so they live inside the cards and
     about rows only. Each row's segment spans that row's full
     height; segments meet at the shared border, so they read as one
     continuous line.
   Both overlays are first children of their parent, so content
   paints above them by DOM order alone. No z-index. */
.gridlines {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.gridlines__frame {
  position: relative;
  height: 100%;
  max-width: 1248px;
  margin-inline: auto;
  padding-inline: clamp(20px, 3vw, 24px);
}

.gridlines__frame i {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--grid-line);
}

/* Positions are relative to the container CONTENT box, which the
   inner absolutely-positioned frame reproduces. */
.gridlines__frame i:nth-child(1) { left: clamp(20px, 3vw, 24px); }
.gridlines__frame i:nth-child(2) { left: calc(clamp(20px, 3vw, 24px) + 24px); }
.gridlines__frame i:nth-child(3) { right: calc(clamp(20px, 3vw, 24px) + 24px); }
.gridlines__frame i:nth-child(4) { right: clamp(20px, 3vw, 24px); }

/* Center pair. Rows are full-bleed and the container is centered,
   so the row's 50% equals the container's 50%. */
.row-centerlines {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.row-centerlines i {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--grid-line);
}

.row-centerlines i:first-child { left: calc(50% - 12px); }
.row-centerlines i:last-child  { left: calc(50% + 12px); }

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

/* Full-bleed horizontal hairline closes each row. The line at the
   very top of the section is NOT drawn here: the hero strip's
   border-bottom already sits there (see handoff note on the
   #E9E7F2 vs #EFEFFE mismatch). */
.work-row {
  position: relative;   /* anchors .row-centerlines */
  border-bottom: 1px solid var(--grid-line);
}

/* Content inset: 24px to the inner hairline + 24px inside it.
   IMPORTANT: .work-inner sits on the same element as .container,
   so its padding REPLACES the container's clamp() padding. The
   container padding must therefore be part of this calc, or the
   content lands on the inner grid line instead of 24px inside it
   (the v1 bug). */
.work-inner {
  padding-inline: calc(clamp(20px, 3vw, 24px) + 48px);
}

/* ---------- Row 1: case study cards ---------- */

.cards-row .work-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--card-gap);
  padding-block: var(--row-pad);
}

/* The media frame owns the thumb box: 520 max, 520/360, r16. Both
   layers (static thumb, optional hover media) fill it absolutely, so
   the card's height and the 32px rhythm to the title are identical to
   the single-image version. overflow:hidden clips both to the radius,
   so neither layer needs its own.
   NOTE: it is a <span> in the markup (an <a> cannot contain a <div>),
   hence the explicit display:block. */
.case-card__media {
  display: block;
  position: relative;
  width: 100%;
  max-width: 520px;             /* exact design size at 1440 */
  aspect-ratio: 520 / 360;      /* keeps 520x360 proportions below 1440 */
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--thumb-bg, #FFBFF2);
}

.case-card__thumb,
.case-card__default,
.case-card__hover {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
 * v1.17.0: the DEFAULT layer. Sits on top of the still image and under
 * the hover layer, and is visible without hovering.
 *
 * No background of its own. A <video> that has not loaded paints
 * nothing, so the still image behind shows through until the first
 * frame arrives. That is the poster frame, without fetching the same
 * image twice.
 */
.case-card__default {
  opacity: 1;
  pointer-events: none;
  background: transparent;
}

/* Hover media (GIF, animated WebP, or video), v1.12.0.
   Hidden by default and cross-faded in on hover or keyboard focus.
   Gated to real pointers: on touch there is no hover state, so the
   swap would either never fire or stick after a tap. */
.case-card__hover {
  opacity: 0;
  pointer-events: none;         /* clicks and hover belong to the <a> */
  transition: opacity var(--card-hover-fade) linear;
}

/*
 * v1.17.0: `.has-hover-media` on the link, not just the presence of
 * the element. The hover file still renders when "No hover swap on
 * desktop" is on, because the Mobile visual setting may be pointing
 * at it; the class is what says whether hover does anything.
 */
@media (hover: hover) and (pointer: fine) {
  .case-card__link.has-hover-media:hover .case-card__hover,
  .case-card__link.has-hover-media:focus-visible .case-card__hover {
    opacity: 1;
  }
}

/*
 * v1.17.0: below 900, one layer at most, chosen per post.
 *
 * `display: none` rather than opacity, so a layer that is not chosen
 * costs nothing: a hidden <video> is never played by card-hover.js and
 * a hidden <img> is not fetched by a browser that honors it. The
 * attribute is written by card.php and already falls back to 'static'
 * when the chosen file is missing.
 *
 * Same 900px breakpoint as the nav and the TOC, deliberately: one
 * number decides what "mobile" means everywhere in this theme.
 */
@media (max-width: 900px) {
  .case-card__default,
  .case-card__hover { display: none; }

  .case-card__media[data-mobile-visual="default"] .case-card__default,
  .case-card__media[data-mobile-visual="hover"] .case-card__hover {
    display: block;
    opacity: 1;
  }
}

/* Reduced motion: no animated media at all. The static thumbnail is
   the whole card, which is the honest fallback for an effect whose
   entire content is motion.
   v1.17.0: this block moved BELOW the mobile block and carries the
   attribute selectors, because `.case-card__media[data-...] .layer` is
   (0,3,0) and would otherwise outrank a bare class here. */
@media (prefers-reduced-motion: reduce) {
  .case-card__default,
  .case-card__hover,
  .case-card__media[data-mobile-visual="default"] .case-card__default,
  .case-card__media[data-mobile-visual="hover"] .case-card__hover {
    display: none;
  }
}

/* v1.13.0: title + status chip ("Coming Soon") on one row, 16px
   apart per Dayana's annotated screenshot. The wrapper only exists
   when the post has a status label, so a normal card is untouched:
   the 32px rhythm below the thumb still comes from .case-card__title
   in that case, and from the row here in this one.
   Chip metrics come from the .label component at the homepage tag
   size, so it matches the tag chips underneath.
   PROVISIONAL: --card-status-rowgap. The design is a single-line
   title, so there is no value for what happens when the row wraps on
   a narrow viewport. */
.case-card__titlerow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  column-gap: var(--card-status-gap);
  row-gap: var(--card-status-rowgap);
  margin: var(--stack-gap) 0 0;
}

.case-card__titlerow .case-card__title { margin: 0; }

/* The chip is a flex item here, so .label's vertical-align does not
   apply; it is centered against the title line by align-items. */
.case-card__status { flex: 0 0 auto; }

.case-card__title {
  margin: var(--stack-gap) 0 0;
  font-family: var(--font-heading);
  font-size: var(--h3-size);
  line-height: var(--h3-lh);
  font-weight: var(--heading-weight);
  color: var(--ink);
}

.case-card__labels {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: var(--stack-gap) 0 0;
  padding: 0;
  list-style: none;
}

/* ---------- Row 2: about ---------- */

.about-row .work-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--card-gap);
  align-items: center;
  /* No spacing rule exists for this row yet; height matches the
     export (534px) with both columns vertically centered. */
  min-height: 534px;
  padding-block: 48px;   /* safety for content taller than 534 */
  box-sizing: border-box;
}

.about-media {
  margin: 0;
}

/* Placeholder for the future photo. Measured from the export:
   475x346 (narrower than the 520 column), radius 16. */
.about-media__ph {
  width: 100%;
  max-width: 475px;
  aspect-ratio: 475 / 346;
  border-radius: var(--radius-card);
  background: #E2E3E6;
}

.about-copy h3 {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--h3-size);
  line-height: var(--h3-lh);
  font-weight: var(--heading-weight);
  color: var(--ink);
}

.about-copy p {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--body-md-size);
  line-height: var(--body-md-lh);
  font-weight: 400;
  color: var(--body-ink);
  max-width: 520px;
}

.about-copy h3 + p { margin-top: 16px; }
.about-copy p + p  { margin-top: 24px; }

/* ============================================================
   SITE FOOTER, v1.18.0
   Was "Row 3" inside .work; now template-parts/site-footer.php,
   shared by the homepage and (per post) the case study pages.

   The banner's own rules below are UNCHANGED. Only its frame moved.
   ============================================================ */

.site-footer {
  position: relative;   /* anchors this section's own .gridlines */
  background: #ffffff;
  /* The hairline ABOVE the banner. Drawn here rather than by the row
     above, because on an article page there is no row above. */
  border-top: 1px solid var(--grid-line);
}

/* Which is why the last .work row must stop drawing it: on the
   homepage the two elements are adjacent and would stack two 1px
   lines into a 2px one. */
.work > .work-row:last-child {
  border-bottom: 0;
}

/* THE HAIRLINE BELOW THE BANNER, v1.21.0. Read this before moving it
   back.

   It used to live on .site-footer__banner. That element is also
   .container: max-width 1248px, margin-inline auto. A border on a
   width-capped centered box is exactly 1248px wide and inset by
   (viewport - 1248) / 2 at each end, so on any monitor wider than
   1248 this line stopped short at both ends while the line ABOVE the
   banner, drawn on the full-bleed .site-footer, ran edge to edge. Two
   lines in the same grid, one of them visibly shorter.

   .site-footer__row is a full-bleed wrapper whose only job is to carry
   the border, which is the arrangement .work-row already uses: line on
   the outer element, content inset on the inner one. The banner keeps
   its padding and loses only the border.

   Positioning moved here too. .gridlines is an absolute overlay and the
   first child of .site-footer, so every sibling that must paint above
   it has to be positioned, and the sibling is now this wrapper rather
   than the banner. Still no z-index (m7). */
.site-footer__row {
  position: relative;
  border-bottom: 1px solid var(--grid-line);
}

.site-footer__banner {
  padding-block: 40px;   /* unchanged */
}

/* THE COLOPHON ROW, v1.24.0.

   Same two-element split as .site-footer__row above, for the reason
   documented there: the border has to be on a full-bleed element or
   it stops at 1248 while the lines above and below it run edge to
   edge. The wrapper carries the line and the positioning; the inner
   .container.work-inner carries the inset. Do not merge them.

   Both the wrapper and the line only exist when the field has text
   (see template-parts/site-footer.php), so clearing the colophon
   removes the hairline with it and the footer falls back to exactly
   the v1.23.0 geometry. */
.site-footer__noterow {
  position: relative;
  border-bottom: 1px solid var(--grid-line);
}

.site-footer__note {
  padding-block: var(--footer-note-pad);
}

/* Centered, and NOT width-capped. The design has this on one line at
   1440, where the sentence measures 966px inside a 1104px content
   area. Any cap tight enough to be a sensible measure would break
   that single line, so the constraint is the content area itself and
   the line wraps below roughly 1100px viewport. If the copy grows
   much past this length it will wrap at 1440 too; that is a content
   decision, not a bug to fix in CSS.

   No max-width in ch (project rule): if a cap is ever wanted here it
   goes in px. */
.site-footer__note p {
  margin: 0;
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--footer-note-size);
  line-height: var(--footer-note-lh);
  font-weight: 400;
  color: var(--footer-note-ink);
}

/* Inline links inside the colophon are not in the design. The rules
   exist because the field allows <a> and an unstyled one would
   inherit the browser default blue. Underlined here, unlike the
   banner links: this is a link inside a sentence, which is the case
   the Body/md-link token covers. */
.site-footer__note a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  border-radius: 4px;
}

.site-footer__note a:hover  { color: var(--contact-link-hover); }
.site-footer__note a:active { color: var(--contact-link-active); }

.site-footer__note a:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}

/* No bottom border here: per the reference, the verticals run past
   the link row to the bottom of the page and nothing closes it. */
.site-footer__meta {
  position: relative;
  padding-block: var(--footer-meta-pad);
}

/* Alignment is on the row, not the list, so the flex container can
   still wrap normally at any width. Right is the design default. */
.footer-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px var(--footer-link-gap);
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-heading);   /* Poppins, per the supplied values */
  font-size: var(--footer-meta-size);
  line-height: var(--footer-meta-lh);
  font-weight: 400;
  color: var(--footer-meta-ink);
}

.site-footer__meta--left   .footer-links { justify-content: flex-start; }
.site-footer__meta--center .footer-links { justify-content: center; }
.site-footer__meta--right  .footer-links { justify-content: flex-end; }

/* A row with a label and no URL renders as a <span>, so the Privacy
   Policy placeholder is visible without being a link to nowhere. It
   inherits the same color and gets no interaction states. */
.footer-links a {
  color: var(--footer-meta-ink);
  text-decoration: none;
  border-radius: 4px;
}

/* Hover and active: no design value was supplied. Per Dayana, the
   link darkens to --ink rather than picking up the banner's lilac
   accent, so the row stays quiet. --contact-link-active is reused for
   the pressed step only because there is no darker step than --ink. */
.footer-links a:hover  { color: var(--ink); }
.footer-links a:active { color: var(--ink); }

.footer-links a:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}

/* ---------- The banner itself (unchanged from v1.14.1) ---------- */

/* Coupled art, hero rules apply: wings use per-image color-burn
   and are only visible where banner color sits behind them.
   isolation: isolate scopes the burn to the banner so it can
   never composite against the page or the grid lines. No
   opacity / transform / filter on the wings or their ancestors
   inside the banner. */
.contact-banner {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 212px;
  border-radius: var(--radius-card);
  /* Banner art: 1104x212, rx 16, #F7F7FF base, gradients at 0.83
     with grain baked in. Chosen variant: baseFrequency 4 + flood 5%
     (finer, fainter grain than the raw Figma export, which read too
     strong in browser; Figma spec was noise mono, size 0.5, #4E4DCA
     10%). If grain ever needs retuning, those two attributes inside
     the SVG are the knobs. */
  background: url("../img/banner-3-fine-soft.svg") center / cover no-repeat;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 32px 24px;
  text-align: center;
}

.contact-banner__wing {
  position: absolute;
  top: 0;
  height: 100%;
  width: auto;
  mix-blend-mode: color-burn;   /* per layer, per hero spec */
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

.contact-banner__wing--left  { left: 0; }
.contact-banner__wing--right { right: 0; }

.contact-banner__title {
  position: relative;   /* paints above the wings via DOM order… */
  margin: 0;
  font-family: var(--font-heading);
  font-size: clamp(24px, 2.3vw, 32px);
  line-height: 42px;
  font-weight: var(--heading-weight);   /* 500 provisional; H2 token is 300 */
  color: var(--ink);
}

.contact-links {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  row-gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-body);
  font-size: var(--body-md-size);
  line-height: var(--body-md-lh);
  font-weight: 400;
}

.contact-links li {
  display: flex;
  align-items: center;
}

.contact-links li + li::before {
  content: "|";
  margin: 0 24px;
  color: var(--ink);
  opacity: 0.35;
}

/* v1.14.1, per Dayana: no underline here. Default #131333 (--ink),
   hover the site link accent. Note this deliberately departs from the
   Body/md-link token, which IS underlined and is still what article
   body links use. The banner links are a short horizontal row read as
   a set, not links inside a paragraph, so nothing has to distinguish
   them from surrounding copy. */
.contact-links a {
  color: var(--ink);
  text-decoration: none;
  border-radius: 4px;
}

/* Hover is #6160FD, the site link accent. :active and the focus ring
   now follow it rather than keeping the older #3A3A98 / #4A4290 pair,
   so all three states come from one family: active is the accent's
   pressed step (the same #5756E4 the article links use), and the ring
   is the accent itself. */
.contact-links a:hover  { color: var(--contact-link-hover); }
.contact-links a:active { color: var(--contact-link-active); }
.contact-links a:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}

/* ============================================================
   RESPONSIVE
   ============================================================ */

@media (max-width: 900px) {
  /* Decorative grid is a desktop device; below 900 it fights the
     single-column layout. */
  .gridlines,
  .row-centerlines { display: none; }

  /* Restore the page-level padding (20px on small screens via the
     clamp). Setting 0 here would put content flush to the viewport
     edge, since this padding replaces the container's. */
  .work-inner { padding-inline: clamp(20px, 3vw, 24px); }

  .cards-row .work-inner,
  .about-row .work-inner {
    grid-template-columns: 1fr;
    gap: 48px;
    padding-block: 48px;
  }

  .about-row .work-inner { min-height: 0; }

  /* v1.12.0: the 520px cap lives on the media frame now, not on the
     thumb itself. */
  .case-card__media,
  .about-media__ph { max-width: 100%; }
}

@media (max-width: 600px) {
  /* v1.24.0. The colophon is one line at 1440 and four or five on a
     phone, so 32px of padding above and below a block that tall reads
     as a gap rather than a row. The type size is unchanged: 14px is
     already the smallest body size on the site and shrinking it
     further would put it under the link row's 12px.
     PROVISIONAL: measured from nothing, there is no mobile export. */
  .site-footer__note { padding-block: 24px; }

  /* The link row keeps its chosen alignment; only the gap tightens,
     since 24px between two stacked-ish links reads as a hole on a
     phone. Nothing here overrides justify-content: if the row is set
     to right it stays right at every width. */
  .footer-links { gap: 8px 16px; }

  .contact-banner { min-height: 180px; }
  .contact-banner__title { line-height: 1.3; }

  /* Stack links; hide the pipe separators. */
  .contact-links { flex-direction: column; row-gap: 12px; }
  .contact-links li + li::before { content: none; }

  /* Wings scale with banner height and may overlap the links on
     narrow screens; keep them but pull them half out of frame. */
  .contact-banner__wing--left  { left: -32px; }
  .contact-banner__wing--right { right: -32px; }
}
