Skip to content
HomePagesHomePages template kit
Menu

template-kit/unlayered-fence

The template-kit/unlayered-fence authoring rule — what it enforces, why, and how to fix it.

This is not “you forgot to layer your CSS.” Everything is layered by default — the build does it for you. This rule governs the escape hatch from layering: an /* unlayered: … */ fence must give a reason and must be closed.

Your hand-written CSS is wrapped in a cascade layer by the build. You do not write @layer yourself, and there is nothing to forget.

The fence opts a run of rules out of that wrapping, hoisting them above every layer:

/* unlayered: <reason> */
…rules that must beat every layer…
/* endunlayered */

Two things are checked, both under this id:

  1. Every opener carries a non-empty reason. A bare /* unlayered: */ is a violation.
  2. Openers and closers balance. An unterminated fence is a violation — it would swallow the whole rest of the file out of the layer, which is never what anyone meant.

Cascade layers have one rule that decides everything here: an unlayered rule beats a layered one, regardless of specificity. Not “usually” — always. That is what layers are for, and it is why the platform layers your CSS: inside the layer order (theme, base, components, sections, template, utilities) a Tailwind utility can always override a section’s stylesheet, and a section’s stylesheet can never leak past its layer to beat someone else’s utility.

So the hatch exists for exactly one situation: a third-party library injects an unlayered rule into the document at runtime — a map SDK writing a <style> element when it mounts, say — and that rule beats your layered override no matter how specific you make it. The only thing that can beat it is a rule that is also unlayered. Nothing else qualifies. If your rule merely needs to beat your own CSS, or a Tailwind utility, it belongs in a layer and you are reaching for the wrong tool.

Which is why the reason is mandatory. A fence with no reason is a rule that outranks every layer on the page for reasons the next author cannot reconstruct — they cannot tell whether it is load-bearing or whether someone was fighting a specificity problem with a hammer. And an unbalanced fence silently promotes every rule below it, so a stylesheet that behaved yesterday starts beating the utilities that were supposed to override it.

Close every fence with /* endunlayered */, and give every opener a reason that names the runtime-injected rule it has to beat. A short phrase is enough — it only has to be non-empty and specific about which rule it’s beating, not a full sentence. If it does not have to beat one, delete the fence: layered is the default, and the default is right.

The Before/After below both open with a /* css-reason: … */ comment. That line has nothing to do with fencing — it satisfies a separate rule, css-reason, which every hand-written stylesheet must open with. It’s shown here because real section CSS carries both; this rule’s own grammar starts at /* unlayered: */.

/* css-reason: overrides the map SDK's injected control chrome. */
/* unlayered: */
.maplibregl-ctrl-group button {
background: var(--tr-color-surface);
border-radius: var(--tr-radius-sm);
}
.tr-map-legend {
padding: 0.5rem;
}

Two violations at once: the reason is empty, and the fence is never closed — so .tr-map-legend is hoisted out of the layer too, where it now outranks every utility a future author might try to override it with.

/* css-reason: overrides the map SDK's control chrome — the SDK builds those nodes after
hydration, so Tailwind's scanner never sees a class to compile. */
/* unlayered: the map SDK injects its control styles as an unlayered <style> element at
runtime; a layered rule cannot beat it at any specificity. */
.maplibregl-ctrl-group button {
background: var(--tr-color-surface);
border-radius: var(--tr-radius-sm);
}
/* endunlayered */
/* Our own DOM — layered, like everything else. */
.tr-map-legend {
padding: 0.5rem;
}

The fence now wraps exactly the rules that need to escape, and .tr-map-legend is back in the layer where a utility can still override it.

  • Theme and CSS — the layer order, and why utilities come last.
  • css-reason — the comment every hand-written stylesheet opens with; the fence reason is the same discipline, one level in.