@rathnasgala2/template 3.2.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -436,6 +436,18 @@ allowlist: raster formats are admitted directly, and SVG is admitted only after
436
436
  in scope and expected** (TPL-H6 decision): this sanitizer is what makes a
437
437
  theme-declared SVG icon mark safe to publish.
438
438
 
439
+ - **Publication palette and "Visitors see" (4.1.0).** Every build with a theme
440
+ derives the theme's palette-driven tokens from `appearance.tokens` (`{}` is
441
+ the theme's default palette) with `@rathnasgala2/schemas/palette`, checks the
442
+ derived values and every contrast pair in both modes (a failure refuses the
443
+ build with `APPEARANCE_PALETTE_CONTRAST`, naming the pair and mode), and
444
+ writes `assets/gala-palette-<12 hex of sha256>.css`, linked last with SRI and
445
+ listed in the manifest. A theme without a `palette` block is refused
446
+ (`THEME_PALETTE_MISSING`; malformed: `THEME_PALETTE_INVALID`).
447
+ `appearance.colorMode` reaches the page as `data-gala-color-mode-default` and
448
+ `data-gala-color-mode-allowed` on the root; a `light`/`dark` default is the
449
+ server-resolved mode, and a single allowed mode renders no toggle and sets
450
+ `color-scheme` to it.
439
451
  - **`baseUrl` path prefix (2.2.0).** `buildInput.baseUrl` may carry a path (a
440
452
  GitHub project site, `https://owner.github.io/g9/`); it is not origin-only.
441
453
  `internal/route.js#derivePublicBasePath(baseUrl, basePath)` joins that path
@@ -629,7 +641,7 @@ npm run verify
629
641
  hand-maintained) runs, in order: Prettier format check, ESLint,
630
642
  `tsc --checkJs --noEmit`, the dependency-cruiser
631
643
  architecture/module-tree-absence gate, `jscpd` duplication scan, the
632
- `contracts/*.jcs` canonical-form check, the no-local-schema-pin check,
644
+ `contracts/*.jcs` canonical-form check, the no-local-schema-pin check, the
633
645
  `node --test`, the license inventory check, the SBOM currency check
634
646
  (`sbom:check` compares `sbom.cdx.json` against the current lockfile — it is not
635
647
  a presence check), the workflow-pin check, and `npm audit --audit-level=high`.
@@ -645,7 +657,7 @@ npm run architecture # dependency-cruiser: core never imports src/modules, no
645
657
  npm run duplication # jscpd, 3% / 50 tokens
646
658
  npm run contracts:generate # (re)write contracts/*.jcs from their reviewed source modules
647
659
  npm run contracts:check # fail if committed contracts drifted
648
- npm run schema-pin:check # fail on a file: @rathnasgala2/schemas specifier
660
+ npm run schema-pin:check # require the exact registry @rathnasgala2/schemas release
649
661
  npm test # node --test
650
662
  npm run licenses:generate # (re)write THIRD_PARTY_LICENSES.json
651
663
  npm run licenses:check # fail if it drifted from package-lock.json
@@ -656,6 +668,11 @@ npm run workflows:drift # fail if workflow files diverge from their own base
656
668
  npm run audit # npm audit --audit-level=high
657
669
  ```
658
670
 
671
+ Source development does not require a sibling schema checkout. The exact
672
+ `@rathnasgala2/schemas@3.10.0` release is installed from the npm registry, and
673
+ the lockfile carries its registry integrity. The exact peer is the public
674
+ consumer contract.
675
+
659
676
  ## Package layout
660
677
 
661
678
  ```text
@@ -679,17 +696,16 @@ editions: they are a rendered content kind (see Editions).
679
696
 
680
697
  ## Consuming `@rathnasgala2/schemas`
681
698
 
682
- This repository consumes `@rathnasgala2/schemas@3.3.0` from the public npm
683
- registry, declared as `"@rathnasgala2/schemas": "3.3.0"` (exact pin, no range)
684
- so `package-lock.json` records the resolved version and integrity hash. The
685
- LOCAL-1/LOCAL-39 local-tarball convention
686
- (`file:../../local-packages/rathnasgala2-schemas-*.tgz`) is retired for this
687
- package now that it publishes to the registry. The 2.8.0->2.11.0 convergence
688
- changes none of the four roots this renderer validates, for the same reason the
689
- 2.7.0-2.8.0 delta below did not. Only the `"."` export (`validateGalaDocument`,
690
- `GALA_SCHEMA_IDS`) is consumed; the 2.6.0 `./runtime-origins` narrow export and
691
- every other addition through 2.6.1 (new OpenAPI operations, App route/catalog
692
- copy, the `PrincipalSummary`/`AuthenticatorSummary`/keyset field additions) are
699
+ This source targets `@rathnasgala2/schemas@3.10.0` with an exact manifest pin.
700
+ Generation-4 development verifies against the schema sibling/packed candidate.
701
+ The historical `package-lock.json` is not a 3.10.0 registry claim: it must be
702
+ regenerated, together with the SBOM, from the authoritative published 3.10.0
703
+ artifact before release. The 2.8.0->2.11.0 convergence changes none of the four
704
+ roots this renderer validates, for the same reason the 2.7.0-2.8.0 delta below
705
+ did not. Only the `"."` export (`validateGalaDocument`, `GALA_SCHEMA_IDS`) is
706
+ consumed; the 2.6.0 `./runtime-origins` narrow export and every other addition
707
+ through 2.6.1 (new OpenAPI operations, App route/catalog copy, the
708
+ `PrincipalSummary`/`AuthenticatorSummary`/keyset field additions) are
693
709
  App/API-surface changes this renderer does not read. The `"."` export's 2.2.2
694
710
  browser-safety refactor (Node builtins replaced with browser-safe equivalents
695
711
  behind the same public API) is byte-identical in behaviour for a Node consumer
@@ -1 +1 @@
1
- {"attributes":[{"match":"exact-value","name":"data-gala-page-kind","role":"semantic","values":["archive","article","author","error","index","page","profile","series","tag"]},{"match":"exact-value","name":"data-gala-resolved-color-mode","role":"state","values":["dark","light"]},{"match":"exact-value","name":"data-gala-slot","role":"semantic","values":["account-intent","article-end","article-footer-ad","article-preamble","conversation","edition-selector","footer-auxiliary","footer-profile","header-actions","newsletter"]},{"match":"presence","name":"data-gala-publication-root","role":"root","values":[]}],"catalogDigest":"sha256:a10fecf6d43e4392312158f15b66d55a9e2bd3c7816a0747eb2084735d336de5","classSelectors":["g-actions","g-article","g-article-cover","g-article-foot","g-article-grid","g-article-head","g-article-labels","g-article-meta","g-author-bio","g-author-card","g-author-name","g-avatar","g-badge","g-brand","g-brand-name","g-brand-tag","g-brand-text","g-btn","g-byline","g-byline-text","g-card","g-card-body","g-card-excerpt","g-card-foot","g-card-link","g-card-media","g-card-placeholder","g-card-row","g-card-top","g-chip","g-codebar","g-codebar-lang","g-codeblock","g-copy","g-copy-done","g-copy-idle","g-crumbs","g-dek","g-dot","g-eyebrow","g-footer","g-footer-about","g-footer-base","g-footer-brand","g-footer-col","g-footer-grid","g-grid","g-header","g-header-row","g-hero","g-hero-body","g-hero-media","g-icon","g-icon-btn","g-kbd","g-label","g-list","g-main","g-mark","g-menu","g-meta","g-mode-dark","g-mode-icon","g-mode-light","g-mode-system","g-more","g-nav","g-newsletter","g-pager","g-pager-link","g-pager-next","g-pagination","g-panel","g-panel-copy","g-pill","g-pill-count","g-pills","g-progress","g-prose","g-search","g-search-box","g-search-btn","g-search-empty","g-search-hit","g-search-hit-meta","g-search-hit-text","g-search-hit-title","g-search-input","g-search-results","g-section","g-section-head","g-series-box","g-series-card","g-series-here","g-series-list","g-series-n","g-series-tag","g-share","g-skip","g-social","g-sr","g-tag","g-tags","g-toast","g-toc","g-toc-list","g-toc-mobile","g-topic-head","g-topic-hero","g-topic-icon","g-topic-strip","g-wrap","language-bash","language-css","language-diff","language-java","language-javascript","language-json","language-jsx","language-markdown","language-markup","language-python","language-sql","language-tsx","language-typescript","language-yaml","token"],"combinators":[" "," > "," + "," ~ "],"composition":{"compoundOrder":["type","id","class","attribute","pseudo-class","pseudo-element"],"functionalPseudoKeywordArguments":["even","odd"],"functionalSelectorArguments":"compound-only","maximumFunctionalDepth":1,"nthExpressionProfile":"gala-positive-an-plus-b-v2","rootScope":"first-compound-required"},"contractVersion":"3.0.0","functionalPseudos":["is","where","not","nth-child","nth-last-child"],"idSelectors":["gala-appearance-color-mode","main-content"],"orderedLayers":["gala-base","gala-tokens","gala-components","gala-utilities","gala-print"],"profile":"gala-template-styling-contract-v2","pseudoClasses":["active","disabled","focus-visible","hover","visited"],"pseudoElements":["after","before","marker","selection"],"publicThemeSlotHooks":[{"hookId":"code-block","selectorAtom":"pre"},{"hookId":"code-inline","selectorAtom":"code"},{"hookId":"code-language-bash","selectorAtom":".language-bash"},{"hookId":"code-language-css","selectorAtom":".language-css"},{"hookId":"code-language-diff","selectorAtom":".language-diff"},{"hookId":"code-language-java","selectorAtom":".language-java"},{"hookId":"code-language-javascript","selectorAtom":".language-javascript"},{"hookId":"code-language-json","selectorAtom":".language-json"},{"hookId":"code-language-jsx","selectorAtom":".language-jsx"},{"hookId":"code-language-markdown","selectorAtom":".language-markdown"},{"hookId":"code-language-markup","selectorAtom":".language-markup"},{"hookId":"code-language-python","selectorAtom":".language-python"},{"hookId":"code-language-sql","selectorAtom":".language-sql"},{"hookId":"code-language-tsx","selectorAtom":".language-tsx"},{"hookId":"code-language-typescript","selectorAtom":".language-typescript"},{"hookId":"code-language-yaml","selectorAtom":".language-yaml"},{"hookId":"code-token","selectorAtom":".token"},{"hookId":"content-article","selectorAtom":"article"},{"hookId":"control-appearance-toggle","selectorAtom":"#gala-appearance-color-mode"},{"hookId":"control-button","selectorAtom":"button"},{"hookId":"disclosure-details","selectorAtom":"details"},{"hookId":"disclosure-summary","selectorAtom":"summary"},{"hookId":"heading-1","selectorAtom":"h1"},{"hookId":"heading-2","selectorAtom":"h2"},{"hookId":"heading-3","selectorAtom":"h3"},{"hookId":"heading-4","selectorAtom":"h4"},{"hookId":"heading-5","selectorAtom":"h5"},{"hookId":"heading-6","selectorAtom":"h6"},{"hookId":"landmark-footer","selectorAtom":"footer"},{"hookId":"landmark-header","selectorAtom":"header"},{"hookId":"landmark-main","selectorAtom":"main"},{"hookId":"landmark-main-content","selectorAtom":"#main-content"},{"hookId":"landmark-navigation","selectorAtom":"nav"},{"hookId":"landmark-section","selectorAtom":"section"},{"hookId":"media-figure","selectorAtom":"figure"},{"hookId":"media-image","selectorAtom":"img"},{"hookId":"page-archive","selectorAtom":"[data-gala-page-kind=\"archive\"]"},{"hookId":"page-article","selectorAtom":"[data-gala-page-kind=\"article\"]"},{"hookId":"page-author","selectorAtom":"[data-gala-page-kind=\"author\"]"},{"hookId":"page-error","selectorAtom":"[data-gala-page-kind=\"error\"]"},{"hookId":"page-index","selectorAtom":"[data-gala-page-kind=\"index\"]"},{"hookId":"page-page","selectorAtom":"[data-gala-page-kind=\"page\"]"},{"hookId":"page-profile","selectorAtom":"[data-gala-page-kind=\"profile\"]"},{"hookId":"page-series","selectorAtom":"[data-gala-page-kind=\"series\"]"},{"hookId":"page-tag","selectorAtom":"[data-gala-page-kind=\"tag\"]"},{"hookId":"prose-blockquote","selectorAtom":"blockquote"},{"hookId":"prose-divider","selectorAtom":"hr"},{"hookId":"prose-emphasis","selectorAtom":"em"},{"hookId":"prose-link","selectorAtom":"a"},{"hookId":"prose-list-item","selectorAtom":"li"},{"hookId":"prose-list-ordered","selectorAtom":"ol"},{"hookId":"prose-list-unordered","selectorAtom":"ul"},{"hookId":"prose-paragraph","selectorAtom":"p"},{"hookId":"prose-span","selectorAtom":"span"},{"hookId":"prose-strong","selectorAtom":"strong"},{"hookId":"prose-time","selectorAtom":"time"},{"hookId":"slot-account-intent","selectorAtom":"[data-gala-slot=\"account-intent\"]"},{"hookId":"slot-article-end","selectorAtom":"[data-gala-slot=\"article-end\"]"},{"hookId":"slot-article-footer-ad","selectorAtom":"[data-gala-slot=\"article-footer-ad\"]"},{"hookId":"slot-article-preamble","selectorAtom":"[data-gala-slot=\"article-preamble\"]"},{"hookId":"slot-conversation","selectorAtom":"[data-gala-slot=\"conversation\"]"},{"hookId":"slot-edition-selector","selectorAtom":"[data-gala-slot=\"edition-selector\"]"},{"hookId":"slot-footer-auxiliary","selectorAtom":"[data-gala-slot=\"footer-auxiliary\"]"},{"hookId":"slot-footer-profile","selectorAtom":"[data-gala-slot=\"footer-profile\"]"},{"hookId":"slot-header-actions","selectorAtom":"[data-gala-slot=\"header-actions\"]"},{"hookId":"slot-newsletter","selectorAtom":"[data-gala-slot=\"newsletter\"]"},{"hookId":"ui-actions","selectorAtom":".g-actions"},{"hookId":"ui-article","selectorAtom":".g-article"},{"hookId":"ui-article-cover","selectorAtom":".g-article-cover"},{"hookId":"ui-article-foot","selectorAtom":".g-article-foot"},{"hookId":"ui-article-grid","selectorAtom":".g-article-grid"},{"hookId":"ui-article-head","selectorAtom":".g-article-head"},{"hookId":"ui-article-labels","selectorAtom":".g-article-labels"},{"hookId":"ui-article-meta","selectorAtom":".g-article-meta"},{"hookId":"ui-author-bio","selectorAtom":".g-author-bio"},{"hookId":"ui-author-card","selectorAtom":".g-author-card"},{"hookId":"ui-author-name","selectorAtom":".g-author-name"},{"hookId":"ui-avatar","selectorAtom":".g-avatar"},{"hookId":"ui-badge","selectorAtom":".g-badge"},{"hookId":"ui-brand","selectorAtom":".g-brand"},{"hookId":"ui-brand-name","selectorAtom":".g-brand-name"},{"hookId":"ui-brand-tag","selectorAtom":".g-brand-tag"},{"hookId":"ui-brand-text","selectorAtom":".g-brand-text"},{"hookId":"ui-btn","selectorAtom":".g-btn"},{"hookId":"ui-byline","selectorAtom":".g-byline"},{"hookId":"ui-byline-text","selectorAtom":".g-byline-text"},{"hookId":"ui-card","selectorAtom":".g-card"},{"hookId":"ui-card-body","selectorAtom":".g-card-body"},{"hookId":"ui-card-excerpt","selectorAtom":".g-card-excerpt"},{"hookId":"ui-card-foot","selectorAtom":".g-card-foot"},{"hookId":"ui-card-link","selectorAtom":".g-card-link"},{"hookId":"ui-card-media","selectorAtom":".g-card-media"},{"hookId":"ui-card-placeholder","selectorAtom":".g-card-placeholder"},{"hookId":"ui-card-row","selectorAtom":".g-card-row"},{"hookId":"ui-card-top","selectorAtom":".g-card-top"},{"hookId":"ui-chip","selectorAtom":".g-chip"},{"hookId":"ui-codebar","selectorAtom":".g-codebar"},{"hookId":"ui-codebar-lang","selectorAtom":".g-codebar-lang"},{"hookId":"ui-codeblock","selectorAtom":".g-codeblock"},{"hookId":"ui-copy","selectorAtom":".g-copy"},{"hookId":"ui-copy-done","selectorAtom":".g-copy-done"},{"hookId":"ui-copy-idle","selectorAtom":".g-copy-idle"},{"hookId":"ui-crumbs","selectorAtom":".g-crumbs"},{"hookId":"ui-dek","selectorAtom":".g-dek"},{"hookId":"ui-dot","selectorAtom":".g-dot"},{"hookId":"ui-eyebrow","selectorAtom":".g-eyebrow"},{"hookId":"ui-footer","selectorAtom":".g-footer"},{"hookId":"ui-footer-about","selectorAtom":".g-footer-about"},{"hookId":"ui-footer-base","selectorAtom":".g-footer-base"},{"hookId":"ui-footer-brand","selectorAtom":".g-footer-brand"},{"hookId":"ui-footer-col","selectorAtom":".g-footer-col"},{"hookId":"ui-footer-grid","selectorAtom":".g-footer-grid"},{"hookId":"ui-grid","selectorAtom":".g-grid"},{"hookId":"ui-header","selectorAtom":".g-header"},{"hookId":"ui-header-row","selectorAtom":".g-header-row"},{"hookId":"ui-hero","selectorAtom":".g-hero"},{"hookId":"ui-hero-body","selectorAtom":".g-hero-body"},{"hookId":"ui-hero-media","selectorAtom":".g-hero-media"},{"hookId":"ui-icon","selectorAtom":".g-icon"},{"hookId":"ui-icon-btn","selectorAtom":".g-icon-btn"},{"hookId":"ui-kbd","selectorAtom":".g-kbd"},{"hookId":"ui-label","selectorAtom":".g-label"},{"hookId":"ui-list","selectorAtom":".g-list"},{"hookId":"ui-main","selectorAtom":".g-main"},{"hookId":"ui-mark","selectorAtom":".g-mark"},{"hookId":"ui-menu","selectorAtom":".g-menu"},{"hookId":"ui-meta","selectorAtom":".g-meta"},{"hookId":"ui-mode-dark","selectorAtom":".g-mode-dark"},{"hookId":"ui-mode-icon","selectorAtom":".g-mode-icon"},{"hookId":"ui-mode-light","selectorAtom":".g-mode-light"},{"hookId":"ui-mode-system","selectorAtom":".g-mode-system"},{"hookId":"ui-more","selectorAtom":".g-more"},{"hookId":"ui-nav","selectorAtom":".g-nav"},{"hookId":"ui-newsletter","selectorAtom":".g-newsletter"},{"hookId":"ui-pager","selectorAtom":".g-pager"},{"hookId":"ui-pager-link","selectorAtom":".g-pager-link"},{"hookId":"ui-pager-next","selectorAtom":".g-pager-next"},{"hookId":"ui-pagination","selectorAtom":".g-pagination"},{"hookId":"ui-panel","selectorAtom":".g-panel"},{"hookId":"ui-panel-copy","selectorAtom":".g-panel-copy"},{"hookId":"ui-pill","selectorAtom":".g-pill"},{"hookId":"ui-pill-count","selectorAtom":".g-pill-count"},{"hookId":"ui-pills","selectorAtom":".g-pills"},{"hookId":"ui-progress","selectorAtom":".g-progress"},{"hookId":"ui-prose","selectorAtom":".g-prose"},{"hookId":"ui-search","selectorAtom":".g-search"},{"hookId":"ui-search-box","selectorAtom":".g-search-box"},{"hookId":"ui-search-btn","selectorAtom":".g-search-btn"},{"hookId":"ui-search-empty","selectorAtom":".g-search-empty"},{"hookId":"ui-search-hit","selectorAtom":".g-search-hit"},{"hookId":"ui-search-hit-meta","selectorAtom":".g-search-hit-meta"},{"hookId":"ui-search-hit-text","selectorAtom":".g-search-hit-text"},{"hookId":"ui-search-hit-title","selectorAtom":".g-search-hit-title"},{"hookId":"ui-search-input","selectorAtom":".g-search-input"},{"hookId":"ui-search-results","selectorAtom":".g-search-results"},{"hookId":"ui-section","selectorAtom":".g-section"},{"hookId":"ui-section-head","selectorAtom":".g-section-head"},{"hookId":"ui-series-box","selectorAtom":".g-series-box"},{"hookId":"ui-series-card","selectorAtom":".g-series-card"},{"hookId":"ui-series-here","selectorAtom":".g-series-here"},{"hookId":"ui-series-list","selectorAtom":".g-series-list"},{"hookId":"ui-series-n","selectorAtom":".g-series-n"},{"hookId":"ui-series-tag","selectorAtom":".g-series-tag"},{"hookId":"ui-share","selectorAtom":".g-share"},{"hookId":"ui-skip","selectorAtom":".g-skip"},{"hookId":"ui-social","selectorAtom":".g-social"},{"hookId":"ui-sr","selectorAtom":".g-sr"},{"hookId":"ui-tag","selectorAtom":".g-tag"},{"hookId":"ui-tags","selectorAtom":".g-tags"},{"hookId":"ui-toast","selectorAtom":".g-toast"},{"hookId":"ui-toc","selectorAtom":".g-toc"},{"hookId":"ui-toc-list","selectorAtom":".g-toc-list"},{"hookId":"ui-toc-mobile","selectorAtom":".g-toc-mobile"},{"hookId":"ui-topic-head","selectorAtom":".g-topic-head"},{"hookId":"ui-topic-hero","selectorAtom":".g-topic-hero"},{"hookId":"ui-topic-icon","selectorAtom":".g-topic-icon"},{"hookId":"ui-topic-strip","selectorAtom":".g-topic-strip"},{"hookId":"ui-wrap","selectorAtom":".g-wrap"}],"publicationRootSelector":"[data-gala-publication-root]","resolvedPaletteSelectors":{"dark":"[data-gala-publication-root][data-gala-resolved-color-mode=\"dark\"]","light":"[data-gala-publication-root][data-gala-resolved-color-mode=\"light\"]"},"stylesheetLayers":{"components":"gala-components","print":"gala-print","tokens":"gala-tokens","utilities":"gala-utilities"},"templatePackage":"@rathnasgala2/template","templateVersion":"3.0.0","typeSelectors":["a","article","blockquote","button","code","details","em","figure","footer","h1","h2","h3","h4","h5","h6","header","hr","img","li","main","nav","ol","p","pre","section","span","strong","summary","time","ul"]}
1
+ {"attributes":[{"match":"exact-value","name":"data-gala-article-layout","role":"semantic","values":["editorial","full-bleed","issue","prose","technical"]},{"match":"exact-value","name":"data-gala-author-layout","role":"semantic","values":["biography","portfolio","portrait","profile"]},{"match":"exact-value","name":"data-gala-density","role":"semantic","values":["comfortable","compact","spacious"]},{"match":"exact-value","name":"data-gala-footer-layout","role":"semantic","values":["compact","expanded"]},{"match":"exact-value","name":"data-gala-header-layout","role":"semantic","values":["compact","masthead","minimal","publication","utility"]},{"match":"exact-value","name":"data-gala-home-layout","role":"semantic","values":["chronological","gallery","magazine","newspaper","topic-index"]},{"match":"exact-value","name":"data-gala-listing-layout","role":"semantic","values":["dated-rows","image-grid","issues","rows"]},{"match":"exact-value","name":"data-gala-media-ratio","role":"semantic","values":["landscape","mixed"]},{"match":"exact-value","name":"data-gala-page-kind","role":"semantic","values":["archive","article","author","error","index","page","profile","series","tag"]},{"match":"exact-value","name":"data-gala-profile","role":"semantic","values":["developer","editorial","newsletter","personal","visual"]},{"match":"exact-value","name":"data-gala-resolved-color-mode","role":"state","values":["dark","light"]},{"match":"exact-value","name":"data-gala-slot","role":"semantic","values":["account-intent","article-end","article-footer-ad","article-preamble","conversation","edition-selector","footer-auxiliary","footer-profile","header-actions","newsletter"]},{"match":"presence","name":"data-gala-publication-root","role":"root","values":[]}],"catalogDigest":"sha256:63a76754b591a3cda91a4be1f43bdb3fe1d44cf4f9be766154f3944a043399b5","classSelectors":["g-actions","g-article","g-article-cover","g-article-cover-full-bleed","g-article-foot","g-article-grid","g-article-head","g-article-labels","g-article-meta","g-author-bio","g-author-card","g-author-name","g-avatar","g-badge","g-brand","g-brand-name","g-brand-tag","g-brand-text","g-btn","g-byline","g-byline-text","g-card","g-card-body","g-card-excerpt","g-card-foot","g-card-link","g-card-media","g-card-placeholder","g-card-row","g-card-top","g-chip","g-codebar","g-codebar-lang","g-codeblock","g-copy","g-copy-done","g-copy-idle","g-crumbs","g-date-stamp","g-dated-list","g-dated-row","g-dek","g-dot","g-eyebrow","g-footer","g-footer-about","g-footer-base","g-footer-brand","g-footer-col","g-footer-grid","g-grid","g-header","g-header-row","g-hero","g-hero-body","g-hero-media","g-icon","g-icon-btn","g-kbd","g-label","g-list","g-main","g-mark","g-menu","g-meta","g-mode-dark","g-mode-icon","g-mode-light","g-mode-system","g-more","g-nav","g-newsletter","g-pager","g-pager-link","g-pager-next","g-pagination","g-panel","g-panel-copy","g-pill","g-pill-count","g-pills","g-progress","g-prose","g-search","g-search-box","g-search-btn","g-search-empty","g-search-hit","g-search-hit-meta","g-search-hit-text","g-search-hit-title","g-search-input","g-search-results","g-section","g-section-head","g-series-box","g-series-card","g-series-here","g-series-list","g-series-n","g-series-tag","g-share","g-skip","g-social","g-sr","g-tag","g-tags","g-toast","g-toc","g-toc-list","g-toc-mobile","g-topic-head","g-topic-hero","g-topic-icon","g-topic-strip","g-wrap","language-bash","language-css","language-diff","language-java","language-javascript","language-json","language-jsx","language-markdown","language-markup","language-python","language-sql","language-tsx","language-typescript","language-yaml","token"],"combinators":[" "," > "," + "," ~ "],"composition":{"compoundOrder":["type","id","class","attribute","pseudo-class","pseudo-element"],"functionalPseudoKeywordArguments":["even","odd"],"functionalSelectorArguments":"compound-only","maximumFunctionalDepth":1,"nthExpressionProfile":"gala-positive-an-plus-b-v2","rootScope":"first-compound-required"},"contractVersion":"4.0.0","functionalPseudos":["is","where","not","nth-child","nth-last-child"],"idSelectors":["gala-appearance-color-mode","main-content"],"orderedLayers":["gala-base","gala-tokens","gala-components","gala-utilities","gala-print"],"profile":"gala-template-styling-contract-v2","pseudoClasses":["active","disabled","focus-visible","hover","visited"],"pseudoElements":["after","before","marker","selection"],"publicThemeSlotHooks":[{"hookId":"code-block","selectorAtom":"pre"},{"hookId":"code-inline","selectorAtom":"code"},{"hookId":"code-language-bash","selectorAtom":".language-bash"},{"hookId":"code-language-css","selectorAtom":".language-css"},{"hookId":"code-language-diff","selectorAtom":".language-diff"},{"hookId":"code-language-java","selectorAtom":".language-java"},{"hookId":"code-language-javascript","selectorAtom":".language-javascript"},{"hookId":"code-language-json","selectorAtom":".language-json"},{"hookId":"code-language-jsx","selectorAtom":".language-jsx"},{"hookId":"code-language-markdown","selectorAtom":".language-markdown"},{"hookId":"code-language-markup","selectorAtom":".language-markup"},{"hookId":"code-language-python","selectorAtom":".language-python"},{"hookId":"code-language-sql","selectorAtom":".language-sql"},{"hookId":"code-language-tsx","selectorAtom":".language-tsx"},{"hookId":"code-language-typescript","selectorAtom":".language-typescript"},{"hookId":"code-language-yaml","selectorAtom":".language-yaml"},{"hookId":"code-token","selectorAtom":".token"},{"hookId":"composition-article-layout-editorial","selectorAtom":"[data-gala-article-layout=\"editorial\"]"},{"hookId":"composition-article-layout-full-bleed","selectorAtom":"[data-gala-article-layout=\"full-bleed\"]"},{"hookId":"composition-article-layout-issue","selectorAtom":"[data-gala-article-layout=\"issue\"]"},{"hookId":"composition-article-layout-prose","selectorAtom":"[data-gala-article-layout=\"prose\"]"},{"hookId":"composition-article-layout-technical","selectorAtom":"[data-gala-article-layout=\"technical\"]"},{"hookId":"composition-author-layout-biography","selectorAtom":"[data-gala-author-layout=\"biography\"]"},{"hookId":"composition-author-layout-portfolio","selectorAtom":"[data-gala-author-layout=\"portfolio\"]"},{"hookId":"composition-author-layout-portrait","selectorAtom":"[data-gala-author-layout=\"portrait\"]"},{"hookId":"composition-author-layout-profile","selectorAtom":"[data-gala-author-layout=\"profile\"]"},{"hookId":"composition-density-comfortable","selectorAtom":"[data-gala-density=\"comfortable\"]"},{"hookId":"composition-density-compact","selectorAtom":"[data-gala-density=\"compact\"]"},{"hookId":"composition-density-spacious","selectorAtom":"[data-gala-density=\"spacious\"]"},{"hookId":"composition-footer-layout-compact","selectorAtom":"[data-gala-footer-layout=\"compact\"]"},{"hookId":"composition-footer-layout-expanded","selectorAtom":"[data-gala-footer-layout=\"expanded\"]"},{"hookId":"composition-header-layout-compact","selectorAtom":"[data-gala-header-layout=\"compact\"]"},{"hookId":"composition-header-layout-masthead","selectorAtom":"[data-gala-header-layout=\"masthead\"]"},{"hookId":"composition-header-layout-minimal","selectorAtom":"[data-gala-header-layout=\"minimal\"]"},{"hookId":"composition-header-layout-publication","selectorAtom":"[data-gala-header-layout=\"publication\"]"},{"hookId":"composition-header-layout-utility","selectorAtom":"[data-gala-header-layout=\"utility\"]"},{"hookId":"composition-home-layout-chronological","selectorAtom":"[data-gala-home-layout=\"chronological\"]"},{"hookId":"composition-home-layout-gallery","selectorAtom":"[data-gala-home-layout=\"gallery\"]"},{"hookId":"composition-home-layout-magazine","selectorAtom":"[data-gala-home-layout=\"magazine\"]"},{"hookId":"composition-home-layout-newspaper","selectorAtom":"[data-gala-home-layout=\"newspaper\"]"},{"hookId":"composition-home-layout-topic-index","selectorAtom":"[data-gala-home-layout=\"topic-index\"]"},{"hookId":"composition-listing-layout-dated-rows","selectorAtom":"[data-gala-listing-layout=\"dated-rows\"]"},{"hookId":"composition-listing-layout-image-grid","selectorAtom":"[data-gala-listing-layout=\"image-grid\"]"},{"hookId":"composition-listing-layout-issues","selectorAtom":"[data-gala-listing-layout=\"issues\"]"},{"hookId":"composition-listing-layout-rows","selectorAtom":"[data-gala-listing-layout=\"rows\"]"},{"hookId":"composition-media-ratio-landscape","selectorAtom":"[data-gala-media-ratio=\"landscape\"]"},{"hookId":"composition-media-ratio-mixed","selectorAtom":"[data-gala-media-ratio=\"mixed\"]"},{"hookId":"composition-profile-developer","selectorAtom":"[data-gala-profile=\"developer\"]"},{"hookId":"composition-profile-editorial","selectorAtom":"[data-gala-profile=\"editorial\"]"},{"hookId":"composition-profile-newsletter","selectorAtom":"[data-gala-profile=\"newsletter\"]"},{"hookId":"composition-profile-personal","selectorAtom":"[data-gala-profile=\"personal\"]"},{"hookId":"composition-profile-visual","selectorAtom":"[data-gala-profile=\"visual\"]"},{"hookId":"content-article","selectorAtom":"article"},{"hookId":"control-appearance-toggle","selectorAtom":"#gala-appearance-color-mode"},{"hookId":"control-button","selectorAtom":"button"},{"hookId":"disclosure-details","selectorAtom":"details"},{"hookId":"disclosure-summary","selectorAtom":"summary"},{"hookId":"heading-1","selectorAtom":"h1"},{"hookId":"heading-2","selectorAtom":"h2"},{"hookId":"heading-3","selectorAtom":"h3"},{"hookId":"heading-4","selectorAtom":"h4"},{"hookId":"heading-5","selectorAtom":"h5"},{"hookId":"heading-6","selectorAtom":"h6"},{"hookId":"landmark-footer","selectorAtom":"footer"},{"hookId":"landmark-header","selectorAtom":"header"},{"hookId":"landmark-main","selectorAtom":"main"},{"hookId":"landmark-main-content","selectorAtom":"#main-content"},{"hookId":"landmark-navigation","selectorAtom":"nav"},{"hookId":"landmark-section","selectorAtom":"section"},{"hookId":"media-figure","selectorAtom":"figure"},{"hookId":"media-image","selectorAtom":"img"},{"hookId":"page-archive","selectorAtom":"[data-gala-page-kind=\"archive\"]"},{"hookId":"page-article","selectorAtom":"[data-gala-page-kind=\"article\"]"},{"hookId":"page-author","selectorAtom":"[data-gala-page-kind=\"author\"]"},{"hookId":"page-error","selectorAtom":"[data-gala-page-kind=\"error\"]"},{"hookId":"page-index","selectorAtom":"[data-gala-page-kind=\"index\"]"},{"hookId":"page-page","selectorAtom":"[data-gala-page-kind=\"page\"]"},{"hookId":"page-profile","selectorAtom":"[data-gala-page-kind=\"profile\"]"},{"hookId":"page-series","selectorAtom":"[data-gala-page-kind=\"series\"]"},{"hookId":"page-tag","selectorAtom":"[data-gala-page-kind=\"tag\"]"},{"hookId":"prose-blockquote","selectorAtom":"blockquote"},{"hookId":"prose-divider","selectorAtom":"hr"},{"hookId":"prose-emphasis","selectorAtom":"em"},{"hookId":"prose-link","selectorAtom":"a"},{"hookId":"prose-list-item","selectorAtom":"li"},{"hookId":"prose-list-ordered","selectorAtom":"ol"},{"hookId":"prose-list-unordered","selectorAtom":"ul"},{"hookId":"prose-paragraph","selectorAtom":"p"},{"hookId":"prose-span","selectorAtom":"span"},{"hookId":"prose-strong","selectorAtom":"strong"},{"hookId":"prose-time","selectorAtom":"time"},{"hookId":"slot-account-intent","selectorAtom":"[data-gala-slot=\"account-intent\"]"},{"hookId":"slot-article-end","selectorAtom":"[data-gala-slot=\"article-end\"]"},{"hookId":"slot-article-footer-ad","selectorAtom":"[data-gala-slot=\"article-footer-ad\"]"},{"hookId":"slot-article-preamble","selectorAtom":"[data-gala-slot=\"article-preamble\"]"},{"hookId":"slot-conversation","selectorAtom":"[data-gala-slot=\"conversation\"]"},{"hookId":"slot-edition-selector","selectorAtom":"[data-gala-slot=\"edition-selector\"]"},{"hookId":"slot-footer-auxiliary","selectorAtom":"[data-gala-slot=\"footer-auxiliary\"]"},{"hookId":"slot-footer-profile","selectorAtom":"[data-gala-slot=\"footer-profile\"]"},{"hookId":"slot-header-actions","selectorAtom":"[data-gala-slot=\"header-actions\"]"},{"hookId":"slot-newsletter","selectorAtom":"[data-gala-slot=\"newsletter\"]"},{"hookId":"ui-actions","selectorAtom":".g-actions"},{"hookId":"ui-article","selectorAtom":".g-article"},{"hookId":"ui-article-cover","selectorAtom":".g-article-cover"},{"hookId":"ui-article-cover-full-bleed","selectorAtom":".g-article-cover-full-bleed"},{"hookId":"ui-article-foot","selectorAtom":".g-article-foot"},{"hookId":"ui-article-grid","selectorAtom":".g-article-grid"},{"hookId":"ui-article-head","selectorAtom":".g-article-head"},{"hookId":"ui-article-labels","selectorAtom":".g-article-labels"},{"hookId":"ui-article-meta","selectorAtom":".g-article-meta"},{"hookId":"ui-author-bio","selectorAtom":".g-author-bio"},{"hookId":"ui-author-card","selectorAtom":".g-author-card"},{"hookId":"ui-author-name","selectorAtom":".g-author-name"},{"hookId":"ui-avatar","selectorAtom":".g-avatar"},{"hookId":"ui-badge","selectorAtom":".g-badge"},{"hookId":"ui-brand","selectorAtom":".g-brand"},{"hookId":"ui-brand-name","selectorAtom":".g-brand-name"},{"hookId":"ui-brand-tag","selectorAtom":".g-brand-tag"},{"hookId":"ui-brand-text","selectorAtom":".g-brand-text"},{"hookId":"ui-btn","selectorAtom":".g-btn"},{"hookId":"ui-byline","selectorAtom":".g-byline"},{"hookId":"ui-byline-text","selectorAtom":".g-byline-text"},{"hookId":"ui-card","selectorAtom":".g-card"},{"hookId":"ui-card-body","selectorAtom":".g-card-body"},{"hookId":"ui-card-excerpt","selectorAtom":".g-card-excerpt"},{"hookId":"ui-card-foot","selectorAtom":".g-card-foot"},{"hookId":"ui-card-link","selectorAtom":".g-card-link"},{"hookId":"ui-card-media","selectorAtom":".g-card-media"},{"hookId":"ui-card-placeholder","selectorAtom":".g-card-placeholder"},{"hookId":"ui-card-row","selectorAtom":".g-card-row"},{"hookId":"ui-card-top","selectorAtom":".g-card-top"},{"hookId":"ui-chip","selectorAtom":".g-chip"},{"hookId":"ui-codebar","selectorAtom":".g-codebar"},{"hookId":"ui-codebar-lang","selectorAtom":".g-codebar-lang"},{"hookId":"ui-codeblock","selectorAtom":".g-codeblock"},{"hookId":"ui-copy","selectorAtom":".g-copy"},{"hookId":"ui-copy-done","selectorAtom":".g-copy-done"},{"hookId":"ui-copy-idle","selectorAtom":".g-copy-idle"},{"hookId":"ui-crumbs","selectorAtom":".g-crumbs"},{"hookId":"ui-date-stamp","selectorAtom":".g-date-stamp"},{"hookId":"ui-dated-list","selectorAtom":".g-dated-list"},{"hookId":"ui-dated-row","selectorAtom":".g-dated-row"},{"hookId":"ui-dek","selectorAtom":".g-dek"},{"hookId":"ui-dot","selectorAtom":".g-dot"},{"hookId":"ui-eyebrow","selectorAtom":".g-eyebrow"},{"hookId":"ui-footer","selectorAtom":".g-footer"},{"hookId":"ui-footer-about","selectorAtom":".g-footer-about"},{"hookId":"ui-footer-base","selectorAtom":".g-footer-base"},{"hookId":"ui-footer-brand","selectorAtom":".g-footer-brand"},{"hookId":"ui-footer-col","selectorAtom":".g-footer-col"},{"hookId":"ui-footer-grid","selectorAtom":".g-footer-grid"},{"hookId":"ui-grid","selectorAtom":".g-grid"},{"hookId":"ui-header","selectorAtom":".g-header"},{"hookId":"ui-header-row","selectorAtom":".g-header-row"},{"hookId":"ui-hero","selectorAtom":".g-hero"},{"hookId":"ui-hero-body","selectorAtom":".g-hero-body"},{"hookId":"ui-hero-media","selectorAtom":".g-hero-media"},{"hookId":"ui-icon","selectorAtom":".g-icon"},{"hookId":"ui-icon-btn","selectorAtom":".g-icon-btn"},{"hookId":"ui-kbd","selectorAtom":".g-kbd"},{"hookId":"ui-label","selectorAtom":".g-label"},{"hookId":"ui-list","selectorAtom":".g-list"},{"hookId":"ui-main","selectorAtom":".g-main"},{"hookId":"ui-mark","selectorAtom":".g-mark"},{"hookId":"ui-menu","selectorAtom":".g-menu"},{"hookId":"ui-meta","selectorAtom":".g-meta"},{"hookId":"ui-mode-dark","selectorAtom":".g-mode-dark"},{"hookId":"ui-mode-icon","selectorAtom":".g-mode-icon"},{"hookId":"ui-mode-light","selectorAtom":".g-mode-light"},{"hookId":"ui-mode-system","selectorAtom":".g-mode-system"},{"hookId":"ui-more","selectorAtom":".g-more"},{"hookId":"ui-nav","selectorAtom":".g-nav"},{"hookId":"ui-newsletter","selectorAtom":".g-newsletter"},{"hookId":"ui-pager","selectorAtom":".g-pager"},{"hookId":"ui-pager-link","selectorAtom":".g-pager-link"},{"hookId":"ui-pager-next","selectorAtom":".g-pager-next"},{"hookId":"ui-pagination","selectorAtom":".g-pagination"},{"hookId":"ui-panel","selectorAtom":".g-panel"},{"hookId":"ui-panel-copy","selectorAtom":".g-panel-copy"},{"hookId":"ui-pill","selectorAtom":".g-pill"},{"hookId":"ui-pill-count","selectorAtom":".g-pill-count"},{"hookId":"ui-pills","selectorAtom":".g-pills"},{"hookId":"ui-progress","selectorAtom":".g-progress"},{"hookId":"ui-prose","selectorAtom":".g-prose"},{"hookId":"ui-search","selectorAtom":".g-search"},{"hookId":"ui-search-box","selectorAtom":".g-search-box"},{"hookId":"ui-search-btn","selectorAtom":".g-search-btn"},{"hookId":"ui-search-empty","selectorAtom":".g-search-empty"},{"hookId":"ui-search-hit","selectorAtom":".g-search-hit"},{"hookId":"ui-search-hit-meta","selectorAtom":".g-search-hit-meta"},{"hookId":"ui-search-hit-text","selectorAtom":".g-search-hit-text"},{"hookId":"ui-search-hit-title","selectorAtom":".g-search-hit-title"},{"hookId":"ui-search-input","selectorAtom":".g-search-input"},{"hookId":"ui-search-results","selectorAtom":".g-search-results"},{"hookId":"ui-section","selectorAtom":".g-section"},{"hookId":"ui-section-head","selectorAtom":".g-section-head"},{"hookId":"ui-series-box","selectorAtom":".g-series-box"},{"hookId":"ui-series-card","selectorAtom":".g-series-card"},{"hookId":"ui-series-here","selectorAtom":".g-series-here"},{"hookId":"ui-series-list","selectorAtom":".g-series-list"},{"hookId":"ui-series-n","selectorAtom":".g-series-n"},{"hookId":"ui-series-tag","selectorAtom":".g-series-tag"},{"hookId":"ui-share","selectorAtom":".g-share"},{"hookId":"ui-skip","selectorAtom":".g-skip"},{"hookId":"ui-social","selectorAtom":".g-social"},{"hookId":"ui-sr","selectorAtom":".g-sr"},{"hookId":"ui-tag","selectorAtom":".g-tag"},{"hookId":"ui-tags","selectorAtom":".g-tags"},{"hookId":"ui-toast","selectorAtom":".g-toast"},{"hookId":"ui-toc","selectorAtom":".g-toc"},{"hookId":"ui-toc-list","selectorAtom":".g-toc-list"},{"hookId":"ui-toc-mobile","selectorAtom":".g-toc-mobile"},{"hookId":"ui-topic-head","selectorAtom":".g-topic-head"},{"hookId":"ui-topic-hero","selectorAtom":".g-topic-hero"},{"hookId":"ui-topic-icon","selectorAtom":".g-topic-icon"},{"hookId":"ui-topic-strip","selectorAtom":".g-topic-strip"},{"hookId":"ui-wrap","selectorAtom":".g-wrap"}],"publicationRootSelector":"[data-gala-publication-root]","resolvedPaletteSelectors":{"dark":"[data-gala-publication-root][data-gala-resolved-color-mode=\"dark\"]","light":"[data-gala-publication-root][data-gala-resolved-color-mode=\"light\"]"},"stylesheetLayers":{"components":"gala-components","print":"gala-print","tokens":"gala-tokens","utilities":"gala-utilities"},"templatePackage":"@rathnasgala2/template","templateVersion":"4.0.0","typeSelectors":["a","article","blockquote","button","code","details","em","figure","footer","h1","h2","h3","h4","h5","h6","header","hr","img","li","main","nav","ol","p","pre","section","span","strong","summary","time","ul"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rathnasgala2/template",
3
- "version": "3.2.1",
3
+ "version": "4.1.0",
4
4
  "description": "Deterministic Eleventy-backed static publication renderer for Galascribe portable repositories.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -72,11 +72,13 @@
72
72
  "dependencies": {
73
73
  "@11ty/eleventy": "3.1.6",
74
74
  "@11ty/eleventy-plugin-syntaxhighlight": "5.0.2",
75
- "@rathnasgala2/schemas": "3.3.0",
76
75
  "jpeg-js": "0.4.4",
77
76
  "markdown-it": "14.3.1",
78
77
  "sanitize-html": "2.17.7"
79
78
  },
79
+ "peerDependencies": {
80
+ "@rathnasgala2/schemas": "3.10.0"
81
+ },
80
82
  "devDependencies": {
81
83
  "@cyclonedx/cyclonedx-npm": "6.0.1",
82
84
  "@eslint/js": "10.0.1",
@@ -104,12 +104,16 @@ export class ThemeAssetError extends Error {
104
104
  * @param {string} reasonCode a stable, machine-checkable reason code (for
105
105
  * example `THEME_STYLESHEETS_INVALID`, `THEME_CONTRACT_SCHEMA_INVALID`)
106
106
  * @param {string} message a human-readable description
107
+ * @param {Record<string, unknown>} [detail] optional machine-readable
108
+ * detail (the palette refusals carry the failing pair and mode)
107
109
  */
108
- constructor(reasonCode, message) {
110
+ constructor(reasonCode, message, detail) {
109
111
  super(`${reasonCode}: ${message}`);
110
112
  this.name = 'ThemeAssetError';
111
113
  /** @type {string} */
112
114
  this.reasonCode = reasonCode;
115
+ /** @type {Record<string, unknown> | undefined} */
116
+ this.detail = detail;
113
117
  }
114
118
  }
115
119
 
package/src/core/index.js CHANGED
@@ -77,6 +77,8 @@ import {
77
77
  GALA_BASE_STYLESHEET_SOURCE,
78
78
  } from './internal/appearance/base-layer.js';
79
79
  import { renderAppearanceControl } from './internal/appearance/controller-markup.js';
80
+ import { resolveColorModePresentation } from './internal/appearance/contract.js';
81
+ import { TEMPLATE_RENDERER_VERSION } from './internal/package-version.js';
80
82
  import {
81
83
  ArtifactManifestValidationError,
82
84
  BuildInputValidationError,
@@ -139,6 +141,7 @@ import {
139
141
  defaultThemeStylesheetLinksHtml,
140
142
  loadThemeAssets,
141
143
  } from './internal/theme-assets.js';
144
+ import { EDITORIAL_COMPOSITION } from './internal/template-composition.js';
142
145
  import { resolveTextDirection } from './internal/text-direction.js';
143
146
  import {
144
147
  escapeHtml,
@@ -189,7 +192,7 @@ export const TEMPLATE_PACKAGE_NAME = '@rathnasgala2/template';
189
192
  *
190
193
  * @type {string}
191
194
  */
192
- export const TEMPLATE_PACKAGE_VERSION = '2.1.0';
195
+ export const TEMPLATE_PACKAGE_VERSION = TEMPLATE_RENDERER_VERSION;
193
196
 
194
197
  /**
195
198
  * Validate the caller-supplied render options, independent of build-input
@@ -391,8 +394,38 @@ export async function renderPublication(buildInput, options) {
391
394
  const urlPrefix = derivePublicBasePath(validatedInput.baseUrl, '/');
392
395
  const homeRoute = joinPublicRoute(publicBasePath, '/');
393
396
 
397
+ // Admit the selected generation-4 theme and its complete structural
398
+ // composition before any output directory is created. Theme-less calls
399
+ // use the renderer's Editorial composition and the conventional print
400
+ // stylesheet link; a supplied theme never receives that fallback.
401
+ const themeAssetsResult = options.themeDirectory
402
+ ? await loadThemeAssets({
403
+ themeDirectory: path.resolve(options.themeDirectory),
404
+ basePath: validatedInput.basePath,
405
+ publicBasePath,
406
+ appearanceTokens: validatedInput.appearance.tokens,
407
+ })
408
+ : undefined;
409
+ // "Visitors see": the author's colour-mode default and allowed modes.
410
+ const colorMode = resolveColorModePresentation(
411
+ /** @type {{default: string, allowed: readonly string[]} | undefined} */ (
412
+ validatedInput.appearance.colorMode
413
+ ),
414
+ );
415
+ const colorModeData = {
416
+ resolvedColorMode: colorMode.resolvedMode,
417
+ colorModeDefault: colorMode.defaultMode,
418
+ colorModeAllowed: colorMode.allowedModes.join(' '),
419
+ colorScheme: colorMode.colorScheme,
420
+ };
421
+ const themeStylesheetLinksHtml = themeAssetsResult
422
+ ? themeAssetsResult.linkTagsHtml
423
+ : defaultThemeStylesheetLinksHtml(publicBasePath);
424
+ const composition = themeAssetsResult?.composition ?? EDITORIAL_COMPOSITION;
425
+
394
426
  const appearanceControlHtml = renderAppearanceControl({
395
427
  messages: siteMessages,
428
+ toggle: colorMode.toggle,
396
429
  });
397
430
 
398
431
  // Run before page assembly, not after: resolving each page's own images
@@ -495,6 +528,8 @@ export async function renderPublication(buildInput, options) {
495
528
  showAttribution:
496
529
  validatedInput.appearance.attribution?.showMadeWith !== false,
497
530
  messages: siteMessages,
531
+ profile: composition.profile,
532
+ footerLayout: composition.footerLayout,
498
533
  });
499
534
 
500
535
  /**
@@ -522,6 +557,8 @@ export async function renderPublication(buildInput, options) {
522
557
  searchIndexHref,
523
558
  appearanceControlHtml,
524
559
  messages: siteMessages,
560
+ profile: composition.profile,
561
+ headerLayout: composition.headerLayout,
525
562
  });
526
563
 
527
564
  // The site-wide feeds, resolved once so every page's feed-discovery
@@ -540,22 +577,6 @@ export async function renderPublication(buildInput, options) {
540
577
  `/${GALA_BASE_STYLESHEET_PATH}`,
541
578
  );
542
579
 
543
- // The selected theme package's copied stylesheets/passive assets and the
544
- // ordered `<link>` markup every generated page's `<head>` inserts.
545
- // Run before page assembly (same reasoning as the media pipeline above):
546
- // every page's `data.themeStylesheetLinksHtml` needs the same one
547
- // already-rendered fragment.
548
- const themeAssetsResult = options.themeDirectory
549
- ? await loadThemeAssets({
550
- themeDirectory: path.resolve(options.themeDirectory),
551
- basePath: validatedInput.basePath,
552
- publicBasePath,
553
- })
554
- : undefined;
555
- const themeStylesheetLinksHtml = themeAssetsResult
556
- ? themeAssetsResult.linkTagsHtml
557
- : defaultThemeStylesheetLinksHtml(publicBasePath);
558
-
559
580
  /** @type {{virtualPath: string, content: string, permalink: string, layout?: string, data?: Record<string, unknown>}[]} */
560
581
  const contentPages = [];
561
582
  /** @type {{joinedSource: string, joinedTarget: string, publicTarget: string, filePath: string}[]} */
@@ -567,6 +588,7 @@ export async function renderPublication(buildInput, options) {
567
588
  mediaAssets,
568
589
  mediaDimensions,
569
590
  interactions: interactionsOn ? interactionsModule : undefined,
591
+ composition,
570
592
  });
571
593
  /** @type {Set<string>} output paths of the interaction-bearing routes */
572
594
  const interactionBearingPaths = new Set();
@@ -629,6 +651,8 @@ export async function renderPublication(buildInput, options) {
629
651
  cspMetaTag,
630
652
  baseStylesheetHref: baseStylesheetHrefValue,
631
653
  themeStylesheetLinksHtml,
654
+ composition,
655
+ ...colorModeData,
632
656
  },
633
657
  });
634
658
  });
@@ -701,6 +725,8 @@ export async function renderPublication(buildInput, options) {
701
725
  cspMetaTag,
702
726
  baseStylesheetHref: baseStylesheetHrefValue,
703
727
  themeStylesheetLinksHtml,
728
+ composition,
729
+ ...colorModeData,
704
730
  },
705
731
  });
706
732
 
@@ -259,7 +259,7 @@ export const GALA_BASE_COMPONENT_CSS = `
259
259
  outline-offset: 3px;
260
260
  }
261
261
  [data-gala-publication-root] img { display: block; max-width: 100%; height: auto; }
262
- [data-gala-publication-root] a { color: inherit; text-decoration: none; }
262
+ [data-gala-publication-root] :where(a) { color: inherit; text-decoration: none; }
263
263
  [data-gala-publication-root] h1, [data-gala-publication-root] h2, [data-gala-publication-root] h3, [data-gala-publication-root] p { margin: 0; }
264
264
  [data-gala-publication-root] button { font: inherit; color: inherit; }
265
265
  [data-gala-publication-root] ul, [data-gala-publication-root] ol { margin: 0; padding: 0; list-style: none; }
@@ -483,6 +483,12 @@ export const GALA_BASE_COMPONENT_CSS = `
483
483
  .g-card-row .g-card-media, .g-card-row .g-card-placeholder { aspect-ratio: 16 / 9; height: 100%; border-bottom: 0; border-right: var(--gala-border-media-divider); }
484
484
  .g-card-row .g-card-body { padding: clamp(1rem, 2.5vw, 1.75rem); }
485
485
  .g-card-row h2, .g-card-row h3 { font-size: clamp(1.3rem, 1rem + 1vw, 1.75rem); }
486
+ .g-dated-list { gap: 0; }
487
+ .g-dated-row { display: grid; grid-template-columns: minmax(8rem, 1fr) minmax(0, 5fr); gap: clamp(1rem, 3vw, 2rem); align-items: start; padding-block: var(--gala-space-4); border-top: var(--gala-border-row-divider); }
488
+ .g-date-stamp { padding-top: var(--gala-space-3); color: var(--gala-color-text-muted); font-family: var(--gala-font-ui); font-size: .8125rem; font-variant-numeric: tabular-nums; }
489
+ .g-dated-row .g-card-row { grid-template-columns: minmax(0, 1fr); padding: 0; border-bottom: 0; box-shadow: none; }
490
+ .g-dated-row .g-card-row .g-card-media, .g-dated-row .g-card-row .g-card-placeholder { display: none; }
491
+ .g-dated-row .g-card-foot .g-meta > time:first-child, .g-dated-row .g-card-foot .g-meta > time:first-child + .g-dot { display: none; }
486
492
 
487
493
  /* ---------- series ---------- */
488
494
  .g-series-card {
@@ -527,6 +533,12 @@ export const GALA_BASE_COMPONENT_CSS = `
527
533
  [data-gala-slot="edition-selector"] { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gala-space-2); min-width: 0; max-width: 100%; }
528
534
  .g-article-cover { margin-block: 0; }
529
535
  .g-article-cover img { width: 100%; height: auto; aspect-ratio: 21 / 9; object-fit: cover; border-radius: var(--gala-radius-large); border: var(--gala-border-card); box-shadow: var(--gala-shadow-card); filter: var(--gala-media-filter); }
536
+ .g-article-cover-full-bleed { width: 100%; max-width: none; margin: 0; padding-inline: 0; }
537
+ .g-article-cover-full-bleed img { aspect-ratio: 16 / 9; border-inline: 0; border-radius: 0; }
538
+ [data-gala-media-ratio="mixed"] .g-hero-media { aspect-ratio: 3 / 2; }
539
+ [data-gala-media-ratio="mixed"] .g-grid > .g-card:nth-child(3n + 1) :is(.g-card-media, .g-card-placeholder) { aspect-ratio: 4 / 5; }
540
+ [data-gala-media-ratio="mixed"] .g-grid > .g-card:nth-child(3n + 2) :is(.g-card-media, .g-card-placeholder) { aspect-ratio: 3 / 2; }
541
+ [data-gala-media-ratio="mixed"] .g-grid > .g-card:nth-child(3n) :is(.g-card-media, .g-card-placeholder) { aspect-ratio: 1; }
530
542
  .g-article-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, var(--gala-content-measure)) minmax(0, 1fr); gap: clamp(1.5rem, 4vw, 3.5rem); padding-block: clamp(2rem, 5vw, 3.5rem) var(--gala-space-4); }
531
543
  .g-article-grid > .g-prose { grid-column: 2; }
532
544
  .g-toc { position: sticky; top: 6rem; align-self: start; justify-self: end; width: min(100%, 15rem); display: grid; gap: var(--gala-space-3); }
@@ -810,6 +822,8 @@ export const GALA_BASE_COMPONENT_CSS = `
810
822
  .g-grid { grid-template-columns: minmax(0, 1fr); }
811
823
  .g-card-row { grid-template-columns: minmax(0, 1fr); }
812
824
  .g-card-row .g-card-media, .g-card-row .g-card-placeholder { border-right: 0; border-bottom: var(--gala-border-media-divider); height: auto; }
825
+ .g-dated-row { grid-template-columns: minmax(0, 1fr); gap: var(--gala-space-2); }
826
+ .g-date-stamp { padding-top: 0; }
813
827
  .g-pager { grid-template-columns: minmax(0, 1fr); }
814
828
  .g-pager-next { grid-column: 1; }
815
829
  .g-article-cover img { aspect-ratio: 16 / 10; }
@@ -832,7 +846,7 @@ export const GALA_BASE_COMPONENT_CSS = `
832
846
  @keyframes g-read { from { transform: scaleX(0); } to { transform: scaleX(1); } }
833
847
  }
834
848
  @supports (animation-timeline: view()) {
835
- .g-grid > .g-card, .g-list > .g-card, .g-panel, .g-series-card, .g-author-card, .g-series-box, .g-prose > pre, .g-codeblock, .g-prose > figure, .g-prose > blockquote {
849
+ .g-grid > .g-card, .g-list > .g-card, .g-dated-row, .g-panel, .g-series-card, .g-author-card, .g-series-box, .g-prose > pre, .g-codeblock, .g-prose > figure, .g-prose > blockquote {
836
850
  animation: g-reveal linear both; animation-timeline: view(); animation-range: entry 0% entry 55%;
837
851
  }
838
852
  @keyframes g-reveal { from { opacity: .15; transform: translateY(28px) scale(.985); } }
@@ -41,6 +41,8 @@
41
41
 
42
42
  import { minifyScript } from './minify-script.js';
43
43
  import {
44
+ APPEARANCE_ALLOWED_ATTRIBUTE,
45
+ APPEARANCE_DEFAULT_ATTRIBUTE,
44
46
  APPEARANCE_MODE_DARK,
45
47
  APPEARANCE_MODE_LIGHT,
46
48
  APPEARANCE_MODE_SYSTEM,
@@ -65,6 +67,8 @@ const READABLE_SCRIPT_SOURCE = String.raw`(function () {
65
67
  var SAVED_KEY = ${JSON.stringify(SAVED_STORAGE_KEY)};
66
68
  var RESOLVED_ATTRIBUTE = ${JSON.stringify(APPEARANCE_RESOLVED_MODE_ATTRIBUTE)};
67
69
  var SELECTION_ATTRIBUTE = ${JSON.stringify(APPEARANCE_SELECTION_ATTRIBUTE)};
70
+ var DEFAULT_ATTRIBUTE = ${JSON.stringify(APPEARANCE_DEFAULT_ATTRIBUTE)};
71
+ var ALLOWED_ATTRIBUTE = ${JSON.stringify(APPEARANCE_ALLOWED_ATTRIBUTE)};
68
72
  var TOGGLE_ID = ${JSON.stringify(APPEARANCE_TOGGLE_ID)};
69
73
  var MODE_LIGHT = ${JSON.stringify(APPEARANCE_MODE_LIGHT)};
70
74
  var MODE_DARK = ${JSON.stringify(APPEARANCE_MODE_DARK)};
@@ -75,14 +79,32 @@ const READABLE_SCRIPT_SOURCE = String.raw`(function () {
75
79
  function isKnownMode(value) {
76
80
  return value === MODE_LIGHT || value === MODE_DARK || value === MODE_SYSTEM;
77
81
  }
82
+ function allowedModes() {
83
+ var listed = (root.getAttribute(ALLOWED_ATTRIBUTE) || '').split(' ');
84
+ var modes = [];
85
+ for (var i = 0; i < listed.length; i++) {
86
+ if (isKnownMode(listed[i])) modes.push(listed[i]);
87
+ }
88
+ return modes.length ? modes : [MODE_SYSTEM, MODE_LIGHT, MODE_DARK];
89
+ }
90
+ function isAllowed(value) {
91
+ return isKnownMode(value) && allowedModes().indexOf(value) !== -1;
92
+ }
93
+ // The author's "Visitors see" default, else system.
94
+ function authorDefault() {
95
+ var value = root.getAttribute(DEFAULT_ATTRIBUTE);
96
+ return isAllowed(value) ? value : MODE_SYSTEM;
97
+ }
98
+ // The reader's stored choice (when the author still allows it), else the
99
+ // author's default, else system.
78
100
  function readStoredSelection() {
79
101
  try {
80
102
  var value = window.localStorage.getItem(STORAGE_KEY);
81
- if (isKnownMode(value)) return value;
103
+ if (isAllowed(value)) return value;
82
104
  } catch (error) {
83
- // Storage blocked: fall back to MODE_SYSTEM below.
105
+ // Storage blocked: fall back to the author's default below.
84
106
  }
85
- return MODE_SYSTEM;
107
+ return authorDefault();
86
108
  }
87
109
  function writeStoredSelection(mode) {
88
110
  try {
@@ -230,7 +252,8 @@ const READABLE_SCRIPT_SOURCE = String.raw`(function () {
230
252
  function enhanceMode() {
231
253
  var button = document.getElementById(TOGGLE_ID);
232
254
  if (!button) return;
233
- var order = [MODE_SYSTEM, MODE_LIGHT, MODE_DARK];
255
+ var order = [MODE_SYSTEM, MODE_LIGHT, MODE_DARK].filter(isAllowed);
256
+ if (order.length < 2) return;
234
257
  var sync = function () {
235
258
  var label = button.getAttribute('data-label-' + readStoredSelection());
236
259
  if (label) {
@@ -67,6 +67,27 @@ export const APPEARANCE_RESOLVED_MODE_ATTRIBUTE =
67
67
  */
68
68
  export const APPEARANCE_SELECTION_ATTRIBUTE = 'data-gala-color-mode-selection';
69
69
 
70
+ /**
71
+ * Template-internal bookkeeping attribute carrying the author's "Visitors
72
+ * see" default (`appearance.colorMode.default`: `light`, `dark` or
73
+ * `system`), rendered on the root by the server. Not part of the published
74
+ * theme styling contract; no theme selector may target it.
75
+ *
76
+ * @type {string}
77
+ */
78
+ export const APPEARANCE_DEFAULT_ATTRIBUTE = 'data-gala-color-mode-default';
79
+
80
+ /**
81
+ * Template-internal bookkeeping attribute carrying the modes the author
82
+ * allows (`appearance.colorMode.allowed`), space separated, rendered on the
83
+ * root so the page script ignores a stored choice the author no longer
84
+ * offers and cycles only through allowed modes. Not part of the published
85
+ * theme styling contract.
86
+ *
87
+ * @type {string}
88
+ */
89
+ export const APPEARANCE_ALLOWED_ATTRIBUTE = 'data-gala-color-mode-allowed';
90
+
70
91
  /** @type {'light'} */
71
92
  export const APPEARANCE_MODE_LIGHT = 'light';
72
93
  /** @type {'dark'} */
@@ -117,6 +138,61 @@ export const APPEARANCE_RESOLVED_MODE_VALUES = Object.freeze([
117
138
  */
118
139
  export const APPEARANCE_SERVER_DEFAULT_RESOLVED_MODE = APPEARANCE_MODE_LIGHT;
119
140
 
141
+ /**
142
+ * What the server renders for one publication's `appearance.colorMode`
143
+ * (the "Visitors see" setting).
144
+ *
145
+ * - `defaultMode`: the author's default, a root attribute.
146
+ * - `allowedModes`: the author's allowed list, in canonical order.
147
+ * - `resolvedMode`: the server-resolved mode. `light` and `dark` defaults
148
+ * are used as is; `system` keeps {@link APPEARANCE_SERVER_DEFAULT_RESOLVED_MODE}
149
+ * (the script resolves it against the reader's system preference).
150
+ * - `colorScheme`: the `<meta name="color-scheme">` content. A single
151
+ * allowed `light` or `dark` is that mode alone; everything else is
152
+ * {@link COLOR_SCHEME_META_CONTENT}.
153
+ * - `toggle`: whether the colour-mode control is rendered (two or more
154
+ * allowed modes).
155
+ *
156
+ * @param {{default: string, allowed: readonly string[]} | undefined} colorMode
157
+ * `appearance.colorMode`; absent behaves as the former fixed behaviour
158
+ * (all three modes allowed, default `system`)
159
+ * @returns {{
160
+ * defaultMode: string,
161
+ * allowedModes: string[],
162
+ * resolvedMode: string,
163
+ * colorScheme: string,
164
+ * toggle: boolean,
165
+ * }} the render facts
166
+ */
167
+ export function resolveColorModePresentation(colorMode) {
168
+ const allowedModes = APPEARANCE_MODE_VALUES.filter((mode) =>
169
+ /** @type {readonly string[]} */ (
170
+ colorMode?.allowed ?? APPEARANCE_MODE_VALUES
171
+ ).includes(mode),
172
+ );
173
+ const defaultMode =
174
+ colorMode !== undefined &&
175
+ /** @type {readonly string[]} */ (allowedModes).includes(colorMode.default)
176
+ ? colorMode.default
177
+ : APPEARANCE_DEFAULT_MODE;
178
+ const resolvedMode =
179
+ defaultMode === APPEARANCE_MODE_LIGHT ||
180
+ defaultMode === APPEARANCE_MODE_DARK
181
+ ? defaultMode
182
+ : APPEARANCE_SERVER_DEFAULT_RESOLVED_MODE;
183
+ const only = allowedModes.length === 1 ? allowedModes[0] : undefined;
184
+ return {
185
+ defaultMode,
186
+ allowedModes,
187
+ resolvedMode,
188
+ colorScheme:
189
+ only === APPEARANCE_MODE_LIGHT || only === APPEARANCE_MODE_DARK
190
+ ? only
191
+ : COLOR_SCHEME_META_CONTENT,
192
+ toggle: allowedModes.length > 1,
193
+ };
194
+ }
195
+
120
196
  /**
121
197
  * The initial reader default is `system`.
122
198
  *
@@ -30,9 +30,13 @@ import {
30
30
  * @param {object} options rendering options
31
31
  * @param {Readonly<Record<string, string | ((...args: string[]) => string)>>} options.messages
32
32
  * the resolved message catalog
33
- * @returns {string} the control markup
33
+ * @param {boolean} [options.toggle] whether the control is rendered; `false`
34
+ * when the author allows a single colour mode ("Visitors see" offers the
35
+ * reader nothing to choose), so no dead control is shown
36
+ * @returns {string} the control markup (empty when `toggle` is `false`)
34
37
  */
35
- export function renderAppearanceControl({ messages }) {
38
+ export function renderAppearanceControl({ messages, toggle = true }) {
39
+ if (!toggle) return '';
36
40
  const control = /** @type {string} */ (messages.appearanceControlLabel);
37
41
  /** @type {Record<string, string>} */
38
42
  const modeText = {