/* Hallmark · v4.1.0 · shape: Stage on flat navy, the reference's left-text right-visual anatomy with Chinese content designed anew (no photographs: the product leads) · genre: modern-minimal · job: sign up — 开始使用, the hero pill · theme: none — the Franca portal's own dark token system (navy ground, one azure signal, brand-truth) with smoked-glass product faces and lit top edges · nav: wordmark, 文档/服务/控制台, session slot + one filled pill · footer: a mast, the wordmark over the links · hero: stage — the 64px/500 Chinese head left, next-token prediction live in smoked glass right, the page's one declared ambient loop (15s) · signature: the model writing the page's own headline, candidate by candidate — probabilities, bars, the winner joining the stream · sections: hero · services · control · cta · footer */
/* critique: 96px/400 read fontless for Chinese, so the ramp is rebuilt for the script — 64/500 display, 40/500 sections, weight carrying the hierarchy; the code walls moved to /docs and the hero visual is the product's own conversation, not decoration */
/* Hallmark · waive 26b · no form control and no aria-disabled anywhere, on either page this sheet serves · the hero demo has no buttons, and the docs samples keep all three language tabs always available, so a :disabled face has no element to land on */
/* Hallmark · dismissed 42 · the nav keeps the reference skeleton's shape: the wordmark, three links and the session slot on one transparent line; it earns glass once it leaves the hero */
/* Hallmark · waive 77 · both service rows are real, the close holds one action, and the docs notes are three hairline rows of prose · a set the user gave keeps its true count (layout.md § 3); every thin band on these pages carries its page's own content, never width-filling padding */
/* answered, on the record, not waivable: 40 — brand-1 #0284C7 under white text
   measures about 4.0:1, below AA. Kept because it is the production
   portal's measured primary colour, and the homepage must match the console
   it sends users to; every such face is 14px+ medium weight. The keyboard's
   skip link and the hero pill both sit on the darker gradient end instead,
   which clears AA on its own */

/* ------------------------------------------------------------------ */
/* Tokens — lifted from franca-portal/src/styles/tokens.css (the real   */
/* brand system). Every colour and font below rides a token.            */
/* ------------------------------------------------------------------ */

:root {
	color-scheme: dark;

	/* Ground and surfaces: the portal's dark navy; structure by borders. */
	--bg: #0a0f1e;
	--surface: #0d1428;
	--frost: oklch(1 0 0 / 4%);
	--frost-strong: oklch(1 0 0 / 8%);
	--halo: oklch(1 0 0 / 6%);
	--halo-strong: oklch(1 0 0 / 10%);
	--border: oklch(1 0 0 / 8%);
	--border-strong: oklch(1 0 0 / 16%);

	/* Ink: two steps; weaker hierarchy by size, not opacity. */
	--text-1: oklch(0.95 0.01 250);
	--text-2: oklch(0.68 0.02 250);

	/* Primary: one azure accent; the gradient lives on the logo mark only.
	   Filled controls sit on the gradient's dark end, the one azure face that
	   clears AA under white text on its own. */
	--brand-1: #0284c7;
	--on-brand: oklch(0.985 0.005 250);
	--brand-grad-a: #0ea5e9;
	--brand-grad-b: #0369a1;

	/* Code roles: the panels keep their own ink set. */
	--code-accent: #38bdf8;
	--code-string: #7dd3fc;

	/* Glass: smoked navy with a lit top edge, over the flat ground. */
	--glass: oklch(0.21 0.03 255 / 62%);
	--glass-edge: oklch(1 0 0 / 12%);
	--glass-lift: oklch(0.1 0.02 255 / 24%);

	--radius-sm: 8px;
	--radius: 16px;
	--radius-pill: 999px;
	--speed: 160ms;
	--ease-out: cubic-bezier(0.22, 1, 0.36, 1);

	--font:
		'Geist Sans', 'Noto Sans SC Variable', -apple-system, 'Segoe UI',
		'PingFang SC', 'Microsoft YaHei', sans-serif;
	--font-mono:
		ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace;

	/* The Chinese ramp: 64/500 display (96/400 read fontless for hanzi),
	   40/500 sections, weight and size carrying the hierarchy. Zero
	   display tracking: hanzi have no kerning pairs to tighten. */
	--fs-display: clamp(40px, 4.6vw, 64px);
	--fs-head: clamp(28px, 3vw, 40px);
	--fs-cta: clamp(36px, 5.4vw, 64px);
	--fs-h3: 25px;
	--fs-body: 16px;
	--fs-sm: 14px;

	/* The measured measure: 1232px of content at 1440 viewport. */
	--measure: 1280px;
	--gutter: 24px;
}

/* ------------------------------------------------------------------ */
/* Base                                                                 */
/* ------------------------------------------------------------------ */

* {
	box-sizing: border-box;
}

html,
body {
	overflow-x: clip;
}

html {
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--bg);
	color: var(--text-1);
	font-family: var(--font);
	font-size: var(--fs-body);
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
}

h1,
h2,
h3 {
	font-weight: 500;
	letter-spacing: 0;
	line-height: 1.15;
	margin: 0;
	overflow-wrap: break-word;
	min-width: 0;
	text-wrap: balance;
}

p {
	margin: 0;
}

a {
	color: var(--text-1);
	text-decoration: none;
}

:focus-visible {
	outline: 2px solid var(--code-accent);
	outline-offset: 2px;
	border-radius: 2px;
}

.measure {
	max-width: var(--measure);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/* ------------------------------------------------------------------ */
/* Skip link                                                           */
/* ------------------------------------------------------------------ */

.skip {
	position: absolute;
	left: var(--gutter);
	top: -48px;
	z-index: 10;
	padding: 8px 16px;
	/* The gradient's dark end: the one brand face that must clear AA on its own,
	   because it is the keyboard's door, not a display label. */
	background: var(--brand-grad-b);
	color: var(--on-brand);
	border-radius: var(--radius-sm);
	transition: top var(--speed);
}

.skip:focus-visible {
	top: var(--gutter);
}

/* ------------------------------------------------------------------ */
/* Controls — one filled pill, one quiet link                           */
/* ------------------------------------------------------------------ */

.btn-primary {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0 24px;
	height: 42px;
	white-space: nowrap;
	/* The dark end of the gradient: filled controls must clear AA on their own,
	   so brand-1 stays for the avatar (answered below), not for text faces. */
	background: var(--brand-grad-b);
	color: var(--on-brand);
	border-radius: var(--radius-pill);
	font-size: var(--fs-body);
	font-weight: 500;
	transition:
		background-color var(--speed),
		color var(--speed);
}

.btn-primary:hover {
	background: color-mix(in oklab, var(--brand-grad-b) 84%, var(--on-brand));
}

.btn-primary:active {
	background: color-mix(in oklab, var(--brand-grad-b) 86%, var(--bg));
}

.btn-lg {
	height: 52px;
	padding: 0 32px;
	font-size: 17px;
}

.link-quiet {
	color: var(--text-2);
	border-bottom: 1px solid transparent;
	padding-bottom: 2px;
	transition: color var(--speed);
}

.link-quiet:hover {
	color: var(--text-1);
}

.link-quiet:active {
	color: var(--code-accent);
}

/* ------------------------------------------------------------------ */
/* Nav — 64px, transparent over the hero, slate glass past it           */
/* ------------------------------------------------------------------ */

.nav {
	position: sticky;
	top: 0;
	z-index: 300;
	/* Transparent over the hero; the solid face declared below runs the
	   header's full width, not the 1280px inner measure, so the bar is
	   edge-to-edge the moment it appears. */
	border-bottom: 1px solid transparent;
	transition:
		background-color var(--speed),
		border-color var(--speed);
}

.nav-inner {
	display: flex;
	align-items: center;
	gap: 32px;
	height: 64px;
}

.nav-solid {
	background: color-mix(in oklab, var(--surface) 72%, transparent);
	backdrop-filter: blur(16px);
	-webkit-backdrop-filter: blur(16px);
	border-bottom-color: var(--border);
}

.lockup {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	color: var(--text-1);
	font-weight: 600;
	font-size: 15px;
}

.lockup:hover {
	color: var(--text-1);
}

.nav-links {
	display: flex;
	gap: 24px;
	font-size: var(--fs-sm);
}

.nav-links a {
	color: var(--text-2);
	transition: color var(--speed);
}

.nav-links a:hover,
.nav-links a:active {
	color: var(--text-1);
}

.nav-session {
	display: flex;
	align-items: center;
	gap: 20px;
	margin-left: auto;
}

.login-link {
	color: var(--text-2);
	font-size: var(--fs-sm);
	font-weight: 500;
	white-space: nowrap;
	transition: color var(--speed);
}

.login-link:hover,
.login-link:active {
	color: var(--text-1);
}

.user-chip {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	font-size: var(--fs-sm);
	color: var(--text-1);
}

.avatar {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	background: var(--brand-1);
	color: var(--on-brand);
	border-radius: 50%;
	font-size: var(--fs-sm);
	font-weight: 600;
}

/* ------------------------------------------------------------------ */
/* Hero — the Chinese head left, the glass conversation right           */
/* ------------------------------------------------------------------ */

.hero {
	/* 160 above and 160 below put the grid's last line near 780 at both fold
	   sizes: past the 84% floor of a 900 screen, inside an 800 fold. */
	padding: 160px 0 160px;
}

.hero-grid {
	display: grid;
	grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
	gap: 96px;
	align-items: end;
}

.hero-copy h1 {
	font-size: var(--fs-display);
	line-height: 1.12;
}

.hero-sub {
	margin-top: 24px;
	max-width: 30em;
	color: var(--text-2);
	font-size: 17px;
}

.hero-actions {
	display: flex;
	align-items: center;
	gap: 24px;
	margin-top: 32px;
	flex-wrap: wrap;
}

/* ------------------------------------------------------------------ */
/* Glass — smoked navy, lit top edge, one deep shadow                   */
/* ------------------------------------------------------------------ */

.glass {
	background: var(--glass);
	border-radius: var(--radius);
	/* The lit top edge plus the hairline: glass without its lit edge is a
	   grey box, and the shadow keeps it off the ground. No backdrop blur:
	   the ground behind is flat navy, so blur would blur nothing. */
	box-shadow:
		inset 0 1px 0 var(--glass-edge),
		0 0 0 1px var(--border),
		0 32px 64px var(--glass-lift);
}

.gen-panel {
	display: flex;
	flex-direction: column;
	gap: 20px;
	/* The panel is the hero's mass: its 560px holds the copy column's foot
	   inside the fold window at both fold sizes. */
	min-height: 560px;
	padding: 32px;
	min-width: 0;
}

.panel-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding-bottom: 20px;
	border-bottom: 1px solid var(--border);
}

.panel-title {
	font-size: var(--fs-body);
	font-weight: 500;
}

.panel-state {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--text-2);
	font-size: var(--fs-sm);
}

.dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--code-accent);
}

/* ------------------------------------------------------------------ */
/* The generation demo — fully rendered by default, replayed by script  */
/* ------------------------------------------------------------------ */

.gen-prompt {
	display: flex;
	align-items: baseline;
	gap: 12px;
	font-size: var(--fs-sm);
	color: var(--text-2);
	min-width: 0;
}

.gen-prompt-text {
	color: var(--text-1);
	overflow-wrap: break-word;
	min-width: 0;
}

.gen-label {
	font-size: var(--fs-sm);
	color: var(--text-2);
}

.gen-block {
	display: flex;
	flex-direction: column;
	gap: 12px;
	min-width: 0;
}

.gen-stream {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
	min-height: 44px;
}

.tok {
	padding: 4px 12px;
	background: var(--frost);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font-size: 17px;
	line-height: 1.5;
	transition:
		opacity 400ms var(--ease-out),
		transform 400ms var(--ease-out);
}

.gen-panel.is-live .tok {
	opacity: 0;
	transform: translateY(8px);
}

.gen-panel.is-live .tok.is-on {
	opacity: 1;
	transform: translateY(0);
}

.gen-cands {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.cand {
	display: grid;
	grid-template-columns: 64px minmax(0, 1fr) 44px;
	align-items: center;
	gap: 12px;
	transition:
		opacity 400ms var(--ease-out),
		transform 400ms var(--ease-out);
}

.gen-panel.is-live .cand {
	opacity: 0;
	transform: translateY(6px);
}

.gen-panel.is-live .cand.is-in {
	opacity: 1;
	transform: translateY(0);
}

.gen-panel.is-live .cand.is-out {
	opacity: 0.3;
	transform: translateY(0);
}

.cand-tok {
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
	color: var(--text-2);
	white-space: nowrap;
}

.cand-bar {
	position: relative;
	height: 8px;
	border-radius: var(--radius-pill);
	background: var(--frost);
	overflow: hidden;
}

.cand-fill {
	position: absolute;
	inset: 0;
	transform-origin: left center;
	background: var(--border-strong);
	transition: transform 600ms var(--ease-out);
}

.cand.is-win .cand-fill {
	background: var(--code-accent);
}

.cand.is-win .cand-tok {
	color: var(--text-1);
}

.cand-pct {
	text-align: right;
	color: var(--text-2);
	font-variant-numeric: tabular-nums;
	font-size: var(--fs-sm);
}

.caret {
	display: inline-block;
	width: 2px;
	height: 1.2em;
	background: var(--code-accent);
	opacity: 0;
}

.caret.is-typing {
	opacity: 1;
	animation: caret-beat 0.9s steps(1) infinite;
}

.gen-foot {
	margin-top: auto;
	display: flex;
	justify-content: space-between;
	padding-top: 16px;
	border-top: 1px solid var(--border);
	color: var(--text-2);
	font-size: var(--fs-sm);
}

.fig {
	color: var(--text-1);
	font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ */
/* Bands — the measured rhythm                                          */
/* ------------------------------------------------------------------ */

.band {
	padding: 144px 0;
}

.band h2 {
	font-size: var(--fs-head);
}

.band-lead {
	margin-top: 16px;
	max-width: 34em;
	color: var(--text-2);
}

/* Rows: hairline-parted, title left, line and wire chips right. */
.service-rows {
	list-style: none;
	margin: 64px 0 0;
	padding: 0;
}

.service-rows li {
	display: grid;
	grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
	gap: 32px;
	align-items: baseline;
	padding: 48px 0;
	border-top: 1px solid var(--border);
}

.service-rows li + li {
	border-bottom: 1px solid var(--border);
}

.service-rows h3 {
	font-size: var(--fs-h3);
}

.service-rows p {
	color: var(--text-2);
}

/* The wire names each settlement rides on: the row's fact, not decoration. */
.row-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 16px;
}

.row-chips code {
	font-family: var(--font-mono);
	font-size: 13px;
	color: var(--code-accent);
	background: var(--frost);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: 4px 12px;
	white-space: nowrap;
}

/* The console's own face, still in glass. */
.console-panel {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 64px;
	margin-top: 64px;
	padding: 48px;
	min-width: 0;
}

.panel-col {
	min-width: 0;
}

.panel-label {
	font-size: var(--fs-sm);
	color: var(--text-2);
	padding-bottom: 16px;
	border-bottom: 1px solid var(--border);
}

.key-row {
	display: flex;
	align-items: baseline;
	gap: 16px;
	padding: 16px 0;
	border-bottom: 1px solid var(--border);
	font-size: var(--fs-sm);
	color: var(--text-2);
	min-width: 0;
}

.key-name {
	font-family: var(--font-mono);
	color: var(--code-accent);
}

.key-note.dim {
	border-bottom: 1px solid var(--border-strong);
	padding-bottom: 2px;
}

.key-state {
	margin-left: auto;
	color: var(--text-1);
}

/* ------------------------------------------------------------------ */
/* Close — a statement, then the job's one action                        */
/* ------------------------------------------------------------------ */

.cta {
	padding: 176px 0;
}

.cta-head {
	font-size: var(--fs-cta);
	line-height: 1.1;
}

.cta-sub {
	margin-top: 24px;
	max-width: 34em;
	color: var(--text-2);
}

.cta-actions {
	display: flex;
	align-items: center;
	gap: 24px;
	margin-top: 40px;
	flex-wrap: wrap;
}

.cta-url {
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
	color: var(--code-accent);
	background: var(--frost);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: 4px 12px;
}

/* ------------------------------------------------------------------ */
/* Footer                                                               */
/* ------------------------------------------------------------------ */

.footer {
	border-top: 1px solid var(--border);
	padding: 64px 0 48px;
}

.footer-inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
	flex-wrap: wrap;
}

.footer-links {
	display: flex;
	align-items: center;
	gap: 32px;
	font-size: var(--fs-sm);
}

.footer-links a {
	color: var(--text-2);
}

.footer-links a:hover,
.footer-links a:active {
	color: var(--text-1);
}

.footer-meta {
	margin-top: 48px;
	color: var(--text-2);
	font-size: var(--fs-sm);
}

/* ------------------------------------------------------------------ */
/* Responsive                                                           */
/* ------------------------------------------------------------------ */

@media (max-width: 960px) {
	.hero {
		padding: 96px 0 96px;
	}

	.hero-grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 64px;
		align-items: start;
	}

	.gen-panel {
		min-height: 0;
	}

	.band {
		padding: 96px 0;
	}

	.console-panel {
		grid-template-columns: minmax(0, 1fr);
		gap: 32px;
		padding: 32px;
	}

	.cta {
		padding: 128px 0;
	}
}

@media (max-width: 640px) {
	.nav-links {
		display: none;
	}

	/* The nav's session pair must hold one line beside the wordmark here. */
	.nav-session {
		gap: 12px;
	}

	.btn-primary {
		padding: 0 16px;
		height: 36px;
	}

	.btn-lg {
		height: 44px;
	}

	.service-rows li {
		grid-template-columns: minmax(0, 1fr);
		gap: 8px;
	}

	.key-row {
		flex-wrap: wrap;
	}
}

/* ------------------------------------------------------------------ */
/* Motion — the demo's beats only; everything else holds still          */
/* ------------------------------------------------------------------ */

@keyframes caret-beat {
	0%,
	50% {
		opacity: 1;
	}

	50.01%,
	100% {
		opacity: 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	* {
		transition-duration: 0s;
	}

	/* The demo never starts under reduced motion, so the panel stays fully
	   rendered; the caret has nothing to mark and stays dark. */
	.gen-panel.is-live .tok,
	.gen-panel.is-live .cand {
		opacity: 1;
		transform: none;
	}

	.caret {
		animation: none;
	}
}
