asw/assets/css/layers/05-utilities.css
Vigilio Desto ea51dbd7cf
M3: dead code purge + layer refs → semantic tokens
Dead code removed:
- 05-utilities: grid-2/card-grid/stats block (superseded by 08-layout)
- 02-semantic: dialog min-width:100% (conflicted with 03-components)
- 02-semantic: hgroup p dead font-family, redundant nested list margin
- All layers: [ai-disclosure] → [data-ai-disclosure] (bug fix)
- table.striped → [data-table="striped"] (classless alignment)

Ref cleanup: 12 --gray-N/--green-N/--blue-N replaced with semantic
tokens. 24 refs marked TODO (syntax highlighting needs --syntax-* aliases).
2026-04-10 19:44:05 +02:00

198 lines
6.5 KiB
CSS

/**
* 05-utilities.css
* Utility patterns (layout helpers, text modifiers, responsive utilities)
* Part of: Agentic Semantic Web
*/
@layer utilities {
/* ══════════════════════════════════════════════════════════════════════════
Text utilities
══════════════════════════════════════════════════════════════════════════ */
[data-text~="mono"] {
font-family: var(--font-mono);
}
[data-text~="dim"] {
color: var(--text-3);
}
[data-text~="accent"] {
color: var(--accent);
}
[data-text~="small"] {
font-size: var(--text-xs);
}
/* Eyebrow — small monospace uppercase accent label above a heading */
[data-text~="eyebrow"] {
display: block;
font-family: var(--font-mono);
font-size: var(--text-xs);
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--accent);
margin-bottom: var(--space-2);
}
/* ══════════════════════════════════════════════════════════════════════════
Layout utilities
══════════════════════════════════════════════════════════════════════════ */
/* Max-width content column — constrains fluid sections to readable width */
[data-wrap] {
max-width: var(--width-content);
margin-inline: auto;
padding-inline: var(--space-5);
}
/* Inline definition lists */
dl[data-layout="inline"] {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.15rem 1rem;
align-items: baseline;
}
dl[data-layout="inline"] dt,
dl[data-layout="inline"] dd {
margin: 0;
padding: 0;
margin-inline-start: 0;
}
/* ══════════════════════════════════════════════════════════════════════════
Responsive visibility
══════════════════════════════════════════════════════════════════════════ */
/* Hide on mobile */
[data-visible="desktop"] {
display: none;
}
@media (--md-n-above) {
[data-visible="desktop"] {
display: initial;
}
}
/* Hide on desktop */
[data-visible="mobile"] {
display: initial;
}
@media (--md-n-above) {
[data-visible="mobile"] {
display: none;
}
}
/* ══════════════════════════════════════════════════════════════════════════
Loading indicator — aria-busy
Usage: <button aria-busy="true">Loading…</button>
<section aria-busy="true">Content loading…</section>
══════════════════════════════════════════════════════════════════════════ */
@keyframes spin {
to { transform: rotate(360deg); }
}
[aria-busy="true"] {
cursor: progress;
}
/* Inline spinner before text in buttons and interactive elements */
:is(button, [role="button"], a)[aria-busy="true"]::before {
content: "";
display: inline-block;
width: 1em;
height: 1em;
margin-right: 0.5em;
vertical-align: -0.125em;
border: var(--border-size-2) solid currentColor;
border-top-color: transparent;
border-radius: 50%;
}
/* Disable interaction on busy buttons */
:is(button, [role="button"])[aria-busy="true"] {
pointer-events: none;
opacity: 0.7;
}
/* Block-level busy: overlay spinner centered */
:is(section, article, main, div)[aria-busy="true"] {
position: relative;
min-height: 3rem;
}
:is(section, article, main, div)[aria-busy="true"]::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 1.5rem;
height: 1.5rem;
margin: -0.75rem 0 0 -0.75rem;
border: var(--outline-width) solid var(--text-3);
border-top-color: transparent;
border-radius: 50%;
}
/* Spinner rotation — guarded: skip for users who prefer reduced motion */
@media (--motionOK) {
:is(button, [role="button"], a)[aria-busy="true"]::before {
animation: spin var(--spinner-duration) linear infinite;
}
:is(section, article, main, div)[aria-busy="true"]::after {
animation: spin var(--spinner-duration) linear infinite;
}
}
/* ══════════════════════════════════════════════════════════════════════════
Accessibility enhancements
══════════════════════════════════════════════════════════════════════════ */
/* Disable all transitions and animations for reduced motion preference */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Increase contrast for high-contrast preference */
@media (prefers-contrast: more) {
:root {
--border-color: var(--gray-10); /* TODO: map to semantic token — no alias for gray-10 (--border=gray-11; high-contrast needs one step higher) */
--border-color-subtle: var(--border-subtle); /* --border-subtle = var(--gray-12) */
--text-primary: var(--gray-0); /* TODO: map to semantic token — no alias for gray-0 (--text=gray-1 in dark; high-contrast needs brightest white) */
--text-secondary: var(--text-2); /* --text-2 = var(--gray-3) */
--border-width: var(--border-size-2);
}
/* Thicker borders on interactive elements */
a,
button,
input,
select,
textarea,
[data-wikilink] {
border-width: var(--border-size-2);
}
/* Stronger focus indicators */
:focus-visible {
outline-width: var(--border-size-3);
outline-offset: var(--border-size-3);
}
}
} /* end @layer utilities */