/* collectible-card.css
   The gallery card shared by the Websites gallery (casestudies.html) and the
   Apps gallery (app-catalog.html): a themed copy of the Tech Business Site
   Template card from pokecard-dropin, one hue per entry.

   Pair with the widget itself — a page using this must also load
   pokecard-dropin/pokecard/pokecard.css and .../pokecard.js. The JS wires every
   .poke-scene it finds, so cards need no per-page script.

   Why the theming lives here and not in the drop-in: .poke-face exposes
   --card-face, but the widget also hardcodes its green in three places the vars
   don't reach — the 150deg face gradient's light/deep stops, and the .poke-top /
   .poke-foot tint washes. Those three rules are re-pointed here at component
   level so the drop-in stays reusable and its own hero card stays green.

   Prefix is tcg- (trading-card gallery), deliberately not cs-: both galleries
   use it, and "cs" would read as case-study on the Apps page.

   Layout note: the card is a fixed 2.5/3.5 ratio, so it needs ~312px of height
   before the art hits its 64px floor. A 2-up phone column (~162px wide -> 226px
   tall) cannot hold it. Phone grids must be 1-up. */

/* ============================================================
   STRUCTURE
   ============================================================ */
.poke-scene.tcg-card {
  width: 100%;
  max-width: 340px;
  margin: 0 auto;            /* centre in its grid column */
  container-type: inline-size;
  container-name: tcg-card;
}

.tcg-card .poke-face {
  --card-face: var(--tcg-face);
  background: linear-gradient(150deg, var(--tcg-light) 0%, var(--tcg-face) 42%, var(--tcg-deep) 100%);
}
.tcg-card .poke-top { background: linear-gradient(180deg, var(--tcg-tint), transparent); }
.tcg-card .poke-foot { background: linear-gradient(0deg, var(--tcg-tint), transparent); }

.tcg-card:focus-within .poke-card {
  box-shadow: 10px 14px 0 rgba(0, 0, 0, 0.45),
              0 0 0 3px var(--tcg-face),
              0 0 22px var(--tcg-tint);
}
.tcg-card .poke-btn:focus-visible { box-shadow: 0 0 0 3px var(--tcg-face); }

/* the art is a full-page capture — show the hero, not the middle */
.tcg-card .poke-art img { object-position: top center; }

/* The drop-in makes .poke-art position:relative (it anchors the template
   card's .art-ph placeholder, which our cards don't use). A positioned box
   paints above ALL in-flow content in its stacking context — which would put
   the image over the in-flow stat pill below, tree order notwithstanding.
   Static art restores plain tree-order painting: the pill row that follows
   the art draws on top of it. Scoped to .tcg-card so the hero template card
   keeps its placeholder anchoring. */
.tcg-card .poke-art { position: static; }

/* A domain or product name is one unbreakable token: unlike the template's
   "Tech Business Site Template" it cannot wrap on a space, so at the widget's
   native 1.15rem a long one widens the top row and shoves whatever sits
   opposite it out of the overflow-hidden plate. Three parts as a set: names
   step down, the flip cue never shrinks, and a <wbr> before each TLD/suffix
   gives a long name somewhere to break. overflow-wrap is a last-resort guard. */
.tcg-card .poke-name {
  min-width: 0;
  font-size: 0.9rem;
  overflow-wrap: anywhere;
}
.tcg-card .tcg-flip-top { flex-shrink: 0; }

/* Back-face title, up from the widget's 0.95rem (owner request, 2026-07-17):
   the back is the card's roomiest face — the buttons' margin-top:auto pushes
   them to the foot and leaves the middle empty on most cards — so the name
   can afford front-name size. overflow-wrap is mandatory here, same reason
   as .poke-name above: a domain is one unbreakable token and the back h3
   markup carries no <wbr>; without a break guard a long name at this size
   would overflow the overflow:auto back panel HORIZONTALLY — a scrollbar,
   which backs must never show. */
.tcg-card .poke-back-inner h3 {
  font-size: 1.15rem;
  overflow-wrap: anywhere;
}

/* Headline stat, as a pill on the art corner — a build estimate on Websites, a
   delivery type on Apps. Deliberately NOT aria-hidden: unlike the flip cue,
   this is real information.

   HOW IT'S PLACED — and why it must stay IN-FLOW. The pill sits in a
   zero-height flex row that follows the art in normal flow, pulled up over the
   image with a negative margin: it contributes nothing to layout (row height 0,
   pill's own height cancelled by the margin) and paints above the img by tree
   order. It must never gain position:absolute, z-index, transform, opacity
   transitions, or will-change — each of those invites a mobile compositor to
   promote it to its own layer, and a promoted descendant of the flattened face
   escapes the card's 3D flattening. That exact failure shipped twice on real
   phones/tablets while desktop looked fine: first the pill painted mirrored
   through the back of flipped cards (backface-visibility on the pill was
   ignored — a promoted transform-less layer culls against an identity
   transform), then a state-driven opacity hide fixed the bleed but flickered
   during the flip-back, because that same promoted layer is misdrawn
   mid-rotation. In-flow content is rasterised into the face itself — exactly
   like .poke-badge, which is the same kind of chip and never glitched once —
   so the pill rides the card through the whole flip and is culled with the
   face at 90deg. No state juggling, no timing gates.

   The numbers mirror the old absolute inset (6px inside the art's 2px border):
   pill height 22px, pulled up 30px so it floats 8px above the art's outer
   bottom edge; right inset = the art's 0.7rem side margin + 8px. */
.tcg-stat-row {
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  height: 0;
  overflow: visible;
  pointer-events: none;
}

.tcg-stat-pill {
  display: inline-flex;
  align-items: center;
  height: 22px;
  margin: -30px calc(0.7rem + 8px) 0 0;
  padding: 0 8px;
  border-radius: 999px;
  border: 1.5px solid var(--card-ink);
  background: var(--tcg-face);
  color: var(--card-ink);
  box-shadow: 1px 1px 0 var(--card-ink);
  font-family: vcr-osd-mono, ibm-plex-mono, monospace;
  font-size: 0.62rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}

/* Flip affordance, in the top bar. The card is a role="button" that flips and
   nothing on the front said so; the hero card's "click to flip" kicker has
   nowhere to live in a grid. aria-hidden — the card's own aria-label says it. */
.tcg-flip-top {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-family: ibm-plex-mono, monospace;
  font-size: 0.55rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--card-ink);
  opacity: 0.8;
  white-space: nowrap;
}
.tcg-flip-top .material-symbols-outlined {
  font-size: 12px;
  line-height: 1;
}

/* Back faces must never scroll (owner rule). The widget gives .poke-back-inner
   overflow:auto, so the guarantee is that the copy FITS — deliberately not
   overflow:hidden, because that would change the failure mode from a visible
   scrollbar to a silently clipped Case Study button.

   Keyed off the CARD's own rendered width (a container query on
   .poke-scene.tcg-card, set up top), not the viewport. It has to be: on
   casestudies.html the mobile zigzag (portfolio-mobile-fixes.css) shrinks the
   card to make room for its number chip, so card width no longer tracks
   viewport width the way it used to — a viewport media query would tighten
   (or fail to tighten) the wrong cards. One tier, sized for the tightest case
   the zigzag produces (236.8px, at a 320px viewport) — proven at 0px to spare
   there, which only means MORE spare room as width grows toward the 336px
   cutoff (a plain text-reflow property, holding font-size/line-height fixed).
   Do not split this back into two tiers without re-sweeping the whole
   245-336px range: an earlier two-tier attempt left a gap where the milder
   tier wasn't tight enough right above the aggressive tier's cutoff.
   If you edit back copy OR the zigzag's reserved badge space, re-verify every
   back across BOTH galleries at a 320px viewport: scrollHeight must equal
   clientHeight. */
@container tcg-card (max-width: 336px) {
  .tcg-card .poke-back-inner {
    gap: 0.14rem;
    padding: 0.35rem 0.4rem;
  }
  .tcg-card .poke-back-inner h3 { font-size: 0.95rem; }
  .tcg-card .poke-back-inner p { font-size: 0.68rem; line-height: 1.18; }
  .tcg-card .poke-back-inner .poke-badge { font-size: 0.4rem; padding: 1px 3px; }
  .tcg-card .poke-back-inner .poke-links .poke-btn { font-size: 0.54rem; padding: 0.26rem 0.42rem; }
  .tcg-card .poke-back-inner .poke-flip-hint { font-size: 0.4rem; }

  /* FRONT face, same narrow-card tier (2026-07-17). On a ~237px zigzag card
     the front's fixed-size sections (body at 0.68rem, wrapped badges) eat the
     whole plate and pin the flex-fill art at its 64px floor. Tightening the
     body and badge rows hands ~25px back to the art — the section that is
     actually the card's hero. Same signal as the back rules on purpose: the
     squeeze is a function of card width, not viewport width. */
  .tcg-card .poke-body {
    font-size: 0.58rem;
    line-height: 1.35;
    padding: 0.35rem 0.45rem;
    margin-bottom: 0.35rem;
  }
  .tcg-card .poke-body .attack-name { font-size: 0.62rem; }
  .tcg-card .poke-badges { padding: 0.3rem 0.7rem 0.25rem; gap: 3px; }
  .tcg-card .poke-stage-line { font-size: 0.5rem; }
}

/* The open/placeholder slot sits in the same grid: match the card silhouette so
   it reads as an empty sleeve rather than a stray wide panel. Its surface and
   dashed border stay page-local — the two galleries style theirs differently. */
.tcg-open-slot {
  width: 100%;
  max-width: 340px;
  margin: 0 auto;
  aspect-ratio: 2.5 / 3.5;
  border-radius: 18px;
}

/* ============================================================
   THEMES — light -> face -> deep drive the 150deg face gradient;
   tint is the same hue at 0.35 for the top/foot washes. Every face
   must stay light: the plate is paper and the ink is near-black.
   ============================================================ */

/* Websites gallery (casestudies.html) */
.tcg-card--jewelry { --tcg-face: #ffd76a; --tcg-light: #fff3cd; --tcg-deep: #c9922a; --tcg-tint: rgba(255, 215, 106, 0.35); }
.tcg-card--yacht   { --tcg-face: #7de8ff; --tcg-light: #d2f7ff; --tcg-deep: #2f9cc2; --tcg-tint: rgba(125, 232, 255, 0.35); }
.tcg-card--photo   { --tcg-face: #ff9aa8; --tcg-light: #ffd8de; --tcg-deep: #c04a5e; --tcg-tint: rgba(255, 154, 168, 0.35); }
.tcg-card--ads     { --tcg-face: #9dbcff; --tcg-light: #dbe6ff; --tcg-deep: #4c69c6; --tcg-tint: rgba(157, 188, 255, 0.35); }
.tcg-card--auction { --tcg-face: #cba6ff; --tcg-light: #ecdcff; --tcg-deep: #7a4fc0; --tcg-tint: rgba(203, 166, 255, 0.35); }
.tcg-card--metals  { --tcg-face: #c3cede; --tcg-light: #e9eff7; --tcg-deep: #6b7a8f; --tcg-tint: rgba(195, 206, 222, 0.35); }

/* Apps gallery (app-catalog.html) — a deliberately separate palette so the two
   galleries don't read as the same set. Hues sit in the gaps the Websites set
   leaves (~20/75/120/172/248/315 vs ~45/190/215/280/350), and every pair within
   this set is >=45 deg apart. */
.tcg-card--app-auction-house { --tcg-face: #ff9d73; --tcg-light: #ffd9c6; --tcg-deep: #c4522a; --tcg-tint: rgba(255, 157, 115, 0.35); }
.tcg-card--app-sdms          { --tcg-face: #d7f77e; --tcg-light: #f0fcc4; --tcg-deep: #8aad2e; --tcg-tint: rgba(215, 247, 126, 0.35); }
.tcg-card--app-benji         { --tcg-face: #8cf2a0; --tcg-light: #cdfad6; --tcg-deep: #2f9e56; --tcg-tint: rgba(140, 242, 160, 0.35); }
.tcg-card--app-mall          { --tcg-face: #66ead9; --tcg-light: #c6f7f0; --tcg-deep: #22998c; --tcg-tint: rgba(102, 234, 217, 0.35); }
.tcg-card--app-metalscalc    { --tcg-face: #a9a2ff; --tcg-light: #ddd9ff; --tcg-deep: #5b52c4; --tcg-tint: rgba(169, 162, 255, 0.35); }
.tcg-card--app-predictor     { --tcg-face: #ff9ae0; --tcg-light: #ffd6f4; --tcg-deep: #c04a9e; --tcg-tint: rgba(255, 154, 224, 0.35); }
