asw/assets/css/layers/02-semantic.css
Vigilio Desto 82754338a9
fix: remap CSS container rules from <main> to <article>
body > nav/header/article/footer all get container alignment
(max-width, auto margins, responsive padding). Replaces all
body > main selectors to match the new landmark structure.
2026-04-10 20:39:13 +02:00

952 lines
21 KiB
CSS

/**
* 02-semantic.css
* Semantic HTML element styles
* Part of: Agentic Semantic Web
*
* Ported from: Pico CSS v2.1.1
* License: MIT
*
* This layer handles typography and semantic HTML elements.
* Classes are NOT supported—use semantic tags only.
*/
/* ── Typography: Headings ──────────────────────────────────────────── */
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: var(--type-space);
line-height: var(--leading-tight);
font-family: var(--font-heading);
text-wrap: balance;
}
h1 {
font-size: var(--h1-size);
color: var(--h1-color);
font-weight: var(--h1-weight);
}
h2 {
font-size: var(--h2-size);
color: var(--h2-color);
font-weight: var(--h2-weight);
}
h3 {
font-size: var(--h3-size);
color: var(--h3-color);
font-weight: var(--h3-weight);
}
h4 {
font-size: var(--h4-size);
color: var(--h4-color);
font-weight: var(--h4-weight);
}
h5 {
font-size: var(--h5-size);
color: var(--h5-color);
font-weight: var(--h5-weight);
text-transform: uppercase;
letter-spacing: 0.05em;
}
h6 {
font-size: var(--h6-size);
color: var(--h6-color);
font-weight: var(--h6-weight);
text-transform: uppercase;
letter-spacing: 0.06em;
}
/* Add spacing before headings that follow content elements */
:where(article, address, blockquote, dl, figure, form, ol, p, pre, table, ul) ~ :is(h1, h2, h3, h4, h5, h6) {
margin-top: var(--type-space-top);
}
/* ── Typography: UI elements — structural, navigational, informational ── */
/* These override the prose body font with the humanist sans UI stack. */
nav,
header,
footer,
label,
th,
caption,
small,
figcaption,
button,
input,
select,
textarea {
font-family: var(--font-ui);
}
/* ── Nav layout ─────────────────────────────────────────────────────── */
/* Ported from Pico CSS, translated to ASW tokens. */
nav {
display: flex;
justify-content: space-between;
align-items: center;
overflow: visible;
}
nav ul {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0;
padding: 0;
margin: 0;
list-style: none;
}
nav li {
display: inline-block;
margin: 0;
padding: var(--space-2) var(--space-3);
}
nav li a {
display: inline-block;
text-decoration: none;
color: var(--text);
padding: var(--space-2) var(--space-3);
margin: calc(var(--space-2) * -1) calc(var(--space-3) * -1);
border-radius: var(--radius-sm);
}
nav li a:hover {
color: var(--accent);
background: var(--surface-hover);
}
nav li strong,
nav li b {
color: var(--text);
}
@media (--md-n-below) {
nav { flex-wrap: wrap; gap: var(--space-2); }
nav ul { flex-wrap: wrap; gap: var(--space-1); }
}
/* ── Typography: Paragraphs ────────────────────────────────────────── */
p {
margin-top: 0;
margin-bottom: var(--type-space);
color: var(--text);
font-style: normal;
font-weight: var(--font-weight-4);
}
/* ── Typography: Lists ─────────────────────────────────────────────── */
address,
dl,
ol,
ul {
margin-top: 0;
margin-bottom: var(--type-space);
color: var(--text);
font-style: normal;
font-weight: var(--font-weight-4);
}
:where(ol, ul) li {
margin-bottom: calc(var(--type-space) * 0.25);
}
/* Nested lists: reduce spacing */
:where(dl, ol, ul) :where(dl, ol, ul) {
margin-top: calc(var(--type-space) * 0.25);
}
ul li {
list-style: square;
}
/* ── Typography: Blockquote ────────────────────────────────────────── */
blockquote {
display: block;
margin: var(--type-space) 0;
padding: var(--space-4);
border-right: none;
border-left: var(--space-1) solid var(--border);
border-inline-start: var(--space-1) solid var(--border);
border-inline-end: none;
}
blockquote footer {
margin-top: calc(var(--type-space) * 0.5);
color: var(--text-3);
}
/* ── Typography: Horizontal Rule ───────────────────────────────────── */
hr {
height: 0;
margin: var(--type-space) 0;
border: 0;
border-top: var(--border-width) solid var(--border);
color: inherit;
}
/* ── Typography: Inline Elements ───────────────────────────────────── */
b,
strong {
font-weight: bolder;
}
mark {
padding: 0.125rem 0.25rem;
background-color: var(--mark-bg);
color: var(--mark-color);
vertical-align: baseline;
}
ins {
color: var(--text-2);
text-decoration: none;
}
del {
color: var(--accent-red);
}
abbr[title] {
border-bottom: var(--border-size-1) dotted;
text-decoration: none;
cursor: help;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
small {
font-size: 0.875em;
}
/* ── Links ─────────────────────────────────────────────────────────── */
:where(a:not([role=button])),
[role=link] {
outline: none;
background-color: transparent;
color: var(--link);
text-decoration: underline;
text-decoration-color: var(--link-underline);
text-underline-offset: 0.125em;
transition: background-color var(--ease),
color var(--ease),
text-decoration var(--ease),
box-shadow var(--ease);
}
:where(a:not([role=button])):is(:hover, :active, :focus),
[role=link]:is(:hover, :active, :focus) {
color: var(--link-hover);
text-decoration-color: var(--link-hover-underline);
}
:where(a:not([role=button])):focus-visible,
[role=link]:focus-visible {
box-shadow: 0 0 0 var(--outline-width) var(--link-focus);
}
/* ── Text Selection ────────────────────────────────────────────────── */
::selection {
background-color: var(--selection);
}
/* ── Tables ────────────────────────────────────────────────────────── */
:where(table) {
width: 100%;
margin-top: 0;
margin-bottom: var(--type-space);
border-collapse: collapse;
border-spacing: 0;
text-indent: 0;
color: var(--text);
font-style: normal;
font-weight: var(--font-weight-4);
}
th,
td {
padding: calc(var(--space-4) / 2) var(--space-4);
border-bottom: var(--border-width) solid var(--border);
background-color: transparent;
color: var(--text);
font-weight: var(--font-weight-4);
text-align: left;
}
thead th,
thead td {
font-weight: 600;
border-bottom-width: var(--border-size-2);
}
tfoot th,
tfoot td {
border-top: var(--border-width) solid var(--border);
border-bottom: 0;
}
/* Striped tables (class-based but useful) */
[data-table="striped"] tbody tr:nth-child(odd) th,
[data-table="striped"] tbody tr:nth-child(odd) td {
background-color: var(--table-stripe);
}
/* ── Code & Preformatted Text ──────────────────────────────────────── */
pre,
code,
kbd,
samp {
font-size: 0.875em;
font-family: var(--font-mono);
border-radius: var(--radius-md);
background: var(--surface-1);
color: var(--code-color);
font-weight: var(--font-weight-4);
line-height: initial;
}
/* Inline code elements */
code,
kbd,
samp {
display: inline-block;
padding: 0.375rem;
}
/* Code blocks */
pre {
display: block;
margin-top: 0;
margin-bottom: var(--space-4);
padding: var(--space-4);
overflow-x: auto;
-ms-overflow-style: scrollbar;
}
pre > code,
pre > samp {
display: block;
padding: 0;
background: none;
font-size: inherit;
font-family: inherit;
line-height: var(--leading);
}
/* Keyboard input */
kbd {
background-color: var(--kbd-bg);
color: var(--kbd-color);
vertical-align: baseline;
}
/* ── Prism.js Syntax Highlighting Theme ────────────────────────────── *
*
* These rules style Prism.js token classes using ASW tokens.
* agentic.css provides the theme; each page loads Prism via:
*
* <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
* <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
* <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
*
* The CDN theme's colors are overridden here. ASW tokens handle dark/light.
* ─────────────────────────────────────────────────────────────────── */
/* Reset Prism default background — pre already styled by ASW */
code[class*="language-"],
pre[class*="language-"] {
color: var(--code-color);
background: none;
text-shadow: none;
}
pre[class*="language-"] {
background: var(--surface-1);
}
/* Token colors — dark (default) */
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: var(--syntax-comment);
font-style: italic;
}
.token.punctuation {
color: var(--text-3); /* slightly muted */
}
.token.tag,
.token.deleted {
color: var(--syntax-deleted);
}
.token.attr-name,
.token.namespace {
color: var(--syntax-namespace);
}
.token.string,
.token.attr-value,
.token.char,
.token.inserted {
color: var(--syntax-string);
}
.token.number,
.token.boolean,
.token.constant,
.token.symbol {
color: var(--orange-4); /* literals */
}
.token.selector,
.token.builtin {
color: var(--teal-4); /* CSS selectors, builtins */
}
.token.keyword,
.token.atrule {
color: var(--syntax-keyword);
}
.token.function,
.token.class-name {
color: var(--cyan-4); /* function/class names */
}
.token.property {
color: var(--syntax-property);
}
.token.operator,
.token.entity,
.token.url {
color: var(--text-2); /* operators */
}
.token.regex {
color: var(--orange-5); /* regex literals */
}
.token.important,
.token.variable {
color: var(--syntax-variable);
font-weight: var(--font-weight-5);
}
.token.bold { font-weight: var(--font-weight-7); }
.token.italic { font-style: italic; }
/* Light mode overrides */
@media (prefers-color-scheme: light) {
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata { color: var(--syntax-comment); }
.token.punctuation { color: var(--syntax-punctuation); }
.token.tag,
.token.deleted { color: var(--syntax-deleted); }
.token.attr-name,
.token.namespace { color: var(--syntax-namespace); }
.token.string,
.token.attr-value,
.token.char,
.token.inserted { color: var(--syntax-string); }
.token.number,
.token.boolean,
.token.constant,
.token.symbol { color: var(--orange-8); }
.token.selector,
.token.builtin { color: var(--teal-8); }
.token.keyword,
.token.atrule { color: var(--syntax-keyword); }
.token.function,
.token.class-name { color: var(--cyan-9); }
.token.property { color: var(--syntax-property); }
.token.operator,
.token.entity,
.token.url { color: var(--syntax-url); }
.token.regex { color: var(--orange-7); }
.token.important,
.token.variable { color: var(--syntax-variable); }
}
/* ── Details / Summary ─────────────────────────────────────────────── */
details {
display: block;
margin-bottom: var(--space-4);
}
details summary {
line-height: 1rem;
list-style-type: none;
cursor: pointer;
transition: color var(--ease);
color: var(--accent);
}
/* Hide browser default marker */
details summary::-webkit-details-marker {
display: none;
}
details summary::marker {
display: none;
}
details summary::-moz-list-bullet {
list-style-type: none;
}
/* CSS-drawn chevron using Unicode character ▸ (U+25B8) */
details summary::after {
content: "▸";
display: inline-block;
width: 1rem;
height: 1rem;
margin-inline-start: calc(var(--space-4, 1rem) * 0.5);
float: right;
font-size: var(--text-sm);
line-height: 1rem;
text-align: center;
color: var(--text-3);
transform: rotate(90deg); /* Point down when closed */
transition: transform var(--ease);
}
details summary:focus {
outline: none;
}
details summary:focus-visible {
outline: var(--outline-width) solid var(--accent-focus);
outline-offset: calc(var(--space-4, 1rem) * 0.5);
color: var(--accordion-active);
}
/* Open state */
details[open] > summary {
margin-bottom: var(--space-4);
color: var(--text-3);
}
details[open] > summary::after {
transform: rotate(180deg); /* Point down when open */
}
/* ── Dialog / Modal ────────────────────────────────────────────────── */
dialog {
display: flex;
z-index: 999;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
align-items: center;
justify-content: center;
width: inherit;
min-width: auto;
height: inherit;
min-height: 100%;
padding: 0;
border: 0;
backdrop-filter: var(--modal-backdrop);
background-color: var(--modal-overlay);
color: var(--text);
}
dialog > article {
width: 100%;
max-height: calc(100vh - var(--space-4) * 2);
margin: var(--space-4);
overflow: auto;
}
/* Responsive max-widths for modal content */
@media (--sm-n-above) {
dialog > article {
max-width: var(--width-sm);
}
}
@media (--md-n-above) {
dialog > article {
max-width: var(--width-md);
}
}
/* Modal header */
dialog > article > header > * {
margin-bottom: 0;
}
dialog > article > header .close,
dialog > article > header :is(a, button)[rel=prev] {
margin: 0;
margin-left: var(--space-4);
padding: 0;
float: right;
}
/* Modal footer */
dialog > article > footer {
text-align: right;
}
dialog > article > footer button,
dialog > article > footer [role=button] {
margin-bottom: 0;
}
dialog > article > footer button:not(:first-of-type),
dialog > article > footer [role=button]:not(:first-of-type) {
margin-left: calc(var(--space-4) * 0.5);
}
/* Close button: Unicode ✕ (U+2715) instead of SVG */
dialog > article .close,
dialog > article :is(a, button)[rel=prev] {
display: block;
width: 1.5rem;
height: 1.5rem;
margin-top: calc(var(--space-4) * -0.5);
margin-bottom: var(--space-4);
margin-left: auto;
border: none;
background-color: transparent;
color: var(--text-3);
font-size: 1.5rem;
line-height: 1;
text-align: center;
opacity: 0.5;
transition: opacity var(--ease);
cursor: pointer;
}
dialog > article .close::before,
dialog > article :is(a, button)[rel=prev]::before {
content: "✕"; /* Unicode heavy multiplication X */
}
dialog > article .close:is([aria-current]:not([aria-current=false]), :hover, :active, :focus),
dialog > article :is(a, button)[rel=prev]:is([aria-current]:not([aria-current=false]), :hover, :active, :focus) {
opacity: 1;
}
/* Hidden state */
dialog:not([open]),
dialog[open=false] {
display: none;
}
/* Body scroll lock when modal is open */
.modal-is-open {
padding-right: var(--scrollbar-width, 0px);
overflow: hidden;
pointer-events: none;
touch-action: none;
}
.modal-is-open dialog {
pointer-events: auto;
touch-action: auto;
}
/* Animations (only if motion is not reduced) */
@media (prefers-reduced-motion: no-preference) {
:where(.modal-is-opening, .modal-is-closing) dialog,
:where(.modal-is-opening, .modal-is-closing) dialog > article {
animation-duration: var(--duration-moderate-1);
animation-timing-function: ease-in-out;
animation-fill-mode: both;
}
:where(.modal-is-opening, .modal-is-closing) dialog {
animation-duration: var(--duration-gentle-2);
animation-name: modal-overlay;
}
:where(.modal-is-opening, .modal-is-closing) dialog > article {
animation-delay: var(--duration-moderate-1);
animation-name: modal;
}
.modal-is-closing dialog,
.modal-is-closing dialog > article {
animation-delay: 0s;
animation-direction: reverse;
}
@keyframes modal-overlay {
from {
backdrop-filter: none;
background-color: transparent;
}
}
@keyframes modal {
from {
transform: translateY(-100%);
opacity: 0;
}
}
}
/* Respect reduced motion: instant show/hide */
@media (prefers-reduced-motion: reduce) {
dialog,
dialog > article {
animation: none !important;
transition: none !important;
}
}
/* ── Figure & Figcaption ───────────────────────────────────────────── */
figure {
display: block;
margin: 0;
margin-bottom: var(--space-4);
padding: 0;
}
figure figcaption {
padding: calc(var(--space-4) * 0.5) 0;
color: var(--text-3);
font-size: var(--text-sm);
}
/* ── Progress ──────────────────────────────────────────────────────── */
progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: inline-block;
vertical-align: baseline;
width: 100%;
height: 0.5rem;
margin-bottom: calc(var(--space-4) * 0.5);
overflow: hidden;
border: 0;
border-radius: var(--radius-md);
background-color: var(--track-bg);
color: var(--accent);
}
progress::-webkit-progress-bar {
border-radius: var(--radius-md);
background: none;
}
progress[value]::-webkit-progress-value {
background-color: var(--accent);
transition: inline-size var(--ease);
}
progress::-moz-progress-bar {
background-color: var(--accent);
}
/* Indeterminate progress (animated) - respect motion preferences */
@media (prefers-reduced-motion: no-preference) {
progress:indeterminate {
background: var(--track-bg)
linear-gradient(to right,
var(--accent) 30%,
var(--track-bg) 30%)
top left / 150% 150% no-repeat;
animation: progress-indeterminate calc(var(--duration-gentle-2) * 2) linear infinite;
}
progress:indeterminate[value]::-webkit-progress-value {
background-color: transparent;
}
@keyframes progress-indeterminate {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
}
@media (prefers-reduced-motion: reduce) {
progress:indeterminate {
background: var(--track-bg);
}
}
/* ── Meter ─────────────────────────────────────────────────────────── */
meter {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: inline-block;
vertical-align: baseline;
width: 100%;
height: 0.5rem;
margin-bottom: calc(var(--space-4) * 0.5);
overflow: hidden;
border: 0;
border-radius: var(--radius-md);
background-color: var(--track-bg);
accent-color: var(--accent); /* Modern CSS: browser renders with our accent */
}
/* Webkit meter styling */
meter::-webkit-meter-bar {
border-radius: var(--radius-md);
background-color: var(--track-bg);
}
meter::-webkit-meter-optimum-value {
background-color: var(--accent);
}
meter::-webkit-meter-suboptimum-value {
background-color: var(--accent-blue);
}
meter::-webkit-meter-even-less-good-value {
background-color: var(--accent-red); /* Red-ish for bad values */
}
/* Firefox meter styling */
meter::-moz-meter-bar {
border-radius: var(--radius-md);
background-color: var(--accent);
}
meter:-moz-meter-optimum::-moz-meter-bar {
background-color: var(--accent);
}
meter:-moz-meter-sub-optimum::-moz-meter-bar {
background-color: var(--accent-blue);
}
meter:-moz-meter-sub-sub-optimum::-moz-meter-bar {
background-color: var(--accent-red);
}
/* ── Content Container ─────────────────────────────────────────────── */
/* All body-level landmarks share container alignment:
<body> > <nav>, <header>, <article role="main">, <footer>
Scoped to body > child to avoid affecting nested elements. */
body > nav,
body > header,
body > article,
body > footer {
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: var(--space-4);
padding-left: var(--space-4);
}
@media (--sm-n-above) {
body > nav,
body > header,
body > article,
body > footer {
max-width: var(--width-sm);
padding-right: 0;
padding-left: 0;
}
}
@media (--md-n-above) {
body > nav,
body > header,
body > article,
body > footer {
max-width: var(--width-md);
}
}
@media (--lg-n-above) {
body > nav,
body > header,
body > article,
body > footer {
max-width: var(--width-lg);
}
}
@media (--xl-n-above) {
body > nav,
body > header,
body > article,
body > footer {
max-width: var(--width-xl);
}
}
@media (--xxl-n-above) {
body > nav,
body > header,
body > article,
body > footer {
max-width: var(--width-2xl);
}
}