/*
 * The component library, implemented.
 *
 * _ds/components.json is the SPECIFICATION and this file is what the deck
 * actually loads. A component arrives here when it has been extracted from the
 * pages that were building it by hand; until then it is `status: listed` in the
 * JSON and lives wherever hc.css already put it.
 *
 * Load after hc.css and before layout.css.
 *
 * ---- the spacing scale, which now lives in hc.css ----------------------
 *
 * --sp-tight, --sp-snug and --sp-block were declared HERE, on `body.hc-air`,
 * and they have moved to hc.css's :root with the rest of the ladder. Two
 * reasons, and the first is the one that mattered:
 *
 * A SCALE SCOPED TO A CLASS IS NOT A SCALE. On a page that is not `.hc-air`,
 * `var(--sp-block)` resolved to nothing, and an invalid var() takes the whole
 * declaration with it — the margin would not be wrong, it would be absent. All
 * ~580 callers are on `.hc-air` pages today, so nothing was broken; nothing was
 * stopping the next page from breaking it either.
 *
 * And stage 2 added the twelve-rung ladder to hc.css. Two spacing scales in two
 * files, one at :root and one at a class, is how a value gets changed in the
 * one that loses.
 *
 * --sp-block came here at 22px, measured from 623 inline margins across the
 * deck. It is 28px now, which is the design system's value and its argument:
 * 22 was enough to separate two cards, whose edges do most of that work, and
 * not enough to separate two blocks where one of them has no edges.
 */

/* ==========================================================================
   screen_head — names the screen
   components.json: kind "header", origin "new", 134 instances across 38 pages.

   WHY IT IS A COMPONENT. It was three loose siblings with hand-typed gaps, and
   the gaps were drawn at nine different values across the deck: eyebrow to
   title at 5, 6 and 7px, title to supporting line at 5, 6, 8, 9, 10 and 16px.
   One component, re-decided 119 times.

   The wrapper owns both gaps and nothing else. It sets no top margin of its
   own — where a page had one it stays on the wrapper, because the container
   gap that would replace it is specified and not yet applied.

   THE SUPPORTING LINE IS THE COMPONENT'S, NOT THE PAGE'S. Anything following
   the title inside the wrapper is the supporting line, whichever primitive it
   uses: .t-sub, .t-meta and .coach-subtitle all appear in that slot and all
   three take the same gap. The primitive decides the type; the component
   decides the space.
   ========================================================================== */
body.hc-air .screen-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-tight);
}

/* The parts stop carrying their own separation once the wrapper owns it.
   These are the declarations the migration removed from 119 elements; they are
   reset here as well so a hand-written header cannot reintroduce them by
   copying an older page. */
/* `> *` RATHER THAN A LIST OF THE PRIMITIVES. The first version enumerated
   them and one of the six — .t-lead — never appeared in a header at all: a
   selector guarding a case that does not exist. The list also had to grow every
   time a header used a primitive it had not used before, which is a rule that
   fails open. The universal selector cannot be wrong about which children a
   wrapper has. */
body.hc-air .screen-head > * {
  margin-top: 0;
  margin-bottom: 0;
}

/* ==========================================================================
   card_head — a title and its supporting line inside a card
   components.json: kind "header", origin "new", 3 instances on 1 page.

   FOUND BY EXTRACTING screen_head. These three were shrinking .screen-title
   with an inline font-size to use it as a card's title, and the screen_head
   migration wrapped them by mistake. A title that has to be resized at the
   call site is the wrong component wearing a style attribute.

   IT IS NOT screen_head, and the difference is not size. A screen header names
   the screen and there is one; a card head names a card and there can be
   several on a screen. Giving them the same component would make "one per
   screen" unenforceable for either.

   The tracking is -0.4px because that is what these three inherited from
   .screen-title and the extraction is not the place to change how they look.
   At 22px it is proportionally tighter than at 26px and should be revisited
   when the type ramp itself gets specified.
   ========================================================================== */
/* THE BLOCK TITLE, AND IT IS ALWAYS 700. The design system's type ramp names
   this step and states the weight on the same line: "--text-lg 21px · the
   block title, always 700 — cards, zones and bare blocks alike". This rule set
   no weight at all, so every card title in the deck rendered at 400 while
   `HcText.cardTitle` already shipped 700 — the app was the conformant side and
   the deck was not.

   AND THE TRACKING IS THE TOKEN, NOT A LITERAL. -0.4px is --tracking-title
   (-0.02em) at this size to within two hundredths of a pixel, so nothing moves;
   what changes is that it now follows the ramp if the step does. The ramp says
   why in as many words: "Always the token, never a literal — a literal is how
   the two drifted apart across two sheets." */
.card-title {
  font-family: var(--font-display); font-size: var(--text-lg);
  font-weight: 700;
  letter-spacing: var(--tracking-title); line-height: var(--leading-tight);
}
body.hc-air .card-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-tight);
}
body.hc-air .card-head > * { margin-top: 0; margin-bottom: 0; }

/* ==========================================================================
   card_note — the line that explains the card above it
   components.json: kind "surface", origin "new", 24 instances across 16 pages.

   IT IS A SIBLING THAT BELONGS TO THE CARD, and that is why it is a sibling
   selector rather than a wrapper. The note sits on the page ground, outside
   the card's padding — "every one of these carries the moment you were told",
   "two things that share a word with what you typed" — so it is not a slot.
   But it is not an independent block either: it hugs the thing it is about,
   and if the block rhythm ever gives it 22px it stops reading as a footnote
   and starts reading as the next paragraph.

   Twenty-four instances were drawn at SIX different gaps: 10, 12, 14, 16, 18
   and 20px. Twelve is the mode, so --sp-snug moved from the 10px it was
   specified at to the 12px the deck actually draws. It had no other user; a
   scale step with no callers is a guess, and one with a caller is a
   measurement.

   THIS IS WHAT THE BLOCK RHYTHM WAS WAITING FOR. A container gap on .scroll
   would have given all twenty-four of these 22px. Now they are exempt by
   class, and the sweep can happen.
   ========================================================================== */
body.hc-air .scroll > .card + .card-note { margin-top: var(--sp-snug); }

/* ==========================================================================
   overlay — the system's one overlay
   components.json: kind "chrome", origin "new".

   THE ONE OVERLAY, AND IT EXISTS FOR ONE JOB: something the reader must read
   or answer WITHOUT LOSING THEIR PLACE. The deck had none. `Say` sits above the
   content and never over it, and the only scrim in the deck before this one was
   the dimming under an open nav dock — which is a dock's own affordance, not a
   surface. Pick by what the reader can afford to lose: they can afford to lose
   their place, it is a screen; they cannot afford to pause at all, it is a
   `say`; they need to come straight back to what is behind, it is this.

   IT REPLACES NO RUNG OF THE SURFACE LADDER. It sits above it, temporarily,
   and the ladder resumes inside it — the body below holds cards and rows on the
   page ground exactly as a scroll does.

   BOTTOM ON A PHONE, SIDE ON A DESKTOP, ONE COMPONENT. A phone sheet rises from
   the bottom edge because that is where the thumb is; a bottom sheet on a
   1160px canvas is a letterbox, so past the tablet rung it comes in from the
   right instead.

   IT CAPS ITS OWN HEIGHT AT 88%. A sheet that can reach the top edge is a
   screen wearing a scrim, and the sliver of the surface behind it is the whole
   argument: the thing behind is still there and still yours to return to.

   THE SCRIM IS CLICKABLE AND NOT TABBABLE. As a real button it is the first
   focusable node in the layer, so tabbing forward reaches a full-screen "Close"
   before the sheet's own title. It keeps the click and loses the tab stop; the
   close control and Escape are the keyboard's routes out.

   NEVER NESTED, AND IT CARRIES NO NAVIGATION. A sheet opened from a sheet is a
   flow that should have been a screen.

   THE SCRIM DARKENS IN BOTH THEMES, and this is the one place the built
   component is not followed. `Sheet.jsx` mixes 32% of `--on-surface` into
   transparent, which is the exact bug hc.css records and fixed at `.scrim`:
   --on-surface is #15171A on paper and #F7F7F8 in dark, so on dark the receding
   page is LIT by a white veil at 32% instead of being dimmed. A scrim is not
   ink. It is the absence of light. The deck's own measured value is used here
   and the package defect is Q192.

   The head's 20px is the design system's own figure and is NOT on the spacing
   ladder, which says every padding is. See Q191 — twelve off-ladder values sit in
   the package's components layer, and where the two disagree components wins. */
.overlay { position: absolute; inset: 0; z-index: 44; display: flex; }

.overlay .overlay-dim {
  position: absolute; inset: 0; cursor: pointer;
  background: rgba(0,0,0,0.30);
}

.overlay .overlay-panel {
  position: relative; display: flex; flex-direction: column; min-height: 0;
  margin-top: auto; width: 100%; max-height: 88%;
  border-radius: var(--r-card) var(--r-card) 0 0;
  background: var(--surface); box-shadow: var(--shadow-float);
}

.overlay .overlay-head {
  flex: none; padding: 20px 24px 16px;
  display: flex; align-items: flex-start; gap: var(--sp-16);
  box-shadow: inset 0 -1px 0 var(--outline);
}
.overlay .overlay-head .tx { flex: 1; min-width: 0; }
.overlay .overlay-head .micro-label { display: block; margin-bottom: var(--sp-tight); }
.overlay .overlay-head .t {
  display: block; font-size: var(--text-lg); font-weight: 700;
  letter-spacing: var(--tracking-title); line-height: var(--leading-tight);
  color: var(--on-surface); text-wrap: pretty;
}
.overlay .overlay-head .p {
  margin: var(--sp-tight) 0 0; font-size: var(--text-sm);
  line-height: var(--leading-body); color: var(--on-surface-variant);
}
.overlay .overlay-head .icon-btn { flex: none; }

.overlay .overlay-body {
  flex: 1; min-height: 0; overflow-y: auto;
  display: grid; gap: var(--sp-block); grid-auto-rows: min-content;
  align-content: start; padding: var(--sp-24);
}

.overlay .overlay-foot {
  flex: none; padding: var(--sp-16) var(--sp-24) var(--sp-24);
  display: grid; gap: var(--sp-12);
  box-shadow: inset 0 1px 0 var(--outline);
}


/* ==========================================================================
   region — a region of the screen, not a thing on it
   components.json: kind "chrome", origin "new".

   THE SURFACE LADDER'S MIDDLE RUNG, AND IT EXISTED NOWHERE. `--surface-container`
   has carried the comment "a zone: a region of the screen, edge to edge" since
   the palette was written and nothing drew one: zero selectors, zero instances,
   and `--r-zone:0px` declared and read by nothing. The ladder is ground → region
   → card and one of its three rungs was a token with no component.

   WHICH LEFT SIXTY BARE OPTIONS GROUPED BY NOTHING, in five different
   containers: twenty in an unclassed div across seven pages, nineteen straight
   in a `.scroll`, eighteen in `.opts` — a grid defined on 07 alone — and three
   in a `.field`. One rung, re-decided five times.

   IT IS NOT A CARD AND MUST NOT BE MISTAKEN FOR ONE. A card says "here is an
   object you can act on or cite", so wrapping a question and its answers in one
   claims the question is an object. A region claims nothing; it says only that
   everything inside belongs together. FULL WIDTH, SQUARE AND FLAT are the three
   things that separate them at a glance — give a region a radius and it becomes
   a very large card, which is the mistake it exists to prevent.

   IT RUNS TO THE SCREEN EDGE by canceling the scroll's own gutter and putting
   it back inside, so the ground it sits on is the only thing that changes at
   the edge.

   ITS TITLE IS A BLOCK TITLE — `--text-lg` at 700, the same step as a card head
   — AND IT NAMES THE REGION AND NOTHING ELSE. Bold at 21px carries more ink
   than the screen title's regular 27px, so a supporting fact parked in that slot
   outranks the question the screen exists to ask; supporting facts go in
   `screen-head`'s own line. THE EYEBROW ALONE IS A COMPLETE REGION: when it
   already names the region a title only repeats it. What is not allowed is
   NEITHER, which is a gray band with no explanation, and that is a check.

   GROUND → REGION → CARD IS THE DEEPEST LEGAL NESTING. A region inside a region
   is not, and neither is a card inside a card inside a region.

   The package calls this `Zone` and the deck class would be `zone`. It is
   `region` on both sides because `hc_domain` already exports a `Zone` — a room
   or area of the house, 89 of them — and `.sheet` colliding with the viewer's
   page cost a full detour one stage ago. The package's own first words are "a
   region of the screen". Ruled 2026-09-06; the naming map carries it with the
   other five deliberate renames. */
.region {
  background: var(--surface-container);
  margin-inline: calc(var(--page-pad) * -1);
  padding: var(--sp-32) var(--page-pad);
  display: grid; gap: var(--sp-24);
  text-align: center;
}
.region.region-left { text-align: left; }

.region .region-head .micro-label { display: block; margin-bottom: var(--sp-tight); }
.region .region-head .t {
  display: block; font-size: var(--text-lg); font-weight: 700;
  letter-spacing: var(--tracking-title); line-height: var(--leading-tight);
  color: var(--on-surface); text-wrap: pretty;
}
.region .region-head .p {
  margin: var(--sp-tight) 0 0; font-size: var(--text-sm);
  line-height: var(--leading-body); color: var(--on-surface-variant);
  text-wrap: pretty;
}

/* THE CONTENTS ARE ALWAYS LEFT-ALIGNED, whatever the heading does. A centered
   heading over centered options is a poster; the options are read, not admired. */
.region .region-body { display: grid; gap: var(--sp-12); text-align: left; }
