/* SPDX-License-Identifier: Apache-2.0 */ /* ========================================================================== 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); }