/* ============================================================================
   Card / Channels Content — the content-object card in a collection grid.

   Figma: `Card / Channels Content`, inside `Channels / Cards / All` on
   `Body / Videos / Page` (FE Client, 23304:960021). Verified geometry:

     Card         234 × 255.6,  gap 8 between media and body
     Img Wrapper  234 × 131.6   → exactly 16:9, radius 8
     Play Button  40 × 40, centred
     Video length 32 × 20, inset 8 from the right, ~8 from the bottom
     Body         gap 4 — Tags Row 24 · Title & Date 64 · Avatar & Actions 20
     Title        44 tall = two 22px lines, ellipsised

   The card is the ONLY part of a collection page that changes between Videos,
   Communities, Programs and Organizations, so the classes below are named for
   the content object in general (`ccard`), not for video. The play button and
   the duration chip are the video-only parts and are opt-in: a card without
   them is still a complete card.

   DIVERGENCES from the frame — deliberate, each one a documented defect or a
   root-CLAUDE.md non-negotiable:

   D1  Img Wrapper is `RAW #4211a0` in the frame — the BigHeart brand seed,
       frozen. CLAUDE.md non-negotiable 4 says do not add a fifth literal
       instance of it. `solid/brand/default` IS that value under BigHeart and
       follows the brand switch, so the letterbox behind a thumbnail is brand
       purple under BigHeart and correct under BWHI.

   D2  Tag / Entity is `RAW` pastel/dark pairs in the frame — #f9f0ff on
       #120338 for `Video`. That is FE Client CLAUDE.md's §12 F4, listed as a
       known defect on this app's own surfaces. Not reproduced: the card uses
       `.tag--brand .tag--bg` from tag.css, which is `soft/brand/default` +
       `on-soft/brand` and honours the §4.4 pairing contract.

   D3  The frame has no hover, focus or pressed state for the card. The DS has
       no focus state on most components and no pressed state anywhere, both
       recorded as known gaps that CLAUDE.md says to IMPLEMENT rather than
       inherit. Focus comes from base.css's `:focus-visible` ring; hover and
       pressed are defined at the bottom of this file.

   TODO(tokens): every bare px length in this file is a SIZE. DESIGN.md §12.4
   records size as not built. No colour, radius, spacing, border-width or
   font-size literal appears anywhere in this file.
   ========================================================================== */

.ccard {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-inline-size: 0;
  text-decoration: none;
  color: inherit;
}

/* SIZING IS THE CONTAINER'S JOB, not the card's. The same card is 234 wide in
   a collection grid (`Body / Videos / Page`) and a fixed 264 in a Channels
   scroll row (`Channels / Cards / Featured`), so `.ccard` itself carries no
   width and each context sets it — collection.css and channels.css. */

/* Same reason as .tag[hidden] in tag.css: `display: flex` above outranks the
   UA's `[hidden]` rule. Load-bearing — filtering hides cards in place rather
   than rebuilding the grid (collection.js). */
.ccard[hidden] {
  display: none;
}

/* --- Img Wrapper --------------------------------------------------------- */
.ccard__media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--shape-radius-card);
  /* D1 — the frame's frozen #4211a0, taken through the brand layer instead. */
  background: var(--color-solid-brand-default);
}

.ccard__thumb {
  inline-size: 100%;
  block-size: 100%;
  /* `cover`, not `contain`: the comp's stills have mixed intrinsic ratios and
     the wrapper is a fixed 16:9 window onto them. */
  object-fit: cover;
  /* An image is replaced content and sits on the text baseline otherwise,
     which leaves a hairline of the brand fill along the bottom edge. */
  display: block;
}

/* --- Play Button ---------------------------------------------------------
   Composed from `e/icon/media/play_fill` rather than pulled in as the frame's
   single flattened 40px asset: ASSETS.md §6 rule 1 wants the icon file, and
   composing it keeps the glyph on `currentColor` so the disc and the mark both
   stay token-bound. */
.ccard__play {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* TODO(tokens): size not built — the frame's 40px disc. */
  inline-size: 40px;
  block-size: 40px;
  border-radius: var(--radius-full);
  background: var(--color-surface-scrim);
  color: var(--color-content-on-artwork);
  transition: background-color 100ms ease; /* TODO(tokens): motion not built */
}

/* --- Tags / Video Length -------------------------------------------------
   `surface/scrim` + `content/on-artwork` is the token pair described for
   exactly this — text laid over imagery. NOTE: the frame paints this chip at
   75% black and the scrim token is 45%; the token's own comment in
   tokens.semantic.css says never to stack more opacity on top of it, so the
   45% stands and the difference is intentional, not an oversight. */
.ccard__duration {
  position: absolute;
  inset-block-end: var(--space-xs);
  inset-inline-end: var(--space-xs);
  padding-inline: var(--space-2xs);
  border-radius: var(--shape-radius-chip);
  background: var(--color-surface-scrim);
  color: var(--color-content-on-artwork);
  font-family: var(--font-family-text);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
  font-weight: var(--font-weight-regular);
}

/* --- Body ---------------------------------------------------------------- */
.ccard__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  min-inline-size: 0;
}

.ccard__tags {
  display: flex;
  gap: var(--space-xs);
}

/* Title & Date — no gap between them in the frame; the 22px and 20px line
   boxes do the spacing. */
.ccard__titles {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
}

.ccard__title {
  margin: 0;
  font-family: var(--font-family-text);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  /* `Text M - Bold` in the frame — Body/MD at the bold weight, which is a real
     step in the type scale, not a synthesised one. */
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--font-letter-spacing-default);
  color: var(--color-content-headline);
  /* Two lines, then ellipsis — the frame's 44px title box. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  transition: color 100ms ease; /* TODO(tokens): motion not built */
}

/* --- Content object / Date and time · p/avatars/content object -----------
   Two different Figma sets that render identically here: a 12px glyph, a 4px
   gap and one line of Body/SM in `content/primary`. */
.ccard__meta {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0;
  min-inline-size: 0;
  color: var(--color-content-primary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

.ccard__meta-text {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- Content Object / Date And Time, the two-part form -------------------
   The event card puts Date and Time side by side in one 20px row, `space/xs`
   apart, each its own icon + label pair. */
.ccard__dates {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
}

/* --- Tag / Price — `Inline`, Price for = Program -------------------------
   Two texts on one baseline: the current price in Body/MD Medium, and the
   struck-through original in Body/SM. The strike is the whole signal that the
   first number is a reduction, so it is never the only channel — the price
   that applies is also the heavier, darker one. */
.ccard__price {
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  margin: 0;
}

.ccard__price-now {
  color: var(--color-content-headline);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  font-weight: var(--font-weight-medium);
}

.ccard__price-was {
  color: var(--color-content-secondary);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
  text-decoration: line-through;
}

/* --- Progress — the Giving card ------------------------------------------
   `.progress`, `.progress__track/__fill/__label/__amount` are feed.css's, from
   the Home page's crowdfunding post. Reused wholesale rather than restated:
   the frame uses the same Campaign / Detail / Progress Bar component in both
   places, and feed.css already resolved its two raw local styles (#f6f6f6
   track → `soft/neutral/strong`, #509e2a fill → `solid/success/default`).
   Only the row that puts "raised" and the status on one line is new. */
.ccard__progress-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-xs);
}

/* `Finished` — a completed campaign. Status is carried by the glyph AND the
   word, never by colour alone (DESIGN.md §9.2). */
.ccard__status {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0;
  flex: none;
  color: var(--color-content-secondary);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

/* --- D3: the states the frame does not draw ------------------------------
   Hover and pressed are carried by the title's ink AND by the play disc, so
   neither rests on a single channel. Focus is base.css's ring on the <a>. */
.ccard:hover .ccard__title,
.ccard:focus-visible .ccard__title {
  color: var(--color-content-brand);
}

/* Hover DARKENS, it does not go brand. `surface/scrim` is 45% black; the disc
   deepens to `surface/media`, the solid black the player itself sits on — so
   the affordance reads as "the picture is about to play" rather than as an app
   accent landing on the artwork. Brand purple here also fought the entity tag
   and the price directly below it for the eye. */
.ccard:hover .ccard__play,
.ccard:active .ccard__play {
  background: var(--color-surface-media);
}

@media (prefers-reduced-motion: reduce) {
  .ccard__title,
  .ccard__play {
    transition: none;
  }
}

/* ============================================================================
   MONETIZATION STATES — the board's 🔒 / ✅ pair, on the card

   Board `High-level screen flow` (zMvmFpUrJiMG1ONIAmNY3q, 6476:56307). The
   Channels Videos shelf is mixed — priced, free and bought cards sit side by
   side — so each of the three has to be tellable from the others at a glance
   AND without colour. Every one below pairs a hue with a glyph or a word.
   ========================================================================== */

/* NO PAYWALL STATE ON THE THUMBNAIL. Every video carries a trailer and the
   thumbnail plays it, so the play disc is unconditional and keeps its brand
   hover — it really does play. The paywall is expressed by the price row
   below and gated on the detail page's Watch control, nowhere else. A lock
   over the disc used to live here; see the note in card.js's mediaOverlays. */

/* Bought. `content/success` + tick + the word — three channels, per the
   root CLAUDE.md gap on status conveyed by wording alone. */
.ccard__price--owned {
  align-items: center;
  color: var(--color-content-success);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  font-weight: var(--font-weight-medium);
}

/* Free. A chip, not a price face, so it never reads as an amount. `soft/
   success` with its own `on-*` partner — DESIGN.md §4.4, never
   `content/primary` on a filled surface. */
.ccard__price--free > span {
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--shape-radius-chip);
  background: var(--color-soft-success-default);
  color: var(--color-on-soft-success);
  font-size: var(--font-label-sm-size);
  line-height: var(--font-label-sm-line-height);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--font-letter-spacing-wide);
  text-transform: uppercase;
}
