/* =========================================================================
   The feature explainer — one record, rendered on Help AND on the marketing
   feature page. Design 2.0, Batch 17 (canvas 19 Help).

   ⚠️ **LOADED BY TWO SHELLS THAT SHARE NO TOKENS.** The app loads
   themes/default.css; the marketing site loads marketing-theme.css, and the
   two name their tokens differently. So every token here carries a fallback
   that is the app's light value — the block renders correctly on marketing,
   which has no dark mode, and follows the app's theme where it has one.
   ⛔ Never add a rule here without a fallback: on the marketing page it would
   simply not apply, and nothing in the test suite reads computed styles.
   ⚠️ **ONE EXCEPTION, AND IT IS ENFORCED THE OTHER WAY.** `--text-muted` is
   declared in BOTH themes/default.css and marketing-theme.css (each sheet its
   own value since the app's was darkened on 2026-10-06), so a fallback for it
   is dead code that hardcodes a hex — and
   `tests/core/test_ux_components.py::TestThemeVariables::
   test_text_muted_references_carry_no_hardcoded_fallback` walks every app
   sheet and goes RED on any reference to that token that carries one — the
   test matches the literal text, so it cannot be named here either. A
   fallback was added on 2026-09-05 by reading the blanket rule above, and
   reverted the same day. Check whether marketing-theme.css declares a token
   before giving it a fallback.

   ⭐ **IN THE GRAMMAR — 2026-09-05** (docs/admin/design_system.md, *the card
   goes on the item; the name goes on the ground*).

   ⛔ **AND THE ONE PLACE THE GRAMMAR IS RE-DECLARED RATHER THAN COMPOSED.**
   Every other ported screen writes `class="section-heading"` and
   `class="list-surface"` and lets `components/type.css` and
   `components/cards.css` paint them. These partials cannot: the marketing
   shell links neither sheet, so a composed class would be an unstyled word on
   half of its consumers — the exact failure the header above exists to
   prevent. The rungs below therefore carry the primitives' NUMBERS under
   `.explainer__*` names, and they must be changed together:

       section heading   20 / 500 / Outfit / ink   type.css .section-heading
       item title        16 / 600 / Outfit / ink   cards.css .item__title
       body              15 / 400 / secondary      cards.css .item__desc
       meta              12 / 400 / muted          type.css .meta
       list surface      white, hairline, 20px radius, 44px rows, the measure
       card              white, hairline, 20px radius, 20px padding

   ⚠️ It is a restatement of VALUES, never of a selector: writing
   `.section-heading` in this file would fail
   tests/core/test_shared_css_is_actually_loaded.py, and rightly — a second
   definition of a shared class is the bug that test was written for.
   ========================================================================= */

/* ── The head: the title, then two rungs, not two sizes of one ─────────── */

/* ⛔ THE SUMMARY WAS 17px INK AND THE WHY 16px SECONDARY — one pixel and one
   step of grey apart, which is the "adjacent rungs differ on one axis"
   failure the ladder names. The summary is the reader's sentence (prose:
   18/1.75 ink, 66ch); the why is the lede (16 secondary, 60ch). */
.explainer__head {
    margin-bottom: var(--space-2xl, 2rem);
}

.explainer__name {
    display: flex;
    align-items: center;
    gap: var(--space-xs, 0.5rem);
    margin: 0 0 var(--space-2xs, 0.25rem);
    font-family: var(--font-heading, 'Outfit', sans-serif);
    font-size: 1.75rem;
    font-weight: 400;
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--text-primary, #232820);
    text-wrap: balance;
}

.explainer__icon {
    display: inline-flex;
    color: var(--primary, #5C6B59);
}

/* ⛔ **A FEATURE MARK WITH NO SIZE OF ITS OWN DREW AT 0px ON THE MARKETING
   PAGE** (found 2026-10-12 on /features/mcp/; /features/explore/ and
   /features/voice-journaling/ had it too). FEATURE partials carry a viewBox
   and no width/height, and the rule that sizes them lives in the app's
   component sheets, which the marketing shell does not load — so the svg
   collapsed and the flex gap beside it pushed the name 8px off the column.
   The size is declared here, where both shells read it, with the token's
   app value as its fallback (Memory's partial hardcodes the same 24px). */
.explainer__icon svg {
    width: var(--icon-size, 24px);
    height: var(--icon-size, 24px);
}

.explainer__summary {
    margin: 0 0 var(--space-sm, 0.5rem);
    max-width: 66ch;
    color: var(--text-primary, #232820);
    font-size: var(--text-lg, 1.125rem);
    line-height: 1.75;
}

.explainer__why {
    margin: 0;
    max-width: 60ch;
    color: var(--text-secondary, #4A5448);
    font-size: var(--text-base, 1rem);
    line-height: 1.6;
}

/* ── The name of a run, ON THE GROUND ──────────────────────────────────── */

/* ⛔ THIS WAS 18/400 OVER 16/500 ROWS — a heading LIGHTER than the thing it
   labels — and on a phone it shrank again to 16 inside a box that held it,
   which is the Memory collapse exactly. It is the section-heading rung at
   every width now: 20/500 ink, with the hairline rule beside the name. It
   sits on the ground; the surface beneath it is the container, so no section
   gets a box of its own.

   ⚠️ TWO TAGS, ONE RUNG. The heading level is a template parameter now, because
   the record sits one level deeper on the marketing page than on /help/ — h2
   there, h3 embedded. The LOOK does not change with the level, so both tags
   carry this rule; matching only h2 made every marketing section heading fall
   back to the browser's default and shrink. */
.explainer__section h2,
.explainer__section h3 {
    display: flex;
    align-items: baseline;
    gap: var(--space-2xs, 0.25rem) var(--space-md, 0.75rem);
    margin: 0 0 var(--space-md, 0.75rem);
    font-family: var(--font-heading, 'Outfit', sans-serif);
    font-size: var(--text-xl, 1.25rem);
    font-weight: 500;
    letter-spacing: -0.01em;
    line-height: 1.3;
    color: var(--text-primary, #232820);
}

.explainer__heading-name {
    flex-shrink: 0;
}

.explainer__heading-rule {
    flex: 1;
    min-width: var(--space-2xl, 2rem);
    height: var(--border-width, 1px);
    background: var(--border-color, rgba(35, 40, 32, 0.09));
    align-self: center;
}

/* ── The run ───────────────────────────────────────────────────────────── */

.explainer__section + .explainer__section {
    margin-top: var(--space-2xl, 2rem);
}

/* ── The folds (Help on a phone) ──
   A `<details>` whose summary is the section heading. Open by default, so with
   no JS every section is simply there; help-folds.js closes them below 45rem.
   The marker is our own chevron, not the browser's triangle.

   ⛔ THE FOLD IS NO LONGER A BOX. It used to grow a border, a background and
   a radius below 45rem — with the heading INSIDE it, which is the one thing
   the rule forbids. The box is on the run of items now (`.explainer__pairs`),
   at every width, and the heading stays on the ground on both. */
.explainer__fold > summary {
    list-style: none;
    cursor: pointer;
}

.explainer__fold > summary::-webkit-details-marker {
    display: none;
}

.explainer__summary-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-xs, 0.5rem);
    min-height: 44px;   /* 📐 the standing touch target; a fold is a control */
}

/* Both tags, same reason as the section heading above: the fold is only used by
   /help/ today, where the level is h2, but the level is a parameter and a
   selector that pins one tag is how the look drifts from the outline. */
.explainer__summary-row h2,
.explainer__summary-row h3 {
    flex: 1;
    margin: 0;
}

.explainer__fold[open] > summary {
    margin-bottom: var(--space-md, 0.75rem);
}

.explainer__chevron {
    display: none;
    color: var(--text-muted);
    transition: transform var(--duration-quick, 120ms) var(--ease-out, ease-out);
}

.explainer__fold[open] > summary .explainer__chevron {
    transform: rotate(180deg);
}

/* ── The list surface: ONE box per run, rows on hairlines ──────────────── */

/* Every run on this block is the same shape — a name with a fact — so it is
   one surface and one row, and the section names stay as modifiers on it
   rather than five copies of one declaration.

   ⛔ `.explainer__answers` / `-item` AND `.explainer__step-desc` HAD NO
   DECLARATION AT ALL. The old rule listed `kinds`, `can`, `where` and `limits`
   by hand, and a hand-kept list of the sections that exist goes stale the day
   a fifth is added — `_pairs.html` had been rendering `answers` since Batch 17
   with nothing to paint it, and `__step-desc` ran on into its own title.

   ⛔ AND THE HOOKS WENT WITH THE RULE. `_pairs.html` no longer writes a class
   per section name at all: `.explainer__limits-item` below is the only
   modifier any run needs, so `_limits.html` passes it by name and every other
   section emits `.explainer__pair` alone. A class in the markup with no rule
   anywhere is that same hand-kept list, spelled in HTML.

   ⚠️ **AND NOBODY SAW IT, BECAUSE THE SECTION NEVER REACHES A PAGE.**
   `core/feature_explainer/__init__.py::explainer_for` builds the dict the two
   surfaces render and omits `answers`, so `feature.answers` is always empty
   and neither the section nor its rail entry has ever appeared — while
   `mcp.py` builds seven rows for it off the tool registry. That is a content
   bug, not a grammar one; it is left for its own change, and the shape is
   ready for the day the field arrives. */
.explainer__pairs {
    list-style: none;
    margin: 0;
    padding: 0;
    /* ⛔ **THE FALLBACK IS NOT DEAD CODE — DO NOT TIDY IT AWAY.** It was
       removed as a stale literal on 2026-09-06 and
       `test_every_template_resolves_every_token_it_references` caught it
       within the hour: `marketing/feature_page.html` links THIS sheet but
       not `themes/default.css`, because the marketing site is a separate
       token system by design (CLAUDE.md -> Frontend conventions). With no
       fallback `--measure-page` is undefined there, the declaration is
       invalid at computed-value time, and `max-width` falls back to `none`
       — the explainer runs the full width of a marketing page.
       ⚠️ The value must equal the token; a guard in test_css_extraction.py
       compares them. */
    max-width: var(--measure-page, 52rem);
    background: var(--surface-raised, #fff);
    border: var(--border-width, 1px) solid var(--border-color, rgba(35, 40, 32, 0.09));
    border-radius: var(--radius-card, 20px);
    overflow: hidden;
}

.explainer__pairs > * + * {
    border-top: var(--border-width, 1px) solid var(--border-color, rgba(35, 40, 32, 0.09));
}

.explainer__pair {
    min-height: 44px;
    padding: var(--space-md, 0.75rem) var(--space-lg, 1.25rem);
}

/* The item title rung. */
.explainer__pair dt,
.explainer__step-title {
    display: block;
    margin: 0;
    font-family: var(--font-heading, 'Outfit', sans-serif);
    font-size: var(--text-base, 1rem);
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: 0;
    color: var(--text-primary, #232820);
    overflow-wrap: anywhere;
}

/* The body rung. */
.explainer__pair dd,
.explainer__step-desc {
    display: block;
    margin: var(--space-2xs, 0.25rem) 0 0;
    font-size: var(--text-base-sm, 0.9375rem);
    font-weight: 400;
    line-height: 1.6;
    color: var(--text-secondary, #4A5448);
}

/* ⛔ The limits are the honest edges: a terra accent, never a warning colour.
   It runs down the inside of the surface's left edge, which is what the box's
   `overflow: hidden` is for — five stripes must not end raggedly on the
   radius. */
.explainer__limits-item {
    border-left: var(--border-width-lg, 3px) solid var(--terra, #CAB99E);
}

.explainer__kind-what {
    display: block;
}

/* The real example from the doc, not a category description. */
.explainer__kind-example {
    display: block;
    margin-top: var(--space-2xs, 0.25rem);
    color: var(--text-muted);
    font-family: var(--font-serif, 'Lora', Georgia, serif);
    font-style: italic;
    font-size: var(--text-base-sm, 0.9375rem);
}

/* ── How it works: the same rows, with the step number as the lead ─────── */

/* The numeral is a counter, not a list marker, so it sits INSIDE the
   surface's padding beside its step instead of hanging outside the box. */
.explainer__steps {
    counter-reset: explainer-step;
}

.explainer__step {
    counter-increment: explainer-step;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
        "num title"
        "num desc";
    column-gap: var(--space-md, 0.75rem);
}

.explainer__step::before {
    content: counter(explainer-step);
    grid-area: num;
    align-self: start;
    font-size: var(--text-base, 1rem);
    line-height: 1.35;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.explainer__step-title {
    grid-area: title;
}

.explainer__step-desc {
    grid-area: desc;
}

/*
 * ⭐ **ONE REAL MOMENT FROM ONE REAL JOURNAL.** Set in the reading face, because
 * it is her writing and everything around it is ours. It is the one CARD on
 * the block — a thing read as a single item — so it carries the card's own
 * numbers: 20px radius, 20px padding, hairline, no resting shadow.
 */
.explainer__example {
    margin: 0;
    max-width: var(--measure-page, 52rem);
    padding: var(--space-lg, 1.25rem);
    background: var(--surface-raised, #fff);
    border: var(--border-width, 1px) solid var(--border-color, rgba(35, 40, 32, 0.09));
    border-radius: var(--radius-card, 20px);
}

.explainer__example figcaption {
    margin-bottom: var(--space-2xs, 0.25rem);
    color: var(--text-muted);
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.5;
}

.explainer__example blockquote {
    margin: 0 0 var(--space-sm, 0.75rem);
    color: var(--text-primary, #232820);
    font-family: var(--font-serif, 'Lora', Georgia, serif);
    font-style: italic;
    font-size: var(--text-lg, 1.125rem);
    line-height: 1.5;
}

.explainer__kept {
    list-style: none;
    margin: 0 0 var(--space-sm, 0.75rem);
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs, 0.25rem) var(--space-xs, 0.5rem);
}

.explainer__kept li {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs, 0.25rem);
    padding: 0.25rem 0.75rem;
    border-radius: var(--radius-pill, 100px);
    background: var(--surface-inset, #F5F5F2);
    color: var(--text-primary, #232820);
    font-size: var(--text-base-sm, 0.9375rem);
}

/* The eyebrow rung, tinted: 11 / 600 / 0.09em caps, body face. */
.explainer__tag {
    font-family: var(--font-body, 'Plus Jakarta Sans', sans-serif);
    font-size: var(--text-2xs, 0.6875rem);
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--primary, #5C6B59);
}

.explainer__outcome {
    margin: 0;
    color: var(--text-secondary, #4A5448);
    font-size: var(--text-base-sm, 0.9375rem);
    line-height: 1.6;
}

@media (max-width: 45rem) {
    /*
     * ⭐ **THE EXAMPLE COMES FIRST ON A PHONE**, because the concrete thing has
     * to. Everything after it is reference, and "Worth knowing" is never the
     * section dropped to make room — it folds, it is not removed.
     *
     * ⛔ `#answers` WAS MISSING FROM THIS LIST, and an unlisted flex item is
     * `order: 0` — so *What you can ask it* rendered ABOVE the head, before
     * the name of the feature, on every phone. It sits between the vocabulary
     * and *What you can do*, which is the reading order the composer states.
     */
    .explainer--full {
        display: flex;
        flex-direction: column;
    }

    .explainer--full .explainer__head { order: 1; }
    .explainer--full #example { order: 2; }
    .explainer--full #kinds { order: 3; }
    .explainer--full #answers { order: 4; }
    .explainer--full #can { order: 5; }
    .explainer--full #where { order: 6; }
    .explainer--full #how { order: 7; }
    .explainer--full #limits { order: 8; }

    .explainer--full .explainer__section + .explainer__section {
        margin-top: var(--space-xl, 1.5rem);
    }

    .explainer__chevron {
        display: block;
    }
}
