diff options
| author | user <user@clank> | 2026-08-30 14:18:57 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-30 14:18:57 +0200 |
| commit | a4e1bb12760c2b9768e2917e41ac4600dcdf3156 (patch) | |
| tree | 51bdafee58c62a542dd2e1f295a30f71bc824798 | |
| parent | web: sloshcast (diff) | |
| download | slosh-a4e1bb12760c2b9768e2917e41ac4600dcdf3156.tar.gz slosh-a4e1bb12760c2b9768e2917e41ac4600dcdf3156.tar.xz slosh-a4e1bb12760c2b9768e2917e41ac4600dcdf3156.zip | |
web: a whole lot of html/css wrangling
| -rw-r--r-- | web/README.md | 8 | ||||
| -rw-r--r-- | web/index.html | 89 | ||||
| -rwxr-xr-x | web/install.sh | 134 | ||||
| -rw-r--r-- | web/recordings/demos/config.py | 6 | ||||
| -rw-r--r-- | web/recordings/demos/reflow.py | 15 | ||||
| -rw-r--r-- | web/recordings/demos/scripting.py | 14 | ||||
| -rw-r--r-- | web/recordings/demos/shaders.py | 7 | ||||
| -rw-r--r-- | web/site.css | 119 |
8 files changed, 278 insertions, 114 deletions
diff --git a/web/README.md b/web/README.md index f720bd6..9eb599b 100644 --- a/web/README.md +++ b/web/README.md @@ -48,6 +48,10 @@ the one condition the webdemo README already states: `.wasm` must be served as - Every feature in the tour has its recording now; what remains on the recordings side (a detach demo, storyline polish, static no-JS posters) is in `recordings/PLAN.md`. -- `install.sh` clones `https://slosh.foo/src` (override: `SLOSH_REPO=`). Pin - the real public repo URL once it exists — same for the `src` links in +- `install.sh` downloads the prebuilt binary from `https://slosh.foo/dist/` + (override: `SLOSH_DIST=`), picking the newest version listed in its + `SHA256SUMS`. Once the GitHub repo is public, the front page and the + script can point at GitHub releases instead — same for the `src` links in `index.html`. +- The windows zips (`make release-windows`) are not uploaded to `/dist/` yet; + the windows install tab points there, so upload them with the next release. diff --git a/web/index.html b/web/index.html index adcb8f7..56dad19 100644 --- a/web/index.html +++ b/web/index.html @@ -10,18 +10,33 @@ </head> <body> -<nav class="nav" aria-label="Site"> - <a href="./" aria-current="page">slosh</a> - <a href="demo/">demo</a> - <a href="docs/">docs</a> - <span class="nav-fill"></span> - <a href="https://slosh.foo/src">src</a> -</nav> +<!-- The little logo: the big one, shrunk into the corner the stage's + v-centering leaves empty. It fades in when the hero scrolls away + (the observer at the bottom of the page) and is a road back up. --> +<a class="logo-float" href="#" aria-label="slosh — back to top"> +<pre aria-hidden="true"> +▄██████▄ ███ ▄██████▄ ▄██████▄ ▄██ ▄██ +███ ▀▀ ███ ███ ███ ███ ▀▀ ███ ███ +▀██████▄ ███ ▄▄▄ ███ ███ ▀██████▄ ████████ +▄▄ ███ ███ ███ ███ ███ ▄▄ ███ ███ ███ +▀██████▀ ███████▀ ▀██████▀ ███████▀ ███ ███ +▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ +▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ +</pre> +</a> <main> <header class="hero"> - <h1>slosh</h1> +<pre class="logo"> +▄██████▄ ███ ▄██████▄ ▄██████▄ ▄██ ▄██ +███ ▀▀ ███ ███ ███ ███ ▀▀ ███ ███ +▀██████▄ ███ ▄▄▄ ███ ███ ▀██████▄ ████████ +▄▄ ███ ███ ███ ███ ███ ▄▄ ███ ███ ███ +▀██████▀ ███████▀ ▀██████▀ ███████▀ ███ ███ +▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ +▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ +</pre> <p class="tagline">a modern terminal multiplexer written in C on top of <a href="https://github.com/ghostty-org/ghostty">libghostty-vt</a>.</p> @@ -139,8 +154,11 @@ <section id="install"> <h2>install</h2> -<p>we aim to make installing `slosh` as easy as possible. we provide binaries for most popular platforms/architectures on our <a href="">github</a>. -and we also provide some arch package repo's as well as a brew formula, check below! +<p>Prebuilt binaries for the popular platforms live at +<a href="dist/">slosh.foo/dist</a> — one static file each, checksummed. The +tabs below are the short roads to one: an installer for linux, a brew formula +for macos, a signed pacman repo for arch, a zip for windows. Building from +source works too, but you never need to.</p> <!-- Pure CSS tabs: hidden radios, labels drawn like a slosh tab strip, one panel per platform. The only JavaScript is the preselect at the @@ -166,10 +184,18 @@ and we also provide some arch package repo's as well as a brew formula, check be <pre><code><span class="prompt">$</span> curl -fsSL https://slosh.foo/install.sh | sudo sh</code></pre> <button class="copy" type="button" aria-label="Copy command">copy</button> </div> - <p class="aside">Piping a URL into a root shell should make you flinch — - <a href="install.sh">read it first</a>, it is short: git, - <a href="https://ziglang.org">zig</a> 0.16, one static binary into - <code>/usr/local/bin</code>, nothing else touched.</p> + <div class="cmd" data-copy="curl -fsSL https://slosh.foo/install.sh | PREFIX=$HOME/.local sh"> + <pre><code><span class="prompt">$</span> curl -fsSL https://slosh.foo/install.sh | PREFIX=$HOME/.local sh <span class="c"># no root</span></code></pre> + <button class="copy" type="button" aria-label="Copy command">copy</button> + </div> + <p class="aside">Piping a URL into a shell should make you flinch — + <a href="install.sh">read it first</a>, it is short: it picks the + prebuilt static binary for your architecture from + <a href="dist/">dist/</a>, checks it against the published SHA256SUMS, + and puts the one file in <code>PREFIX/bin</code>. The sudo in the first + line is only for writing to <code>/usr/local/bin</code>; the second line + needs no root at any step and lands it in <code>~/.local/bin</code>. + Nothing compiled, nothing else touched.</p> </div> <div class="os-panel" id="install-macos"> @@ -179,7 +205,9 @@ and we also provide some arch package repo's as well as a brew formula, check be <button class="copy" type="button" aria-label="Copy commands">copy</button> </div> <p class="aside">No Homebrew? The linux tab's installer works here too — - it only needs <a href="https://ziglang.org">zig</a> 0.16 and git.</p> + on Apple silicon it fetches the signed prebuilt binary from + <a href="dist/">dist/</a>, verifies it, and installs that. No Xcode, no + build.</p> </div> <div class="os-panel" id="install-arch"> @@ -199,13 +227,14 @@ Server = https://slosh.foo/arch/$arch <div class="os-panel" id="install-windows"> <div class="cmd"> - <pre><code><span class="prompt">$</span> make -f Makefile.windows <span class="c"># from a mac or linux box</span></code></pre> + <pre><code><span class="prompt">></span> curl.exe -LO https://slosh.foo/dist/slosh-<version>-windows-x86_64.zip +<span class="prompt">></span> tar xf slosh-*-windows-x86_64.zip <span class="c"># tar ships with Windows 10+</span></code></pre> </div> - <p class="aside">The same one binary: <code>slosh.exe</code>, Windows - 10/11, x86-64 and ARM64, no runtime dependency beyond the OS. Panes are + <p class="aside">Pick the newest zip from <a href="dist/">dist/</a> — + x86-64 and ARM64, Windows 10/11. Inside is the same one binary: + <code>slosh.exe</code>, no runtime dependency beyond the OS. Panes are ConPTYs, sessions are AF_UNIX sockets, everything on this page works - there. Cross-compiled, then copied across — - <a href="docs/windows.html">the details</a>.</p> + there — <a href="docs/windows.html">the details</a>.</p> </div> <div class="os-panel" id="install-source"> @@ -215,20 +244,15 @@ Server = https://slosh.foo/arch/$arch <span class="prompt">$</span> make <span class="c"># about a second</span> <span class="prompt">$</span> sudo install build/slosh /usr/local/bin/</code></pre> </div> - <p class="aside">Needs <a href="https://ziglang.org">zig</a> 0.16 and - nothing else. No cmake, no autotools, no libraries. The result is one + <p class="aside">For the curious — the tabs above hand you this same + binary prebuilt. Needs <a href="https://ziglang.org">zig</a> 0.16 and + nothing else: no cmake, no autotools, no libraries. The result is one static binary.</p> </div> </div> </section> </main> -<footer class="foot"> - <span>MIT</span> - <span>C on <a href="https://github.com/ghostty-org/ghostty">libghostty-vt</a></span> - <span>one static binary</span> -</footer> - <script src="recordings/player.js"></script> <script> // The scripts on the page: the copy buttons, the install preselect and the @@ -247,6 +271,15 @@ for (const box of document.querySelectorAll(".cmd[data-copy]")) { }); } +// The little logo in the corner: on while the big one is off screen. +const bigLogo = document.querySelector(".hero .logo"); +const littleLogo = document.querySelector(".logo-float"); +if (bigLogo && littleLogo && "IntersectionObserver" in window) { + new IntersectionObserver(([e]) => { + littleLogo.classList.toggle("show", !e.isIntersecting); + }).observe(bigLogo); +} + // The install box opens on the platform reading it; the tabs are CSS. const ua = navigator.userAgent; const os = /Windows/i.test(ua) ? "windows" : /Mac/i.test(ua) ? "macos" : "linux"; diff --git a/web/install.sh b/web/install.sh index ebf5a64..8e93e21 100755 --- a/web/install.sh +++ b/web/install.sh @@ -6,67 +6,125 @@ # brew tap sl0p/slosh https://git.sl0p.foo/homebrew-slosh.git # brew install slosh # +# and on Arch there is a signed pacman repo -- https://slosh.foo/arch/. +# # You are reading this before running it, which is correct. What it does: # -# 1. checks for zig 0.16 and git, -# 2. clones the source into a temporary directory, -# 3. `make vendor && make` -- the vendored terminal core, then one static -# binary, no other dependencies, -# 4. installs build/slosh into /usr/local/bin (the sudo is for this step +# 1. works out your OS and architecture, +# 2. downloads the prebuilt static binary for it from +# https://slosh.foo/dist/ (the newest release, or SLOSH_VERSION=), +# 3. checks it against the SHA256SUMS published next to it, +# 4. installs the one file into /usr/local/bin (the sudo is for this step # and nothing else). # -# Nothing is downloaded except the git clone and what `make vendor` fetches -# (the pinned libghostty-vt). No package manager, no config written, nothing -# started. Uninstall is `rm /usr/local/bin/slosh`. +# No root at all is also fine: pipe into `PREFIX=$HOME/.local sh` instead of +# `sudo sh` and the binary lands in ~/.local/bin, owned by you. +# +# Nothing is compiled, no package manager is touched, no config is written, +# nothing is started. Uninstall is `rm $PREFIX/bin/slosh`. +# +# Windows is not this script's job: slosh runs there natively as slosh.exe -- +# grab the zip from https://slosh.foo/dist/ and see docs/windows.md. # -# Windows is not this script's job: slosh runs there natively, but as a -# cross-compiled slosh.exe rather than a shell-script install -- see -# docs/windows.md in the repo. +# Prefer to build from source? It is three commands and one dependency +# (zig 0.16): clone https://slosh.foo/src, `make vendor`, `make`. set -eu -REPO="${SLOSH_REPO:-https://slosh.foo/src}" # TODO: pin to the public repo URL +BASE="${SLOSH_DIST:-https://slosh.foo/dist}" PREFIX="${PREFIX:-/usr/local}" -ZIG="${ZIG:-zig}" say() { printf ' %s\n' "$*"; } fail() { printf 'install.sh: %s\n' "$*" >&2; exit 1; } -case "$(uname -s 2>/dev/null || true)" in - *MINGW*|*MSYS*|*CYGWIN*) - fail "this builds the POSIX binary; Windows runs slosh.exe -- see docs/windows.md" ;; -esac - -command -v git >/dev/null 2>&1 || fail "git is required" - -# zig 0.16, the one thing the build wants. Also try the location the -# Makefile's own docs suggest. -if ! command -v "$ZIG" >/dev/null 2>&1; then - if [ -x "$HOME/zig-0.16.0/zig" ]; then - ZIG="$HOME/zig-0.16.0/zig" +fetch() { # fetch URL [outfile] -- curl where it exists, wget where it doesn't + if command -v curl >/dev/null 2>&1; then + if [ $# -gt 1 ]; then curl -fsSL -o "$2" "$1"; else curl -fsSL "$1"; fi + elif command -v wget >/dev/null 2>&1; then + if [ $# -gt 1 ]; then wget -qO "$2" "$1"; else wget -qO- "$1"; fi else - fail "zig 0.16 not found -- https://ziglang.org/download, or ZIG=/path/to/zig" + fail "neither curl nor wget found" fi -fi -case "$("$ZIG" version 2>/dev/null)" in - 0.16.*) ;; - *) fail "zig 0.16 is required, found $("$ZIG" version 2>/dev/null || echo nothing)" ;; +} + +sha256_of() { # portable: coreutils on linux, shasum on mac, openssl anywhere + if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1 + elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1 + elif command -v openssl >/dev/null 2>&1; then openssl dgst -sha256 "$1" | sed 's/.*= *//' + else fail "no sha256sum, shasum or openssl here -- cannot verify the download" + fi +} + +# The platform, spelled the way the release artifacts spell it. +os="$(uname -s 2>/dev/null || true)" +arch="$(uname -m 2>/dev/null || true)" +case "$os" in + Linux) + case "$arch" in + x86_64|amd64) plat=linux-x86_64; ext=tar.gz ;; + aarch64|arm64) plat=linux-aarch64; ext=tar.gz ;; + *) fail "no prebuilt binary for linux/$arch yet -- building from + source is short (zig 0.16, then make vendor && make): https://slosh.foo/src" ;; + esac ;; + Darwin) + case "$arch" in + arm64) plat=macos-arm64; ext=zip ;; + *) fail "no prebuilt binary for intel macs yet -- use Homebrew + (brew tap sl0p/slosh https://git.sl0p.foo/homebrew-slosh.git && brew install slosh)" ;; + esac ;; + *MINGW*|*MSYS*|*CYGWIN*) + fail "Windows runs slosh.exe -- download the zip from $BASE/ (see docs/windows.md)" ;; + *) + fail "unrecognized platform $os/$arch -- the binaries live at $BASE/" ;; esac tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT INT TERM -say "cloning $REPO" -git clone --quiet --depth 1 "$REPO" "$tmp/slosh" +# The version: whatever SHA256SUMS says is newest for this platform, unless +# the caller pinned one. SHA256SUMS is also the checksum check below, so one +# fetch serves twice. +say "fetching $BASE/SHA256SUMS" +fetch "$BASE/SHA256SUMS" "$tmp/SHA256SUMS" +if [ -n "${SLOSH_VERSION:-}" ]; then + ver="${SLOSH_VERSION#v}" +else + ver="$(sed -n "s/^.* slosh-\(.*\)-$plat\.$ext\$/\1/p" "$tmp/SHA256SUMS" \ + | sort -V | tail -1)" + [ -n "$ver" ] || fail "no $plat build listed in $BASE/SHA256SUMS" +fi + +stem="slosh-$ver-$plat" +asset="$stem.$ext" + +say "downloading $BASE/$asset" +fetch "$BASE/$asset" "$tmp/$asset" -say "building (make vendor, once; then make all)" -make -C "$tmp/slosh" ZIG="$ZIG" vendor -# `all`, spelled out: the default goal is the help text, so a bare `make` here -# would print it cheerfully and install whatever build/slosh happened to exist. -make -C "$tmp/slosh" ZIG="$ZIG" all +want="$(sed -n "s/^\([0-9a-f]\{64\}\) $asset\$/\1/p" "$tmp/SHA256SUMS" | tail -1)" +[ -n "$want" ] || fail "$asset is not in SHA256SUMS -- refusing to install it" +got="$(sha256_of "$tmp/$asset")" +[ "$got" = "$want" ] || fail "checksum mismatch for $asset + expected $want + got $got" +say "sha256 verified" + +case "$ext" in + tar.gz) tar -xzf "$tmp/$asset" -C "$tmp" ;; + zip) unzip -q "$tmp/$asset" -d "$tmp" ;; +esac +[ -f "$tmp/$stem/slosh" ] || fail "$asset did not contain $stem/slosh" say "installing to $PREFIX/bin/slosh" install -d "$PREFIX/bin" -install -m 755 "$tmp/slosh/build/slosh" "$PREFIX/bin/slosh" +install -m 755 "$tmp/$stem/slosh" "$PREFIX/bin/slosh" + +# The one way a non-root install goes quietly wrong: ~/.local/bin exists now +# but the shell does not look there. Say so instead of letting `slosh` print +# "command not found" a minute after "done". +case ":$PATH:" in + *":$PREFIX/bin:"*) ;; + *) say "note: $PREFIX/bin is not in your PATH -- add it, e.g.:" + say ' export PATH="'"$PREFIX/bin"':$PATH"' ;; +esac say "done. run: slosh" diff --git a/web/recordings/demos/config.py b/web/recordings/demos/config.py index b8509ab..760ca59 100644 --- a/web/recordings/demos/config.py +++ b/web/recordings/demos/config.py @@ -23,15 +23,15 @@ shutil.copyfile(THEME, cfg) r = Recorder(["/bin/sh"], cols=100, rows=28, title="make it yours", config=cfg, env=ENV) -# A neighbour with something on it, so geometry changes have a witness. -r.api("split", dir="cols") +# Something on the one pane, so geometry changes have a witness. No neighbour +# beyond that: the editor C-a e opens is the only split, and gets half the +# window to itself. r.capture(force=True) r.pause(0.6) r.run( "for i in 1 1 2 2 3 3 4 4 5 5 6 6; do" " printf '\\033[4%sm%-40s\\033[0m\\n' $i ' '; done" ) -r.api("focus", id=sorted(p["id"] for p in r.api("panes")["panes"])[0]) r.capture(dt=0.4) r.pause(0.8) diff --git a/web/recordings/demos/reflow.py b/web/recordings/demos/reflow.py index 5287650..d9afc2a 100644 --- a/web/recordings/demos/reflow.py +++ b/web/recordings/demos/reflow.py @@ -10,11 +10,22 @@ import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from castgen import Recorder, out_path +from castgen import ROOT, Recorder, out_path ENV = {"PS1": "$ ", "ENV": "/dev/null"} -r = Recorder(["/bin/sh"], cols=100, rows=28, title="layouts that reflow", env=ENV) +# Slate, not the house pink: each cast in the tour records under its own +# theme, so scrolling to the next step reads as a scene change. +THEME = os.path.join(ROOT, "contrib", "themes", "slate.kdl") + +r = Recorder( + ["/bin/sh"], + cols=100, + rows=28, + title="layouts that reflow", + config=THEME, + env=ENV, +) # Three named panes, built over the socket -- the demo is about the layout. r.api("split", dir="cols") diff --git a/web/recordings/demos/scripting.py b/web/recordings/demos/scripting.py index 65ee4f5..a3a2ac8 100644 --- a/web/recordings/demos/scripting.py +++ b/web/recordings/demos/scripting.py @@ -15,10 +15,14 @@ import sys import tempfile sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from castgen import Recorder, out_path +from castgen import ROOT, Recorder, out_path ENV = {"PS1": "$ ", "ENV": "/dev/null"} +# Amber, not the house pink: each cast in the tour records under its own +# theme, so scrolling to the next step reads as a scene change. +THEME = os.path.join(ROOT, "contrib", "themes", "amber.kdl") + work = tempfile.mkdtemp(prefix="slosh-demo-") # The left pane's shell: reads a line, answers like the socket does. The @@ -63,7 +67,13 @@ with open(lay, "w") as f: ) r = Recorder( - ["/bin/sh"], cols=100, rows=28, title="built to be driven", env=ENV, layout=lay + ["/bin/sh"], + cols=100, + rows=28, + title="built to be driven", + config=THEME, + env=ENV, + layout=lay, ) r.capture(force=True, settle_ms=150) diff --git a/web/recordings/demos/shaders.py b/web/recordings/demos/shaders.py index 889b0de..f7ce3ac 100644 --- a/web/recordings/demos/shaders.py +++ b/web/recordings/demos/shaders.py @@ -16,10 +16,15 @@ import sys import tempfile sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from castgen import ROOT, THEME, Recorder, out_path +from castgen import ROOT, Recorder, out_path ENV = {"PS1": "$ ", "ENV": "/dev/null"} +# Mono, not the house pink: this demo is about colour passes, so the base +# theme is the one without colour -- every hue on screen is a shader's. It +# also gives this cast its own look in the tour's theme rotation. +THEME = os.path.join(ROOT, "contrib", "themes", "mono.kdl") + work = tempfile.mkdtemp(prefix="slosh-demo-") cfg = os.path.join(work, "config.kdl") with open(cfg, "w") as f: diff --git a/web/site.css b/web/site.css index aba3bcd..70d7d7c 100644 --- a/web/site.css +++ b/web/site.css @@ -13,6 +13,10 @@ --faint: #45454a; --pink: #ff5fd7; --dead: #ff875f; + /* The feature tour's geometry, up here because the floating logo (a fixed + * element, outside the tour) centres itself on the tour's stage column. */ + --tour-w: min(94vw, 88rem); + --tour-gap: clamp(1.5rem, 4vw, 4.5rem); --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace; --sans: system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; @@ -45,28 +49,41 @@ kbd { font-size: 0.85em; } -/* ---- the nav -------------------------------------------------------- */ +/* ---- the floating logo ---------------------------------------------- */ +/* The hero logo again, small, in the corner the stage's v-centering leaves + * empty on desktop. Faded in by the observer in index.html once the big one + * is off screen; a link back to the top. Hidden on one-column screens, + * where that corner is content, not air. */ -.nav { - position: sticky; - top: 0; - z-index: 3; - display: flex; - gap: 1.5em; - overflow-x: auto; - padding: 0 1.25rem; - border-bottom: 1px solid var(--panel); - background: var(--bg); +.logo-float { + position: fixed; + top: 13.8rem; + /* Centred on the stage column: the tour is layout-centred and the stage + * is the 3fr of its 3fr/2fr split, so the terminal's midline sits at + * 50% - tourW/2 + (tourW - gap) * 3/10. 50%, not 50vw: a fixed element's + * percentages exclude the scrollbar, like the layout the tour centres in; + * vw would drag the logo half a scrollbar to the right. The translateX + * does the logo's own half. */ + left: calc(50% - var(--tour-w) / 2 + (var(--tour-w) - var(--tour-gap)) * 0.3); + z-index: 4; + color: var(--pink); + opacity: 0; + transform: translateX(-50%) translateY(-0.4rem); + transition: opacity 0.25s, transform 0.25s; + pointer-events: none; +} +.logo-float.show { opacity: 1; transform: translateX(-50%); pointer-events: auto; } +.logo-float:hover { color: var(--fg); } +.logo-float pre { + margin: 0; font-family: var(--mono); - font-size: 13px; - line-height: 2.6; - white-space: nowrap; + font-size: 12px; + line-height: 1em; } -.nav a { color: var(--dim); } -.nav a:hover { color: var(--pink); text-decoration: none; } -.nav a[aria-current] { color: var(--fg); } -.nav-fill { flex: 1; } +@media (max-width: 54rem) { + .logo-float { display: none; } +} /* ---- the hero ------------------------------------------------------- */ @@ -81,6 +98,11 @@ main { text-align:center !important; } +.hero .logo { + color: var(--pink); + line-height: 1em; +} + .hero h1 { margin: 0; color: var(--pink); @@ -235,13 +257,33 @@ section > p:last-child { margin-bottom: 0; } * recordings are 100 columns and want the room. */ .scrolly { - --tour-w: min(94vw, 88rem); width: var(--tour-w); margin-left: calc((100% - var(--tour-w)) / 2); display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); - gap: clamp(1.5rem, 4vw, 4.5rem); + gap: var(--tour-gap); + /* Tuck the tour up under the hero. The stage's 100vh box centres the + * terminal, so before it pins, everything above the terminal is air — + * about 45vh minus half the player (≤ ~500px tall at this column width), + * minus the optical lift. Overlap the hero by that much, less ~2rem of + * breathing room; min() keeps it at 0 on viewports short enough that the + * air runs out. Pinned geometry is scroll-invariant, so alignment inside + * the tour is untouched. */ + margin-top: min(0rem, 17.5rem - 45vh); + /* ...and the same at the exit, where the air below the terminal is larger + * still (the optical lift rides it high — ~54.5vh minus half the player). + * This collapses with the next section's 3.5rem margin-top, which the + * constant accounts for; the result is ~2.75rem from the terminal's final + * resting bottom to the install heading at any viewport height. */ + margin-bottom: min(0rem, 14.5rem - 54.5vh); + /* The overlapped regions are transparent air, but they would still sit on + * top of the hero's buttons above and the install tabs below — let clicks + * fall through, and switch hit-testing back on for the things inside that + * want it. */ + pointer-events: none; } +.stage-pin [data-sloshcast], +.scrolly-steps .step { pointer-events: auto; } .stage-pin { position: sticky; @@ -251,11 +293,25 @@ section > p:last-child { margin-bottom: 0; } flex-direction: column; justify-content: center; align-items: center; + /* Sit a touch above true centre: the steps on the right centre their text + * on the viewport, and against them a dead-centred terminal reads as low + * (the tab strip weights its top). border-box, so this lifts the centred + * content rather than growing the 100vh box. */ + padding-bottom: clamp(2.5rem, 9vh, 6rem); } .stage-pin [data-sloshcast] { display: none; } .stage-pin .stage-active { display: block; } +/* Breathing room at both ends of the steps column. Without it the column is + * exactly steps*50vh tall and the sticky stage has no travel margin: the + * terminal is still riding below centre when the first step reaches the + * middle of the viewport, and has already been dragged up past centre by the + * container's bottom edge when the last one does. 25vh each side means the + * stage is pinned (centred) from before the first step centres until after + * the last step does. */ +.scrolly-steps { padding: 25vh 0; } + .step { min-height: 50vh; display: flex; @@ -300,10 +356,10 @@ section > p:last-child { margin-bottom: 0; } * beneath it. The sticky moves up to .scrolly-stage here: in block layout * .stage-pin's parent is only as tall as the player, so a sticky inside it * has nowhere to stick; .scrolly-stage is bounded by the whole tour. */ - .scrolly { display: block; } + .scrolly { display: block; margin-top: 0; margin-bottom: 0; pointer-events: auto; } .scrolly-stage { position: sticky; - top: 2.2rem; /* below the nav */ + top: 0; z-index: 2; padding: 0.6rem 0; background: var(--bg); @@ -313,6 +369,9 @@ section > p:last-child { margin-bottom: 0; } height: auto; padding: 0; } + /* One column: the stage sticks above the steps, so the travel margin is + * pointless air here. */ + .scrolly-steps { padding: 0; } .step { min-height: 50vh; } .step:first-child { padding-top: 1.5rem; } } @@ -353,22 +412,6 @@ section > p:last-child { margin-bottom: 0; } .doclist a { font-family: var(--mono); font-size: 14px; } .doclist span { color: var(--faint); } -/* ---- the footer ----------------------------------------------------- */ - -.foot { - display: flex; - flex-wrap: wrap; - gap: 0 1.5rem; - padding: 0.4rem 1.25rem; - border-top: 1px solid var(--panel); - color: var(--faint); - font-family: var(--mono); - font-size: 12.5px; - line-height: 2; -} - -.foot a { color: var(--dim); } - /* ---- small screens -------------------------------------------------- */ @media (max-width: 44rem) { |
