Files
pbakaus_impeccable/site/styles/home-rebuild.css
T
373039a837 Give DESIGN.md a real type ramp so the design hook stops crying wolf (#390)
* Give DESIGN.md a real type ramp so the design hook stops crying wolf

The design hook fired on nearly every CSS file we touched. The cause was
DESIGN.md's typography block: it declared seven named roles rather than a
scale, and two of those roles used clamp(), which the extractor skipped
outright. That left an allowlist of five sizes standing against the 86
distinct font sizes actually in use, so design-system-font-size flagged
roughly 500 declarations. Editing any .astro page made it worse, because
the companion-stylesheet scan re-reported the whole backlog.

Extractor (cli/engine/design-system.mjs):
- Read a typography.scale map as the enumerated ramp.
- Read both clamp() endpoints as allowed sizes. These stay additive on
  purpose: clamp endpoints alone cannot switch the rule on, because a fully
  fluid system enumerates no discrete ramp and inferring one from its
  endpoints would flag every intermediate size. The existing abstention
  test still passes, and three new tests cover the added behavior.

DESIGN.md:
- Document a 19-step ramp, 8px through 72px at a 16px root.
- Snap the five discrete role sizes onto ramp steps.

This also fixes real drift. DESIGN.md claims to mirror kinpaku-tokens.css
verbatim, but wordmark was 1.15rem in the CSS against 1.3rem documented,
with tracking at 0.42em against 0.15em. Both are re-synced.

Standardization, 64 declarations:
- Six near-identical steps between 13.7px and 15.4px collapse onto 14 and 15.
- .foundation-card-label, .designing-lane-mock-title and
  .designing-iterate-name each existed at two different sizes in two files.
  Now unified.
- The wordmark rendered at four sizes (20.8, 18.4, 17, 16.8px). Now 18px,
  plus one deliberate smaller nav variant.

Exemptions, for designs that are foreign on purpose: the antipattern-example
fixtures, the neo-mirai case-study build, the periodic-table cell
annotations in framework-viz.js (5 to 7px diagram geometry sitting at 2 to
3px offsets), and the .why-slop-* before-state card's Inter and gradient
text.

Verified by computed style across ten rendered pages: every element lands on
a ramp step except clamp() values mid-interpolation, which is what fluid
means. Full test suite and build validators pass.

Generated provider output is deliberately left out; the sync workflow owns it.

Prepared with AI assistance (Claude Code).

Co-Authored-By: Claude <noreply@anthropic.com>

* Validate clamp() endpoints in usage, not just when reading DESIGN.md

Reading clamp endpoints as documented steps without also checking them in
source left an asymmetry: `isAllowedFontSizeRaw` returned true for anything
failing the px/rem literal test, so `clamp(99rem, 1vw, 200rem)` passed. That
is how `.ptable-symbol` at `clamp(1.45rem, 1.8vw, 1.8rem)` stayed invisible
until someone measured computed styles, which is not a check the hook can run.

Fluid values are now judged on their min and max. The viewport term
interpolates between them and is never a fixed step, so it is left alone.
Endpoints that cannot be resolved, such as var() or calc() or em, abstain
rather than guess. Findings name the offending endpoint and use it as the
ignore-value, because the whole clamp string is not actionable on its own.

Turning the check on surfaced 22 fluid declarations that had never been
looked at. Three used hero sizes above the ramp's 72px cap (80, 83.2 and
88px) alongside the display role's documented 89.6px max, so the top of the
ramp was genuinely incomplete. Added the 80 and 88 steps, which gives the
display end consistent 8px increments instead of 48/56/64/72 plus an orphan
at 89.6, and fixes two declarations outright.

The other 20 are snapped by a stated rule: nearest step, ties toward the
smaller step, endpoints already matching a documented fluid role left as-is,
and where nearest-step would make a breakpoint override meet or exceed its
base, the next smaller step so the override still reduces. That last case
applies once, to .designing-page-title.

Also narrows the framework-viz.js waiver. The periodic-table cell
annotations now carry two `impeccable-disable-line` comments naming the
reason, instead of a config entry wildcarding the whole file for the rule.
Inline waivers travel with the code and cannot silence future drift
elsewhere in that file.

Verified at 420px, 900px and 1600px across seven pages. The pinned ends are
fully on-ramp; the only off-ramp values at 900px are the vw term
mid-interpolation, which is what fluid means.

Prepared with AI assistance (Claude Code).

Co-Authored-By: Claude <noreply@anthropic.com>

* Address review: wordmark tracking picked the wrong side, stale ramp count

Two review findings, both fair.

Wordmark tracking (greptile, bugbot). This PR moved DESIGN.md's wordmark
letterSpacing from 0.15em to 0.42em on the grounds that DESIGN.md claims to
mirror kinpaku-tokens.css and the token read 0.42em. That was the wrong side
to trust. `--ks-type-wordmark-track` has exactly one consumer,
design-system.css:570, which is the specimen page. Every production lockup
(.ks-wordmark, .kinpaku-chrome .site-header-brand-name, .footer-logo)
hardcodes 0.15em, so 0.15em is what every visitor actually sees and what
DESIGN.md already documented correctly before this PR touched it.

Reverted the doc to 0.15em and moved the token to 0.15em as well, so the
specimen now renders the same lockup as production instead of a wider one
nothing else uses. Verified by computed style: header and specimen both
report 18px with 2.7px tracking. No production visual change.

Stale ramp count (copilot). The sidecar described an "18-step ramp, 8px
through 72px". It went stale twice inside this PR, once when the 8 step was
added and again when 80 and 88 were added for the hero display sizes. It is
21 steps, 8px through 88px.

Prepared with AI assistance (Claude Code).

Co-Authored-By: Claude <noreply@anthropic.com>

* Strip !important from the font-size ignore value

Follow-on from the waiver wiring in the hook branch. The ignoreValue is what a
`hooks ignore-value` waiver has to match, and `font-size: 1.4rem !important`
emitted `1.4rem !important` while a plain declaration emitted `1.4rem`. Once
font-size is a direct-value rule, that means the same size needs two different
waivers depending on whether it carries a priority marker.

font-family already strips the marker before matching, and there is a test for
that. font-size now does the same. The snippet still shows the declaration as
authored.

Prepared with AI assistance (Claude Code).

Co-Authored-By: Claude <noreply@anthropic.com>

* Have the wordmark rules consume their tokens instead of copying the values

Follow-up to the tracking fix, and the residual half of what the reviewers
were pointing at. `.ks-wordmark` and the kinpaku chrome lockup each repeated
`1.125rem` and `0.15em` literally rather than reading
`--ks-type-wordmark-size` and `--ks-type-wordmark-track`. That duplication is
exactly how the token drifted to 0.42em while every production lockup stayed
at 0.15em and nobody noticed, which is the confusion that started this thread.

The values already agree, so this is a no-op visually and is verified as such:
computed styles across the home, design-system, docs and changelog pages all
still report 18px with 2.7px tracking. What changes is that there is now one
place to edit, so the next tracking change cannot silently apply to the
specimen page alone.

Prepared with AI assistance (Claude Code).

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-19 20:39:55 -07:00

2204 lines
64 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.
/* ============================================================================
Homepage rebuild: hero + slop teaser
Built to match the /design-system aesthetic (neo kinpaku).
Loaded after home-kinpaku.css so these rules win on the rebuilt sections.
All brand tokens (--ks-kinpaku, --ks-kinpaku-pale, --ks-patina, etc.) come
from kinpaku-tokens.css via home-kinpaku.css's import — no duplicate
declarations here.
============================================================================ */
/* ============================================================================
HERO REBUILD
============================================================================ */
/* The header overlays the hero (see .home-kinpaku .site-header below), so the
hero fills the full viewport and its art runs to the very top, behind the
transparent nav — the /design-system topbar treatment. */
.hero-rebuild {
position: relative;
/* Leave ~115px of the testimonials section visible above the fold
(dotted divider + first row's top edge). Without this the hero
fills the entire viewport and the testimonials read as out of sight. */
min-height: calc(100svh - 115px);
display: grid;
align-items: center;
/* Top padding clears the fixed (overlay) header (97px). On short viewports the
hero grows to fit its content and pins it at this padding-top, so the demo
never tucks under the nav; on tall viewports the content still centers. */
padding: 113px 0 96px;
overflow: hidden;
/* Hairline divider into the testimonials below, matching the testimonial
card border color. */
border-bottom: 1px solid oklch(0.64 0 0 / 0.22);
}
/* Header sits on top of the hero image like the /design-system topbar:
transparent over the hero, then glassing in as you scroll. Pinned (fixed) so
it overlays the hero without taking flow space. Overrides the sticky light
bar from sub-pages.css.
--hp is the scroll progress (0 at the top → 1 once past the hero top), set
px-by-px from app.js, so the glass interpolates continuously rather than
snapping. */
.home-kinpaku .site-header {
--hp: 0;
position: fixed;
top: 0;
left: 0;
right: 0;
background: oklch(8% 0.006 95 / calc(0.72 * var(--hp)));
border-bottom: 1px solid oklch(78% 0.12 82 / calc(0.18 * var(--hp)));
-webkit-backdrop-filter: saturate(calc(1 + 0.3 * var(--hp))) blur(calc(16px * var(--hp)));
backdrop-filter: saturate(calc(1 + 0.3 * var(--hp))) blur(calc(16px * var(--hp)));
}
/* The wide-viewport seam treatment is light-only and lives in light-mode.css.
Dark mode needs none: the cream nav text reads fine over the darker seam. */
.hero-rebuild-art {
position: absolute;
inset: 0;
z-index: 0;
background:
url("/assets/neo-kinpaku/candidates/finalists/m-01-v2-01.png") center / cover no-repeat;
filter: saturate(1.2) contrast(1.08);
}
/* Mirror .site-content's container math so the hero text aligns horizontally
with every other section's content edge. */
.hero-rebuild-container {
position: relative;
z-index: 1;
max-width: 1500px;
margin: 0 auto;
padding: 0 56px;
width: 100%;
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 0.95fr);
gap: 72px;
align-items: center;
}
.hero-rebuild-left {
display: grid;
gap: 28px;
align-content: center;
max-width: 620px;
}
.home-kinpaku .hero-rebuild-title {
margin: 0;
color: var(--ks-champagne);
font-family: var(--ks-font-display);
font-weight: 100;
font-size: clamp(3.4rem, 6.5vw, 5.6rem);
line-height: 1.02;
letter-spacing: -0.01em;
}
.hero-rebuild-body {
margin: 0;
color: var(--ks-text);
font-size: 1rem;
line-height: 1.6;
font-weight: 300;
max-width: 56ch;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
.hero-rebuild-actions {
display: flex;
flex-wrap: wrap;
gap: 14px;
margin-top: 4px;
}
/* Hero CTAs migrated to .ks-button.ks-button-primary / .ks-button-secondary
(see kinpaku-kit.css). The .hero-rebuild-arrow class is gone too — the
arrow now lives in .ks-button-arrow inside the button.
"How it works" is the kit ghost variant: plain champagne (white) text, no
border or fill, hovering to gold. */
.hero-rebuild-meta {
margin: 24px 0 0;
color: var(--ks-muted);
font-size: 0.86rem;
line-height: 1.5;
max-width: 52ch;
}
.hero-rebuild-logos {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 14px;
margin-top: 4px;
}
.home-kinpaku .hero-rebuild-logo {
display: inline-grid;
place-items: center;
width: 24px;
height: 24px;
border: 0;
border-radius: 0;
background: transparent;
opacity: 0.72;
transition: opacity 180ms var(--ks-ease), transform 180ms var(--ks-ease);
}
.home-kinpaku .hero-rebuild-logo img {
width: 22px;
height: 22px;
object-fit: contain;
opacity: 0.78;
filter: grayscale(1) saturate(0) invert(1) brightness(1.18) contrast(0.72);
transition: opacity 180ms var(--ks-ease), filter 180ms var(--ks-ease);
}
/* Pi's source SVG is already white-on-transparent, so the row's default
invert(1) filter would turn it black (invisible against the lacquer
hero). Skip the filter entirely; the asset is already on-brand. */
.home-kinpaku .hero-rebuild-logo[data-tooltip="Pi"] img {
filter: none;
}
.home-kinpaku .hero-rebuild-logo:hover,
.home-kinpaku .hero-rebuild-logo:focus-visible {
opacity: 1;
transform: translateY(-1px);
}
.home-kinpaku .hero-rebuild-logo:hover img,
.home-kinpaku .hero-rebuild-logo:focus-visible img {
opacity: 1;
filter: none;
}
/* GitHub Copilot and Codex CLI logos are dark monochrome glyphs. The row's
default invert filter makes them readable; removing it on hover would put
them back to dark-on-dark, which is invisible. Keep them inverted on
hover — they don't have a brand color to restore. */
.home-kinpaku .hero-rebuild-logo[data-tooltip="GitHub Copilot"]:hover img,
.home-kinpaku .hero-rebuild-logo[data-tooltip="GitHub Copilot"]:focus-visible img,
.home-kinpaku .hero-rebuild-logo[data-tooltip="Codex CLI"]:hover img,
.home-kinpaku .hero-rebuild-logo[data-tooltip="Codex CLI"]:focus-visible img {
filter: grayscale(1) saturate(0) invert(1) brightness(1.18);
}
/* Right column hosts the existing split comparison */
.hero-rebuild-right {
position: relative;
width: 100%;
max-width: 720px;
justify-self: end;
}
/* The .home-kinpaku .split-container rule caps width/height for the magazine
spread. Inside the hero rebuild we want the demo to fill the right column,
so override both caps here. Higher specificity wins. */
.home-kinpaku .hero-rebuild-right .split-comparison {
max-width: 100%;
}
.home-kinpaku .hero-rebuild-right .split-container {
max-width: 100%;
height: 440px;
}
/* problem-section.css applies @keyframes splitEntry to every .split-divider
with a baked-in skewX(-10deg) in the from/to transforms. That keyframe
transform overrides our flat translateX(-50%) for the 0.9s animation
window, producing a visible "skewed-then-corrects" effect on first paint.
Disable the animation here — the home kinpaku divider doesn't need an
entry effect. */
.home-kinpaku .hero-rebuild-right .split-divider {
animation: none;
}
/* The category labels under the demo ("Generic AI output" / "With Impeccable")
need to stay readable on the vibrant kinpaku-leaf hero. Localized frosted
pills behind each label only — backdrop stays full-color elsewhere. */
.home-kinpaku .hero-rebuild-right .split-labels {
margin-top: 18px;
}
.home-kinpaku .hero-rebuild-right .split-label-item {
display: inline-flex;
align-items: center;
gap: 9px;
padding: 7px 14px;
background: oklch(4% 0.004 95 / 0.72);
backdrop-filter: blur(8px) saturate(1.4);
-webkit-backdrop-filter: blur(8px) saturate(1.4);
border: 1px solid var(--ks-rule);
border-radius: 2px;
font-size: 0.72rem;
letter-spacing: 0.14em;
font-weight: 500;
color: var(--ks-champagne);
}
.home-kinpaku .hero-rebuild-right .split-label-item[data-point="after"] {
color: var(--ks-kinpaku);
border-color: oklch(78% 0.12 82 / 0.45);
}
@media (max-width: 1080px) {
.hero-rebuild { padding: 108px 36px 80px; } /* keep top clear of the fixed header */
/* minmax(0, 1fr), not 1fr: a plain 1fr track has an `auto` (min-content)
floor, so the demo's 460px-wide browser frame held the column wider than a
phone viewport and the hero clipped. minmax(0,…) lets it shrink and the
frame clips its own content (overflow:hidden) instead. */
.hero-rebuild-container { grid-template-columns: minmax(0, 1fr); gap: 48px; }
.hero-rebuild-right { justify-self: stretch; max-width: 100%; }
.home-kinpaku .hero-rebuild-right .split-container { height: 380px; }
}
@media (max-width: 720px) {
.hero-rebuild { padding: 92px 24px 64px; } /* clear the compact mobile header */
/* The hero's 24px gutter is the mobile margin now; the container's desktop
56px padding stacked on top of it (160px of chrome) starved the content and
forced the grid track wider than the viewport. Drop it on mobile. */
.hero-rebuild-container { padding-left: 0; padding-right: 0; }
/* Title keeps its design-system clamp (floors at 3.4rem ≈ 54px here): the
Alumni Sans display face is narrow, so "interfaces" stays well within a
320px+ viewport. No mobile shrink — at 54px against 16.8px body it holds a
~3.2× hero hierarchy; shrinking it made the heading read smaller than body. */
.hero-rebuild-actions { flex-direction: column; align-items: stretch; }
.home-kinpaku .hero-rebuild-right .split-container { height: 320px; }
/* The hotel mock is authored ~460px wide; in the narrow mobile frame its full
nav (logo + 4 links + Book) overran the right edge and clipped mid-word.
Collapse to logo + Book — the realistic narrow-viewport nav, and it keeps
the hero (the picked element) as the demo's clear subject. */
.hero-live-demo .hotel-nav-links { display: none; }
}
/* ============================================================================
CATCH THE SLOP TEASER
============================================================================ */
.slop-teaser-section {
padding: 120px 0;
}
.slop-teaser-head {
display: grid;
gap: 18px;
max-width: 760px;
margin-bottom: 64px;
}
.slop-teaser-eyebrow {
margin: 0;
color: var(--ks-kinpaku);
font-family: var(--ks-mono);
font-size: 0.72rem;
letter-spacing: 0.28em;
text-transform: uppercase;
}
.home-kinpaku .slop-teaser-title {
margin: 0;
color: var(--ks-champagne);
font-family: var(--ks-font-display);
font-weight: var(--ks-type-headline-weight);
font-size: clamp(2.6rem, 4vw, 3.4rem);
line-height: 1.04;
letter-spacing: -0.005em;
}
.slop-teaser-body {
margin: 0;
color: var(--ks-text);
font-size: 1.02rem;
line-height: 1.6;
/* Weight 400 + explicit smoothing for the same reason .hero-rebuild-body
uses them: Avenir Next Light (weight 300) isn't installed on every system,
so the browser synthesizes it from the regular face and the anti-aliasing
goes splotchy. Weight 400 with explicit smoothing renders cleanly. */
font-weight: 400;
max-width: 60ch;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
.slop-teaser-numerics {
display: inline-block;
margin-left: 8px;
color: var(--ks-muted);
font-family: var(--ks-mono);
font-size: 0.82rem;
letter-spacing: 0.04em;
}
/* Gallery: horizontal scroller of antipattern thumbnails */
.slop-teaser-gallery {
position: relative;
margin: 0 0 56px;
}
.slop-teaser-track {
display: flex;
gap: 18px;
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
padding: 4px 4px 18px;
margin: 0 -4px;
}
.slop-teaser-track::-webkit-scrollbar { display: none; }
.home-kinpaku .slop-teaser-card {
flex: 0 0 320px;
scroll-snap-align: start;
display: grid;
grid-template-rows: auto auto;
text-decoration: none;
background: var(--ks-lacquer-raised);
border: 1px solid var(--ks-rule);
border-radius: 2px;
overflow: hidden;
transition: border-color 180ms var(--ks-ease), transform 220ms var(--ks-ease);
position: relative;
}
.home-kinpaku .slop-teaser-card:hover {
border-color: var(--ks-kinpaku);
transform: translateY(-2px);
}
.slop-teaser-thumb {
position: relative;
aspect-ratio: 16 / 10;
overflow: hidden;
background: oklch(13% 0.008 290);
}
.slop-teaser-thumb img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: top left;
display: block;
transition: transform 360ms var(--ks-ease);
}
.home-kinpaku .slop-teaser-card:hover .slop-teaser-thumb img {
transform: scale(1.03);
}
/* Marker scribble across the thumbnail, evoking "caught" */
.slop-teaser-thumb::after {
content: "";
position: absolute;
inset: 0;
background:
repeating-linear-gradient(135deg, transparent 0 22px, oklch(58% 0.15 35 / 0.04) 22px 23px),
linear-gradient(180deg, transparent 60%, oklch(4% 0.004 95 / 0.55));
pointer-events: none;
}
.slop-teaser-meta {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 12px;
padding: 14px 16px;
border-top: 1px solid var(--ks-rule);
}
.slop-teaser-cat {
color: var(--ks-kinpaku);
font-family: var(--ks-mono);
font-size: 0.62rem;
letter-spacing: 0.22em;
text-transform: uppercase;
}
.home-kinpaku .slop-teaser-card strong {
color: var(--ks-champagne);
font-family: var(--ks-font);
font-weight: 400;
font-size: 1rem;
line-height: 1.2;
}
.slop-teaser-flag {
color: oklch(58% 0.15 35);
font-family: var(--ks-mono);
font-size: 0.62rem;
letter-spacing: 0.22em;
border: 1px solid oklch(58% 0.15 35);
padding: 2px 8px;
border-radius: 2px;
}
/* Gallery nav buttons */
.slop-teaser-arrow {
position: absolute;
top: 38%;
width: 40px;
height: 40px;
display: grid;
place-items: center;
border: 1px solid var(--ks-rule);
background: oklch(8% 0.006 95 / 0.92);
color: var(--ks-kinpaku);
border-radius: 999px;
cursor: pointer;
transition: border-color 180ms var(--ks-ease), color 180ms var(--ks-ease);
}
.slop-teaser-arrow:hover { border-color: var(--ks-kinpaku); }
.slop-teaser-arrow svg { width: 12px; height: 20px; }
.slop-teaser-arrow--prev { left: -20px; }
.slop-teaser-arrow--next { right: -20px; }
@media (max-width: 720px) {
.slop-teaser-card { flex: 0 0 80%; }
.slop-teaser-arrow { display: none; }
}
.slop-teaser-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 24px;
margin-top: 14px;
}
.home-kinpaku .slop-teaser-cta-primary {
display: inline-flex;
align-items: center;
gap: 14px;
color: var(--ks-kinpaku);
font-size: 1rem;
font-weight: 400;
text-decoration: none;
padding-bottom: 4px;
border-bottom: 1px solid var(--ks-kinpaku);
transition: gap 180ms var(--ks-ease);
}
.home-kinpaku .slop-teaser-cta-primary:hover {
gap: 18px;
color: var(--ks-kinpaku);
}
.slop-teaser-cta-primary svg {
width: 16px;
height: 8px;
flex: none;
}
/* Scoped against the global .home-kinpaku code color override using the
chained selector (.home-kinpaku code.slop-teaser-cli has higher specificity
than .home-kinpaku code alone). Keeps the CLI block in the softer code-gold
so the line reads as a terminal command, not a pumpkin headline. */
.home-kinpaku code.slop-teaser-cli {
color: var(--ks-code-block-fg);
font-family: var(--ks-mono);
font-size: 0.86rem;
background: var(--ks-code-block-bg);
padding: 10px 16px;
border: 1px solid var(--ks-code-block-border);
border-radius: var(--ks-code-block-radius);
user-select: all;
}
@media (max-width: 1080px) {
.slop-teaser-section { padding: 80px 0; }
.slop-teaser-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
.slop-teaser-section { padding: 64px 0; }
.slop-teaser-grid { grid-template-columns: 1fr; }
.slop-teaser-actions { flex-direction: column; align-items: stretch; }
.slop-teaser-cli { text-align: center; }
}
/* ============================================================================
LIVE SECTION — right-aligned intro
The section header and lead paragraph sit flush right so the heavy demo
block below reads as left-anchored to the page, with the intro language
right-anchored above it. (Language section keeps its default left-align;
Get Started below is centered.)
============================================================================ */
.home-kinpaku .live-section .section-header {
text-align: right;
justify-items: end;
}
.home-kinpaku .live-section .section-lead {
margin-left: auto;
text-align: right;
}
/* ============================================================================
GET STARTED REBUILD
============================================================================ */
.downloads-rebuild {
padding: 120px 0;
}
/* The card wrapper holds everything: header, install command, examples,
extras. Plinth surface. The --card-* tokens are kept so inner rules
reference them once and we can re-theme the whole card in one place if
needed later. */
.downloads-rebuild-card {
--card-fg: var(--ks-text);
--card-fg-strong: var(--ks-champagne);
--card-fg-muted: var(--ks-muted);
--card-accent: var(--ks-kinpaku);
--card-cmd-bg: var(--ks-code-block-bg);
--card-cmd-fg: var(--ks-code-block-fg);
--card-copy-border: var(--ks-rule);
--card-copy-fg: var(--ks-kinpaku);
--card-copy-hover-bg: oklch(77% 0.14 82 / 0.08);
--card-link-color: var(--ks-kinpaku);
--card-link-underline: var(--ks-kinpaku);
--card-link-secondary: var(--ks-muted);
/* Command-frame accents. The install box is the primary CTA and carries
kinpaku; the update box carries patina, which in this system reads as the
"improved / updated" state. Both re-theme in light-mode.css. */
--card-cmd-border: var(--ks-kinpaku);
--card-prompt: var(--ks-kinpaku);
--card-cmd-border-update: oklch(70% 0.12 188 / 0.5);
--card-prompt-update: var(--ks-patina);
/* Width of the accent's reserved right column. Content padding-right
matches this so the accent never overlaps text. */
--card-accent-w: 280px;
position: relative;
max-width: 1080px;
margin: 0 auto;
padding: 80px var(--card-accent-w) 80px 56px;
border-radius: 2px;
background: oklch(0.17 0 0);
color: var(--card-fg);
text-align: left;
overflow: hidden;
}
/* Oxidation edge accent — moved here from the footer. Full-bleed on the
right, full opacity (much more glorious than the 0.6 it carried in the
footer). Content gets dedicated padding-right via --card-accent-w above,
so the accent and the content never overlap. */
.downloads-rebuild-card::before {
content: "";
position: absolute;
right: 0;
top: 0;
width: var(--card-accent-w);
height: 100%;
/* `cover` instead of `contain` so the image fills the card's full height —
the source PNG is 1:2 but the card aspect is more like 1:5, so `contain`
bottom-anchored a half-height render. Right-anchored, vertically centered
overflow goes off the left edge (the gold streak lives on the right side
of the image, so cropping there is fine). */
background: url("/assets/neo-kinpaku/oxidation-edge-accent.png") right center / cover no-repeat;
opacity: 1;
pointer-events: none;
z-index: 0;
}
/* Make sure the inner content stacks above the accent. */
.downloads-rebuild-card > * {
position: relative;
z-index: 1;
}
/* Narrow viewports — the accent's reserved column would crush content.
Drop the accent below the lg breakpoint and restore symmetric padding. */
@media (max-width: 980px) {
.downloads-rebuild-card {
padding: 64px 40px;
}
.downloads-rebuild-card::before { display: none; }
}
.downloads-rebuild-head {
display: grid;
gap: 18px;
max-width: 760px;
margin: 0 0 40px;
text-align: left;
justify-items: start;
}
.downloads-rebuild-eyebrow {
margin: 0;
color: var(--ks-kinpaku);
font-family: var(--ks-mono);
font-size: 0.72rem;
letter-spacing: 0.28em;
text-transform: uppercase;
}
.home-kinpaku .downloads-rebuild-title {
margin: 0;
color: var(--card-fg-strong);
font-family: var(--ks-font-display);
font-weight: var(--ks-type-headline-weight);
font-size: clamp(2.6rem, 4vw, 3.4rem);
line-height: 1.04;
}
.downloads-rebuild-install {
display: grid;
gap: 22px;
margin: 0 0 48px;
width: 100%;
max-width: 600px;
min-width: 0;
text-align: left;
}
/* Each command is a labeled group: a small mono cap above its box. */
.downloads-rebuild-cmd-group {
display: grid;
gap: 9px;
min-width: 0;
}
.downloads-rebuild-cmd-label {
font-family: var(--ks-mono);
font-size: 0.7rem;
font-weight: 500;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--card-prompt);
}
.downloads-rebuild-cmd-label--update {
color: var(--card-prompt-update);
}
/* "Install via [impeccable] [marketplace] [skills.sh]" — the method selector
that replaces the static "Install" label. Compact inline tabs that reuse the
design-system ks-tab selected-state language (kinpaku text + underline on the
active tab) beside the mono "Install via" cap. Baseline alignment so the tab
text sits on the same line as the "INSTALL VIA" label; the tabs are
inline-block (not flex) so their text baseline is what the row aligns to, and
marks ride along via vertical-align without dragging the baseline. */
.downloads-rebuild-tabs {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 4px 12px;
}
.downloads-rebuild-tabs-label {
font-family: var(--ks-mono);
font-size: 0.7rem;
font-weight: 500;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--card-prompt);
margin-right: 2px;
}
.downloads-rebuild-tab {
display: inline-block;
border: 0;
background: transparent;
padding: 2px 0 4px;
font-family: var(--ks-mono);
font-size: 0.84rem;
line-height: 1;
color: var(--ks-text-muted);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: color 160ms var(--ks-ease), border-color 160ms var(--ks-ease);
}
.downloads-rebuild-tab:hover { color: var(--ks-champagne); }
/* Brand mark flags the marketplace tab as Claude-tied. Dimmed until the tab is
active so it reads as a quiet qualifier, not a CTA. vertical-align:middle
keeps it centered on the text without shifting the text baseline the row
aligns to. */
.downloads-rebuild-tab-logo {
display: inline-block;
width: 13px;
height: 13px;
margin-right: 5px;
vertical-align: middle;
opacity: 0.7;
transition: opacity 160ms var(--ks-ease);
}
svg.downloads-rebuild-tab-logo {
fill: var(--ks-champagne);
}
.downloads-rebuild-tab:hover .downloads-rebuild-tab-logo,
.downloads-rebuild-tab[aria-selected="true"] .downloads-rebuild-tab-logo {
opacity: 1;
}
/* Persistent "Recommended" cue on the impeccable tab — a small gold star, the
conventional best/featured glyph. Stays visible even when another method is
selected, so the blessed path is always legible, and reads in a fraction of
the width the spelled-out word needed. Accessible name lives on the SVG. */
.downloads-rebuild-tab-rec {
display: inline-block;
width: 11px;
height: 11px;
margin-left: 5px;
vertical-align: middle;
fill: var(--ks-kinpaku);
opacity: 0.9;
}
.downloads-rebuild-tab[aria-selected="true"] {
color: var(--ks-kinpaku);
border-bottom-color: var(--ks-kinpaku);
}
.downloads-rebuild-tab:focus-visible {
outline: 2px solid var(--ks-kinpaku);
outline-offset: 3px;
border-radius: 2px;
}
/* Per-method explainer under the install box — carries the "what you give up"
note for the skills.sh path and the Claude-Code-only caveat for marketplace. */
.downloads-rebuild-method-note {
margin: 9px 0 0;
max-width: 60ch;
font-size: 0.82rem;
line-height: 1.5;
color: var(--ks-text-muted);
}
.home-kinpaku .downloads-rebuild-method-note code {
font-family: var(--ks-mono);
font-size: 0.9em;
color: var(--card-fg-muted);
}
.downloads-rebuild-method-note strong {
color: var(--ks-kinpaku);
font-weight: 600;
cursor: help;
}
/* Marketplace updates from a menu, not a shell command, so its Update slot is
quiet guidance text rather than a runnable box. */
.downloads-rebuild-update-menu {
margin: 0;
font-size: 0.92rem;
line-height: 1.5;
color: var(--card-fg-muted);
padding: 4px 0;
}
.home-kinpaku .downloads-rebuild-update-menu code {
font-family: var(--ks-mono);
color: var(--card-prompt-update);
}
/* Copilot is built in, so it isn't a tab — it's a quiet one-line aside right
under the method tabs, there to catch Copilot users BEFORE they copy an
install command they don't need. Deliberately NOT boxed: a bordered notice
competed with the real command boxes. Plain muted text + small glyph reads as
a footnote, not a step. */
.downloads-rebuild-copilot-note {
display: flex;
align-items: baseline;
gap: 7px;
margin: 6px 0 18px;
max-width: 62ch;
font-size: 0.8rem;
line-height: 1.5;
color: var(--ks-text-muted);
}
.downloads-rebuild-copilot-note-logo {
flex: none;
width: 12px;
height: 12px;
transform: translateY(1px);
fill: currentColor;
opacity: 0.85;
}
.home-kinpaku .downloads-rebuild-copilot-note strong {
color: var(--ks-champagne);
font-weight: 600;
}
/* "Why one command, many builds" — a collapsed disclosure that visualizes the
impeccable source fanning out into a build tailored per harness. The branch
lines draw themselves in when the section opens; the targets fade up behind
them, staggered, so the eye follows source → target. */
.downloads-rebuild-branch {
margin: 16px 0 0;
}
.downloads-rebuild-branch-summary {
display: inline-flex;
align-items: center;
gap: 7px;
cursor: pointer;
list-style: none;
font-size: 0.82rem;
color: var(--ks-text-muted);
transition: color 160ms var(--ks-ease);
}
.downloads-rebuild-branch-summary::-webkit-details-marker { display: none; }
.downloads-rebuild-branch-summary:hover { color: var(--ks-champagne); }
.downloads-rebuild-branch[open] > .downloads-rebuild-branch-summary {
color: var(--card-fg-strong);
margin-bottom: 14px;
}
.downloads-rebuild-branch-arrow {
flex: none;
transition: transform 180ms var(--ks-ease);
}
.downloads-rebuild-branch[open] > .downloads-rebuild-branch-summary .downloads-rebuild-branch-arrow {
transform: rotate(90deg);
}
.downloads-rebuild-branch-diagram {
display: block;
width: 100%;
max-width: 430px;
height: auto;
font-family: var(--ks-mono);
}
/* Connectors: hidden (fully dashed-out) until the section opens, then each
draws from the source node to its target. */
.downloads-rebuild-branch-line {
fill: none;
stroke: color-mix(in oklch, var(--ks-kinpaku) 55%, transparent);
stroke-width: 1.3;
stroke-dasharray: 230;
stroke-dashoffset: 230;
}
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line {
animation: branch-draw 620ms var(--ks-ease) forwards;
}
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line:nth-of-type(1) { animation-delay: 60ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line:nth-of-type(2) { animation-delay: 130ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line:nth-of-type(3) { animation-delay: 200ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line:nth-of-type(4) { animation-delay: 270ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line:nth-of-type(5) { animation-delay: 340ms; }
.downloads-rebuild-branch-root-box {
fill: color-mix(in oklch, var(--ks-kinpaku) 9%, transparent);
stroke: var(--ks-kinpaku);
stroke-width: 1.2;
}
.downloads-rebuild-branch-root-text {
fill: var(--ks-kinpaku);
font-size: 13px;
font-weight: 500;
}
.downloads-rebuild-branch-dot {
fill: var(--ks-kinpaku);
}
.downloads-rebuild-branch-name {
fill: var(--ks-champagne);
font-size: 11.5px;
font-weight: 600;
}
.downloads-rebuild-branch-tags {
fill: var(--ks-text-muted);
font-size: 8.6px;
letter-spacing: 0.01em;
}
/* The model-specific slop rules are the headline of this diagram, so the rows
that carry them light up gold while the plumbing tags stay muted. */
.downloads-rebuild-branch-tags--slop {
fill: var(--ks-kinpaku);
font-weight: 600;
}
/* Targets fade up behind the drawing lines, staggered to match. */
.downloads-rebuild-branch-target {
opacity: 0;
transform: translateX(-5px);
}
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target {
animation: branch-rise 460ms var(--ks-ease) forwards;
}
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target:nth-of-type(1) { animation-delay: 220ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target:nth-of-type(2) { animation-delay: 290ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target:nth-of-type(3) { animation-delay: 360ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target:nth-of-type(4) { animation-delay: 430ms; }
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target:nth-of-type(5) { animation-delay: 500ms; }
.downloads-rebuild-branch-caption {
margin: 12px 0 0;
max-width: 56ch;
font-size: 0.8rem;
line-height: 1.5;
color: var(--ks-text-muted);
}
.home-kinpaku .downloads-rebuild-branch-caption code {
font-family: var(--ks-mono);
font-size: 0.9em;
color: var(--card-fg-muted);
}
@keyframes branch-draw {
to { stroke-dashoffset: 0; }
}
@keyframes branch-rise {
to { opacity: 1; transform: translateX(0); }
}
/* Reduced motion: skip the draw/rise, show the finished diagram immediately. */
@media (prefers-reduced-motion: reduce) {
.downloads-rebuild-branch[open] .downloads-rebuild-branch-line {
animation: none;
stroke-dashoffset: 0;
}
.downloads-rebuild-branch[open] .downloads-rebuild-branch-target {
animation: none;
opacity: 1;
transform: none;
}
}
/* Install command is THE primary CTA of the Get Started section. A full
kinpaku hairline frame + gold prompt glyph + left-aligned mono make it read
as a runnable terminal line, not a decorative chip. Copy button nests on the
right. Full border, not a side-stripe (brand-ban). */
.home-kinpaku .downloads-rebuild-cmd {
display: flex;
align-items: center;
gap: 14px;
width: 100%;
min-width: 0;
box-sizing: border-box;
padding: 15px 14px 15px 22px;
background: var(--card-cmd-bg);
border: 1px solid var(--card-cmd-border);
border-radius: 2px;
}
/* The shell prompt that signals "this is a command you run." Carries the
row's accent (gold for install, patina for update). */
.home-kinpaku .downloads-rebuild-prompt {
flex: none;
font-family: var(--ks-mono);
font-size: 1.125rem;
font-weight: 500;
line-height: 1;
color: var(--card-prompt);
user-select: none;
}
.home-kinpaku .downloads-rebuild-cmd > code {
flex: 1 1 auto;
min-width: 0;
overflow-x: auto;
white-space: nowrap;
color: var(--card-cmd-fg);
font-family: var(--ks-mono);
font-size: 1.22rem;
letter-spacing: 0;
background: transparent;
border: 0;
padding: 0;
user-select: all;
}
/* Update box: same frame, quieter patina accent (the "improved" signal). */
.home-kinpaku .downloads-rebuild-cmd--update {
border-color: var(--card-cmd-border-update);
}
.home-kinpaku .downloads-rebuild-cmd--update .downloads-rebuild-prompt {
color: var(--card-prompt-update);
}
/* Compact icon-only copy button nested inside the cmd box, on the right. */
.home-kinpaku .downloads-rebuild-copy {
flex: none;
position: relative;
display: inline-grid;
place-items: center;
width: 40px;
height: 40px;
border: 1px solid var(--card-copy-border);
background: transparent;
color: var(--card-copy-fg);
border-radius: 2px;
cursor: pointer;
transition:
background 180ms var(--ks-ease),
border-color 180ms var(--ks-ease),
color 180ms var(--ks-ease),
transform 120ms var(--ks-ease);
}
.home-kinpaku .downloads-rebuild-copy:active {
transform: scale(0.96);
}
.home-kinpaku .downloads-rebuild-copy-icon,
.home-kinpaku .downloads-rebuild-check-icon {
grid-area: 1 / 1;
transition:
opacity 140ms var(--ks-ease),
transform 180ms var(--ks-ease);
}
.home-kinpaku .downloads-rebuild-copy-icon {
opacity: 1;
transform: scale(1);
}
.home-kinpaku .downloads-rebuild-check-icon {
opacity: 0;
transform: scale(0.86);
}
.home-kinpaku .downloads-rebuild-check-icon path {
stroke-dasharray: 24;
stroke-dashoffset: 24;
}
.home-kinpaku .downloads-rebuild-copy.copied {
background: var(--card-copy-hover-bg);
border-color: currentColor;
}
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-copy-icon {
opacity: 0;
transform: scale(0.82);
}
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-check-icon {
opacity: 1;
transform: scale(1);
}
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-check-icon path {
animation: downloads-check-draw 260ms var(--ks-ease) forwards;
}
@keyframes downloads-check-draw {
to { stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
.home-kinpaku .downloads-rebuild-copy,
.home-kinpaku .downloads-rebuild-copy-icon,
.home-kinpaku .downloads-rebuild-check-icon {
transition: none;
}
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-check-icon path {
animation: none;
stroke-dashoffset: 0;
}
}
.home-kinpaku .downloads-rebuild-copy span {
/* Hide the "Copy" label — icon carries the meaning. Kept in markup for a11y. */
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
.home-kinpaku .downloads-rebuild-copy:hover {
background: var(--card-copy-hover-bg);
border-color: var(--card-copy-fg);
}
/* Update copy button tracks the patina accent rather than gold. */
.home-kinpaku .downloads-rebuild-cmd--update .downloads-rebuild-copy {
color: var(--card-prompt-update);
}
.home-kinpaku .downloads-rebuild-cmd--update .downloads-rebuild-copy:hover {
background: oklch(70% 0.12 188 / 0.08);
border-color: var(--card-prompt-update);
}
/* "Other install methods" — a quiet disclosure under the primary command.
Native <details> so it works without JS and stays accessible. */
.downloads-rebuild-alts {
margin: 2px 0 0;
text-align: left;
}
.downloads-rebuild-alts-summary {
display: inline-flex;
align-items: center;
gap: 7px;
cursor: pointer;
list-style: none;
font-size: 0.84rem;
color: var(--ks-text-muted);
transition: color 160ms var(--ks-ease);
}
.downloads-rebuild-alts-summary::-webkit-details-marker { display: none; }
.downloads-rebuild-alts-summary:hover { color: var(--ks-patina); }
.downloads-rebuild-alts[open] > .downloads-rebuild-alts-summary {
color: var(--card-fg-strong);
margin-bottom: 18px;
}
.downloads-rebuild-alts-arrow {
flex: none;
transition: transform 180ms var(--ks-ease);
}
.downloads-rebuild-alts[open] > .downloads-rebuild-alts-summary .downloads-rebuild-alts-arrow {
transform: rotate(90deg);
}
.downloads-rebuild-alt + .downloads-rebuild-alt { margin-top: 18px; }
.downloads-rebuild-alt-label {
display: block;
margin-bottom: 7px;
font-size: 0.82rem;
font-weight: 600;
color: var(--card-fg-strong);
}
/* Smaller, quieter command box for the alternatives. */
.home-kinpaku .downloads-rebuild-cmd--alt {
padding: 9px 9px 9px 18px;
gap: 12px;
}
.home-kinpaku .downloads-rebuild-cmd--alt > code { font-size: 0.98rem; }
.home-kinpaku .downloads-rebuild-cmd--alt .downloads-rebuild-copy {
width: 34px;
height: 34px;
}
.downloads-rebuild-alt-note {
display: block;
margin-top: 7px;
font-size: 0.82rem;
line-height: 1.5;
color: var(--ks-text-muted);
}
.downloads-rebuild-alt-note code {
font-family: var(--ks-mono);
font-size: 0.9em;
color: var(--card-fg-muted);
}
.downloads-rebuild-note {
margin: 0;
max-width: 60ch;
text-align: left;
color: var(--card-fg-muted);
font-size: 0.88rem;
line-height: 1.55;
}
.home-kinpaku .downloads-rebuild-note code {
font-family: var(--ks-mono);
font-size: 0.86em;
color: var(--card-fg-strong);
}
/* Quieter than the note — the changelog + FAQ hints sit just under the
primary "works with" line. Patina links so they read as related but
distinct from the kinpaku primary CTA above. */
.downloads-rebuild-secondary {
margin: 6px 0 0;
text-align: left;
font-size: 0.84rem;
color: var(--ks-text-muted);
}
.downloads-rebuild-secondary a {
color: var(--ks-patina);
text-decoration: none;
border-bottom: 1px solid oklch(70% 0.12 188 / 0.35);
}
.downloads-rebuild-secondary a:hover {
color: var(--ks-patina-pale);
border-bottom-color: var(--ks-patina-pale);
}
/* Closing links under the setup extras — workflow + command docs. */
.downloads-rebuild-more {
margin: 28px 0 0;
text-align: left;
font-size: 0.9rem;
color: var(--ks-text-muted);
}
.downloads-rebuild-more a {
color: var(--ks-patina);
text-decoration: none;
border-bottom: 1px solid oklch(70% 0.12 188 / 0.35);
}
.downloads-rebuild-more a:hover {
color: var(--ks-patina-pale);
border-bottom-color: var(--ks-patina-pale);
}
.downloads-rebuild-extras {
list-style: none;
margin: 0;
padding: 40px 0 0;
border-top: 1px solid var(--ks-rule);
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 36px;
max-width: 820px;
}
/* Each cell is a flex column so primary links can be bottom-anchored.
Text is left-aligned within the cell — wrapping paragraphs read better
that way than centered. The grid as a whole stays centered on the page. */
.downloads-rebuild-extras li {
display: flex;
flex-direction: column;
gap: 10px;
text-align: left;
align-items: stretch;
}
.downloads-rebuild-extras strong {
color: var(--card-fg-strong);
font-family: var(--ks-font);
font-weight: 400;
font-size: 1rem;
}
.downloads-rebuild-extras span {
color: var(--card-fg-muted);
font-size: 0.88rem;
line-height: 1.5;
}
.home-kinpaku .downloads-rebuild-extras span code {
background: transparent;
border: 0;
border-radius: 0;
padding: 0;
font-family: var(--ks-mono);
font-size: 0.84rem;
color: var(--card-fg-strong);
}
.home-kinpaku .downloads-rebuild-extras a {
color: var(--card-link-color);
font-size: 0.88rem;
text-decoration: underline;
text-decoration-color: var(--card-link-underline);
text-underline-offset: 4px;
text-decoration-thickness: 1px;
width: fit-content;
transition: color 180ms var(--ks-ease);
}
/* Push the primary link to the bottom of each cell so all three primary
links sit at the same Y. The secondary link follows naturally below. */
.home-kinpaku .downloads-rebuild-extras a:not(.downloads-rebuild-link-secondary) {
margin-top: auto;
}
.home-kinpaku .downloads-rebuild-extras a.downloads-rebuild-link-secondary {
color: var(--card-link-secondary);
text-decoration-color: var(--card-link-secondary);
margin-top: 4px;
}
.home-kinpaku .downloads-rebuild-extras a.downloads-rebuild-link-secondary:hover {
color: var(--card-fg);
text-decoration-color: var(--card-fg);
}
@media (max-width: 1080px) {
.downloads-rebuild { padding: 80px 0; }
.downloads-rebuild-extras { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
.downloads-rebuild { padding: 64px 0; }
.downloads-rebuild-install { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
.home-kinpaku .downloads-rebuild-cmd {
gap: 10px;
padding: 13px 12px 13px 16px;
}
.home-kinpaku .downloads-rebuild-cmd > code {
overflow-x: visible;
white-space: normal;
overflow-wrap: anywhere;
font-size: 0.96rem;
line-height: 1.35;
}
.home-kinpaku .downloads-rebuild-prompt {
font-size: 1rem;
}
.home-kinpaku .downloads-rebuild-copy {
width: 34px;
height: 34px;
}
}
/* ============================================================================
FOUNDATION CARD VISUALIZATIONS (varied per discipline)
Foundation cards use the original animated SVG icons (foundation-animations.js
restored). No extra chrome here.
============================================================================ */
@media (prefers-reduced-motion: reduce) {
.home-kinpaku .slop-teaser-cta-primary {
transition: none;
}
}
/* ============================================================================
Section dividers — varied patterns from /design-system#dividers, so each
transition has its own personality without being noisy. All drawn as a
::before pseudo on the section so no markup change required.
============================================================================ */
.home-kinpaku .slop-teaser-section,
.home-kinpaku .live-section,
.home-kinpaku .language-section,
.home-kinpaku .downloads-rebuild {
position: relative;
/* Override stray border-tops applied by main.css → live-mode.css and any
other transitive imports — section dividers are drawn via ::before. */
border-top: 0;
}
/* The Hero → Slop dot-grid divider previously lived here as a ::before on
.slop-teaser-section. After the testimonials section was inserted between
hero and slop, that divider moved onto .testimonials-section in
testimonials.css. The slop section no longer needs a top divider — its
own padding and the testimonials section above carry the transition. */
/* Slop → Live, Live → Language, Language → Get Started: intentionally no
dividers. The plinth dot grid at the top of Testimonials and the verdigris
dot grid at the top of the footer bracket the section stack — interior
transitions read on layout alone. */
/* ============================================================================
HERO LIVE-MODE DEMO
The Live Mode loop (live-demo.js, #live-demo) now lives in the hero. Override
the section-03 frame proportions — the base frame is 16:9, too short for the
portrait card in the narrow hero column — and give all variants a single
card footprint so the pick-outline hugs them.
============================================================================ */
.hero-live-demo {
display: block; /* override the .live-demo 2-col grid */
width: 100%;
}
.hero-live-demo .live-demo-frame {
aspect-ratio: auto;
/* Height follows content — fixed min was leaving ivory gap under clipped suites. */
height: auto;
max-height: min(540px, calc(100svh - 140px));
max-width: 100%;
}
/* The hero-scoped demo-chrome refinements (crisp outline, neutral chrome dots /
URL, quiet gbar border, crisp active-Pick pill, tighter radii, refined frame
elevation) were promoted into the shared picker chrome in kinpaku-kit.css /
live-mode-kinpaku.css / home-kinpaku.css so /live-mode and the injected
picker (skill/scripts/live-browser.js) match. Nothing hero-specific remains. */
/* The stage holds a full (fake) website now, not a centered card. */
.hero-live-demo .live-demo-stage {
display: block;
padding: 0;
height: auto;
min-height: 0;
overflow: hidden;
}
/* Default .hotel-site is position:absolute; inset:0, which stretches to the tall
stage and paints ivory in the gap below clipped suites. */
.hero-live-demo .hotel-site {
position: relative;
inset: auto;
height: auto;
}
/* The picked element is the hero — a single, full-width, one-of-a-kind block.
Contained with side margins so the pick-outline hugs it inside the frame. */
.hero-live-demo .live-demo-target.hotel-hero-pick {
align-self: stretch;
width: auto;
height: 214px;
min-height: 0;
margin: 16px 18px 0;
}
.hero-live-demo .live-demo-variant {
display: grid;
place-items: stretch;
}
.hero-live-demo .live-demo-variant > .hotel-hero {
width: 100%;
height: 100%;
box-sizing: border-box;
}
/* Suite cards run to the frame bottom; the gbar overlaps their lower edge. */
.hero-live-demo .hotel-suites {
flex: none;
max-height: 132px;
padding: 10px 0 0 22px;
overflow: hidden;
}
.hero-live-demo .hotel-suites-row > .hotel-card {
width: 198px;
height: 226px;
box-sizing: border-box;
flex: none;
}
/* The contextual bar's optional free-text input reads as a placeholder (in the
real picker you type here OR annotate; here the annotation is the input). */
.hero-live-demo [data-demo-input-text]:empty::before {
content: "refine further…";
opacity: 0.5;
}
@media (max-width: 1080px) {
.hero-live-demo { max-width: 460px; margin-inline: auto; }
}
/* ----------------------------------------------------------------------------
The page under the picker: AURELIA, a warm serif boutique-hotel site.
Deliberately the opposite of Impeccable's dark kinpaku aesthetic.
---------------------------------------------------------------------------- */
.hotel-site {
--h-ivory: oklch(96.5% 0.012 84);
--h-sand: oklch(92% 0.02 80);
--h-ink: oklch(31% 0.025 55);
--h-muted: oklch(50% 0.025 55);
--h-green: oklch(43% 0.055 150);
--h-line: oklch(82% 0.02 80);
--h-serif: "Cormorant Garamond", Georgia, serif;
--h-sans: var(--ks-font, system-ui, sans-serif);
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
background: var(--h-ivory);
color: var(--h-ink);
overflow: hidden;
}
.hotel-nav {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 22px;
height: 44px;
flex: none;
border-bottom: 1px solid var(--h-line);
}
.hotel-logo {
font-family: var(--h-serif);
font-weight: 600;
font-size: 18px;
letter-spacing: 0.22em;
color: var(--h-ink);
}
.hotel-nav-links {
display: flex;
gap: 18px;
font-family: var(--h-sans);
font-size: 11px;
letter-spacing: 0.06em;
color: var(--h-muted);
}
.hotel-nav-book {
font-family: var(--h-sans);
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--h-green);
border: 1px solid var(--h-green);
border-radius: 999px;
padding: 5px 13px;
}
/* ----------------------------------------------------------------------------
The hero = the picked element. One shared structure; the slop original is
generic + sans, the three elegant variants are the on-brand fixes.
---------------------------------------------------------------------------- */
.hotel-hero {
position: relative;
display: flex;
align-items: flex-end;
overflow: hidden;
border-radius: 12px;
box-sizing: border-box;
}
.hotel-hero-photo {
position: absolute;
inset: 0;
background:
linear-gradient(to top, oklch(24% 0.03 40 / 0.82), oklch(38% 0.04 40 / 0.12) 58%, transparent),
linear-gradient(150deg, oklch(66% 0.08 60), oklch(48% 0.08 34) 52%, oklch(36% 0.05 255));
}
.hotel-hero-inner {
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 6px;
padding: 22px 24px;
}
/* The hotel hero text sits on dark teal/gold photos, so it stays light in both
themes. These carry an extra .hotel-hero class purely for specificity: the
global `.home-kinpaku h2`/`p` color rules (0,1,1) otherwise win and, in light
mode, drag the headline to the dark --ks-champagne ink — illegible on the
photo. The slop variant's own dark overrides still win on source order. */
.hotel-hero .hotel-hero-eyebrow {
margin: 0;
font-family: var(--h-sans);
font-size: 10px;
letter-spacing: 0.26em;
text-transform: uppercase;
color: oklch(91% 0.05 85);
}
.hotel-hero .hotel-hero-title {
margin: 0;
font-family: var(--h-serif);
font-weight: 500;
font-size: 2rem;
line-height: 1.05;
letter-spacing: -0.01em;
color: oklch(98% 0.01 85);
}
.hotel-hero .hotel-hero-sub {
margin: 0;
font-family: var(--h-sans);
font-size: 12px;
color: oklch(89% 0.02 85);
}
.hotel-hero-cta {
margin-top: 5px;
font-family: var(--h-sans);
font-weight: 600;
font-size: 12px;
letter-spacing: 0.04em;
padding: 9px 18px;
border: 0;
border-radius: 6px;
background: var(--h-ivory);
color: var(--h-ink);
cursor: pointer;
}
/* original — AI slop: flat, generic, sans, purple CTA. Clashes with the brand. */
.hotel-hero--slop {
align-items: center;
background: oklch(95% 0.004 270);
}
.hotel-hero--slop .hotel-hero-photo { display: none; }
.hotel-hero--slop .hotel-hero-title {
font-family: ui-sans-serif, system-ui, sans-serif;
font-weight: 800;
font-size: 1.75rem;
letter-spacing: -0.02em;
color: oklch(32% 0.02 285);
}
.hotel-hero--slop .hotel-hero-sub { color: oklch(56% 0.015 285); }
.hotel-hero--slop .hotel-hero-cta {
background: linear-gradient(135deg, oklch(62% 0.2 300), oklch(56% 0.21 268));
color: oklch(98% 0.01 300);
border-radius: 8px;
}
/* v1 — warm dusk, text bottom-left (uses base photo) */
.hotel-hero--1 .hotel-hero-cta { background: oklch(98% 0.01 85); color: oklch(30% 0.03 40); }
/* v2 — sea-toned, centered, outline CTA. justify-content centers the inner
block horizontally (the base hero is a flex row defaulting to flex-start). */
.hotel-hero--2 { align-items: center; justify-content: center; text-align: center; }
.hotel-hero--2 .hotel-hero-photo {
background:
linear-gradient(to top, oklch(24% 0.03 220 / 0.82), oklch(38% 0.04 220 / 0.12) 58%, transparent),
linear-gradient(150deg, oklch(64% 0.08 205), oklch(46% 0.07 230) 55%, oklch(34% 0.05 255));
}
.hotel-hero--2 .hotel-hero-inner { align-items: center; }
.hotel-hero--2 .hotel-hero-title { font-style: italic; }
.hotel-hero--2 .hotel-hero-cta {
background: transparent;
color: oklch(97% 0.01 85);
border: 1px solid oklch(97% 0.01 85 / 0.7);
}
/* v3 — golden hour, gold CTA */
.hotel-hero--3 .hotel-hero-photo {
background:
linear-gradient(to top, oklch(26% 0.04 50 / 0.78), oklch(42% 0.05 55 / 0.12) 58%, transparent),
linear-gradient(150deg, oklch(78% 0.1 75), oklch(60% 0.1 50) 52%, oklch(44% 0.07 38));
}
.hotel-hero--3 .hotel-hero-cta {
background: var(--ks-kinpaku, oklch(84% 0.19 80));
color: oklch(24% 0.03 60);
}
.hotel-suites {
flex: 1;
padding: 16px 0 0 22px; /* no right padding so the row runs off the edge */
overflow: hidden;
}
.hotel-suites-label {
margin: 0 0 11px;
font-family: var(--h-sans);
font-size: 10px;
letter-spacing: 0.24em;
text-transform: uppercase;
color: var(--h-muted);
}
/* Left-aligned row; the later suites run off the right edge (clipped by the
site), so the page reads as scrollable rather than a centered modal. */
.hotel-suites-row {
display: flex;
gap: 16px;
}
/* ----------------------------------------------------------------------------
The room/rate card — one shared structure, four distinct treatments.
---------------------------------------------------------------------------- */
.hotel-card {
--c-surface: oklch(99% 0.008 84);
--c-ink: var(--h-ink);
--c-accent: var(--h-green);
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 10px;
background: var(--c-surface);
border: 1px solid var(--h-line);
box-shadow: 0 3px 10px oklch(40% 0.04 60 / 0.08); /* flat in layout, not a modal */
font-family: var(--h-sans);
text-align: left;
}
.hotel-card-photo--b {
background:
radial-gradient(120% 90% at 30% 10%, oklch(88% 0.05 250 / 0.6), transparent 60%),
linear-gradient(150deg, oklch(70% 0.06 235), oklch(85% 0.05 90));
}
.hotel-card-photo--c {
background:
radial-gradient(120% 90% at 60% 0%, oklch(90% 0.06 70 / 0.7), transparent 60%),
linear-gradient(150deg, oklch(76% 0.07 50), oklch(86% 0.05 110));
}
.hotel-card-photo {
flex: none;
height: 104px;
background:
radial-gradient(120% 90% at 70% 10%, oklch(88% 0.06 95 / 0.7), transparent 60%),
linear-gradient(150deg, oklch(74% 0.05 160), oklch(86% 0.05 78));
}
.hotel-card-body {
display: flex;
flex-direction: column;
gap: 4px;
flex: 1;
padding: 13px 15px 14px;
}
.hotel-card-kicker {
margin: 0;
font-size: 9px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--c-accent);
}
.hotel-card-name {
margin: 0;
font-family: var(--h-serif);
font-weight: 600;
font-size: 1.5rem;
line-height: 1.05;
color: var(--c-ink);
}
.hotel-card-meta {
margin: 0;
font-size: 11px;
color: var(--h-muted);
}
.hotel-card-foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-top: auto;
padding-top: 10px;
}
.hotel-card-price {
font-family: var(--h-serif);
font-weight: 600;
font-size: 20px;
color: var(--c-ink);
}
.hotel-card-price i {
font-style: normal;
font-family: var(--h-sans);
font-size: 10px;
color: var(--h-muted);
}
.hotel-card-btn {
flex: none;
font-family: var(--h-sans);
font-weight: 500;
font-size: 11px;
letter-spacing: 0.06em;
padding: 7px 14px;
border: 0;
border-radius: 6px;
background: var(--c-ink);
color: var(--h-ivory);
cursor: pointer;
}
/* original — the AI-slop card: generic sans, purple gradient, overdone radius +
shadow, weak copy. Clashes on purpose with the serif siblings. */
.hotel-card--slop {
font-family: ui-sans-serif, system-ui, sans-serif;
border-radius: 16px;
border-color: transparent;
box-shadow: 0 12px 30px oklch(52% 0.2 295 / 0.4);
}
.hotel-card--slop .hotel-card-photo {
background: linear-gradient(135deg, oklch(68% 0.2 300), oklch(60% 0.21 268));
}
.hotel-card--slop .hotel-card-kicker {
font-size: 10px;
letter-spacing: 0.02em;
text-transform: none;
color: oklch(58% 0.2 290);
}
.hotel-card--slop .hotel-card-name {
font-family: inherit;
font-weight: 700;
font-size: 1.125rem;
letter-spacing: -0.01em;
color: oklch(32% 0.02 290);
}
.hotel-card--slop .hotel-card-meta { color: oklch(62% 0.01 290); }
.hotel-card--slop .hotel-card-price {
font-family: inherit;
font-weight: 700;
font-size: 16px;
color: oklch(32% 0.02 290);
}
.hotel-card--slop .hotel-card-price i { font-family: inherit; }
.hotel-card--slop .hotel-card-btn {
background: linear-gradient(135deg, oklch(62% 0.2 300), oklch(56% 0.21 268));
border-radius: 8px;
text-transform: none;
letter-spacing: 0;
}
/* v1 — full-bleed dusk photo, body overlaid on a scrim */
.hotel-card--1 {
position: relative;
border-color: transparent;
}
.hotel-card--1 .hotel-card-photo {
position: absolute;
inset: 0;
height: auto;
background:
linear-gradient(to top, oklch(22% 0.03 40 / 0.92), oklch(30% 0.04 40 / 0.15) 55%, transparent),
linear-gradient(155deg, oklch(64% 0.08 55), oklch(40% 0.06 28) 55%, oklch(32% 0.05 320));
}
.hotel-card--1 .hotel-card-body { position: relative; justify-content: flex-end; }
.hotel-card--1 .hotel-card-kicker { color: oklch(88% 0.06 85); }
.hotel-card--1 .hotel-card-name,
.hotel-card--1 .hotel-card-price { color: oklch(97% 0.01 85); }
.hotel-card--1 .hotel-card-meta { color: oklch(86% 0.02 85); }
.hotel-card--1 .hotel-card-price i { color: oklch(86% 0.02 85); }
.hotel-card--1 .hotel-card-btn {
background: oklch(97% 0.01 85);
color: oklch(28% 0.03 40);
}
/* v2 — editorial, no photo, type-forward */
.hotel-card--2 {
background: var(--h-sand);
justify-content: center;
text-align: center;
}
.hotel-card--2 .hotel-card-photo { display: none; }
.hotel-card--2 .hotel-card-body { gap: 7px; padding: 22px 18px; align-items: center; }
.hotel-card--2 .hotel-card-name { font-size: 2rem; font-style: italic; }
.hotel-card--2 .hotel-card-foot {
flex-direction: column;
gap: 10px;
border-top: 1px solid var(--h-line);
margin-top: 12px;
}
.hotel-card--2 .hotel-card-price { font-size: 1.5rem; }
.hotel-card--2 .hotel-card-btn {
background: transparent;
color: var(--c-accent);
border-bottom: 1px solid currentColor;
border-radius: 0;
padding: 2px 0;
}
/* v3 — framed, terracotta accent */
.hotel-card--3 {
--c-accent: oklch(56% 0.13 42);
background: oklch(98% 0.012 70);
padding: 7px;
border-color: oklch(56% 0.13 42 / 0.4);
}
.hotel-card--3 .hotel-card-photo {
height: 88px;
border-radius: 5px;
background:
linear-gradient(150deg, oklch(72% 0.09 45), oklch(84% 0.06 70));
}
.hotel-card--3 .hotel-card-name { color: oklch(34% 0.04 42); }
.hotel-card--3 .hotel-card-price { color: var(--c-accent); }
.hotel-card--3 .hotel-card-btn { background: var(--c-accent); }
/* ----------------------------------------------------------------------------
Annotation layer: freehand circle + comment pin, drawn on the picked card.
The layer is sized/positioned onto the card by live-demo.js (positionAnnotations);
marks sit in element-local space, mirroring the real picker.
---------------------------------------------------------------------------- */
.hero-live-demo .live-demo-annotations {
position: absolute;
z-index: 4; /* above the card + outline, below the cursor (5) */
pointer-events: none;
color: var(--ks-kinpaku);
transform: none; /* JS sets exact left/top/width/height onto the card */
opacity: 0;
transition: opacity 200ms var(--ks-ease, ease);
}
.hero-live-demo .live-demo-annotations.is-visible { opacity: 1; }
/* Circle stroke fills the card-sized layer (viewBox 0 0 100 100). The base rule
centers + offsets the stroke for the old layout — null that out here. */
.hero-live-demo .live-demo-stroke {
position: absolute;
inset: 0;
left: 0;
top: 0;
width: 100%;
height: 100%;
transform: none;
overflow: visible;
color: var(--ks-kinpaku);
}
.hero-live-demo .live-demo-stroke path {
stroke-dasharray: 1;
stroke-dashoffset: 1;
filter: drop-shadow(0 1px 2px oklch(0% 0 0 / 0.35));
}
/* Single circle around the off-brand button, drawn when the layer reveals. */
.hero-live-demo .live-demo-annotations.is-visible .live-demo-stroke path {
animation: liveDemoStroke 620ms var(--ks-ease, ease) forwards;
}
/* Comment pin: gold dot + note bubble, dropped near the button / suites edge. */
.live-demo-pin {
position: absolute;
left: 46%;
top: 78%;
opacity: 0;
transform: scale(0.5);
transform-origin: center;
transition: opacity 160ms ease, transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
}
.hero-live-demo .live-demo-annotations.is-pin-visible .live-demo-pin {
opacity: 1;
transform: scale(1);
}
.live-demo-pin-dot {
display: block;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--ks-kinpaku);
border: 2px solid oklch(98% 0.005 95);
box-shadow: 0 2px 7px oklch(0% 0 0 / 0.45);
}
.live-demo-pin-note {
position: absolute;
left: -3px;
bottom: 24px;
display: inline-flex;
align-items: center;
white-space: nowrap;
padding: 6px 10px;
border-radius: 7px;
background: oklch(19% 0.008 95);
border: 1px solid var(--ks-gold-hairline-strong, oklch(74% 0.09 82 / 0.6));
color: oklch(94% 0.02 85);
font-family: var(--ks-font, system-ui, sans-serif);
font-size: 11.5px;
line-height: 1;
box-shadow: 0 8px 22px oklch(0% 0 0 / 0.4);
opacity: 0;
transform: translateY(3px);
transition: opacity 160ms ease, transform 160ms ease;
}
.hero-live-demo .live-demo-annotations.is-note-visible .live-demo-pin-note {
opacity: 1;
transform: none;
}
.live-demo-pin-caret {
display: inline-block;
width: 1px;
height: 12px;
margin-left: 1px;
background: var(--ks-kinpaku);
animation: liveDemoCaret 1s steps(1) infinite;
}
@keyframes liveDemoCaret { 50% { opacity: 0; } }
/* CLEAR chip, top-right of the annotation overlay (authentic to the picker). */
.live-demo-annot-clear {
position: absolute;
top: 6px;
right: 6px;
font-family: var(--ks-mono, monospace);
font-size: 8.5px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--ks-kinpaku);
background: oklch(8% 0.006 95 / 0.72);
border: 1px solid var(--ks-rule);
border-radius: 4px;
padding: 3px 7px;
opacity: 0;
transition: opacity 200ms ease;
}
.hero-live-demo .live-demo-annotations.is-visible .live-demo-annot-clear { opacity: 0.85; }
/* ============================================================================
SECTION 03 (Live Mode) — how-it-works flow + audience tiles
The animated demo lives in the hero; this section explains how Live Mode wires
itself into your codebase, then sells it to each evaluator. Left-aligned blocks
below the (right-aligned) section header.
============================================================================ */
/* --- How it works: 3 steps, each with a minimal glyph -------------------- */
.live-how {
list-style: none;
margin: 48px 0 0;
padding: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
text-align: left;
}
/* No outer card — the mini-screen below is the only framed element, so the
step reads as one clean unit instead of a box-in-a-box. */
.live-how-step {
display: grid;
align-content: start;
gap: 13px;
padding: 18px;
border: 1px solid var(--ks-rule);
border-radius: 6px;
background: oklch(10% 0.006 95 / 0.45);
}
.live-how-step .live-how-n { margin-top: 4px; }
.live-how-n {
font-family: var(--ks-mono);
font-size: 0.72rem;
letter-spacing: 0.18em;
color: var(--ks-kinpaku);
}
.live-how-title {
margin: 0;
font-family: var(--ks-font-display);
font-weight: var(--ks-type-headline-weight);
font-size: 1.125rem;
color: var(--ks-champagne);
}
.live-how-copy {
margin: 0;
font-size: 0.92rem;
line-height: 1.55;
color: var(--ks-muted);
}
.live-how-copy code {
font-family: var(--ks-mono);
font-size: 0.85em;
color: var(--ks-kinpaku);
}
/* Each step's visual is a clean mini browser screen (chrome bar + screen),
echoing the picker still — not an abstract panel. */
.live-how-glyph {
border-radius: 5px;
overflow: hidden;
background: oklch(6% 0.005 95);
}
.live-how-screen {
position: relative;
min-height: 104px;
padding: 16px;
display: grid;
align-content: center;
justify-items: start;
gap: 9px;
}
/* Step 1: terminal line + framework chips */
.live-how-term {
font-family: var(--ks-mono);
font-size: 0.72rem;
color: var(--ks-champagne);
}
.live-how-term-prompt { color: var(--ks-kinpaku); }
.live-how-chips {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.live-how-chips span {
font-family: var(--ks-mono);
font-size: 0.6rem;
letter-spacing: 0.04em;
color: var(--ks-muted);
padding: 2px 7px;
border: 1px solid var(--ks-rule);
border-radius: 999px;
}
.live-how-chips span:first-child {
color: var(--ks-kinpaku);
border-color: oklch(74% 0.09 82 / 0.55);
}
/* Step 2: an element with a pick outline + an attached comment, echoing the
on-canvas picker from the hero loop. */
.live-how-screen--pick { justify-items: center; align-content: start; }
.live-how-pick {
position: relative;
width: 122px;
height: 40px;
border-radius: 4px;
background: oklch(14% 0.006 95);
border: 2px solid var(--ks-kinpaku);
box-shadow: 0 0 0 4px oklch(78% 0.12 82 / 0.12);
display: grid;
place-items: center;
}
.live-how-pick-tag {
font-family: var(--ks-mono);
font-size: 0.62rem;
color: var(--ks-muted);
}
.live-how-pick-dot {
position: absolute;
right: -5px;
top: -5px;
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--ks-kinpaku);
border: 2px solid oklch(98% 0.005 95);
}
.live-how-note {
position: absolute;
top: calc(100% + 9px);
right: -14px;
white-space: nowrap;
font-family: var(--ks-mono);
font-size: 0.6rem;
color: var(--ks-champagne);
background: oklch(13% 0.006 95);
border: 1px solid var(--ks-rule);
box-shadow: inset 0 -2px 0 var(--ks-kinpaku);
border-radius: 3px;
padding: 4px 8px;
}
.live-how-note-caret {
position: absolute;
top: -4px;
left: 13px;
width: 7px;
height: 7px;
background: oklch(13% 0.006 95);
border-left: 1px solid var(--ks-rule);
border-top: 1px solid var(--ks-rule);
transform: rotate(45deg);
}
/* Step 3: the floating contextual bar at accept, plus the source write. */
.live-how-screen--accept { justify-items: center; gap: 12px; }
.live-how-ctxbar {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 5px 6px 5px 10px;
border: 1px solid var(--ks-rule);
border-radius: 999px;
background: oklch(12% 0.006 95);
box-shadow: 0 6px 18px oklch(2% 0.004 95 / 0.45);
font-family: var(--ks-mono);
font-size: 0.62rem;
}
.live-how-ctx-nav { color: var(--ks-muted); }
.live-how-ctx-count { color: var(--ks-champagne); }
.live-how-ctx-div { width: 1px; height: 13px; background: var(--ks-rule); }
.live-how-ctx-accept {
padding: 3px 10px;
border-radius: 999px;
background: var(--ks-kinpaku);
color: oklch(16% 0.02 90);
font-weight: 600;
}
.live-how-wrote {
display: inline-flex;
align-items: center;
gap: 6px;
font-family: var(--ks-mono);
font-size: 0.62rem;
color: var(--ks-patina);
}
.live-how-wrote-check { font-size: 0.7rem; }
/* --- Who it's for: three role tiles -------------------------------------- */
.live-audience-eyebrow {
margin: 52px 0 22px;
font-family: var(--ks-mono);
font-size: 0.62rem;
letter-spacing: 0.26em;
text-transform: uppercase;
color: var(--ks-patina);
}
.live-audience {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px;
text-align: left;
}
.live-audience-tile {
padding: 16px 0 0;
border-top: 2px solid var(--ks-patina);
}
.live-audience-role {
display: block;
margin-bottom: 11px;
font-family: var(--ks-mono);
font-size: 0.66rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--ks-patina);
}
.live-audience-tile p {
margin: 0;
font-size: 0.92rem;
line-height: 1.55;
color: var(--ks-muted);
}
@media (max-width: 920px) {
.live-how { grid-template-columns: 1fr; }
.live-audience { grid-template-columns: 1fr; }
}