SchOS/docs/Website/app.css
Nexoniarz 26bca020b6 licence: SchOS is GPL-2.0-or-later, no longer Apache-2.0
Nexoniarz is the sole author and SchOS was never published under
Apache-2.0, so this is a straight relicence. LICENSE is the FSF GPLv2 text,
every first-party SPDX header moves to GPL-2.0-or-later, and NOTICE,
README.md, docs/licensing.md and the site say so. projects/schfs-linux
follows the rest of the tree.

The GPL gives copyleft: a fork has to ship its source. It also lifts the
old "Linux drivers, never" rule, since GPL-2.0-only code combines with
GPL-2.0-or-later. "Or later" leaves room for GPLv3, but one binary still
has to pick one version, so docs/licensing.md now keeps Apache-2.0 and
GPLv3 code out of the kernel to keep Linux code possible there. BSD
4-clause code goes from "avoid" to "no", because the advertising clause
is GPL-incompatible.

LDLS still ships no .ko. That boundary is now project policy rather than
a legal requirement, and ldls.md, devices.md and licensing.md section 6
say so. refmod declares license=GPL, and ldls-check passes (27 checks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 08:48:45 +02:00

542 lines
14 KiB
CSS

/* SPDX-License-Identifier: GPL-2.0-or-later */
/* ==========================================================================
The SchOS site — layout only
--------------------------------------------------------------------------
Everything here is *arrangement*: where things sit, how wide they get, when
they stack. Not one colour, shadow, radius, type size or duration is stated
in this file — those come from Niveus, which is the whole point of the
split. A hex value in here means the system is missing a token, and the
answer is to add one rather than to work around it.
The one exception is `--nv-brand`, which is declared in the pages: it is
SCH_ACCENT from include/theme.h, and it is an input to the system rather
than a restatement of it.
========================================================================== */
/* --- The page shell -------------------------------------------------------- */
.shell {
max-inline-size: var(--nv-layout-max-width);
margin-inline: auto;
padding-inline: var(--nv-layout-gutter);
}
.section {
padding-block: var(--nv-space-20);
}
.section__head {
max-inline-size: var(--nv-measure);
margin-block-end: var(--nv-space-8);
display: flex;
flex-direction: column;
gap: var(--nv-space-3);
}
/* A closing remark under a figure. Narrower than the figure, so it reads as
commentary on it rather than as the next section. */
.section__note {
max-inline-size: var(--nv-measure);
margin-block-start: var(--nv-space-5);
}
/* The flag in the bar. Deliberately small: the site is about an operating
system, and the flag is a statement, not a subject. */
.pride img {
display: block;
block-size: var(--nv-space-4);
inline-size: auto;
border-radius: var(--nv-radius-xs);
}
@media (max-width: 60rem) {
.appearance { display: none; }
}
/* --- Hero ------------------------------------------------------------------ */
.hero {
display: grid;
gap: var(--nv-space-12);
padding-block: var(--nv-space-16) var(--nv-space-8);
align-items: center;
}
@media (min-width: 62rem) {
.hero {
grid-template-columns: 5fr 7fr;
gap: var(--nv-space-14);
}
}
.hero__copy {
display: flex;
flex-direction: column;
gap: var(--nv-space-5);
align-items: flex-start;
}
.hero__title {
display: flex;
align-items: center;
gap: var(--nv-space-4);
font-size: clamp(var(--nv-font-size-4xl), 7vw, var(--nv-font-size-5xl));
}
.hero__mark {
inline-size: 1.15em;
block-size: 1.15em;
}
/* --- The console ----------------------------------------------------------- */
/*
A terminal is a recess, not a card that happens to hold monospace: the
material says "this is a window into the machine" before the text does.
*/
.console {
overflow: hidden;
}
.console__bar {
display: flex;
align-items: center;
gap: var(--nv-space-3);
padding: var(--nv-space-2) var(--nv-space-3);
border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
}
.console__log {
margin: 0;
padding: var(--nv-space-4);
min-block-size: 18rem;
overflow-x: auto;
white-space: pre;
line-height: var(--nv-line-height-relaxed);
background: var(--nv-color-surface-inset);
box-shadow: var(--nv-elevation-inset-sm);
}
/* The cursor the boot log types behind. */
.console__log::after {
content: "";
display: inline-block;
inline-size: 0.6em;
block-size: 1em;
vertical-align: text-bottom;
background: var(--nv-color-accent);
animation: console-blink 1.1s steps(2, start) infinite;
}
@keyframes console-blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
.console__log::after { animation: none; }
}
/* --- Origin, as a timeline -------------------------------------------------- */
/*
The rail is not decoration: these steps happened in this order, and the
order is the claim the section makes. A grid would lose it.
*/
.timeline {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--nv-space-8);
border-inline-start: var(--nv-border-width) solid var(--nv-color-border);
padding-inline-start: var(--nv-space-6);
}
.timeline__step {
display: flex;
flex-direction: column;
gap: var(--nv-space-2);
max-inline-size: var(--nv-measure);
position: relative;
}
.timeline__step::before {
content: "";
position: absolute;
inline-size: var(--nv-space-2);
block-size: var(--nv-space-2);
border-radius: var(--nv-radius-full);
background: var(--nv-color-accent);
inset-inline-start: calc(var(--nv-space-6) * -1 - var(--nv-space-1));
inset-block-start: var(--nv-space-1);
}
.timeline__when {
color: var(--nv-color-text-tertiary);
}
/* --- The stack -------------------------------------------------------------- */
.stack {
display: flex;
flex-direction: column;
}
.stack__layer {
display: grid;
grid-template-columns: 12rem 1fr;
gap: var(--nv-space-4);
align-items: baseline;
padding: var(--nv-space-3) var(--nv-space-5);
border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
}
.stack__layer:last-child { border-block-end: 0; }
.stack__name {
display: flex;
align-items: center;
gap: var(--nv-space-2);
font-family: var(--nv-font-family-mono);
color: var(--nv-color-text-primary);
}
/* The three seams the section is about. They are the argument, so they carry
the accent ground; everything else is the arrangement between them. */
.stack__layer--seam {
background: var(--nv-color-accent-subtle);
box-shadow: inset var(--nv-border-width-strong) 0 0 var(--nv-color-accent);
}
@media (max-width: 48rem) {
.stack__layer {
grid-template-columns: 1fr;
gap: var(--nv-space-1);
}
}
/* --- Hybrid: what a driver needs -------------------------------------------- */
.needs {
display: grid;
gap: var(--nv-space-4);
margin-block-end: var(--nv-space-8);
}
@media (min-width: 48rem) {
.needs { grid-template-columns: repeat(2, 1fr); }
}
/* --- Numbers ---------------------------------------------------------------- */
.figures {
display: grid;
gap: var(--nv-space-4);
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
/* A card carries no padding of its own -- its parts do -- and a stat tile has
no parts. */
.figure {
display: flex;
flex-direction: column;
gap: var(--nv-space-1);
align-items: flex-start;
padding: var(--nv-space-5);
}
.figure__value {
font-variant-numeric: tabular-nums;
letter-spacing: var(--nv-letter-spacing-tight);
}
/* --- PSOGM ------------------------------------------------------------------ */
.crash {
display: grid;
gap: var(--nv-space-8);
align-items: center;
padding: var(--nv-space-12);
}
@media (min-width: 48rem) {
.crash { grid-template-columns: auto 1fr; }
}
/* The bed's label is a caption for the whole region, not the first cell of
its grid. */
.crash .nv-bed__label {
grid-column: 1 / -1;
}
.crash__mark {
inline-size: var(--nv-space-20);
block-size: auto;
}
.crash__copy {
display: flex;
flex-direction: column;
gap: var(--nv-space-4);
}
/* --- The closing band -------------------------------------------------------- */
/* Padded here for the same reason .figure is: a card's padding lives on its
parts, and this band has none -- it is a mark, some copy and two buttons. */
.getband {
display: grid;
gap: var(--nv-space-8);
align-items: center;
padding: var(--nv-space-8);
}
@media (min-width: 48rem) {
.getband { grid-template-columns: auto 1fr; }
}
.getband__mark {
inline-size: var(--nv-space-20);
block-size: auto;
justify-self: center;
}
.getband__copy {
display: flex;
flex-direction: column;
gap: var(--nv-space-4);
align-items: flex-start;
}
/* --- Cards ------------------------------------------------------------------- */
/* Niveus's reset makes images block-level, which is right nearly everywhere
and wrong for a mark that belongs beside a title. A flex row rather than
`display: inline`, so the two stay aligned whatever the title does. */
.nv-card__title:has(.cardmark) {
display: flex;
align-items: center;
gap: var(--nv-space-2);
}
.cardmark {
inline-size: 1.2em;
block-size: 1.2em;
flex: none;
}
/* --- Footer ------------------------------------------------------------------ */
.site-footer {
display: flex;
flex-direction: column;
gap: var(--nv-space-5);
padding-block: var(--nv-space-8) var(--nv-space-16);
}
.site-footer__row {
display: flex;
flex-wrap: wrap;
gap: var(--nv-space-2) var(--nv-space-6);
align-items: baseline;
justify-content: space-between;
padding-block-start: var(--nv-space-6);
}
.pride-note {
display: flex;
align-items: center;
gap: var(--nv-space-3);
}
.pride-note img {
block-size: var(--nv-space-4);
inline-size: auto;
border-radius: var(--nv-radius-xs);
}
/* --- Reveal on scroll -------------------------------------------------------- */
/*
app.js adds .is-revealed. Without the script every section is simply
visible, which is the only acceptable failure mode for decoration.
*/
.section[data-reveal] {
opacity: 0;
translate: 0 var(--nv-travel-md);
transition:
opacity var(--nv-duration-slow) var(--nv-ease-entrance),
translate var(--nv-duration-slow) var(--nv-ease-entrance);
}
.section[data-reveal].is-revealed {
opacity: 1;
translate: 0 0;
}
/* --- Cards that are entirely a link ------------------------------------------ */
/*
The whole card is the target -- `.nv-card--interactive` says so by lifting
under the pointer -- so an underline on the title is a second affordance for
the same thing, and it reads as a link *inside* a link.
*/
.nv-card__link {
text-decoration: none;
}
/* --- Command blocks ----------------------------------------------------------- */
/*
A command is the one thing on these pages that must be copied exactly, so it
gets a recess of its own rather than sitting in the card's own material.
`white-space: pre` and not `pre-wrap`: a wrapped shell command is a command
that can be mistyped.
*/
.cmd {
margin: 0;
padding: var(--nv-space-3) var(--nv-space-4);
overflow-x: auto;
white-space: pre;
line-height: var(--nv-line-height-relaxed);
background: var(--nv-color-surface-inset);
border-radius: var(--nv-radius-nested-md);
box-shadow: var(--nv-elevation-inset-sm);
}
/* --- The documentation reader ------------------------------------------------ */
/*
Index, document, contents. Three columns that become one on a narrow screen,
in that order of importance: the document is the page, the index is how you
got there, and the contents panel is a convenience.
*/
.docshell {
max-inline-size: var(--nv-layout-max-width);
margin-inline: auto;
padding-inline: var(--nv-layout-gutter);
padding-block: var(--nv-space-8) var(--nv-space-16);
display: grid;
gap: var(--nv-space-8);
align-items: start;
}
@media (min-width: 64rem) {
.docshell {
grid-template-columns: 15rem minmax(0, 1fr) 14rem;
gap: var(--nv-space-10);
}
}
@media (max-width: 64rem) {
.docshell__rail { display: none; }
}
/* Both panels follow the reader down the page, under the bar rather than
behind it. */
.docshell__aside,
.docshell__rail {
position: sticky;
inset-block-start: var(--nv-space-16);
max-block-size: calc(100vh - var(--nv-space-24));
overflow-y: auto;
}
/* A vertical nav that is a panel in a page, not the chrome of an app: no
surface of its own, and no full-height rule down its edge. */
.docnav {
position: static; /* the column is what sticks, not the nav */
background: none;
border: 0;
box-shadow: none;
padding: 0;
inline-size: 100%; /* the sidebar component is a fixed 15rem */
block-size: auto;
}
.docnav .nv-nav__list {
flex-direction: column;
align-items: stretch;
gap: var(--nv-space-px);
margin-block-end: var(--nv-space-5);
}
/* A nav item in a bar is one line by definition; a document title is not. The
contents panel is 14rem wide and some headings are longer than that, so they
wrap rather than being cut off mid-word -- a truncated entry is a
destination you cannot recognise. */
.docnav .nv-nav__item {
justify-content: flex-start;
inline-size: 100%;
white-space: normal;
block-size: auto;
min-block-size: var(--nv-control-height-sm);
padding-block: var(--nv-space-1-5);
text-align: start;
}
/* A contents panel is a shape: depth reads as indentation. */
.toc-lvl3 .nv-nav__item { padding-inline-start: var(--nv-space-5); }
.toc-lvl4 .nv-nav__item { padding-inline-start: var(--nv-space-8); }
/* --- The document itself ----------------------------------------------------- */
.doc {
max-inline-size: none; /* the column already sets the measure */
}
.doc > * + * {
margin-block-start: var(--nv-space-4);
}
.doc h1,
.doc h2,
.doc h3,
.doc h4 {
margin-block-start: var(--nv-space-8);
scroll-margin-block-start: var(--nv-space-20);
}
.doc h2 {
padding-block-end: var(--nv-space-2);
border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
}
.doc__pre {
margin: 0;
padding: var(--nv-space-4);
overflow-x: auto;
white-space: pre;
line-height: var(--nv-line-height-relaxed);
background: var(--nv-color-surface-inset);
border-radius: var(--nv-radius-md);
box-shadow: var(--nv-elevation-inset-sm);
}
.doc blockquote {
margin-inline: 0;
padding: var(--nv-space-1) var(--nv-space-5);
border-inline-start: var(--nv-border-width-strong) solid var(--nv-color-accent-border);
color: var(--nv-color-text-secondary);
}
.doc ul,
.doc ol {
padding-inline-start: var(--nv-space-6);
}
.doc li + li {
margin-block-start: var(--nv-space-2);
}
/* --- The feature rail --------------------------------------------------------- */
/*
One declaration, because the component already does the rest: the equal
heights are the flex default, the snapping, the hidden scrollbar and the
fade that marks which end has more behind it are all .nv-scroller's. The
only thing it cannot know is how wide a card of *this* content wants to be,
and 18rem is a line where these carry a paragraph.
*/
.features {
--nv-scroller-item: 21rem;
}