SchOS/docs/Website/style.css
Nexoniarz ef94fac4ac docs: a Markdown reader on the site, and the flag stays up
Two additions to docs/Website.

**The reader.** docs.html renders the 29 documents in docs/ in the site's own
theme -- index down the left, table of contents down the right, and links
between documents rewritten so ../history/schfs.md navigates inside the
reader instead of downloading a file.

The parser is ~150 lines in docs.js, not a dependency: it handles exactly
what docs/ uses, and a Markdown library would outweigh every other asset here
combined. Everything is escaped before a tag is emitted, so the only HTML
that reaches the page is HTML docs.js wrote. Verified by rendering all 30
documents (302 KB of Markdown) with zero failures, no unrestored sentinels
and no runaway loops.

One caveat, stated in the page itself rather than hidden: browsers block
fetch() on file:// URLs, so this page needs a server. It says so, with the
command, and offers the raw file as a fallback. The rest of the site is
unaffected.

**The flag.** A Progress Pride flag in the top bar and a line in the footer,
on both pages, permanently. Support with an end date is marketing. It is
deliberately small and deliberately not a page of its own -- this is an
operating system, and the flag is a statement, not a subject.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
2026-09-12 21:53:06 +02:00

578 lines
17 KiB
CSS

/* SPDX-License-Identifier: Apache-2.0
*
* The palette is not chosen here. It is include/theme.h, transcribed, because
* a site that describes an operating system should look like the operating
* system. That includes the rule theme.h enforces:
*
* normal states are calm and dark; only failure is loud.
*
* PSOGM purple (--psogm) therefore appears exactly once on this page, in the
* crash-screen section. If it ever appears anywhere else, delete it there.
*/
:root {
/* include/theme.h */
--bg: #0C0E13; /* SCH_BG */
--fg: #E6E8EC; /* SCH_FG */
--dim: #707784; /* SCH_DIM */
--accent: #7C5CFF; /* SCH_ACCENT */
--accent-dim: #2A2440; /* SCH_ACCENT_DIM */
--ok: #4ADE80; /* SCH_OK */
--warn: #FBBF24; /* SCH_WARN */
--psogm: #4B1D9A; /* PSOGM_BG — failure, and nothing else */
/* Surfaces lifted off the ground, keeping its blue bias rather than
sliding toward neutral grey. */
--surface: #12151C;
--surface-2: #171B24;
--line: #212632;
--sans: "Roboto", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "Cascadia Code",
Menlo, Consolas, monospace;
--measure: 66ch;
--gap: clamp(1rem, 2.5vw, 1.75rem);
--section: clamp(4rem, 10vw, 7.5rem);
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
body {
margin: 0;
background: var(--bg);
color: var(--fg);
font-family: var(--sans);
font-size: clamp(1rem, 0.95rem + 0.2vw, 1.0625rem);
line-height: 1.65;
-webkit-font-smoothing: antialiased;
}
/* ---- shared shells ------------------------------------------------- */
.wrap {
width: min(100% - 2.5rem, 68rem);
margin-inline: auto;
}
section { padding-block: var(--section); }
.eyebrow {
font-family: var(--mono);
font-size: 0.75rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--accent);
margin: 0 0 0.75rem;
}
h1, h2, h3 { text-wrap: balance; line-height: 1.15; margin: 0; }
h2 {
font-size: clamp(1.75rem, 1.3rem + 2vw, 2.75rem);
font-weight: 700;
letter-spacing: -0.02em;
}
.lede {
max-width: var(--measure);
color: var(--dim);
font-size: clamp(1.05rem, 1rem + 0.35vw, 1.2rem);
margin: 1.25rem 0 0;
}
p { max-width: var(--measure); }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--fg); }
a:focus-visible,
button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
border-radius: 2px;
}
code, .mono { font-family: var(--mono); font-size: 0.9em; }
code { color: var(--fg); background: var(--surface-2); padding: 0.1em 0.4em; border-radius: 3px; }
/* ---- header -------------------------------------------------------- */
header.top {
position: sticky;
top: 0;
z-index: 10;
background: color-mix(in srgb, var(--bg) 88%, transparent);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--line);
}
.top .wrap {
display: flex;
align-items: center;
gap: 1.5rem;
padding-block: 0.85rem;
}
.brand {
display: flex; align-items: center; gap: 0.6rem;
font-weight: 700; letter-spacing: -0.01em;
color: inherit; text-decoration: none;
}
.brand img { width: 26px; height: 26px; display: block; }
.top nav { margin-left: auto; display: flex; gap: 1.5rem; font-size: 0.9rem; }
.top nav a { color: var(--dim); text-decoration: none; }
.top nav a:hover { color: var(--fg); }
@media (max-width: 46rem) { .top nav { display: none; } }
/* ---- hero ---------------------------------------------------------- */
.hero { padding-block: clamp(3.5rem, 9vw, 6.5rem) var(--section); }
.hero .wrap {
display: grid;
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
gap: clamp(2rem, 5vw, 4rem);
align-items: center;
}
@media (max-width: 56rem) {
.hero .wrap { grid-template-columns: 1fr; }
}
.hero h1 {
font-size: clamp(2.75rem, 1.8rem + 4.2vw, 4.75rem);
font-weight: 700;
letter-spacing: -0.035em;
}
.hero h1 .mark {
display: inline-block;
width: 0.95em;
height: 0.95em;
vertical-align: -0.08em;
margin-right: 0.22em;
}
.hero p { color: var(--dim); font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem); margin-top: 1.25rem; }
.hero .cta { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }
.btn {
display: inline-block;
padding: 0.65rem 1.25rem;
border-radius: 4px;
font-size: 0.925rem;
font-weight: 500;
text-decoration: none;
border: 1px solid var(--line);
color: var(--fg);
background: var(--surface);
}
.btn:hover { border-color: var(--accent); color: var(--fg); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #0B0714; font-weight: 700; }
.btn.primary:hover { background: #8F73FF; border-color: #8F73FF; color: #0B0714; }
/* ---- console ------------------------------------------------------- */
.console {
background: #090B0F;
border: 1px solid var(--line);
border-radius: 6px;
overflow: hidden;
box-shadow: 0 24px 60px -30px #000;
}
.console-bar {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.55rem 0.85rem;
border-bottom: 1px solid var(--line);
background: var(--surface);
font-family: var(--mono);
font-size: 0.72rem;
color: var(--dim);
letter-spacing: 0.06em;
}
.console-bar .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); }
.console-bar .dot.live { background: var(--ok); }
.console-bar span { margin-left: auto; }
.console pre {
margin: 0;
padding: 1rem 1.1rem 1.4rem;
font-family: var(--mono);
font-size: clamp(0.72rem, 0.62rem + 0.35vw, 0.82rem);
line-height: 1.85;
color: var(--fg);
overflow-x: auto;
min-height: 16.5rem;
}
.console .t { color: var(--dim); }
.console .k { color: var(--accent); }
.console .g { color: var(--ok); }
.console .cursor {
display: inline-block;
width: 0.55em;
height: 1.05em;
background: var(--accent);
vertical-align: -0.18em;
animation: blink 1.1s step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .console .cursor { animation: none; } }
/* ---- origin timeline ----------------------------------------------- */
.origin-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
gap: var(--gap);
margin-top: 3rem;
}
.step {
border-left: 2px solid var(--accent-dim);
padding-left: 1.1rem;
}
.step h3 { font-size: 1.05rem; font-weight: 700; margin-bottom: 0.4rem; }
.step .when { font-family: var(--mono); font-size: 0.72rem; color: var(--accent); letter-spacing: 0.08em; text-transform: uppercase; display: block; margin-bottom: 0.5rem; }
.step p { color: var(--dim); font-size: 0.925rem; margin: 0; }
/* ---- the stack ----------------------------------------------------- */
.stack { display: flex; flex-direction: column; gap: 3px; margin-top: 3rem; }
.layer {
display: grid;
grid-template-columns: 10.5rem 1fr;
gap: 1.25rem;
align-items: baseline;
padding: 0.95rem 1.15rem;
background: var(--surface);
border: 1px solid transparent;
border-radius: 3px;
}
.layer:hover { border-color: var(--accent-dim); background: var(--surface-2); }
.layer .name { font-family: var(--mono); font-size: 0.8rem; color: var(--accent); letter-spacing: 0.04em; }
.layer .what { color: var(--dim); font-size: 0.9rem; }
.layer.seam { background: var(--accent-dim); }
.layer.seam .name { color: var(--fg); }
.layer.seam .what { color: #C9BEEC; }
@media (max-width: 42rem) {
.layer { grid-template-columns: 1fr; gap: 0.3rem; }
}
.seam-note { margin-top: 1.5rem; color: var(--dim); font-size: 0.9rem; }
/* ---- features ------------------------------------------------------ */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
gap: var(--gap);
margin-top: 3rem;
}
.card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: 5px;
padding: 1.4rem;
display: flex;
flex-direction: column;
gap: 0.6rem;
}
.card h3 { font-size: 1.05rem; font-weight: 700; }
.card p { color: var(--dim); font-size: 0.925rem; margin: 0; max-width: none; }
.card .tag {
align-self: flex-start;
font-family: var(--mono);
font-size: 0.68rem;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 0.2rem 0.5rem;
border-radius: 3px;
border: 1px solid var(--line);
color: var(--dim);
}
.card .tag.runs { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.card .tag.partial{ color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.card .tag.planned{ color: var(--dim); }
/* ---- numbers ------------------------------------------------------- */
.figures {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
gap: var(--gap);
margin-top: 3rem;
}
.figure { border-top: 1px solid var(--line); padding-top: 1rem; }
.figure b {
display: block;
font-family: var(--mono);
font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.25rem);
font-weight: 700;
font-variant-numeric: tabular-nums;
letter-spacing: -0.02em;
}
.figure span { color: var(--dim); font-size: 0.85rem; }
/* ---- the crash screen: the one loud thing --------------------------- */
.crash { background: var(--psogm); color: #fff; }
.crash .wrap {
display: grid;
grid-template-columns: 8rem minmax(0, 1fr);
gap: clamp(1.5rem, 4vw, 3rem);
align-items: start;
}
@media (max-width: 44rem) { .crash .wrap { grid-template-columns: 1fr; } }
.crash img { width: 100%; max-width: 8rem; height: auto; }
.crash .eyebrow { color: #C3AEEC; }
.crash h2 { color: #fff; }
.crash p { color: #DBCEF5; }
.crash code { background: rgba(0, 0, 0, 0.28); color: #fff; }
/* ---- closing links -------------------------------------------------- */
.links { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: var(--gap); margin-top: 2.5rem; }
.link-card {
display: block;
padding: 1.2rem;
border: 1px solid var(--line);
border-radius: 5px;
text-decoration: none;
color: var(--fg);
background: var(--surface);
}
.link-card:hover { border-color: var(--accent); color: var(--fg); }
.link-card b { display: block; margin-bottom: 0.3rem; }
.link-card span { color: var(--dim); font-size: 0.875rem; }
footer {
border-top: 1px solid var(--line);
padding-block: 2.5rem 3.5rem;
color: var(--dim);
font-size: 0.85rem;
}
footer .wrap { display: flex; flex-wrap: wrap; gap: 1rem 2rem; align-items: center; }
footer .mono { font-size: 0.78rem; }
/* ---- reveal on scroll ---------------------------------------------- */
.reveal { opacity: 0; transform: translateY(12px); transition: opacity .5s ease, transform .5s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.reveal { opacity: 1; transform: none; transition: none; }
}
/* The SchFS mark, set beside its own card heading. Baseline-aligned rather
than centred: it sits next to a word, so it follows the word. */
.card h3 .cardmark {
width: 1.15em;
height: 1.15em;
vertical-align: -0.22em;
margin-right: 0.4em;
}
/* =====================================================================
The pride mark
---------------------------------------------------------------------
Small, and permanent. It is in the top bar in November the same way it
is in June, which is the only version of this that means anything --
support with an end date is marketing.
Deliberately not bigger than this. The site is about an operating
system; the flag is a statement, not a subject.
===================================================================== */
.pride {
display: inline-flex;
align-items: center;
line-height: 0;
border-radius: 2px;
text-decoration: none;
}
.pride img {
width: 26px;
height: auto;
display: block;
border-radius: 2px;
/* Sits down slightly against the dark ground so it reads as part of the
bar rather than as a sticker on top of it; full colour on hover. */
opacity: 0.85;
transition: opacity .18s ease, transform .18s ease;
}
.pride:hover img { opacity: 1; transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) {
.pride img { transition: none; }
.pride:hover img { transform: none; }
}
.pride-note {
display: flex;
align-items: center;
gap: 0.6rem;
flex-basis: 100%;
color: var(--dim);
font-size: 0.82rem;
}
.pride-note img { width: 20px; height: auto; border-radius: 2px; flex: none; }
/* =====================================================================
The documentation reader
===================================================================== */
body.reading { display: flex; flex-direction: column; min-height: 100vh; }
body.reading footer { margin-top: auto; }
.docshell {
width: min(100% - 2.5rem, 84rem);
margin-inline: auto;
display: grid;
grid-template-columns: 15rem minmax(0, 1fr) 13rem;
gap: clamp(1.5rem, 3vw, 3rem);
align-items: start;
padding-block: 2.5rem 4rem;
}
@media (max-width: 72rem) { .docshell { grid-template-columns: 14rem minmax(0, 1fr); } .rail { display: none; } }
@media (max-width: 54rem) { .docshell { grid-template-columns: 1fr; } .sidebar .sticky { position: static; max-height: none; } }
.sticky {
position: sticky;
top: 4.5rem;
max-height: calc(100vh - 6rem);
overflow-y: auto;
scrollbar-width: thin;
}
.navgroup {
font-family: var(--mono);
font-size: 0.68rem;
letter-spacing: 0.13em;
text-transform: uppercase;
color: var(--dim);
margin: 1.6rem 0 0.5rem;
}
.navgroup:first-child { margin-top: 0; }
#docnav ul, #toc ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
#docnav a, #toc a {
display: block;
padding: 0.28rem 0.6rem;
margin-left: -0.6rem;
border-radius: 3px;
color: var(--dim);
text-decoration: none;
font-size: 0.875rem;
line-height: 1.45;
}
#docnav a:hover, #toc a:hover { color: var(--fg); background: var(--surface); }
#docnav a.on {
color: var(--fg);
background: var(--accent-dim);
box-shadow: inset 2px 0 0 var(--accent);
}
#toc .lvl3 a { padding-left: 1.5rem; font-size: 0.8rem; }
/* ---- prose ---------------------------------------------------------- */
.prose { max-width: 46rem; }
.prose .loading { color: var(--dim); font-family: var(--mono); font-size: 0.85rem; }
.prose h1 {
font-size: clamp(1.9rem, 1.4rem + 2.2vw, 2.6rem);
font-weight: 700;
letter-spacing: -0.025em;
margin: 0 0 1.25rem;
}
.prose h2 {
font-size: clamp(1.3rem, 1.1rem + 1vw, 1.65rem);
font-weight: 700;
letter-spacing: -0.015em;
margin: 2.75rem 0 0.9rem;
padding-top: 1.6rem;
border-top: 1px solid var(--line);
}
.prose h3 { font-size: 1.1rem; font-weight: 700; margin: 2rem 0 0.6rem; }
.prose h4, .prose h5, .prose h6 { font-size: 0.95rem; font-weight: 700; margin: 1.5rem 0 0.5rem; color: var(--dim); }
.prose p, .prose li { color: #C6CAD3; }
.prose p { margin: 0 0 1.1rem; max-width: none; }
.prose strong { color: var(--fg); }
.prose a { color: var(--accent); }
.prose ul, .prose ol { margin: 0 0 1.2rem; padding-left: 1.35rem; display: flex; flex-direction: column; gap: 0.4rem; }
.prose li { line-height: 1.6; }
.prose li::marker { color: var(--accent); }
.prose hr { border: 0; border-top: 1px solid var(--line); margin: 2.25rem 0; }
.prose blockquote {
margin: 1.4rem 0;
padding: 0.2rem 0 0.2rem 1.1rem;
border-left: 2px solid var(--accent);
color: var(--dim);
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose pre.code {
background: #090B0F;
border: 1px solid var(--line);
border-radius: 5px;
padding: 0.95rem 1.1rem;
overflow-x: auto;
margin: 0 0 1.3rem;
position: relative;
}
.prose pre.code code {
font-family: var(--mono);
font-size: 0.815rem;
line-height: 1.7;
color: #CBD1DC;
background: none;
padding: 0;
white-space: pre;
}
.prose pre.code[data-lang]::after {
content: attr(data-lang);
position: absolute;
top: 0.5rem;
right: 0.7rem;
font-family: var(--mono);
font-size: 0.62rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--dim);
}
.prose :not(pre) > code {
font-family: var(--mono);
font-size: 0.85em;
background: var(--surface-2);
border: 1px solid var(--line);
color: #D8DCE4;
padding: 0.08em 0.36em;
border-radius: 3px;
}
.tablewrap { overflow-x: auto; margin: 0 0 1.4rem; }
.prose table { border-collapse: collapse; width: 100%; font-size: 0.9rem; }
.prose th, .prose td {
text-align: left;
padding: 0.55rem 0.85rem;
border-bottom: 1px solid var(--line);
vertical-align: top;
}
.prose th {
font-family: var(--mono);
font-size: 0.72rem;
letter-spacing: 0.07em;
text-transform: uppercase;
color: var(--accent);
border-bottom-color: var(--accent-dim);
white-space: nowrap;
}
.prose td { color: #C6CAD3; }
.prose tbody tr:hover td { background: var(--surface); }
.prose img { max-width: 100%; height: auto; }
.top nav a.on { color: var(--fg); }
.readerlink { margin-top: 2rem; }