Scoped Surface CSS Plan

Scoped Surface And CSS Migration Plan

Purpose

This note captures the next frontend architecture step for generator:

  • stop growing island-prefixed variables like --header_*, --footer_*, --aside_*
  • move toward one shared variable vocabulary scoped by the cascade
  • generalize the section system so banner, spotlight, and wrapper become presets over a smaller shared model
  • migrate from SCSS to authored CSS where that is realistic, without forcing a risky flag-day rewrite

This is intentionally separate from the editor plan. It is about the site styling contract first, then editor implications.

Goals

  • Keep one shared framework for all sites.
  • Let websites vary primarily through Hugo-emitted variables and tokens, not ad hoc override stylesheets.
  • Keep Hugo as the source of truth for tokens and scoped surfaces.
  • Make the section model easier for the editor to expose and mutate.
  • Move new and simple styling to CSS where possible.

Non-goals

  • Do not remove SCSS in one pass.
  • Do not break existing site palettes or layouts while introducing the new contract.
  • Do not make banner, spotlight, and wrapper disappear immediately from authored content.
  • Do not require site-specific CSS files for ordinary stylistic differences.

Current problems

1. Too many island-prefixed variables

Today the framework still emits and consumes many variables like:

  • --header_bg
  • --footer_fg
  • --aside_border
  • --article_nav_accent

That makes the vocabulary larger than it needs to be and encourages component logic to depend on the island name.

2. Section families are doing too much

banner, spotlight, and wrapper currently bundle together several concerns:

  • palette/surface
  • text alignment
  • content width
  • media placement
  • motion
  • prose vs split layout

That makes the authored API and the future editor harder to reason about.

3. SCSS is still the generator layer for too much of the system

Some files are effectively already plain CSS in .scss clothing, while others still genuinely benefit from Sass generation.

The current setup makes it easy to keep adding to SCSS even where plain CSS would now be cleaner.

Target model

Shared variable vocabulary

The framework should use one shared vocabulary, for example:

  • --bg
  • --bg-alt
  • --fg
  • --fg-bold
  • --fg-light
  • --border
  • --border-alt
  • --accent
  • --hover-accent
  • --icon
  • --content-max-width
  • --section-gap
  • --section-padding-x
  • --section-padding-y
  • --media-width

These names should mean the same thing everywhere.

Scoped surfaces

Those same names should be rebound by scope:

:root {
  --bg: ...;
  --fg: ...;
  --content-max-width: ...;
}

header {
  --bg: ...;
  --fg: ...;
  --content-max-width: ...;
}

main {
  --content-max-width: ...;
}

footer {
  --bg: ...;
  --fg: ...;
}

Then sections and blocks can override the same names more locally:

.wrapper {
  --content-max-width: var(--content-max-width-prose);
}

.wrapper.width-wide {
  --content-max-width: var(--content-max-width-wide);
}

The important point is:

  • same variable names
  • different scopes
  • no need for a separate variable family per island

Widgets are scoped subsystems

Widgets should follow the same scoped-surface rule instead of behaving like exceptions to the site theme.

The architectural pattern is:

  1. the site theme owns the base tokens
  2. the widget root aliases those tokens into local --widget-* variables
  3. the widget root resets global component leakage such as shared button styles
  4. the widget rebuilds its own controls explicitly with flex/grid and explicit spacing
  5. widget internals consume only the local aliases

That gives the framework one consistent CSS model:

  • sites brand widgets automatically through the shared token cascade
  • widgets remain internally stable even when shared component rules evolve
  • per-site widget customisation can happen through local alias overrides instead of deep selector forks

Treat the widget as a scoped subsystem inside the generator, not as a special-case island outside the shared surface contract.

Compatibility bridge

We should not delete prefixed island variables immediately. The correct transition is:

  1. Hugo emits the new scoped generic variables.
  2. Hugo continues emitting legacy prefixed variables for compatibility.
  3. SCSS/CSS consumers are migrated to the generic names.
  4. Prefixed variables become compatibility-only.
  5. Eventually they can be removed.

The first shared migration slice now lives in assets/css/variables.css:

  • :root still emits the legacy prefixed palette families for compatibility
  • header, footer, aside, and #article-nav now also rebind the shared names --bg, --fg, --fg-bold, --fg-light, --border, --border-alt, --border-bg, --accent, --hover-accent, --icon, and --fig-bg
  • consumers should prefer those shared scoped names first and only fall back to the prefixed variables while older SCSS is still being migrated

Section model generalization

Yes: banner, spotlight, and wrapper should be generalized.

Not by deleting them outright, but by treating them as presets over a smaller section contract.

Better section contract

Every section should be understandable in terms of a few orthogonal concerns:

  • surface palette and skin
  • width prose / medium / wide / full
  • flow prose / split / stack / media-led
  • media none / left / right / fit / contain / cover
  • alignment left / center / right
  • motion none / onload / onscroll

The first live bridge toward that model is now in place in Hugo:

  • content_only no section media
  • figure_led section media exists, but uses figure-led layouts like .fit
  • split section media participates in split banner/spotlight layout

That shared flow distinction now decides whether split-screen tokens like halfscreen and orient-* survive section-class resolution. Explicit section attrs still own section semantics: authored banner / spotlight sections with orient-left or orient-right stay on the split-flow path even when the figure carries .fit.

The next bridge is now in place too: Hugo emits a neutral section-axis contract on the rendered DOM and in #editorData, without removing any legacy classes yet. The first axis set is:

  • flow
  • media_side
  • size
  • content_align
  • surface
  • layout_family

These currently surface as data-ql-* hooks on each rendered <section>, so the editor and later SCSS migration can read explicit semantics first and keep banner / spotlight / wrapper as compatibility presets instead of the only source of truth.

The editor-side write split now matches that direction:

  • section-frame semantics write to the leading section attr block
  • content width and block layout presets keep writing to the trailing content attr block

So the next SCSS migration can treat the emitted data-ql-* hooks as the semantic read surface without introducing a second competing write authority.

That means:

  • wrapper becomes mostly a prose/stack surface preset
  • spotlight becomes a split-flow preset
  • banner becomes a media-led preset

They can remain as legacy class names for authored content, but the framework and editor should think in the more general model above.

Why this is better

  • easier authored API
  • easier editor UI
  • fewer hardcoded section species
  • style differences become tokens and modifiers, not distinct layout regimes

Width model

The width contract should follow the same scoped-variable principle.

Recommended shared width names:

  • --content-max-width-prose
  • --content-max-width-medium
  • --content-max-width-narrow
  • --content-max-width-wide
  • --content-max-width-full

Then scoped usage:

  • main { --content-max-width: var(--content-max-width-prose); }
  • header { --content-max-width: ...; }
  • footer { --content-max-width: ...; }

And section-level overrides:

  • .width-prose
  • .width-medium
  • .width-narrow
  • .width-wide
  • .width-full

This is better than inventing:

  • --header-content-max-width
  • --footer-content-max-width
  • --wrapper-content-max-width

unless those are only temporary bridge names.

SCSS to CSS migration

Bottom line

A large share of the codebase can move to plain authored CSS now, but not all of it.

The realistic path is:

  • CSS-first for new/simple surfaces
  • keep SCSS temporarily for breakpoint/grid/generator-heavy layout core
  • deliberately shrink that core

Good CSS-first candidates now

These are already close to plain CSS:

  • assets/scss/components/_regions.scss
  • assets/scss/components/_button.scss
  • assets/scss/components/_modal.scss
  • assets/scss/components/_actions.scss
  • assets/scss/components/_list.scss
  • assets/scss/base/_typography.scss
  • assets/scss/layout/_wrapper.scss

These should be the first migration candidates.

Keep in SCSS for now

These still materially benefit from Sass:

  • assets/scss/libs/_breakpoints.scss
  • assets/scss/libs/_html-grid.scss
  • assets/scss/components/_row.scss
  • assets/scss/components/_banner.scss
  • assets/scss/components/_spotlight.scss
  • assets/scss/components/_items.scss
  • assets/scss/components/_figure.scss
  • assets/scss/main.scss

Reasons:

  • breakpoint DSL is pervasive
  • grid utilities are generated
  • several layout families still rely on pattern generation and repeated media/layout rules

Migration order

Phase 1. Freeze Sass growth

  • Prefer plain CSS for new simple rules.
  • Only add new SCSS when generation or shared breakpoint DSL is genuinely needed.

Phase 2. Introduce the scoped generic surface vocabulary

  • Emit generic scoped variables for header, main, footer, and aside.
  • Keep emitting prefixed island variables for compatibility.
  • Start documenting the generic names as canonical.

Phase 3. Migrate consumers off island-prefixed vars

Start with:

  • assets/scss/layout/_nav.scss
  • assets/scss/layout/_footer.scss
  • assets/scss/components/_button.scss

Goal:

  • these should consume generic names like --bg, --fg, --accent, --border, --content-max-width from scope
  • not hardcoded --header_*, --footer_*, etc

Phase 4. Move CSS-like SCSS partials into CSS

Move the low-risk partials listed above into authored CSS files or flatten them enough that Sass is no longer adding value.

Phase 5. Generalize the section model

  • keep banner, spotlight, and wrapper working
  • redefine them internally as presets over:
    • surface
    • width
    • flow
    • media
    • alignment
    • motion

This is the point where the editor should also stop thinking in terms of the old section species.

Phase 6. Shrink the SCSS generator core

After the width/palette/section contracts are stable:

  • reduce Sass dependence in breakpoint-heavy components
  • decide whether the breakpoint/grid system should itself be replaced or kept as the last SCSS island

Editor implications

This architecture is better for the editor because it exposes smaller shared controls:

  • Surface
  • Width
  • Flow
  • Media
  • Alignment
  • Motion

Instead of presenting users with:

  • banner
  • spotlight
  • wrapper
  • style1
  • style2
  • style3

The editor can still write the legacy classes where needed during migration, but its conceptual model should target the smaller shared contract.

Editor should edit the scoped variables directly

Yes: the editor should ultimately read and write the shared scoped variables themselves.

That is the right way to let designers and clients change:

  • colors
  • margins and padding
  • content widths
  • section spacing
  • media widths
  • typography scale

without inventing a second styling system parallel to Hugo and the theme.

Editor scopes

The editor should expose a small number of styling scopes:

  • site
  • header
  • main
  • footer
  • aside
  • page-type
  • page
  • section
  • block

These should all use the same shared variable vocabulary.

Example:

  • site sets the default --content-max-width
  • homepage overrides it to be wider
  • footer overrides --bg and --fg
  • one section overrides --content-max-width again to become wide

Page-type scope

Page-type scope should be first-class in the editor.

The old minimum split was:

  • homepage
  • list
  • single

But the better long-term model is:

  • homepage
  • list
  • landing
  • detail

Where:

  • landing first-level singleton pages such as /about/, /contact/, /bookings/, /gallery/
  • detail deeper nested pages with more document/article-like rhythm

This is a better editor and framework model than single-root / single-nested.

This lets the editor set sensible defaults for each page family, such as:

  • content width
  • section spacing
  • prose rhythm
  • lead max-width
  • lead-section behavior
  • brochure-like vs document-like density

Why this matters:

  • wider default content widths for top-level pages
  • stronger lead-section behavior on landing pages
  • different section spacing rhythm
  • more brochure-like presentation on first-level pages
  • more document/article-like presentation on nested pages

The shared scope shape should therefore become:

  • body.ql-page-type-homepage
  • body.ql-page-type-list
  • body.ql-page-type-landing
  • body.ql-page-type-detail

and then rebind main through the same shared variables, for example:

  • main { --content-max-width: ... }
  • main { --section-gap: ... }
  • main { --lead-max-width: ... }

Current implementation status:

  • body now emits:
    • ql-page-type-homepage
    • ql-page-type-list
    • ql-page-type-single
    • ql-page-type-landing
    • ql-page-type-detail
  • main now mirrors the primary semantic scope as data-ql-page-type="homepage|list|landing|detail"
  • main rebinds:
    • --main-content-max-width
    • --surface-content-max-width
    • --surface-section-padding-y
    • --surface-section-gap-y
    • --lead-max-width
    • --surface-structured-gap
    • --surface-compact-padding-y
    • --surface-intro-card-gap
    • --surface-intro-card-padding-y
    • --surface-intro-card-padding-x
    • --surface-intro-card-max-width
    • --surface-intro-card-mobile-max-width from the shared page-type scope
  • content-only wrapper, banner, and spotlight sections now consume that shared surface width by default instead of hardcoding prose-only caps
  • core wrapper.style1 / wrapper.style2 and banner.style1 / spotlight.style1 now consume the shared surface section padding token on desktop
  • wrapper breakpoint padding now stays on the shared section/surface token path instead of dropping straight to raw size_* fallbacks
  • media-bearing banner.style1 / spotlight.style1 content caps now resolve through semantic content-width tokens before the legacy size_inner fallback
  • remaining wrapper / banner / spotlight preset breakpoint geometry still uses legacy size math where the contract is asymmetric; that needs an explicit responsive token model before another migration pass
  • wrapper, banner, and spotlight now also consume shared section rhythm vars for outer spacing and inner padding
  • legacy .squeeze / .pad variants are compatibility aliases over the shared spacing vars
  • automatic section rhythm now comes from page scope + section flow + semantic adjacency first
  • shared SCSS now tightens common transitions such as:
    • heading/lead -> grid/note/buttons
    • grid -> note/buttons
    • note -> grid
    • figure-led media -> content
  • shared SCSS now also compacts common short sections such as:
    • a single note / facts block / buttons row
    • a heading plus one semantic module
    • short update sections like heading + paragraph or heading + note
  • media-bearing banner / spotlight sections still keep their preset split geometry
  • heading scale
  • card/grid density

Next page-type migration step:

  • continue moving remaining rhythm/layout consumers onto shared scoped tokens
  • extend the page-type contract beyond width/padding/lead into section density and component spacing
  • keep reducing reliance on preset-specific SCSS branches

Current implementation now covers:

  • page-scope width defaults
  • page-scope section padding and section gap defaults
  • page-scope structured-block adjacency density
  • page-scope compact-section padding
  • page-scope intro-card sizing and density
  • page-scope intro-card visual controls:
    • radius
    • card background / border / shadow / blur
    • glow opacity
    • kicker colors
    • title font / size / weight
    • lead max width
    • ink accent color
  • page-scope brochure component density:
    • grid/card spacing
    • note padding
    • chip/facts density
    • action row gap
    • team/contact card density
    • fixed-height embed caps
  • page-scope typography and nav density:
    • body/heading line-height
    • paragraph and heading rhythm
    • nav row/column gap
    • nav link size and padding
  • a neutral section shell:
    • all rendered sections expose .ql-section
    • shared content-only width/fullscreen and intro-card scaffolding now come from shared section mixins instead of separate banner / spotlight copies
    • figure_led sections preserve promoted/base layout families rather than collapsing back to wrapper
    • explicit section layout/orientation beats figure-led inference, so .fit no longer downgrades authored split sections into wrapper
  • editor bridge alignment:
    • the local markdown bridge now exposes a primary surface token group
    • the bridge also exposes a site-level chrome group for header / aside / article-nav / footer shell spacing
    • global edits map to params.style.tokens.surface.* and params.style.tokens.chrome.*
    • site + page-type surface emissions now land after generated --main-* defaults so authored overrides actually win in the cascade
    • local edits map to --surface-* and --lead-max-width overrides on markdown attr styles
    • legacy section / region token groups remain compatibility-only
  • chrome shell spacing now runs through shared applied vars:
    • --surface-shell-padding
    • --surface-shell-margin
  • scope mappings preserve compatibility with:
    • --size_header_multiplier
    • --size_aside_multiplier
    • --size_article_nav_multiplier
    • --size_footer_multiplier
    • legacy --*_margin vars when present

without forcing those changes onto every page individually.

Margin and width editing

Margins and widths should be driven by shared variables where possible.

Preferred variables:

  • --content-max-width
  • --section-gap
  • --section-padding-x
  • --section-padding-y
  • --media-width
  • --figure-width

Shared rhythm should also use:

  • --section-gap-before
  • --section-gap-after
  • --section-padding-top
  • --section-padding-bottom

Automatic adjacency tightening should live in shared SCSS and be driven by semantic DOM hooks, not JavaScript-only logic.

The intended authored rule is:

  • let shared SCSS handle ordinary rhythm automatically
  • use .space-* / .pad-* only for real exceptions
  • keep .squeeze* / .pad* only as migration aliases

The editor can label these more clearly as:

  • Content width
  • Section spacing
  • Section padding
  • Media width
  • Figure width

Immediate implementation priorities

  1. Emit generic scoped variables alongside current island-prefixed ones.
  2. Move width handling onto the shared scoped model.
  3. Migrate nav, footer, and button consumers off prefixed island vars.

Concrete migration sequence

This is the recommended implementation order for the current generator state.

It is intentionally conservative:

  • keep Hugo render authority intact
  • keep the editor writing markdown/front matter/local attrs, not CSS files
  • keep legacy variables alive until their consumers are gone

0. Treat the current token layer as the public API

Use the canonical token emission in assets/css/variables.css as the stable style API:

  • :root owns the global vocabulary
  • main rebinds the shared surface variables
  • page-type scopes rebind those same variables
  • page front matter writes page-local token overrides
  • section/block attrs write local overrides

For implementation purposes, the current public token layer is:

  • global/shared:
    • color
    • width
    • surface
    • space
    • radius
    • shadow
    • type
  • compatibility-only:
    • section
    • region

Rule:

  • do not add new editor-facing token families outside that set unless there is a clear cross-site need

Acceptance:

  • new styling work targets the canonical token groups first
  • section and region are treated as migration shims, not the long-term editor vocabulary
  • legacy Hugo palette vars with underscores, such as --fg_bold, should continue to emit hyphen aliases like --fg-bold so older site configs remain compatible with the newer surface token layer

1. Freeze token naming and reduce vocabulary drift

The next migration work should use one preferred semantic language:

  • surface
  • width
  • spacing
  • density
  • alignment
  • media
  • type

Implementation rule:

  • if a new variable is really just a scoped surface decision, prefer a --surface-*, --color-*, --content-*, --space-*, or --radius-* name
  • do not introduce new island-prefixed families such as --header_* or component-private editor vocabularies unless they are genuinely compatibility-only

Acceptance:

  • new code does not introduce fresh island-specific token families
  • editor labels can be expressed in semantic terms rather than section-species or preset names

2. Consumer migration wave A: layout chrome

Move the obvious outer-shell consumers onto the shared scoped names first.

Primary files:

  • assets/scss/layout/_nav.scss
  • assets/scss/layout/_footer.scss
  • assets/scss/components/_button.scss

Goal:

  • consume scoped --bg, --fg, --accent, --border, --surface-*, and shared width tokens from the cascade
  • keep prefixed variables only as fallback bridges where needed

Why this wave comes first:

  • these files define the visible site chrome
  • they are easier to reason about than banner/spotlight internals
  • they reduce the amount of header/footer-specific vocabulary exposed to the editor

Acceptance:

  • those consumers prefer shared scoped names first
  • no new direct dependency on --header_*, --footer_*, --aside_*, or --article_nav_* is added in migrated code
  • visual output stays unchanged for existing sites

3. Consumer migration wave B: section shell and brochure surface

After layout chrome, continue with the section shell that the editor most directly manipulates.

Primary files:

  • assets/scss/components/_wrapper.scss
  • assets/scss/components/_banner.scss
  • assets/scss/components/_spotlight.scss
  • assets/scss/main.scss

Goal:

  • make section width, spacing, padding, density, and lead sizing flow primarily through the shared surface vocabulary
  • keep banner, spotlight, and wrapper as compatibility presets over the smaller shared contract

Implementation rule:

  • if a rule is really about section rhythm or content width, it should resolve through shared section/surface variables before any preset-specific fallback
  • preset classes should increasingly choose defaults, not define separate style systems

Acceptance:

  • section rhythm comes from shared scoped vars first
  • width presets resolve through shared width tokens
  • banner, spotlight, and wrapper still work for authored content, but the implementation thinks in shared section properties

4. Consumer migration wave C: repeated brochure blocks

Once the section shell is stable, move structured brochure blocks onto the same density and spacing language.

Primary targets:

  • note/card/grid spacing
  • actions/chips/facts/team/contact density
  • media-width-like block decisions

Goal:

  • repeated brochure components read from the same page/section surface tokens instead of bespoke spacing knobs

Acceptance:

  • structured blocks on the same page family share density and spacing behavior by default
  • block-level overrides remain local and markdown-backed

5. Keep editor scope support aligned with actual consumers

The bridge and token inspector already support:

  • site
  • page_type
  • page
  • section
  • block

The focused Nowtype section controls should resolve onto that same model rather than opening a separate layout-only UI. The current bridge for that is an explicit shared-inspector section context, so Layout and Style can still target section scope even when the user is editing a focused markdown section rather than selecting a live page node.

Current guardrail:

  • page_type and page global writes should stay primarily surface-focused until more consumers actually read shared color, type, space, and width tokens consistently

This avoids exposing controls the site does not yet honor uniformly.

Implementation rule:

  • widen editable scope groups only after the corresponding SCSS consumers have been migrated

Acceptance:

  • editor controls match real framework behavior
  • no inspector control claims to be page-wide or page-type-wide unless the cascade actually honors it across the surface

6. Turn the inspector from token-shaped to semantic

After enough consumer migration, the editor should stop presenting raw token groups as the primary mental model.

Preferred inspector groups:

  • Surface
  • Width
  • Spacing
  • Density
  • Alignment
  • Media
  • Typography

The runtime can still map those controls onto:

  • shared token writes
  • page front matter token writes
  • section/block local attr writes
  • compatibility class aliases during migration

Acceptance:

  • common edits do not require thinking in raw class names
  • preset names become secondary descriptions, not primary controls

7. Define the cleanup threshold explicitly

Legacy variables should only be removed after both conditions are true:

  1. the shared consumer path is stable across header, main, footer, aside, and common section/block surfaces
  2. the editor uses the shared semantic/token vocabulary without relying on legacy-prefixed names

Before that point, legacy variables are compatibility infrastructure, not technical debt to delete aggressively.

Exit criteria for this migration:

  • new styling work uses the shared token vocabulary by default
  • page-type and page scopes are meaningful and consistent
  • section editing is expressed as semantic controls over shared variables plus small local overrides
  • site-specific styling differences no longer require per-site theme forks or ad hoc style override files

Migration checkpoints:

  1. Add scoped variable surfaces for homepage, list, and single.
  2. Make the editor capable of reading and writing shared scoped variables at site/page-type/page/section/block scope.
  3. Introduce width/flow/surface modifiers as the canonical section editing API.
  4. Treat banner, spotlight, and wrapper as legacy presets over that contract.

Current editor bridge status:

  • the local bridge now exposes a first-class surface token group
  • the token inspector now orders surface first and pushes legacy section / region groups to the end as compatibility
  • scope targeting is now landing in the editor, so the same shared tokens can be written intentionally at:

Current section-axis migration status:

  • Hugo now emits neutral section axes on rendered section roots and in #editorData
  • the shared inspector now edits those axes first and writes section-frame semantics back to the leading inline section attr block
  • the old standalone Nowtype section-layout popover has been removed, so section layout now routes only through the shared inspector path
  • the first additive SCSS slice now consumes:
    • data-ql-flow="figure_led"
    • data-ql-size="full" | "half"
    • data-ql-section-surface="intro_card"
  • legacy banner / spotlight / wrapper classes still remain authoritative for the rest of the geometry until more selector families have been migrated
    • site
    • page type
    • page
    • section
    • block
  • the current implemented non-local scopes are:
    • site
    • page type
    • page with local scopes now behaving explicitly as:
    • section: authored section ordinal (s0, s1, …) backed by the leading section attr block
    • block: section media first (s0:media), then structured fenced blocks by kind + ordinal (team:0, gallery:0, contact:0, testimonials:0, buttons:0), then explicit attr/fence-backed block ids when present
  • page-type and page scopes currently target the shared surface token family only, which is intentional: the CSS contract already consumes those tokens consistently across width, spacing, density, typography, and nav rhythm

Editor-mode implication:

  • the shared token model should serve all three editor surfaces:
    • page WYSIWYG
    • single-page PDF
    • double-page spread PDF
  • those are different editing presentations over the same Hugo + markdown + scoped-token contract, not separate style systems

Editor-Grade Scope Architecture

This is the architecture needed to make the editor feel closer to SquareSpace while preserving Hugo, markdown, and the shared theme as the only styling authority.

Scope stack

The scope stack should be:

  • site
  • chrome region header, main, footer, aside, article-nav
  • page_type
  • page
  • section
  • block
  • widget-local alias scope inside the rendered widget root

The important rule is:

  • the editor should not invent a second token vocabulary for these scopes
  • each scope reuses the same shared vocabulary and relies on the cascade
  • widgets stay on the same system by aliasing shared site tokens into local --widget-* variables

Bridge contract

The current token bridge in scripts/local-markdown-bridge.mjs already exposes:

  • token catalog reads
  • global token reads/writes
  • local token reads/writes

The next step is to make reads inheritance-aware, not just value-aware.

Each token read should eventually return:

  • requested scope
  • requested token group/key
  • effective value
  • declared value at this scope, if any
  • source scope currently supplying the effective value
  • source path or node id when relevant
  • fallback chain
  • writable target metadata

Without that metadata, the editor can write scoped tokens but cannot explain inheritance clearly, which is the main remaining gap versus a professional website builder.

Inspector contract

The token inspector in cdn/custom/toggleMarkdown.js should evolve from a raw token panel into an inheritance-aware scoped inspector.

It should show, for each field:

  • effective value
  • inherited vs overridden state
  • source scope
  • reset action
  • optional preview state across desktop, tablet, and phone

The primary visible scopes should become:

  • Site
  • Header
  • Main
  • Footer
  • Aside
  • Article Nav
  • Page Type
  • Page
  • Section
  • Block

The primary visible control groups should become semantic first:

  • Surface
  • Width
  • Spacing
  • Density
  • Alignment
  • Media
  • Typography

The raw token group structure can remain the implementation layer underneath that UI.

Consumer migration rule

The editor may only advertise a scope/token control as broad if the cascade actually honors it broadly.

That means:

  • page_type and page should remain primarily surface-focused until more consumers read shared color, type, space, width, radius, and shadow tokens consistently
  • chrome region scopes should not be exposed in the editor until shared chrome consumers actually prefer shared scoped names over legacy island-prefixed ones
  • widget-specific controls should only appear when they are backed by documented widget-local alias layers rather than deep selector overrides

Current implementation gap

Architecturally, the framework is already close:

  • shared vocabulary exists
  • scoped token reads and writes exist
  • site, page_type, page, section, and block are already modeled in the editor
  • the bridge already exposes a first-class surface group

But the editor is not yet editor-grade because:

  • chrome scopes are not yet first-class in the inspector
  • global reads now expose effective value, declared value, source scope, and fallback metadata, but local reads and the live inspector still need broader semantic polish
  • too many consumers still depend on legacy or bespoke variables
  • the inspector is still more token-shaped than semantic

Implementation checklist

  1. Extend the inspector scope model from site/page_type/page/section/block to include header, main, footer, aside, and article-nav.
  2. Upgrade bridge reads so the editor can render effective value, declared value, source scope, source target, and fallback chain.
  3. Treat the token catalog as the editor field schema, including type, scope support, and reset behavior.
  4. Keep page_type and page editing surface-first until shared consumers honor broader token groups consistently.
  5. Continue migrating broad framework consumers onto shared scoped names before widening editor claims.
  6. Keep widgets on the same scope model by exposing widget-local alias layers rather than raw selector-specific style knobs.
  7. Keep page WYSIWYG, single-page PDF, and spread PDF as different views over the same scoped-token contract.

Definition of done

This part of the architecture is complete when:

  • a token changed at site, chrome region, page_type, page, section, or block reliably affects the expected rendered scope
  • the editor can show whether a value is inherited or overridden and from where
  • chrome region styling no longer depends on legacy-prefixed variables for ordinary theme decisions
  • common sections and brochure components primarily resolve through shared --surface-* and shared scoped tokens
  • widgets inherit brand defaults through shared tokens and expose only documented local alias overrides
  • the same scope model behaves consistently across page WYSIWYG and PDF editing surfaces

Recommendation

Yes:

  • generalize banner, spotlight, and wrapper
  • move toward scoped generic variables instead of island-prefixed ones
  • migrate from SCSS to CSS incrementally

No:

  • do not try to remove SCSS all at once
  • do not keep solving site differences with per-site override CSS when shared tokens and scoped variables can express them cleanly

TutorLumin partners with QuantaLumin

You’re connecting to your QuantaLumin account on members.quantalumin.com.