/**
* 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);
}
/* Grid layout with responsive stacking */
[data-layout="grid-2"] {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
@media (--md-n-below) {
[data-layout="grid-2"] {
grid-template-columns: 1fr;
}
}
/* Card grid — responsive wrap for article cards */
[data-layout="card-grid"] {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
[data-layout="card-grid"] > * {
flex: 1 1 calc(50% - 0.75rem);
min-width: var(--size-px-13);
}
@media (--md-n-below) {
[data-layout="card-grid"] > * {
flex-basis: 100%;
}
}
/* Stats bar — horizontal row of key-value metrics */
[data-layout="stats"] {
display: flex;
flex-wrap: wrap;
gap: 0;
}
[data-layout="stats"] > * {
flex: 1 1 0;
min-width: 5rem;
padding: 0.75rem 0;
text-align: center;
border-right: 1px solid var(--border-subtle);
}
[data-layout="stats"] > *:last-child {
border-right: none;
}
[data-layout="stats"] .value {
display: block;
font-family: var(--font-mono);
font-size: 1.5rem;
font-weight: 600;
line-height: 1.2;
}
[data-layout="stats"] .label {
display: block;
font-family: var(--font-mono);
font-size: 0.65rem;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-3);
margin-top: 0.2rem;
}
@media (--sm-n-below) {
[data-layout="stats"] > * {
flex-basis: 33%;
border-right: none;
border-bottom: 1px solid var(--border-subtle);
}
}
/* 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:
══════════════════════════════════════════════════════════════════════════ */
@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: 2px 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);
--border-color-subtle: var(--gray-12);
--text-primary: var(--gray-0);
--text-secondary: 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 */