/* ==========================================================================
   CENTAURI 0.4.0 — the page layer (authored; copied through)
   GENERATED by scripts/generate.mjs from scripts/tokens.source.mjs. Do not edit.
   A local edit is not a disagreement to adjudicate; it is a build that no
   longer reproduces, and scripts/check.mjs will say so.
   ========================================================================== */
/* -----------------------------------------------------------------------------
   CENTAURI — the page layer. The blocks an editorial page needs and
   neither a console nor a phone app does, for Centauri Marketing (ADR-012).

   It is called `page` and not `marketing` because a layer is named for what it
   HOLDS, never for the system that imports it — `table`, `chart`, `surface`,
   `lit` — and because a profile and a layer that share a name emit one file
   instead of two (generate.mjs, nameCollisions).

   THE PREMISE. Console and Field are both OPERATING surfaces: a returning user
   working a table, or a returning user working a phone. A marketing page is
   read once, by somebody who has never seen the product, in the order it is
   laid out, and then left. That is a different job, and ADR-010's "no third
   density" refused it on the grounds that a third density would be a looser
   console. It would have been. This is not a looser console: the profile
   changes the rhythm and this layer changes the BLOCKS.

   WHAT THIS LAYER DELIBERATELY DOES NOT ADD. Every house mechanism a marketing
   page needs is already in the base layer, and this composes them rather than
   restating them:

     the eyebrow            `.centauri-label--ruled` — the tracked-caps micro label
                            with its 12px leading rule (ADR-004 D1.8)
     a figure's magnitude   `.centauri-dimension` — length carries the number and
                            color only confirms it; the tick terminates both ends
     rules, not boxes       `.centauri-rows` — a seam is a hairline, never a card
     the "you are here"     `--centauri-static-tick-length` — the same 6px tick that
                            marks the selected tab marks the recommended plan
     a disclosure           `.centauri-disclosure` — the FAQ is that, with motion
     an action              `.centauri-button` / `--primary` / `--quiet`

   So what is here is the page's SKELETON — measure, section rhythm, hero,
   feature seams, figure band, pull quote, plan columns — and nothing that the
   console and the phone already own.

   NO CARD AROUND A FEATURE, AND NO GRADIENT IN THIS LAYER. Those are the two
   defaults that make every generated marketing page the same page. A feature is
   separated from the next one by a rule and by the section rhythm, which is
   what the whitespace is FOR.

   The gradient half of that rule is narrower than it reads. ADR-010 §11 put
   every gradient in the lit surface's static fallback; its amendment of
   2026-09-13 and then ADR-013 D1 replaced the prohibition with three DECLARED
   roles — `bed`, `rim` and `wash` — each bounded at three color stops and one
   hue-carrying role, and each carrying the `@centauri-gradient` declaration
   that says why. Those roles live in `centauri.expressive.css`, never here:
   the page's skeleton declares none, so a gradient reaching a block in THIS
   file is still a defect. A page that wants the material imports
   `centauri.expressive.css` and puts its `.centauri-pane` inside a
   `.centauri-bed` (ADR-013), or `centauri.lit.css` for the one rendered
   region, and declares the composition.
   -------------------------------------------------------------------------- */

/* ---- the page: one measure, one rhythm --------------------------------------

   The measure is the whole of the difference between a marketing page and a
   wide form. WCAG 2.2 SC 1.4.8 puts the AAA ceiling at 80 characters; the
   typography skill's `type_lint.py` reports anything over that and names 60–75
   as the band. 68ch sits in it and is the one number here that is not a token,
   because a measure is a property of the TEXT rather than of the density.

   `--centauri-marketing-measure` is overridable per product for a face whose
   average character width is far from the stack's; nothing else in this layer
   is, on purpose. */
.centauri-page {
  --centauri-marketing-measure: 68ch;
  --centauri-marketing-wide: 72rem;
  margin-inline: auto;
  padding-inline: var(--centauri-scaled-4);
  max-inline-size: var(--centauri-marketing-wide);
  color: var(--color-prose);
}

/* A section is a band of the page, not a container of it. The rhythm is the
   profile's `space-section` — 64px under `marketing`, and the one value the
   profile introduces rather than inherits — and the seam between two sections
   is a hairline, so the page reads as one sheet ruled into parts rather than
   as a stack of cards. */
.centauri-section {
  padding-block: var(--centauri-scaled-section);
}
.centauri-section + .centauri-section {
  border-block-start: var(--centauri-static-stroke-hairline) solid var(--color-hairline);
}
/* Half the rhythm, for two blocks that are one argument — a heading band above
   the features it introduces. */
.centauri-section--tight { padding-block: var(--centauri-scaled-7); }
/* The one section that is NOT ruled off: the first. A rule above the hero is a
   line under the header, which the nav layer already draws. */
.centauri-section:first-child { padding-block-start: var(--centauri-scaled-7); }

.centauri-measure { max-inline-size: var(--centauri-marketing-measure); }

/* ---- the hero ---------------------------------------------------------------

   Every size here is a clamp solved through two real points, and it is BOUNDED
   BY THE SPINE'S OWN TOKENS rather than by a pair of literals. A hand-written
   `clamp(2rem, 5vw, 4rem)` ignores the reader's own font-size setting everywhere
   between its bounds; a solved one written as literals has a subtler problem
   here, and it shipped in the first draft of this file:

     IN CENTAURI, 1rem IS THE PROFILE'S BODY SIZE, NOT 16px.

   The base layer sets the root font-size to `var(--text-body)`, so the root is
   14px under `console`, 16px under `field` and 18px under `marketing` — and
   `generate.mjs` emits the whole geometric tier as `px / 16`, so the display
   tier scales with the profile too. A clamp solved in px and divided by 16
   therefore renders 12.5% large under `marketing`, which is exactly what
   `type_scale.py --fluid 37.32@360 64.5@1280` produced and what the browser
   measured: a 67.8px hero where 64.5px was solved for.

   So the bounds are the tokens, which makes the endpoints exact in EVERY
   profile, and only the `vw` coefficient is solved — for the marketing root,
   because this is the layer Marketing imports. Measured in Chromium at 1280px
   and 375px; `--fluid` still solves the line, the conversion to rem is just
   against 18 rather than 16.

   The title runs display-sm -> display-lg between 360px and 1280px. */
.centauri-hero { display: flex; flex-direction: column; gap: var(--centauri-scaled-5); }
.centauri-hero__title {
  margin: 0;
  max-inline-size: 20ch;
  font-family: var(--font-serif);
  font-size: clamp(var(--text-display-sm), 1.66777rem + 3.32364vw, var(--text-display-lg));
  line-height: var(--text-display-lg--line-height);
  letter-spacing: var(--text-display-lg--letter-spacing);
  font-weight: var(--text-display-lg--font-weight);
  color: var(--color-strong);
  text-wrap: balance;
}

/* The lead paragraph: body -> title-md between 360px and 1280px. Carbon calls
   this `expressive-paragraph-01` and sets it at 24px/1.334 — the only place in
   that system where a paragraph is bigger than body copy, and the reason this
   rung exists rather than the lead just being bold body. */
.centauri-lead {
  margin: 0;
  max-inline-size: var(--centauri-marketing-measure);
  font-size: clamp(var(--text-body), 0.86304rem + 0.68478vw, var(--text-title-md));
  line-height: var(--text-title-md--line-height);
  color: var(--color-muted);
  text-wrap: pretty;
}

/* A section heading: title-lg -> display-sm between 360px and 1280px. */
.centauri-section__title {
  margin: 0 0 var(--centauri-scaled-4);
  max-inline-size: 24ch;
  font-family: var(--font-serif);
  font-size: clamp(var(--text-title-lg), 1.34119rem + 1.39402vw, var(--text-display-sm));
  line-height: var(--text-display-sm--line-height);
  letter-spacing: var(--text-display-sm--letter-spacing);
  font-weight: var(--text-title-lg--font-weight);
  color: var(--color-strong);
  text-wrap: balance;
}

/* ---- running copy ----------------------------------------------------------
   The rhythm inside prose is the profile's, so the same markup is tighter under
   `console` (a docs page in a console product) and looser under `marketing`. */
.centauri-prose { max-inline-size: var(--centauri-marketing-measure); }
.centauri-prose > * { margin-block: 0; }
.centauri-prose > * + * { margin-block-start: var(--centauri-scaled-4); }
.centauri-prose h2, .centauri-prose h3 {
  color: var(--color-strong);
  margin-block-start: var(--centauri-scaled-6);
}
.centauri-prose h2 { font-size: var(--text-title-md); line-height: var(--text-title-md--line-height); }
.centauri-prose h3 { font-size: var(--text-title-sm); line-height: var(--text-title-sm--line-height); }
.centauri-prose a { color: var(--color-accent); text-underline-offset: 0.2em; }
.centauri-prose ul, .centauri-prose ol { padding-inline-start: var(--centauri-scaled-5); }
.centauri-prose li + li { margin-block-start: var(--centauri-scaled-2); }

/* ---- the actions row --------------------------------------------------------
   ONE primary. `craft_lint.py`'s hierarchy family reports a row of controls all
   forced to one width as a fence with no primary action, and a marketing page
   is where that happens most: two equally weighted buttons is a page that has
   not decided what it wants the reader to do. The row does not stretch its
   children, so each keeps its content width. */
.centauri-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--centauri-scaled-3);
}
.centauri-actions > .centauri-button {
  block-size: var(--centauri-scaled-control-height);
  padding-inline: var(--centauri-scaled-control-x);
}
.centauri-actions__note {
  font-size: var(--text-small);
  line-height: var(--text-small--line-height);
  color: var(--color-subtle);
}

/* ---- features: rules at the seams, never a card ---------------------------- */
/* THE SEAM IS HORIZONTAL ONLY, and that is the browser's correction twice over.

   Draft one gave each cell a block-start AND an inline-start rule and shifted
   the grid a negative pixel to clip the outer ones. At 375px the grid is one
   column, so every cell's inline-start rule became a stray left rule down the
   page with nothing on the other side of it — measured, all four of them, and
   invisible to a source pass because the rule is correct as written.

   Draft two made the seam a one-pixel `gap` over a hairline ground. That is
   column-count agnostic and it is what most systems do, and it fails on the row
   that is not full: four features in a three-column grid leave two EMPTY tracks,
   and the grid's hairline ground paints them as a filled block half the width of
   the section. Worse than a stub, and again only visible rendered.

   So: a block-start rule on the cell and nothing else. A full row shares one
   continuous rule, a short row rules only the cells it has, one column rules
   between each — no stub, no filled track, no negative margin, no clipping
   context to trap a focus ring. It is also the more restrained answer, which is
   the house stance: a vertical rule between two features is the beginning of a
   table, and these are not columns of anything. */
.centauri-features {
  display: grid;
  gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}
.centauri-feature {
  display: flex;
  flex-direction: column;
  gap: var(--centauri-scaled-2);
  padding: var(--centauri-scaled-5);
  border-block-start: var(--centauri-static-stroke-hairline) solid var(--color-hairline);
  /* The track floor is `min(100%, 18rem)`, so a long unbroken string — a URL, a
     product code, a German compound — overflows the cell rather than widening
     it. This is the content-side half of that, and the one the author never
     types because the copy they wrote happens to wrap. */
  overflow-wrap: break-word;
}
.centauri-feature__title {
  margin: 0;
  font-size: var(--text-title-sm);
  line-height: var(--text-title-sm--line-height);
  letter-spacing: var(--text-title-sm--letter-spacing);
  font-weight: var(--text-title-sm--font-weight);
  color: var(--color-strong);
}
.centauri-feature > p { margin: 0; color: var(--color-muted); }

/* ---- the figure band --------------------------------------------------------
   A number on a marketing page is a claim, and the house rule is that magnitude
   is carried by LENGTH with color only confirming (ADR-004). So a figure ships
   with `.centauri-dimension` under it from the base layer, and the caption says
   what the length is a fraction OF — a bar with no denominator is decoration. */
.centauri-figures {
  display: grid;
  gap: var(--centauri-scaled-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
}
.centauri-figure { display: flex; flex-direction: column; gap: var(--centauri-scaled-2); }
.centauri-figure__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-display-sm);
  line-height: var(--text-display-sm--line-height);
  letter-spacing: var(--text-display-sm--letter-spacing);
  color: var(--color-strong);
}
/* The unit is not the value. A figure read at the display step with `min` or
   `of 11` set at the same size is two values in one string; at the small step
   beside it, it is a value and its unit. */
.centauri-figure__unit {
  font-family: var(--font-sans);
  font-size: var(--text-small);
  letter-spacing: normal;
  color: var(--color-subtle);
}
.centauri-figure__caption {
  font-size: var(--text-small);
  line-height: var(--text-small--line-height);
  color: var(--color-subtle);
  text-wrap: pretty;
}
/* A figure's bar is read from across a room rather than down a column, so the
   dimension gets the band's own length. `--value` and `--domain` stay the
   caller's: the device is the base layer's and this changes only its scale. */
.centauri-figure > .centauri-dimension { --centauri-dimension-length: 100%; }

/* ---- the pull quote ---------------------------------------------------------
   Marked by a rule on the inline start rather than by a giant glyph or a tinted
   box. The attribution is a definition, not a sentence: a name and a role, each
   labeled by position. */
.centauri-quote {
  margin: 0;
  max-inline-size: var(--centauri-marketing-measure);
  padding-inline-start: var(--centauri-scaled-4);
  border-inline-start: var(--centauri-static-stroke-edge) solid var(--color-edge);
}
.centauri-quote > p {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-title-md);
  line-height: var(--text-title-md--line-height);
  letter-spacing: var(--text-title-md--letter-spacing);
  color: var(--color-strong);
  text-wrap: pretty;
}
.centauri-quote > figcaption {
  margin-block-start: var(--centauri-scaled-3);
  font-size: var(--text-small);
  line-height: var(--text-small--line-height);
  color: var(--color-muted);
}

/* ---- plan columns -----------------------------------------------------------
   A price is a VALUE, so it is set at the datum step in the mono face with
   tabular figures, exactly as a table cell is. The recommended plan is marked
   by the TICK — the same 6px mark that says "you are here" on a tab and "this
   column is sorted" on a table — and not by a filled panel, because a filled
   panel is the one device every pricing page in the category already uses. */
/* Same seam, same reason. A plan column is already legible as a column — the
   name, the price set as a value, and a ruled list under it — so it does not
   also need a line drawn beside it, and a line drawn beside it is what breaks
   the moment three plans wrap to two columns. */
.centauri-plans {
  display: grid;
  gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.centauri-plan {
  display: flex;
  flex-direction: column;
  gap: var(--centauri-scaled-3);
  padding: var(--centauri-scaled-5);
  border-block-start: var(--centauri-static-stroke-hairline) solid var(--color-hairline);
  overflow-wrap: break-word;
}
.centauri-plan__price {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-title-lg);
  line-height: var(--text-title-lg--line-height);
  letter-spacing: var(--text-title-lg--letter-spacing);
  color: var(--color-strong);
}
.centauri-plan__price > span {
  font-family: var(--font-sans);
  font-size: var(--text-small);
  color: var(--color-subtle);
}
.centauri-plan__list { margin: 0; padding: 0; list-style: none; }
.centauri-plan__list > li + li {
  margin-block-start: var(--centauri-scaled-2);
  padding-block-start: var(--centauri-scaled-2);
  border-block-start: var(--centauri-static-stroke-hairline) solid var(--color-hairline);
}
/* The recommendation: a tick above the column, and the word said out loud in
   the micro label. The mark alone is not an accessible name for it. */
.centauri-plan[data-recommended] { position: relative; }
.centauri-plan[data-recommended]::before {
  content: "";
  position: absolute;
  inset-block-start: var(--centauri-static-stroke-hairline);
  inset-inline-start: var(--centauri-scaled-5);
  inline-size: var(--centauri-static-rule-length);
  block-size: var(--centauri-static-tick-length);
  background: var(--color-accent);
}

/* ---- the FAQ ----------------------------------------------------------------
   `.centauri-disclosure` in the base layer already carries the open/close motion
   and the marker reset. This adds the seams and the summary's target size, and
   nothing else. */
.centauri-faq > .centauri-disclosure {
  border-block-start: var(--centauri-static-stroke-hairline) solid var(--color-hairline);
}
.centauri-faq > .centauri-disclosure:last-child {
  border-block-end: var(--centauri-static-stroke-hairline) solid var(--color-hairline);
}
.centauri-faq > .centauri-disclosure > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--centauri-static-gap-icon);
  min-block-size: var(--centauri-scaled-control-height);
  padding-block: var(--centauri-scaled-3);
  font-size: var(--text-datum);
  line-height: var(--text-datum--line-height);
  color: var(--color-strong);
}
.centauri-faq > .centauri-disclosure > summary::after {
  content: "";
  inline-size: var(--centauri-static-rule-length);
  block-size: var(--centauri-static-stroke-edge);
  flex: none;
  background: var(--color-edge);
  transition: rotate var(--centauri-static-enter-fast) var(--ease-standard);
}
.centauri-faq > .centauri-disclosure[open] > summary::after { rotate: 90deg; }
.centauri-faq > .centauri-disclosure > summary + * {
  padding-block-end: var(--centauri-scaled-4);
  max-inline-size: var(--centauri-marketing-measure);
  color: var(--color-muted);
}

/* ---- reduced motion ---------------------------------------------------------
   Shortened, never removed: `transition: none` means no `transitionend` ever
   fires, and anything unmounting on that event stays on screen. 0.01ms still
   completes and still fires (motion_lint.py, PREFERENCE family). */
@media (prefers-reduced-motion: reduce) {
  .centauri-faq > .centauri-disclosure > summary::after {
    transition-duration: 0.01ms;
  }
}
