/**
 * @file
 * Cards row component styles. DONI-739 / SDC-5.
 *
 * Canonical Figma `PMOumVEsuQEHJFYkbGBD84`, canvas `24410:65586` (7-29-2026).
 * The `Cards` component set is `10195:14314`; the 580 card width is corroborated
 * by the committed census (design-system-census.md — Video Player Card
 * `23216:27665` desktop 580×412, and `10452:36828` / `10291:38418` at 580×275).
 *
 * ⚠️ No Figma visual comparison was possible for this build — the Figma REST API
 * was returning 429. Every number below comes from the ticket's numeric
 * acceptance criteria and the committed census, not from a live read, and not
 * from `figma-to-html/` (which is r53-era reference and forbidden as an input).
 *
 * ─────────────────────────────────────────────────────────────────────────
 * 🔴 GRID, NOT flex-wrap — AND `1fr` TRACKS, NOT `580px` TRACKS.
 *
 * The row is 580 + 40 + 580 = exactly 1200 with zero slack. Under `flex-wrap`
 * card 2 broke to its own line the moment the container lost a single pixel —
 * a scrollbar alone did it, measured at 1524 instead of 1119 on a 1425 viewport.
 *
 * Two explicit `1fr` tracks have no wrapping mechanism at all: no `auto-fit`,
 * no `minmax`, no `flex-wrap`. Losing a pixel to a scrollbar shrinks each track
 * to 579.5 instead of reflowing. Fixed `580px` tracks would NOT be safe — they
 * would overflow the column rather than absorb the loss. The `1fr` is the fix,
 * not an incidental choice.
 * ─────────────────────────────────────────────────────────────────────────
 *
 * Fallback literals on every `var()` are deliberate, for the same reason
 * `container.css:13-18` gives: this file is what Canvas renders when it attaches
 * the component library alone, without `css/base/`. Every token below IS
 * declared globally — these are a safety net for that one case, not the
 * `var(--never-declared, #hex)` pattern where the fallback always wins.
 */

.cards-row {
  /* The content column. Duplicated from `.l-container` (css/base/layout.css)
     so the SDC is self-contained under a component-only library attach; the
     class is still on the root so the canonical rule governs when base CSS is
     present, and so check-alignment.py sees this row. Both agree on 1200. */
  inline-size: min(100%, var(--layout-content, 1200px));
  margin-inline: auto;

  display: grid;

  /* Stacked below 768. The AC does not specify a stacked gap, so the two-up
     value carries over rather than a third number being invented.

     ⚠️ Both gaps in this file come from the `--space-*` family ON PURPOSE, and
     that needs saying because the obvious choice for a gap is `--gap-size-*`.
     There is NO 40px rung in that family — it steps `--gap-size-xl: 2rem`
     (32px) straight to `--gap-size-2xl: 3rem` (48px). An earlier draft took 32
     from `--gap-size-xl` and 40 from `--space-2xl`, which rendered correctly but
     left a trap: normalising the pair into one family would have picked
     `--gap-size-2xl` and silently turned 40px into 48px, and nothing lints CSS.
     `--space-xl` is also exactly 2rem/32px, so using it costs nothing and keeps
     both values on one scale. If a 40px gap rung is ever added, this is the
     place to revisit — see FND-2 / DONI-701. */
  grid-template-columns: 1fr;
  gap: var(--space-xl, 2rem); /* 32px */
}

/* ─────────────────────────────────────────────────────────────────────────
 * THE TWO BREAKPOINTS. Each is written ONCE, here, and nowhere else in this
 * file. CSS media queries cannot read a custom property, so "one place" is
 * enforced by convention: if you change a number below, it is the only copy.
 *
 * 768  — stacked becomes two-up. The ticket's own lower bound.
 * 1024 — two-up gap 32 becomes desktop gap 40.
 *
 * 🔴 THE 1024 BOUNDARY IS PROVISIONAL — it depends on DONI-864, an OPEN
 * Decision asking whether the tablet band is 992-1200 and whether the
 * hamburger moves below 1200. This component's AC says "two-up at 768-1023
 * with a 32px gap. That range is ours; the design has no tablet artboard", so
 * that is what is built. If DONI-864 moves the boundary to 1200, this is a
 * one-line change to the single query below. Several other components key off
 * the current 991/992 boundary, so the change is not ours to make alone.
 *
 * ⚠️ css/base/layout.css:52 deliberately refuses a 1024 breakpoint for the
 * layout FOUNDATION ("the design supplies 1440 and 375 and NOTHING between").
 * That refusal is about the container, which is continuous and needs no
 * breakpoint. A component may still have one, and `columns.css:33` already
 * does. This row needs one because its AC specifies two different gaps either
 * side of it.
 * ───────────────────────────────────────────────────────────────────────── */

/* Grid items. The wrappers are the grid items, never the slotted content —
   see the note in cards-row.twig. */
.cards-row__item {
  min-inline-size: 0; /* let a wide child shrink instead of forcing the track open */
}

/**
 * Overhang the section above — Home's cards over the hero.
 *
 * ⚠️ IMPLEMENTED TO SPEC, NOT VERIFIED. This is the one criterion that needs
 * FND-8 / DONI-717 (the band) to exist before it can be checked, and that had
 * not landed when this was written. No local `.band` was created to test
 * against: testing against a fake certifies nothing.
 *
 * The offset goes on the CONTENT, never on the band. Putting it on the band
 * drags the brick texture over the hero.
 *
 * Exposed as a component-local custom property so a page with a genuinely
 * different measured overhang can re-declare it on itself without editing this
 * component — the local-override pattern css/base/layout.css:69-77 blesses.
 * It is not a global token and must not become one.
 */
/* Requires `.cards-row`: the modifier is inert if it lands on a wrapper. */
.cards-row.cards-row--overlap {
  /* Mobile-first: the mobile figure is the default and the 768 query below
     overrides it, so neither breakpoint gains a second occurrence. */
  --cards-row-overlap: 40px;

  /* An offset, NOT a negative top margin. As the first child of its wrapper that
     margin collapsed through and moved the whole section up instead of the cards.
     The negative bottom margin pulls following content up, as the old margin did. */
  position: relative;
  inset-block-start: calc(-1 * var(--cards-row-overlap));
  margin-block-end: calc(-1 * var(--cards-row-overlap));

  /* Beats the band above. Must stay far below the ISI tray's 1000. */
  z-index: 1;
}

/* ─── The two media queries. Last in the file ON PURPOSE. ──────────────────
 *
 * 🔴 Both override single-class base rules above at EQUAL specificity, so they
 * only win by coming later in source order. An earlier draft had the 768 block
 * above `.cards-row--overlap` and its 74px was silently dead: the overhang
 * measured -80px at 1425 as well as at 375. `fin validate` does not lint CSS
 * and the component still rendered, so nothing caught it but measurement.
 * Do not move these blocks up.
 * ───────────────────────────────────────────────────────────────────────── */

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

  .cards-row--cols-3 {
    grid-template-columns: repeat(3, 1fr);
  }

  .cards-row.cards-row--overlap {
    --cards-row-overlap: 37px;
  }
}

@media (min-width: 768px) and (max-width: 869px) {
  .cards-row.cards-row--overlap {
    --cards-row-overlap: 262px;
  }
}

/* (1200 - 40) / 2 = 580 per card at the full content column. */
@media (min-width: 1024px) {
  .cards-row {
    gap: var(--space-2xl, 2.5rem); /* 40px */
  }
}

@media (max-width: 990px) {
  .cards-row.cards-row-container-layout,
  .cards-row.cards-row-container-layout.cards-row--cols-3 {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 445px) {
  .cards-row.cards-row--overlap {
    --cards-row-overlap: 130px;
  }
}

@media (min-width: 685px) and (max-width: 771px) {
  .cards-row.cards-row--overlap {
    --cards-row-overlap: 243px;
  }
}

@media (min-width: 446px) and (max-width: 684px) {
  .cards-row.cards-row--overlap {
    --cards-row-overlap: 139px;
  }
}

/**
 * Modifiers — `--stats`, `--dosing`, `--steps`, `--study`, `--videos`.
 *
 * Driven by the `modifier` prop. It is deliberately not called `variant`:
 * that name is reserved by Drupal core and breaks the component on every
 * render. See the note in cards-row.twig.
 *
 * The class is emitted by the Twig so a page or a card can hang styling off it.
 * No per-variant geometry is declared here on purpose: the ticket names the five
 * modifiers but specifies no geometry that differs between them, and inventing
 * a difference would be fabricating design rather than building it. Empty
 * rulesets are not written either — they would read as an unfinished
 * implementation. When a variant gets a measured spec, it lands here with its
 * Figma node id.
 */

/**
 * Neon connector — `connector` prop.
 *
 * The coral line running between the cards (Figma `10324:18632`). It matches
 * the NEON FRAME rather than being a plain rule: the same three stacked coral
 * bands and the same outer glow, so a connector and the frames it joins read as
 * one piece of neon tube.
 *
 * The ring values are re-declared here rather than referenced from `neon-card`:
 * an SDC gets its own CSS attached in isolation, so a custom property declared
 * on `.neon-card` is not in scope on `.cards-row`. If those values change, both
 * files change — they describe the same tube.
 *
 * 🔴 DECORATIVE, AND DELIBERATELY NOT AN ELEMENT. Pseudo-elements cannot be
 * reached by assistive technology, and a connecting line carries no information
 * a screen reader needs — the relationship it draws is already in reading order.
 *
 * It sits BEHIND the cards so it passes under each one instead of over its
 * border; the frames paint their own background, which is what hides the
 * segment crossing them.
 *
 * ⚠️ 768 and up only. Stacked, the cards are one column and a horizontal line
 * between them would connect nothing.
 *
 * ⚠️ Geometry is reasoned from the ring stroke measured on `24261:43129`
 * (2px per band, 8px glow), not read from `10324:18632` — Figma REST was
 * rate-limited. Thickness and spacing want confirming.
 */
.cards-row--connector {
  position: relative;
  isolation: isolate;
}

/* Shared by both orientations — only the axis and the gradient direction change. */
.cards-row--connector::before {
  content: '';
  position: absolute;
  z-index: -1;
  pointer-events: none;

  /* Same glow pair the frame carries. */
  box-shadow:
    0 0 8px 0 var(--neon-glow-a, #c94808),
    0 0 8px 0 var(--neon-glow-b, #e08a67);
}

/* Stacked: the cards are in one column, so the tube runs VERTICALLY down the
   container between them. 24px short top and bottom so the outermost cards
   cover its ends, mirroring the horizontal inset. */
.cards-row--connector::before {
  inset-block: 24px;
  inset-inline-start: 50%;
  inline-size: 0.375rem;
  transform: translateX(-50%);
  background:
    linear-gradient(
      to right,
      var(--neon-connector-light, #fcddd7) 0 0.125rem,
      var(--neon-connector-mid, var(--color-primary, #f16b50)) 0.125rem 0.25rem,
      var(--neon-connector-dark, #e2422d) 0.25rem 0.375rem
    );
}

/* A connector row needs a bigger STACKED gap than a plain one: the tube has to
   be visible between the cards rather than pinched between them. Ruled by
   Caroline Casals.

   ⚠️ A max-width query, which is the only one in this file. The file is
   otherwise mobile-first, but a base-level override here would win at EVERY
   width: it is single-class like `.cards-row`, and it sits after the 1024 gap
   rule, so later-wins would carry it onto desktop where the row already has its
   own 40px. Bounding it at 767 keeps the change where it was asked for. */
@media (max-width: 767px) {
  .cards-row--connector {
    gap: 2.5rem;
  }
}

@media (min-width: 768px) {
  /* Two-up and wider: the tube turns and runs horizontally between the cards.
     Every inset is re-stated rather than inherited — the two orientations set
     opposite axes, and a leftover `inset-block` would stretch it. */
  .cards-row--connector::before {
    inset-block: auto;
    inset-block-start: 50%;
    inset-inline: 24px;
    inline-size: auto;
    block-size: 0.375rem;
    transform: translateY(-50%);
    background:
      linear-gradient(
        var(--neon-connector-light, #fcddd7) 0 0.125rem,
        var(--neon-connector-mid, var(--color-primary, #f16b50)) 0.125rem 0.25rem,
        var(--neon-connector-dark, #e2422d) 0.25rem 0.375rem
      );
  }
}
