/* 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/gfx/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 window into the machine, so it is drawn as one: a solid .nv-window whose body is a recess the log is typed into. The traffic lights are decoration here -- nothing on this page can be closed -- so they are spans, hidden from assistive tech, rather than buttons that do nothing. */ .console { min-inline-size: 0; } .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. */ #bootlog::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; } /* Only the boot log types; a finished transcript is as tall as it is. */ .console__log:not(#bootlog) { min-block-size: 0; } @keyframes console-blink { 50% { opacity: 0; } } @media (prefers-reduced-motion: reduce) { #bootlog::after { animation: none; } } /* --- Origin, as steps ------------------------------------------------------- */ /* 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. .nv-steps cuts the rail into the surface and lights what is done; all this adds is the measure, because a step is a paragraph and not a label. */ .origin .nv-steps__body { max-inline-size: var(--nv-measure); padding-block-end: var(--nv-space-4); display: flex; flex-direction: column; gap: var(--nv-space-1); } .origin .nv-steps__title { font-size: var(--nv-font-size-lg); } .origin .nv-steps__text { font-size: var(--nv-font-size-md); color: var(--nv-color-text-secondary); } /* --- 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); } } /* --- 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 ------------------------------------------------------------------- */ /* A feature's tile belongs beside its title, not above it. A flex row rather than `display: inline`, so the two stay aligned whatever the title does. */ .nv-card__title:has(.nv-tile) { display: flex; align-items: center; gap: var(--nv-space-3); } .nv-card__title .nv-tile { 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; }