WORK-478
ID:WORK-478Status:done

Lumina prose interpretation + generalised dropcap

Give Lumina its theme-owned interpretation of [data-reading="prose"] and generalise textblock's dropcap to a prose-register-gated opt-in. Per SPEC-108 §2–§3 + Work breakdown 3.

Priority:mediumComplexity:moderateMilestone:v0.26.0Source:SPEC-108

Criteria completion

Criteria completion: 3 of 3 (100%) checked; history from Jun 25 to Jun 250%25%50%75%100%Jun 25Jun 25
Branches 3
History 4
  1. 9aa2b77
    • ☑ `reading="prose"` drives a theme-owned editorial treatment in Lumina: capped measure (distinct from `width`), a paragraph style, lede eligibility, and running-text niceties — selected by `[data-reading="prose"]`, not rune-name lists.
    • ☑ `dropcap` is a per-instance opt-in available on any `prose` body (generalised from `textblock`), gated on the resolved `prose` register (not a rune allowlist) and a no-op elsewhere; the theme owns the glyph treatment.
    • ☑ `measure` and `width` remain independent — a `width: full` block can hold `reading: prose` text at a capped measure (the editorial-header composition renders correctly, light + dark).
    by bjornolofandersson
  2. cd6daae
    Content editedby Claude
    WORK-478: Lumina prose interpretation + generalised dropcap
  3. ad0a142
    Created (ready)by bjornolofandersson
  4. 17d2678
    Content editedby Claude
    v0.26.0: accept ADR-018 + SPEC-099/100/108, break down into 15 work item

Scope

  • Style [data-reading="prose"] (not rune-name lists) in Lumina: capped measure (--rf-measure, distinct from width), a paragraph style, lede eligibility, and running-text niceties (hanging punctuation, link underline, widow/orphan, hyphenation). fine gets its smaller/tighter treatment; ui is unchanged.
  • Generalise dropcap: plumb it centrally (not re-declared per rune) and gate it on the resolved prose register via READING_CAPABILITIES (WORK-476); a no-op (dev warn) off-register. The non-rune article body reaches it by wrapping the opening passage in textblock. The theme owns the glyph treatment; the author owns where.
  • textblock keeps columns as its own feature; its body becomes reading="prose".

Acceptance Criteria

  • reading="prose" drives a theme-owned editorial treatment in Lumina: capped measure (distinct from width), a paragraph style, lede eligibility, and running-text niceties — selected by [data-reading="prose"], not rune-name lists.
  • dropcap is a per-instance opt-in available on any prose body (generalised from textblock), gated on the resolved prose register (not a rune allowlist) and a no-op elsewhere; the theme owns the glyph treatment.
  • measure and width remain independent — a width: full block can hold reading: prose text at a capped measure (the editorial-header composition renders correctly, light + dark).

Dependencies

  • WORK-476[data-reading] emission + the READING_CAPABILITIES gate.
  • WORK-477 — the per-rune/layout defaults that put bodies into prose to style.

References

  • Spec: SPEC-108 §2 (what prose enables), §3 (dropcap, prose-gated). Composes with SPEC-107.
  • packages/lumina/styles/dimensions/sections.css, packages/runes/src/tags/textblock.ts.

Resolution

Completed: 2026-06-25

Branch: claude/spec-108-lumina-prose

What was done

  • Generalised dropcapdropcap is now a universal boolean attribute (packages/runes/src/lib/index.ts + UNIVERSAL_ATTRIBUTE_NAMES). The engine gates it on the resolved prose register via READING_CAPABILITIES: emits data-dropcap="true" on the body section only when reading is prose, else drops it with a warn-once. Threaded through applyBemClasses/applyProjection alongside data-reading.
  • textblock cleanup — removed its per-rune dropcap attribute, meta, and config modifier (now universal); kept columns/lead/align. Removed the dead .rf-textblock--dropcap CSS (skeleton + lumina).
  • Lumina prose interpretation — new dimensions/reading.css (skeleton: capped --rf-measure, text-wrap, hanging punctuation, dropcap float; lumina: line-height, paragraph rhythm, link underline, the dropcap glyph, and a quieter fine treatment), keyed on [data-reading] — not rune-name lists. Imported in skeleton index.css and lumina index.css + base.css.
  • Tests: dropcap emission (prose → data-dropcap, off-register dropped, flips on when author sets prose) in reading.test.ts; updated the reference universal-attr list and the textblock test; regenerated contracts (TextBlock lost --dropcap).

Notes

  • measure (on [data-reading="prose"]) is independent of the block's width modifier — orthogonal selectors. The gallery visual guard for the full-bleed-frame + capped-measure editorial header lands in WORK-480.
  • 1710 transform/runes/lumina tests green (contracts + CSS coverage + entry parity).