/* The landing page: flat Sticknife chrome framing the pantheon. Everything is scoped to body.landing so the rest of the app keeps styles.css as it was. The identity is the logo's construction — content banded between hard rules, sitting on a baseline — plus one discipline: gold belongs to the art and to status, never to the chrome. That is what lets thirteen gilt seals be the only rich thing on the page. */ body.landing { --ink: #0c0b0a; --wall: #141210; --rule: #2b2622; --rule-2: #3a342d; --cream: #f2ece1; --muted: #8e8579; --dim: #5f584f; --gold: #b5976e; --hot: #e1812b; --chrome: "Oswald", "Archivo Narrow", "Barlow Condensed", "Roboto Condensed", "Helvetica Neue Condensed", "Arial Narrow", system-ui, sans-serif; --plaque: "Cinzel", "Trajan Pro", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif; --data: ui-monospace, "SF Mono", Menlo, Consolas, monospace; --gutter: clamp(16px, 3vw, 28px); --col: 1180px; /* roughly the width of the Sign in button: how far right of the content column the fixed nav sits, so the sign-up card passes underneath it rather than through it */ --nav-clear: 104px; background: var(--ink); color: var(--cream); font-family: var(--chrome); font-stretch: 85%; overflow-x: hidden; } /* a faint warm cast from above, so the black isn't flat vinyl */ body.landing::before { content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none; background: radial-gradient(120% 70% at 50% -10%, rgba(181, 151, 110, .07), transparent 60%); } body.landing .page { position: relative; z-index: 1; display: block; } body.landing .landing-shell { width: 100%; margin: 0; padding: 0; border: 0; background: none; box-shadow: none; } .sn-page { width: min(var(--col), 100%); margin: 0 auto; padding: 0 var(--gutter); } /* The auth nav lives in the shared topbar. It used to line up with the content column's right edge, which is exactly where the sign-up card is, so scrolling dragged the card straight under it. Sitting it a button's width further right puts it in the margin instead — and on viewports too narrow to have a margin to spare, the floor keeps it on the page. */ body.landing .topbar { top: 34px; right: max(10px, calc(50vw - var(--col) / 2 + var(--gutter) - var(--nav-clear))); gap: 8px; } body.landing .nav-button { min-height: 36px; border: 2px solid var(--cream); border-radius: 0; background: transparent; color: var(--cream); font-family: var(--chrome); font-size: .78rem; font-stretch: 85%; font-weight: 600; letter-spacing: .11em; text-transform: uppercase; transition: background .16s, color .16s; } body.landing .nav-button:hover { background: var(--cream); color: var(--ink); } body.landing .navlinks form { margin: 0; } /* ---------------------------------------------------------------- brand and structure */ .sn-head { padding: 30px 0 22px; } .sn-brand { display: inline-block; } .sn-brand img { display: block; width: clamp(150px, 17vw, 200px); height: auto; } .sn-baseline { height: 3px; background: var(--cream); } .sn-hair { height: 1px; background: var(--rule); } /* ------------------------------------------------------------------------------- gate */ .sn-gate { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(320px, .7fr); gap: clamp(28px, 5vw, 60px); align-items: start; padding: clamp(38px, 6vw, 62px) 0 clamp(34px, 5vw, 52px); } .sn-eyebrow { margin: 0 0 18px; color: var(--muted); font-size: .72rem; font-weight: 600; letter-spacing: .3em; text-transform: uppercase; } body.landing .sn-gate-copy h1 { margin: 0 0 20px; color: var(--cream); font-family: var(--chrome); font-size: clamp(2.3rem, 5.4vw, 4.2rem); font-weight: 600; line-height: .94; letter-spacing: .012em; text-transform: uppercase; text-wrap: balance; } body.landing .sn-lede { max-width: 46ch; margin: 0; color: var(--muted); font-family: var(--plaque); font-size: clamp(1rem, 1.5vw, 1.12rem); line-height: 1.6; } .sn-lede em { color: var(--cream); font-style: normal; } .sn-gate-card { padding: clamp(20px, 2.4vw, 28px); border: 1px solid var(--rule-2); background: var(--wall); } body.landing .sn-gate-card h2 { margin: 0 0 18px; color: var(--muted); font-family: var(--chrome); font-size: .74rem; font-weight: 600; letter-spacing: .26em; text-transform: uppercase; } body.landing .sn-gate-card label { display: grid; gap: 7px; color: var(--muted); font-family: var(--chrome); font-size: .72rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; } body.landing .sn-gate-card .stack { display: grid; gap: 14px; } body.landing .sn-gate-card input { width: 100%; height: 42px; padding: 0 12px; border: 1px solid var(--rule-2); border-radius: 0; background: #0a0908; color: var(--cream); font-family: var(--data); font-size: .92rem; letter-spacing: 0; text-transform: none; } body.landing .sn-gate-card input:focus-visible { border-color: var(--gold); } body.landing .sn-gate-card button { width: 100%; min-height: 42px; margin-top: 4px; border: 2px solid var(--cream); border-radius: 0; background: var(--cream); color: var(--ink); font-family: var(--chrome); font-size: .8rem; font-weight: 600; font-stretch: 85%; letter-spacing: .11em; text-transform: uppercase; cursor: pointer; transition: background .16s; } body.landing .sn-gate-card button:hover { background: #fff; } body.landing .sn-fineprint { margin: 16px 0 0; color: var(--dim); font-family: var(--data); font-size: .74rem; line-height: 1.55; } .sn-fineprint b { color: var(--muted); font-weight: 400; } /* the global link colour belongs to the other pages' palette; at this size the underline is doing most of the work anyway */ body.landing .sn-fineprint a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--rule-2); } body.landing .sn-fineprint a:hover { color: var(--gold); text-decoration-color: var(--gold); } body.landing ul.sn-fineprint { display: grid; gap: 9px; padding: 0; list-style: none; /* separated by space alone — no marker, no indent */ } body.landing .sn-gate-card .notice { margin-bottom: 16px; border-radius: 0; font-family: var(--plaque); font-size: .88rem; } /* ------------------------------------------------------------------------ section band */ .sn-band { display: flex; align-items: baseline; justify-content: center; gap: 20px; padding: 28px 0 2px; } .sn-band-label { color: var(--gold); font-family: var(--plaque); font-size: .96rem; letter-spacing: .34em; text-indent: .34em; /* offset the trailing letter-space so it centres optically */ text-transform: lowercase; } /* ----------------------------------------------------------------------------- the field */ .sn-field { position: relative; width: 100vw; margin-left: calc(50% - 50vw); /* Taller than the ring needs. geometry() spends the surplus on margin rather than on a bigger ring, which is what keeps the tenants pushed outside the ring — Nanshe at the top of it especially — from running off the top edge. */ height: clamp(900px, 105vh, 1140px); overflow: hidden; } .sn-graph { position: absolute; inset: 0; width: 100%; height: 100%; } /* houses are invisible until you go looking for one */ .sn-links g { opacity: 0; transition: opacity .3s ease; } .sn-links g.on { opacity: 1; } .sn-links line { stroke: var(--gold); stroke-width: 1; } /* The cluster keeps its edges drawn rather than surfacing them on hover — it is small enough to read at a glance, and the lines are what make it hang off the one at the top. Faint, though: they are there to be inferred, not read. */ .sn-side-graph .sn-links line { stroke-opacity: .18; transition: stroke-opacity .3s ease; } .sn-side-graph .sn-links.on line { stroke-opacity: .5; } .sn-node { cursor: pointer; } .sn-node image { transition: transform .3s ease; transform-box: fill-box; transform-origin: center; } .sn-node .sn-halo { opacity: 0; transition: opacity .3s ease; } .sn-node.lit .sn-halo, .sn-node.sel .sn-halo { opacity: 1; } .sn-node.lit image, .sn-node.sel image { transform: scale(1.07); } .sn-niche-ring { fill: #100e0c; stroke: var(--rule-2); stroke-width: 1; } .sn-monogram { fill: var(--rule-2); font-family: var(--plaque); font-size: 1.5rem; letter-spacing: .08em; text-anchor: middle; } .sn-label { fill: var(--muted); font-family: var(--plaque); font-size: .68rem; letter-spacing: .17em; text-anchor: middle; text-transform: uppercase; opacity: .5; transition: opacity .25s, fill .25s; } .sn-node.lit .sn-label, .sn-node.sel .sn-label { fill: var(--cream); opacity: 1; } .sn-node[data-state="planned"] .sn-label, .sn-node[data-state="machine"] .sn-label { opacity: .34; } .sn-graph.busy .sn-node:not(.lit):not(.sel) { opacity: .26; } .sn-node { transition: opacity .3s ease; } /* House names are authored lowercase — that is the control string. Every place one is shown title-cases it in CSS, so the data stays plain and the page stays capitalised. */ .sn-house-tag { fill: var(--gold); font-family: var(--plaque); font-size: .68rem; letter-spacing: .22em; text-anchor: middle; text-transform: capitalize; opacity: 0; transition: opacity .3s ease; } .sn-house-tag.on { opacity: 1; } .sn-node:focus { outline: none; } .sn-node:focus-visible .sn-focus-ring { stroke: var(--hot); stroke-width: 2; } .sn-focus-ring { fill: none; stroke: none; } /* ------------------------------------------------------------------- the side drawers */ /* A rail of tabs pinned to the right edge, and one parked panel per tab behind it. The tabs live on the rail rather than on the panels so that opening one never buries another's handle underneath it. */ .sn-drawers { position: absolute; inset: 0; z-index: 6; pointer-events: none; /* the field underneath stays reachable */ --rail-w: 36px; /* keep in step with RAIL in pantheon.js */ } .sn-drawers[hidden] { display: none; } .sn-rail { position: absolute; z-index: 2; top: 0; bottom: 0; right: 0; width: var(--rail-w); display: flex; flex-direction: column; gap: 10px; padding-top: 72px; border-left: 1px solid var(--rule-2); background: rgba(11, 10, 9, .95); pointer-events: auto; } .sn-side-tab { flex: none; padding: 20px 0; border: 0; background: transparent; color: var(--muted); cursor: pointer; font-family: var(--plaque); font-size: .7rem; letter-spacing: .22em; text-transform: capitalize; transition: color .2s; } .sn-side-tab span { display: block; writing-mode: vertical-rl; white-space: nowrap; } .sn-side-tab:hover { color: var(--cream); } .sn-side-tab.on { color: var(--gold); } .sn-side-tab:focus-visible { outline: 1px solid var(--hot); outline-offset: -3px; } .sn-side-body { position: absolute; z-index: 1; top: 0; bottom: 0; right: var(--rail-w); width: clamp(260px, 24vw, 360px); border-left: 1px solid var(--rule-2); background: rgba(11, 10, 9, .97); transform: translateX(calc(100% + var(--rail-w))); pointer-events: none; transition: transform .42s cubic-bezier(.22, .61, .36, 1); } .sn-side-body.open { transform: none; pointer-events: auto; } .sn-side-graph { display: block; width: 100%; height: 100%; } .sn-hint { position: absolute; z-index: 2; bottom: 14px; left: 50%; margin: 0; color: var(--dim); font-family: var(--data); font-size: .7rem; transform: translateX(-50%); transition: opacity .3s; } .sn-hint.away { opacity: 0; } /* ------------------------------------------------------------- no-script / no-d3 listing */ /* The listing ships hidden and is only revealed when the graph cannot run — either by the noscript rule in the page or by pantheon.js giving up. This [hidden] rule has to be here: the display below would otherwise outrank the browser's own [hidden] { display: none }. */ .sn-fallback[hidden] { display: none; } /* The stacked view: one block per family, each member a card that opens in place. It is the no-JavaScript fallback and the whole layout on a narrow screen, where a ring of thirty-two seals is unreadable and a list of families is not. */ .sn-fallback { position: relative; z-index: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 30px 40px; width: min(var(--col), 100%); margin: 0 auto; padding: 34px var(--gutter); } body.landing .sn-fallback h2 { margin: 0 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--rule); color: var(--gold); font-family: var(--plaque); font-size: .8rem; letter-spacing: .2em; text-transform: capitalize; } .sn-fallback ul { margin: 0; padding: 0; list-style: none; } .sn-fallback li { margin: 0 0 10px; } .sn-card { border: 1px solid var(--rule); background: rgba(20, 18, 16, .5); } .sn-card[open] { border-color: var(--rule-2); background: var(--wall); } .sn-card summary { display: flex; gap: 14px; align-items: center; padding: 12px; cursor: pointer; list-style: none; } .sn-card summary::-webkit-details-marker { display: none; } .sn-card summary::marker { content: ""; } .sn-card summary:focus-visible { outline: 1px solid var(--hot); outline-offset: -2px; } .sn-card-face { flex: none; display: grid; place-items: center; width: 58px; height: 58px; } .sn-card-face img { display: block; width: 100%; height: auto; } .sn-card-face .sn-empty { display: grid; place-items: center; width: 46px; height: 46px; border: 1px solid var(--rule-2); border-radius: 50%; color: var(--dim); font-family: var(--plaque); font-size: 1rem; } .sn-card-head { display: grid; gap: 2px; min-width: 0; } .sn-fallback b { color: var(--cream); font-family: var(--plaque); font-size: .84rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; } .sn-card-domain { color: var(--gold); font-family: var(--data); font-size: .66rem; letter-spacing: .12em; text-transform: lowercase; } .sn-card-does { color: var(--muted); font-family: var(--plaque); font-size: .82rem; line-height: 1.45; } .sn-card-body { padding: 0 12px 14px; border-top: 1px solid var(--rule); } .sn-card-body p { margin: 12px 0 0; color: var(--muted); font-family: var(--plaque); font-size: .88rem; line-height: 1.6; } .sn-card-body .sn-spec { margin: 14px 0 16px; } .sn-card[data-state="machine"] .sn-card-body .sn-actions { display: none; } .sn-fallback a { color: var(--gold); font-family: var(--data); font-size: .78rem; } .sn-fallback span { color: var(--dim); font-family: var(--data); font-size: .78rem; } /* --------------------------------------------------------------------------- the drawer */ /* The detail panel rides in from the left edge of the field; the graph re-centres into the space that is left, which the simulation animates on its own. */ .sn-drawer { position: absolute; z-index: 7; top: 0; bottom: 0; left: 0; width: clamp(320px, 33vw, 452px); overflow-y: auto; border-right: 1px solid var(--rule-2); background: rgba(11, 10, 9, .97); transform: translateX(-101%); pointer-events: none; transition: transform .42s cubic-bezier(.22, .61, .36, 1); } .sn-drawer.open { transform: none; pointer-events: auto; } .sn-drawer-in { display: block; padding: clamp(22px, 2.4vw, 34px); } .sn-drawer-art { width: min(200px, 54%); margin-bottom: clamp(18px, 2vw, 26px); } .sn-drawer-art img { display: block; width: 100%; height: auto; } .sn-drawer-art .sn-empty { display: grid; place-items: center; aspect-ratio: 1; border: 1px solid var(--rule-2); border-radius: 50%; background: radial-gradient(circle at 50% 36%, #171512, #0e0c0b 72%); color: var(--rule-2); font-family: var(--plaque); font-size: 3rem; } .sn-drawer-body { position: relative; } body.landing .sn-drawer-body h3 { margin: 0 44px 6px 0; /* clear of the close button */ color: var(--cream); font-family: var(--plaque); font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 600; letter-spacing: .13em; text-transform: uppercase; } .sn-drawer-domain { margin: 0 0 20px; color: var(--gold); font-size: .78rem; font-weight: 600; letter-spacing: .22em; text-transform: uppercase; } body.landing .sn-long { max-width: 58ch; margin: 0 0 22px; color: var(--muted); font-family: var(--plaque); font-size: 1rem; line-height: 1.65; } .sn-spec { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 9px 18px; margin: 0 0 24px; padding: 18px 0 0; border-top: 1px solid var(--rule); font-family: var(--data); font-size: .78rem; } .sn-spec dt { color: var(--dim); } .sn-spec dd { margin: 0; color: var(--cream); } .sn-spec .sn-house-name { text-transform: capitalize; } .sn-actions { display: flex; flex-wrap: wrap; gap: 10px; } .sn-btn { display: inline-flex; align-items: center; justify-content: center; min-height: 38px; padding: 0 16px; border: 2px solid var(--cream); background: transparent; color: var(--cream); font-family: var(--chrome); font-size: .78rem; font-weight: 600; font-stretch: 85%; letter-spacing: .11em; text-transform: uppercase; text-decoration: none; cursor: pointer; transition: background .16s, color .16s; } .sn-btn:hover { background: var(--cream); color: var(--ink); } .sn-btn-quiet { border-color: var(--rule-2); color: var(--muted); } .sn-btn-quiet:hover { border-color: var(--cream); background: transparent; color: var(--cream); } .sn-close { position: absolute; top: 0; right: 0; z-index: 2; display: grid; place-items: center; width: 34px; height: 34px; border: 1px solid var(--rule-2); background: transparent; color: var(--muted); font-size: 1.1rem; line-height: 1; cursor: pointer; } .sn-close:hover { border-color: var(--cream); color: var(--cream); } /* ------------------------------------------------------------------------------- footer */ .sn-maker { display: flex; align-items: flex-end; justify-content: space-between; gap: 28px; min-height: 128px; } .sn-maker img { display: block; width: 60px; height: auto; opacity: .16; } body.landing .sn-thesis { padding-bottom: 22px; color: var(--muted); font-family: var(--plaque); font-size: 1rem; letter-spacing: .04em; } .sn-colophon { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 14px; padding: 14px 0 44px; color: var(--dim); font-family: var(--data); font-size: .72rem; } /* -------------------------------------------------------------------------- responsive */ @media (max-width: 900px) { .sn-gate { grid-template-columns: minmax(0, 1fr); } } /* no room to slide the graph aside: the panel simply covers it */ @media (max-width: 700px) { .sn-drawer { width: 100%; border-right: 0; } } /* Below this the ring stops being readable: thirty-two seals want more width than a phone has, and shrinking them to fit turns the whole thing into gravel. So the field gives way to the stacked families, which need no script and no physics — the [hidden] attribute is overridden here rather than removed, so this works with JavaScript switched off. */ @media (max-width: 820px) { .sn-field { height: auto; overflow: visible; } .sn-graph, .sn-hint, .sn-drawers, .sn-drawer { display: none; } .sn-fallback[hidden] { display: grid; } .sn-fallback { padding-top: 8px; } /* Reading order down the column, set by STACK_ORDER in pantheon.py. Scoped to this query on purpose: the custom property is inert everywhere else, so the desktop listing keeps the order the markup is in and the ring is untouched. */ .sn-family { order: var(--stack, 0); } } @media (max-width: 560px) { body.landing .topbar { top: auto; right: var(--gutter); bottom: max(16px, env(safe-area-inset-bottom)); } /* the field is already stacked by here — nothing left to size */ .sn-fallback { grid-template-columns: minmax(0, 1fr); gap: 26px; } } @media (prefers-reduced-motion: reduce) { body.landing *, body.landing *::before, body.landing *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; } }