open-design/apps/landing-page/app/globals.css
Jane 3f4fd58937
Some checks failed
ci / Detect CI change scopes (push) Successful in 0s
visual-baseline / Capture visual baselines (push) Waiting to run
landing-page-ci / Validate landing page (push) Failing after 2s
landing-page-staging / Deploy landing page to staging (push) Has been skipped
nix-check / build (push) Failing after 2s
ci / Validate Nix flake (push) Has been skipped
ci / Preflight (push) Failing after 2s
ci / Workspace unit tests (push) Failing after 2s
ci / Daemon workspace tests (push) Failing after 1s
ci / Web workspace tests (push) Failing after 1s
ci / Browser tests (push) Failing after 1s
ci / Build workspaces (push) Failing after 2s
ci / Validate workspace (push) Failing after 0s
ci / Runtime trace (push) Has been skipped
feat(landing-page): surface Discord + X in header, restructure site footer (#3230)
* feat(landing-page): surface Discord + X in header, restructure site footer

Two related public-chrome adjustments:

- **Header gains compact Discord + X icon buttons.** Both community
  channels were previously buried in the footer, so the typical
  visitor never saw them on a page-deep scroll. They now sit before
  the Download / Star CTAs in `nav-side`, share the ghost-button
  outline language, and stay icon-only with `aria-label` so they
  read as social affordances rather than competing with the text
  CTAs. At ≤1080px the icon buttons hide alongside the existing
  ghost CTA, so the bar still collapses cleanly into the hamburger
  panel — Star stays in the bar at every breakpoint.

- **Footer restructured into 4 columns: Products / Plugins /
  Resources / Connect.** The old `Plugins / Open Design / Connect`
  three-column layout muddled three different things — sister
  products, the artifact catalogue, and contributor channels —
  under one roof, so visitors hunting for "the other thing this
  team makes" had nowhere obvious to go.
  - **Products** (new) lists the team's apps: Open Design (links
    to homepage) and HTML Anything. Two entries by design — adding
    more products without an editorial pass would dilute the
    column.
  - **Plugins** mirrors the topbar `Plugins` dropdown verbatim:
    Templates / Skills / Systems / Craft, with no count prefix on
    Systems / Craft so it reads identically to the nav.
  - **Resources** (renamed from `Open Design`) carries the
    docs-style links: Official source / Quickstart / Agents locaux
    / Compare / Claude Design alternative. The old column heading
    was confusing because the OD logo + brand name already sit
    under the column.
  - **Connect** gains an X / Twitter row pointing at
    `@nexudotio`. The brand entries on this column are
    contributor / community surfaces only — code, releases,
    chat, social, RSS, contact form.

Implementation:

- `_components/header.tsx` — `DISCORD` and `X_TWITTER` consts at
  the top alongside `REPO`. Two `<a class="nav-icon">` blocks with
  inline SVG before the existing Download / Star CTAs.
- `_components/site-footer.astro` — `HTML_ANYTHING` and `NEXU_IO`
  consts. `<div class="sub-footer-col">` re-ordered to put
  Products first, Plugins second (no longer carries `counts.*`
  values), Resources third, Connect fourth (with the new X / Twitter
  row).
- `globals.css` — `.nav-icon` rule cloned from the ghost CTA's
  visual language (transparent + 1px line, fills on hover) but
  square (36×36 round) so it reads as a social-icon affordance.
  Added `display: none` for `.nav-side .nav-icon` to the existing
  ≤1080px and ≤880px media queries so the icons follow the same
  collapse behaviour as the Download CTA.
- `sub-pages.css` — `.sub-footer-grid` switches from
  `1.6fr 1fr 1fr 1fr` to `1.4fr 1fr 1fr 1fr 1fr` (brand + 4
  columns). At ≤1080px it falls back to a 3-column shape so each
  column has room to breathe; at ≤720px it stays a single column
  (existing behaviour).
- `i18n.ts` — adds `products`, `resources`, `xTwitter`,
  `sisterProjects`, `htmlAnything`, `nexuIo` to `LandingUiCopy.footer`
  (the last three are kept around even though `sisterProjects` is no
  longer rendered after the column was renamed Products — they're
  harmless and avoid churning the type if a future iteration brings
  the Sister-projects framing back). All 17 non-English landing
  locales gain translations for the new keys via the existing
  `LOCALIZED_LANDING_FOOTER_COPY` map (and the `LANDING_UI_COPY_OVERRIDES`
  block for `zh` / `zh-tw`). Translations were generated with
  `claude-haiku-4-5` over OpenRouter, with explicit instructions
  to keep "Open Design", "HTML Anything", and "X / Twitter" in
  English and to render "Products" / "Resources" in sentence case
  per locale convention. Spot-checked against rendered pages on
  `/zh/`, `/zh-tw/`, `/ja/`, `/ko/`, `/de/`, `/fr/` (and `/ar/` for
  RTL) for natural phrasing.

Validation: `pnpm --filter @open-design/landing-page typecheck` ->
0 errors / 0 warnings; local dev server smoke-tested on en root
(`/html-anything/`) and 5 locale variants (`/zh/`, `/zh-tw/`,
`/ja/`, `/de/`, `/fr/`) — header renders 2 nav-icon buttons,
footer renders 4 localized column headings in the correct order
with the right link targets.

* fix(landing-page): address PR #3230 review — locale-aware HTML Anything link + drop unused const

Two non-blocking inline review points from @PerishCode on PR #3230:

- The HTML Anything entry in the new Products column hardcoded
  `https://open-design.ai/html-anything/` via a top-level
  `HTML_ANYTHING` const, but `/html-anything/` is a real localized
  route in this app (`pages/[locale]/html-anything/index.astro`)
  and `open-design.ai` is the same site's live domain. A visitor
  on `/zh/…` clicking through landed on the English route and lost
  locale context, and hardcoding the production domain meant a
  preview build would surface a link that bounces visitors back
  to prod. Switch to `href('/html-anything/')` so the locale prefix
  + the current site's domain (resolved by `localizedHref`) are
  honored, matching every other footer link.

- `NEXU_IO` was declared at the top of the component but never
  referenced — leftover from an earlier iteration that listed
  `nexu.io` as a Sister-projects entry before the column was
  renamed Products and reduced to OD + HTML Anything. Removed.

No behavior change beyond the locale routing fix; the i18n keys
and column structure stay as they landed in the original commit.

* fix(landing-page): correct nav-icon comment to match actual responsive behaviour

The JSX comment introduced for the new Discord + X icon buttons in
PR #3230 claimed the icons "survive at narrow widths while text-only
nav items get pushed off". The CSS that shipped in the same PR does
the opposite: both `@media (max-width: 1080px)` and `@media (max-width:
880px)` blocks add `.nav-side .nav-icon { display: none; }`, so at
narrow widths the icons collapse alongside the ghost Download CTA
while the text nav <ul> moves into the hamburger panel — only the
Star CTA remains visible in the bar.

Rewrite the comment to describe the actual responsive contract so
the next reader of `header.tsx` doesn't have to cross-reference
`globals.css` to figure out which surface stays. Reviewer flag from
@PerishCode on PR #3230.

No code-path change; comment-only.

* fix(landing-page): correct sub-footer 1080px comment to describe actual 3-column grid

The CSS comment introduced for the new sub-footer grid claimed the
≤1080px breakpoint drops to "brand + 2x2 grid of columns" — but the
rule produces a 3-column grid, not a 2x2.

`.sub-footer-grid` has 5 children at this breakpoint (the brand
block + the four footer columns) and `.sub-footer-brand` carries
no `grid-column` span, so with `grid-template-columns: 1.6fr
repeat(2, 1fr)` they flow as: row 1 = brand · Products · Plugins,
row 2 = Resources · Connect · empty cell. The brand sits inline
with two columns rather than on its own, and the four content
columns are not a clean 2x2.

The layout itself is fine; only the comment misleads the next
reader about how the columns wrap. Same flavor as the `header.tsx`
icon comment fixed in 744daec — describe what the rule actually
does so the comment doesn't drift from the CSS. Reviewer flag
from @PerishCode on PR #3230.

Comment-only change.

---------

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
2026-05-29 05:59:24 +00:00

3484 lines
88 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Atelier Zero — landing page styles.
*
* Mirrors `design-templates/open-design-landing/example.html` <style> block 1:1.
* When the canonical example.html changes, mirror the diff here so the
* template's known-good rendering stays in lockstep with the deployed site.
*
* Fonts are self-hosted via `@fontsource-variable/*` packages. The variable
* font files (one woff2 per family, ~30-50KB each) cover the entire
* weight axis we use, are served same-origin (no Google Fonts CSS or
* fonts.gstatic.com TLS handshake), and ship through CF's edge — PageSpeed
* was attributing ~2.3s of render-blocking + LCP to the old Google Fonts
* round-trip chain.
*
* Subset CSS files only declare @font-face metadata (~1KB each). The
* browser downloads the woff2 that matches the unicode-range of text it's
* about to render, so multi-script support stays intact without paying for
* unused scripts up front.
*/
@import '@fontsource-variable/inter';
@import '@fontsource-variable/inter-tight';
@import '@fontsource-variable/playfair-display';
@import '@fontsource-variable/playfair-display/wght-italic.css';
@import '@fontsource-variable/jetbrains-mono';
:root {
--paper: #efe7d2;
--paper-warm: #ece4cf;
--paper-dark: #ddd2b6;
--ink: #15140f;
--ink-soft: #2a2620;
--ink-mute: #5a5448;
--ink-faint: #8b8676;
--coral: #ed6f5c;
--coral-soft: #f08e7c;
--mustard: #e9b94a;
--olive: #6e7448;
--bone: #f7f1de;
--line: rgba(21, 20, 15, 0.16);
--line-soft: rgba(21, 20, 15, 0.08);
--line-faint: rgba(21, 20, 15, 0.05);
--shadow: 0 30px 60px -30px rgba(21, 20, 15, 0.18);
--serif: 'Playfair Display Variable', 'Playfair Display', 'Times New Roman', serif;
--sans: 'Inter Tight Variable', 'Inter Tight', 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
--body: 'Inter Variable', 'Inter', -apple-system, system-ui, sans-serif;
--mono: 'JetBrains Mono Variable', 'JetBrains Mono', 'SF Mono', Menlo, monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
background: var(--paper);
color: var(--ink);
/*
* Lock the page width to the viewport so any decorative element
* positioned with negative offsets (ribbons, hero-art margin-right,
* mega footer word, etc.) cannot create a horizontal scrollbar on
* narrow viewports.
*
* Use `overflow-x: clip` (modern) instead of `hidden`: clip does not
* establish a containing block for `position: fixed/sticky`, so the
* sticky nav keeps working. Browsers that don't support clip fall
* back to the hidden declaration just above it.
*/
overflow-x: hidden;
overflow-x: clip;
max-width: 100%;
}
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
font-family: var(--body);
font-size: 16px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
position: relative;
overflow-wrap: break-word;
word-wrap: break-word;
}
img, video, canvas { max-width: 100%; height: auto; }
/*
* Paper texture overlay across the whole page.
*
* Rendered ABOVE `.shell` (z-index 2) so the noise/grain multiply blend
* applies uniformly to every section — including `.topbar` and `.nav`,
* which have an opaque `background: var(--paper)` to keep sticky-scroll
* content readable. Without this, opaque sections would show clean paper
* and transparent sections (hero, about, …) would show textured paper,
* which reads as two slightly different colors at the seam.
*
* Z-index is set equal to the side-rails (also z-index 3); because the
* pseudo-element appears in document order before the rails, the rails
* paint on top of the texture and keep their crisp rotated lettering.
*/
body::before {
content: '';
position: fixed;
inset: 0;
pointer-events: none;
z-index: 3;
background-image:
radial-gradient(circle at 12% 18%, rgba(106, 92, 56, 0.07) 0, transparent 28%),
radial-gradient(circle at 88% 72%, rgba(106, 92, 56, 0.06) 0, transparent 32%),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.18 0 0 0 0 0.16 0 0 0 0 0.12 0 0 0 0.06 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
background-size: auto, auto, 240px 240px;
mix-blend-mode: multiply;
opacity: 0.92;
}
.shell { position: relative; z-index: 2; }
.container {
max-width: 1360px;
padding: 0 64px;
margin: 0 auto;
position: relative;
}
.container.wide { max-width: 1480px; }
/* fixed side rails — rotated brand text on the right edge */
.side-rail {
position: fixed;
top: 0;
bottom: 0;
width: 36px;
z-index: 3;
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
}
.side-rail.right { right: 0; border-left: 1px solid var(--line-faint); }
.side-rail.left { left: 0; border-right: 1px solid var(--line-faint); }
.side-rail .rail-text {
font-family: var(--sans);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.42em;
text-transform: uppercase;
color: var(--ink-faint);
writing-mode: vertical-rl;
transform: rotate(180deg);
white-space: nowrap;
}
.side-rail.right .rail-text { transform: rotate(180deg); }
.side-rail.left .rail-text { writing-mode: vertical-rl; transform: none; }
/*
* Sticky chrome bar — wraps the editorial metadata strip + main nav as a
* single Headroom-style unit. Keeping them welded means the language
* switcher stays reachable while reading the page (you can flip locales
* mid-scroll without scrolling back to the top), and the masthead +
* navigation always read as a single nameplate rather than two unrelated
* rows.
*
* Sticky/transform/transition lived on `.nav` historically — they belong
* here now so both rows slide together. The `data-chrome-headroom` hook
* is what `header-enhancer.astro` (and the homepage inline script)
* toggle `is-hidden` on.
*/
.site-chrome {
position: sticky;
top: 0;
z-index: 50;
background: var(--paper);
transform: translateY(0);
transition: transform 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
box-shadow 220ms ease,
border-color 220ms ease;
will-change: transform;
}
.site-chrome.is-hidden {
transform: translateY(-100%);
pointer-events: none;
box-shadow: none;
}
/* top metadata strip */
.topbar {
border-bottom: 1px solid var(--line);
padding: 10px 0;
background: var(--paper);
/*
* Stays a positioned context so the locale menu has an absolute
* anchor. The z-index is small but non-zero so the topbar — and the
* menu that drops out of it — paint above the sibling nav inside
* `.site-chrome`. Without this the menu would be obscured by the
* nav's download/star buttons.
*/
position: relative;
z-index: 2;
}
.topbar-inner {
display: flex;
justify-content: space-between;
align-items: center;
gap: 24px;
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
}
.topbar-inner b { color: var(--ink); font-weight: 600; }
.topbar-inner .coral { color: var(--coral); }
.topbar-inner > span { white-space: nowrap; }
.topbar-inner .mid { display: inline-flex; gap: 26px; }
.topbar-inner .mid > span { white-space: nowrap; }
.topbar-inner .right { display: inline-flex; gap: 18px; align-items: center; }
.topbar-inner .right > span,
.topbar-inner .right > a { white-space: nowrap; }
.topbar-link {
color: inherit;
text-decoration: none;
border-bottom: 1px solid transparent;
transition: color 160ms ease, border-color 160ms ease;
}
.topbar-link:hover { color: var(--coral); border-bottom-color: var(--coral); }
/*
* Editorial language switcher. The trigger reads as part of the
* masthead line ("● LIVE · V0.7.0 / LANG · ZH-TW") — uppercase
* tracked text, no pill, no border. The dropdown is a small
* floating panel that mirrors the topbar's paper/ink palette but
* drops the tracking so native scripts (中文 / 한국어 / العربية)
* read at their intended rhythm.
*/
.locale-switch {
display: inline-block;
position: relative;
}
.locale-trigger {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
color: inherit;
list-style: none;
border-bottom: 1px solid transparent;
transition: color 160ms ease, border-color 160ms ease;
user-select: none;
outline: none;
padding: 0;
}
.locale-trigger::-webkit-details-marker { display: none; }
.locale-trigger:hover,
.locale-switch[open] > .locale-trigger,
.locale-trigger:focus-visible {
color: var(--coral);
border-bottom-color: var(--coral);
}
.locale-trigger-prefix {
color: var(--ink-faint);
}
.locale-trigger:hover .locale-trigger-prefix,
.locale-switch[open] > .locale-trigger .locale-trigger-prefix,
.locale-trigger:focus-visible .locale-trigger-prefix {
color: var(--coral);
}
.locale-trigger-sep {
opacity: 0.55;
}
.locale-trigger-code {
font: inherit;
letter-spacing: inherit;
color: var(--ink);
font-weight: 600;
}
.locale-trigger:hover .locale-trigger-code,
.locale-switch[open] > .locale-trigger .locale-trigger-code,
.locale-trigger:focus-visible .locale-trigger-code {
color: var(--coral);
}
.locale-trigger-caret {
width: 8px;
height: 5px;
flex-shrink: 0;
opacity: 0.7;
transition: transform 160ms ease, opacity 160ms ease;
}
.locale-switch[open] > .locale-trigger .locale-trigger-caret {
transform: rotate(180deg);
opacity: 1;
}
/*
* Two-column editorial catalogue. 17 locales × single-column would either
* scroll (ugly) or run most of the hero's height (worse). A 2-col grid
* keeps the panel under 9 rows so every language is visible at once and
* reads like a small index of nameplates rather than a dropdown.
*
* The 20px top offset gives clear breathing room from the topbar baseline
* — without it the active row (which mirrors the trigger label) feels
* fused to the chrome above it.
*/
.locale-menu {
position: absolute;
top: calc(100% + 20px);
right: 0;
z-index: 60;
display: grid;
grid-template-columns: repeat(2, minmax(168px, 1fr));
gap: 2px 4px;
padding: 10px;
background: var(--paper);
border: 1px solid rgba(21, 20, 15, 0.22);
box-shadow:
0 1px 0 rgba(21, 20, 15, 0.04),
0 28px 60px -32px rgba(21, 20, 15, 0.42);
font-family: var(--sans);
letter-spacing: normal;
text-transform: none;
/* Subtle entrance — matches the rest of the site's 200ms ease-out */
animation: locale-menu-in 180ms cubic-bezier(0.23, 1, 0.32, 1);
}
@keyframes locale-menu-in {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.locale-menu-item {
display: flex;
align-items: baseline;
gap: 12px;
padding: 8px 12px;
color: var(--ink);
text-decoration: none;
font-size: 12.5px;
line-height: 1.2;
transition: background 140ms ease, color 140ms ease;
}
.locale-menu-item:hover {
background: color-mix(in oklab, var(--paper), var(--ink) 6%);
color: var(--coral);
}
.locale-menu-item:hover .locale-menu-code { color: var(--coral); }
.locale-menu-item.is-active {
background: color-mix(in oklab, var(--paper), var(--coral) 8%);
color: var(--coral);
}
.locale-menu-item.is-active .locale-menu-code {
color: var(--coral);
}
.locale-menu-code {
flex-shrink: 0;
min-width: 46px;
font-size: 9.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
transition: color 140ms ease;
}
.locale-menu-label {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (max-width: 520px) {
.locale-menu {
grid-template-columns: minmax(0, 1fr);
min-width: min(260px, calc(100vw - 32px));
}
.locale-menu-item { padding: 9px 12px; }
}
@media (prefers-reduced-motion: reduce) {
.locale-menu { animation: none; }
.locale-trigger-caret { transition: none; }
}
.topbar .pulse {
width: 6px; height: 6px;
border-radius: 50%;
background: var(--coral);
display: inline-block;
margin-right: 6px;
animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.35; }
}
/* nav */
/*
* The sticky + headroom behavior lives on the outer `.site-chrome`
* wrapper now (so the topbar + nav slide as one unit). This rule keeps
* only the spacing and surface treatment.
*/
.nav {
padding: 22px 0;
background: var(--paper);
border-bottom: 1px solid transparent;
}
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--sans);
font-weight: 700;
letter-spacing: -0.01em;
color: var(--ink);
text-decoration: none;
font-size: 18px;
}
.brand-mark {
/*
* Bumped from 36px → 44px (≈22% larger). The new black brand mark
* needs the extra optical weight against the wordmark, especially
* given the speech-bubble negative space visually shrinks the glyph.
* (PR #2588's brand polish, restored on top of #2469.)
*/
width: 44px; height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
}
.brand-name {
white-space: nowrap;
}
.brand-mark img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
/* Round the corners of the brand glyph (~22% of side, app-icon
* silhouette convention) so the solid-fill square reads as a
* brand mark next to the wordmark rather than a screenshot. */
border-radius: 10px;
}
.brand-meta {
font-family: var(--sans);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
line-height: 1.3;
margin-left: 4px;
border-left: 1px solid var(--line);
padding-left: 14px;
}
.brand-meta b { display: block; color: var(--ink); font-weight: 600; }
.nav-links {
display: flex;
gap: 38px;
list-style: none;
}
.nav-links a {
color: var(--ink);
text-decoration: none;
font-family: var(--sans);
font-size: 14px;
font-weight: 500;
transition: color 0.18s ease;
position: relative;
}
.nav-links a:hover { color: var(--coral); }
.nav-links a .num {
font-size: 9px;
color: var(--ink-faint);
position: absolute;
top: -7px;
right: -16px;
letter-spacing: 0.04em;
}
/*
* Product dropdown — CSS-only, no JS. The submenu is hidden by default and
* revealed on `:hover` of the parent `li.has-dropdown`, or on `:focus-within`
* for keyboard navigation. This keeps the static export self-contained.
*/
.nav-links li.has-dropdown {
position: relative;
}
.nav-links .dropdown-caret {
display: inline-block;
margin-left: 4px;
font-size: 10px;
color: var(--ink-faint);
transition: transform 0.18s ease;
}
.nav-links li.has-dropdown:hover .dropdown-caret,
.nav-links li.has-dropdown:focus-within .dropdown-caret {
transform: translateY(1px);
color: var(--coral);
}
.nav-dropdown {
position: absolute;
top: 100%;
left: -16px;
margin: 0;
padding: 10px;
list-style: none;
min-width: 320px;
background: var(--paper);
border: 1px solid rgba(26, 26, 26, 0.12);
border-radius: 8px;
box-shadow: 0 12px 36px rgba(26, 26, 26, 0.08);
opacity: 0;
visibility: hidden;
transform: translateY(-4px);
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
z-index: 50;
}
.nav-links li.has-dropdown:hover .nav-dropdown,
.nav-links li.has-dropdown:focus-within .nav-dropdown {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
/* invisible bridge so cursor can travel from trigger to menu without
* crossing a gap that closes the menu mid-traverse */
.nav-dropdown::before {
content: '';
position: absolute;
top: -10px;
left: 0;
right: 0;
height: 10px;
}
.nav-dropdown a {
display: block;
padding: 10px 12px;
border-radius: 6px;
color: var(--ink);
text-decoration: none;
transition: background 0.12s ease;
}
.nav-dropdown a:hover {
background: rgba(255, 122, 89, 0.08);
color: var(--ink);
}
.nav-dropdown a.is-active {
background: rgba(26, 26, 26, 0.04);
}
.nav-dropdown .dropdown-name {
display: block;
font-family: var(--sans);
font-size: 14px;
font-weight: 600;
margin-bottom: 2px;
}
.nav-dropdown .dropdown-blurb {
display: block;
font-size: 12px;
color: var(--ink-faint);
line-height: 1.4;
}
/*
* Hamburger toggle. Hidden at desktop widths (≥1080px). At narrower
* viewports it replaces the inline nav-links and toggles a panel
* underneath the header bar via a small handler in `header-enhancer`.
*/
.nav-toggle {
display: none;
align-items: center;
justify-content: center;
width: 38px;
height: 38px;
margin-left: auto;
padding: 0;
background: transparent;
border: 1px solid rgba(26, 26, 26, 0.18);
border-radius: 8px;
cursor: pointer;
color: var(--ink);
transition: background 0.18s ease, border-color 0.18s ease;
}
.nav-toggle:hover {
background: rgba(26, 26, 26, 0.04);
border-color: rgba(26, 26, 26, 0.32);
}
.nav-toggle-icon,
.nav-toggle-icon::before,
.nav-toggle-icon::after {
display: block;
width: 18px;
height: 2px;
background: currentColor;
border-radius: 2px;
transition: transform 0.18s ease, opacity 0.18s ease;
}
.nav-toggle-icon {
position: relative;
}
.nav-toggle-icon::before,
.nav-toggle-icon::after {
content: '';
position: absolute;
left: 0;
}
.nav-toggle-icon::before { top: -6px; }
.nav-toggle-icon::after { top: 6px; }
/* When open, morph into an "X" */
.nav.is-open .nav-toggle-icon { background: transparent; }
.nav.is-open .nav-toggle-icon::before { top: 0; transform: rotate(45deg); }
.nav.is-open .nav-toggle-icon::after { top: 0; transform: rotate(-45deg); }
.nav-side {
display: inline-flex;
align-items: center;
gap: 18px;
}
/*
* Compact icon-only chrome buttons for community-channel links
* (Discord, X) sitting beside the Download / Star CTAs. They share
* the ghost-button outline language but stay square so they read as
* social affordances and don't compete with the text CTAs.
*/
.nav-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
border: 1px solid rgba(21, 20, 15, 0.18);
color: var(--ink);
background: transparent;
text-decoration: none;
transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
flex-shrink: 0;
}
.nav-icon:hover {
background: var(--ink);
border-color: var(--ink);
color: var(--paper);
}
.nav-icon svg {
display: block;
}
.nav-cta {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 9px 16px;
border-radius: 999px;
background: var(--ink);
color: var(--paper);
font-family: var(--sans);
font-size: 13px;
font-weight: 500;
text-decoration: none;
white-space: nowrap;
flex-shrink: 0;
}
.nav-cta [data-github-stars],
.nav-cta [data-github-version] {
font-variant-numeric: tabular-nums;
}
.nav-cta::after {
content: '★';
color: var(--mustard);
font-size: 11px;
}
.nav-cta.ghost {
background: transparent;
color: var(--ink);
border: 1px solid rgba(21, 20, 15, 0.18);
transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.nav-cta.ghost:hover {
background: rgba(21, 20, 15, 0.04);
border-color: rgba(21, 20, 15, 0.36);
}
.nav-cta.ghost::after {
content: '↓';
color: var(--ink);
font-size: 12px;
}
.status-dot {
width: 28px; height: 28px;
border-radius: 50%;
border: 1px solid var(--line);
display: inline-flex;
align-items: center;
justify-content: center;
}
.status-dot::after {
content: '';
width: 6px; height: 6px;
border-radius: 50%;
background: var(--coral);
}
/* ---------- typography primitives ---------- */
.label {
font-family: var(--sans);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--coral);
display: inline-flex;
align-items: center;
gap: 12px;
}
.label::before {
content: '';
width: 18px;
height: 1px;
background: var(--coral);
display: inline-block;
}
.label .ix {
color: var(--ink-faint);
font-weight: 500;
margin-left: 4px;
}
.display {
font-family: var(--sans);
font-weight: 800;
letter-spacing: -0.028em;
color: var(--ink);
line-height: 1.0;
}
.display em {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
letter-spacing: -0.018em;
}
.display .dot { color: var(--coral); }
.lead {
font-family: var(--body);
font-size: 16px;
line-height: 1.55;
color: var(--ink-soft);
max-width: 36ch;
}
.meta {
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
}
.coord {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.04em;
color: var(--ink-faint);
}
.roman {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
color: var(--coral);
}
/* buttons */
.btn {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 22px;
border-radius: 999px;
font-family: var(--sans);
font-size: 14px;
font-weight: 500;
letter-spacing: -0.005em;
text-decoration: none;
border: 1px solid transparent;
transition: transform 0.18s ease, background 0.18s ease, color 0.18s ease;
cursor: pointer;
white-space: nowrap;
}
.btn-primary {
background: var(--coral);
color: #fff;
box-shadow: 0 14px 26px -16px rgba(237, 111, 92, 1);
}
.btn-primary:hover { transform: translateY(-1px); background: #e25e4a; }
.btn-ghost {
background: transparent;
color: var(--ink);
border-color: rgba(21, 20, 15, 0.2);
}
.btn-ghost:hover { background: rgba(21, 20, 15, 0.04); }
.btn .arrow {
width: 16px; height: 16px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.btn .arrow svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.6; }
/* helper used inline in headlines */
.code-inline {
font-family: var(--mono);
font-size: 14px;
background: var(--bone);
padding: 1px 6px;
border-radius: 4px;
}
/* ---------- HERO ---------- */
.hero {
position: relative;
padding: 0;
min-height: calc(100vh - 140px);
display: flex;
flex-direction: column;
align-items: stretch;
border-bottom: 1px solid var(--line);
}
.hero > .container { flex: 0 0 auto; }
.hero > .container.hero-grid { flex: 1 1 auto; }
.hero::before {
content: '';
position: absolute;
left: 50%;
top: 0;
bottom: 0;
width: 1px;
background: var(--line-soft);
z-index: 0;
display: none;
}
.hero-grid {
display: grid;
grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
gap: 36px;
align-items: stretch;
width: 100%;
position: relative;
}
.hero-copy {
padding: 4vh 0 4vh;
display: flex;
flex-direction: column;
position: relative;
}
.hero-discord-pill {
align-self: flex-start;
display: inline-flex;
align-items: center;
gap: 7px;
margin-bottom: 22px;
padding: 7px 13px;
border: 1px solid rgba(237, 111, 92, 0.28);
border-radius: 999px;
background: rgba(237, 111, 92, 0.12);
color: var(--coral);
font-family: var(--sans);
font-size: 12px;
font-weight: 600;
letter-spacing: -0.005em;
line-height: 1;
text-decoration: none;
box-shadow: 0 12px 24px -22px rgba(237, 111, 92, 0.8);
transition: transform 160ms ease, background 160ms ease, border-color 160ms ease;
}
.hero-discord-pill:hover {
transform: translateY(-1px);
border-color: rgba(237, 111, 92, 0.46);
background: rgba(237, 111, 92, 0.18);
}
.hero-discord-pill span {
font-size: 8px;
line-height: 1;
}
.hero-copy .label { margin-bottom: 28px; }
.hero-copy .lead { margin-bottom: 30px; max-width: 38ch; font-size: 16px; }
.hero h1 {
font-size: clamp(44px, 5vw, 78px);
line-height: 1.0;
margin-bottom: 28px;
}
.hero-actions {
display: inline-flex;
align-items: center;
gap: 14px;
margin-bottom: 38px;
}
.hero-stats {
display: flex;
align-items: center;
gap: 22px;
flex-wrap: nowrap;
margin-bottom: 28px;
}
.hero-stats .stat { display: inline-flex; align-items: center; gap: 9px; white-space: nowrap; }
.hero-stats .stat .ring {
width: 34px; height: 34px;
border-radius: 50%;
border: 1px dashed var(--ink);
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--sans);
font-size: 11px;
font-weight: 700;
flex-shrink: 0;
}
.hero-stats .stat .ring.solid { border-style: solid; }
.hero-stats .stat .ring.coral { border-color: var(--coral); color: var(--coral); }
.hero-stats .stat-label {
font-family: var(--sans);
font-size: 11px;
line-height: 1.25;
color: var(--ink-soft);
letter-spacing: 0.04em;
text-transform: uppercase;
}
.hero-stats .stat-label b { display: block; font-weight: 700; color: var(--ink); font-size: 12px; }
.hero-foot {
margin-top: auto;
padding-top: 22px;
border-top: 1px solid var(--line);
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
}
.hero-foot .meta { line-height: 1.4; }
.hero-art {
position: relative;
height: calc(100vh - 160px);
max-height: 860px;
margin-left: auto;
margin-right: -12px;
width: 100%;
overflow: visible;
}
.hero-art img {
width: 100%; height: 100%;
object-fit: contain;
object-position: right center;
display: block;
}
/* image annotations */
.annot {
position: absolute;
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
line-height: 1.4;
white-space: nowrap;
}
.annot.has-line::before {
content: '';
position: absolute;
background: var(--ink-faint);
}
.annot-tl { top: 14px; left: 14px; }
.annot-tr { top: 14px; right: 14px; text-align: right; }
.annot-bl { bottom: 14px; left: 14px; }
.annot-br { bottom: 14px; right: 14px; text-align: right; }
.annot.coord { font-family: var(--mono); font-size: 10px; letter-spacing: 0.04em; text-transform: none; }
.hero-art .index {
position: absolute;
right: 12px;
top: 36%;
font-family: var(--sans);
font-size: 10.5px;
font-weight: 600;
letter-spacing: 0.16em;
color: var(--ink-faint);
text-transform: uppercase;
background: rgba(239, 231, 210, 0.7);
padding: 10px 12px;
border: 1px solid var(--line-soft);
border-radius: 6px;
backdrop-filter: blur(2px);
}
.hero-art .index span { display: block; line-height: 1.6; }
.hero-art .index span .n { color: var(--coral); margin-right: 6px; font-weight: 700; }
.hero-art .index span.on { color: var(--ink); font-weight: 700; }
.hero-art .index span.on .n { color: var(--coral); }
.hero-art .corner {
position: absolute;
width: 22px; height: 22px;
border-color: var(--ink-faint);
border-style: solid;
border-width: 0;
}
.hero-art .corner.tl { top: 0; left: 0; border-top-width: 1px; border-left-width: 1px; }
.hero-art .corner.tr { top: 0; right: 0; border-top-width: 1px; border-right-width: 1px; }
.hero-art .corner.bl { bottom: 0; left: 0; border-bottom-width: 1px; border-left-width: 1px; }
.hero-art .corner.br { bottom: 0; right: 0; border-bottom-width: 1px; border-right-width: 1px; }
/* ---------- common section header ---------- */
section { position: relative; padding: 130px 0; }
section.tight { padding: 90px 0; }
.sec-rule {
border-top: 1px solid var(--line);
padding-top: 18px;
margin-bottom: 48px;
display: flex;
justify-content: space-between;
align-items: center;
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
}
.sec-rule .roman {
font-family: var(--serif);
font-style: italic;
color: var(--coral);
font-size: 14px;
letter-spacing: 0.05em;
text-transform: none;
}
.sec-rule .meta-grp { display: inline-flex; gap: 26px; }
.sec-rule .dot-mark { color: var(--coral); }
.section-header { margin-bottom: 70px; }
.section-header .label { margin-bottom: 32px; }
.section-header h2 {
font-size: clamp(40px, 4.6vw, 66px);
max-width: 22ch;
}
.section-header .lead { margin-top: 22px; }
/* ---------- WIRE / GLOBAL TICKER ----------
*
* Slim editorial strip between the hero and the About section. Two
* counter-scrolling marquees (cities → and contributors ←) signal that
* the project is global and community-driven, without disrupting the
* existing roman-numeral section count. Pure CSS animation; the track
* content is duplicated in markup so the loop wraps seamlessly.
*/
.wire {
border-bottom: 1px solid var(--line);
padding: 26px 0 28px;
background: var(--paper);
position: relative;
overflow: hidden;
}
.wire-inner {
display: grid;
grid-template-columns: minmax(180px, 220px) minmax(0, 1fr);
gap: 32px;
align-items: center;
}
.wire-left {
display: inline-flex;
align-items: center;
gap: 14px;
border-right: 1px solid var(--line);
padding-right: 24px;
min-height: 56px;
}
.wire-mark {
width: 22px;
height: 22px;
border-radius: 50%;
border: 1px solid var(--line);
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.wire-pulse {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--coral);
display: inline-block;
animation: pulse 2.4s ease-in-out infinite;
}
.wire-title {
font-family: var(--sans);
font-size: 11px;
line-height: 1.4;
display: flex;
flex-direction: column;
gap: 3px;
}
.wire-title b {
color: var(--ink);
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.wire-title span {
color: var(--ink-faint);
font-size: 10px;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.wire-rows {
display: grid;
gap: 8px;
min-width: 0;
}
.wire-row {
overflow: hidden;
mask-image: linear-gradient(
90deg,
transparent,
black 5%,
black 95%,
transparent
);
-webkit-mask-image: linear-gradient(
90deg,
transparent,
black 5%,
black 95%,
transparent
);
}
.marquee-track {
display: inline-flex;
align-items: center;
gap: 36px;
width: max-content;
white-space: nowrap;
animation: marquee-x 52s linear infinite;
will-change: transform;
}
.wire-row.reverse .marquee-track {
animation-direction: reverse;
animation-duration: 64s;
}
.wire-row:hover .marquee-track {
animation-play-state: paused;
}
@keyframes marquee-x {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
.wire-item {
display: inline-flex;
align-items: baseline;
gap: 8px;
font-family: var(--sans);
font-size: 12px;
letter-spacing: 0.04em;
color: var(--ink-mute);
text-decoration: none;
flex-shrink: 0;
}
.wire-item .wire-dot {
color: var(--coral);
font-size: 16px;
line-height: 0;
position: relative;
top: -1px;
margin-right: 2px;
}
.wire-item .wire-coord {
font-family: var(--mono);
font-size: 10.5px;
color: var(--ink-faint);
letter-spacing: 0;
}
.wire-item .wire-name {
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--ink);
font-weight: 500;
}
.wire-item .wire-handle {
font-family: var(--mono);
color: var(--ink);
font-size: 11.5px;
font-weight: 500;
}
.wire-item .wire-role {
text-transform: uppercase;
letter-spacing: 0.16em;
color: var(--coral);
font-size: 10px;
}
.wire-item.is-link {
transition: color 160ms ease;
}
.wire-item.is-link:hover .wire-handle {
color: var(--coral);
}
@media (prefers-reduced-motion: reduce) {
.marquee-track {
animation: none;
}
}
/* ---------- ABOUT ---------- */
.about-grid {
display: grid;
grid-template-columns: 1.05fr 1fr;
gap: 80px;
align-items: center;
}
.about h2 {
font-size: clamp(44px, 5.4vw, 78px);
margin: 30px 0 36px;
}
.about .label { margin-bottom: 28px; }
.about .lead { margin-bottom: 36px; max-width: 42ch; font-size: 17px; }
.about .footer-row {
display: flex;
align-items: center;
gap: 20px;
margin-top: 56px;
color: var(--ink-faint);
font-family: var(--sans);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.about .footer-row .mark {
width: 30px; height: 30px;
border-radius: 50%;
border: 1px solid var(--ink);
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--serif);
font-style: italic;
font-size: 14px;
color: var(--ink);
}
.about .stamp {
margin-left: auto;
display: inline-flex;
flex-direction: column;
align-items: flex-end;
line-height: 1.4;
}
.about .stamp span:first-child { color: var(--coral); }
.about-art {
position: relative;
aspect-ratio: 1 / 1;
max-width: 620px;
margin-left: auto;
}
.about-art img { width: 100%; height: 100%; object-fit: contain; }
.about-side-note {
position: absolute;
right: -8px;
top: 26px;
text-align: right;
font-family: var(--sans);
font-size: 10.5px;
line-height: 1.55;
color: var(--ink-faint);
letter-spacing: 0.04em;
max-width: 16ch;
}
.about-side-note b {
display: block;
color: var(--coral);
width: 36px;
height: 1px;
background: var(--coral);
margin: 0 0 10px auto;
}
.about-caption {
position: absolute;
right: 18px;
bottom: 4px;
font-family: var(--sans);
font-size: 9.5px;
color: var(--ink-faint);
text-align: right;
letter-spacing: 0.06em;
line-height: 1.45;
}
.about-caption b { color: var(--ink); display: block; }
/* ---------- CAPABILITIES ---------- */
.capabilities-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 70px;
align-items: center;
}
.capabilities-art {
position: relative;
aspect-ratio: 1 / 1;
max-width: 600px;
}
.capabilities-art img { width: 100%; height: 100%; object-fit: contain; }
.capabilities-art .ribbon {
position: absolute;
right: -42px;
top: 50%;
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.42em;
text-transform: uppercase;
color: var(--ink-faint);
writing-mode: vertical-rl;
transform: rotate(180deg);
}
.capabilities-art .ribbon b { color: var(--coral); }
.capabilities-art .corner { position: absolute; width: 22px; height: 22px; border-color: var(--ink-faint); border-style: solid; border-width: 0; }
.capabilities-art .corner.tl { top: 0; left: 0; border-top-width: 1px; border-left-width: 1px; }
.capabilities-art .corner.br { bottom: 0; right: 0; border-bottom-width: 1px; border-right-width: 1px; }
.capabilities-copy h2 { font-size: clamp(40px, 4.8vw, 64px); margin: 22px 0 30px; }
.cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
margin-top: 22px;
}
.card {
padding: 28px 26px 32px;
background: var(--bone);
border-radius: 18px;
box-shadow: var(--shadow), inset 0 0 0 1px rgba(21, 20, 15, 0.06);
position: relative;
overflow: hidden;
transition: transform 0.2s ease;
}
.card:hover { transform: translateY(-3px); }
.card .num {
font-family: var(--serif);
font-style: italic;
font-size: 22px;
font-weight: 500;
color: var(--coral);
letter-spacing: 0.04em;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: baseline;
}
.card .num .tag {
font-family: var(--sans);
font-size: 9.5px;
color: var(--ink-faint);
letter-spacing: 0.18em;
text-transform: uppercase;
font-style: normal;
font-weight: 500;
}
.card .icon {
width: 28px;
height: 28px;
margin-bottom: 16px;
color: var(--ink);
}
.card h3 {
font-family: var(--sans);
font-size: 22px;
font-weight: 700;
line-height: 1.05;
letter-spacing: -0.014em;
margin-bottom: 14px;
}
.card p {
font-family: var(--body);
font-size: 13.5px;
color: var(--ink-mute);
line-height: 1.55;
max-width: 24ch;
}
.card .arrow-mark {
position: absolute;
right: 22px;
bottom: 22px;
width: 28px; height: 28px;
border: 1px solid var(--line);
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--ink);
transition: all 0.18s ease;
}
.card:hover .arrow-mark { background: var(--coral); border-color: var(--coral); color: #fff; }
.card .arrow-mark svg { width: 11px; height: 11px; stroke: currentColor; fill: none; stroke-width: 1.6; }
/* ---------- LABS ---------- */
.labs-head {
display: grid;
grid-template-columns: 1.4fr 1fr;
gap: 60px;
align-items: end;
margin-bottom: 48px;
}
.labs-head h2 { font-size: clamp(40px, 4.8vw, 68px); }
.pills {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: flex-end;
}
.pill {
padding: 9px 18px;
border-radius: 999px;
border: 1px solid var(--line);
font-family: var(--sans);
font-size: 13px;
color: var(--ink-soft);
background: transparent;
cursor: pointer;
transition: all 0.18s ease;
display: inline-flex;
align-items: center;
gap: 8px;
}
.pill:hover { background: rgba(21, 20, 15, 0.04); }
.pill.active {
background: var(--coral);
border-color: var(--coral);
color: #fff;
}
.pill .count {
font-size: 10px;
color: var(--ink-faint);
border-left: 1px solid var(--line);
padding-left: 8px;
}
.pill.active .count { color: rgba(255,255,255,0.7); border-color: rgba(255,255,255,0.3); }
.labs-meta {
display: flex;
align-items: flex-start;
justify-content: flex-end;
gap: 22px;
margin-bottom: 30px;
}
.labs-meta .ring {
width: 38px; height: 38px;
border-radius: 50%;
border: 1px dashed var(--ink);
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--sans);
font-size: 11px;
font-weight: 700;
}
.labs-meta .meta-text {
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
line-height: 1.55;
color: var(--ink-faint);
max-width: 28ch;
}
.labs-meta .meta-text b { display: block; color: var(--ink); }
.labs-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 22px;
}
.lab {
display: flex;
flex-direction: column;
}
.lab-img {
aspect-ratio: 4 / 5;
background: var(--bone);
border-radius: 14px;
overflow: hidden;
margin-bottom: 18px;
box-shadow: var(--shadow);
position: relative;
}
.lab-img img { width: 100%; height: 100%; object-fit: cover; }
.lab-img .badge {
position: absolute;
top: 12px;
left: 12px;
background: rgba(239, 231, 210, 0.9);
color: var(--ink);
padding: 4px 9px;
border-radius: 4px;
font-family: var(--sans);
font-size: 9.5px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.lab .num-row {
font-family: var(--sans);
font-size: 10.5px;
color: var(--ink-faint);
letter-spacing: 0.14em;
margin-bottom: 8px;
display: flex;
justify-content: space-between;
text-transform: uppercase;
}
.lab h4 {
font-family: var(--sans);
font-size: 18px;
font-weight: 700;
letter-spacing: -0.014em;
margin-bottom: 8px;
}
.lab p {
font-family: var(--body);
font-size: 13px;
color: var(--ink-mute);
line-height: 1.55;
margin-bottom: 14px;
}
.lab .arrow-mark {
width: 28px; height: 28px;
border: 1px solid var(--line);
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--ink);
margin-top: auto;
align-self: flex-start;
}
.lab .arrow-mark svg { width: 11px; height: 11px; stroke: currentColor; fill: none; stroke-width: 1.6; }
.labs-foot {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 50px;
border-top: 1px dashed var(--line);
padding-top: 22px;
}
.progress {
display: flex;
align-items: center;
gap: 8px;
}
.progress span {
width: 26px; height: 2px;
background: var(--line);
border-radius: 2px;
}
.progress span.on { background: var(--coral); }
/* ---------- METHOD ---------- */
.method-head {
display: grid;
grid-template-columns: 1.4fr 1fr;
gap: 60px;
align-items: start;
margin-bottom: 80px;
}
.method-head h2 { font-size: clamp(44px, 5.2vw, 76px); }
.method-head .right {
display: flex;
align-items: flex-start;
gap: 14px;
padding-top: 14px;
}
.method-head .plus {
color: var(--coral);
font-size: 24px;
line-height: 1;
font-family: var(--sans);
}
.method-head .right p {
font-family: var(--sans);
font-size: 13px;
color: var(--ink-soft);
max-width: 22ch;
line-height: 1.55;
}
.method-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 50px;
position: relative;
}
.method-grid::before {
content: '';
position: absolute;
top: 60px;
left: 50px;
right: 50px;
height: 1px;
background: var(--line-soft);
}
.method-step { position: relative; }
.method-step .num {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
font-size: 78px;
color: var(--coral);
line-height: 0.85;
margin-bottom: 24px;
letter-spacing: -0.02em;
background: var(--paper);
display: inline-block;
padding-right: 12px;
position: relative;
z-index: 1;
}
.method-step h4 {
font-family: var(--sans);
font-size: 30px;
font-weight: 800;
letter-spacing: -0.022em;
margin-bottom: 18px;
display: flex;
align-items: center;
justify-content: space-between;
padding-right: 18px;
}
.method-step h4 .arrow-r {
color: var(--ink-faint);
font-size: 22px;
line-height: 1;
}
.method-step:last-child h4 .arrow-r { display: none; }
.method-step p {
font-family: var(--body);
font-size: 13.5px;
color: var(--ink-mute);
line-height: 1.55;
margin-bottom: 24px;
max-width: 24ch;
}
.method-step .img {
aspect-ratio: 1 / 1;
background: var(--bone);
border-radius: 12px;
overflow: hidden;
box-shadow: var(--shadow);
}
.method-step .img img { width: 100%; height: 100%; object-fit: cover; }
.method-foot {
margin-top: 80px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px dashed var(--line);
padding-top: 24px;
}
.method-foot .left,
.method-foot .right {
font-family: var(--sans);
font-size: 11px;
color: var(--ink-faint);
letter-spacing: 0.18em;
text-transform: uppercase;
}
.method-foot .left {
display: inline-flex;
align-items: center;
gap: 12px;
}
.method-foot .left .ring {
width: 20px; height: 20px;
border: 1px dashed var(--ink-faint);
border-radius: 50%;
}
.method-foot .right b { color: var(--ink); }
/* ---------- WORK ---------- */
.work {
background: #15140f;
color: var(--paper);
border-radius: 32px;
margin: 0 64px;
overflow: hidden;
position: relative;
padding: 110px 64px;
}
.work::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background-image:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n2'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 0.95 0 0 0 0 0.85 0 0 0 0.05 0'/></filter><rect width='100%' height='100%' filter='url(%23n2)'/></svg>");
background-size: 240px 240px;
opacity: 0.6;
mix-blend-mode: screen;
}
.work-rule {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid rgba(247, 241, 222, 0.16);
padding-top: 16px;
margin-bottom: 60px;
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: rgba(247, 241, 222, 0.55);
}
.work-rule .roman { color: var(--coral); font-family: var(--serif); font-style: italic; font-size: 14px; letter-spacing: 0.04em; text-transform: none; }
.work-grid {
display: grid;
grid-template-columns: 1fr 1.05fr 0.85fr;
gap: 48px;
align-items: center;
position: relative;
}
.work .label { color: var(--coral); }
.work .label::before { background: var(--coral); }
.work-copy h2 {
font-family: var(--sans);
font-weight: 800;
font-size: clamp(40px, 5vw, 66px);
line-height: 1.0;
letter-spacing: -0.024em;
margin: 28px 0 36px;
color: var(--paper);
}
.work-copy h2 em {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
}
.work-copy h2 .dot { color: var(--coral); }
.work-link {
display: inline-flex;
align-items: center;
gap: 18px;
color: var(--paper);
font-family: var(--sans);
font-size: 14px;
text-decoration: none;
border-bottom: 2px solid var(--coral);
padding-bottom: 12px;
width: fit-content;
}
.work-link::after { content: '↗'; color: var(--coral); }
.work-card {
background: var(--paper);
color: var(--ink);
border-radius: 18px;
padding: 32px 30px;
position: relative;
transform: rotate(-1.2deg);
text-decoration: none;
display: block;
transition: transform 280ms ease, box-shadow 280ms ease;
}
.work-card:hover {
transform: rotate(-1.2deg) translateY(-4px);
box-shadow: var(--shadow);
}
.work-card.alt {
transform: rotate(2.4deg) translateY(20px);
padding: 28px 26px;
}
.work-card.alt:hover {
transform: rotate(2.4deg) translateY(16px);
box-shadow: var(--shadow);
}
.work-card .label-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 22px;
}
.work-card .small-label {
font-family: var(--sans);
font-size: 10.5px;
color: var(--coral);
letter-spacing: 0.18em;
text-transform: uppercase;
font-weight: 600;
}
.work-card .index {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-faint);
letter-spacing: 0.04em;
}
.work-card h3 {
font-family: var(--sans);
font-size: clamp(26px, 2.4vw, 38px);
font-weight: 800;
letter-spacing: -0.022em;
line-height: 1.05;
margin-bottom: 14px;
}
.work-card p {
font-family: var(--body);
font-size: 14px;
color: var(--ink-mute);
line-height: 1.55;
margin-bottom: 22px;
max-width: 28ch;
}
.work-card .img {
aspect-ratio: 4 / 3;
background: var(--bone);
border-radius: 12px;
overflow: hidden;
margin-bottom: 22px;
}
.work-card .img img { width: 100%; height: 100%; object-fit: cover; }
.work-card .meta-row {
display: flex;
justify-content: space-between;
color: var(--ink-faint);
font-family: var(--sans);
font-size: 11px;
letter-spacing: 0.16em;
text-transform: uppercase;
border-top: 1px solid var(--line);
padding-top: 14px;
}
.work-card .year { color: var(--coral); font-weight: 600; }
.work-arrows {
position: absolute;
right: 64px;
bottom: 64px;
display: inline-flex;
align-items: center;
gap: 10px;
}
.work-arrows .nav-btn {
width: 46px; height: 46px;
border-radius: 50%;
border: 1px solid rgba(247, 241, 222, 0.2);
background: transparent;
color: var(--paper);
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.work-arrows .nav-btn.active { background: var(--coral); border-color: var(--coral); }
/* ---------- TESTIMONIAL / COLLABORATORS ---------- */
.testimonial-grid {
display: grid;
grid-template-columns: 1.2fr 1fr;
gap: 80px;
align-items: center;
}
.testimonial-copy h2 {
font-family: var(--sans);
font-size: clamp(36px, 4vw, 54px);
font-weight: 700;
letter-spacing: -0.022em;
line-height: 1.12;
margin-bottom: 36px;
}
.testimonial-copy h2 em {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
}
.author {
display: flex;
align-items: center;
gap: 18px;
margin-top: 22px;
}
.author .avatar {
width: 50px; height: 50px;
border-radius: 50%;
background: var(--ink);
overflow: hidden;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--paper);
font-family: var(--serif);
font-style: italic;
font-size: 24px;
}
.author p {
font-family: var(--sans);
font-size: 14px;
color: var(--ink);
font-weight: 600;
}
.author p span {
display: block;
color: var(--ink-mute);
font-weight: 400;
}
.divider {
border-top: 1px solid var(--line);
margin: 60px 0 32px;
}
.partners-text {
font-family: var(--body);
font-size: 14px;
color: var(--ink-mute);
margin-bottom: 26px;
max-width: 38ch;
}
.partners {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 22px;
align-items: end;
}
.partner {
display: flex;
flex-direction: column;
gap: 10px;
text-decoration: none;
color: inherit;
cursor: pointer;
transition: transform 220ms ease;
}
.partner:hover { transform: translateY(-2px); }
.partner:hover .glyph { color: var(--coral); }
.partner:hover span { color: var(--coral); }
.partner .glyph {
height: 32px;
display: flex;
align-items: center;
color: var(--ink);
transition: color 220ms ease;
}
.partner .glyph svg { height: 100%; width: auto; max-width: 90px; }
.partner span {
font-family: var(--sans);
font-size: 13px;
color: var(--ink);
letter-spacing: -0.005em;
font-weight: 600;
transition: color 220ms ease;
}
.partner small {
font-family: var(--sans);
font-size: 10px;
color: var(--ink-faint);
letter-spacing: 0.1em;
text-transform: uppercase;
}
.read-more {
margin-top: 56px;
display: inline-flex;
align-items: center;
gap: 10px;
font-family: var(--sans);
font-size: 13px;
color: var(--ink);
text-decoration: none;
letter-spacing: 0.04em;
border-bottom: 1px solid var(--coral);
padding-bottom: 6px;
}
.read-more::after { content: '→'; color: var(--coral); }
.testimonial-art {
position: relative;
aspect-ratio: 1 / 1;
max-width: 560px;
}
.testimonial-art img { width: 100%; height: 100%; object-fit: contain; }
/* ---------- CTA ---------- */
.cta-grid {
display: grid;
grid-template-columns: 1.05fr 1fr;
gap: 50px;
align-items: center;
}
.cta h2 {
font-size: clamp(54px, 6.6vw, 100px);
margin: 32px 0 32px;
}
.cta .lead { margin-bottom: 36px; max-width: 36ch; font-size: 16px; }
.cta-actions {
display: inline-flex;
align-items: center;
gap: 14px;
margin-bottom: 32px;
}
.email-pill {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 18px 14px 22px;
border-radius: 999px;
border: 1px solid var(--line);
font-family: var(--sans);
font-size: 14px;
color: var(--ink);
text-decoration: none;
}
.email-pill .arrow-circle {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--ink);
color: var(--paper);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.cta-foot {
display: flex;
gap: 28px;
align-items: center;
margin-top: 32px;
padding-top: 22px;
border-top: 1px solid var(--line);
font-family: var(--sans);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-faint);
}
.cta-foot .stamp { color: var(--coral); font-weight: 600; }
.cta-art {
position: relative;
aspect-ratio: 1 / 1;
max-width: 620px;
margin-left: auto;
}
.cta-art img { width: 100%; height: 100%; object-fit: contain; }
.cta-art .index {
position: absolute;
right: 8px;
top: 24px;
font-family: var(--serif);
font-style: italic;
font-size: 28px;
color: var(--ink-faint);
}
.cta-art .ribbon {
position: absolute;
left: -32px;
top: 50%;
font-family: var(--sans);
font-size: 10.5px;
letter-spacing: 0.42em;
text-transform: uppercase;
color: var(--ink-faint);
writing-mode: vertical-rl;
transform: rotate(180deg);
}
/* ---------- OFFICIAL SOURCE STRIP ----------
*
* Slim attestation band that sits between the hero/wire and About.
* Reinforces the canonical surfaces — official site, GitHub repo,
* releases, download, docs, Discord — for both Google entity merge
* and human verification. Minimal chrome on purpose.
*/
.official-strip {
padding: 38px 0 18px;
border-top: 1px solid var(--line);
border-bottom: 1px solid var(--line);
background: var(--paper);
}
.official-strip-inner {
display: grid;
grid-template-columns: minmax(180px, 220px) 1fr;
gap: 28px;
align-items: center;
}
.official-strip-label {
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
}
.official-strip-label .ix {
color: var(--coral);
margin-left: 6px;
}
.official-strip-list {
list-style: none;
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 18px 24px;
padding: 0;
margin: 0;
}
.official-strip-list li {
display: flex;
min-width: 0;
}
.official-strip-list a {
display: grid;
gap: 4px;
padding: 6px 0;
border-bottom: 1px solid transparent;
text-decoration: none;
color: var(--ink);
font-family: var(--sans);
min-width: 0;
transition: border-color 0.16s ease, color 0.16s ease;
}
.official-strip-list a:hover {
border-bottom-color: var(--coral);
color: var(--coral);
}
.official-strip-list .label {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-mute);
}
.official-strip-list .value {
font-size: 13.5px;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 980px) {
.official-strip-inner {
grid-template-columns: 1fr;
gap: 18px;
}
.official-strip-list {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 560px) {
.official-strip-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px 18px;
}
}
/* ---------- FAQ ---------- */
.faq-head {
max-width: 880px;
margin: 36px 0 48px;
}
.faq-head .label {
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
display: inline-block;
margin-bottom: 18px;
}
.faq-head .display {
font-family: var(--serif);
font-weight: 600;
font-size: clamp(36px, 5.4vw, 64px);
line-height: 1.06;
letter-spacing: -0.022em;
color: var(--ink);
}
.faq-head .display em {
font-style: italic;
font-weight: 600;
color: var(--coral);
}
.faq-head .display .dot { color: var(--coral); }
.faq-list {
list-style: none;
padding: 0;
margin: 0;
border-top: 1px solid var(--line);
}
.faq-item {
border-bottom: 1px solid var(--line);
}
.faq-item details {
padding: 0;
}
.faq-item summary {
display: grid;
grid-template-columns: 56px 1fr 32px;
gap: 24px;
align-items: center;
padding: 26px 0;
cursor: pointer;
list-style: none;
user-select: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-index {
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.16em;
color: var(--ink-faint);
}
.faq-q {
font-family: var(--serif);
font-size: clamp(20px, 2.2vw, 26px);
line-height: 1.25;
color: var(--ink);
}
.faq-toggle {
justify-self: end;
width: 32px;
height: 32px;
border-radius: 50%;
border: 1px solid var(--line);
color: var(--ink);
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--sans);
font-size: 16px;
transition: transform 0.22s cubic-bezier(0.23, 1, 0.32, 1),
background-color 0.22s cubic-bezier(0.23, 1, 0.32, 1),
color 0.22s cubic-bezier(0.23, 1, 0.32, 1);
}
.faq-item details[open] .faq-toggle {
transform: rotate(45deg);
background: var(--ink);
color: var(--paper);
border-color: var(--ink);
}
.faq-a {
grid-column: 2 / 3;
margin: 0 0 26px;
padding-left: 80px;
max-width: 64ch;
font-family: var(--sans);
font-size: 15.5px;
line-height: 1.7;
color: var(--ink-mute);
}
@media (max-width: 720px) {
.faq-item summary {
grid-template-columns: 36px 1fr 28px;
gap: 14px;
padding: 20px 0;
}
.faq-a {
padding-left: 50px;
font-size: 14.5px;
}
}
/* ---------- FOOTER ---------- */
footer {
border-top: 1px solid var(--line);
padding: 60px 0 30px;
margin-top: 60px;
}
.foot-grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr 1fr;
gap: 40px;
margin-bottom: 60px;
}
.foot-brand .brand { margin-bottom: 18px; }
.foot-brand p {
font-family: var(--body);
font-size: 13.5px;
color: var(--ink-mute);
line-height: 1.55;
max-width: 38ch;
}
.foot-cta {
display: inline-flex;
align-items: center;
gap: 10px;
margin-top: 22px;
padding: 11px 18px;
border-radius: 999px;
background: var(--ink);
color: var(--paper);
font-family: var(--sans);
font-size: 13px;
font-weight: 500;
letter-spacing: -0.005em;
text-decoration: none;
transition: transform 160ms ease, background 160ms ease;
}
.foot-cta:hover {
transform: translateY(-1px);
background: var(--ink-soft);
}
.foot-cta::after {
content: '↓';
color: var(--mustard);
font-size: 12px;
}
.foot-cta .meta {
color: rgba(239, 231, 210, 0.55);
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
margin-left: 4px;
}
.foot-brand p .inline-link,
.inline-link {
color: var(--ink);
text-decoration: none;
border-bottom: 1px solid var(--line);
transition: color 160ms ease, border-color 160ms ease;
}
.inline-link:hover {
color: var(--coral);
border-bottom-color: var(--coral);
}
.method-repo-link {
color: inherit;
text-decoration: none;
border-bottom: 1px solid transparent;
transition: color 160ms ease, border-color 160ms ease;
}
.method-repo-link:hover {
color: var(--coral);
border-bottom-color: var(--coral);
}
.library-link {
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 160ms ease;
}
.library-link:hover { border-bottom-color: var(--coral); }
.foot-col h5 {
font-family: var(--sans);
font-size: 11px;
color: var(--ink);
letter-spacing: 0.18em;
text-transform: uppercase;
margin-bottom: 18px;
font-weight: 700;
}
.foot-col ul { list-style: none; }
.foot-col li { margin-bottom: 10px; }
.foot-col a {
font-family: var(--body);
font-size: 13.5px;
color: var(--ink-soft);
text-decoration: none;
}
.foot-col a:hover { color: var(--coral); }
.foot-bottom {
border-top: 1px solid var(--line);
padding-top: 22px;
display: flex;
justify-content: space-between;
align-items: center;
font-family: var(--sans);
font-size: 11px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-faint);
}
.foot-bottom .right { display: inline-flex; gap: 24px; align-items: center; }
.foot-bottom .pulse {
width: 6px; height: 6px;
border-radius: 50%;
background: var(--coral);
display: inline-block;
margin-right: 6px;
vertical-align: middle;
}
.foot-mega {
margin-top: 60px;
padding-top: 0;
padding-bottom: 12px;
border-top: 1px solid var(--line);
overflow-x: hidden;
overflow-y: visible;
}
.foot-mega .word {
font-family: var(--sans);
font-weight: 900;
font-size: clamp(70px, 13vw, 200px);
letter-spacing: -0.04em;
line-height: 1.05;
color: var(--ink);
white-space: nowrap;
margin-top: 30px;
padding-bottom: 0.18em;
}
.foot-mega .word em {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
color: var(--coral);
}
/* ---------- scroll-reveal motion ----------
*
* Driven by `app/_components/reveal-root.tsx`. Elements with
* `data-reveal` start hidden + offset; the observer sets
* `data-revealed='true'` once they enter the viewport, triggering
* the transition.
*
* Uses `translate` / `scale` longhand properties (not `transform`) so
* that elements like `.work-card` keep their static `transform: rotate()`
* intact while still translating in.
*/
[data-reveal] {
opacity: 0;
translate: 0 28px;
transition:
opacity 900ms cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay, 0ms),
translate 900ms cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay, 0ms),
scale 900ms cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay, 0ms);
will-change: opacity, translate, scale;
}
[data-reveal='left'] { translate: -36px 0; }
[data-reveal='right'] { translate: 36px 0; }
[data-reveal='scale'] { translate: 0 0; scale: 0.96; }
[data-reveal='rise-lg'] { translate: 0 64px; scale: 0.985; }
[data-reveal][data-revealed='true'] {
opacity: 1;
translate: 0 0;
scale: 1;
}
/* stagger primitives — set --reveal-delay on grid children so siblings
* appear in sequence rather than all at once. */
.cards > .card[data-reveal]:nth-child(1) { --reveal-delay: 0ms; }
.cards > .card[data-reveal]:nth-child(2) { --reveal-delay: 90ms; }
.cards > .card[data-reveal]:nth-child(3) { --reveal-delay: 180ms; }
.cards > .card[data-reveal]:nth-child(4) { --reveal-delay: 270ms; }
.labs-grid > .lab[data-reveal]:nth-child(1) { --reveal-delay: 0ms; }
.labs-grid > .lab[data-reveal]:nth-child(2) { --reveal-delay: 90ms; }
.labs-grid > .lab[data-reveal]:nth-child(3) { --reveal-delay: 180ms; }
.labs-grid > .lab[data-reveal]:nth-child(4) { --reveal-delay: 270ms; }
.labs-grid > .lab[data-reveal]:nth-child(5) { --reveal-delay: 360ms; }
.method-grid > .method-step[data-reveal]:nth-child(1) { --reveal-delay: 0ms; }
.method-grid > .method-step[data-reveal]:nth-child(2) { --reveal-delay: 110ms; }
.method-grid > .method-step[data-reveal]:nth-child(3) { --reveal-delay: 220ms; }
.method-grid > .method-step[data-reveal]:nth-child(4) { --reveal-delay: 330ms; }
.partners > .partner[data-reveal]:nth-child(1) { --reveal-delay: 0ms; }
.partners > .partner[data-reveal]:nth-child(2) { --reveal-delay: 70ms; }
.partners > .partner[data-reveal]:nth-child(3) { --reveal-delay: 140ms; }
.partners > .partner[data-reveal]:nth-child(4) { --reveal-delay: 210ms; }
.partners > .partner[data-reveal]:nth-child(5) { --reveal-delay: 280ms; }
.partners > .partner[data-reveal]:nth-child(6) { --reveal-delay: 350ms; }
/* hero copy — let label, headline, lead, actions, stats arrive in sequence
* so the headline isn't waiting on a single block-level reveal. */
.hero-copy > [data-reveal]:nth-of-type(1) { --reveal-delay: 0ms; }
.hero-copy > [data-reveal]:nth-of-type(2) { --reveal-delay: 80ms; }
.hero-copy > [data-reveal]:nth-of-type(3) { --reveal-delay: 160ms; }
.hero-copy > [data-reveal]:nth-of-type(4) { --reveal-delay: 240ms; }
.hero-copy > [data-reveal]:nth-of-type(5) { --reveal-delay: 320ms; }
.hero-copy > [data-reveal]:nth-of-type(6) { --reveal-delay: 400ms; }
@media (prefers-reduced-motion: reduce) {
[data-reveal] {
opacity: 1 !important;
translate: 0 0 !important;
scale: 1 !important;
transition: none !important;
}
/* Skip the slide-in on the sticky chrome for users who prefer no motion;
* the show/hide still toggles, just instantly. */
.site-chrome { transition: none !important; }
}
/* ---------- responsive ----------
*
* Breakpoint ladder:
* 1280 — desktop chrome shrinks (drop side rails, slimmer container).
* 1200 — topbar mid label crowds first, hide it.
* 1080 — small desktop / large laptop. Smaller hero/section heads.
* 880 — tablet portrait. Stack two-column grids, tame the dark work
* card, trim partners to 3 cols.
* 640 — large phone landscape. Wrap toolbars, trim foot-mega.
* 560 — phone portrait. One-column lists/cards. Hero shrinks again.
* 420 — tiny phones. Drop decorative ribbons that overflow, shrink
* the locale switcher, tighten section padding.
*/
@media (max-width: 1280px) {
.container { padding: 0 44px; }
.work { margin: 0 44px; padding: 90px 44px; }
.side-rail { display: none; }
}
/* hide topbar mid text early — between 1200 and 1280 it crowds even with nowrap */
@media (max-width: 1200px) {
.topbar-inner .mid { display: none; }
}
/* nav: between 1080 and 1180 the brand tail + nav links + 2 CTAs + dot
* crowd the row. Drop the brand sub-meta first, then tighten link spacing,
* so the Star CTA never has to compress. */
@media (max-width: 1180px) {
.nav-inner { gap: 18px; }
.brand-meta { display: none; }
.nav-links { gap: 28px; }
}
/* nav: at ≤1080px there's no clean way to fit Product · Skills · Systems ·
* Templates · Craft · Blog · Contact + Download + Star + dot in one row,
* so swap to a hamburger panel. Star CTA stays visible in the bar (it's
* the social-proof CTA); Download moves into the panel. The Product
* submenu flattens from a hover-popup to an always-expanded inline list,
* since hover doesn't translate to touch.
*/
@media (max-width: 1080px) {
.nav-toggle { display: inline-flex; }
.brand { white-space: nowrap; }
/* Hide Download + Discord/X icon buttons from the bar (Star stays). */
.nav-side .nav-cta.ghost { display: none; }
.nav-side .nav-icon { display: none; }
/* Collapse the nav <ul> into a panel that drops below the header bar.
* The header is `position: sticky`, so absolute-positioning the panel
* relative to the header element keeps it pinned correctly. */
.nav { position: sticky; }
.nav > .nav-inner > nav[data-nav-primary] {
position: absolute;
top: 100%;
left: 0;
right: 0;
margin: 0;
padding: 0;
pointer-events: none;
opacity: 0;
visibility: hidden;
transform: translateY(-6px);
transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
background: var(--paper);
border-top: 1px solid rgba(26, 26, 26, 0.08);
box-shadow: 0 12px 32px rgba(26, 26, 26, 0.06);
}
.nav.is-open > .nav-inner > nav[data-nav-primary] {
pointer-events: auto;
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.nav-links {
flex-direction: column;
align-items: stretch;
gap: 0;
padding: 12px 24px 20px 24px;
}
.nav-links li {
border-bottom: 1px solid rgba(26, 26, 26, 0.06);
}
.nav-links li:last-child { border-bottom: none; }
.nav-links a {
display: block;
padding: 14px 0;
font-size: 16px;
}
.nav-links a .num {
position: static;
margin-left: 6px;
font-size: 11px;
}
/* Product dropdown flattens — always show OD + HA as nested static items. */
.nav-links li.has-dropdown { position: static; }
.nav-links .dropdown-caret { display: none; }
.nav-dropdown {
position: static;
opacity: 1;
visibility: visible;
transform: none;
margin: 0 0 4px 0;
padding: 0 0 4px 16px;
border: none;
border-left: 2px solid rgba(26, 26, 26, 0.08);
border-radius: 0;
box-shadow: none;
background: transparent;
min-width: 0;
}
.nav-dropdown::before { display: none; }
.nav-dropdown a { padding: 8px 8px; border-radius: 4px; }
.nav-dropdown .dropdown-blurb { display: none; }
}
@media (max-width: 1080px) {
.container { padding: 0 32px; }
.hero h1 { font-size: clamp(36px, 4.6vw, 54px); }
.section-header h2 { font-size: clamp(32px, 4vw, 50px); }
.labs-grid { grid-template-columns: repeat(5, 1fr); gap: 14px; }
.partners { grid-template-columns: repeat(3, 1fr); gap: 18px; row-gap: 28px; }
.foot-grid { grid-template-columns: 2fr 1fr 1fr; }
.foot-grid .foot-col:nth-child(4),
.foot-grid .foot-col:nth-child(5) { display: none; }
.work { padding: 80px 40px; }
.work-arrows { right: 32px; bottom: 32px; }
}
@media (max-width: 880px) {
.container { padding: 0 24px; }
/* stack two-column grids */
.hero-grid, .about-grid, .capabilities-grid, .testimonial-grid, .cta-grid {
grid-template-columns: 1fr;
gap: 50px;
}
.labs-head, .method-head { grid-template-columns: 1fr; gap: 28px; }
.labs-meta { justify-content: flex-start; }
.pills { justify-content: flex-start; }
.labs-grid { grid-template-columns: repeat(2, 1fr); }
.method-grid { grid-template-columns: repeat(2, 1fr); gap: 36px; }
.method-grid::before { display: none; }
/* hero — copy first, art second; trim art height so the page isn't 200vh */
.hero { min-height: 0; padding: 32px 0 0; }
.hero::before { display: none; }
.hero-grid { gap: 36px; }
.hero-copy { padding: 18px 0 8px; }
.hero-copy .lead { max-width: none; }
.hero-art { height: auto; aspect-ratio: 4 / 5; max-height: none; margin: 0 -8px 0 0; }
.hero-actions { flex-wrap: wrap; }
.hero-stats { flex-wrap: wrap; gap: 14px 22px; }
.hero-foot { flex-wrap: wrap; gap: 12px 24px; padding-top: 18px; }
.sec-rule { flex-wrap: wrap; gap: 8px 18px; }
.sec-rule .meta-grp { gap: 18px; flex-wrap: wrap; }
.section-header { margin-bottom: 48px; }
.section-header h2 { max-width: none; }
/* wire — stack the field label above the marquee rows */
.wire-inner { grid-template-columns: 1fr; gap: 14px; }
.wire-left {
border-right: none;
border-bottom: 1px solid var(--line);
padding-right: 0;
padding-bottom: 12px;
min-height: 0;
}
/* about copy first */
.about-art { max-width: 460px; margin: 0 auto; }
.about-side-note { display: none; }
.about-caption { right: 12px; }
.about .footer-row { flex-wrap: wrap; gap: 14px 20px; margin-top: 36px; }
/* capabilities */
.capabilities-art { max-width: 460px; margin: 0 auto; }
.capabilities-art .ribbon { display: none; }
/* method */
.method-step .num { font-size: 56px; margin-bottom: 16px; }
.method-step h4 { font-size: 24px; padding-right: 0; }
.method-foot { flex-direction: column; align-items: flex-start; gap: 14px; padding-top: 18px; margin-top: 56px; }
/* dark work card */
.work { margin: 0 12px; padding: 60px 24px; border-radius: 24px; }
.work-grid { grid-template-columns: 1fr; gap: 36px; }
.work-arrows { position: static; margin-top: 32px; }
.work-card,
.work-card.alt { transform: none; }
.work-card:hover { transform: translateY(-3px); }
.work-card.alt:hover { transform: translateY(-3px); }
/* testimonial / partners */
.testimonial-art { max-width: 420px; margin: 0 auto; }
.partners { grid-template-columns: repeat(3, 1fr); gap: 18px; }
/* cta */
.cta-art { max-width: 460px; margin: 0 auto; }
.cta-art .ribbon { display: none; }
.cta-actions { flex-wrap: wrap; }
.cta-foot { flex-wrap: wrap; gap: 14px 24px; }
/* footer */
.foot-grid { grid-template-columns: 1fr 1fr; gap: 32px; }
.foot-bottom { flex-direction: column; align-items: flex-start; gap: 12px; }
.foot-bottom .right { flex-wrap: wrap; gap: 12px 20px; }
/* nav — at ≤880px tighten padding; nav-links stay reachable through
* the hamburger panel introduced at ≤1080px. Brand meta, Download,
* and the Discord/X icon buttons stay hidden; Star CTA still pings
* in the bar. */
.nav { padding: 16px 0; }
.brand-meta { display: none; }
.nav-side .nav-cta.ghost { display: none; }
.nav-side .nav-icon { display: none; }
}
@media (max-width: 640px) {
.topbar-inner { gap: 14px; }
.topbar-inner .right { gap: 12px; }
.hero-actions .btn { padding: 12px 18px; font-size: 13px; }
.work-card h3 { font-size: clamp(24px, 6vw, 30px); }
.foot-mega .word { font-size: clamp(54px, 18vw, 120px); }
}
@media (max-width: 560px) {
.container { padding: 0 16px; }
.hero h1 { font-size: clamp(34px, 9.5vw, 44px); }
.about h2,
.capabilities-copy h2,
.labs-head h2,
.method-head h2,
.testimonial-copy h2,
.cta h2,
.section-header h2 { font-size: clamp(30px, 8.5vw, 44px); }
.cta h2 { font-size: clamp(34px, 10vw, 54px); }
.labs-grid { grid-template-columns: 1fr; }
.cards { grid-template-columns: 1fr; }
.method-grid { grid-template-columns: 1fr; gap: 28px; }
.method-step .num { font-size: 48px; }
.method-step h4 { font-size: 22px; }
section { padding: 80px 0; }
.topbar-inner { font-size: 9px; gap: 10px; }
.topbar-inner .right { gap: 10px; }
.locale-trigger { gap: 4px; }
.locale-trigger-prefix { display: none; }
.locale-trigger-sep { display: none; }
.locale-menu { min-width: 208px; }
.partners { grid-template-columns: repeat(2, 1fr); gap: 14px; }
.foot-grid { grid-template-columns: 1fr; gap: 24px; }
.work { margin: 0 8px; padding: 48px 20px; border-radius: 20px; }
.hero-actions { width: 100%; }
.hero-actions .btn { flex: 1 1 auto; justify-content: center; }
.cta-actions { width: 100%; }
.cta-actions .btn,
.cta-actions .email-pill { flex: 1 1 auto; justify-content: center; }
.nav-inner { gap: 12px; }
.brand { font-size: 16px; gap: 8px; }
.brand-mark { width: 32px; height: 32px; font-size: 16px; }
.read-more { margin-top: 36px; }
.foot-mega .word { font-size: clamp(48px, 16vw, 88px); }
}
@media (max-width: 420px) {
.container { padding: 0 14px; }
.topbar-inner { align-items: flex-start; }
.topbar-inner .right {
flex-direction: column;
align-items: flex-end;
gap: 6px;
}
.locale-menu { min-width: 192px; }
.hero-stats { gap: 10px 16px; }
.hero-stats .stat { font-size: 11px; }
.hero-foot { font-size: 9.5px; }
.sec-rule { font-size: 9.5px; gap: 6px 12px; }
.partners { grid-template-columns: repeat(2, 1fr); }
.foot-mega .word { font-size: clamp(40px, 16vw, 64px); }
.work-card { padding: 26px 22px; }
.work-card.alt { padding: 24px 20px; }
}
/* ====== Plugin registry pages ====== */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.plugin-shell .nav { border-bottom: 1px solid var(--line-soft); }
.plugin-directory,
.plugin-detail { padding-bottom: 96px; }
.plugin-hero,
.plugin-detail-hero {
padding: 96px 0 72px;
border-bottom: 1px solid var(--line);
background:
linear-gradient(180deg, rgba(247, 241, 222, 0.74), rgba(239, 231, 210, 0.4)),
var(--paper);
}
.plugin-hero__grid,
.plugin-detail-hero__grid {
display: grid;
gap: 56px;
align-items: start;
}
.plugin-hero__grid {
grid-template-columns: minmax(0, 1fr) minmax(360px, 440px);
}
.plugin-detail-hero__grid {
grid-template-columns: minmax(0, 1fr) minmax(380px, 520px);
}
.plugin-hero h1,
.plugin-detail h1 {
max-width: 900px;
margin-top: 18px;
font-family: var(--serif);
font-size: clamp(48px, 7vw, 96px);
line-height: 0.94;
letter-spacing: 0;
}
.plugin-hero p,
.plugin-detail-hero p,
.plugin-detail-panel p {
max-width: 760px;
margin-top: 24px;
color: var(--ink-mute);
font-size: 18px;
line-height: 1.65;
}
.plugin-hero__actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 34px;
}
.plugin-hero__panel,
.plugin-detail-preview,
.plugin-detail__facts,
.plugin-detail-panel {
border: 1px solid var(--line);
border-radius: 8px;
background: rgba(247, 241, 222, 0.72);
box-shadow: var(--shadow);
}
.plugin-hero__panel {
display: grid;
gap: 12px;
padding: 14px;
overflow: hidden;
}
.plugin-showcase__head {
min-height: 116px;
padding: 18px;
background: rgba(255, 255, 255, 0.18);
border-bottom: 1px solid var(--line-soft);
}
.plugin-showcase__head span,
.plugin-showcase__head small,
.plugin-showcase-item small,
.plugin-showcase-item em {
display: block;
color: var(--ink-mute);
font: 700 10px var(--body);
text-transform: uppercase;
letter-spacing: 0.1em;
}
.plugin-showcase__head strong {
display: block;
font-family: var(--serif);
font-size: 56px;
font-weight: 500;
line-height: 0.86;
}
.plugin-showcase__head small {
margin-top: 10px;
}
.plugin-showcase__list {
display: grid;
gap: 10px;
}
.plugin-showcase-item {
display: grid;
grid-template-columns: 88px minmax(0, 1fr);
gap: 12px;
align-items: center;
min-height: 88px;
padding: 10px;
border: 1px solid var(--line-soft);
border-radius: 8px;
background: rgba(255, 255, 255, 0.18);
color: inherit;
text-decoration: none;
}
.plugin-showcase-item__visual {
position: relative;
display: block;
aspect-ratio: 16 / 10;
overflow: hidden;
border: 1px solid rgba(21, 20, 15, 0.14);
border-radius: 6px;
background: #101b38;
}
.plugin-showcase-item__visual img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.plugin-showcase-item__visual > span {
position: absolute;
display: block;
background: rgba(247, 241, 222, 0.86);
}
.plugin-showcase-item__visual > span:nth-child(1) {
left: 12%;
top: 22%;
width: 58%;
height: 10px;
}
.plugin-showcase-item__visual > span:nth-child(2) {
left: 12%;
top: 46%;
width: 72%;
height: 5px;
opacity: 0.72;
}
.plugin-showcase-item__visual > span:nth-child(3) {
left: 12%;
bottom: 18%;
width: 36%;
height: 5px;
opacity: 0.56;
}
.plugin-showcase-item__copy {
min-width: 0;
}
.plugin-showcase-item strong {
display: block;
margin-top: 3px;
font-family: var(--serif);
font-size: 22px;
font-weight: 600;
line-height: 1.02;
overflow-wrap: anywhere;
}
.plugin-showcase-item em {
margin-top: 7px;
font-family: var(--mono);
font-style: normal;
text-transform: none;
letter-spacing: 0;
overflow-wrap: anywhere;
}
.plugin-showcase-item--image .plugin-showcase-item__visual { background: #d9b86f; }
.plugin-showcase-item--video .plugin-showcase-item__visual { background: #16120f; }
.plugin-showcase-item--dashboard .plugin-showcase-item__visual { background: #eef3ed; }
.plugin-showcase-item--system .plugin-showcase-item__visual { background: #243025; }
.plugin-showcase-item--atom .plugin-showcase-item__visual { background: #f2e8c9; }
.plugin-hero__stats {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1px;
overflow: hidden;
border: 1px solid var(--line-soft);
border-radius: 8px;
}
.plugin-hero__stats div {
min-width: 0;
padding: 14px;
background: rgba(255, 255, 255, 0.16);
}
.plugin-hero__stats dt {
font-family: var(--serif);
font-size: 30px;
line-height: 0.95;
}
.plugin-hero__stats dd {
margin-top: 8px;
color: var(--ink-mute);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.plugin-registry-section,
.plugin-detail-section {
padding: 64px 0 0;
}
.plugin-toolbar {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(280px, 420px);
gap: 24px;
align-items: end;
}
.plugin-toolbar h2,
.plugin-detail-panel h2 {
margin-top: 8px;
font-family: var(--serif);
font-size: clamp(34px, 4vw, 54px);
line-height: 1;
letter-spacing: 0;
}
.plugin-search input {
width: 100%;
min-height: 54px;
padding: 0 18px;
border: 1px solid var(--line);
border-radius: 8px;
background: rgba(247, 241, 222, 0.86);
color: var(--ink);
font: 500 15px var(--body);
outline: none;
}
.plugin-search input:focus {
border-color: rgba(237, 111, 92, 0.72);
box-shadow: 0 0 0 3px rgba(237, 111, 92, 0.16);
}
.plugin-filter-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 28px;
}
.plugin-filter {
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 42px;
padding: 0 16px;
border: 1px solid var(--line);
border-radius: 999px;
background: rgba(247, 241, 222, 0.65);
color: var(--ink-mute);
font: 600 14px var(--body);
cursor: pointer;
}
.plugin-filter span { color: var(--ink-faint); }
.plugin-filter.is-active {
background: var(--ink);
color: var(--bone);
border-color: var(--ink);
}
.plugin-filter.is-active span { color: rgba(247, 241, 222, 0.72); }
.plugin-result-count {
margin-top: 18px;
color: var(--ink-mute);
font-size: 14px;
}
.plugin-card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 16px;
margin-top: 24px;
}
.plugin-card-grid.compact { margin-top: 22px; }
.plugin-card-grid.compact .plugin-card {
min-height: 280px;
padding: 20px;
}
.plugin-card {
min-height: 430px;
display: flex;
flex-direction: column;
gap: 14px;
min-width: 0;
padding: 14px 16px 16px;
border: 1px solid var(--line);
border-radius: 8px;
background: rgba(247, 241, 222, 0.66);
box-shadow: 0 18px 36px -30px rgba(21, 20, 15, 0.22);
overflow: hidden;
transition: transform 180ms ease, background 180ms ease, border-color 180ms ease;
}
.plugin-card:hover {
transform: translateY(-2px);
border-color: rgba(21, 20, 15, 0.24);
background: rgba(247, 241, 222, 0.82);
}
.plugin-card[hidden] { display: none; }
.plugin-card__preview {
position: relative;
display: block;
aspect-ratio: 16 / 10;
overflow: hidden;
border: 1px solid rgba(21, 20, 15, 0.13);
border-radius: 7px;
background: #17213a;
color: inherit;
text-decoration: none;
}
.plugin-card__preview img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.plugin-card__mock {
position: absolute;
inset: 0;
display: block;
background:
linear-gradient(90deg, rgba(255, 255, 255, 0.08) 1px, transparent 1px) 0 0 / 42px 42px,
linear-gradient(180deg, rgba(255, 255, 255, 0.07) 1px, transparent 1px) 0 0 / 42px 42px,
#12224a;
}
.plugin-card__mock span {
position: absolute;
display: block;
background: rgba(247, 241, 222, 0.9);
}
.plugin-card__mock span:nth-child(1) {
left: 9%;
top: 18%;
width: 58%;
height: 24px;
}
.plugin-card__mock span:nth-child(2) {
left: 9%;
top: 42%;
width: 76%;
height: 8px;
opacity: 0.7;
}
.plugin-card__mock span:nth-child(3) {
right: 9%;
bottom: 16%;
width: 24%;
height: 42px;
background: var(--coral);
}
.plugin-card__preview--image { background: #d0b169; }
.plugin-card__preview--image .plugin-card__mock {
background:
linear-gradient(135deg, rgba(21, 20, 15, 0.2), transparent 55%),
#d9b86f;
}
.plugin-card__preview--video { background: #15140f; }
.plugin-card__preview--video .plugin-card__mock {
background:
linear-gradient(90deg, rgba(237, 111, 92, 0.42) 0 18%, transparent 18% 82%, rgba(237, 111, 92, 0.42) 82%),
#15140f;
}
.plugin-card__preview--dashboard .plugin-card__mock {
background:
linear-gradient(90deg, rgba(21, 20, 15, 0.08) 1px, transparent 1px) 0 0 / 32px 32px,
linear-gradient(180deg, rgba(21, 20, 15, 0.08) 1px, transparent 1px) 0 0 / 32px 32px,
#eff2e6;
}
.plugin-card__preview--system .plugin-card__mock {
background:
linear-gradient(90deg, rgba(247, 241, 222, 0.08) 1px, transparent 1px) 0 0 / 28px 28px,
#273324;
}
.plugin-card__preview--atom .plugin-card__mock {
background:
linear-gradient(90deg, rgba(21, 20, 15, 0.08) 1px, transparent 1px) 0 0 / 38px 100%,
#f1e5c5;
}
.plugin-card__preview--workflow .plugin-card__mock {
background:
linear-gradient(135deg, rgba(237, 111, 92, 0.2), transparent 46%),
#eee2c3;
}
.plugin-card__preview-label {
position: absolute;
left: 10px;
right: 10px;
bottom: 10px;
display: block;
max-width: calc(100% - 20px);
padding: 7px 9px;
border: 1px solid rgba(21, 20, 15, 0.12);
border-radius: 999px;
background: rgba(247, 241, 222, 0.88);
color: var(--ink-soft);
font: 700 10px var(--body);
text-transform: uppercase;
letter-spacing: 0.08em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.plugin-card__meta,
.plugin-card__footer,
.plugin-detail__badges {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.plugin-card__meta {
justify-content: space-between;
color: var(--ink-faint);
font: 500 12px var(--mono);
}
.plugin-badge,
.plugin-detail__badges span {
display: inline-flex;
align-items: center;
min-height: 28px;
padding: 0 10px;
border: 1px solid var(--line);
border-radius: 999px;
color: var(--ink-soft);
background: rgba(255, 255, 255, 0.24);
font: 700 11px var(--body);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.plugin-badge--official {
color: #6f2c1f;
border-color: rgba(237, 111, 92, 0.35);
background: rgba(237, 111, 92, 0.14);
}
.plugin-badge--community {
color: #454c20;
border-color: rgba(110, 116, 72, 0.38);
background: rgba(110, 116, 72, 0.14);
}
.plugin-card h3 {
min-width: 0;
font-family: var(--serif);
font-size: 28px;
line-height: 1.04;
letter-spacing: 0;
overflow-wrap: anywhere;
}
.plugin-card h3 a,
.plugin-card__footer a,
.plugin-back-link,
.plugin-source-list a {
color: inherit;
text-decoration-color: rgba(21, 20, 15, 0.28);
text-underline-offset: 4px;
}
.plugin-card code,
.plugin-detail__commands code,
.plugin-detail__facts dd {
font-family: var(--mono);
font-size: 12px;
overflow-wrap: anywhere;
}
.plugin-card p {
color: var(--ink-mute);
line-height: 1.6;
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
.plugin-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: auto;
}
.plugin-tags span {
display: inline-flex;
align-items: center;
min-height: 28px;
padding: 0 10px;
border: 1px solid var(--line-soft);
border-radius: 999px;
color: var(--ink-mute);
background: rgba(255, 255, 255, 0.2);
font-size: 12px;
}
.plugin-tags--large {
margin-top: 22px;
}
.plugin-tags--large span {
min-height: 34px;
font-size: 13px;
}
.plugin-card__footer {
justify-content: space-between;
margin-top: 4px;
padding-top: 14px;
border-top: 1px solid var(--line-soft);
color: var(--ink-mute);
font-size: 13px;
}
.plugin-back-link {
display: inline-flex;
margin-bottom: 24px;
color: var(--ink-mute);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 12px;
}
.plugin-detail__commands {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: stretch;
max-width: 720px;
margin-top: 34px;
padding: 12px;
border: 1px solid var(--line);
border-radius: 8px;
background: rgba(21, 20, 15, 0.05);
}
.plugin-detail__commands.compact {
display: block;
max-width: none;
margin-top: 28px;
}
.plugin-detail__commands div {
display: grid;
gap: 4px;
min-width: 0;
}
.plugin-detail__commands span {
color: var(--ink-mute);
font: 700 11px var(--body);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.plugin-detail__commands button {
min-width: 86px;
border: 1px solid rgba(237, 111, 92, 0.36);
border-radius: 8px;
background: var(--coral);
color: #fff;
font: 700 13px var(--body);
cursor: pointer;
}
.plugin-detail-side {
display: grid;
gap: 16px;
min-width: 0;
}
.plugin-detail-preview {
overflow: hidden;
}
.plugin-detail-preview__head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 13px 14px;
border-bottom: 1px solid var(--line-soft);
color: var(--ink-mute);
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.plugin-detail-preview__head small {
color: var(--ink-faint);
font: inherit;
}
.plugin-detail-preview__frame {
position: relative;
aspect-ratio: 16 / 10;
overflow: hidden;
background: #121f42;
}
.plugin-detail-preview__frame iframe,
.plugin-detail-preview__frame img {
display: block;
border: 0;
}
.plugin-detail-preview__frame iframe {
width: 1080px;
height: 675px;
transform: scale(0.48);
transform-origin: top left;
}
.plugin-detail-preview__frame img {
width: 100%;
height: 100%;
}
.plugin-detail-preview__frame img {
object-fit: cover;
}
.plugin-detail-preview__mock {
position: absolute;
inset: 0;
background:
linear-gradient(90deg, rgba(247, 241, 222, 0.12) 1px, transparent 1px) 0 0 / 44px 44px,
linear-gradient(180deg, rgba(247, 241, 222, 0.1) 1px, transparent 1px) 0 0 / 44px 44px,
#121f42;
}
.plugin-detail-preview__mock span {
position: absolute;
display: block;
background: rgba(247, 241, 222, 0.9);
}
.plugin-detail-preview__mock span:nth-child(1) {
left: 9%;
top: 20%;
width: 56%;
height: 42px;
}
.plugin-detail-preview__mock span:nth-child(2) {
left: 9%;
top: 42%;
width: 72%;
height: 10px;
opacity: 0.74;
}
.plugin-detail-preview__mock span:nth-child(3) {
right: 9%;
bottom: 14%;
width: 22%;
height: 64px;
background: var(--coral);
}
.plugin-detail-preview--image .plugin-detail-preview__frame { background: #d9b86f; }
.plugin-detail-preview--video .plugin-detail-preview__frame { background: #15140f; }
.plugin-detail-preview--dashboard .plugin-detail-preview__frame { background: #eff2e6; }
.plugin-detail-preview--system .plugin-detail-preview__frame { background: #263223; }
.plugin-detail-preview--atom .plugin-detail-preview__frame { background: #f1e5c5; }
.plugin-detail__facts {
padding: 22px;
}
.plugin-detail__facts dl {
display: grid;
gap: 18px;
}
.plugin-detail__facts div {
display: grid;
gap: 4px;
padding-bottom: 14px;
border-bottom: 1px solid var(--line-soft);
}
.plugin-detail__facts div:last-child {
padding-bottom: 0;
border-bottom: 0;
}
.plugin-detail__facts dt {
color: var(--ink-mute);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.plugin-detail-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.plugin-detail-panel--wide {
grid-column: 1 / -1;
}
.plugin-detail-panel {
padding: 26px;
}
.plugin-example-query {
max-height: 260px;
margin-top: 24px;
padding: 18px;
overflow: auto;
border: 1px solid var(--line-soft);
border-radius: 8px;
background: rgba(21, 20, 15, 0.05);
color: var(--ink-soft);
font: 12px/1.7 var(--mono);
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.plugin-source-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 28px;
}
.plugin-source-list a {
display: inline-flex;
align-items: center;
min-height: 40px;
padding: 0 14px;
border: 1px solid var(--line);
border-radius: 999px;
background: rgba(255, 255, 255, 0.18);
font-weight: 700;
text-decoration: none;
}
.plugin-related {
padding-top: 72px;
}
@media (max-width: 980px) {
.plugin-hero__grid,
.plugin-detail-hero__grid,
.plugin-toolbar,
.plugin-detail-grid {
grid-template-columns: 1fr;
}
.plugin-hero__panel {
max-width: 640px;
}
}
@media (max-width: 640px) {
.plugin-hero,
.plugin-detail-hero {
padding: 72px 0 52px;
}
.plugin-hero h1,
.plugin-detail h1 {
font-size: clamp(40px, 12vw, 58px);
}
.plugin-hero p,
.plugin-detail-hero p,
.plugin-detail-panel p {
font-size: 16px;
}
.plugin-hero__panel {
max-width: none;
}
.plugin-hero__stats {
grid-template-columns: 1fr;
}
.plugin-card-grid {
grid-template-columns: 1fr;
}
.plugin-card {
min-height: auto;
}
.plugin-card__preview {
aspect-ratio: 16 / 9;
}
.plugin-detail-preview__frame {
aspect-ratio: 16 / 9;
}
.plugin-detail-preview__frame iframe {
width: 1120px;
height: 630px;
transform: scale(0.32);
}
.plugin-detail__commands {
grid-template-columns: 1fr;
}
.plugin-detail__commands button {
min-height: 44px;
}
}