Something went wrong. Try again.
Browser extension: detect and subscribe to standard.site publications on ATProto
Something went wrong. Try again.
12 kB · 527 lines
CSS
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528/* substandard brand theme: paper, ink, and a red pen that disagrees. Everything sits a degree or two off level on purpose — tilts are static (they are the design, not motion), only the hover corrections animate. */
:root { --bg: #f4f3ee; --card: #fdfcf9; --fg: #26282b; --muted: #6d6a62; --line: #dedcd3; --red: #d9482b; --gold: #e8b52a; --gold-hl: rgba(232, 181, 42, 0.35); --shadow: #dedcd3;}
@media (prefers-color-scheme: dark) { :root { --bg: #1c1d20; --card: #26272b; --fg: #e9e7e0; --muted: #96938a; --line: #3a3b40; --red: #e2593a; --gold: #d9a826; --gold-hl: rgba(217, 168, 38, 0.28); --shadow: #131417; }}
* { box-sizing: border-box;}
body { margin: 0; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; line-height: 1.6; background: var(--bg); color: var(--fg);}
::selection { background: var(--gold-hl);}
a { color: var(--fg); text-decoration: underline; text-decoration-style: wavy; text-decoration-color: var(--red); text-decoration-thickness: 1.5px; text-underline-offset: 3px;}
.hero { max-width: 44rem; margin: 0 auto; padding: 4rem 1.5rem 3rem; text-align: center;}
/* The lockup follows the og card: Subby on the left, wordmark to his right. Subby arrives pre-tilted, same 2° as his sticker frame; hovering straightens him out, and he leans right back when you let go. */.hero-mark { display: flex; align-items: center; justify-content: center; gap: 1.25rem;}
.hero-icon { width: 5.5rem; height: 5.5rem; transform: rotate(2deg); transition: transform 0.25s ease;}
.hero-icon:hover { transform: rotate(0deg);}
/* The wordmark is inlined so the theme can retake its baked-in colors: ink follows the foreground, the squiggle keeps the red pen. */.hero-wordmark { flex: 0 1 17rem; min-width: 0;}
.hero-wordmark svg { display: block; width: 100%; height: auto;}
.hero-wordmark text { fill: var(--fg);}
.hero-wordmark path { stroke: var(--red);}
.hero h1 { margin: 1.25rem 0 0.75rem; font-size: 3rem; line-height: 1.15; letter-spacing: -0.01em; transform: rotate(-1deg); text-decoration: underline; text-decoration-style: wavy; text-decoration-color: var(--red); text-decoration-thickness: 3px; text-underline-offset: 10px;}
/* The signup button is a gold sticker somebody slapped on almost straight. Its drop shadow is a solid misprint offset, not a blur. */.blurb { display: block; max-width: 36rem; margin: 1.75rem auto 0; padding: 1.1rem 1.5rem; border: 3px solid var(--fg); border-radius: 0.9rem; background: var(--gold); color: #26282b; text-decoration: none; font-size: 1.15rem; font-weight: 650; transform: rotate(-0.8deg); box-shadow: 4px 5px 0 var(--shadow); transition: transform 0.15s ease, box-shadow 0.15s ease;}
.blurb:hover { transform: rotate(-0.8deg) translate(2px, 3px); box-shadow: 1px 1px 0 var(--shadow);}
main { max-width: 44rem; margin: 0 auto; padding: 0 1.5rem 3rem;}
/* Cards were laid out by eye: each one tilts its own way, and none of the shadows agree on where the light is. */main section { background: var(--card); border: 2px solid var(--line); border-radius: 0.75rem; padding: 1.5rem; margin-bottom: 1.75rem;}
main section:nth-of-type(odd) { transform: rotate(-0.6deg); box-shadow: 5px 4px 0 var(--shadow);}
main section:nth-of-type(even) { transform: rotate(0.45deg); box-shadow: -4px 5px 0 var(--shadow);}
/* Headings get a slightly overshooting marker highlight. */main h2 { display: inline-block; margin: 0 0 0.5rem; font-size: 1.5rem; line-height: 1.3; padding: 0 0.35rem; background: linear-gradient( 100deg, transparent 0.5%, var(--gold-hl) 3%, var(--gold-hl) 98%, transparent 99.5% ); transform: rotate(-0.4deg);}
main p { margin: 0.5rem 0 0; color: var(--muted);}
main ul { margin: 0.5rem 0 0; padding-left: 1.5rem; color: var(--muted);}
main li::marker { color: var(--red);}
/* The screenshot gallery: the popup captures the store listing is composed from (scripts/shots.mjs), taped to the page by somebody in a hurry. Each frame leans the other way from the one before it and none of the shadows agree; hovering one straightens it out. The frames live here rather than in the images so they follow the theme and stay sharp at any width. *//* Wrapping flex rather than a grid: with an odd number of shots a grid leaves a hole in the last row, and a centered short row looks handmade where a hole just looks broken. The cap keeps a lone last shot the same size as the pair above it instead of stretching across the card. */.shots { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 1.75rem 1.5rem; margin: 1.25rem 0 0.25rem; padding: 0;}
.shot { flex: 1 1 15rem; max-width: 20rem; margin: 0;}
.shot img { display: block; width: 100%; height: auto; border: 2px solid var(--fg); border-radius: 0.4rem; background: var(--card); box-shadow: 5px 5px 0 var(--shadow); transform: rotate(-1.1deg); transition: transform 0.25s ease;}
.shot:nth-child(3n + 2) img { box-shadow: -4px 6px 0 var(--shadow); transform: rotate(0.9deg);}
.shot:nth-child(3n) img { box-shadow: 6px 4px 0 var(--shadow); transform: rotate(1.5deg);}
/* Last, so it beats the per-position tilts at equal specificity. */.shot img:hover { transform: rotate(0deg);}
.shot-caption { margin: 0.9rem 0 0; font-size: 0.85rem; transform: rotate(-0.3deg);}
/* Updates: the homepage preview list, the /posts backlog, and the posts themselves. Posts reuse the tilted section cards; these are trimmings. */
.hero-sub { margin: 0.75rem 0 0; color: var(--muted);}
/* A post page has no hero above it, so the first card needs its own air. */.post-page { padding-top: 3rem;}
/* The homepage's updates feed is a little changelog note. In the narrow flow it sits at the bottom of the column; once the viewport has room it is pinned off to the side instead — a sticky note beside the page proper, dashed border and a harder lean to set it apart from the real cards. */.changelog { background: var(--card); border: 2px dashed var(--line); border-radius: 0.75rem; padding: 1rem 1.25rem; margin-bottom: 1.75rem; font-size: 0.9rem; transform: rotate(0.9deg); box-shadow: 4px 4px 0 var(--shadow);}
.changelog h2 { font-size: 1.05rem;}
/* 84rem, not the 80rem the raw geometry suggests: the note leans and casts a shadow past its own box, and the scrollbar eats into the viewport — pinning it any earlier puts a horizontal scrollbar on the whole page. */@media (min-width: 84rem) { main { position: relative; }
.changelog { position: absolute; top: 0; left: calc(100% + 2rem); width: 16rem; margin-bottom: 0; transform: rotate(1.2deg); }}
.update-list { list-style: none; margin: 0.5rem 0 0.75rem; padding-left: 0;}
.update-list li { margin: 0.6rem 0 0;}
/* Date above title, changelog style. */.update-list .post-meta { display: block;}
.post-card h2 { display: block; background: none; transform: none;}
.post-card h2 a { padding: 0 0.35rem; background: linear-gradient( 100deg, transparent 0.5%, var(--gold-hl) 3%, var(--gold-hl) 98%, transparent 99.5% );}
.post-meta { color: var(--muted); font-size: 0.9rem;}
.post-meta > * + * { margin-left: 0.6rem;}
.post-tag,.post-draft { padding: 0 0.35rem; border: 1px solid var(--line); border-radius: 0.4rem;}
.post-draft { color: var(--red); border-color: var(--red);}
.post-back { color: var(--muted);}
/* The architecture diagram (/architecture). Mermaid's own stylesheet is stripped at render time — `style-src 'self'` covers inline SVG, so a <style> inside the figure would be dropped in production and the diagram would render as black boxes on black lines. Everything it would have said is restated here instead, which is also how the picture picks up the theme's tokens rather than baking one palette into the file.
The geometry was measured at 16px system-ui, so that size is pinned rather than inherited: a different one would spill the labels out of their boxes. Below the diagram's natural width the figure scrolls instead of scaling, because a 900px picture squeezed into a phone is unreadable long before it stops fitting. *//* /architecture is the one page whose content is a picture and two reference tables rather than paragraphs. At the 44rem the prose pages use, the diagram needs a scrollbar on every desktop and the tables crush their columns to one character; the column is widened for that page alone. */main.wide { max-width: 62rem;}
.diagram { margin: 1.25rem 0 0; overflow-x: auto;}
.diagram svg { display: block; width: 100%; min-width: 40rem; height: auto; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; font-size: 16px;}
.diagram text { fill: var(--fg);}
/* Mermaid lays a node's label out from the node's centre and leaves the centring to its stylesheet, so without this the labels run out of the right-hand side of their boxes. Cluster labels are pre-offset and stay left-anchored. */.diagram .node .label text { text-anchor: middle;}
/* Boxes inside the browser are solid cards; the services outside it are dashed and unfilled, so the trust boundary reads without a legend. */.diagram .node rect { fill: var(--card); stroke: var(--fg); stroke-width: 1.5px; rx: 6; ry: 6;}
.diagram .node.outsideNode rect { fill: var(--bg); stroke: var(--muted); stroke-dasharray: 5 4;}
.diagram .cluster rect { fill: none; stroke: var(--line); stroke-width: 2px; rx: 10; ry: 10;}
.diagram .cluster-label text { fill: var(--muted);}
.diagram .flowchart-link { fill: none; stroke: var(--muted); stroke-width: 1.5px;}
.diagram .arrowMarkerPath { fill: var(--muted); stroke: none;}
/* The label's backing plate knocks the edge out from under the text. */.diagram .edgeLabel .background { fill: var(--bg);}
.diagram .edgeLabel text { fill: var(--muted);}
/* Reference tables: what talks to what, and what is kept where. Narrow screens scroll the table rather than crushing the columns. */.table-scroll { overflow-x: auto; margin: 1rem 0 0;}
.table-scroll table { border-collapse: collapse; width: 100%; min-width: 40rem; font-size: 0.9rem;}
.table-scroll th,.table-scroll td { border-bottom: 1px solid var(--line); padding: 0.45rem 0.6rem; text-align: left; vertical-align: top; color: var(--muted);}
.table-scroll th { color: var(--fg); font-weight: 650;}
/* Identifiers carry the weight on /architecture: NSIDs, hostnames, paths. */main code { font-size: 0.9em; overflow-wrap: anywhere;}
/* The footer rule is the mark's own squiggle: four honest humps, then the tail gives out. Masked so it takes the theme's red. */footer { max-width: 44rem; margin: 0 auto; padding: 2.5rem 1.5rem 2rem; color: var(--muted); font-size: 0.9rem; text-align: center;}
footer p { margin: 0.35rem 0 0;}
footer::before { content: ""; display: block; width: 108px; height: 34px; margin: 0 auto 1.25rem; background-color: var(--red); mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 108 34"><path d="M4,16 q8,-12 16,0 t16,0 t16,0 t16,0 q8,-8 16,4 q6,8 8,14" fill="none" stroke="black" stroke-width="6" stroke-linecap="round"/></svg>') center / contain no-repeat;}
@media (prefers-reduced-motion: reduce) { .hero-icon, .blurb, .shot img { transition: none; }}