/* ══════════════════════════════════════════════════════════════════════════
   fechter — THE CARD

   The first component in the rebuilt system, and the one every surface was
   already building by hand. Twenty card families existed across preview.html
   and the three engines before this file did; nineteen of them laid their
   content out identically without anyone writing it down, which is how they
   also came to carry eight paddings, six gaps and two radii between them.

   The reading that found it, and the count behind every number below, is
   law/card-anatomy.html. This file is that law as CSS.

   Specified by:  law/card-anatomy.html
   Depends on:    ../tokens/colors_and_type.css   (values)
                  ../materials/                   (grounds — see §4)
   Tested by:     ../test/card.test.ts
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · THE ANATOMY ───────────────────────────────────────────────────────
   Five slots, one fixed order, on a column.

       ┌─────────────────────────────────┐
       │ A eyebrow            B index    │   what it is · which one
       │                                 │
       │           C stage               │   optional — the thing itself
       │                                 │
       │ D subject                       │   REQUIRED — title + body
       │ ─────────────────────────────── │
       │ E footer                        │   optional — the spec line
       └─────────────────────────────────┘

   [Decided — Rafael, 2026-09-01] D is the only required slot; it appears in
   20 of 20 families. A, B, C and E are optional and appear in 11, 9, 9 and 4.
   The order never varies: no card puts the index below the subject, and none
   puts the stage above the eyebrow.
   ────────────────────────────────────────────────────────────────────────── */

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-s);
  border-radius: var(--radius-s);
  border: var(--theme-rim);
  background: var(--theme-card);
  box-shadow: var(--theme-shadow);
  position: relative;
  overflow: hidden;
  box-sizing: border-box;

  /* The measure inside the card is a doubling ladder, and it satisfies the
     Composition Law's grouping rule — the gap INSIDE a group is smaller than
     the gap AROUND it:

         16   the card's own padding        --space-s
          8   the gap between its slots     --space-xs

     There is no third number above them. This block used to open with "32 —
     the field gap between cards, .slots.gap-l", which was wrong twice: the
     field gap was 16, not 32, so it equalled the padding and broke the very
     rule being cited; and .slots.gap-l lives in fechter-deck.css and is not
     what .field uses. Between cards there is now no gap at all — see
     §03, where the wall replaces it. */
}

.card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-s);
}

/* THE ONE LINE THAT MAKES THE CARD READ BOTTOM-LEFT.

   Four families spelled this as justify-content: space-between on the frame,
   three stacked flush, two let a stage push it and eight just let the content
   fall where it landed. margin-top: auto is the only spelling that holds
   regardless of how much content sits above it, so it is the spelling. */
.card-subject { margin-top: auto; }

/* An index without an eyebrow still sits top-right. [Proposed — Claude, 2026-09-30] */
.card-head > .card-index:only-child { margin-left: auto; }

.card-foot {
  padding-top: var(--space-xs);
  border-top: 1px solid var(--border-2);
}

/* ── 2 · THE INDEX IS A CLOSED SET ─────────────────────────────────────────
   [Decided — Rafael, 2026-09-01] The top-right holds a NUMBER, an ICON, or a
   VERY SHORT TAG. Nothing else.

   This retires the loosest thing the old families did with it: sentences.
   .brand-ring-card carried "r = 8 · ROOM ANCHOR" and .bento-card carried
   "Zero cloud runtime" — both prose in a slot that is meant to be scanned,
   not read. A tag that does not fit --card-index-max is too long to be a tag.
   ────────────────────────────────────────────────────────────────────────── */

/* THE EYEBROW IS TITANIUM; THE INDEX IS HEARTH.
   [Decided — Rafael, 2026-09-18] "the cards top right (the icon) is hearth
   colour and the top left side (the tag) is titanium." The eyebrow read
   --theme-accent until then, so a card carried the accent twice in one head
   — the name and the mark competing for the same colour. The eyebrow says
   what class of thing this is; it is a label, and labels are titanium. The
   accent stays with the index, which is the one thing on the card to find. */
.card-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tracking-label);
  color: var(--theme-ink-3);
  display: block;
  min-width: 0;
}

.card-index {
  --card-index-max: 12ch;                 /* a tag, not a sentence */
  flex: none;
  max-width: var(--card-index-max);
  font-family: var(--font-mono);
  font-size: var(--text-eyebrow);
  font-weight: 700;
  letter-spacing: var(--tracking-label);
  color: var(--theme-ink-3);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* the icon form */
.card-index .material-symbols-rounded {
  font-size: var(--icon-xl);
  color: var(--theme-accent);
  display: block;
}

/* THE DOT FORM OF THE ICON — a status LED.
   [Proposed — Claude, 2026-09-02] NOT a fourth index form: the set stays a
   number, an icon or a very short tag, and a dot is the simplest icon there
   is. It is here because the token file already names --blush-led "soft blush
   circadian status LED" and nothing in the system drew one — so every surface
   that wanted a status light hand-rolled a 6px circle. preview.html carries
   ten of them, all off the icon scale, all at a radius the system does not
   have. 8px is --icon-xs, which is half a unit.

   Needs Rafael. The token anticipated this component and the component was
   never built; this is the smallest thing that closes the gap. If it is
   wrong, delete these fourteen lines and the readings lose their light. */
.card-dot {
  display: block;
  width: var(--icon-xs);
  height: var(--icon-xs);
  border-radius: var(--radius-circle);
  background: var(--theme-ink-3);
}
.card-dot.on {
  background: var(--hearth-bright);
  box-shadow: 0 0 var(--space-xs) var(--hearth-bright);
}

/* the numeral form, foreground */
.card-index.numeral {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  font-weight: 400;
  line-height: 1;
  letter-spacing: var(--tracking-none);
  color: var(--theme-accent);
  max-width: none;
}

/* the numeral form, as ground. "Number as icon": the numeral is set at
   display size behind the content, and it REPLACES the top-right mark rather
   than accompanying it. It aligns to the card's padding box, never to the
   rim, so it never reads as a second, clipped element. */
.card-index.watermark {
  position: absolute;
  top: var(--space-s);
  right: var(--space-s);
  max-width: none;
  font-family: var(--font-display);
  font-size: var(--text-h1);            /* was 88px, off the ramp. 96 is the step above it. */
  font-weight: 400;
  line-height: 1;
  color: var(--theme-ink);
  opacity: 0.08;
  pointer-events: none;
  user-select: none;
}

/* ── 3 · THE FOOTPRINT LIVES IN field.css ──────────────────────────────────
   The field, the slot, the tile and the gap moved to ../components/field.css
   on 2026-09-02, and .field became .field.

   The name was the problem. A field does not care what a tile contains — a
   specimen strip, a diagram row and a set of readings belong on one as much
   as a card does — and calling it .field pushed every surface toward
   wrapping things in cards so they could be laid out at all. That is how
   prose ended up in card-shaped boxes.

   A card uses the field by taking a footprint class: .card.u-2x1 on a .field.
   The footprint classes are not scoped to .card and never were meant to be.
   ────────────────────────────────────────────────────────────────────────── */

/* ── 4 · THE GROUND IS A MATERIAL ──────────────────────────────────────────
   [Decided — Rafael, 2026-09-01] The design system holds three kinds of
   thing: TOKENS, COMPONENTS and MATERIALS. A ground is a material.

   Tiers 1-3 are substances and follow the day/dusk switch. Tiers 4 and 5 are
   materials — a photograph, a drawn arc — and must NOT follow it: a timber
   product plate is timber in daylight too. They therefore carry their own ink,
   which is the one thing the token layer cannot yet give them. See
   law/card-anatomy.html §06, the last open item.
   ────────────────────────────────────────────────────────────────────────── */

/* tier 1 · plate — the default, declared by .card above */

/* tier 2 · glass */
.card-glass {
  background: var(--theme-glass);
  background-image: var(--theme-glass-gradient);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}

/* tier 3 · well */
.card-well {
  background: var(--theme-well);
  border: var(--theme-rim-subtle);
  box-shadow: none;
}

/* NO GROUND · bare — the card with its surface taken away.
   [Decided — Rafael, 2026-09-28] Text standing alone on the page, not in a
   box, "should still follow the same spacing logic and size like the cards".
   So it is a card: the same five slots, the same padding and gap, the same
   type, the same footprint on the field — and nothing drawn around it. The
   section's ground shows through.

   [Proposed — Claude, 2026-09-28] The rim is made transparent, not removed:
   a border of zero would shift the content one pixel against the plate
   beside it, and a bare tile must line up with a card exactly. Not a sixth
   ground, the absence of one — law/card-anatomy.html still lists five. */
.card-bare {
  background: none;
  border-color: transparent;
  box-shadow: none;
}

/* tiers 4 AND 5 · the two materials. Both are dark and both are
   theme-independent, so both need the same ink — which is why the ink block
   below names both. It named only tier 4 when this file landed, and tier 5
   inherited theme-bound --theme-ink instead: in light mode its title drew
   #1c1511 on #221d18, a contrast of 1.08:1. A material that carries its own
   ground must carry its own ink in the same rule, or the next one added will
   repeat the fault.

   The ivory is a DS-GAP: the system has no theme-free ink, only theme-bound
   --theme-ink. fechter-doc.css .quote-dark carries the same literal for the
   same reason, and law/card-anatomy.html §06 proposes the token that ends it. */
.card-material,
.card-vector {
  background: var(--timber-base);
  --card-ink: #f7f3ec;                                          /* DS-GAP */
  --card-ink-2: var(--titanium-light);
  --card-ink-3: var(--titanium-base);
  --card-accent: var(--hearth-bright);
  /* The card is a ground, so it hands its ink to what is composed inside it:
     a .nav-link or .btn reads --ink, and without these kept the page's theme
     ink — #5c4e44 on #221d18 in the light theme. */
  --ink: var(--card-ink);
  --ink-2: var(--card-ink-2);
  --ink-3: var(--card-ink-3);
  --accent: var(--card-accent);
  color: var(--card-ink);
}
/* THE DRAWN CARD FOLLOWS THE DAY. [Decided — Rafael, 2026-09-29] "the cards
   with the backgrounds also in dark even if we have light backgrounds" — a
   drawing is not a photograph, so tier 5 takes the theme's substrate: honed
   creme by day with the timber ink, as .g-creme. The photograph, tier 4,
   stays what it was shot on. The inks are the light theme's own tokens, so
   no second copy of the literal. */
[data-theme="light"] .card-vector {
  background: var(--creme-base);
  --card-ink: var(--theme-ink);
  --card-ink-2: var(--theme-ink-2);
  --card-ink-3: var(--titanium-base);
  --card-accent: var(--hearth-base);
  --cutout-blend: multiply;
}
[data-theme="light"] .card-vector .card-veil {
  background: linear-gradient(180deg,
    rgba(var(--creme-base-rgb), 0.20) 0%,
    rgba(var(--creme-base-rgb), 0.90) 100%);
}
.card-material { border-color: rgba(var(--titanium-light-rgb), 0.30); }

.card-material .card-title, .card-vector .card-title,
.card-material .card-val,   .card-vector .card-val   { color: var(--card-ink); }
.card-material .card-body,  .card-vector .card-body  { color: var(--card-ink-2); }
.card-material .card-sub,   .card-vector .card-sub,
.card-material .card-index, .card-vector .card-index,
.card-material .card-eyebrow, .card-vector .card-eyebrow { color: var(--card-ink-2); }
.card-material .card-index.numeral, .card-vector .card-index.numeral,
.card-material .card-index .material-symbols-rounded,
.card-vector   .card-index .material-symbols-rounded { color: var(--card-accent); }
.card-material .card-index.watermark,
.card-vector   .card-index.watermark { color: var(--card-ink); }

/* tier 5 · a drawn ground. The stage bleeds to all four edges and the subject
   floats over it, so the veil is what keeps the type legible over artwork. */
/* object-fit IS WHAT MAKES THIS WORK FOR A PHOTOGRAPH. The rule was written
   for an inline <svg>, which frames itself with preserveAspectRatio, so it
   only ever set width and height. Given an <img> it stretched a square
   2048×2048 source into a 598×244 slot — `fill` is the initial value, so the
   distortion was silent. `cover` is ignored on an inline <svg>, so this costs
   the original use nothing. [Proposed — Claude, 2026-09-04] */
.card-bleed {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.card-veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(var(--timber-base-rgb), 0.20) 0%,
    rgba(var(--timber-base-rgb), 0.90) 100%);
}
/* A BAND STACKS ABOVE A BLEED WHATEVER SURFACE THE CARD WEARS.
   This was scoped `.card-vector > …`, so a .card-material carrying a
   photograph put its veil — absolutely positioned, and therefore painted
   above static content — straight over its own title. The card rendered as a
   picture with no words on it and reported nothing.

   Found by src/engines/sample-robot-doc.html, which is what the specimens are
   for. The lift is a property of the BAND, not of the surface: any card may
   take a bleed, so every card's bands are lifted.
   [Proposed — Claude, 2026-09-04] */
.card > .card-head,
.card > .card-subject,
.card > .card-foot { position: relative; z-index: 2; }

/* ── 5 · THE STAGE, INSET ──────────────────────────────────────────────────
   The other form of slot C: a well with its own rim, holding a drawing or a
   live component rather than becoming the card's ground.
   ────────────────────────────────────────────────────────────────────────── */
.card-stage {
  background: var(--theme-well);
  border: var(--theme-rim-subtle);
  border-radius: var(--radius-s);
  min-height: calc(var(--card-unit) / 2);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.card-stage > svg { width: 100%; display: block; }

/* THE THIRD FORM OF SLOT C — THE CUTOUT.
   [Decided — Rafael, 2026-09-28] "the robot rendering just like this on top
   of it without no background" — a render standing on the surface, with no
   well, rim or crop around it. The bleed covers the card; the stage insets a
   well; the cutout stands the object on whatever the card is made of.

   [Proposed — Claude, 2026-09-28] It takes the space left above the subject
   and is contained in it, never cropped: a render cut in half is not standing
   on anything. The studio renders on white, and multiplying white onto a
   light surface returns the surface, so the backdrop disappears and only the
   object and its shadow remain. On a dark surface multiply would sink the
   object with its backdrop, so there the image is drawn as it is and needs a
   render with a transparent background. --cutout-blend carries the switch:
   the light theme and the light grounds in ../core.css set multiply, the
   dark grounds and the materials set normal, and the default is normal
   because the default theme is timber. */
.card-cutout {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  object-fit: contain;
  mix-blend-mode: var(--cutout-blend, normal);
}

/* THE FOURTH FORM OF SLOT C — THE PICTURE.
   [Proposed — Claude, 2026-09-28] A render that is its own scene — the house
   in section, on its own ground — fills the space above the foot and crops to
   it, inside the card's padding. It is the bleed that leaves room for words:
   a bleed covers the whole card, so its captions would have to sit on a veil
   over the picture. With the picture in slot C the captions go in slot E,
   below the foot's hairline, on a nested field — which is how a picture
   carries several captions without each becoming a tile of its own. */
.card-picture {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  object-fit: cover;
  border-radius: var(--radius-s);
}

[data-theme="light"] { --cutout-blend: multiply; }
.card-material,
.card-vector { --cutout-blend: normal; }

/* A PLATE THAT IS A DRAWING OF A PLATE.
   [Decided — Rafael, 2026-09-02] Rule 7 says a variable-height plate is not a
   tile. A specimen inside a stage is the declared exception: the stage is slot
   C, "the thing itself", and what stands in it is an ILLUSTRATION of a card
   rather than a card doing a job. It carries no footprint because it is not on
   a field, and it sizes to its content because that is what it demonstrates.

   It needs a NAME so the exception is visible. An undeclared exception is
   indistinguishable from the rule being broken — which is how eighteen
   variable-height blocks survived in the first draft of law/the-field.html.
   They looked like a choice. */
.card-specimen {
  min-height: 0;
  box-shadow: var(--elev-1);
}

/* ── 6 · THE SUBJECT'S TYPE ────────────────────────────────────────────────
   Two shapes, one anatomy: a display title over a body, or a numeral over a
   unit. The second is the first at a different scale, which is why .stat-card
   and .touchcard-frame were never two components.
   ────────────────────────────────────────────────────────────────────────── */
.card-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-h3);
  line-height: 1.2;
  color: var(--theme-ink);
  margin: 0;
}
/* THE LARGE TITLE — one step up the ramp, for a tile whose title is the whole
   point (a promise, an invitation) and the body only explains it.
   [Proposed — Claude, 2026-09-30, from Rafael: "the headline of each needs to
   be a bigger font"] */
.card-title.lg { font-size: var(--text-h2); line-height: 1.1; }
.card-val {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-h3);
  line-height: 1;
  color: var(--theme-ink);
}
.card-val-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-xs);
  flex-wrap: wrap;
}
.card-unit-label {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--theme-ink-3);
  letter-spacing: var(--tracking-label);
}
.card-body {
  font-size: var(--text-body);
  line-height: 1.5;
  color: var(--theme-ink-2);
  margin: var(--space-2xs) 0 0;
}
/* THE TITLE STANDS APART FROM ITS BODY — 16, on every card, not only the
   split one. [Decided — Rafael, 2026-09-30: "the space between the headline
   and body is not right. its to close … a design system component problem"]
   4 read as one block; the split card had already been moved to 16. */
.card-title + .card-body { margin-top: var(--space-s); }
.card-sub {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--theme-ink-3);
  display: block;
  margin-top: var(--space-2xs);
}

/* ── 6b · THE PARTS preview.html STATED FIRST ─────────────────────────────
   [Decided — Rafael, 2026-09-29] "these are some of the most beautiful parts
   we have and we are not really using them anywhere". They were written in
   preview.html's own <style>, which said each "belongs in card.css once it
   has been seen on more than three cards". A web page cannot link a preview,
   so they move here, unchanged, and preview.html reads them from this file.
   ────────────────────────────────────────────────────────────────────────── */

/* The third form of slot C: the stage bleeds to the rim on three sides and
   carries the head inside it, so eyebrow and index sit on the material. */
.card-stage-bleed {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-s);
  flex: 1 1 auto;
  margin: calc(-1 * var(--space-s)) calc(-1 * var(--space-s)) 0;
  padding: var(--space-s);
  border: 0;
  border-bottom: var(--theme-rim-subtle);
  border-radius: var(--radius-s) var(--radius-s) 0 0;   /* the card's top corners, a square foot */
  min-height: 0;
  align-items: stretch;
  position: relative;
}
.card-stage-bleed > .card-head { position: relative; z-index: 2; }

/* THE SPLIT 1×2 — two squares, one above the other. [Decided — Rafael,
   2026-09-29] "make the top part of the card square ... and the text below
   also square so its 1x2 each from ratio, and give the text a little more
   room." The bleed stage takes exactly one module; the subject has the other,
   starting at the top of its square with one more rung of padding. Only in a
   field, where --module is known. */
.field > .card-split > .card-stage-bleed {
  flex: none;
  height: calc(var(--module) - var(--field-gap));
}
.card-split > .card-subject {
  margin-top: 0;
  padding: var(--space-xs);
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}
.card-split .card-eyebrow + .card-title { margin-top: var(--space-2xs); }
/* [Decided — Rafael, 2026-09-29] "the space between line and body can be a
   little bit more" — one rung up, 4 to 8; and again [Decided — Rafael,
   2026-09-30: "a little bigger between the body and headline"], 8 to 16. */
.card-split .card-title + .card-body { margin-top: var(--space-s); }

/* A drawing in a stage — a trace, a ground — positioned, never sized by hand. */
.trace-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* A ground stage holds artwork that bleeds; a backdrop stage centres the
   plate that floats on its material. */
.ground-stage   { padding: 0; }
.backdrop-stage { align-items: center; justify-content: center; }
.backdrop-plate {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  width: 85%;
  max-width: calc(var(--card-unit) * 1.5);
}
.room-plate-name { font-size: var(--text-caption); font-weight: 700; }

/* THE HEARTH CARD — the one warm card in a row.
   [Decided — Rafael, 2026-09-29] preview.html §03's 4 % share, which wore it
   as an inline style. The accent as the ground, timber as the ink: 5.08:1 on
   --hearth-base, so the card spends the page's one hearth and nothing else
   on it is orange. Everything composed inside reads the timber. */
.card-hearth {
  background: var(--hearth-light);            /* the dark theme's --theme-accent */
  border-color: transparent;
  --theme-ink: var(--timber-dark);
  --theme-ink-2: var(--timber-dark);
  --theme-ink-3: var(--timber-dark);
  --theme-accent: var(--timber-dark);
  --ink: var(--timber-dark);
  --ink-2: var(--timber-dark);
  --ink-3: var(--timber-dark);
  --accent: var(--timber-dark);
  color: var(--timber-dark);
}
[data-theme="light"] .card-hearth { background: var(--hearth-base); }   /* the light theme's */

/* ── 7 · WHAT IS NOT A CARD ────────────────────────────────────────────────
   [Decided — Rafael, 2026-09-01] .type-card-mini was a row — icon, text,
   control — wearing a card's border. It is a list row, and it is named as one.
   The anatomy stays a column; a row is a different component.

   It was also at a 6px radius, against a token file that says there is one
   container radius and there will not be a third. Both faults were the same
   fault: a component nobody had written down.

   [Corrected 2026-09-02] This note said 6px was the only such corner in the
   repo. It is not — preview.html alone carries 34 of them, and seven distinct
   radius spellings. Correcting this one was right; the count was not.
   ────────────────────────────────────────────────────────────────────────── */
.list-row {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-s);
  border-radius: var(--radius-s);
  border: var(--theme-rim-subtle);
  background: var(--theme-card);
  box-sizing: border-box;
}
.list-row > .grow { flex: 1 1 auto; min-width: 0; }
