Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/components/ui/FinalCtaSection.astro
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const repositoryUrl = productData.links.repositoryUrl

.final-band-title {
margin: 0;
color: var(--hearth-ink-strong);
color: var(--hearth-text-heading-strong);
font-family: var(--font-display);
font-size: clamp(2rem, 4vw, 2.7rem);
line-height: 0.98;
Expand All @@ -109,7 +109,7 @@ const repositoryUrl = productData.links.repositoryUrl
align-items: center;
gap: 0.4rem;
margin-top: 0.2rem;
color: var(--hearth-ink-soft);
color: var(--hearth-text-body-soft);
font-family: var(--font-ui);
font-size: 0.82rem;
font-weight: 600;
Expand All @@ -122,7 +122,7 @@ const repositoryUrl = productData.links.repositoryUrl

.final-source-link:hover {
opacity: 1;
color: var(--hearth-ink-strong);
color: var(--hearth-text-heading-strong);
}

@media (min-width: 1200px) {
Expand Down
72 changes: 50 additions & 22 deletions src/components/ui/HeroSection.astro
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
<code>{installCommand}</code>
<span class="specimen-cmd-hint">{t(lang, 'hero.copy')}</span>
</button>
{/* Stable empty region so the copy confirmation is announced; swapping the
hint text in place is silent for screen readers. */}
<span class="hearth-sr-only" role="status" aria-live="polite" data-copy-status></span>
</div>

<div
Expand All @@ -227,9 +230,12 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
data-reveal-child
style={`--reveal-index:0;--cap-alt-surface:${initialCompareTheme.surface};--cap-alt-ink:${initialCompareTheme.foreground};--cap-alt-accent:${initialCompareTheme.accent}`}
>
<p class="hero-kicker">{t(lang, 'hero.kicker')}</p>
{/* The kicker text carries the page's purpose, so it belongs in the h1;
the visible copy is hidden from assistive tech to avoid a duplicate. */}
<p class="hero-kicker" aria-hidden="true">{t(lang, 'hero.kicker')}</p>
<h1 class="hero-title">
<span>{heroWordmark.primary}</span>{heroWordmark.secondary ? <span>{heroWordmark.secondary}</span> : null}
<span>{heroWordmark.primary}</span>{heroWordmark.secondary ? <span class="hero-title-accent">{heroWordmark.secondary}</span> : null}
<span class="hearth-sr-only">{` — ${t(lang, 'hero.kicker')}`}</span>
</h1>
<p class="hero-subtitle hearth-copy">{t(lang, 'hero.subtitle')}</p>

Expand Down Expand Up @@ -350,19 +356,27 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
padding: 0;
}

/* Stage and capsule share one grid cell. The capsule still overlays the
specimen, but as a grid item it contributes its height to the row, so a
short viewport grows the section instead of letting an absolutely
positioned panel escape and land on top of the next one. */
.hero-specimen {
position: relative;
min-width: 0;
display: grid;
}

/* ---- Specimen stage: the product IS the page ------------------------- */

.specimen-stage {
position: relative;
height: clamp(540px, calc(100svh - 160px), 820px);
grid-area: 1 / 1;
/* min-height, not height: the stage stretches to the row so the panes keep
filling the frame when the capsule is the taller of the two. */
min-height: clamp(540px, calc(100svh - 160px), 820px);
overflow: hidden;
border-top: 1px solid color-mix(in srgb, var(--pick-accent) 14%, var(--hearth-card-border));
border-bottom: 1px solid color-mix(in srgb, var(--pick-accent) 14%, var(--hearth-card-border));
border-top: 1px solid color-mix(in srgb, var(--pick-accent) 14%, var(--hearth-surface-border-weak));
border-bottom: 1px solid color-mix(in srgb, var(--pick-accent) 14%, var(--hearth-surface-border-weak));
}

.specimen-layer {
Expand Down Expand Up @@ -457,7 +471,7 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
place-items: center;
width: 2.15rem;
aspect-ratio: 1;
border: 1px solid color-mix(in srgb, var(--pick-keyword) 55%, var(--hearth-card-border));
border: 1px solid color-mix(in srgb, var(--pick-keyword) 55%, var(--hearth-surface-border-weak));
border-radius: 50%;
color: var(--pick-keyword);
background: color-mix(in srgb, var(--hearth-bg) 94%, black 6%);
Expand Down Expand Up @@ -548,9 +562,11 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
--cap-ink: var(--pick-ink);
--cap-accent: var(--pick-keyword);
--cap-line: color-mix(in srgb, var(--cap-ink) 22%, transparent);
position: absolute;
top: clamp(1rem, 3vh, 2.2rem);
left: clamp(1rem, 3.4vw, 3rem);
position: relative;
grid-area: 1 / 1;
justify-self: start;
align-self: start;
margin: clamp(1rem, 3vh, 2.2rem) 0 clamp(1rem, 3vh, 2.2rem) clamp(1rem, 3.4vw, 3rem);
z-index: 4;
display: grid;
gap: 0.62rem;
Expand Down Expand Up @@ -596,7 +612,7 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
line-height: 0.95;
}

.hero-title span:last-child {
.hero-title-accent {
color: color-mix(in srgb, var(--cap-accent) 60%, var(--cap-ink));
}

Expand Down Expand Up @@ -750,7 +766,7 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '

.hero-select-row:focus-within {
border-color: var(--cap-accent);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--cap-accent) 70%, transparent);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--cap-accent) 70%, transparent);
}

.hero-file-select {
Expand Down Expand Up @@ -807,7 +823,7 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
.hero-forge-card small {
color: color-mix(in srgb, var(--cap-ink) 64%, transparent);
font-family: var(--font-ui);
font-size: 0.59rem;
font-size: 0.7rem;
font-weight: 580;
line-height: 1.35;
}
Expand Down Expand Up @@ -846,8 +862,10 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
.hero-action:focus-visible,
.hero-forge-card:focus-visible,
.hero-support-links a:focus-visible,
/* The command button lives in .specimen-stage, not in .hero-capsule, so the
--cap-* tokens are out of scope here; --pick-accent is set on the stage. */
.specimen-cmd:focus-visible {
outline: 2px solid var(--cap-accent);
outline: 2px solid var(--pick-accent);
outline-offset: 2px;
}

Expand All @@ -862,13 +880,16 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
.hero-capsule {
order: -1;
position: static;
/* Undo the grid-overlay placement: this column is a flex stack. */
align-self: stretch;
width: auto;
margin: 0.9rem 1rem;
backdrop-filter: none;
}

.specimen-stage {
height: auto;
min-height: 0;
display: grid;
}

Expand Down Expand Up @@ -929,20 +950,26 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
}
}

/* Stacked directly above the command chip on the stage's right edge: the
capsule is left-anchored and can be taller than the stage, so the old
bottom-left slot was covered by it. The right edge is always the compare
layer (it is clipped from --split-x rightward), so it takes compare ink. */
.specimen-ignite {
position: absolute;
left: 1.1rem;
bottom: 1rem;
right: 1.1rem;
bottom: 4.2rem;
z-index: 2;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.2rem;
font-family: var(--font-metric);
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.08em;
font-variant-numeric: tabular-nums;
color: color-mix(in srgb, var(--pick-ink) 76%, transparent);
text-align: right;
color: color-mix(in srgb, var(--compare-ink) 76%, transparent);
pointer-events: none;
}

Expand Down Expand Up @@ -1425,19 +1452,20 @@ const initialForgeUrl = `${forgeUrl}?color=${ignitionDefaultSeed.replace(/^#/, '
root.querySelectorAll('[data-copy-command]').forEach((button) => {
if (!(button instanceof HTMLElement)) return
const hint = button.querySelector('.specimen-cmd-hint')
const status = root.querySelector('[data-copy-status]')
const originalHint = hint?.textContent || ''
const copiedLabel = button.getAttribute('data-copied-label') || originalHint
button.addEventListener('click', async () => {
const command = button.querySelector('code')?.textContent?.trim()
if (!command) return
try {
await navigator.clipboard.writeText(command)
if (hint) {
hint.textContent = copiedLabel
window.setTimeout(() => {
hint.textContent = originalHint
}, 1600)
}
if (status) status.textContent = copiedLabel
if (hint) hint.textContent = copiedLabel
window.setTimeout(() => {
if (hint) hint.textContent = originalHint
if (status) status.textContent = ''
}, 1600)
} catch {
/* clipboard unavailable — the command stays selectable text */
}
Expand Down
7 changes: 5 additions & 2 deletions src/components/ui/InstallChannelGrid.astro
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ const channels = allChannels.filter(({ id, href }) => productData.channels[id] &
}

.install-channel-grid--hero {
/* The hero grid is the primary install path — it must not inherit the
smallest fallback meta size just because it skips the override. */
--channel-meta-size: 0.7rem;
--channel-card-edge: color-mix(in srgb, var(--cap-ink) 28%, transparent);
--channel-card-face: color-mix(in srgb, var(--cap-ink) 4%, transparent);
--channel-card-hover: color-mix(in srgb, var(--cap-accent) 10%, transparent);
Expand All @@ -181,8 +184,8 @@ const channels = allChannels.filter(({ id, href }) => productData.channels[id] &
--channel-card-edge: var(--hearth-panel-edge);
--channel-card-face: color-mix(in srgb, var(--hearth-panel-face) 92%, var(--hearth-bg));
--channel-card-hover: color-mix(in srgb, var(--hearth-kicker-accent) 9%, var(--hearth-panel-face));
--channel-card-ink: var(--hearth-ink-strong);
--channel-card-accent: color-mix(in srgb, var(--hearth-kicker-accent) 72%, var(--hearth-ink-strong));
--channel-card-ink: var(--hearth-text-heading-strong);
--channel-card-accent: color-mix(in srgb, var(--hearth-kicker-accent) 72%, var(--hearth-text-heading-strong));
}

@media (max-width: 360px) {
Expand Down
7 changes: 6 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"nav.themes": "Themes",
"nav.forge": "Forge",
"nav.install": "Install",
"nav.langSwitch": "Language",
"nav.skip": "Skip to content",
"lang.notice.body": "This page is available in English.",
"lang.notice.action": "View in English",
"lang.notice.dismiss": "Dismiss",
"hero.kicker": "Two materials. One semantic system.",
"hero.subtitle": "Warmth or structure. Meaning stays clear. Choose Ember or Moss, compare Dark and Light live, then install it where you work.",
"hero.flow.preview": "Preview theme",
Expand All @@ -11,7 +16,7 @@
"hero.flow.more": "More ways to explore HearthCode",
"hero.scope.label": "Sample language",
"hero.divider.label": "Drag to compare dark and light",
"hero.copy": "Click to copy",
"hero.copy": "Copy",
"hero.copied": "Copied",
"hero.ignite.count": "{n} tokens",
"hero.ignite.custom": "Color direction",
Expand Down
7 changes: 6 additions & 1 deletion src/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"nav.themes": "テーマ",
"nav.forge": "Forge",
"nav.install": "インストール",
"nav.langSwitch": "言語",
"nav.skip": "本文へスキップ",
"lang.notice.body": "このページには日本語版があります。",
"lang.notice.action": "日本語で表示",
"lang.notice.dismiss": "閉じる",
"hero.kicker": "二つの質感。一つの意味体系。",
"hero.subtitle": "温もりか、構造か。意味は明瞭なまま。Ember または Moss を選び、Dark と Light をライブ比較して、使う場所へインストールできます。",
"hero.flow.preview": "テーマを確認",
Expand All @@ -11,7 +16,7 @@
"hero.flow.more": "HearthCode を試すその他の方法",
"hero.scope.label": "サンプル言語",
"hero.divider.label": "ドラッグしてダークとライトを比較",
"hero.copy": "クリックしてコピー",
"hero.copy": "コピー",
"hero.copied": "コピーしました",
"hero.ignite.count": "{n} トークン",
"hero.ignite.custom": "カラー方向",
Expand Down
7 changes: 6 additions & 1 deletion src/i18n/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"nav.themes": "主题",
"nav.forge": "Forge",
"nav.install": "安装",
"nav.langSwitch": "语言",
"nav.skip": "跳到主要内容",
"lang.notice.body": "本页面提供简体中文版本。",
"lang.notice.action": "切换到简体中文",
"lang.notice.dismiss": "关闭",
"hero.kicker": "两种质感,一套语义系统。",
"hero.subtitle": "温暖或秩序,语义始终清晰。选择 Ember 或 Moss,实时比较 Dark 与 Light,再安装到你的工作平台。",
"hero.flow.preview": "预览主题",
Expand All @@ -11,7 +16,7 @@
"hero.flow.more": "更多体验 HearthCode 的方式",
"hero.scope.label": "代码示例语言",
"hero.divider.label": "拖动比较深浅两版",
"hero.copy": "点击复制",
"hero.copy": "复制",
"hero.copied": "已复制",
"hero.ignite.count": "{n} 个 token",
"hero.ignite.custom": "色彩方向",
Expand Down
Loading