mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 15:46:30 +03:00
* 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>
962 lines
22 KiB
CSS
962 lines
22 KiB
CSS
/* ============================================
|
||
LIVE MODE — interactive demo loop
|
||
============================================ */
|
||
|
||
.live-section {
|
||
padding: var(--spacing-2xl) 0;
|
||
border-top: 1px solid var(--color-mist);
|
||
}
|
||
|
||
.live-content .section-lead {
|
||
max-width: 64ch;
|
||
margin-bottom: var(--spacing-xl);
|
||
}
|
||
|
||
.live-demo {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
|
||
gap: var(--spacing-xl);
|
||
align-items: start;
|
||
margin-bottom: var(--spacing-xl);
|
||
}
|
||
.live-demo-frame-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--spacing-md);
|
||
min-width: 0;
|
||
}
|
||
@media (max-width: 920px) {
|
||
.live-demo { grid-template-columns: 1fr; }
|
||
}
|
||
|
||
.live-demo-frame {
|
||
position: relative;
|
||
background: var(--color-cream);
|
||
border: 1px solid var(--color-mist);
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
aspect-ratio: 16 / 9;
|
||
max-width: 960px;
|
||
box-shadow: 0 20px 50px oklch(0% 0 0 / 0.08);
|
||
user-select: none;
|
||
}
|
||
|
||
.live-demo-chrome {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 10px 14px;
|
||
border-bottom: 1px solid var(--color-mist);
|
||
background: var(--color-paper);
|
||
}
|
||
.live-demo-dot {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
background: var(--color-mist);
|
||
}
|
||
.live-demo-url {
|
||
margin-left: 14px;
|
||
padding: 4px 14px;
|
||
background: var(--color-cream);
|
||
border: 1px solid var(--color-mist);
|
||
border-radius: 5px;
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--color-charcoal);
|
||
}
|
||
|
||
.live-demo-stage {
|
||
position: relative;
|
||
height: calc(100% - 42px - 60px); /* minus chrome + bar */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 32px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* Target card */
|
||
.live-demo-target {
|
||
position: relative;
|
||
width: min(360px, 80%);
|
||
min-height: 200px;
|
||
}
|
||
.live-demo-variant {
|
||
position: absolute;
|
||
inset: 0;
|
||
opacity: 0;
|
||
transform: translateY(8px) scale(0.99);
|
||
transition: opacity 280ms var(--ease-out), transform 280ms var(--ease-out);
|
||
pointer-events: none;
|
||
}
|
||
.live-demo-variant.is-active {
|
||
opacity: 1;
|
||
transform: translateY(0) scale(1);
|
||
pointer-events: auto;
|
||
}
|
||
.live-demo-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
padding: 22px 24px;
|
||
background: var(--color-paper);
|
||
border: 1px solid var(--color-mist);
|
||
border-radius: 8px;
|
||
height: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
.live-demo-card-kicker {
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0.18em;
|
||
text-transform: uppercase;
|
||
color: var(--color-ash);
|
||
}
|
||
.live-demo-card h3 {
|
||
font-family: var(--font-display);
|
||
font-weight: 400;
|
||
font-size: 20px;
|
||
line-height: 1.2;
|
||
color: var(--color-ink);
|
||
margin: 0;
|
||
}
|
||
.live-demo-card p {
|
||
font-family: var(--font-body);
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
color: var(--color-charcoal);
|
||
margin: 0;
|
||
}
|
||
.live-demo-card button {
|
||
align-self: flex-start;
|
||
margin-top: auto;
|
||
font-family: var(--font-body);
|
||
font-weight: 500;
|
||
font-size: 12px;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
padding: 9px 16px;
|
||
background: var(--color-ink);
|
||
color: var(--color-paper);
|
||
border: 0;
|
||
border-radius: 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Per-variant look */
|
||
.live-demo-card--plain {}
|
||
.live-demo-card--v1 {
|
||
background: var(--color-cream);
|
||
}
|
||
.live-demo-card--v1 h3 { font-style: italic; }
|
||
.live-demo-card--v1 h3 em { color: var(--color-accent); font-style: italic; }
|
||
.live-demo-card--v2 {
|
||
background: var(--color-paper);
|
||
border: 1px dashed var(--color-accent);
|
||
}
|
||
.live-demo-card--v2 .live-demo-card-kicker { color: var(--color-accent); }
|
||
.live-demo-card--v2 h3 { font-family: var(--font-display); font-style: italic; }
|
||
.live-demo-card--v2 button {
|
||
background: var(--color-accent);
|
||
}
|
||
.live-demo-card--v3 {
|
||
background: var(--color-cream);
|
||
border: 1px solid var(--color-accent-soft);
|
||
}
|
||
.live-demo-card--v3 h3 em { color: var(--color-accent); font-style: italic; }
|
||
.live-demo-card--v3 .live-demo-card-kicker { color: var(--color-accent-hover); }
|
||
|
||
/* Highlight outline over the target */
|
||
.live-demo-outline {
|
||
position: absolute;
|
||
border: 2px solid var(--color-accent);
|
||
border-radius: 8px;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
transition: opacity 200ms var(--ease-out);
|
||
box-shadow: 0 0 0 4px var(--color-accent-dim);
|
||
}
|
||
.live-demo-outline.is-visible {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Annotations */
|
||
.live-demo-annotations {
|
||
position: absolute;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
transition: opacity 280ms var(--ease-out);
|
||
color: var(--color-accent);
|
||
}
|
||
.live-demo-annotations.is-visible { opacity: 1; }
|
||
.live-demo-stroke {
|
||
position: absolute;
|
||
width: 280px;
|
||
height: 56px;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -24px);
|
||
pointer-events: none;
|
||
}
|
||
.live-demo-stroke path {
|
||
stroke-dasharray: 1;
|
||
stroke-dashoffset: 1;
|
||
}
|
||
.live-demo-annotations.is-visible .live-demo-stroke path {
|
||
animation: liveDemoStroke 800ms var(--ease-out) forwards;
|
||
}
|
||
@keyframes liveDemoStroke {
|
||
to { stroke-dashoffset: 0; }
|
||
}
|
||
.live-demo-comment {
|
||
position: absolute;
|
||
top: 56%;
|
||
left: 50%;
|
||
transform: translate(-50%, 0);
|
||
padding: 5px 10px;
|
||
background: var(--color-ink);
|
||
color: var(--color-paper);
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
border-radius: 4px;
|
||
white-space: nowrap;
|
||
opacity: 0;
|
||
transition: opacity 200ms var(--ease-out);
|
||
}
|
||
.live-demo-annotations.is-comment-visible .live-demo-comment { opacity: 1; }
|
||
|
||
/* Simulated cursor */
|
||
.live-demo-cursor {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 18px;
|
||
height: 22px;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
transform: translate(0, 0);
|
||
transition: opacity 200ms var(--ease-out), transform 560ms var(--ease-out-quint);
|
||
z-index: 5;
|
||
filter: drop-shadow(0 2px 4px oklch(0% 0 0 / 0.2));
|
||
}
|
||
.live-demo-cursor.is-visible { opacity: 1; }
|
||
.live-demo-cursor.is-click svg path {
|
||
transform-origin: 4px 4px;
|
||
animation: liveDemoCursorClick 220ms var(--ease-out);
|
||
}
|
||
@keyframes liveDemoCursorClick {
|
||
0%, 100% { transform: scale(1); }
|
||
40% { transform: scale(0.78); }
|
||
}
|
||
|
||
/* Global bar — mirrors live-browser.js initGlobalBar (brand + inner toggles). */
|
||
.live-demo-gbar {
|
||
position: absolute;
|
||
bottom: 14px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
display: flex;
|
||
align-items: stretch;
|
||
gap: 0;
|
||
width: max-content;
|
||
max-width: calc(100% - 24px);
|
||
overflow: hidden;
|
||
box-sizing: border-box;
|
||
min-height: 36px;
|
||
padding: 0;
|
||
background: oklch(14% 0 0);
|
||
color: oklch(92% 0 0);
|
||
border: 1px solid oklch(22% 0 0);
|
||
border-radius: 10px;
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
line-height: 1;
|
||
box-shadow: 0 8px 24px oklch(0% 0 0 / 0.2);
|
||
z-index: 4;
|
||
}
|
||
.live-demo-gbar-brand {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
align-self: stretch;
|
||
flex-shrink: 0;
|
||
padding: 0 6px 0 14px;
|
||
color: var(--color-accent);
|
||
}
|
||
.live-demo-gbar-brand-mark {
|
||
display: block;
|
||
}
|
||
.live-demo-gbar-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2px;
|
||
flex: 0 0 auto;
|
||
padding: 4px 6px 4px 2px;
|
||
}
|
||
.live-demo-gbar-btn {
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-sizing: border-box;
|
||
flex: 0 0 auto;
|
||
min-width: 30px;
|
||
flex-shrink: 0;
|
||
padding: 6px 8px;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 7px;
|
||
color: oklch(75% 0 0);
|
||
font: inherit;
|
||
font-size: 11.5px;
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
transition: background 0.15s ease, color 0.15s ease;
|
||
}
|
||
.live-demo-gbar-btn svg {
|
||
width: 14px;
|
||
height: 14px;
|
||
flex: 0 0 14px;
|
||
}
|
||
.live-demo-gbar-btn-label {
|
||
display: inline-block;
|
||
max-width: 0;
|
||
opacity: 0;
|
||
margin-left: 0;
|
||
overflow: hidden;
|
||
transition: opacity 0.2s ease;
|
||
}
|
||
.live-demo-gbar-btn-label--mono {
|
||
font-family: var(--font-mono);
|
||
}
|
||
.live-demo-gbar:hover .live-demo-gbar-btn:not(.is-active) .live-demo-gbar-btn-label,
|
||
.live-demo-gbar-btn.is-active .live-demo-gbar-btn-label {
|
||
max-width: 120px;
|
||
opacity: 1;
|
||
margin-left: 6px;
|
||
}
|
||
.live-demo-gbar-btn.is-active {
|
||
background: var(--color-accent-dim);
|
||
color: var(--color-accent);
|
||
}
|
||
.live-demo-gbar-dmd {
|
||
display: inline-grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
grid-template-rows: 1fr 1fr;
|
||
width: 14px;
|
||
height: 14px;
|
||
flex-shrink: 0;
|
||
border-radius: 3px;
|
||
overflow: hidden;
|
||
box-shadow: inset 0 0 0 1px var(--color-mist);
|
||
}
|
||
.live-demo-gbar-dmd span:nth-child(1) { background: oklch(84% 0.19 80.46); }
|
||
.live-demo-gbar-dmd span:nth-child(2) { background: oklch(70% 0.12 188); }
|
||
.live-demo-gbar-dmd span:nth-child(3) { background: oklch(91% 0 0); }
|
||
.live-demo-gbar-dmd span:nth-child(4) { background: oklch(34% 0.014 82); }
|
||
.live-demo-gbar-x {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-sizing: border-box;
|
||
flex: 0 0 24px;
|
||
align-self: center;
|
||
width: 24px;
|
||
height: 24px;
|
||
padding: 0;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 6px;
|
||
color: oklch(60% 0 0);
|
||
font-size: 0;
|
||
line-height: 0;
|
||
cursor: pointer;
|
||
transition: color 0.12s ease, background 0.12s ease;
|
||
}
|
||
.live-demo-gbar-x:hover {
|
||
color: oklch(58% 0.15 35);
|
||
}
|
||
|
||
/* Contextual bar — LIGHT paper-backed pill that floats near the picked
|
||
element during a session. Matches live-browser.js's buildConfigureRow
|
||
look (dark command pill, transparent input, ×N count, magenta Go). */
|
||
.live-demo-ctx {
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translate(-50%, 6px);
|
||
padding: 6px;
|
||
background: var(--color-paper);
|
||
border: 1px solid var(--color-mist);
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 20px oklch(0% 0 0 / 0.08), 0 1px 3px oklch(0% 0 0 / 0.06);
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
color: var(--color-ink);
|
||
display: none;
|
||
opacity: 0;
|
||
transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
|
||
z-index: 3;
|
||
max-width: 90%;
|
||
}
|
||
.live-demo-ctx[data-phase="configuring"],
|
||
.live-demo-ctx[data-phase="generating"],
|
||
.live-demo-ctx[data-phase="cycling"],
|
||
.live-demo-ctx[data-phase="accepted"] {
|
||
display: block;
|
||
opacity: 1;
|
||
transform: translate(-50%, 0);
|
||
}
|
||
.live-demo-ctx-row {
|
||
display: none;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
.live-demo-ctx[data-phase="configuring"] .live-demo-ctx-row--configure,
|
||
.live-demo-ctx[data-phase="generating"] .live-demo-ctx-row--generating,
|
||
.live-demo-ctx[data-phase="cycling"] .live-demo-ctx-row--cycling,
|
||
.live-demo-ctx[data-phase="accepted"] .live-demo-ctx-row--accepted {
|
||
display: flex;
|
||
}
|
||
|
||
.live-demo-ctx[data-phase="configuring"] {
|
||
padding: 0;
|
||
background: oklch(15% 0.008 95);
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* Configure row: [h1 pill | input …] | [adapt ▾ ×3 | voice →] */
|
||
.live-demo-ctx-row--configure {
|
||
width: 100%;
|
||
min-height: 36px;
|
||
}
|
||
.live-demo-ctx-command {
|
||
display: flex;
|
||
align-items: center;
|
||
flex: 1;
|
||
min-width: 180px;
|
||
height: 36px;
|
||
padding: 0 6px 0 7px;
|
||
background: transparent;
|
||
border: 0;
|
||
overflow: hidden;
|
||
}
|
||
.live-demo-ctx-trailing {
|
||
display: inline-flex;
|
||
align-items: stretch;
|
||
flex-shrink: 0;
|
||
border-left: 1px solid oklch(92% 0 0 / 0.12);
|
||
}
|
||
.live-demo-ctx-modifiers {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 0 10px;
|
||
flex-shrink: 0;
|
||
}
|
||
.live-demo-ctx-selection {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2px;
|
||
box-sizing: border-box;
|
||
min-width: 28px;
|
||
height: auto;
|
||
padding: 1px 4px;
|
||
background: transparent;
|
||
color: oklch(70% 0.12 188);
|
||
border: 1px solid oklch(70% 0.12 188);
|
||
border-radius: 7px;
|
||
flex-shrink: 0;
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
line-height: 18px;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: background 0.15s ease, color 0.15s ease;
|
||
}
|
||
.live-demo-ctx-selection:hover {
|
||
background: oklch(27% 0 0);
|
||
}
|
||
.live-demo-ctx-action,
|
||
.live-demo-ctx-count {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2px;
|
||
box-sizing: border-box;
|
||
height: 18px;
|
||
padding: 0;
|
||
background: transparent;
|
||
color: var(--color-ash);
|
||
border: 0;
|
||
border-radius: 0;
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
line-height: 18px;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
transition: color 0.12s ease;
|
||
}
|
||
.live-demo-ctx-count {
|
||
font-family: var(--font-mono);
|
||
font-weight: 600;
|
||
}
|
||
.live-demo-ctx-action:hover,
|
||
.live-demo-ctx-count:hover {
|
||
color: var(--color-ink);
|
||
}
|
||
.live-demo-ctx-action-caret {
|
||
font-size: 10px;
|
||
margin-left: 2px;
|
||
color: inherit;
|
||
}
|
||
.live-demo-ctx-input {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
flex: 1;
|
||
min-width: 0;
|
||
height: 18px;
|
||
padding: 0;
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
line-height: 18px;
|
||
color: oklch(94% 0.02 82);
|
||
background: transparent;
|
||
border: 0;
|
||
}
|
||
.live-demo-ctx-actions {
|
||
display: inline-flex;
|
||
align-items: stretch;
|
||
flex-shrink: 0;
|
||
border-left: 1px solid oklch(92% 0 0 / 0.12);
|
||
}
|
||
.live-demo-ctx-voice {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 36px;
|
||
height: 36px;
|
||
padding: 0;
|
||
background: transparent;
|
||
color: var(--color-ash);
|
||
border: 0;
|
||
box-shadow: inset -1px 0 0 oklch(22% 0 0);
|
||
border-radius: 0;
|
||
cursor: pointer;
|
||
}
|
||
.live-demo-ctx-caret {
|
||
display: inline-block;
|
||
width: 1px;
|
||
height: 13px;
|
||
background: var(--color-ink);
|
||
margin-left: 2px;
|
||
animation: liveDemoCaret 1s steps(1) infinite;
|
||
}
|
||
@keyframes liveDemoCaret {
|
||
50% { opacity: 0; }
|
||
}
|
||
.live-demo-ctx-go {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 36px;
|
||
height: 36px;
|
||
box-sizing: border-box;
|
||
padding: 0;
|
||
background: var(--color-accent);
|
||
color: var(--color-paper);
|
||
border: 0;
|
||
box-shadow: inset 1px 0 0 oklch(22% 0 0);
|
||
border-radius: 0;
|
||
font-family: var(--font-body);
|
||
font-size: 0;
|
||
line-height: 0;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* Generating row */
|
||
.live-demo-ctx-row--generating {
|
||
gap: 10px;
|
||
padding: 4px 12px 4px 6px;
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
color: var(--color-charcoal);
|
||
}
|
||
.live-demo-ctx-spinner {
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 50%;
|
||
border: 1.5px solid var(--color-mist);
|
||
border-top-color: var(--color-accent);
|
||
animation: liveDemoSpin 700ms linear infinite;
|
||
}
|
||
@keyframes liveDemoSpin { to { transform: rotate(360deg); } }
|
||
|
||
/* Cycling row */
|
||
.live-demo-ctx-row--cycling { gap: 2px; padding: 2px; }
|
||
.live-demo-ctx-nav {
|
||
padding: 4px 10px;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 5px;
|
||
color: var(--color-charcoal);
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
.live-demo-ctx-counter {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--color-ink);
|
||
padding: 0 6px;
|
||
min-width: 40px;
|
||
text-align: center;
|
||
}
|
||
.live-demo-ctx-divider {
|
||
width: 1px;
|
||
height: 18px;
|
||
background: var(--color-mist);
|
||
margin: 0 4px;
|
||
}
|
||
.live-demo-ctx-discard {
|
||
padding: 4px 10px;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 5px;
|
||
color: var(--color-ash);
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
}
|
||
.live-demo-ctx-accept {
|
||
padding: 5px 14px;
|
||
background: var(--color-ink);
|
||
color: var(--color-paper);
|
||
border: 0;
|
||
border-radius: 6px;
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Accepted confirmation row */
|
||
.live-demo-ctx-row--accepted {
|
||
gap: 8px;
|
||
padding: 6px 14px;
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
color: oklch(45% 0.18 145);
|
||
}
|
||
|
||
/* Phase caption under the frame */
|
||
.live-demo-caption {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 10px;
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
color: var(--color-ash);
|
||
}
|
||
.live-demo-caption::before {
|
||
content: "";
|
||
display: inline-block;
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--color-accent);
|
||
animation: liveDemoPulse 1.6s var(--ease-out) infinite;
|
||
}
|
||
@keyframes liveDemoPulse {
|
||
0%, 100% { opacity: 1; transform: scale(1); }
|
||
50% { opacity: 0.4; transform: scale(0.7); }
|
||
}
|
||
.live-demo-caption-label { color: var(--color-ink); }
|
||
|
||
/* Supporting row under the demo */
|
||
.live-demo-support {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--spacing-md);
|
||
align-self: stretch;
|
||
}
|
||
.live-demo-support-cell {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 4px;
|
||
padding-bottom: var(--spacing-md);
|
||
border-bottom: 1px dashed var(--color-mist);
|
||
}
|
||
.live-demo-support-cell:last-child {
|
||
border-bottom: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
.live-demo-support-k {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.16em;
|
||
text-transform: uppercase;
|
||
color: var(--color-accent);
|
||
}
|
||
.live-demo-support-v {
|
||
font-family: var(--font-body);
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
color: var(--color-ink);
|
||
}
|
||
.live-demo-support-v code {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.875em;
|
||
background: var(--color-mist);
|
||
padding: 1px 6px;
|
||
border-radius: 3px;
|
||
color: var(--color-ink);
|
||
}
|
||
|
||
@media (max-width: 760px) {
|
||
.live-demo-frame { aspect-ratio: 4 / 5; }
|
||
.live-demo-target { width: 90%; }
|
||
.live-demo-bar { font-size: 11px; min-height: 32px; }
|
||
.live-demo-support { grid-template-columns: 1fr; gap: var(--spacing-md); }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.live-demo-cursor,
|
||
.live-demo-outline,
|
||
.live-demo-variant,
|
||
.live-demo-annotations,
|
||
.live-demo-stroke path {
|
||
transition: none !important;
|
||
animation: none !important;
|
||
}
|
||
.live-demo-caption::before { animation: none; }
|
||
}
|
||
/* ============================================
|
||
LIVE MODE — skeleton page + richer variants
|
||
============================================ */
|
||
|
||
/* Skeleton elements behind the target card — suggest "this is a real page" */
|
||
.live-demo-skeleton {
|
||
position: absolute;
|
||
inset: 24px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
opacity: 0.3;
|
||
pointer-events: none;
|
||
filter: blur(0.3px);
|
||
}
|
||
.live-demo-skel-nav {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px solid var(--color-mist);
|
||
}
|
||
.live-demo-skel-logo {
|
||
width: 22px;
|
||
height: 22px;
|
||
border-radius: 4px;
|
||
background: var(--color-charcoal);
|
||
}
|
||
.live-demo-skel-link {
|
||
width: 48px;
|
||
height: 8px;
|
||
border-radius: 2px;
|
||
background: var(--color-mist);
|
||
}
|
||
.live-demo-skel-cta {
|
||
margin-left: auto;
|
||
width: 72px;
|
||
height: 24px;
|
||
border-radius: 4px;
|
||
background: var(--color-charcoal);
|
||
}
|
||
.live-demo-skel-heading {
|
||
width: 60%;
|
||
height: 18px;
|
||
border-radius: 3px;
|
||
background: var(--color-mist);
|
||
margin-top: 20px;
|
||
}
|
||
.live-demo-skel-line {
|
||
height: 8px;
|
||
border-radius: 2px;
|
||
background: var(--color-mist);
|
||
}
|
||
.live-demo-skel-line--short { width: 40%; }
|
||
|
||
/* Target stays above skeleton */
|
||
.live-demo-target { position: relative; z-index: 1; }
|
||
|
||
/* ---- Card variants — sharper, more distinct ---- */
|
||
|
||
/* Variant 1: magazine column — italic serif, rule lines, off-white */
|
||
.live-demo-card--v1 {
|
||
background: var(--color-cream);
|
||
padding: 18px 22px;
|
||
border: 0;
|
||
box-shadow: inset 0 3px 0 var(--color-ink);
|
||
border-radius: 0;
|
||
gap: 6px;
|
||
}
|
||
.live-demo-card--v1 .live-demo-card-kicker {
|
||
color: var(--color-accent);
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0.28em;
|
||
}
|
||
.live-demo-card--v1 h3 {
|
||
font-family: var(--font-display);
|
||
font-style: italic;
|
||
font-weight: 400;
|
||
font-size: 28px;
|
||
line-height: 1.05;
|
||
letter-spacing: -0.01em;
|
||
margin-top: 4px;
|
||
}
|
||
.live-demo-card--v1 h3 em { color: var(--color-accent); font-style: italic; }
|
||
.live-demo-card--v1 p {
|
||
font-family: var(--font-display);
|
||
font-style: italic;
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
color: var(--color-charcoal);
|
||
}
|
||
.live-demo-card--v1 button {
|
||
font-family: var(--font-body);
|
||
align-self: flex-start;
|
||
margin-top: 6px;
|
||
background: transparent;
|
||
color: var(--color-ink);
|
||
border: 0;
|
||
border-bottom: 1.5px solid var(--color-ink);
|
||
padding: 4px 0;
|
||
border-radius: 0;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
|
||
/* Variant 2: brutalist ticket — thick ink block, stamp glyph, mono */
|
||
.live-demo-card--v2 {
|
||
position: relative;
|
||
background: var(--color-ink);
|
||
color: var(--color-paper);
|
||
padding: 20px 24px;
|
||
border: 0;
|
||
border-radius: 0;
|
||
overflow: hidden;
|
||
gap: 8px;
|
||
}
|
||
.live-demo-card--v2::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 6px;
|
||
background: var(--color-accent);
|
||
}
|
||
.live-demo-card-stamp {
|
||
position: absolute;
|
||
top: 14px;
|
||
right: 18px;
|
||
font-size: 28px;
|
||
line-height: 1;
|
||
color: var(--color-accent);
|
||
transform: rotate(-8deg);
|
||
}
|
||
.live-demo-card--v2 .live-demo-card-kicker {
|
||
color: var(--color-accent);
|
||
letter-spacing: 0.3em;
|
||
font-weight: 600;
|
||
}
|
||
.live-demo-card--v2 h3 {
|
||
font-family: var(--font-body);
|
||
font-weight: 700;
|
||
font-size: 24px;
|
||
line-height: 1.1;
|
||
color: var(--color-paper);
|
||
letter-spacing: -0.02em;
|
||
}
|
||
.live-demo-card--v2 button {
|
||
font-family: var(--font-mono);
|
||
font-weight: 500;
|
||
align-self: flex-start;
|
||
margin-top: 6px;
|
||
background: var(--color-accent);
|
||
color: var(--color-paper);
|
||
border: 0;
|
||
border-radius: 0;
|
||
padding: 9px 14px;
|
||
letter-spacing: 0.04em;
|
||
text-transform: none;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* Variant 3: playful ticket — accent background, sticker stars, postcard vibe */
|
||
.live-demo-card--v3 {
|
||
position: relative;
|
||
background:
|
||
radial-gradient(circle at 20% 80%, oklch(77% 0.13 82 / 0.16) 0, transparent 45%),
|
||
var(--color-cream);
|
||
border: 1px dashed var(--color-accent);
|
||
border-radius: 10px;
|
||
padding: 22px 24px 20px;
|
||
gap: 8px;
|
||
}
|
||
.live-demo-card-sticker {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 14px;
|
||
display: flex;
|
||
gap: 3px;
|
||
color: var(--color-accent);
|
||
font-size: 14px;
|
||
line-height: 1;
|
||
transform: rotate(6deg);
|
||
}
|
||
.live-demo-card--v3 .live-demo-card-kicker {
|
||
font-family: var(--font-display);
|
||
font-style: italic;
|
||
font-weight: 400;
|
||
font-size: 13px;
|
||
letter-spacing: 0.04em;
|
||
color: var(--color-accent-hover);
|
||
text-transform: none;
|
||
}
|
||
.live-demo-card--v3 h3 {
|
||
font-family: var(--font-display);
|
||
font-weight: 400;
|
||
font-size: 1.25rem;
|
||
line-height: 1.2;
|
||
color: var(--color-ink);
|
||
}
|
||
.live-demo-card--v3 button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
align-self: flex-start;
|
||
background: var(--color-ink);
|
||
color: var(--color-paper);
|
||
border: 0;
|
||
border-radius: 999px;
|
||
padding: 10px 18px;
|
||
font-family: var(--font-body);
|
||
font-weight: 500;
|
||
letter-spacing: 0.06em;
|
||
text-transform: none;
|
||
font-size: 12px;
|
||
margin-top: 6px;
|
||
}
|