/*
 * The membership card.
 *
 * SCOPE 7 makes the card the product, so this is the most carefully drawn sheet
 * in the codebase. It follows the design the owner supplied (nine treatments,
 * one anatomy) and it is built at REAL BANK-CARD GEOMETRY.
 *
 * ── Geometry ────────────────────────────────────────────────────────────────
 *
 * ISO/IEC 7810 ID-1 - the size of every bank card, driving licence and insurance
 * card in a wallet: 85.60 x 53.98 mm, an aspect ratio of 1.58577. That number is
 * not a style choice. A member is going to keep this next to their bank cards,
 * print it, and hold it up at a counter beside other cards, and anything that is
 * ALMOST card-shaped reads as a coupon.
 *
 * ── Anatomy (identical on all nine) ─────────────────────────────────────────
 *
 *   top-left      brand lockup: mark + "Inspiration" / "HEALTH"
 *   top-right     "HEALTH CARD"
 *   mid-left      EMV chip, gold or silver per treatment
 *   below chip    NAME in caps, then ID / blood group / emergency
 *   bottom-right  inspirationhealth.org
 *   right third   the treatment's motif, watermarked
 *
 * ── What is deliberately absent ─────────────────────────────────────────────
 *
 * NO QR CODE AND NO BARCODE, anywhere, ever (SCOPE 2 and 7.2). The card is a
 * VISUAL CREDENTIAL: it identifies a person and recalls their number. It does
 * not settle eligibility - an authenticated look-up does. A scannable mark would
 * tell every front desk the opposite of what 7.2 decided, and there is no public
 * verification URL for one to point at.
 *
 * Everything here is CSS and inline SVG. No image files and no web fonts beyond
 * the two the whole product already loads, because this renders on a clinic's
 * guest wifi and a card that fails to load is a card that does not exist.
 */

/* ── Tokens ──────────────────────────────────────────────────────────────── */

:root {
  /* ISO/IEC 7810 ID-1. 85.60 / 53.98 = 1.58577. */
  --card-ratio: 1.58577;
  --card-max: 384px;
}

/*
 * THE SCALING UNIT.
 *
 * Everything inside the card is expressed in --card-u, which is 1% of the
 * card's own rendered width. That makes the interior resolution-independent:
 * the same rules render the 272px preview in the chooser, the 330px card in
 * the household rail and the 384px card on its own page, with no media query
 * for the interior at all.
 *
 * It has to be declared HERE, on the card, and not on :root. Custom properties
 * are substituted where the declaration lives, so a calc() on :root referring
 * to a width set further down computes once against :root and inherits a fixed
 * number - which is the bug this replaced.
 *
 * `1cqw` needs a container, and the wrapper is one in every mode including
 * print. Without a container cqw falls back to the VIEWPORT, which would make
 * a printed card scale with the paper size.
 */
/*
 * THE FALLBACK, first. 1u = 1% of the width the card actually renders at in that
 * context. Used whenever container queries are unavailable — without it `cqw`
 * silently measures the VIEWPORT and every dimension inside the card comes out
 * several times too large, which clips the entire content and leaves only the
 * motif visible.
 */
.card-wrap                { --card-u: 3.84px; }   /* 384px, its own page       */
.hero-art .card-wrap      { --card-u: 3.80px; }   /* 380px, marketing hero     */
.cardstack .card-wrap     { --card-u: 3.30px; }   /* 330px, the household rail */
.cardset .card-wrap       { --card-u: 3.00px; }   /* 300px, the member chooser */
.stylegrid .card-wrap     { --card-u: 3.00px; }   /* 300px, the admin picker   */
.sample-stack .card-wrap  { --card-u: 3.30px; }   /* 330px, the fanned samples */

/*
 * And the real thing where it is available. Declared on `.idcard` rather than on
 * the wrapper on purpose: a value set directly on an element always beats one it
 * inherited, so this wins over the fallback above without needing !important or
 * a specificity fight.
 */
@supports (container-type: inline-size) {
  .card-wrap { container-type: inline-size; }
  .idcard    { --card-u: 1cqw; }
}

/* ── The 3D stage ────────────────────────────────────────────────────────── */

.card-wrap {
  width: 100%;
  max-width: var(--card-max);
}

.card3d {
  perspective: 1500px;
  --mx: 0;
  --my: 0;
}

.idcard {
  position: relative;
  width: 100%;
  aspect-ratio: var(--card-ratio);
  border-radius: calc(var(--card-u) * 4.2);
  overflow: hidden;
  isolation: isolate;

  /* The resting tilt, plus cursor tracking when the script is running. The
     var() fallbacks are 0, so with JS off the card simply sits flat and still
     lifts on hover - nothing depends on the script. */
  transform:
    rotateY(calc(var(--mx) * 7deg))
    rotateX(calc(var(--my) * -7deg))
    translateZ(0);
  transform-style: preserve-3d;
  transition: transform .28s cubic-bezier(.2, .7, .3, 1), box-shadow .28s ease;

  box-shadow:
    0 1px 2px rgba(20, 16, 12, .18),
    0 12px 26px -12px rgba(20, 16, 12, .34),
    0 30px 60px -30px rgba(20, 16, 12, .4);
}

.card3d:hover .idcard {
  transform:
    rotateY(calc(var(--mx) * 9deg))
    rotateX(calc(var(--my) * -9deg))
    translateY(calc(var(--card-u) * -1))
    scale(1.012);
  box-shadow:
    0 2px 4px rgba(20, 16, 12, .2),
    0 20px 40px -14px rgba(20, 16, 12, .38),
    0 46px 80px -34px rgba(20, 16, 12, .46);
}

/* ── Layers ──────────────────────────────────────────────────────────────── */

/* 1. The field. Each treatment paints this. */
.idcard .field {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* 2. The motif, watermarked into the right third. */
.idcard .motif {
  position: absolute;
  right: calc(var(--card-u) * 4);
  top: 50%;
  width: calc(var(--card-u) * 30);
  height: calc(var(--card-u) * 30);
  transform: translateY(-50%);
  z-index: 1;
  pointer-events: none;
}
.idcard .motif svg { width: 100%; height: 100%; display: block; }

/* 3. Engraved guilloche - the fine line-work a real card has. Inline SVG so
      there is no asset to fail to load. */
.idcard .geo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  opacity: .34;
  pointer-events: none;
}

/* 4. The foil sweep. Follows the cursor, and sits still without it. */
.idcard .foil {
  position: absolute;
  inset: -30%;
  z-index: 2;
  pointer-events: none;
  opacity: .5;
  background: linear-gradient(
    105deg,
    transparent 32%,
    rgba(255, 255, 255, .16) 45%,
    rgba(255, 255, 255, .34) 50%,
    rgba(255, 255, 255, .16) 55%,
    transparent 68%
  );
  transform: translateX(calc(var(--mx) * 14%)) translateY(calc(var(--my) * 8%));
  transition: transform .3s ease;
}

/* 5. The content.

      A flex column with a FIXED header and foot and a growing middle. The
      middle is bottom-aligned and clipped, which is what makes a long name
      degrade gracefully: it wraps upward into the slack instead of pushing the
      emergency row off the bottom edge of the card. */
.idcard .inner {
  position: relative;
  z-index: 3;
  height: 100%;
  padding: calc(var(--card-u) * 5) calc(var(--card-u) * 5.4);
  display: flex;
  flex-direction: column;
  font-family: var(--sans);
  color: var(--c-fg, #fff);
  overflow: hidden;
}
.idcard .head, .idcard .chip, .idcard .foot { flex: none; }
/* Neither the name nor the ID rows may be chosen as the item to shrink. */
.idcard .nm, .idcard .rows { flex: none; }

/* Flat treatments skip the gloss entirely. Paper is photocopy-safe by design
   and marble reads as stone, not lacquer. */
.idcard.flat .foil,
.t-paper .foil,
.t-marble .foil { display: none; }

.t-paper { box-shadow: 0 1px 2px rgba(20,16,12,.14), 0 8px 20px -12px rgba(20,16,12,.2); }

/* ── Header ──────────────────────────────────────────────────────────────── */

.idcard .head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: calc(var(--card-u) * 3);
}

.idcard .lockup {
  display: flex;
  align-items: center;
  gap: calc(var(--card-u) * 2.4);
  min-width: 0;
}

/* The cross mark. Drawn in CSS from four rounded arms - no asset, and it stays
   crisp at any size. */
.idcard .mark {
  width: calc(var(--card-u) * 8.2);
  height: calc(var(--card-u) * 8.2);
  flex: none;
  color: var(--c-mark, #e4a20d);
}
.idcard .mark svg { width: 100%; height: 100%; display: block; }

.idcard .word {
  font-family: var(--serif);
  font-size: calc(var(--card-u) * 6.4);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -.005em;
  white-space: nowrap;
}
.idcard .word small {
  display: block;
  font-family: var(--sans);
  font-size: calc(var(--card-u) * 2.5);
  font-weight: 600;
  letter-spacing: .34em;
  text-transform: uppercase;
  margin-top: calc(var(--card-u) * .9);
  opacity: .82;
}

/* The "HEALTH CARD" label is gone. It occupied the top-right corner and
   only repeated what the card obviously is, and the STATUS - which a front
   desk actually needs - now has that corner to itself. */

/* ── Chip ────────────────────────────────────────────────────────────────── */
/* Drawn, not an image: a gradient plate with the contact traces on top. This is
   the single detail that makes a rectangle read as a card. */

.idcard .chip {
  width: calc(var(--card-u) * 11);
  height: calc(var(--card-u) * 7.8);
  border-radius: calc(var(--card-u) * 1.4);
  margin-top: calc(var(--card-u) * 2.6);
  position: relative;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .16);
}

.chip-gold {
  background:
    linear-gradient(135deg, #f4dea4 0%, #d9ad4e 26%, #b8862c 52%, #e6c982 78%, #c39a3c 100%);
}
.chip-silver {
  background:
    linear-gradient(135deg, #eef1f4 0%, #b9c1c9 26%, #8e979f 52%, #dfe4e9 78%, #a5aeb7 100%);
}

/* The contact traces. Two horizontals and two verticals, the layout every EMV
   chip actually has. */
.idcard .chip::before,
.idcard .chip::after {
  content: "";
  position: absolute;
  background: rgba(0, 0, 0, .26);
}
.idcard .chip::before {
  left: 12%; right: 12%;
  top: 33%; height: 1px;
  box-shadow: 0 calc(var(--card-u) * 1.9) 0 rgba(0, 0, 0, .26);
}
.idcard .chip::after {
  top: 16%; bottom: 16%;
  left: 34%; width: 1px;
  box-shadow: calc(var(--card-u) * 2.6) 0 0 rgba(0, 0, 0, .26);
}

/* ── Body ────────────────────────────────────────────────────────────────── */

.idcard .body {
  margin-top: calc(var(--card-u) * 1.8);
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  /* TOP aligned, not bottom. With flex-end an overlong name was pushed up and
     clipped by the overflow - losing the one thing on the card that must never
     be lost. Aligned to the top, anything that does not fit falls off the
     bottom, where the fine print can absorb it. */
  justify-content: flex-start;
  overflow: hidden;
  max-width: 66%;   /* the motif owns the right third */
}

.idcard .nm {
  font-size: calc(var(--card-u) * 4.6);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.06;
  overflow-wrap: break-word;
  /* TWO LINES, then clamp. The vertical budget has room for a second line and
     not a third, and a name that overflows the card is worse than one that
     ends in an ellipsis - the number below it is what the desk types anyway. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-bottom: calc(var(--card-u) * 1.6);
}

/* The plan line is GONE from the face. It was the ~5u that did not fit, and
   the supplied design does not carry one. See the note in card-face. */

.idcard .rows {
  display: flex;
  flex-direction: column;
  gap: calc(var(--card-u) * 1.05);
  font-size: calc(var(--card-u) * 2.85);
  line-height: 1.22;
  flex: none;
}
.idcard .rows > div { display: flex; gap: calc(var(--card-u) * 1.1); }
.idcard .rows .k { opacity: .74; flex: none; }
.idcard .rows .v { font-weight: 600; letter-spacing: .02em; }

/* The member number is the field a desk reads out loud, so it gets tabular
   figures - the digits line up and cannot be misread. */
.idcard .rows .num {
  font-variant-numeric: tabular-nums;
  letter-spacing: .06em;
}

/* ── Foot ────────────────────────────────────────────────────────────────── */

.idcard .foot {
  margin-top: calc(var(--card-u) * 2.4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--card-u) * 2);
  font-size: calc(var(--card-u) * 2.4);
}

/* 7.2 / 9 - on the card itself, so nobody at a counter treats it as an insurance
   card or as proof of coverage in its own right. */
/* One line, ellipsised. Two lines of fine print is the other thing that used
   to overflow, and the full sentence is on the card page and the PDF sheet. */
.idcard .fine {
  opacity: .68;
  line-height: 1.25;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.idcard .site {
  opacity: .86;
  letter-spacing: .02em;
  white-space: nowrap;
  flex: none;
}

/* The status sits in the HEADER, as a flex sibling of the lockup.

   Not absolutely positioned. The first version floated it over the top-right
   corner where the "HEALTH CARD" label already was and the two printed on top
   of each other; two siblings in a flex row cannot overlap, whatever either
   of them grows to. */
.idcard .status { flex: none; padding-top: calc(var(--card-u) * .6); }
.idcard .status .pill {
  font-size: calc(var(--card-u) * 2.3);
  padding: calc(var(--card-u) * .7) calc(var(--card-u) * 1.8);
  white-space: nowrap;
}

/* ── The nine treatments ─────────────────────────────────────────────────── */
/*
 * Each sets four custom properties and paints its field. Keeping them to the
 * same four means a tenth treatment is a dozen lines, not a rewrite.
 *
 *   --c-fg     ink
 *   --c-mark   the cross mark and the motif
 *   --geo      the guilloche stroke
 *   --c-edge   the inner hairline
 */

/* 1. Navy + gold. The brand's own pairing, and the default. */
.t-navy {
  --c-fg: #f4f7fb;
  --c-mark: #e4a20d;
  --geo: rgba(228, 162, 13, .3);
  --c-edge: rgba(228, 162, 13, .22);
}
.t-navy .field {
  background:
    radial-gradient(120% 90% at 88% 8%, #1e4d80 0%, transparent 55%),
    linear-gradient(155deg, #12233f 0%, #0d1b31 48%, #0a1526 100%);
}

/* 2. Gold on cream. */
.t-gold {
  --c-fg: #2b2318;
  --c-mark: #b0821f;
  --geo: rgba(176, 130, 31, .3);
  --c-edge: rgba(176, 130, 31, .3);
}
.t-gold .field {
  background:
    radial-gradient(120% 90% at 86% 10%, #f7e6bd 0%, transparent 58%),
    linear-gradient(150deg, #fdf6e6 0%, #f3e3c2 52%, #e8d3a6 100%);
}

/* 3. Paper. PHOTOCOPY-SAFE: flat, no gradient, maximum contrast, hairline edge.
      A front desk that photocopies a card needs one that survives it. */
.t-paper {
  --c-fg: #1d1a16;
  --c-mark: #8a6a1c;
  --geo: rgba(0, 0, 0, .1);
  --c-edge: rgba(0, 0, 0, .3);
}
.t-paper .field { background: #ffffff; }
.t-paper .motif { opacity: .1 !important; }

/* 4. Mist - near-white with teal. */
.t-mist {
  --c-fg: #17323a;
  --c-mark: #0f8ea0;
  --geo: rgba(15, 142, 160, .22);
  --c-edge: rgba(15, 142, 160, .2);
}
.t-mist .field {
  background:
    radial-gradient(110% 95% at 90% 88%, rgba(15, 142, 160, .22) 0%, transparent 56%),
    linear-gradient(150deg, #ffffff 0%, #f2f7f8 55%, #e6eff1 100%);
}

/* 5. Onyx - black with a teal ECG trace. */
.t-onyx {
  --c-fg: #f2f4f5;
  --c-mark: #22c3d6;
  --geo: rgba(255, 255, 255, .12);
  --c-edge: rgba(255, 255, 255, .14);
}
.t-onyx .field {
  background:
    radial-gradient(120% 90% at 12% 10%, #24282b 0%, transparent 52%),
    linear-gradient(150deg, #17191b 0%, #0e1011 60%, #08090a 100%);
}

/* 6. Forest - deep green with gold. */
.t-forest {
  --c-fg: #f0f5ef;
  --c-mark: #d7ab4c;
  --geo: rgba(215, 171, 76, .28);
  --c-edge: rgba(215, 171, 76, .2);
}
.t-forest .field {
  background:
    radial-gradient(120% 90% at 86% 8%, #1d4433 0%, transparent 56%),
    linear-gradient(152deg, #14301f 0%, #0e2417 52%, #091a10 100%);
}

/* 7. Indigo - blue into violet. */
.t-indigo {
  --c-fg: #f6f4ff;
  --c-mark: #ffffff;
  --geo: rgba(255, 255, 255, .16);
  --c-edge: rgba(255, 255, 255, .18);
}
.t-indigo .field {
  background:
    radial-gradient(110% 80% at 8% 4%, #3f74e8 0%, transparent 52%),
    linear-gradient(148deg, #2f5fd8 0%, #4b3fc4 46%, #6d2fae 100%);
}

/* 8. Marble - stone with a gold rule. Flat, like paper: stone is not lacquered. */
.t-marble {
  --c-fg: #292319;
  --c-mark: #a9821f;
  --geo: rgba(169, 130, 31, .2);
  --c-edge: rgba(169, 130, 31, .5);
}
.t-marble .field {
  background:
    /* The veining. Three soft diagonal washes, which is enough to read as
       marble without becoming a texture nobody asked for. */
    linear-gradient(118deg, transparent 34%, rgba(160, 150, 132, .2) 37%, transparent 41%),
    linear-gradient(74deg, transparent 56%, rgba(160, 150, 132, .16) 60%, transparent 65%),
    radial-gradient(90% 70% at 22% 82%, rgba(150, 140, 122, .18) 0%, transparent 60%),
    linear-gradient(150deg, #fbfaf7 0%, #f2f0ea 55%, #e9e6dd 100%);
}

/* 9. Teal. */
.t-teal {
  --c-fg: #f0fafb;
  --c-mark: #ffffff;
  --geo: rgba(255, 255, 255, .16);
  --c-edge: rgba(255, 255, 255, .18);
}
.t-teal .field {
  background:
    radial-gradient(115% 90% at 88% 90%, #1d8fa1 0%, transparent 58%),
    linear-gradient(150deg, #14707f 0%, #0d5766 54%, #093f4b 100%);
}

/* Shared, driven by the tokens above. */
.idcard .geo g { stroke: var(--geo); }
.idcard .motif { color: var(--c-mark); opacity: .17; }
.t-onyx .motif, .t-indigo .motif, .t-teal .motif { opacity: .26; }

/* The inner hairline every printed card has, one pixel in from the edge. */
.idcard::after {
  content: "";
  position: absolute;
  inset: calc(var(--card-u) * 1.6);
  border: 1px solid var(--c-edge, transparent);
  border-radius: calc(var(--card-u) * 2.6);
  z-index: 4;
  pointer-events: none;
}

/* ── Flat mode: print, PDF-adjacent and photocopy contexts ───────────────── */

.idcard.flat {
  transform: none !important;
  box-shadow: none;
  border: 1px solid rgba(0, 0, 0, .22);
}
.idcard.flat .foil { display: none; }

@media print {
  .idcard { transform: none !important; box-shadow: none; }
  .idcard .foil { display: none; }
  /* Backgrounds print, because a card whose field does not print is a white
     rectangle with a name on it. */
  .idcard, .idcard .field { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ── The chooser ─────────────────────────────────────────────────────────── */

.cardset {
  display: grid;
  /* 300px minimum: below about that the ID row stops being readable and the
     preview stops doing its job, which is showing a member their own card. */
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 22px;
}

.cardset .opt { display: block; }

.cardset label {
  display: block;
  cursor: pointer;
  border-radius: 16px;
  padding: 12px;
  border: 2px solid transparent;
  transition: border-color .16s ease, background .16s ease;
}
.cardset label:hover { background: var(--cream); }

/* The radio is visually hidden but focusable, so the whole tile is clickable
   AND the control is still keyboard-reachable and announced. */
.cardset input[type=radio] {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
  overflow: hidden;
}
.cardset input[type=radio]:checked + label,
.cardset label:has(input[type=radio]:checked) {
  border-color: var(--gold-deep);
  background: var(--cream);
}
.cardset input[type=radio]:focus-visible + label,
.cardset label:has(input[type=radio]:focus-visible) {
  outline: 2px solid var(--gold-deep);
  outline-offset: 2px;
}

.cardset .opt-name,
.cardset .style-name {
  display: block;
  text-align: center;
  margin-top: 11px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}

/* A horizontal rail of cards, for the household view. */
.cardstack {
  display: flex;
  gap: 20px;
  overflow-x: auto;
  padding: 6px 2px 16px;
  scroll-snap-type: x mandatory;
}
.cardstack .card-wrap { max-width: 330px; flex: none; scroll-snap-align: start; }

@media (max-width: 820px) {
  .cardset { grid-template-columns: 1fr; max-width: 400px; }
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */
/* The tilt and the foil are decoration. The card is not. */

@media (prefers-reduced-motion: reduce) {
  .idcard,
  .card3d:hover .idcard { transform: none; transition: none; }
  .idcard .foil { display: none; }
}
